FrameScript

React コンポーネントとして動画を書き、Studio でプレビューし、ヘッドレス Chromium で書き出す コードファーストなモーショングラフィックス & 動画編集基盤。

これは何か

FrameScript は 「タイムラインを React の JSX で記述する」 動画ツール。 After Effects のようなノードや GUI でなく、<Clip><Video> を 並べた tsx ファイルが動画の「ソースコード」になる。

前提

動かすには Node.js が必要。
プロジェクトの本体(src/)は基本いじらず、project/ 配下を編集していくスタイル。

最小コード

1本だけ動画を流すだけならこれで十分。

project/project.tsx
import { Clip } from "../src/lib/clip"
import { Project, type ProjectSettings } from "../src/lib/project"
import { TimeLine } from "../src/lib/timeline"
import { Video } from "../src/lib/video/video"

export const PROJECT_SETTINGS: ProjectSettings = {
  name: "framescript-minimal",
  width: 1920,
  height: 1080,
  fps: 60,
}

export const PROJECT = () => (
  <Project>
    <TimeLine>
      <Clip label="Clip Name">
        <Video video={{ path: "~/Videos/example.mp4" }} />
      </Clip>
    </TimeLine>
  </Project>
)

3つの要点

1. すべては frame で動く

FrameScript の世界はリアルタイムの「秒」ではなく、整数の フレーム番号で動く。 Studio のシークバーがフレームを進めるたびに、React ツリーが「そのフレームの値」で再描画されるイメージ。

だから seconds(1.5) のようなヘルパーはプロジェクトの fps を見て フレーム数に変換するし、useCurrentFrame() も「今表示されているフレーム」を返す。

2. <Clip> がタイムラインの単位

タイムライン上に並ぶ箱が <Clip>startduration を 指定するか、子要素(<Video>useAnimation)に長さを「報告」させて 自動で長さが決まる。

3. アニメーションは「事前に全部決める」

useAnimation(async ctx => ...) は async/await で書くが、 実際にフレームごとに await されるわけではない。マウント時に最後まで実行されて、 各変数のセグメント(区間)が事前計算される。再生時はそのセグメントから補間値を サンプリングするだけ。

だから「ループ」「永続的な subscribe」「フレームごとの動的分岐」みたいなものは書けない。 シーンの完全なタイムテーブルを async/await で組み立てるのが正しいメンタルモデル。

向いていること / 苦手なこと

得意: モーション、テキストアニメ、ロゴ、キャラ立ち絵の口パク、UI動画、解説動画。
苦手: 物理シミュレーション、ユーザー操作に応じたインタラクション。
後者は別ツールで作って動画として読み込むほうが楽。

このノートの読み方

  1. クイックスタート でプロジェクトを起動する。
  2. プロジェクト構成 でディレクトリの役割を把握する。
  3. 基本コンポーネントアニメーション を読む。ここが本体。
  4. 必要に応じて 動画とサウンドキャラクター3D へ進む。
  5. 書き出し時に何かおかしくなったら 注意点・既知問題 を見る。