film-engine: コードから1フレームずつ描画するフィルム
キットの場所: このスキルのコマンドはすべて
reels-makerフォルダ(template/とtools/を持つgithub.com/thativanng/reels-makerのクローン)から実行してください。プロジェクトにない場合は、まずそのリポジトリの SETUP.md に従ってセットアップしてください。
1段落でわかるコンセプト
ここでの「フィルム」とは、1つのHTMLページであり、1つのルールがあります:window.seek(t) は、時間 t のフレームを毎回、t からのみ正確に描画しなければなりません。画面内の何も実際の時計を読んではいけません。レンダラーは t を30fpsで進め、各フレームを2倍サイズでスクリーンショットし、ffmpegにパイプします。ページは確定論的であるため、再レンダリングは一致します(平均して、レベル値の誤差はわずか、GPUノイズにより単一ピクセルが最大約60レベル移動することがあります)、17.3秒の静止画は動画で表示されるフレームそのものであり、すべてのチェック(film-audit)はフィルムを再生せずに任意の瞬間を確認できます。
ルート(駅を飛ばさないこと)
- 最初にブリーフとルック。 reel-intake は署名済みブリーフとストーリーボード(フォーマット、長さ、サウンド、絶対に登場しないもの)で終了します。reel-style は選ばれたルックで終了します。このスキルのビルド手順を両方なしで開かないでください。
- ストーリーボード。 reel-intake が作成します(時間・画面上の言葉・音声とキャプション・理由;references/brief.md)。あなたが構築する前に、担当者が署名してください。バナーを含むスタイルはバナー列を追加します。
- テストストリップ。 選択したルックで最初の約10秒間を構築します(ウォークスタイルのフィルムは1チャプターを見せるのに15〜30秒かかるかもしれません)。スチルを撮り、承認を得てください。署名されていないルックでフルビルドするのは無駄な作業です。
- フルフィルムをビルド(スタイルパックがシーンの構築方法を指示します)。
- ゲート(film-audit):40fpsでの衝突チェック、ピクセルプローブ、その後独立した監査人。担当者に何も渡す前にこれを行います。
- レンダリング:
node tools/render.mjs --page reels/<name>/page.html --out reels/<name>/out/film-silent.mp4(2倍フレーム、lanczosでスケールダウン、色タグなし)。 - 音声:
python3 template/audio.py out/film.wav(フィルムと同じクロックのキューリスト)。 - 仕上げ:
zsh tools/mux.sh out/film-silent.mp4 out/film.wav out/film.mp4。これにより −14 LUFS、リミッター、タグなしH.264ファイル、およびフィルムと同じ形状の電話プレビュー(短辺720px)が生成されます。 - カバー:
node tools/cover.mjs --page reels/<name>/page.html --out reels/<name>/out/cover.jpg。カバーモードを持つページ(スターターの?cover、configcoverから)はデザインされたスチルを描画します。それ以外のページはT=のフレームを提供します。フィルム自身の形状で保存され、2MB未満に抑えられます。さらに9:16フィルム用に中央の3:4クロップ(Instagramグリッド、報告済み)も生成されます。LinkedInは投稿時のみカバーを受け付けます。その後は投稿のテキストのみ編集可能です(LinkedInヘルプ、「共有した投稿を編集する」、https://www.linkedin.com/help/linkedin/answer/a522811)。そのサムネイル仕様は、動画の形状のJPGまたはPNGで最大2MBです。これは検索サマリーで引用されたLinkedInのヘルプに基づきます。ページ自体は読み込まれないため、未確認として扱ってください。 - 電話プレビューを最初に送信し、次にフルファイルとカバーを送信します。
ページ契約
window.seek(T):フレームTを描画します。アニメーションを行う唯一の場所です。window.ready:フォント、テクスチャ、最初のフレームの後に解決するプロミス。window.DUR:フィルムの長さ(秒)。window.FILM = { w, h, format, safe }:フレームサイズとピクセル単位のクリアゾーン。すべてのツールはこれからウィンドウをサイズ設定するため、ページが自身のフォーマットを所有します。- オプション:
window.cover()はフレームの代わりにカバーを描画し、FILM.coverAtはカバーが載っている瞬間を指定します(tools/cover.mjs は両方を使用します。ない場合はT=のフレームを取得します)。 window.collide(T)とwindow._dbg:film-audit 用のフック(そのスキルを参照)。- ツールはキットフォルダをhttpで提供します(ESモジュールは
file://から読み込めません)。ブラウザでページをライブで見るには、npm run serveして http://127.0.0.1:8765/template/starter.html を開いてください。
フォーマット、スターター、およびその他の言語
template/formats.jsonは4つのサイズ(9:16 1080×1920 · 4:5 1080×1350 · 1:1 1080×1080 · 16:9 1920×1080)、プラットフォーム→フォーマットマップ、および各プラットフォームのクリアゾーンとそのソースを保持します。ブリーフのフォーマット行がここから選択します。- すべてのリールは独自のフォルダ
reels/<name>/に格納されます(gitignore対象):そのブリーフ、ストーリーボード、page.html(スターターまたは film.html のコピー)、reel.jsonまたはcareer.json、そしてout/。ページはキットのルートからフォントとformats.jsonを読み込むため、コピーはそこから機能します。ツールをその場所に向けます:PAGE=reels/<name>/page.html。 template/starter.html+template/reel.jsonは、voxel walk を除くすべてのルックの骨格です。その言葉とタイミングは設定に格納され、?fmt=または設定から自身をサイズ設定し、すべての単語をプラットフォームのクリアゾーンコア内に収めます。?guidesはカバーゾーンを赤で表示します。確認専用です。オンにしたままレンダリングしないでください。これは骨格であり、ルックではありません。reel-style がそのトークンとレイアウトを書き換えます。template/film.html(voxel テンプレート)は4:5のみであり、クリアゾーン(safeは0)を無効にします。そのバナーと字幕は意図的に端近くに配置されるため、safeプローブは常に合格し、監査人の目がチェックとなります。カメラは4:5用にキー設定されています。別の比率では再キー設定とすべてのゲートの再実行が必要です。- 中国語、日本語、韓国語: スターターはGoogle FontsからNoto Sans TCをレンダリング時に読み込みます(設定で使用する文字のみ)、CJKタイプはラテンサイズの約0.72倍で実行されます(それらの文字は全角幅です)。改行したい場所に
\nを書きます。中国語は任意の2文字間で改行されるため、長い行には選択した改行が必要です。template/reel.zh.jsonは実際の例です。他のスクリプトはスタック内に独自のフォントが必要です。
クロックとタイミング
- 1つのフィルムクロックが、シーン、カメラ、バナー、字幕、サウンドを駆動します。後ですべてを再タイミングせずにビートを挿入するには、リマップを使用します。シーンクロックは挿入ポイントで一時停止し、オーバーレイは実際のクロックを維持します。
音声スクリプトも同じテーブルを必要とします。const INS = [[24.0, 5.0, 'detail']]; // シーン時刻24.0で、5秒の挿入ビートを再生 function remap(T) { let sh = 0; for (const [a, len, id] of INS) { if (T < a + sh) return { t: T - sh, ins: null }; if (T < a + sh + len) return { t: a, ins: id, u: T - sh - a, len }; sh += len; } return { t: T - sh, ins: null }; }RT(t)を書き、シーン時刻に挿入長を追加し、すべてのキューをRT(t)に配置します。そうしないと挿入後のすべてのキューがずれます。(テンプレートには挿入がないため、その audio.py は必要ありません。) - イージング: カメラ移動には
eio、到着するものにはeo、歩行や運転にはtrap(台形速度)を使用します。これにより、動き手が端で「パチッ」と止まることがありません。 - カメラキー は絶対
A(pos, target)または主人公の接地点からの追従F(offset, targetOffset)です。キー間をeioでブレンドします。重要なビートではホールドします。常に動くショットは神経質に見えます。
オーバーレイ(DOM内、キャンバスの上)
- バナー: 年、次に会社、役割ピル、さらに現在の年でドットが呼吸するタイムライン。バナーは新しいシーンが画面に表示されたとき(そのセットが上がり、衣装が変わり、主人公が到着したとき)に変わります。コードが構築を開始したときではありません。各変更の前後±1秒のフレームシートでこれを確認してください。
- 字幕: ビートごとに1行のストーリー。キーフレーズは太字で強調。
text-wrap: balanceを使用してください。読者に秒速約3語を与え、高速なカメラ移動が背後にある被写体を露出する前に字幕をフェードアウトさせてください。 - キャラクターに追従する吹き出し: 頭の点を投影し、吹き出しをフレーム内の≥24ピクセルにクランプします。
- エンドカード: 名前、1つのタグライン、得意なこと、1つの引用。背後でシーンがぼやけます。
音声
- キューはフィルムクロック上に、それが属する瞬間の隣に書かれます(歩行脚ごとのステップ、何かが現れるときのチャイム、着地するときのドスン)。
- トランジションに「シュー」という効果音は使わないでください。 安っぽく聞こえます。チャイム、チック、ソフトな衝撃音を使用してください。
template/audio.pyのデフォルトのベッドはサイン波から生成されるため、どこでも無料で使用できます。誰かがAI生成トラックを持ち込んだ場合、そのライセンスを確認してください。一部のモデルのウェイトは非商用利用のみ許可しています。- ラウドネス: 2パス loudnorm(−14 LUFS)(測定、その後線形適用)後、リミッター。1パスではオーバーシュートします。
私たちに数日を費やさせたレンダリングの事実(詳細は references/gotchas.md)
- 2倍でレンダリングしてスケールダウン。 EffectComposer はキャンバスのアンチエイリアシングをドロップするため、1倍レンダリングではどこもギザギザのエッジになります。
- MP4に色タグを付けない。 JPEGパイプはフルレンジとしてタグ付けされ、一部のプレーヤーで色がずれます。フィルタで
setparams=...=unknownを使用します。 - 同じ平面内の2つの顔がちらつく(Zファイティング)。前面のものに深度オフセットを与えてください。
- フォントはロードしておく(
document.fonts.load)こと。キャンバステキストを描画する前にロードしないと、静かにフォールバックします。 - GPUオン をヘッドレスChromiumで(macOSでは
--use-angle=metal)。これがないとレンダリングは約10倍遅くなります。
各ステップでプロンプトなしで作業する
担当者はキットの許可ルールに一度だけ同意しました(SETUP.md ステップ4)。その範囲内に収めてください。そうしないと、何度も承認を求められます。
- Write ツールと Edit ツールを使用して ファイルを書き込み、変更します:ページ、reel.json、ブリーフ、ストーリーボード、AUDIT.md。Python やシェルスクリプト、heredoc、
sed -iで生成しないでください。それらはすべて承認プロンプトになります。 - キットのツールで測定する(スチル、プローブ、シート、コライド、レンダリング、カバー)。使い捨ての
python3 -cスニペットは使わないでください。 mkdir、ループ、チェーンは不要: すべてのツールは自身の出力フォルダを作成し、1回の呼び出しで時間のリストを受け取ります(stills.mjs … 1.5,6,12)。- リール独自のスクリプト(サウンドスクリプト、ヘルパー)は
reels/<name>/に配置し、python3 reels/<name>/audio.pyまたはnode reels/<name>/x.mjsとして実行します。これらはルールでカバーされます。
コマンド
各ツールを1つのプレーンなコマンド(フラグ、先頭に VAR=… なし、ループなし、&& チェーンなし)として実行してください。これにより、担当者の許可ルール(node tools/*)がそれをカバーし、毎回承認を求められません。環境変数はスクリプトに対して引き続き機能します。
npm run doctor # まずこのマシンをチェック
npm run demo # 12秒の証明:out/demo/
node tools/stills.mjs "2,8.5,15" # 2倍スチル → out/stills(voxel テンプレート)
node tools/stills.mjs --page template/starter.html --format 16:9 1.6 # 別の比率のスターター
node tools/stills.mjs --page template/starter.html --cfg reel.zh.json 1.6 # 別の設定(ここでは中国語)
node tools/stills.mjs --dsf 1 --out out/chk 2,8.5 # シート用のクイック1倍フレーム
python3 tools/sheet.py out/chk/sheet.jpg 6 300 out/chk/t*.jpg
node tools/render.mjs --page reels/<name>/page.html --out reels/<name>/out/film-silent.mp4
python3 template/audio.py out/film.wav
zsh tools/mux.sh out/film-silent.mp4 out/film.wav out/film.mp4