Communitygithub.com

旁白版 A/B 影片

為 PR 或功能製作一部附帶旁白的 A/B 對比影片:使用 Playwright 錄製瀏覽器操作(包含時間標記、動態輸入如 OTP 碼的鉤子),渲染標題/證據卡片與 A/B 角落橫幅,以 macOS say 為每個片段配音,加速模型等待時間,凍結最後影格以配合旁白長度,最後合併成一個 mp4 檔。觸發詞:建立含旁白的影片、旁白示範影片、將 A/B 結果錄成影片、證明功能運作、團隊示範影片、含旁白的螢幕錄製。

B 影片 是什麼?

Narrated A/B video 是一項專為 macOS Apple Silicon 設計的 AI Agent 技能,用於自動化製作 PR 或功能的 A/B 對比示範影片。它透過 Playwright 分別錄製 A 與 B 兩個版本的瀏覽器操作,自動生成標題卡片、證據卡片與判決卡片,並以 macOS 的 `say` 合成語音(或支援 ElevenLabs 的更高品質聲音),最後使用 FFmpeg 將所有素材合併成一部完整的 MP4 影片。此技能處理了許多常見的痛點:模型等待時間被加速、語音長度超過影片時自動凍結最後影格、動態輸入(如 OTP 碼)可透過鉤子函數注入,以及避免依賴系統缺少的 `drawtext` 過濾器(改用透明 PNG 橫幅)。支援的觸發詞包含「建立旁白影片」、「A/B 比較錄影」、「功能證明影片」等,適合開發團隊快速產出高品質的示範內容。

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

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

B 影片 是做什麼的?

更多觸發詞

PR 的影片導覽、製作示範錄影、旁白示範、同時錄製兩個版本、解說影片、沒有 drawtext 濾鏡、Playwright recordVideo、缺少 headless shell

每個斷言集合一個 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 語音
bun $S/record.ts a.json raw/a-run                         # 每側一個場景(複製 examples/scenario.json)
bun $S/record.ts b.json raw/b-run
bun $S/cards.ts cards.json cards                          # 標題/證據/判決 PNG + banner-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。計畫路徑相對於計畫檔案。已在一個 4 片段、40 秒的建置中端到端驗證,使用兩個真實剪輯。

為何如此設計(已知摩擦點)

  • Playwright 固定的 headless shell 經常未下載。 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 會標記「sent」,而 waitStable 會標記「replied」。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): 錄製一個場景,為 cards.json 提供一個橫幅,並將同一個剪輯切割成幾個計畫片段,每個片段一個斷言,使用 spans 加速等待時間(例如 5 倍)。建置方式相同,沒有 A 側。
  • 使用者可能只貼上 <voice_id> <key>。 這意味著使用 --eleven <voice_id> 重新建置。較慢的語音會拉長影片(使用 say 的 72 秒變成了 92 秒),因為 build.py 會將最後一個影格保持到語音結束。
  • 拍攝前重新建立已拆除的示範環境: 短期有效的驗證資訊(本機 JWT、隧道 URL、暫時的雲端資源)通常到隔天就會失效。在錄製前先用一次 API 呼叫重新驗證;如果那邊出現「JWT token expired」的 401 錯誤,你拍攝的回合將永遠等不到結果。
  • 遺失原始片段: 從先前的輸出 mp4 中剪下該側的 footage(透過取樣橫幅角落顏色來找出其時間範圍),將其儲存為 <dir>/a.webm 並使用 -f mp4 和空的 marks.json,然後使用一個明確的 span。因為橫幅已經嵌入其中,所以省略 banner。
  • 音訊: say -o 只會寫入檔案。在未經使用者明確同意之前,切勿播放影片或任何音訊。以暫停狀態開啟並交給使用者。
  • 先證明再拍攝。 先執行 A/B 測試並斷言結果(API 或日誌)。影片展示的是已證明的結果,它本身不是測試。
  • 卡片必須與片段尺寸相符。 build.py 不會縮放。如果使用 "viewport": [1440, 900] 錄製,則 cards.json 中也需要 "size": [1440, 900],否則合併時會出現混合的影格尺寸。
  • 非同步 UI 需要標記,而非固定等待。 waitText 會在正規表達式出現時標記(或 timeout:<mark>),probeEnabled 搭配 waitMs 會輪詢按鈕並將結果記錄在 marks.json 的 probes[] 中,type / send / click 上的 tryMs 會標記 skipped:<step> 而非中止,這樣「維持禁用」的一側仍能完成片段。
  • 探測你要點擊的同一個元素。 CSS 探測(button[aria-label=...])可能匹配到不同的按鈕,而非角色名稱為 send 的那個,並在點擊成功時回報禁用狀態;請在 probeEnabled 中使用 "role"。
  • 開發模式疊加層(查詢 devtools、錯誤提示)會出現在片段中。 在第一次 wait 之後加上 {"clickIfPresent": "^Close .* devtools$"}。
  • 等待一個永遠不會「穩定」的回覆: 一個即時經過時間的徽章每秒都在變更主體文字。在建置前請先檢查 marks.json 中是否有 replied 標記。
  • 確認證明存在於可見文字中。 折疊的工具卡片可能不會展開(expand 靜默地什麼都不點)。請閱讀 marks.json 的 body 來尋找斷言字串。如果找不到,請修改提示詞,或改為在卡片上證明。
  • 在拍攝「基礎版本失敗」的斷言前,先證明兩者相等。 一旦本機基礎版本因為某個原因(某個在本機開啟、在遠端關閉的旗標)而失敗,而這個原因是真實環境中永遠不會發生的,並且旁白卻宣稱了這個失敗。請先匹配遠端的旗標,然後再拍攝。
  • 標題卡片:每個側邊測試的提交與旗標狀態。每個片段一個斷言。以判決卡片結束。

相關技能

  • narrated-screenshot:單張帶註解的靜態圖片,而非影片。
  • pr-ab-evidence:此影片所拍攝的紅/綠 A/B 方法。

Individual skills in this repo

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

相關技能