自動デモ動画の録画(Playwright)
モード(最初に決定)
受け取った引数: $ARGUMENTS
| 引数 | モード | テンプレート |
|---|---|---|
audio を含む(またはリクエストに音声 / ナレーション / 話すナレーションが含まれる) | ナレーション付き — TTS音声 + キャプション | record-demo-narrated-template.mjs + narrate.py |
| 空 / その他 | サイレント — キャプションのみ(デフォルト) | record-demo-template.mjs |
ナレーションモード: 言語 en(デフォルト)または pt(ブラジルポルトガル語); エンジン auto(デフォルト: 英語 → kokoro オフライン; ポルトガル語 → edge、オフライン時は kokoro にフォールバック)、または kokoro / edge を強制。例: audio, audio pt, audio pt kokoro, audio en edge。ナレーションモードのセクションも参照してください。
キャプションとナレーションは選択された言語で記述します(pt が指定されていない、またはユーザーがポルトガル語で書いていない限り en)。
概要
デモ動画はコードであり、手動キャプチャではありません。Playwright スクリプトがブラウザを駆動し、ネイティブ録画、オーバーレイキャプション、視覚的なハイライトを提供します。製品が変更されるたびに再録画可能で(npm run demo:record)、ペースとストーリーを制御できます。
基本原則: 動画はピッチであり、E2Eテストではありません。 すべてのシーンは1つの主張を証明するために存在し、作業は生成された動画をフレームごとに確認して初めて完了します。
使用するタイミング / 使用しないタイミング
- ✅ Web製品のPOC/デモ(投資家、顧客、ステークホルダー、オンボーディング向け)
- ✅ 進化し続けるエンドツーエンドフローの文書化(再録画可能)
- ✅ 音声付き: ナレーションモード(ローカル/オフラインTTS)— 上記参照
- ❌ 自動テスト(Playwright Test を使用)· ❌ 非Webアプリ · ❌ アプリ自体の音声のキャプチャ(Playwright はブラウザ音声を録音しません)
プロセス
- まず決定論的な状態を確保する。 動画は実際のアクション(ログイン、クリック、DB書き込み)を実行します。録画前に冪等なシード/デモデータと専用アカウントを準備してください。サーバーはプロダクションモード(
build && start)で実行するか、開発モードでルートをウォームアップしてください。レイジーコンパイルは動画で白い画面として表示されます。 - コーディング前にスクリプトを書く。 4幕のピッチアーク: ビジョン(オープニング)→ 仕組み(差別化要因、内部)→ エンドユーザー体験 → 証明/結果(ビジョンで締めくくる)。各シーン = 1つの主張 + 1つのキャプション(強い見出し + 説明サブテキスト)。目標: 合計60〜120秒、各キー画面3〜5秒。
- テンプレートを適応する — キャプション、ハイライト、ログイン、ペース調整、変換のための既製ヘルパーがあります。プロジェクトのブランドカラーをキャプションに使用してください。
- 録画し、セレクタの失敗はスクリプトのバグとして扱います(修正し、回避しないでください)。
- 動画を確認 — 必須。 再生時間とシーン:
フレームを確認した後にのみ納品してください。シーンが失敗した場合は再録画します。ffprobe -v error -show_entries format=duration -of csv=p=0 demo.mp4 # 各シーンの1フレームを取得し、それぞれを**見る**(正しいキャプション?正しい画面?何も壊れていない?) ffmpeg -y -ss <t> -i demo.mp4 -frames:v 1 -vf scale=800:-1 frame_<t>.png .mp4を納品する(PowerPoint/Slack/WhatsApp で動作)。.webmに加えて。npmスクリプト(demo:record)を残し、出力をgitignoreしてください(再生成可能です)。
ナレーションモード(audio)
上記と同じプロセスですが、以下の違いがあります:
- 前提条件: PATHに
uvとffmpegが必要です(uv --version、ffmpeg -version)。narrate.pyを録画スクリプトと同じフォルダにコピーしてください。初回実行時にKokoroモデル(約120MB、~/.cache/recording-demo-videosにキャッシュ)をダウンロードします。 - ペースは音声に合わせる。
SCRIPT内の各シーンにはcaption(画面表示)とsay(発話、1〜2文、ピッチトーン)があります。await narrate(page, "id")はキャプションを表示し、発話を配置してその終了を待ちます — 発話シーンでは固定のpause()を使用しないでください。インタラクション中の発話:narrate(page, id, { wait: false }); 次のnarrate()は前の発話が終了するのを待ちます(重複なし)。 - 言語/音声は環境変数で設定:
DEMO_LANG=en|pt、DEMO_TTS=auto|kokoro|edge、DEMO_VOICE=<voice>(Kokoro:af_heart、am_michael、bf_emma、pf_dora、pm_alex; edge:en-US-AvaMultilingualNeural、pt-BR-FranciscaNeural…)。kokoro= オフライン、Apache-2.0、英語のデフォルト; ポルトガル語は著しく自然さに欠けます。edge= ポルトガル語のデフォルト、最高の音声ですが、非公式のMicrosoftエンドポイントを経由したオンライン — 内部デモには問題ありません; 商用利用ではkokoroまたは公式のTTSを推奨します。 - 同期は自動: テンプレートはマゼンタのフラッシュ(
syncMarker)で開き、実際のビデオ開始遅延を測定してフラッシュをトリミングします。syncMarkerを最初のアクションとして維持してください; ログに「Sync marker not found」と表示された場合、音声が同期しなくなります —syncMarkerが最初のアクションであり、最初の1秒間に画面を覆うものがないことを確認し、再録画してください。 - 出力:
demo.mp4(ナレーション付き — 納品物)、demo.srt、timeline.json、demo.raw.webm(生、サイレント)、audio/(キャッシュ: 再録画では変更された行のみ再合成)。 - 追加確認(必須): フレームに加えて、音声が正しい位置にあることを確認:
ffprobe -v error -show_entries stream=codec_type,duration -of csv=p=0 demo.mp4 # ビデオと音声の両方が必要 ffmpeg -i demo.mp4 -af silencedetect=n=-45dB:d=0.6 -f null - 2>&1 | grep silence_end # 各 silence_end ≈ timeline.json 内のシーンの atVideo (±0.2秒); その時間のフレームを取得してキャプションを確認
落とし穴(経験から学んだもの)
| 落とし穴 | 修正方法 |
|---|---|
| 動画のファイル名がランダムになる | 閉じる前に page.video() を取得; await video.path() を context.close() の後に呼び出し; 名前を変更 |
| ナビゲーションでキャプションが消える | 各 goto の後にキャプションを再注入(caption() ヘルパー)、または addInitScript + sessionStorage を使用 |
| 動画が人間には速すぎる | slowMo: 100–150 + シーンごとに明示的な3〜5秒の一時停止 + 可視タイピングには pressSequentially({ delay: 40–60 }) |
| mp4がPowerPoint/プレイヤーで開けない | ffmpeg -c:v libx264 -pix_fmt yuv420p |
| 動画が小さい/切り取られている | recordVideo.size は viewport と等しくなければならない |
| 動画に白/保留中の画面が表示される | アクション後に waitUntil: "networkidle" + waitForURL; 開発モードではルートをウォームアップ |
| 視聴者がどこを見ればよいかわからない | クリックする前に要素にアンバーハイライト(box-shadow)、または注入されたフェイクカーソル |
| 再録画でデータが重複する | 冪等なアクション、または再実行を許容するシード(サフィックス付きスラッグ、アップサート) |
| ログイン情報がペルソナ間で漏れる | ユーザー切り替え間に context.clearCookies() |
| (ナレーション付き)音声が画面と同期しない | Playwrightのビデオはページより0.2〜1.5秒遅れて開始します(実行/バージョンによって異なる)— テンプレートの syncMarker を使用し、決して固定オフセットを使用しないでください |
| (ナレーション付き)音声が途切れたり、シーンが急かされる | 発話シーンでの固定 pause() — 代わりに narrate() を使用してください。これは発話が終了するのを待ちます |
| (ナレーション付き)頭字語/ブランド名の発音が間違っている | say で発音どおりにスペルする(例: "S Q L" または "sequel"); キャプションは正しいまま |
よくある間違い
- フレーム確認をスキップする(「エラーなしで実行された」≠「動画が良い」)— 常に確認する。
- キャプションがUIを説明している(「ログイン画面」)のではなく、主張をナレーションしている(「チームがサインイン — きめ細かいロール制御」)。
- 書かれたスクリプトなしで録画する: ストーリーのない長いスクリーンキャストになる。
- 実際の認証情報をハードコードする — デモ/シードアカウントを使用し、必要に応じて環境変数で注入する。