project-demo-video
デモ動画をコードとして構築するため、変更後も数分で再レンダリングできます。画面に表示されるものはすべて本物です。実行中のアプリ、実際のコマンド出力、実際のソースファイルです。モックアップは一切ありません。
このスキルは、能力の低いコーディングエージェントでもステップバイステップで従えるように書かれています。フェーズは順番に実行してください。各フェーズには「完了条件」の行があります。それが満たされるまで先に進まないでください。ファイルは毎回書き直すのではなく、templates/ からコピーしてください。
インストール: このフォルダ全体(SKILL.md と templates/)をエージェントのスキルフォルダ(例: ~/.claude/skills/project-demo-video/)にコピーするか、単にエージェントに SKILL.md を指定します。
生成するもの
| 出力 | 説明 |
|---|---|
<name>-voiced.mp4 | 1920x1080、30 fps、H.264 + AAC、キャプション焼き付け、音声付き |
<name>-captions-only.mp4 | 同じ映像、無音のオーディオトラック(ユーザーがこちらを選ぶか、自分の声を録音する場合があります) |
<name>.srt | キャプションファイル。ナレーションと同じテキスト |
thumbnail.png | 1280x720 |
narration.md、shotlist.md | 実際のタイムスタンプ付きスクリプト。各シーンとそのソース |
frames/ | 実際に確認した QA フレーム |
repo/ | 変更または新規追加されたプロジェクトファイル。リポジトリパスをミラーリング |
COPY_LIST.md、README-snippet.md、REPORT.md | どこに何をコピーするか、「動作確認」用の README セクション、完了したこととリスクがあること |
0. 絶対に破ってはいけないルール
- ソースは読み取り専用。 ユーザーの実際のリポジトリに書き込んだり、コミットしたり、プッシュしたりしないでください。コピー(
robocopy/cp、node_modules、.git、ビルド出力を除外)で作業し、そこでnpm ciを実行してください。保持する価値のある変更は、出力フォルダの下にリポジトリパスをミラーリングして保存し、COPY_LIST.mdに記録してください。git 作業は別のツールまたは人が行います。 - 画面上で正直に。 シミュレートされたもの(デバイス、コネクタ、支払い、モデル)は、動画内でシミュレートと明示してください。存在しないハードウェア、デプロイ、ユーザーを決して暗示しないでください。プロジェクト自身の「現実 vs シミュレーション」テーブルをコピーしてください。README が間違っている場合は、レポートでその旨を述べ、その主張を繰り返さないでください。
- 画面や出荷するファイルに機密情報を含めないこと: トークン、API キー、
.envの内容、秘密鍵、実際のメールアドレス。プロジェクトが文書化している開発用トークン(例:Bearer dev-alice)は問題ありません。コードを表示するときは、機密情報を除外する行範囲を選択してください。 - コードを書いた AI ツールやそのベンダーについて、 フレーム、ナレーション、キャプション、出荷するドキュメントで言及しないでください。ただし、ユーザーが別途指示した場合を除きます。製品設定の一部であるランタイムモデル ID は、モデル名として表示される場合があります。終了する前に
grep -riで確認してください。 - コンテストのルールを尊重してください。 制限時間(通常「3:00 未満」、2:50 を目標に)と必須技術ルールを読んでください。動画では必須技術が実際に動作していることを示し、言及するだけでは不十分です。
- 無料枠、デプロイ不要、購入不要。 デプロイしたり、クラウドリソースを作成したり、費用をかけたりしないでください。手順に認証情報やユーザーからの録画が必要な場合は、一度だけ平易に尋ね、他のすべての作業を続けてください。
- ユーザーに尋ねるのは 認証情報、ユーザー自身の録画、または本当にユーザーに決定権がある選択肢(例: どの音声を使うか)のみです。それ以外はすべて自分で決定し、決定した内容を伝えてください。
1. 前提条件(確認、想定しない)
node --version # 22+ (24推奨; .mjs ファイルはプレーンな JavaScript である必要があり、TypeScript キャスト不可)
- プロジェクトのコピー内:
@playwright/test(Chromium インストール済み)とffmpeg-staticが存在する必要があります。確認:node -e "import('@playwright/test').then(async m=>{const b=await m.chromium.launch();console.log(b.version());await b.close()})"およびnode -e "import('ffmpeg-static').then(m=>console.log(m.default))"。不足しており、プロジェクトが新しい依存関係を禁止している場合は、別のツールフォルダに配置してパスを指定してください。 - 音声: Windows PowerShell と
System.Speech(組み込み)。macOS ではsay、Linux ではespeak-ngを使用します。その場合、templates/lib/tts.mjs(OS 固有なのはsynthAllとtts.ps1のみ)を適応させる必要があります。 ffmpeg-staticにはffprobeは付属していません。WAV ヘッダー(templates/lib/tts.mjsのwavSeconds)とレコーダー自身のタイミングから長さを測定してください。- Windows シェルに関する注意: バックスラッシュ、正規表現、
$を含むファイルには、Write ツールと Edit ツールを優先して使用してください。インラインのpython -c/heredoc による JS の書き換えは、エスケープを静かに壊します。フォアグラウンドのsleepは一部のエージェントでブロックされます。代わりにuntil grep -q "done" log; do sleep 10; doneで待機してください。
2. フェーズ
フェーズ A: 要件と証明マップ
ルールページ、README、プロジェクト自身のドキュメント、ストーリーラインのメモを読んでください。ノートにテーブルを書いてください。
| 審査員が納得しなければならないこと | 動画でそれを証明する箇所 | シーン |
|---|---|---|
| 必須技術がコード内で呼び出されている | 実際の呼び出しが可視: リクエストログ、ターミナル、コード抜粋 | ... |
| エクスペリエンスが動作する | アプリがブラウザで実行中 | ... |
| 何が現実で何がシミュレートか | プロジェクト自身のテーブル | ... |
完了条件: すべての行にシーンが割り当てられている。
フェーズ B: ワークスペース
- リポジトリをスクラッチフォルダにコピーし、インストール:
npm ci。 templates/をコピー内にvideo/としてコピー(構造を維持:video/lib、video/pages、video/scenes、video/final.mjs、video/narration.mjs、...)。package.jsonの scripts に追加:"video:final": "node video/final.mjs"。依存関係は追加しないでください。- コピー内の
.gitignoreにvideo/out/を追加します。
フェーズ C: 実際のアプリをドライランしてバグを探す(録画の前に行うこと)
審査員が行う方法でアプリを起動します(npm run demo または README のコマンド)。文書化されたデフォルトポートで起動し、画面上のすべてのコマンドが文字通り表示されるようにします。小さな Playwright スクリプトで操作し、ストーリーの各ステップごとに 1920x1080 のスクリーンショットを撮り、確認します。チェック項目:
- サインイン、空のパネル、赤いエラーバナー、コンソールエラー;
- ストーリーに必要なすべての状態が実際にレンダリングされる(参考プロジェクトの初回実行では、サインイン失敗、空の受信トレイ、主要なビューがないことが判明しましたが、古いドラフト動画ではすべて隠されていました);
- テキストの重複や途切れ。
実際のバグはコピー内で最小限に修正し、プロジェクト自身のチェック(npm run verify、テスト、型チェック)を実行し、各修正を COPY_LIST.md に記録してください。アプリにワイヤトラフィックを表示する方法がない場合は、偽装するのではなく、小さなオプションのフック(リクエストログ)を追加してください。
完了条件: ストーリー全体が 2 回連続で正常に実行され、プロジェクトのチェックがパスする。
フェーズ D: ストーリーボードとナレーション
- シーンを選びます。参考ストーリー(約 2:50):
| シーン | 長さ | 表示内容 |
|---|---|---|
| フック | 12 秒 | 1 つの変更が複数のコミットメントに波及する様子(アニメーションカード) |
| 起動 | 6 秒 | すべてを開始する 1 つのコマンド、実際の出力 |
| sim(アプリ) | 60 秒 | 8~10 ビート。2 ビートでリクエストログを開く |
| 証明ターミナル | 17~30 秒 | 同じサーバーに対する公式クライアントまたは CLI。認証チェック |
| コードツアー | 16 秒 | 必須技術を証明する 3~4 の実際の抜粋 |
| アーキテクチャ、クラウドスタック、現実 vs シミュレーション | 30 秒 | 図、スタックソース、正直さテーブル、オープンソースカード |
| クローズ | 12 秒 | タグライン、リポジトリリンク、ビルドクレジット、「X はシミュレートです」フッター |
video/narration.mjsを書く:scenes = [{ id, title, segs: [{ id, text }] }]。各segは 1 つの話し言葉のラインであり、1 つのキャプションです(textはそのまま表示されます)。ルール: 毎秒約 2.4 ワード。総話し言葉は 330~380 ワード。1 行に 1 つのアイデア。画面上のカードには約 12 ワードまで。文頭大文字。誇大広告なし。sayテーブルに発音ヒントを追加します(音声エンジンのみ。頭字語はスペルアウト、「Alexa+」は「Alexa plus」)。キャプションテキストは決して変更しないでください。 完了条件: ナレーションが見知らぬ人にも理解できるストーリーとして読め、証明マップのすべての行が話されるか表示される。
フェーズ E: テンプレートの適応
プロジェクト固有のものだけを編集します:
| ファイル | 編集 |
|---|---|
video/narration.mjs | シーンとライン |
video/scenes/sim.mjs | アプリのステップ: 入力またはクリックする内容、セレクタ、カメラズーム(lens(...)、zoomWire) |
video/scenes/static.mjs | ターミナルコマンド(CMD)、codeBlocks(ファイル + 最初の行の正規表現 + 行数 + ハイライト正規表現)、フック/クローズページ呼び出し |
video/proofs.mjs、video/proof-auth.mjs | 主張を証明する実際のコマンド。ステータスコードとエラー名のみを出力 |
video/pages/*.html | テキスト、色、タイル、図ボックス、テーブル行、リンク |
video/lib/overlay.mjs | アプリのレイアウト用 SIM_CSS セレクタ(レイアウトルール参照)、ティッカーのデータソース |
video/final.mjs | LIMIT 定数とシーン順序(順序は narration.mjs から) |
video/thumbnail.mjs、video/docs.mjs | タイトルと SHOT テーブル |
lib/recorder.mjs、lib/director.mjs、lib/tts.* は、壊れていない限り編集しないでください。
フェーズ F: 実際の証明出力をキャプチャ
node video/proofs.mjs は新しいサーバーを起動し、実際のコマンド(公式インスペクターまたはクライアント CLI、認証チェック、インストール/起動出力)を実行し、出力を video/out/proofs.json に保存します。ターミナルシーンは、このキャプチャされた出力を、読みやすいサイズの HTML ターミナルで再生します。ルール: 実際のコマンドテキストを表示(パッケージパスのみ短縮)。非常に長い出力は、目に見えて切り詰め(薄暗い「... N 行 ...」行)、チップに「録画実行」と表示。トークンは決して表示しない。JSON はプリティプリントし、その旨を記載する。
フェーズ G: ナレーション音声
デフォルト(アカウント不要): node video/final.mjs --rate 2 は、組み込みの Windows 音声(Microsoft Zira)でラインごとに 1 つの WAV ファイルを作成し、それぞれの長さを測定します。レート 1 は参照スクリプトで約 150 秒、レート 2 で約 139 秒、レート 3 は速すぎます。動画全体を制限時間内に収める最も遅いレートを選択してください。
オプションの人間らしい音声: 付録 A を参照。以降の手順はどちらでも同じです。
フェーズ H: 録画とアセンブル
node video/final.mjs --rate 2 # すべて: tts、証明、全シーン録画、両方のカットをアセンブル
node video/final.mjs --rate 2 --reuse-proofs # 証明の再実行をスキップ
node video/final.mjs --scenes sim,close --reuse-tts --reuse-proofs # 一部のシーンのみ再録画
node video/final.mjs --assemble-only # 再録画せずにリマックス(キャプション、音声)
node video/final.mjs --tts-dir video/out/tts-human --name my_video --single # 別の音声フォルダからビルド
フル実行には 6~10 分かかります。バックグラウンドで実行し、ログをポーリングしてください。合計が 180 秒以上になると失敗します。 170 秒を目指してください。
重要: ナレーションテキストや音声を変更すると、長さが変わるため、すべてのシーンを再録画する必要があります(マークは長さに基づいているため)。1 つのシーンのビジュアルのみを変更する場合は --scenes <id> --reuse-tts を使用します。
フェーズ I: QA(決してスキップせず、ログを信頼しない)
- 最終 MP4 から各ナレーションラインの終了フレームを抽出:
ffmpeg -ss <markEnd-0.3> -i final.mp4 -frames:v 1 frame.png(タイムラインはvideo/out/timeline.jsonにあります)。確認します。1080p での可読性、空きスペース、クリップされたテキスト、キャプションの位置とサイズ、同期(キャプションのイベントが画面に表示されていること)、秘密情報なし、ベンダー言及なし、正直ラベルの存在。 ffmpeg -i final.mp4 -af volumedetect -f null -: 平均約 -22 dB、最大 0 dB 以下。- 両方のカットで制限時間以内。両方のファイルにビデオストリームとオーディオストリームがある。
grep -ril "<vendor語>" video/pages video/narration.mjs <出力ドキュメント>が、許可されたモデル ID 以外を返さない。- プロジェクトのチェックを再度実行(
npm run verify、UI が変更された場合は e2e)。 - すべてパスするまで修正して再レンダリング。
フェーズ J: 成果物
node video/docs.mjs <outdir> で narration.md と shotlist.md を生成(実際のタイムスタンプ)。MP4、SRT、サムネイル(node video/thumbnail.mjs <png>)、QA フレーム、変更されたリポジトリファイル(元のコピーとの間で異なるすべてのファイル、リポジトリパスで)をコピーします。COPY_LIST.md(バグ修正を最初に、次に新しいファイル、推奨コミットメッセージ、「コピー後にビルドと検証を実行」)、README-snippet.md(実行コマンド、エントリポイントファイル:行、クライアントファイル:行、スキルファイル、動画リンクプレースホルダー)、REPORT.md(完了したこと、ユーザーが行うべきこと、リスク)を書きます。確認できなかったことを率直に述べてください(例: 音声を聞くことはできませんでした)。
3. パイプラインの仕組み(変更する前に読むこと)
レコーダー(lib/recorder.mjs)。Playwright の recordVideo はビットレートを制限し、小さなテキストをぼやけさせるため、このスキルでは Chromium スクリーンキャストを使用します。JPEG フレーム(品質 92)は到着時にタイムスタンプが押され、ディスクに書き込まれ、libx264 crf 17 で 30 fps の一定レートでエンコードされます。静的な画面ではフレーム数が少なくなります。最後のフレームは保持されます。タイムスタンプは、ディレクターも使用する同じクロック(performance.timeOrigin + performance.now())から取得されます。
ディレクター(lib/director.mjs)。各ナレーションラインは セグメント です。d.seg(id, actions, {tail}) は開始時間を記録し、画面上のアクションを実行し、ラインの再生が完了してから tail * 0.45 秒後まで待機します(テールは制限時間に収まるようにグローバルにトリミングされます)。マーク(id、開始、終了、テキスト)は video/out/<scene>.marks.json に保存されます。音声は後で記録されたマークに配置されるため、画像と音声のずれは発生しません。ビートのルール: アクションをセグメント内で実行し、アクションがナレーションより先に終了するようにします。ラインがアクションより短い場合は、2 つのラインに分割します(これが、1 つのストーリービートが sim9 と sim10 になった理由です)。
音声(final.mjs)。各 WAV は adelay でグローバル開始時間まで遅延され、amix=normalize=0 でミックスされ、alimiter で制限され、apad=whole_dur=<total> でパディングされます(パディングがないと、-shortest が動画の終わりをカットします)。
キャプション。 キューポイントは、ナレーションテキストを文の終わり(「2.0」のような小数点は保護)と、82 文字を超える場合はカンマで分割し、時間は長さに比例して分割されます。.srt が出荷されます。焼き付けバージョンは、PlayResX: 1920, PlayResY: 1080 とフォントサイズ 36 の ASS ファイルを使用します。force_style で SRT を焼き付けないでください。libass はそれを 288 ピクセル高のキャンバスに対してスケーリングし、テキストが約 4 倍大きくなります。
オーバーレイ(lib/overlay.mjs)は、録画されたアプリページにのみ注入されます(アプリ自体は編集されません...)
[以下、元の SKILL.md の全文が続きます。翻訳はプロの技術翻訳者によるもので、コードブロック、コマンド、ファイルパス、URL、インラインコードはそのまま保持されています。]