Монтаж на Remotion + Storybook
Студия — папка studio/ (команды в studio/README.md). Формат и стиль уже выбраны на этапах 1–2 docs/agent-contract/WORKFLOW.md
и записаны в videos/<проект>/CONCEPT.md.
Стек
- Remotion — сцены пишутся React-компонентами, анимация только от
useCurrentFrame():interpolate,spring, свои кривые. CSS-переходы и CSS-анимации в рендере не работают. Время в коде — секунды речи (t = frame / fps). - Storybook — каждый блок (карточка, список, счётчик, логотипы, призыв, переход) смотрится отдельно в
studio/src/stories/; весь ролик — через@remotion/playerс перемоткой. Блок сначала принимается в витрине, потом идёт в ролик. - Библиотека
studio/src/kitиstudio/src/ds: стекло с преломлением (kit/liquid), глубина текста и панелей (ds), 3D через@remotion/three(kit/three.tsx), постерная типографика (kit/poster.tsx), переходы сцен (kit/presentations.tsx), телефон, тогл, курсор, иллюминатор. - Шаблон
studio/src/template— стиль КАНВАС в двух форматах:Template.tsx(сборка),blocks.tsx(хук, список, цифра, логотипы, призыв),desk.tsx(стол, карточки, пунктир),canvas.tsx(камера, курсор),Speaker.tsx,formats.tsрядом.
Паттерны
Каталог — patterns/README.md: стили 1–12 с документами и кадрами готовых роликов (patterns/reels/<ролик>/frames.jpg),
паттерны движения (studio/src/examples/vibe/blocks/: колода, рентген, слот-машина, разрыв кадра, перемотка стройки,
разбор на детали, переливание), код утверждённых роликов 19–22 в studio/src/examples/, приёмы (patterns/techniques/)
и разборы референсов (patterns/breakdowns/). До карты монтажа — прочитать документы выбранного стиля и его грабли.
Код из examples/ — образец: блок переносится в studio/src/videos/<проект>/ и подгоняется под текст, ролик целиком не копируется.
Стили 5–12 — движок studio/src/styles
engine.tsx собирает ролик из тех же блоков, что и шаблон КАНВАС (hook, list, stat, logos, flow, cta): сцена на блок
(TransitionSeries, переход 0,5 с входит в начало новой сцены — смена фона попадает ровно на фразу), поверх — спикер, субтитры
и звук. Стиль (StyleDef) задаёт фон сцены, отрисовку блоков, переход, раскладку спикера (card, square, roam, circle,
half, podcast), зону графики и субтитры. PRISM рисует блоки сам (prism.tsx), остальные — общей раскладкой skinned.tsx
со своей «кожей» и своими слоями (глубина ORBIT, ручка TRACE, предметы PULSE, маркер подкаста). Сменить стиль ролика — одна
строка в точке входа: reelOf(ORBIT). Своя механика блока, которой нет в стиле, пишется в studio/src/videos/<проект>/.
Форматы — studio/src/formats.ts
| Рилс | YouTube | |
|---|---|---|
| Кадр | 1440×2560, 60 fps | 2560×1440, 60 fps |
| Зона графики | x80 y290 w1280 h1090 | x110 y110 w1580 h1060 |
| Спикер | снизу по центру: base 864×819, compact 648×614, wide 1010×958 | справа снизу: base 660×680, compact 500×440, wide 760×900 |
| Субтитры | центр 720/1467, ширина ≤ 920, 53,3 px | центр 900/1300, ширина ≤ 1400, 56 px |
Раскладку из головы не придумывать — брать из профиля. Для YouTube всё раскладывается от прямоугольника зоны, а не от
координат рилса. 4K только по просьбе: Config.setScale(1.5) в remotion.config.ts, рендер ×1,7 дольше.
Карта монтажа — своя под каждый ролик
До кода — таблица в videos/<проект>/DIRECTION.md: время → фраза → фон/зона → что на экране → стык и его причина из речи →
размер карточки спикера. Каждый раз заново придумываются герой хука, форма схемы (цепочка, развилка, воронка, до/после),
вставки (настоящие записи экрана, логотипы, предметы), набор переходов и зоны цвета. Набор сцен прошлого ролика целиком
не переносить: берётся метод и блоки библиотеки, не сценарий.
Воздух: один главный объект ≥ 50 % зоны графики, не больше трёх смысловых элементов в кадре, новый элемент не чаще раза в 1,2 с.
Правила кадра
- Спикер — одна скруглённая карточка Screen Studio; размер меняется по смене смыслового блока, переход 0,6 с, масштаб равномерный.
- Субтитры — стеклянная капсула под строкой, произносимое слово подчёркнуто мятой; не под карточкой спикера.
- Фон меняется на каждом смысловом блоке; три перекраски одного фона не считаются.
- Палитра: графит, чёрный, белый; мятный
#3DEDC3(текст на нём#05231D) и оранжевый#FF7A2F— только акценты. Неон подсветки карточек в КАНВАСЕ — синий#3AA6FF(NEONвtemplate/canvas.tsx). - Глубина у каждого текста и контейнера:
textDepth, фаска, торец плиты, стекло. Светлые карточки не кладутся на светлый фон. - Названный сервис — его настоящий логотип из
studio/public/brand(нет нужного — скачать с сайта сервиса: favicon.svg, apple-touch-icon, аватар организации на GitHub; не нашёл — спросить владельца, не рисовать замену). - Предметы —
studio/public/objects/*.webp(стеклянные 3D-рендеры с промптами рядом). Новый предмет — генерация по промпту в той же палитре (scripts/gen-object.mjs, ключ OpenAI вOPENAI_API_KEY) и проверка глазами до анимации. - Курсор агента кликает по пунктам, а не проезжает мимо; метка «Claude» не закрывает текст (на кликах по списку прячется, у правого края разворачивается).
- Эмоция вместо перечисления: отмеченный пункт зачёркивается и вспыхивает, число считается с нуля, логотип выпрыгивает с бликом.
- Ни одного пустого кадра: первый кадр не пустой, после стыка нет голого фона, камера не наезжает так, что карточка уходит за край.
- Звук: эффекты из
studio/public/sfx, громкость ×0,37 от исходных нарезок, без приглушения речи; под каждый ролик свои нарезки и тембры, не один и тот же набор.
Проверки до показа кадров
npm run typecheck— без ошибок.ENTRY=src/videos/<проект>/index.tsx node scripts/qa-fit.mjs <проект>→FIT PASS(содержимое не вылезает из контейнеров, поля ≥ половины кегля).node scripts/qa-fit.mjs FitTestобязан датьFIT FAIL— доказательство, что проверка жива.- Кадры каждые 2 с:
ENTRY=… node scripts/review.mjs <проект>→ листы владельцу ⏸. Плюс сам агент смотрит середины всех переездов камеры и по 3 кадра на каждый стык: наложения, обрезанный текст, метка курсора поверх текста, пустой фон.
Рендер и сдача
cd studio && npx remotion render src/videos/<проект>/index.tsx <проект> ../videos/<проект>/renders/raw.mp4
bash scripts/master.sh ../videos/<проект>/renders/raw.mp4 ../videos/<проект>/renders/final.mp4
Фоновой задачей, один рендер за раз. Remotion громкость не выравнивает — master.sh доводит до −14 LUFS / ≤ −1 dBTP.
После — лист из самого MP4 и замер размера, битрейта (цель 48 Мбит/с в 2K) и громкости.
Грабли
-
Текст вылезал за капсулу субтитров на смене строки: капсула росла 0,22 с, а текст новой строки появлялся сразу. Субтитры — только
studio/src/montage/Captions.tsx(capsuleAt: капсула не уже видимого текста — под длинную строку растёт сразу, плавно только сужается; в qa-режиме — проверка всех стыков строк с шагом 1/120 с). Любой контейнер, меняющий размер, проверять на всём отрезке анимации, а не выборкойqa-fitраз в 0,5 с. -
Имя папки композиции (
<Folder name>) и id композиции — только латиница, цифры и дефис. -
sideEffectsвpackage.jsonдержит"**/fonts.ts", иначе сборщик выкидывает шрифты и текст уходит в засечки. -
Storybook рядом с Remotion ставится с
legacy-peer-deps(уже вstudio/.npmrc). -
Шрифты для замеров текста — через
useFontsReady(kit/liquid/useAssetReady.ts), иначе строки слипаются в отдельных кадрах. -
Стекло размывает только то, что лежит с ним в одном слое: у предков стеклянного блока нет
filter,opacity < 1,mask. -
Процент в размерах
<Video>не работает — размеры считать в пикселях (так сделано вSpeaker.tsx). -
Консоль браузера при
remotion stillдо терминала не доходит — поэтому qa-fit ловит сообщения через API рендера.