remotion-video について
remotion-videoは、ReactでMP4、GIF、WebMを生成するスキルです。テンプレート型やデータ駆動型のモーショングラフィックスに向き、フレーム単位で決定的にプレビュー・再現し、CIでレンダリングできます。
主な機能
- 01フレーム駆動の決定的なアニメーション
- 02SequenceとSeriesによるタイムライン構成
- 03型付きパラメータプロパティ
- 04音声とビートの同期
- 05ブラウザプレビューとコマンドラインレンダリング
活用シーン
- 01個別化したソーシャル動画の一括生成
- 02バージョン管理可能なモーショングラフィックス制作
- 03CIでのMP4またはGIFレンダリング
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ iart-ai/ motion-design-skills --skill remotion-videoインストール後、Claude Code で/remotion-videoを入力して読み込まれたか確認します。
同梱ファイルREADME.mdreferences/api-and-patterns.md
詳細
Remotion(プログラムによる動画制作)
React で本物の MP4/GIF/WebM 動画を作成できます。すべてのフレームは useCurrentFrame() の純粋関数であるため、出力は決定的で、スクラブ可能、差分比較可能であり、CI でレンダリングできます。テンプレート化やデータ駆動型のモーショングラフィックス向けに、After Effects に代わるコードファーストの方法です。
使用する場面
- コードから MP4/GIF/WebM をレンダリングする(SNS 用クリップ、タイトルカード、解説動画など)。
- テンプレート化/データ駆動型の動画:1 つのコンポジションから、props に応じて多数の出力を生成する(ユーザーごと、レコードごと、CSV/DB の行ごとなど)。
- バージョン管理やコードレビューが必要で、GUI を使わずに CI でレンダリングするモーショングラフィックス。
- プログラムによる音声同期、データに基づいてアニメーションするグラフ、動画へのシェーダー/Three.js の埋め込み。
コア技術
フレーム駆動アニメーション
アニメーションは常に現在のフレームから導出し、setState や requestAnimationFrame は使いません。interpolate は入力範囲を出力範囲に対応付け、spring は物理的に自然な動きを生成します。
import {useCurrentFrame, useVideoConfig, interpolate, spring} from 'remotion';
export const Title = () => {
const frame = useCurrentFrame();
const {fps} = useVideoConfig();
// Fade in over frames 0-30, then stay (clamp prevents over/undershoot).
const opacity = interpolate(frame, [0, 30], [0, 1], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
});
// Spring entrance; divide by spring duration is unnecessary — drive transforms directly.
const scale = spring({frame, fps, config: {damping: 200, mass: 1, stiffness: 100}});
return <h1 style={{opacity, transform: `scale(${scale})`}}>Hello</h1>;
};
意図的にオーバーシュートさせる場合を除き、必ず interpolate をクランプしてください。デフォルトでは範囲外に線形外挿されるため、不透明度が 1 を超えたり、値が負になったりします。
スケジューリング:Sequence と Series
<Sequence> は時間をずらします。子要素の frame は、シーケンスの from の位置で 0 にリセットされます。タイムライン上にクリップを配置するために使います。<Series> はオフセットを手動で計算せずに、セグメントを連続して配置します。
import {Sequence, Series, AbsoluteFill} from 'remotion';
export const Timeline = () => (
<AbsoluteFill style={{backgroundColor: 'black'}}>
<Sequence from={0} durationInFrames={60}><Intro /></Sequence>
<Sequence from={60} durationInFrames={90}><Body /></Sequence>
{/* Series auto-sequences; offset overlaps the previous segment for crossfades */}
<Series>
<Series.Sequence durationInFrames={60}><ShotA /></Series.Sequence>
<Series.Sequence durationInFrames={60} offset={-15}><ShotB /></Series.Sequence>
</Series>
</AbsoluteFill>
);
コンポジションの登録とパラメーター化された props
<Composition> で id、サイズ、fps、長さ、defaultProps を宣言します。zod スキーマを使うと、props の型安全性が保たれ、Studio のサイドバーから編集できるようになります。
import {Composition} from 'remotion';
import {z} from 'zod';
export const schema = z.object({
title: z.string(),
accent: z.string(),
fps: z.number().default(30),
});
export const Root = () => (
<Composition
id="Promo"
component={Promo}
durationInFrames={150}
fps={30}
width={1080}
height={1920}
schema={schema}
defaultProps={{title: 'Launch', accent: '#5b8cff', fps: 30}}
/>
);
長さをデータに応じて決めるには、Composition の calculateMetadata を使って、レンダリング前に props から durationInFrames を計算します(例:行数 × 行あたりのフレーム数)。
音声とビートの同期
import {Audio, staticFile, useCurrentFrame, useVideoConfig} from 'remotion';
const BEATS_SEC = [0.5, 1.0, 1.5, 2.0]; // detected offline
export const Music = ({children}) => {
const frame = useCurrentFrame();
const {fps} = useVideoConfig();
const t = frame / fps;
const onBeat = BEATS_SEC.some((b) => Math.abs(t - b) < 1 / fps);
return (
<>
<Audio src={staticFile('track.mp3')} />
<div style={{transform: `scale(${onBeat ? 1.06 : 1})`}}>{children}</div>
</>
);
};
ビートはオフラインで検出し(例:web-audio-beat-detector や aubio を使用)、タイムスタンプを props に組み込んでください。ヘッドレスレンダリングにはリアルタイムの音声クロックがないため、レンダリング時に音声を解析しないでください。
レンダリング
ブラウザベースの Studio でプレビューし、CLI またはプログラム API を使ってヘッドレスでレンダリングします。
npx remotion studio # interactive preview
npx remotion render Promo out/promo.mp4 \
--props='{"title":"Launch","accent":"#f43"}' # pass parametric props
npx remotion render Promo out.gif --codec=gif # GIF output
バッチ/データ駆動型のパイプラインでは、Node で @remotion/renderer を使ってレンダリングします(バンドルは 1 回、レンダリングは複数回)。参考ファイルを参照してください。
納品と検証(レンダリングした静止画 → MP4)
同梱ヘルパー(
scripts/):scripts/contact-sheet.sh sheet.png f-hook.png f-mid.png f-end.pngで静止画をタイル状に並べ、scripts/probe-mp4.sh out.mp4 [WxH] [fps]でエンコード結果を検証します。scripts/README.mdを参照してください。
Remotion は設計上、フレーム決定論的です。すべてのフレームは useCurrentFrame() の純粋関数なので、シーク用ハーネスなしで任意のフレームをヘッドレスにレンダリングできます(Web シーンの ?t=N に相当する、より高負荷な方式です)。出力を MP4/GIF にする必要がある場合、正確な数値やテキストを含める必要がある場合、またはデータからバッチ生成する場合は、この方式を使ってください。軽量な Web アニメーションには、代わりにスタンドアロン HTML を納品してください。
出力要件:
- コンポジションが登録された Remotion プロジェクト(
<Composition>+ zodschema+defaultProps)で、すべてのモーションがフレーム駆動であること(タイマー/Date.now()/Math.random()は使用しない)。 - 納品物 = レンダリング済みの
out/*.mp4(および、ユーザーが新しい props/データで再レンダリングできるよう、プロジェクトも含めます)。 - 長さがデータに依存する場合は、手作業で指定せず、
calculateMetadataで計算してください。
検証手順 — 静止画をレンダリング → 確認 → エンコード。 まず単一フレームをレンダリングし(低コストで、動画のエンコードは不要です)、内容を確認してから、フレームが適切になった時点で動画全体を一度だけエンコードします。
# 1. Frame-exact stills at start / mid / end (PNG, headless, fast)
npx remotion still Promo out/f-start.png --frame=0
npx remotion still Promo out/f-mid.png --frame=75
npx remotion still Promo out/f-end.png --frame=149 # last frame = durationInFrames - 1
# render with the SAME props you'll ship, not just defaultProps:
# npx remotion still Promo out/f-mid.png --frame=75 --props='{"title":"Launch"}'
# 2. Inspect each PNG — fidelity (matches brief; numbers/text correct) AND
# artifacts (text overflow, off-canvas, clipped safe-area, missing font, wrong data binding).
# 3. Only after the stills check out, encode the video:
npx remotion render Promo out/promo.mp4 --props='{"title":"Launch"}'
npx remotion compositionsを使って各コンポジションのdurationInFrames/fpsを確認し、最終フレームを選びます。- データ駆動/バッチ処理:全行をバッチレンダリングする前に、代表的な props セットを 1 つ選び、静止画で検証します。レイアウトの不具合を N 回ではなく、1 回で発見できます。
- README のデモ GIF を無料で作成:
npx remotion render Promo out/demo.gif --codec=gifを実行すると、最初の画面のプレビュークリップが生成されます(方向 D)。
完了前の確認事項:
npx remotion stillでフレーム 0、中間、最終フレームが問題なくレンダリングされること — エラーやアセット/フォントの欠落がないこと。- 確認したすべてのフレームで、数値/テキストが正確で、セーフエリア内に収まっていること。
- フレーム駆動のみであること —
Date.now()/Math.random()/タイマーを使用しないこと(CI でも決定論性が保たれます)。 - props が zod で型付けされていること。納品する props で正しくレンダリングされること(
defaultPropsだけで確認しないこと)。 - MP4 全体がエンコードされ、再生できること。(任意)README 用の GIF をレンダリングすること。
クイックリファレンス
| 必要な処理 | 使用するもの |
|---|---|
| 時刻 → 値に変換 | interpolate(frame, [a,b], [x,y], {extrapolateRight:'clamp'}) |
| 自然なイージング | spring({frame, fps, config}) |
| 時刻 t にクリップを配置 | <Sequence from durationInFrames> |
| ショットを連続して配置 | <Series> |
| 音声 | <Audio src={staticFile(...)} /> |
| フレーム ↔ 秒 | frame / fps |
| 値をループ | frame % period を計算してから補間 |
| 編集可能な props | <Composition> の zod schema |
| CI でのレンダリング | npx remotion render または @remotion/renderer |
注意点
Math.random()、Date.now()、アニメーション用タイマーは使用しないでください。決定論性が損なわれます。フレームごとの安定したランダム性には、Remotion のrandom(seed)を使用してください。- フォントとアセットは
staticFile()で読み込み、delayRender/continueRenderで待機してください。そうしないと、レンダリング途中でフォントが表示されます。 interpolateはデフォルトで外挿します。クランプしてください。<Sequence>内のuseCurrentFrameはローカル(0 から開始)です。絶対時刻にはuseVideoConfig().durationInFramesを使用してください。
参考ファイル
references/api-and-patterns.md—interpolateオプションとEasing、spring 設定のレシピ、Sequence/Series のスケジューリング、<Audio>とビート同期、zod とcalculateMetadataを使ったパラメーター化可能なdefaultProps、CLI フラグ、@remotion/rendererによるプログラムからのバッチレンダリング、GLSL シェーダー/Three.js(@remotion/three)の埋め込み。