プロダクトローンチビデオ
モーショングラフィックスがストーリーを牽引し、すべての「製品」ピクセルは実際のアプリケーションでレンダリングされる、約40秒のフィルムを生成します。
このスキルは、人々が陥りがちな誤った二者択一を解決するために存在します。
- 純粋なモーショングラフィックスフィルムはプロフェッショナルに見えますが、何も証明しません — 実際の製品がありません。
- 生のスクリーンレコーディングはすべてを証明しますが、アマチュアに見えます — モーションデザインがありません。
答えはそのどちらでもありません。Remotion がマスタータイムラインであり、製品ショットはヘッドレスブラウザで実際のアプリケーションを操作してキャプチャされたリアルなフレームです。
製品の隣に小さな Remotion プロジェクトを構築します。共有キャプチャツールキットとプリミティブ、アプリのフィルムごとに1つのディレクトリ(ブランド、ショット、キャプチャスクリプト、タイムライン)を持ちます。推奨されるレイアウトについては references/toolkit.md を参照してください。
絶対条件
コードを書く前にこれらを読んでください。それぞれが実際のデバッグ時間を要したものであり、どれも黙って失敗します。つまり、もっともらしく見える出力が生成されますが、それは間違っています。
キャプチャ
| 落とし穴 | 何が起こるか | 修正方法 |
|---|---|---|
setViewport({deviceScaleFactor: 2}) | page.screencast() がシステムの DPR で ffmpeg フィルターチェーンを計測するため、1× チェーンを構築し、Retina のディテールを破棄します。エラーは発生しません。 | ブラウザに強制する: --force-device-scale-factor=2 + ビューポート内で deviceScaleFactor: 0 (0 = "システムデフォルト")。 |
| ヘッドレスではカーソルが表示されない | page.mouse.move() は CDP イベントをディスパッチし、ページはそれを認識しますが、何も描画されません。 | evaluateOnNewDocument を介して DOM カーソルを注入します。Remotion でコンポジットするのではなく、ページ内に配置します。そうすれば、すべての Remotion 変換(フレームインセット、ズームパンチ)が実際の録画とまったく同じようにスケーリングされます。スプライトを使用するとすべての変換を反転する必要があり、6px のずれは壊れているように見えます。 |
| ヘッドレスにはGPU がない | WebGL/three.js コンテンツは空白または黒いパネルとして記録されます。 | --use-gl=angle --use-angle=swiftshader --enable-unsafe-swiftshader。"コンテキストが存在したか" だけでなく、ピクセルの読み戻しで確認します。 |
| SwiftShader もページをコンポジットする | 2560x1440 をコンポジットするソフトウェア GL ドライバーは、タブ全体を約8fpsに制限するため、アニメーションショットはスライドショーとして記録されます。これは低速な製品として認識され、キャプチャのバグとは思われないため、誰もフラグを疑いません。 | --disable-gpu-compositing を追加します。Skia の CPU ラスタライザーはプレーンな 2D ではるかに高速で、WebGL は引き続き動作し、A/B の静止画は同一です。同じページで測定: 8.2fps → 60.1fps。 |
| 目視でスムーズさを判断する | 重複フレームはコンタクトシートでは問題なく見え、1フレームずつスクラブしても問題ありません。再生時にのみ明らかになり、その時にはすでにレンダリングされています。 | 異なるフレームをカウントします: ffmpeg -i take.mp4 -vf mpdecimate,showinfo -f null - 2>&1 | grep -c pts_time。ファイルのフレーム数より大幅に少ない場合は、スタッターがあることを意味します。 |
page.mouse.click(x, y, {clickCount: 2}) | clickCount メタデータを運ぶ1回の押下を送信します。Chrome は dblclick を合成することはありません。60ms 間隔の2回の個別のクリックも合成しません。 | アプリが実際の dblclick を必要とする場合は、目に見えるカーソルモーションのためにクリックし、次にフレーム内の要素自身の座標でイベントをディスパッチします。 |
iframe 内をクリックした後に page.keyboard.type() を使用する | キーは親ページがフォーカスしているものに送られます。親がキーをアプリに転送する場合(矢印キーナビゲーション、ショートカット)、入力はテキストを入力する代わりに、静かに UI を操作します。 | フレームに入力します: frame.type(selector, text)。 |
DOM 作業を行う evaluateOnNewDocument | ドキュメントの開始時に実行され、document.head と document.documentElement の両方が null になる可能性があります。ガードされていない appendChild はスローされ、そのスクリプト内の後続のすべてを静かに中断します。 | ガードし、DOMContentLoaded まで延期します。 |
| ナビゲーションの記録 | 有用な秒数をファイルの奥深くに埋め、中間ファイルを肥大化させます。 | 各ショットを setup(記録しない)と action(記録する)に分割します。 |
| マーカータイムスタンプを信頼する | Screencast は可変フレームレートです。エンコードされたタイムラインは実時間に対して圧縮されるため、22秒のマーカーはファイル内では22秒の位置にありません。 | マーカーを使用しておおよその位置を特定し、フレームを抽出して確認することで startAt を選択します。 |
| リモート/ホットリンクされたアセット | サードパーティの CDN が断続的にキャプチャブラウザを拒否します。画像グリッドは空の透明度チェッカーボードとしてペイントされ、製品が壊れているように見えます。 | 画像を待機して警告し、それらを避けるようにショットをフレーミングします。空白のアートが含まれるテイクを出荷しないでください。 |
アプリシェル内での window.scrollTo | 多くのシェルは内部要素(<main class="overflow-y-auto">)をスクロールし、ウィンドウはスクロールしません。ウィンドウのスクロールは静かなノーオペレーションであり、ショットは決して動きません。 | 実際のスクローラーを見つけ、その scrollTop を設定します。 |
| クリック座標の推測 | アプリは特定のノードでのみインタラクションを受け付けることがよくあります(例えば、リーフ要素(childElementCount === 0)のみを受け付けるインラインエディターで、見出しがテキストをスパンでラップしている場合など)。視覚的に明白なターゲットをクリックしても何も起こりません。 | アプリ自身のソースからルールを読み取り、ページに有効なターゲットがどこにあるかを尋ねます(frame.evaluate)。フレーム座標を iframe の測定されたボックスを介してページ座標にマッピングします。 |
レンダリング
| 落とし穴 | 何が起こるか | 修正方法 |
|---|---|---|
| 中間トランスコードのスキップ | Remotion は任意にシークします。通常の GOP では、すべてのシークは以前の I フレームからデコードされます。3分のレンダリングが40分になります。 | オールイントラにトランスコードします: -c:v libx264 -crf 14 -g 1 -keyint_min 1 -sc_threshold 0 -pix_fmt yuv420p。さらに、Chrome がブランドカラーをシフトしないように、明示的な bt709 タグを追加します。 |
page.screencast({format:'mp4'}) | フラグメント化された MP4 内で VP9 を出力します。サポートが不十分です。 | format: 'webm' にしてからトランスコードします。 |
ビートグリッドを使用した <TransitionSeries> | トランジションはオーバーラップするため、合計期間 = シーケンスの合計 - トランジションの合計となります。フレームグリッドが静かにずれます。 | フレーム正確なカットには、明示的な <Sequence from/durationInFrames> を使用し、トランジションはローカルで行います。チェーンが合計と一致することをアサートします。 |
ソースよりも長い <Sequence> | 最後にデコードされたフレームでフリーズします。エラーではなく、停止として認識されます。 | すべての期間を実際のテイクの長さで制限します。コメントにソースの期間を記録します。 |
重複するシーケンスでの premountFor | プリマウントされたシーケンスは、現在のシーケンスの上に早期にレンダリングされます。ゴーストのように二重露光されたテキストが表示されます。 | 画面スペースを共有するシーケンスをプリマウントしないでください。ハードカットをまたぐ場合のみプリマウントします。 |
| コンポジション空間に配置されたオーバーレイ | フッテージコンポーネントが内部でプレートをクロップおよびスケーリングする場合、コンポジション座標に配置されたマスクやハイライトはフレーム内の何とも位置が合いません。エッジがコンテンツを切り抜きます。 | オーバーレイをプレートと同じ変換の内側に配置するか、フッテージの上に重ねる代わりにネイティブに処理を行います。 |
コンポジション内での Math.random() / Date.now() | フレームごとに再ロールされます。テキストがちらつきます。Remotion は各フレームを個別にレンダリングします。 | すべてのランダム性をインデックスの純粋関数(sin ベースのハッシュ)にします。 |
Remotion 内での CSS アニメーション / トランジション / Tailwind animate-* | レンダリングがフリーズするか、ガベージを生成します。Remotion は壁時計ではなく useCurrentFrame() を介して時間を駆動します。 | useCurrentFrame() でモーションを再構築します。これは、一般的にマーケティングサイトのアニメーションコンポーネントを再利用できないことも意味します。 |
| フィルム内にオフセットしてループを構築する | 2つのシームバグ: 範囲がディゾルブで開く場合の黒いフラッシュ、およびラップする場所でのハードジャンプカット。 | ループに独自のコンポジションを与え、そのテールを自身のヘッドの <Freeze frame={0}> にクロスフェードします。継続的に動くショットを選択します。静止するものはほぼ静的で、自動再生には適していません。 |
プロセス
1. フィルムをデザインする前にプロダクトの真実を確立する
最も重要なステップ。 フィルムが主張しようとしているすべての機能についてコードを読んでください。マーケティングページは願望を説明します。製品が自身のランディングページのアニメーションが示唆することを実際に実行できるとは想定しないでください。
これはすでに一度起こりました。フィルムの中心的な見せ場は、マーケティングサイトのアニメーションコンポーネントから取られており、1つのドキュメントが4つの異なるアスペクト比に変化する様子を示していました。製品は単一のアスペクト比と固定のエクスポートステージをハードコーディングしていました。そのコンポーネントはアイデアのイラストであり、機能ではありませんでした。それにマネーショットを構築することは、サポートされていない主張をホームページに載せることになっていました。
具体的に確認すること:
- 実際にレンダリングされるコンテンツはどれか?古いレコードは現在のエンジンではレンダリングできない可能性があります。
- どのルートに認証が必要か?事前の状態なしでリダイレクトするものはどれか?
- 各インタラクティブ機能を実際に機能させるには何が必要か?
2. 最小限のテストでパイプラインのリスクを軽減する
上に何かを構築する前に、以下の順序で行います:
- キャプチャジオメトリを証明する(コーナーマーク付きページ → ファイルは本当に2倍か?)。
- 認証を証明する(ブラウザはサインイン済みルートに到達できるか?)。
- 3Dが関係する場合は WebGL を証明する。
- 1つのインタラクションをエンドツーエンドで証明する。
3. 推測せずに偵察する
すべての候補となる画面をスクリーンショットし、ビデオテイクに時間を費やす前にユーザーにコンタクトシートを見せます。コンテンツの選択がプロダクション価値を左右します。平凡なデモコンテンツは、美しいフィルムを平凡な製品の広告に変えてしまいます。
4. デモコンテンツを意図的に選ぶ
製品自身のブランドを優先します。認識可能なサードパーティをフィーチャーすることはより説得力がありますが、他の誰かの商標をホームページに載せることになります。サードパーティを別のものに交換しても、それは変わりません。自己言及的なコンテンツはループを閉じます。つまり、ツールを販売する成果物は、ツールによって作成されたものになります。
コンテンツがまだ存在しない場合、それを作成することはキャプチャ作業ではなく、デザイン作業です。それはフィルムの後半のすべてのフレームです。意図的にドラフトを作成し、いくつかの候補を生成し、ユーザーに選ばせます。
5. グリッドにカットする
120 BPM ⇒ 1小節 = 60フレーム = 30fps で 2秒。すべてのカットを30の倍数に、すべての幕の境界を60の倍数に揃えます。コストはかからず、カットダウンは自動的に行われます。
6. 見て確認する
レンダリングのたびに、フレームを抽出して実際に見ます。ラベル付きのコンタクトシートを作成します。これまでに見つかった実際の欠陥(空白のロゴ、間違ったページを示すショット、ライトパネルで読めないキャプション、誤測定されたクロップからの暗い帯、ラベルを通るマスクのシーム)はすべて、テストに合格したからではなく、フレームを見ることによって発見されました。
ミュートで視聴します。これが自動再生される方法だからです。
編集ルール
これらは、良いフィルムと実際に機能するフィルムを区別するものです。
画面上のすべての主張は、隣のフッテージによって裏付けられなければなりません。 あるカットでは、「リンクを共有」という主張が、共有を示すものがないフッテージの上に重ねられていました。それを表示するか、カードに平易に記載してください。暗示してはいけません。
コンテキストでは正直だが、ビデオスケールではそうではない主張に注意してください。 小さなタイプで「イラスト」とラベル付けされた図は、マーケティングフィルムで保持されたヒーローフレームになった瞬間に、強い主張になります。保持されたフレームからそれらを除外してください。
製品の動きを引用し、再発明しないでください。 アプリ自身のイージングカーブとエントランス語彙を持ち上げてください。すべてのエントリーまたは着地に1つのカーブを使用します。バウンドするものはありません。オーバーシュートはためらいとして読み取られます。
2つのグラウンド。ミッドグレーは使用しないでください。 発言にはダークグラウンド、説明にはライトグラウンドを使用します。製品自身のトークンから選択してください。
1つのアクセントを控えめに使用します。 キャレット、文を担う1つの単語、変化する状態。装飾ではありません。
フレーム内には、視聴者のためのものだけを配置します。 実際のメールアドレス、組織名、オペレーター自身のアプリ内アシスタントとの会話、開発モードバッジ。CSS ハックよりも、アプリ自身のメカニズム(折りたたまれたサイドバーや閉じられたバナーのための Cookie)を優先します。カメラにフラッシュを当てないでください。
「マネーショット」は最も多くの時間を費やす価値があります。 競合他社が構造的にできないことを示す瞬間を1つ選び、カメラを固定し、カットなし、テキストを重ねず、音楽をフェードアウトさせます。静止は、カメラではなく被写体が動いていることを目に伝えます。説明文はその後に配置します。反応の前にテキストがあると、人々に何を考えるべきかを指示することになります。
可読性はカバレッジに勝ります。 4つの画面にまたがるショットは、どれも読み取れなくなる可能性があります。1つに留まる方が通常は優れています。
UI がパフォーマンスを発揮できない場合は、撮影する代わりにビートを構築します。 静的な画面では、3つのものを1つずつ紹介することはできません。製品が行わないシーケンスをビートが必要とする場合は、製品の実際のコピーとトークンを使用して Remotion でネイティブに構成し、偽のスクリーンショットではなく説明者として読まれるように、フッテージと視覚的に区別できるようにします。
ナレーションがない場合、カードが意味の100%を担います。 読む時間を予算に入れてください。
ユーザーと話し合う。一人で決めないでください。
- スローガンと画面上のコピー。 角度ごとにグループ化したいくつかのオプションを、推奨事項とその理由とともに提供します。フィルムは「デモキュー」を必要とするのに対し、ウェブサイトの見出しは「耐久性のあるポジショニングステートメント」を必要とするという点に注意してください。これらは同じラインである必要はありません。
- どのコンテンツをフィーチャーするか — コンタクトシートを表示します。
- 音楽。 トラックをライセンスすることはできません。フィルムを無音でも機能するようにデザインし、キューシート(BPM、任意のドロップが着地する場所)を出荷して、後で提供されたトラックがグリッドにドロップできるようにします。トラックが到着したら、配置する前にその形状を確認します。イントロやドロップがあると想定せずに、時間の経過に伴うラウドネスを測定します。
- Remotion ライセンス。 個人、非営利団体、および従業員3人以下の企業は無料です。それを超えると商用ライセンスが必要です。出荷前にフラグを立ててください。
コマンド(シェイプ)
キャプチャは決してサーバーを起動せず、ポートを推測しません。認証 URL は通常固定されています。
# ターミナル 1 — 製品はすでに提供中
pnpm --filter <app> dev # または同等のもの
# ターミナル 2 — フィルムプロジェクト
pnpm install
pnpm check-webgl # 3D がある場合
pnpm capture:<app> # または1ショット: pnpm capture:<app> <shot>
pnpm mezzanine:<app> # 必須 — トラップを参照
pnpm studio
pnpm render:<app> # 必要に応じて mp4 / webm / loop / poster
サインイン済みサーフェスの認証: 使い捨てユーザーをサインアップするよりも、ライブセッション Cookie を借用することを好みます(空のアカウントは、すべての撮影前に遅いコンテンツ生成を強制します)。
ページへの出荷
2つの形状があり、それはユーザーの判断に委ねられます:
- 短いループ、クリックでフィルムへ。 最も軽量 — 数百KBが自動再生され、完全なフィルムはフェッチ時にのみロードされます。