Communitygithub.com

ナレーション付きA/Bビデオ

PRや機能のA/B検証ビデオを作成します。Playwrightで各サイドのブラウザ実行を記録し、タイトル/エビデンスカードやA/Bコーナーバナーを重ね、macOS sayで各セグメントを音声化し、モデル待ち時間を高速化、最終フレームを固定してナレーションに合わせ、1つのmp4に連結します。

Bビデオ とは?

このスキルは、プルリクエストや機能のA/B検証をナレーション付きビデオとして記録・生成するためのツールです。macOS Apple Silicon環境向けに設計されており、Playwrightを使用して各サイド(A/B)のブラウザ操作を録画し、タイトルカード・エビデンスカード・判定カードなどのグラフィックオーバーレイと、macOS sayまたはElevenLabsによる音声ナレーションを組み合わせます。モデルの応答待ち時間(デッドエア)は高速再生(デフォルト10倍速)で圧縮し、ナレーションがクリップより長い場合は最終フレームを固定して表示を継続することで、説明と映像の同期を実現します。動的入力(OTPコードやIDなど)にはフック機構を提供し、非同期UIのためのマークベースの待機、プローブ機構など、実際の開発現場の摩擦を軽減する工夫が多数組み込まれています。生成されたビデオはQuickTime Playerで一時停止状態で開かれ、ユーザーの明示的な許可なしに再生されることはありません。

対応✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/sblattj/agent-chandlery/tree/main/skills/narrated-ab-video

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

Bビデオ は何をしますか?

その他のトリガー

PRのビデオウォークスルー、デモ録画の作成、音声付きデモ、両スタックの記録、説明ビデオ、drawtextフィルタ不要、Playwright recordVideo、ヘッドレスシェル不足

クレームセットごとに1つのmp4:タイトルカード、Aクリップ、Bクリップ、エビデンスカード、判定カード、それぞれ音声付き。

Apple Silicon上のmacOS向けに構築(say、~/Library/Caches/ms-playwright下のPlaywrightキャッシュ、chrome-mac-arm64)。それ以外の環境ではCHROMIUM_EXEを設定し、音声には--elevenを使用。Bun、ffmpeg、Python 3が必要。

実行手順

S=${SKILL_DIR:-~/.claude/skills/narrated-ab-video}
$S/preflight.sh /tmp/vid                                  # chromium, playwright ffmpeg, ffmpeg, say voice
bun $S/record.ts a.json raw/a-run                         # サイドごとに1シナリオ(examples/scenario.jsonをコピー)
bun $S/record.ts b.json raw/b-run
bun $S/cards.ts cards.json cards                          # タイトル/エビデンス/判定PNG + バナーA/B.png
python3 $S/build.py plan.json                             # [--voice Samantha] [--rate 182]
open -a "QuickTime Player" demo.mp4                       # 一時停止状態で開く;自分で再生しないこと

examples/内の例:scenario.json(ステップ: wait, select, click, clickIfPresent, type, send, waitStable, expand, fetchText, waitText, probeEnabled, reload;record.tsのヘッダー参照)、cards.json、plan.json。プランパスはプランファイルからの相対パス。実際の2クリップから4セグメント、40秒のビルドでエンドツーエンド検証済み。

このように構築された理由(摩擦の採掘)

  • Playwrightの固定ヘッドレスシェルはダウンロードされていないことが多い。 record.tsとcards.tsは最新のキャッシュされたchromium-*フルビルド(または$CHROMIUM_EXE)を起動し、失敗を回避。
  • recordVideoにはPlaywright独自のffmpegビルドが必要。 欠如するとwebmが生成されない。preflightはbrowsers.jsonからリビジョンを読み取り、bunx playwright install ffmpegを実行。
  • Homebrewのffmpegはdrawtextが欠如していることがある。 バナーはcards.tsからの透明PNGで、build.pyでオーバーレイ。フォントやフィルタの探索は不要。
  • モデルの応答には10〜60秒の無音時間が発生する。 sendは「送信済み」、waitStableは「応答あり」をマーク。build.pyはその区間をspeed(デフォルト10倍速)で再生し、残りは1倍速で再生。
  • ナレーションは通常クリップより長い。 build.pyは最終フレーム(tpad stop_mode=clone)を音声終了まで保持するため、応答が画面に表示されたまま説明が行われる。
  • 動的入力(OTPコード、前のターンのIDなど): typeステップに{{fn:NAME}}を配置し、シナリオと同じディレクトリのhooks.tsからNAME(page, state)をエクスポート。state.lastJsonはcaptureJsonFromに一致する最後のPOST JSONを保持。
  • セレクター: ボタンはロールと名前の正規表現でマッチ("Tools used"、"^Send$")。CSSは入力とセレクトのみ。スクリプト作成前にクイックスクリーンショットで名前を確認。
  • 連結には同一エンコードが必要。 すべてのセグメントは同じコーデック、レート、オーディオレイアウトで再エンコードされ、-c copyで結合。
  • より良い音声: ELEVENLABS_API_KEY=... build.py plan.json --eleven <voice_id>(モデルeleven_multilingual_v2;クリップは音声+テキストハッシュでキャッシュされるため、再実行では文字数消費なし)。キーは0600のファイルに保管し、プランには決して書かず、使用後は削除。
  • 片側デモ(A/Bなし): 1つのシナリオを記録し、cards.jsonに1つのバナーを与え、同じクリップを複数のプランセグメント(クレームごと)に分割し、待機時間を高速化するspans(例:5倍速)。同じビルドで、Aサイドなし。
  • ユーザーが単に<voice_id> <key>を貼り付ける場合もある。 つまり--eleven <voice_id>で再ビルド。遅い音声はビデオを引き伸ばす(sayで72秒→92秒)。build.pyは音声終了まで最終フレームを保持するため。
  • 撮影前に破棄されたデモの再構築: 短期間の認証(ローカルJWT、トンネルURL、一時的なクラウドリソース)は翌日には無効になっていることが多い。録画前に1回のAPI実行で再確認すること;そこで401「JWTトークン期限切れ」が発生した場合、結果が届かないターンを撮影してしまう。
  • 生クリップの喪失: 以前の出力mp4から該当サイドの映像を切り出す(バナーコーナーの色でスパンを特定)、<dir>/a.webmとして-f mp4と空のmarks.jsonで保存し、明示的な1スパンを使用。バナーは焼き込まれているので省略。
  • オーディオ: say -oはファイルのみ書き出し。ユーザーの明示的な許可なしにビデオやオーディオを再生してはならない。一時停止状態で開き、ユーザーに引き渡す。
  • 撮影前に証明せよ。 先にA/Bを実行し、結果(APIまたはログ)をアサートすること。ビデオは証明された結果を示すものであり、テストではない。
  • カードはクリップサイズと一致しなければならない。 build.pyはスケーリングを行わない。"viewport": [1440, 900]での録画にはcards.jsonで"size": [1440, 900]が必要。そうしないと連結時にフレームサイズが混在する。
  • 非同期UIには固定待機ではなくマークが必要。 waitTextは正規表現が出現した時点でマーク(またはtimeout:<mark>)、probeEnabledはwaitMsでボタンをポーリングしmarks.jsonにprobes[]を記録、tryMsはtype/send/clickで失敗時にskipped:<step>をマークしてアボートしないため、「無効のまま」のサイドでもクリップが完了する。
  • クリックする要素と同じ要素をプローブせよ。 CSSプローブ(button[aria-label=...])がロール名sendとは異なるマッチングボタンにヒットし、sendが通過中にdisabledを読み取った;probeEnabledでは"role"を使用。
  • Devモードのオーバーレイ(クエリdevtools、エラートースト)はクリップに写り込む。 最初のwaitの後に{"clickIfPresent": "^Close .* devtools$"}を追加。
  • 「安定化」しない応答を待つ場合: ライブの経過時間バッジが本文テキストを毎秒変更する。ビルド前にmarks.jsonにrepliedマークがあるか確認。
  • 証拠が可視テキストにあることを確認せよ。 折りたたまれたツールカードは展開されないことがある(expandは静かに何もクリックしない)。marks.jsonのbodyでクレーム文字列を確認。欠如している場合はプロンプトを変更するか、代わりにカード上で証明。
  • 「ベースが失敗する」クレームを撮影する前にパリティを証明せよ。 ローカルベースが、実際の環境では決して発生しない理由(ローカルではオン、リモートではオフのフラグ)で失敗したことがあり、ナレーションでそれを主張した。まずリモートのフラグに合わせてから撮影。
  • タイトルカード:テストされたコミットと各サイドのフラグ。クリップセグメントごとに1クレーム。判定カードで終了。

関連

  • narrated-screenshot:ビデオではなく、注釈付きの単一静止画。
  • pr-ab-evidence:このスキルが撮影する赤/緑のA/Bメソッド。

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

関連スキル