gfx-html は何をしますか?
グラフィックは、ヘッドレスChromeによって1フレームずつレンダリングされ、アルファムービーにエンコードされるHTMLページです。完全なリクエストテキストは$ARGUMENTSに格納されます。最初のトークンは通常、プロジェクトスラッグです。動詞名はビルドコントラクトに従います。python engine/ve.py --helpが競合した場合に優先されます。
このレーンを機能させるルール
すべてのグラフィックは ?t=<秒> の純粋関数です。 CSSアニメーション、GSAPタイムライン、requestAnimationFrame、トランジションは使用しません。ページは location.search から t を読み取り、レイアウトを計算し、1つの静的フレームをレンダリングします。
これはスタイル上の好みではありません。chrome --headless --screenshot は「ページがロードされたように見えるとき」に実行されます。このビルドには仮想クロック、Emulation.setVirtualTimePolicy、beginFrame はありません。そのようにサンプリングされたCSSアニメーションページは、実行のたびに異なるピクセルを返します。これにより、コンテンツアドレス可能なキャッシュ(同じキー、異なるピクセル)が破壊され、目に見えるカクツキが発生します。
t の純粋関数は、同じ単純なループでサンプリングされた場合、決定論的でキャッシュ可能です。これがすべての違いです。
事前に提示する予算
Chromeは定常状態でフレームあたり約430〜470 msでレンダリングし、コールドスタートは7.9秒かかります。30 fpsで5秒のグラフィックは150フレームであり、シングルスレッドで約65秒かかります。エンジンは4つのChromeプロセスを並列化し、フレームごとのPNGをキャッシュするため、変更のないグラフィックの再レンダリングは無料で行われます。ただし、最初のレンダリングは瞬時ではありません。
長いグラフィックを開始する前に、フレーム数と推定時間をユーザーに伝えてください。短いグラフィックを推奨します。6秒間保持するテロップは、6秒間のモーションを必要としません。0.4秒のフェードイン、ホールド、0.4秒のフェードアウトで十分です。
ステップ1 - テンプレートを選択または作成する
テンプレートは presets/graphics/*.html にあります。作成する前に再利用してください。テンプレートは、以下のことを行う単一の自己完結型HTMLファイルです。
location.searchからt(秒)とそのプロパティを読み取ります。- すべての位置/不透明度を
tから純粋な算術演算で計算します。イージング関数は問題ありません。これらは純粋です。 - 透明なボディ上にレンダリングします。背景色を塗ってはいけません。
assets/fonts/のフォントを@font-faceとfile:///URL を使用して使用します。システムフォントに依存しないでください。このボックス上のChromeが解決するフォントは、QCコントロールレンダリングが想定するものと同じではありません。- 1920x1080で、かつプラットフォームのキャプションセーフエリア内で読みやすいこと。
output.platformを確認してください。下3分の1に配置するテロップは、TikTokのUIの下に隠れてしまいます。
レイアウトの詳細、イージング規則、およびプロパティコントラクトは docs/graphics.md にあります。ここでは繰り返しません。
ステップ2 - フレームをレンダリングする
python engine/ve.py gfx <slug>
フレームごとに、エンジンはChromeをargvリストとして呼び出します。おおよそ以下のようになります。
chrome.exe --headless=new --disable-gpu --no-sandbox --hide-scrollbars
--user-data-dir=<win-path>\prof --default-background-color=00000000
--window-size=1920,1080 --screenshot=<win-path>\frame_0007.png
"file:///C:/.../template.html?t=0.233&title=..."
レーン全体を担う2つのフラグがあります。
--default-background-color=00000000は、本物のアルファを生成するものです。確認済み:コーナーピクセルは0 0 0 0を読み取ります。これがないと、不透明な黒が生成され、オーバーレイがビデオを覆い隠します。file:///URLは、実際のWindowsパスである必要があります。Git Bashの$PWDパスは黙って失敗します。3つの異なるHTMLファイルが、空白のダークモードエラーページの同一のmd5を生成し、終了コード0、もっともらしいファイルサイズを返します。これが、QCチェック(g)が既知の空白ハッシュと比較する理由です。
フレームは .cache/html/ にキャッシュされ、キーは sha256(html_content + t + params + renderer + renderer_version) です。テンプレートを変更するとすべてのフレームが無効になります。これは正しい動作です。
ステップ3 - アルファを保持してエンコードする
同じコマンドです。ve gfx はフレームをレンダリングし、1回のパスでエンコードします。別個のエンコード用の動詞はありません。なぜなら、隣にムービーのないPNGシーケンスは、下流で何も使用できない中途半端なアーティファクトだからです。
PNGシーケンスをQuickTime RLE (qtrle、argb) に変換します。ProRes 4444と生のPNGシーケンスもアルファを正しく維持します。VP9-in-WebMは、このビルドではアルファを黙って破棄します。-metadata alpha_mode=1 を使用しても同様です。使用しないでください。また、プローブせずにユーザーのアセットから受け入れないでください。
出力は .cache/ovl/<xx>/<key>.mov に配置され、<key>.json サイドカーファイルが付随します。
ステップ4 - オーバーレイをアンカーする
overlays[] エントリを記述します。id、kind: "html"、template、props、anchor、duration_frames、layer、render です。
anchor は常に {segment_id, offset_frames} です。絶対タイムラインポジションを使用してはいけません。 タイムラインポジションは、有効なセグメントの累積和から導出されます。上流の誰かがセグメントを無効にした瞬間、すべての絶対ポジションが間違ったものになり、すべてのグラフィックがずれます。アンカーされたオーバーレイは、セグメントとともに自動的に移動します。これはエディターが期待する動作です。
layer はコンポジットの順序を決定します。数値が大きいほど手前に表示されます。キャプションは最後に焼き付けられ、グラフィックの上に表示されます。
ステップ5 - 完了と宣言する前に検証する
3つのチェックがあり、すべて低コストです。
- アルファプローブ。 コーナーフレームから1つのraw rgbaピクセルを読み取り、
a = 0をアサートします。QC (d)。 - ブランクページチェック。 フレームがそれぞれ単一のフラットカラーではないことをアサートします。QC (g)。これにより、不正な
file:///URL、読み込みに失敗したフォント、JSエラーが検出されます。これらはすべて、もっともらしいファイルサイズで終了コード0を返します。最初、中間、4分の3のフレームをサンプリングし、すべて が均一である場合にのみ失敗します。ここのすべてのテンプレートは不透明度0で開くため、動作中のグラフィックのフレーム0は正当に空白であり、それだけで判断すると正しいレンダリングが失敗します。
ve gfx は、作成したばかりのものに対して自動的に両方を実行し、いずれかが失敗した場合は終了コード2で終了します。
3. 決定論。 1つのフレームを2回レンダリングし、ハッシュを比較します。それらが異なる場合、テンプレート内の何かが t の純粋関数ではありません。それを見つけてください。このチェックが存在するのは、それがキャッチする障害が、キャッシュされたレンダリングと新しいレンダリングが一致しなくなるまで目に見えないからです。
次に、中間点の静止画をユーザーに表示します。スクリーンショットが1コマンドで取得できるのに、散文でグラフィックを説明しないでください。
障害モード
| 症状 | 原因 | 修正方法 |
|---|---|---|
| オーバーレイがビデオを黒で覆う | --default-background-color がない、またはテンプレートが背景を塗る | フラグを追加する。ボディを透明にする |
| すべてのフレームが同一、もっともらしいファイルサイズ | 不正な file:/// URLによる空白のエラーページ | 実際のWindowsパスを使用する。空白ハッシュに対してアサートする |
| 同じキー、異なるピクセル(実行間) | テンプレートが t の純粋関数ではない | すべてのCSSアニメーションとrAFを削除する |
| テキストが間違った書体でレンダリングされる | システムフォントのフォールバック | assets/fonts/ から @font-face を file:/// URL で使用する |
| エンコード後にアルファが失われる | VP9/WebM | qtrle argb または ProRes 4444 を使用する |
| 上流の編集後にグラフィックがずれる | 絶対タイムラインアンカー | {segment_id, offset_frames} にアンカーする |
| レンダリングに数分かかる | 430 ms/フレームが下限 | グラフィックを短くするか、それを受け入れる。キャッシュにより2回目の実行は無料 |