Remotion モーショングラフィックス — フレームベースの2D動画
Remotion は React を動画にレンダリングします。すべてのフレームはフレームインデックスの純粋関数であるため、出力は決定論的で、差分可能、レビュー可能です。テキスト主体およびデータ駆動型の動画に最適なデフォルトであり、Blender や Manim のパスにタイポグラフィ、キャプション、トランジションを合成するための最適な「コンポジター」です。
規約については references/REMOTION-PLAYBOOK.md を、コピー可能なコンポーネントについては references/REMOTION-RECIPES.md を参照してください。現在のAPIについては公式ドキュメントとインストール済みのCLIを確認してください: https://www.remotion.dev/docs/
1. セットアップ
node --version # 18以上必須、20/22 LTS推奨
npx create-video@latest my-video # 空のテンプレートを選択
cd my-video
npx skills add remotion-dev/skills # 公式の Remotion エージェントスキル(推奨)
npm run dev # Remotion Studio が http://localhost:3000 で起動
レンダリング:
npx remotion render <エントリ> <CompositionId> out/video.mp4 --codec=h264
npx remotion render <エントリ> <CompositionId> out/preview.mp4 --scale=0.5
npx remotion render <エントリ> <CompositionId> out/frames --sequence --image-format=png
正確なフラグはバージョンによって異なります。npx remotion render --help で確認してください。
ライセンス: Remotion は ソース利用可能であり、OSI オープンソースではありません。個人および適格な小規模組織は現在の条件のもとで無料で使用できます。大企業や商用・自動化での使用には有料ライセンスが必要な場合があります。納品物を約束する前に、https://www.remotion.dev/docs/license/pricing でユーザーの実際のケースを確認してください。これを「MIT」や「どの企業でも無料」と説明しないでください。
2. プロジェクト構成
スターターに合わせて適合させ、無理に変更しないでください:
src/
Root.tsx # コンポジションを登録
compositions/
MainVideo.tsx # シーンを順序付ける
scenes/
Intro.tsx Feature.tsx Outro.tsx
components/
AnimatedTitle.tsx Background.tsx Grid.tsx Caption.tsx Transition.tsx
animations/
easing.ts timing.ts reveal.ts
data/
content.ts # テキストと数値、レイアウトとは分離
styles/
tokens.ts # パレット、タイプスケール、スペーシング
public/
audio/ fonts/ images/ video/
ルール:
- 1ファイル1シーン。
MainVideoはそれらを順序付けるだけにします。 - テキストとデータは
data/に置き、5つのシーンにインライン展開しないでください。 - デザイントークンは
styles/tokens.tsに;マジックな hex 値を散りばめないでください。 - 再利用可能なプリミティブは
components/に;シーンごとに重複させないでください。 public/以下のすべてのものにはstaticFile("...")を使用します。
3. 決定論性(絶対ルール)
すべての視覚的状態は現在のフレームから導出されます:
import { useCurrentFrame, useVideoConfig, interpolate, spring } from "remotion";
const frame = useCurrentFrame();
const { fps, durationInFrames, width, height } = useVideoConfig();
アニメーションのドライバーとして禁止: Date.now()、setTimeout、setInterval、requestAnimationFrame、CSS キーフレーム、シードなしの Math.random()、レンダリング間に変化する非同期データ。
ばらつきが欲しい場合のシード付き乱数:
export const rand = (seed: number) => {
const x = Math.sin(seed * 12.9898) * 43758.5453;
return x - Math.floor(x);
};
非同期アセットはフレームレンダリング前に解決する必要があります。delayRender/continueRender を正しく使用し、catch で必ず continue するか、フレーム外でアセットをプリロードします(推奨)。
4. タイミング
durationInFramesは明示的に指定します。30 FPS の場合、10 秒 = 300 フレーム、インデックスは 0 から 299 です。- 一度だけ変換:
const s = (n: number) => Math.round(n * fps)。 - シーン境界は累積的なタイムラインから取得し、シーンごとの丸めは行いません。
<Sequence from={start} durationInFrames={len}>を使用します;コンポジションを超えて伸びていないか確認します。- オーバーラップは意図的に行います;1フレームのギャップは目に見えるフラッシュになります。
- 時間やサイズがプロップスに依存する場合は
calculateMetadataを使用します。
5. アニメーションの技巧
| 動き | プリミティブ |
|---|---|
| 出現/落ち着き | spring または Easing.out(Easing.cubic) を使った interpolate |
| 退出 | Easing.in(Easing.cubic) |
| 対称的な移動 | Easing.inOut(Easing.cubic) |
| 機械的/連続的 | Easing.linear |
| 数字/色/回転 | クランプされた外挿を使った interpolate |
| スタガー | 要素ごとに from をオフセット (30~80 ms) |
const enter = spring({ frame, fps, config: { damping: 18, stiffness: 120, mass: 0.8 } });
const opacity = interpolate(frame, [0, 12], [0, 1], {
extrapolateLeft: "clamp", extrapolateRight: "clamp",
});
すべてに spring を使わないでください。すべてのプロパティをアニメートしないでください。レイアウトプロパティよりも transform と opacity(GPU フレンドリー)を優先してください。短い見出しで少なくとも約0.8~1.2秒の滞留時間を確保し、本文はそれ以上にします。
6. タイポグラフィとデザイン
- タイプスケールを設定し(例:1080p で 96/64/40/28/20 px)、それをどこでも使用します。
@remotion/fontsまたはスターターの文書化されたパターンを使用してpublic/fontsからフォントを読み込み、レンダリング前に準備完了を待ちます。システムフォントへの依存は避けてください。- 行長(約45~75文字)、行高(ディスプレイタイプで1.1~1.4)、トラッキングを確認します。
- 5~8% のセーフマージンを維持します;縦型/ソーシャルフォーマットのプラットフォームUIオーバーレイを確認します。
- ペルシア語/アラビア語: 正しい
dir="rtl"、字形整形可能なフォント、混在する数字/URL を確認し、レンダリングされたフレームを検査します — ヘッドレス Chrome は一部のデザインツールとは異なるテキスト整形を行います。 - 最終的なコピーを一字一句確認します。動画の誤字は出荷バグです。
7. コンポジションとトランジション
- 1ビートにつき1つの焦点;画面全体ではなく、目の動きをアニメートします。
- トランジションの語彙を使用します: カット、6~10フレームのクロスフェード、マスクワイプ、スケールスルー、ブラースルー。意図的に再利用します。
- すべてをディゾルブするよりも、ビートでカットすることを優先します。
- 長い動画の場合は、最初にタイミングチャート(秒 → フレーム → シーン)を作成し、1つのファイルにエンコードします。
8. オーディオとキャプション
import { Audio, staticFile } from "remotion";
<Audio src={staticFile("audio/music.mp3")} volume={0.6} />
- 音を鳴らしたいシーケンスにのみインポートします。
interpolateをvolumeに使ってフェードイン/アウトします;クリックノイズを避けます。- 音楽をボイスオーバーの下にダッキングします;会話の明瞭さを維持します。
- キャプション: ソーシャル用に
<Caption>で焼き付けるか、.srtをエクスポートしてプラットフォームに任せます。セーフエリアと読み取り速度(約15~20文字/秒)を尊重します。 - エンコードされた ファイルでミックスを確認します。プレビューだけではありません。
9. パフォーマンス
- メモリ制限のあるマシンでは同時実行数を減らす:
--concurrency=4。 - 巨大なブラー、フィルターチェーン、巨大なSVG、何千ものDOMノードを避けます;密度の高いグラフィックにはCanvasを使用します。
- 静的バックグラウンドをキャッシュします(
<Freeze>またはプリレンダリング画像)。 - 画像を最適化し(適切なサイズ、サポートされている場合は WebP/AVIF)、動画アセットをトリミングします。
- プレビューは
--scale=0.5と短いフレーム範囲で最初にレンダリングします。
10. バッチおよびデータ駆動型動画
- プロップススキーマを定義し、レンダリング前に検証します。
- データは JSON/CSV に;レイアウトはコンポーネントに保持します。
- テキストをフィット: 最大行数、代替フォントサイズ、切り捨てルール、オーバーフローテスト。
- 同じコンポジションから異なる
--propsで各バリアントをレンダリングします。 - マニフェストを作成し、すべての出力の長さと空でないサイズを検証します。
npx remotion render src/index.ts Main out/acme.mp4 --props='{"brand":"Acme","tagline":"Build faster"}'
11. Blender とのハイブリッド
- Blender ショットを Remotion コンポジションと同じ FPS、解像度、フレーム数でレンダリングします。
- プロジェクトでオフセットが定義されていない限り、Blender フレーム 1 を Remotion フレームインデックス 0 にマッピングします。
- 透明度が必要な場合は、PNG シーケンスまたは ProRes 4444 をエクスポートし、チェッカーボード上でアルファを確認します;MP4 にはアルファがありません。
- カラーパイプラインを一致させます: ブラウザ出力と同じトランスファー/ビュー変換の仮定で Blender パスをエンコードし、コンポジットを検査します。
- パスは
<Video>ではなく<OffthreadVideo>で<Sequence>内に配置し、フレームマップからstartFrom/フレームオフセットを設定します。
12. 納品前の検証
npx remotion compositions src/index.ts # IDと寸法を一覧表示
ffprobe -v error -show_entries format=duration,size \
-show_entries stream=codec_name,width,height,r_frame_rate,pix_fmt,channels \
-of json out/video.mp4
その後、フレーム0、各シーン境界、各トランジション、テキストが多いフレーム、最終フレームを検査します。クリップされたテキスト、欠落したフォント、黒フレーム、オーディオのずれを確認します。エンコード/正規化のレシピについては video-composition を、完全なゲートについては motion-studio/references/QUALITY-CHECKLIST.md を参照してください。
13. よくある失敗モード
- コンポジションが見つからない → エントリファイルかIDが間違っています;
npx remotion compositionsを実行します。 - プレビューでは動作するがレンダリングが空白 → アセットパスが Studio では解決されるがヘッドレスでは解決されない;
staticFileを使用し、public/の大文字小文字を確認します。 - フォントが Times にフォールバック → レンダリング前にフォントがロードされていない;準備完了を待ちます。
- レンダリングごとに出力が異なる → 壁時計時間またはシードなしの乱数。
- OOM または極端に遅い →
--concurrencyを減らし、ブラー/スケールを減らし、レンダリングを分割します。 - オーディオの同期がずれる →
startFromの誤り、fps の不一致、または可変フレームレートソース。