Создание видео с помощью Claude Code и Remotion
Claude Code со скиллом Remotion — это рабочий процесс для генерации видео из промптов на естественном языке: установите скилл, создайте проект Remotion, опишите видео на обычном английском и позвольте Claude написать точный по кадрам React-код, который рендерится в MP4. Вот и весь цикл. Сложность никогда не в промпте — она в том, чтобы достаточно хорошо понять код, который возвращает Claude, и исправить его, когда результат рендера расходится с тем, что вы просили. В этой статье разобран один практический пример для разработчиков от начала до конца, а также показано, как освоить ментальную модель Remotion, чтобы диагностировать сломанный рендер через превью в Studio, а не перезапускать промпт вслепую.
Ключевые выводы
- Remotion — это React-фреймворк, который рендерит видео, рассматривая каждый кадр как чистую функцию от номера кадра, доступного через
useCurrentFrame(), и делая скриншоты этого вывода для создания MP4. - При 30fps 15-секундное видео состоит из 450 кадров; каждая анимация — это отображение номера кадра в CSS-значение, без какого-либо редактора таймлайна.
- Команда установки встречалась в нескольких вариантах в разных руководствах — перед запуском сверьтесь с актуальной версией на
remotion.dev/docs/ai/claude-code, поскольку инструментарий скиллов находится в процессе изменений. - Когда анимации в превью запускаются одновременно, причина почти всегда в отсутствии смещений
fromу компонентов<Sequence>, которые по умолчанию начинаются с кадра 0. - Remotion рендерит видео, запуская headless Chromium и делая скриншот каждого кадра — именно поэтому 30-секундная композиция при 30fps требует 900 скриншотов и именно для этого существует Remotion Lambda для продакшн-пайплайнов.
Что представляет собой этот стек
Remotion — это open-source React-фреймворк для программного создания видео: вы определяете сцены как React-компоненты, управляете таймингом через номера кадров и рендерите результат в MP4, WebM или GIF — без редактора таймлайна, без drag-and-drop. Скилл Remotion для Claude Code — это набор правил, который обучает агента API-поверхности Remotion: композициям, последовательностям, interpolate(), spring(), конфигурации рендера — чтобы он генерировал корректную математику кадров вместо угадывания. Это не плагин, работающий во время рендера; это контекст, внедряемый в Claude, чтобы написанный им код компилировался и анимировался именно так, как вы описали.
Что такое ментальная модель Remotion?
В Remotion ваше видео — это чистая функция от номера кадра. Композиция — это React-компонент с фиксированной длительностью в кадрах. При 30fps 15-секундное видео состоит из 450 кадров, и каждая анимация выражается как отображение текущего кадра в CSS-значение: opacity, transform, color. Таймлайна нет — есть только математика.
Четыре примитива составляют всю модель, все они задокументированы в основах Remotion:
useCurrentFrame()возвращает номер кадра, который рендерится прямо сейчас. Ваш компонент перезапускается для каждого кадра.fpsиdurationзадаются в<Composition>. Согласно документации по композициям, там устанавливаютсяdurationInFrames,fps,widthиheight.<Sequence>сдвигает время. Дочерний элемент, обёрнутый в<Sequence from={90}>, видит кадр 0, когда глобальный кадр равен 90 — именно так реализуется поочерёдный запуск сцен.interpolate()отображает диапазон кадров на диапазон значений.
Математика кадров, которая вам постоянно понадобится:
| Длительность | Кадры при 30fps |
|---|---|
| 5с | 150 |
| 10с | 300 |
| 15с | 450 |
| 30с | 900 |
| 60с | 1800 |
Как только вы усвоите принцип «кадр на входе, CSS-значение на выходе», генерируемый код перестанет казаться магией.
Предварительные требования и установка
Discover how at OpenReplay.com.
Вам понадобятся Node.js (проверьте требования к версии на странице начала работы с Remotion перед установкой) и Claude Code — терминальный агент для написания кода от Anthropic. Claude Code работает через подписку на Claude или по API-биллингу — уточните актуальные требования к доступу в документации Anthropic по Claude Code, поскольку доступность тарифных планов меняется.
Теперь о том, что каждое руководство обходит стороной. Команда установки скилла Remotion встречалась как минимум в трёх разных вариантах в недавних материалах (npx @anthropic-ai/skills add remotion, npx skills add remotion, npx skills add remotion-dev/skills). Упаковка скиллов продолжает меняться, поэтому не доверяйте скопированным командам. Откройте официальную страницу скиллов — remotion.dev/docs/ai/skills — и запустите то, что там указано на данный момент. Считайте эту страницу единственным источником истины, пока экосистема не устоится.
Сначала убедитесь, что Claude Code доступен в вашем PATH:
claude --version
Затем установите скилл с помощью команды с официальной страницы документации и подтвердите успешную установку, спросив Claude внутри проекта: «Do you have the Remotion skill loaded?»
Практический пример: 15-секундный ролик с демонстрацией фич
Наиболее сильные сценарии использования этого стека для разработчиков — это ресурсы, которые вы регенерируете из данных или по расписанию: ролик с изменениями, собранный из CHANGELOG.md, анимированная архитектурная диаграмма, отражающая текущее состояние системы, или демонстрация фич продукта, перерендериваемая с каждым релизом. Мы создадим именно такой ролик.
Шаг 1 — Создание проекта
Команда для создания проекта задокументирована на странице начала работы с Remotion:
npx create-video@latest feature-reveal
cd feature-reveal
npm install
Создайте проект с TypeScript-шаблоном или конфигурацией. В результате вы получите src/Root.tsx (где регистрируются композиции) и стартовую композицию.
Шаг 2 — Промпт для Claude Code
Откройте агент в проекте и явно укажите математику кадров — именно здесь чаще всего возникают проблемы с генерацией:
Create a Remotion composition called FeatureReveal.
- 15 seconds at 30fps (450 frames), 1920x1080.
- Dark background (#0d1117).
- A headline "Ship changelogs as video" fades in over frames 0-30,
holds, then fades out over frames 420-450.
- Three feature rows below the headline, each sliding up from 40px
with a spring, staggered: row 1 enters at frame 60, row 2 at 90,
row 3 at 120.
- Register FeatureReveal in Root.tsx with the correct
durationInFrames and fps.
Шаг 3 — Разбор сгенерированного кода
Корректная генерация выглядит примерно так. Заголовок использует interpolate(); строки используют смещения <Sequence from> в сочетании со spring():
import {
AbsoluteFill,
interpolate,
spring,
Sequence,
useCurrentFrame,
useVideoConfig,
} from "remotion";
const features = ["One prompt", "Re-render per release", "Version-controlled"];
const FeatureRow: React.FC<{ label: string }> = ({ label }) => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
// spring() возвращает значение от 0 до 1; мы отображаем его на translateY и opacity.
const enter = spring({ frame, fps, config: { damping: 14 } });
const translateY = interpolate(enter, [0, 1], [40, 0]);
return (
<div style={{ opacity: enter, transform: `translateY(${translateY}px)` }}>
{label}
</div>
);
};
export const FeatureReveal: React.FC = () => {
const frame = useCurrentFrame();
// Opacity заголовка: появляется к кадру 30, удерживается, исчезает с кадра 420 по 450.
const headlineOpacity = interpolate(
frame,
[0, 30, 420, 450],
[0, 1, 1, 0],
{ extrapolateRight: "clamp" }
);
return (
<AbsoluteFill style={{ backgroundColor: "#0d1117", color: "white" }}>
<h1 style={{ opacity: headlineOpacity, fontSize: 72 }}>
Ship changelogs as video
</h1>
{features.map((label, i) => (
// Каждая строка начинается на 30 кадров позже предыдущей через `from`.
<Sequence key={label} from={60 + i * 30}>
<FeatureRow label={label} />
</Sequence>
))}
</AbsoluteFill>
);
};
Строка, которую стоит запомнить — это interpolate() для заголовка. Вызов отображает номера кадров на значения opacity: в кадре 0 opacity равно 0, к кадру 30 — 1, удерживается до кадра 420, затем затухает до 0 к кадру 450. Массив кадров и массив значений должны быть одинаковой длины, а { extrapolateRight: "clamp" } останавливает значение от продолжения за пределы последней точки — название опции и её поведение задокументированы в справочнике по interpolate().
Поочерёдный запуск обеспечивается через from={60 + i * 30} на каждом <Sequence>. Поскольку каждая строка является собственной последовательностью, её useCurrentFrame() сбрасывается до 0 в начальном кадре, поэтому spring() срабатывает от точки входа строки, а не от начала видео.
Claude также должен зарегистрировать композицию в Root.tsx:
import { Composition } from "remotion";
import { FeatureReveal } from "./FeatureReveal";
export const RemotionRoot: React.FC = () => (
<Composition
id="FeatureReveal"
component={FeatureReveal}
durationInFrames={450}
fps={30}
width={1920}
height={1080}
/>
);
Если durationInFrames и fps здесь расходятся с номерами кадров в вашем компоненте, тайминг ломается. Это наиболее распространённая причина того, что «видео имеет неправильную длину».
Шаг 4 — Превью в Studio
Запустите Remotion Studio:
npm run dev
Studio откроется в браузере (обратите внимание на порт, который он выводит — он не всегда одинаков). Выберите FeatureReveal, нажмите play и перемотайте ползунок воспроизведения. Перемотка к конкретному кадру — это основной приём отладки: превью показывает вам именно то, что рендерится в кадре N, что позволяет сопоставить это с математикой кадров в вашем коде.
Как диагностировать неправильный рендер Remotion?
Диагностируйте по превью в Studio, а не по списку типичных ошибок. Перемотайте к кадру, где возникает проблема, и изучите код, управляющий этим диапазоном кадров. Большинство проблем объясняется тремя типами сбоев.
Всё анимируется одновременно. Когда анимации в превью запускаются одновременно, причина почти всегда в отсутствии смещений from у компонентов <Sequence>: каждая сцена по умолчанию начинается с кадра 0, если не задать from={startFrame}. Перемотайте к кадру 0 — если все три строки уже движутся, последовательности не разнесены по времени. Исправьте это, попросив: «Wrap each feature row in its own <Sequence> with from set to 60, 90, and 120.»
Видео имеет неправильную длину. Claude генерирует номера кадров исходя из указанного вами fps. Если вы не указали fps, он предполагает значение по умолчанию и может неверно рассчитать его относительно иначе настроенной композиции. Перемотайте к концу ползунка: если ваша 450-кадровая анимация заканчивается на кадре 300, значит durationInFrames в композиции установлен в 300. Переформулируйте промпт с точными числами — «15 seconds at 30fps is 450 frames; set durationInFrames={450}» — вместо расплывчатого «сделай длиннее».
Движение выглядит роботизированным. Линейный interpolate() без смягчения воспринимается как механический. Перемотайте через анимацию входа: если она движется с постоянной скоростью — смягчения нет. Замените на spring() для органичного движения (он возвращает значение от 0 до 1, которое вы отображаете на transform), или передайте опцию easing в interpolate() согласно документации по interpolate. Попросите: «Use spring() for the row entry instead of a linear interpolate.»
Записи сессий встроенных демо-видео на лендингах нередко выявляют отдельный тип сбоя — автовоспроизведение большого MP4, блокирующее отрисовку страницы — но это проблема доставки контента, а не рендера.
Рендер в MP4
Выполните рендер из командной строки с помощью npx remotion render, передав идентификатор композиции и путь для сохранения:
npx remotion render FeatureReveal out/feature-reveal.mp4
Вот реальность, которую промпт-гайды обходят стороной. Remotion рендерит видео, запуская headless Chromium, делая скриншот каждого кадра и передавая кадры через ffmpeg — архитектура описана в документации по рендерингу. 30-секундная композиция при 30fps означает 900 скриншотов браузера. Именно поэтому время рендера масштабируется с количеством кадров и сложностью каждого кадра, и именно поэтому длинная или визуально насыщенная композиция может занять ощутимое время на ноутбуке, а не отрендериться «меньше чем за минуту».
Для продакшн-пайплайнов — длинных видео, множества вариантов, CI, который не может занимать агент сборки — задокументированный облачный путь Remotion — это Remotion Lambda, который распределяет кадры по параллельным Lambda-функциям. Lambda оправдывает затраты на настройку, когда локальное время рендера становится узким местом или когда нужно рендерить по расписанию без участия машины разработчика. Для разового 15-секундного ролика рендерьте локально и не усложняйте.
Remotion бесплатен для частных лиц и небольших компаний; более крупным компаниям требуется лицензия — уточните актуальные условия на странице лицензии Remotion перед коммерческим использованием.
Когда не стоит использовать Remotion?
Выбирайте Remotion, когда видео основано на данных, воспроизводимо или должно точно соответствовать дизайн-системе — ролик с изменениями, анимированная диаграмма, демонстрация фич к каждому релизу. Выбирайте традиционный редактор или AI-генератор видео, когда контент включает живую съёмку, фотореалистичен или представляет собой разовый творческий проект, где стоимость итерации через перерендер превышает преимущества программного контроля. Вырезание неудачных дублей из записи выступления, цветокоррекция отснятого материала или создание органичного фотореалистичного движения — всё это задачи, с которыми Remotion будет бороться против вас. Граница проходит там, где результат выигрывает от того, что является программой: если вы отрендерите его один раз и больше никогда не прикоснётесь, код — это накладные расходы, а не преимущество.
Ценность этого стека раскрывается при втором рендере, а не при первом. Как только композиция создана, её регенерация из новых данных — нового changelog, новой метрики, нового релиза — это одна команда. Установите скилл с официальной страницы документации, создайте пример с демонстрацией фич выше, а затем направьте ту же композицию на данные, которые вы реально публикуете.
Часто задаваемые вопросы
interpolate() по умолчанию линейно отображает диапазон кадров на диапазон значений, что даёт точный контроль над начальными и конечными кадрами — например, изменение opacity с 0 до 1 между кадрами 0 и 30. spring() возвращает физически обоснованное значение от 0 до 1, которое плавно нарастает и естественно затухает — его вы отображаете на transform или opacity. Используйте interpolate() для точного тайминга и удержания значений; используйте spring() для органичного движения, которое должно ощущаться менее механическим.
Длительность определяется параметром durationInFrames в Composition в Root.tsx, а не значениями анимации внутри вашего компонента. Если durationInFrames равен 300, а ваша анимация рассчитана до кадра 450, рендер остановится на кадре 300 и обрежет остальное. Значение fps также должно соответствовать используемой математике: при 30fps 15 секунд — это 450 кадров. Задавайте оба параметра явно, чтобы математика компонента и конфигурация композиции совпадали.
Вы можете описывать видео на обычном английском и позволить Claude Code генерировать React-код, но вам всё равно нужно читать результат, чтобы исправить его, когда рендер расходится с тем, что вы просили. Скилл обучает Claude API Remotion, чтобы тот генерировал корректную математику кадров, но не устраняет необходимость понимать композиции, последовательности и номера кадров при отладке. Знание ментальной модели «кадр на входе, CSS-значение на выходе» — это то, что позволяет диагностировать проблемы по превью в Studio.
Remotion Lambda оправдывает затраты на настройку, когда локальное время рендера становится узким местом или когда нужно рендерить по расписанию без участия машины разработчика. Поскольку Remotion делает скриншот каждого кадра через headless Chromium, время рендера масштабируется с количеством кадров и сложностью каждого кадра — длинные видео или множество вариантов занимают ноутбук или агент сборки. Lambda распределяет кадры по параллельным функциям. Для разового короткого ролика рендерьте локально и не используйте Lambda.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.