Files

415 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: HyperFrames — Создание Reels из HTML
created: 2026-06-12
updated: 2026-06-12
type: concept
tags: [hyperframes, video, reels, gsap, tiktok]
sources:
- concepts/web-psychology.md
- concepts/micro-interactions.md
confidence: high
---
# HyperFrames — Создание профессиональных Reels из HTML
> **Формула:** HTML + GSAP анимации + Edge-TTS = готовый Reels без видеоредакторов
>
> *Инструкция для LLM-агента: создавай Reels через HyperFrames — пиши HTML, линтируй, рендери MP4.*
---
## Фаза 0: Подготовка
### 0.1. Проверка окружения
```bash
node --version # нужен 22+
ffmpeg -version # нужен 6.1.1+
npx hyperframes doctor # проверка окружения
```
**Требования:** Node.js 22+, FFmpeg 6.1.1+, Chromium (скачивается автоматически при первом рендере).
### 0.2. Структура проекта
```
reels-project/
├── index.html # МАСТЕР: root-контейнер, без <template>
├── compositions/
│ ├── 01-hook.html # Хук (0–3s): решает, смотреть или нет
│ ├── 02-intro.html # Интро (3–8s)
│ ├── 03-content.html # Контент (8–20s)
│ ├── 04-cta.html # CTA (20–30s): призыв к действию
│ └── 05-outro.html # Финал (25–30s): логотип + подписка
├── assets/
│ ├── narration.mp3 # Озвучка (Edge-TTS предпочтительно)
│ └── bg-music.mp3 # Фоновая музыка (тихо, -20dB)
└── lib/
└── gsap.min.js # Локальная копия GSAP (CDN = 404 в headless)
```
### 0.3. Разрешение для Reels
**1080×1920 (портрет, 9:16)** — стандарт для Reels/TikTok/Shorts.
```css
html, body { width: 1080px; height: 1920px; overflow: hidden; }
```
---
## Фаза 1: Написание композиции
### 1.1. Базовая структура (inline, без вложенных сцен)
```html
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { width: 1080px; height: 1920px; overflow: hidden; background: #0a0820; }
</style>
</head>
<body>
<div class="clip-text clip" data-track-index="2" data-start="0" data-type="text">
Как создать <span class="accent">Reels</span>
</div>
<script src="lib/gsap.min.js"></script>
<script>
const tl = gsap.timeline({ paused: true });
tl.from('.clip-text', { opacity: 0, y: 100, duration: 0.8, ease: 'power3.out' }, 0);
tl.set({}, {}, 10);
window.__timelines = window.__timelines || {};
window.__timelines['reels-hook'] = { timeline: tl, paused: true };
</script>
</body>
</html>
```
### 1.2. Правило трёх
Каждая композиция должна содержать:
- ✅ **Root:** `data-composition-id` + `data-width` + `data-height`
- ✅ **Timed Elements:** `class="clip"` + `data-start` + `data-duration` + `data-track-index`
- ✅ **Animations:** `gsap.timeline({ paused: true })` + регистрация на `window.__timelines`
### 1.3. Обязательные атрибуты
| Атрибут | Обязательный | Описание |
|---|---|---|
| `class="clip"` | Да | Элемент — клип видео |
| `data-start` | Да | Секунда начала |
| `data-duration` | Да | Длительность в секундах |
| `data-track-index` | Да | Трек/слой (уникальный для каждого клипа) |
| `data-type` | Нет | Тип элемента (`text`, `audio`, `clip`) |
**НЕ НАДО:** `data-duration` на clip НЕ нужен — длительность управляется GSAP-таймлайном.
### 1.4. Цветовая схема (проверенная)
```css
background: #0a0820; /* Глубокий тёмно-синий */
text: #fff; /* Белый текст */
accent: #00ff88; /* Зелёный акцент */
secondary: #8800ff; /* Фиолетовый */
muted: #888; /* Серый для подписей */
```
### 1.5. Шрифты
```html
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700;900&family=JetBrains+Mono:wght@400;700&display=swap" rel="stylesheet">
```
| Шрифт | Где |
|-------|-----|
| **Inter** | Заголовки, текст, CTA (мин 40px для мобильного) |
| **JetBrains Mono** | Код, цифры, технические блоки |
---
## Фаза 2: Режиссура Reels
### 2.1. Золотое правило: Hook первые 3 секунды
> **В Reels зритель скроллит каждые 0.5 секунды. Первые 3 секунды = жизнь видео.**
**Лучшие паттерны хуков (ранг):**
1. **Blur-in** — текст из размытия `blur(15px)` за 0.6s → `blur(0px)`
2. **Крупный заголовок** — `font-size: 72px`, акцентный цвет, fade-up
3. **Glitch** — `steps(1)` + RGB-сплит (для tech-аудитории)
```javascript
// Blur-in хук (самый надёжный)
tl.from('.hook-text', {
opacity: 0, y: 60, filter: 'blur(15px)',
duration: 0.6, ease: 'power3.out'
}, 0);
```
### 2.2. Каденция текста
> **1 фраза = 1 слайд. Средняя скорость русской речи: ~3 слова/сек.**
```
Хук: "HTML в Reels за 30 сек" → 3s
Интро: "Без видеоредакторов" → 3s
Контент: "HyperFrames = HTML → MP4" → 4s
Контент: "Пишите HTML, рендерите" → 4s
CTA: "Подпишись для туториалов" → 3s
Итого: 17s (минимум 20–30s для алгоритма)
```
### 2.3. Оптимальная длина
| Длина | Назначение | Сцен |
|---|---|---|
| 15–20s | Вирусный хук, тизер | 3–4 |
| 25–30s | Туториал (стандарт) | 5–7 |
| 35–45s | Глубокий разбор | 8–10 |
### 2.4. Эффекты для Reels (ранжированы)
**Подходит:**
- **Blur reveal** — универсальный, профессиональный
- **Кинетическая типографика** — по слову, держит внимание
- **Счётчик** — `onUpdate` обновляет `textContent`
- **Lower Thirds** — имя + бейдж + описание
- **SVG прогресс-кольцо** — метрики, проценты
- **Пульсирующая CTA** — `boxShadow` yoyo-repeat
**НЕ подходит для Reels:**
- Глитч — слишком агрессивный
- 3D параллакс — отвлекает от текста
- RGB-сплит — на мобильном barely заметен
### 2.5. Аудио = 50% успеха
```bash
# Edge-TTS (предпочтительно)
edge-tts --text "Текст озвучки" --voice ru-RU-DmitryNeural --write-media assets/narration.mp3
# Проверка длительности
ffprobe -v error -show_entries format=duration \
-of default=noprint_wrappers=1:nokey=1 assets/narration.mp3
```
**Голоса:**
| Голос | Тип |
|-------|-----|
| `ru-RU-DmitryNeural` | Мужской, нейтральный |
| `ru-RU-SvetlanaNeural` | Женский, тёплый |
| `ru-RU-SergeyNeural` | Мужской, энергичный |
---
## Фаза 3: Готовые паттерны (copy-paste)
### Паттерн 1: Счётчик
```html
<div class="stat-number" style="font-size:100px;font-weight:900;color:#00ff88">0</div>
```
```javascript
let counter = { val: 0 };
tl.to(counter, {
val: 10000,
duration: 2,
ease: 'power2.out',
onUpdate: () => {
document.querySelector('.stat-number').textContent =
Math.floor(counter.val).toLocaleString();
}
}, 0.5);
```
### Паттерн 2: Lower Thirds
```html
<div class="lower-third" style="position:fixed;bottom:300px;left:60px">
<div class="lt-name" style="font-size:40px;font-weight:700;color:#fff">HYPERFRAMES</div>
<div class="lt-line" style="width:100px;height:4px;background:#00ff88;margin-top:8px"></div>
<div class="lt-desc" style="font-size:24px;color:#888;margin-top:8px">HTML → MP4</div>
</div>
```
```javascript
tl.from('.lt-name', { x: -40, opacity: 0, duration: 0.4, ease: 'power2.out' }, 0.3);
tl.from('.lt-line', { scaleX: 0, transformOrigin: 'left', duration: 0.3 }, 0.5);
tl.from('.lt-desc', { x: -30, opacity: 0, duration: 0.4, ease: 'power2.out' }, 0.6);
```
### Паттерн 3: SVG прогресс-кольцо
```html
<svg width="160" height="160" viewBox="0 0 180 180">
<circle cx="90" cy="90" r="80" fill="none" stroke="#222" stroke-width="8"/>
<circle class="ring" cx="90" cy="90" r="80" fill="none" stroke="#00ff88" stroke-width="8"
stroke-dasharray="502" stroke-dashoffset="502" stroke-linecap="round"
transform="rotate(-90 90 90)"/>
</svg>
```
```javascript
tl.to('.ring', { strokeDashoffset: 0, duration: 2, ease: 'power2.out' }, 0.5);
```
### Паттерн 4: Пульсирующая CTA
```html
<div class="cta-button" style="
margin: 0 auto; padding: 24px 48px;
background: #00ff88; color: #000;
font-size: 36px; font-weight: 900;
border-radius: 16px;
">ПОДПИШИСЬ</div>
```
```javascript
tl.to('.cta-button', {
boxShadow: '0 0 40px rgba(0,255,136,0.6)',
duration: 0.3, yoyo: true, repeat: 3
}, 1);
```
### Паттерн 5: Кинетическая типографика
```html
<div style="overflow:hidden">
<span class="word" style="font-size:70px;font-weight:900;color:#fff;display:inline-block">КАЖДОЕ</span>
<span class="word" style="font-size:70px;font-weight:900;color:#00ff88;display:inline-block">СЛОВО</span>
</div>
```
```javascript
document.querySelectorAll('.word').forEach((word, i) => {
tl.from(word, {
y: 80, opacity: 0, filter: 'blur(15px)',
duration: 0.6, ease: 'power3.out'
}, i * 0.25);
});
```
### Паттерн 6: Детерминированные частицы (canvas)
```javascript
function mulberry32(a) {
return function() {
a |= 0; a = a + 0x6D2B79F5 | 0;
var t = Math.imul(a ^ a >>> 15, 1 | a);
t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
return ((t ^ t >>> 14) >>> 0) / 4294967296;
}
}
const rng = mulberry32(42); // всегда одинаковый результат
```
> **НИКОГДА** `Math.random()` в canvas — рендер будет не детерминированным.
---
## Фаза 4: Рендер и экспорт
### 4.1. Команды
```bash
npx hyperframes lint # ОБЯЗАТЕЛЬНО: проверка
npx hyperframes preview # Порт 3003, HMR
npx hyperframes render --quality high --workers 1 --output reels.mp4
```
### 4.2. Параметры рендера
| Параметр | Значение | Описание |
|---|---|---|
| `--quality` | `draft`, `standard`, `high` | draft = без аудио, standard/high = с аудио |
| `--workers` | `1` | Для тяжёлых композиций — ТОЛЬКО 1 |
| `-f` | `30` | FPS. 30 достаточно для Reels |
### 4.3. Микширование narration
```bash
# Без перекодирования видео (мгновенно)
ffmpeg -y -i reels.mp4 -i assets/narration.mp3 \
-c:v copy -c:a aac -b:a 192k -shortest \
-map 0:v:0 -map 1:a:0 \
-movflags +faststart \
reels-final.mp4
```
### 4.4. Проверка результата
```bash
# Поток
ffprobe -v error -show_entries stream=codec_type,codec_name reels-final.mp4
# Ожидаемо: video/h264 + audio/aac
```
---
## Фаза 5: Типичные ошибки
### Ошибка 1: Видео обрезается короче narration
**Решение:** добавить `tl.set({}, {}, DURATION)` в конец таймлайна.
### Ошибка 2: `gsap_infinite_repeat`
**Причина:** `repeat: -1` ломает детерминированный рендер.
**Решение:** `repeat: N` (конечное число).
### Ошибка 3: Canvas в screenshot mode
**Причина:** raw `requestAnimationFrame()` в inline `<script>`.
**Решение:** `setInterval` или вынести в `canvas.js`.
### Ошибка 4: `root_composition_missing_html_wrapper`
**Причина:** комментарий перед `<!DOCTYPE html>`.
**Решение:** `<!DOCTYPE html>` — строго первая строка.
### Ошибка 5: Перекрывающиеся клипы
**Решение:** каждый `.clip` — уникальный `data-track-index`.
### Ошибка 6: CSS `transform` + GSAP `y`/`x`
**Решение:** `xPercent`/`yPercent` вместо CSS `transform`.
### Ошибка 7: CDN GSAP = 404
**Решение:** локальная `lib/gsap.min.js`.
---
## Фаза 6: Чек-лист перед публикацией
- [ ] Хук в первые 3 секунды (blur-in / крупный текст)
- [ ] Длитель narration = длительность GSAP-таймлайна
- [ ] `npx hyperframes lint` — без ошибок
- [ ] `npx hyperframes preview` — каждый слайд визуально проверен
- [ ] `--workers 1` для тяжёлых композиций
- [ ] FFmpeg микширование: `-c:v copy -c:a aac`
- [ ] `ffprobe` — два потока (h264 + aac)
- [ ] Размер < 100MB (лимит Instagram)
- [ ] Разрешение 1080×1920 (портрет)
- [ ] Текст читается на мобильном (мин 40px)
---
## Готовые блоки
```bash
npx hyperframes add flash-through-white # Переход через вспышку
npx hyperframes add warm-grain # Зерно плёнки
npx hyperframes add instagram-follow # Анимация подписки
npx hyperframes add swiss-grid # Швейцарская сетка
npx hyperframes add lower-third # Нижний титр
```
## GSAP Easing
| Easing | Эффект | Применение |
|--------|--------|-----------|
| `power2.out`, `power3.out` | Плавное замедление | Появление текста |
| `back.out(1.7)` | Пружинящее | CTA-кнопки |
| `sine.inOut` | Мягкий синус | Фоновые элементы |
| `circ.inOut` | Медленное начало/конец | Элегантные переходы |
| `steps(1)` | Глитч | Резкие кадры |