説明用アニメーション
動画は src/timeline.ts 内のシーンが順に並んだものです。3種類あります:
intro: フックカード。最初の行がフックで大きく表示され、読み上げられるにつれて単語が光ります(キャプションを兼ねます)。anim: レジストリから1つのアニメーションコンポーネントを、シーンのナレーションラインに同期させて配置します。outro: AGILabs バッジ、「javieraguilar.ai」、およびSETTINGS.articleTitleの記事タイトルを表示する閉じカード。
タイムラインの作成
import type { Cuts } from './types.ts';
import { L, anim, intro, outro, say, videos } from './narrate.ts';
const build = (): Cuts => ({
main: [
intro('hook', [say(0.4, 'EN hook line.', 'ES hook line.')]),
anim(
'result',
'BarCompare',
{ bars: [{ label: L('With the reason', 'Con el porqué'), value: 14, display: '14/20', highlight: true },
{ label: L('Without it', 'Sin él'), value: 4, display: '4/20' }], max: 20 },
[say(0.3, 'First line.', 'Primera línea.'), say(0, 'Second line.', 'Segunda línea.')],
{ min: 4 },
),
outro('outro', [say(0.4, 'More at javieraguilar.ai.', 'Más en javieraguilar.ai.')]),
],
});
export const VIDEOS = videos(build);
export const TIMELINE = VIDEOS.en.main;
say(at, en, es, spoken?): 1つのナレーション行。atは開始可能な最も早いシーン秒数です。行が重なることはありません(0.35 秒のギャップ)。シーンは最後の行が終了してから 0.8 秒後、またはminの長さまで続きます。spoken({ en?, es? }) は、キャプションテキストと異なる場合に TTS が読み上げる内容です(narration参照)。- ビート. シーン内の各行の開始時間がビートです。コンポーネントはビート i でステップ i を再生します(バー i が成長、ノード i が出現、タイル i がポップイン)。したがって、表示したいステップごとに1行ずつ記述します。TTS 前は、ビートは長さの推定値から得られます。
npm run ttsの後は、実際の音声から得られるため、ナレーション後にスチルを再確認してください。 L(en, es): 画面上のバイリンガルラベル。プレーンな文字列は両方の言語で使用されます。- シーンIDは一意である必要があります。ラインキー(
<scene>-01、...)は音声ファイルの名前となります。 animのopts.chapterはシーンに保存されますが、まだどのコンポーネントでも描画されません。- 変更後は毎回
npm run lintを実行してください。targetSecondsに対する長さ(±20%)、キャプションキューが 0.8 秒未満または 17 文字/秒を超えていないか、レジストリにないコンポーネント名がないかをチェックします。
コンポーネントカタログ
すべてのコンポーネントは、シーンから t、beats、dur、lang、vertical を受け取ります。以下の props はタイムラインから渡されます。画面に表示される数字は、記事の正確な形式を使用します。記事に「14/20」「0.0018」「83%」と書かれている場合は、計算されたテキストではなく display / 文字列の value を優先してください。
| コンポーネント | 用途 | Props |
|---|---|---|
Counter | 1つの見出し数字をカウントアップし、その下にラベルを表示 | value: number, label: Label, prefix?, suffix?, decimals? (0-8), beat?(カウントを開始するビートのインデックス、デフォルト0) |
BarCompare | 2〜5本の水平バーをビートごとに1本ずつ成長表示。ハイライトされたバーはアクセントグラデーション | bars: { label: Label; value: number; display?: string; highlight?: boolean; at?: number }[], max?(スケールの上限、デフォルトは最大値), unit?(display がない場合に追加) |
FlowDiagram | 順番に表示されるボックスと矢印。broken エッジは破線でミュートされ、ギャップあり | nodes: { id; label: Label; at?: number }[], edges: { from; to; label?: Label; broken?: boolean }[], `layout: 'vertical' |
KeyQuote | キーセンテンスを単語ごとに表示。強調された単語はアクセントカラーで下線付き | text: Label, emphasis?: string[](単語またはフレーズ、大文字小文字と句読点を無視して一致), beat? |
StatGrid | 2〜4つの数値タイルをビートごとに1つずつポップイン表示 | stats: { value: string; label: Label; at?: number }[] |
バー、ノード、タイルの at は、その要素を自身のビートではなくシーン秒数に固定します。ビートや at がないステップは、前のステップから 0.6 秒後に続きます。すべてのコンポーネントはシーン終了までに終了するように調整されています。最後のフレームには常に完了状態が表示されます。
全ライブラリを確認するには: npm run studio を実行して Gallery-vertical を開くか、そのスチルをレンダリングします。
カスタムコンポーネントの追加
スクリプトがシーンを「bespoke」とフラグ付けした場合:
- まず状態を、テスト付きで作成。 props の型と、プレーンな数値と文字列を返す純粋な
frameState(props, t, beats, dur)を含むsrc/anim/<Name>.state.tsを作成します。そこには Remotion や React のインポートはありません。src/anim/steps.ts(sceneTime、stepTimes、fit、progress、beatAt、easeOutCubic)上に構築し、以下の要件を満たします: 任意のtで有限値、progress フィールドは [0, 1] の範囲、最初のビートより前には何も表示されない、t = durで終了状態になる。 test/anim.test.tsのCASESにケースを追加し(および自身の動作をテストするテスト)、npm testを実行します。これは、t < 0、すべてのビート、dur、durを超えた場合について、欠落、遅延、非常に短いビートを含む状態をチェックします。- 描画 を
src/anim/<Name>.tsxで行います:frameStateを呼び出し、<Stage vertical={...}>内に描画し、src/brand.tsのブランドトークン(C、GRADIENT、alpha)と Inter フォントを使用します。新しい色やフォントは追加しないでください。 - 登録 を
src/anim/index.tsのANIMSに行います。ANIMSは名前のプレーンなオブジェクトリテラルのままにしてください。npm run lintがソースから読み取ります。 - オプションでサンプルを
src/Gallery.tsxに追加します。再利用可能な場合、プラグインのテンプレートに戻す必要があります。
生成画像. ほとんどのシーンはコード(ブランドトークンを使用した SVG と CSS)で描画する必要があります。シーンで本当に生成画像(背景、ベース画像、テクスチャ部分)が必要な場合、画像モデル(例: Codex CLI の画像生成)で作成できます。public/ の下に保存し、staticFile() で読み込み、ブランドパレット内に収め、スチルを確認します。
縦の安全領域 (1080x1920)
- プラットフォーム UI は上部約 220 px と下部約 380 px をカバーします。側面は 72 px を確保します。
- アニメーションはステージ内のみに描画されます: y = 280(AGILabs バッジの下)から y = 1280(2つのキャプション行の上)まで、幅 936 px。
Stage/stageOf()でそのボックスを取得できます。 - キャプションはステージの下に、最大2行、約32文字、幅約900 px 以内で配置されます。
スチル: 目視で確認
スチルをレンダリングし、動画をレンダリングする前に すべての PNG を読んで ください。クリーンな lint やビルドでは、オーバーフロー、クリッピングされたテキスト、誤った数字は表示されません。
npx remotion still src/index.ts Main-EN-vertical out/stills/f0150.png --frame=150
各シーンの最後のステップが再生された後に1枚、さらに約3秒ごと(30 fps で90フレームごと)に1枚のスチルを取得します。確認項目: AGILabs バッジ以外のブランディングがないこと、安全領域の外に何もないこと、テキストがボックスからあふれていないこと、すべての数値が記事と一致していること、画面上のキャプションがその瞬間のアニメーションと一致していること。