以下の内容はhttps://www.randpy.tokyo/entry/remotion-1-outlineより取得しました。


React で動画を作れる Remotion を触ってみたので全体像をまとめる【Remotion 第1回】

youtu.be

📚 Remotion シリーズ 全8回の記事一覧

  1. ▶ 第1回: 全体像をまとめる(この記事)
    Composition / AbsoluteFill / Sequence で動画の骨組みを作る
  2. 第2回: Hooks を理解する
    useCurrentFrame / useVideoConfig でフレーム番号と設定を取得する
  3. 第3回: アニメーションを作る
    interpolate / spring でフレーム番号を CSS の値に変換する
  4. 第4回: 素材を使う
    画像・動画・音楽素材を組み込む
  5. 第5回: テロップを入れる
    テキストオーバーレイの作り方
  6. 第6回: シーンを構成する
    Series / TransitionSeries でシーン切り替えとトランジション
  7. 第7回: GitHub Actions で自動レンダリング
    CI/CD で動画レンダリングを自動化する
  8. 第8回: 応用テクニック(準備中)
    GIF・静止画書き出し / FFmpeg カスタマイズ / Lambda / 3D

はじめに

「Reactで動画が作れる」と聞いて、ちょっと興味が湧いたので触ってみました。

Remotion というフレームワークで、React のコンポーネントをそのまま動画にできるそうです。普段は PythonやGo案件が多く、React は最近ちょくちょく触っている程度。Remotion に至っては完全に初見です。

今回はプロジェクトを作って中身を読み解いてみたので、そこで理解した仕組みをまとめておきます。

触ってみてまず驚いたのが、Remotion は 「AI エージェント時代の動画生成」を前提に設計されている ということ。 人間が Premiere Pro のような GUI で操作するのではなく、コードで動画を記述し、そのコードもAI に生成させることを想定しているんですね。

プロジェクト作成時に「Claude などの AI エージェント向けのベストプラクティス集」が自動でダウンロードされるオプションがあるのも、その設計思想の表れかなと…。今の時代を感じます!

環境構築

前提条件

Remotion を使うには、Node.js がインストールされている必要があります。

  • Node.js: バージョン 16 以上(機能によっては Node 20+ 推奨/必須のものもある)

ちなみに、筆者の環境は WSL2 の Ubuntu。 Windows でも Mac でも、Node.js が動けば問題なく使えるでしょう。

プロジェクト作成

Remotion のプロジェクト作成は1コマンドで完了します。

npx create-video@latest

Add agent skills? の画面
Add agent skills? の画面

対話形式でプロジェクト名やテンプレートを聞かれるので、それぞれ入力・選択します。

テンプレートは今回はデフォルトの Hello World を選びました。あとは、基本的に Enter キーを押していくだけでセットアップが完了します。

npm run dev

npm run dev を実行すると Remotion Studio というプレビュー画面がブラウザで開きます。ここでリアルタイムに動画を確認しながら開発できるのが便利ですね。

Remotion Studio の画面
Remotion Studio の画面

動画の書き出しは以下のコマンドです。

npx remotion render HelloWorld out/video.mp4

これだけで mp4 が生成されます。環境構築で詰まるポイントは特にありませんでした! (この記事のトップで貼り付けている動画は、このコマンドで生成したものを YouTubeに置いたものです。)

AI エージェント向けの skills が自動でダウンロード!

プロジェクト作成時に、こんな質問が表示されます。

Add agent skills?

create-videoのコマンド実行画面
create-videoのコマンド実行画面

これは Claude などの AI エージェント向けのベストプラクティス集で、yes を選ぶと .claude/skills/remotion-best-practices/ ディレクトリなどに自動でダウンロードされます。

中身は Markdown で書かれた「AI にコードを書かせるための設計ドキュメント」になっています。

.claude/
└─ skills/
   └─ remotion-best-practices/
      ├─ skill.md
      └─ rules/
         ├─ assets.md
         ├─ videos.md
         ├─ transitions.md
         └─ ...

人間向けのドキュメントとは別に、AI 向けの構造化されたルール集 が最初から用意されているのが面白いですね。 「動画を AI に生成させる」前提で設計されているフレームワークなんだな、と実感します。

プロジェクト構成

テンプレートで生成されるファイル構成はこうなっています。

src/
├── index.ts          ... エントリーポイント(起動地点)
├── Root.tsx          ... 動画の登録簿
├── HelloWorld.tsx    ... メインの動画コンポーネント
└── HelloWorld/
    ├── Logo.tsx      ... ロゴのアニメーション
    ├── Title.tsx     ... タイトル文字のアニメーション
    ├── Subtitle.tsx  ... サブタイトルのアニメーション
    ├── Arc.tsx       ... ロゴの円弧パーツ
    ├── Atom.tsx      ... ロゴの中心パーツ
    └── constants.ts  ... 定数

データの流れは一方向で、

index.ts → Root.tsx → HelloWorld.tsx → Logo / Title / Subtitle
(起動)     (登録簿)   (メインの動画)   (個別の部品)

という構造になっています。index.ts は3行だけで Root を登録して終わり。実質的に触るのは Root.tsx 以降です。

import { registerRoot } from "remotion";
import { RemotionRoot } from "./Root";

registerRoot(RemotionRoot);

Remotion の根本的な考え方

Remotion の考え方はシンプルで、

動画 = 1秒間に N 枚の画像(フレーム)の連続

この N(fps: frames per second)は設定可能で、30fps なら1秒間に30枚、60fps なら1秒間に60枚の画像を生成します。一般的な動画は 30fps、滑らかな動きが必要なら 60fps、映画的な見た目なら 24fps といった具合ですね。

Remotion は「今は何フレーム目か」を教えてくれます。 開発者はそのフレーム番号に応じて画面に何を表示するかを返すだけでOKです。

(このあたりの実装方法は、次回以降の記事で詳しくまとめます)

Root.tsx = 動画の設定ファイル

Root.tsx は「どんな動画があるか」を定義する登録簿です。Rootで定義されているの <Composition> それぞれが1本の動画に対応します。

// Root.tsx 
<Composition
  id="HelloWorld"
  component={HelloWorld}
  durationInFrames={150}
  fps={30}
  width={1920}
  height={1080}
  schema={myCompSchema}
  defaultProps={{
    titleText: "Welcome to Remotion",
    titleColor: "#000000",
    logoColor1: "#91EAE4",
    logoColor2: "#86A8E7",
  }}
/>

<Composition
  id="OnlyLogo"
  component={Logo}
  durationInFrames={150}
  fps={30}
  width={1920}
  height={1080}
  schema={myCompSchema2}
  defaultProps={{
    logoColor1: "#91dAE2" as const,
    logoColor2: "#86A8E7" as const,
  }}
/>

Hello World というテンプレートでは、以下の2つの動画(Composition)が定義されています。

  • HelloWorld: タイトルテキストとロゴが入ったメイン動画
    • 動画の実体は、HelloWorldコンポーネントで実装
  • OnlyLogo: ロゴだけの動画
    • 動画の実体は、Logoコンポーネントで実装

1つの Root に複数の <Composition> を置くこともできます。Remotion Studio のサイドバーにそれぞれ表示されるので、パーツ単体の開発にも使えて便利ですね。

Remotion Studio のサイドバーに表示される Composition 一覧
Remotion Studio のサイドバーに表示される Composition 一覧

各パラメータの役割

パラメータ 意味
id 動画の識別名。レンダリング時に npx remotion render HelloWorld のように指定する
component 描画を担当するコンポーネント
durationInFrames 動画の全フレーム数。fps と合わせて動画の長さが決まる
fps 1秒あたりのフレーム数
width / height キャンバスの解像度(px)
schema props の型定義(後述)
defaultProps コンポーネントに渡すデフォルト引数

注意点として、Composition はキャンバスの解像度と時間を決めるだけで、中身の配置はすべて各コンポーネント内で CSS で行います。

schema と defaultProps

schema は zod で書く props の型定義です。

export const myCompSchema = z.object({
  titleText: z.string(),
  titleColor: zColor(),
  logoColor1: zColor(),
  logoColor2: zColor(),
});

Python でいうと pydantic の BaseModel に近いですね。

class MyCompSchema(BaseModel):
    title_text: str
    title_color: Color
    logo_color1: Color
    logo_color2: Color

ここで、定義した schema は Remotion Studio の GUI 生成(色のピッカーやテキスト入力の自動表示)や、CLI からの props バリデーションに使われるようです。

Remotion Studio の props 自動生成画面
Remotion Studio の props 自動生成画面

なので、ある程度変数を決めておいて、あとはGUIで値を入れ替えながらプレビューする、という使い方ができます。

HelloWorld.tsx のコード構造を読み解く

ここまでで Root.tsx の役割(動画の設定ファイル)を理解しました。次は、実際に動画の中身を描画する コンポーネントを見ていきましょう。

構成要素:AbsoluteFill と Sequence

HelloWorld.tsx の return 部分を見ると、主に AbsoluteFillSequence の2つの要素で構成されています。

役割の違い:AbsoluteFill は位置(WHERE)を指定し、Sequence は時間(WHEN)を指定します。

// HelloWorld.tsx
return (
  <AbsoluteFill style={{ backgroundColor: "white" }}>
    <AbsoluteFill style={{ opacity }}>
        <AbsoluteFill style={{ transform: `translateY(${logoTranslation}px)` }}>
          <Logo logoColor1={logoColor1} logoColor2={logoColor2} />
        </AbsoluteFill>
      {/* Sequences can shift the time for its children! */}
      <Sequence from={35}>
        <Title titleText={propOne} titleColor={propTwo} />
      </Sequence>
      {/* The subtitle will only enter on the 75th frame. */}
      <Sequence from={75}>
          <Subtitle />
        </Sequence>
    </AbsoluteFill>
  </AbsoluteFill>
);

AbsoluteFill:空間の制御(レイヤー)

<AbsoluteFill>WHERE(どこに配置するか) を制御します。style プロパティで位置を指定します。

// 画面全体に広がる背景レイヤー
<AbsoluteFill style={{ backgroundColor: "white" }}>
  <p>背景</p>
</AbsoluteFill>

// 中央に配置(flexbox)
<AbsoluteFill style={{ justifyContent: "center", alignItems: "center" }}>
  <Title />
</AbsoluteFill>

// Y軸方向に移動(transform)
<AbsoluteFill style={{ transform: `translateY(-150px)` }}>
  <Logo />
</AbsoluteFill>

styleで位置(top, left, bottom, right)や配置方法(justifyContent, alignItems)、変形(transform)を指定することで、画面上のどこに表示するかが決まります。

また、次の記事で詳しく扱いますが、Remotion では useCurrentFrame() で現在のフレーム番号を取得することができます。 その値から transform などの style を動的に変化させることで、アニメーションを実現できます(少しずつ位置をずらすイメージ)。

複数の <AbsoluteFill> を重ねると Photoshop のレイヤーのように重なります。

レイヤー構造(上が前面):
┌─────────────────────────────────────┐
│ AbsoluteFill (opacity)              │
│  ├─ AbsoluteFill (Logo + transform) │ ← レイヤー1
│  ├─ Sequence (Title)                │ ← レイヤー2
│  └─ Sequence (Subtitle)             │ ← レイヤー3
├─────────────────────────────────────┤
│ AbsoluteFill (backgroundColor)      │ ← 背景レイヤー
└─────────────────────────────────────┘

Sequence:時間の制御(タイミング)

<Sequence>WHEN(いつ表示するか) を制御します。fromdurationInFrames で時間を指定します。

// frame 0 から 35フレーム間表示
<Sequence from={0} durationInFrames={35}>
  <Logo />
</Sequence>

// frame 35 から表示開始(終了は指定しない = 最後まで)
<Sequence from={35}>
  <Title />
</Sequence>

// frame 75 から 75フレーム間表示
<Sequence from={75} durationInFrames={75}>
  <Subtitle />
</Sequence>

fromで開始フレーム、durationInFramesで表示時間(長さ)を指定することで、いつ表示するかが決まります。

timeline:  0 --------- 35 -------- 75 --------- 150
           [= Logo  =] [=== Title ============]
                                  [= Subtitle =]
  • Logo: frame 0 から 35 まで表示
  • Title: frame 35 から表示開始
  • Subtitle: frame 75 から表示開始

ちなみに、GUIでは、このSequence がタイムライン上のクリップに相当します。Hello Worldプロジェクトだと、2つの Sequence がタイムラインに表示されています。

Remotion Studio のタイムライン画面
Remotion Studio のタイムライン画面

注目すべき点: HelloWorld.tsx では、Logo コンポーネントは <Sequence> でラップされていないため、タイムラインには表示されません。しかし、実際には frame 0 から画面に表示されています。

GUI上で表示したい場合は、Logo コンポーネントも <Sequence> でラップしておきましょう。 (なぜ、このテンプレートがこのようになっているのかは分からないのですが、個人的にはすべて <Sequence> でラップしておいた方が良いと思います)

これらを組み合わせて1本の Composition を構成

HelloWorld.tsx のコードは、AbsoluteFill でレイヤーを作り、Sequence でタイミングを制御して、1本の動画を構成 しています。

┌── HelloWorld (Composition) ──────────────┐
│                                           │
│  AbsoluteFill                             │
│   ├─ AbsoluteFill     → Logo             │
│   ├─ Sequence from=35 → Title            │
│   └─ Sequence from=75 → Subtitle         │
│                                           │
│  ※これで1本の動画が完成                   │
└───────────────────────────────────────────┘

また、Remotion では JSX の記述順 で各要素の重なり順が決まります。

<AbsoluteFill>
  <Video />     {/* 背面に配置 */}
  <Title />     {/* 前面に配置(後から書いた方が前面) */}
</AbsoluteFill>

後から書いたものが前面に表示されます。HTML の描画順と同じですね。

Title.tsx を例に:React と Remotion の関係

個々のコンポーネント(Logo, Title, Subtitle)は 普通の React コンポーネント として定義されています。Title.tsx を見てみましょう。

export const Title: React.FC<{
  readonly titleText: string;
  readonly titleColor: string;
}> = ({ titleText, titleColor }) => {
  const videoConfig = useVideoConfig();
  const frame = useCurrentFrame();

  const words = titleText.split(" ");

  return (
    <h1 style={title}>
      {words.map((t, i) => {
        const delay = i * 5;
        const scale = spring({
          fps: videoConfig.fps,
          frame: frame - delay,
          config: { damping: 200 },
        });

        return (
          <span key={t} style={{ color: titleColor, transform: `scale(${scale})` }}>
            {t}
          </span>
        );
      })}
    </h1>
  );
};

React の部分

  • React.FC<...> で型定義された関数コンポーネント
  • props で titleTexttitleColor を受け取る
  • JSX で <h1><span> を返す

これは普通の React です。 Web 開発の知識がそのまま使えます。

Remotion の部分

HelloWorld.tsxでは、以下のような Remotion 特有の Hooks や関数を使っています。

  • useCurrentFrame() — 今のフレーム番号を取得(Remotion 特有)
  • useVideoConfig() — 動画の設定(fps, durationInFrames など)を取得(Remotion 特有)
  • spring() — フレーム番号からアニメーション値を計算(Remotion 特有)

Remotion 特有の Hooks を使うだけで、React コンポーネントが動画になります。

なお、useCurrentFrame / useVideoConfig などの Hooks の詳細は 次の記事でまとめているので、そちらもぜひ!

www.randpy.tokyo

最初勘違いしたところ

Root.tsx に複数の <Composition> が書いてあるので、「それらが重なって1本の動画になる」と思ってしまいました。Premiere Pro でいうと、「複数のクリップを重ねてレイヤーにする」イメージですね。

// これで2つが重なって1本の動画になる…?
<Composition id="HelloWorld" ... />
<Composition id="OnlyLogo" ... />

前述した通り、各 <Composition> = 完全に独立した1本の動画 です。そして、その各動画の中で、さらに AbsoluteFill と Sequence を組み合わせてレイヤーやタイミングを制御していく、という構造になっています。

書き出すときも、id を指定してそれぞれ別のファイルにします。

# HelloWorld だけを書き出し
npx remotion render HelloWorld out/video1.mp4

# OnlyLogo だけを書き出し
npx remotion render OnlyLogo out/video2.mp4

まとめ

ここまで読んできて、Remotion は思った以上にシンプルだと分かりました。

動画編集ツールというと複雑なUIや独自の概念を覚える必要があるイメージですが、Remotion は React の知識があればほぼそのまま使えます。というより、普通の React コンポーネントを書いているだけで動画になるというのが正しいですね。

各要素はReactのコンポーネントで書いて、それを AbsoluteFill と Sequence で配置と時間を制御する。あとは Remotion 特有の Hooks を使ってフレーム番号に応じた見た目を返すだけです。

まず押さえるべきポイントは以下の3つ。

1. Composition = 動画の設定ファイル

Root.tsx<Composition> を定義して、解像度・fps・フレーム数を指定する。これが1本の動画の「器」になります。複数の <Composition> を書けば、それぞれが独立した動画として扱えます。

2. AbsoluteFill と Sequence で配置と時間を決める

  • AbsoluteFill → WHERE(どこに配置するか)を style で指定
  • Sequence → WHEN(いつ表示するか)を fromdurationInFrames で指定

この2つを組み合わせるだけで、レイヤー構造とタイミング制御ができます。

3. React + Remotion Hooks

コンポーネント自体は普通の React です。useCurrentFrame()useVideoConfig() といった Remotion 特有の Hooks を使うことで、「フレーム番号に応じた見た目を返す」コンポーネントになり、それが動画として出力されます。


今回は HelloWorld テンプレートのコードを読み解いて、Remotion の基本構造を理解しました。

次は実際に動画を作るための実践的な機能に入ります。

www.randpy.tokyo




以上の内容はhttps://www.randpy.tokyo/entry/remotion-1-outlineより取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14