Community程式設計與開發github.com

AppLoidx/record-demo

使用 Playwright 編寫臨時分鏡腳本,錄製產品展示影片的 AI 代理技能。

record-demo 是什麼?

這個技能讓 AI 代理(如 Claude Code)能夠自動錄製產品展示影片。它提供一個基於 Playwright 的 DSL(領域特定語言),讓代理可以編寫臨時的分鏡腳本(storyboard),並透過自包含的引擎執行錄製與後製。支援多種輸出格式(16:9、1:1、9:16),可自訂瀏覽器框架主題,並能輸出高品質 MP4 與 GIF。針對已驗證的網站,技能內建了安全的一次性登入與 Session 儲存機制,確保不會在磁碟上留下認證資訊。錄影完成後,還能匯出為 Remotion Studio 專案,讓使用者進一步編輯字幕、縮放動畫與片尾。最後,技能提供了嚴格的品質驗證流程,包括類型檢查、測試、動畫評分與逐格畫面審查,確保最終影片沒有畫面裁剪、字幕延遲或開發網址等問題。

相容平台✓Claude Code~Codex CLI✓Cursor
npx skills add AppLoidx/record-demo

Installed? Explore more 程式設計與開發 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜歡的 AI 中提問

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

說明文件

錄製展示影片

編寫臨時的 Playwright 分鏡腳本,然後從任何工作目錄執行自包含的引擎。 除非使用者要求,否則不要將分鏡腳本加入應用程式儲存庫。 保持分鏡腳本自包含;執行器在 Playwright 載入之前會將該檔案暫存到引擎內部,因此不要使用相對於分鏡腳本的輔助匯入。 <skill-dir> 表示此儲存庫被複製的目錄,例如 ~/.claude/skills/record-demo。

編寫分鏡腳本

使用以下可攜式匯入來匯入 DSL:

import { demo } from "record-demo/storyboard";

執行器在暫存時會將此指定符重寫為引擎的實際路徑,因此分鏡腳本檔案可以放在任何位置。 編輯器對 record-demo/storyboard 的型別解析來自於 engine/tsconfig.json 的 paths - 在儲存庫外部,請將 record-demo/storyboard 對應到絕對路徑 <skill-dir>/engine/lib/storyboard.ts,放在您的 tsconfig paths 中,或將檔案保留在 engine/scripts/ 目錄下。

使用 engine/scripts/example-site.demo.ts 作為參考。優先使用 getByRole 選擇器,使用 d.click(locator) 而不是 locator.click(),使用 d.hold(...) 調整操作節奏,並對最終狀態進行斷言或等待。

demo("storyboard-title", async (d) => {
  await d.seed(async (page) => {
    await page.getByRole("heading", { name: "Example Domain" }).waitFor();
  });

  await d.step("Read the page", async (page) => {
    const heading = page.getByRole("heading", { name: "Example Domain" });
    await d.zoomTo(heading, { padding: 48 });
    await d.hold(2_000);
    d.zoomOut();
    await heading.waitFor({ state: "visible" });
  });
});

引擎會使用 --name 或腳本基礎名稱覆寫時間軸名稱,因此傳遞給 demo(...) 的字串不需要與輸出 slug 相符。

預飛檢查(在任何擷取之前)

當對本地提供的 checkout 進行錄製時:在提供服務的 checkout 中執行 git fetch origin 並斷言 HEAD == origin/main(或使用者命名的分支)— 過時的 checkout 會錄製到過時的設計。如果過時,請先重建/重新啟動伺服器。將服務中的 SHA 印製到錄製備註中,以便每個錄製都可以追溯。

錄製

需要 Node >= 22.18(透過 nvm 或系統)、ffmpeg、Xvfb 和 xdpyinfo。在 engine/ 目錄下使用 pnpm install 安裝一次相依套件。

node <skill-dir>/engine/record.mjs \
  --script /absolute/or/cwd-relative/demo.demo.ts \
  --url https://example.org \
  [--name output-slug] [--formats 16x9,1x1,9x16] \
  [--chrome none|macos|browser] [--storage-state <path>] [--raw]

使用 --formats 選擇一個或多個構圖預設(預設為 16x9),使用 --chrome 選擇要渲染的視窗框架(預設為 none)。格式按照請求的順序渲染,第一個格式用作主格式來編碼 GIF。 9x16 格式是激進的中心裁切(在廣角鏡頭中,約 44% 的頁面寬度是可見的),因此在為直向創作時,請將動作保持在中心。

使用 --raw 可在乾淨擷取後停止。不使用此參數時,預計會得到以下成品:

  • engine/out/<name>-raw.mp4
  • engine/out/<name>-<format>.mp4 (每個請求的格式)
  • engine/out/<name>.gif (從主格式編碼)

執行器在完成時會印出成品的絕對路徑。將即時網站的可重現性視為目標網站的責任,且永遠不要在分鏡腳本中嵌入真實憑證。

已驗證的網站

僅使用暫存或測試帳戶錄製已驗證的流程;絕不使用正式環境的憑證。代理應先使用自己的工具,透過無頭 Playwright 腳本登入一次。如果登入需要透過電子郵件傳送 OTP 或魔法連結,建議的方法是使用代理自己的郵件存取權限 - 在 Claude Code 上使用已連接的 Gmail 連接器/MCP,或在其他執行環境上使用郵件 CLI - 以便代理自行讀取代碼;否則請要求使用者貼上。登入後,使用 await context.storageState({ path: storageStatePath }) 儲存 Session,其中 storageStatePath 是建立為 storageStatePath="$(mktemp -d)/<account>.storage-state.json" 的一次性臨時路徑。然後使用 --storage-state "$storageStatePath" 執行錄製命令。

Playwright 的 storageState 只會還原 Cookie 和 localStorage。將認證資訊儲存在 IndexedDB 或 sessionStorage 中的應用程式會默默地錄製到登出畫面,因此在擷取前請先驗證已驗證的頁面。storage-state 檔案是機密:永遠不要印出或提交它。錄製器在載入後會立即刪除它;這是一次性交接,因此重新錄製需要重新登入,且磁碟上不會留下任何與認證相關的資訊。一次性登入輔助腳本也包含憑證:請保持其臨時性,且永遠不要提交。

在 Remotion Studio 中編輯錄製的展示影片

錄製後匯出一個自包含的專案,然後安裝並開啟 Studio:

node <skill-dir>/engine/scripts/export-project.mjs <name>
cd <skill-dir>/engine/out/<name>-project
pnpm install
pnpm studio

Studio 的時間軸面板顯示編輯器風格的軌道(螢幕膠片、每個字幕一個命名的剪輯、聚光燈、縮放移動和片尾)- 拖曳播放頭來瀏覽,點擊剪輯的行來找到其事件。使用屬性面板或 fixtures/timeline.json 來編輯字幕、縮放時間(保持縮放移動在 1650ms 底限以上)、聚光燈時間和片尾標題。編輯 remotion/theme.ts 來調整顏色、排版、間距和動畫。使用 pnpm render 渲染完成的 16:9 影片。

動畫和分鏡規則(使剪輯可發布的要素)

  • 每個場景一個攝影機移動,而不是每個欄位。 縮放一次到區塊,然後在區塊內操作。每個輸入的縮放讀起來像突兀的剪接。
  • 在頁面轉換時保持廣角,在稀疏頁面上保持廣角。 在點擊進行導覽之前 d.zoomOut();永遠不要在幾乎空白的頁面上縮放到一個狀態藥丸。
  • 接近頁面底部的區塊: d.zoomTo([...locators], { scroll: "center", padding: 48 }) - 攝影機夾具無法將頁面邊緣的矩形居中;滾動居中可以在根層級修正此問題。Locator[] 透過聯合邊界框來框住整個區塊。
  • d.spotlight([...locators]) = Apple 風格的焦點暗化(鏤空 + 光環)。給予充足的 holdMs,在步驟結束前明確使用 d.spotlightOff() + hold(600) 結束。聚光燈矩形必須適合視口(強制執行);縮放矩形依設計可能會溢出。
  • Seed 等待真實資料,而不僅僅是觸發元素 - 否則影片會在骨架畫面上開啟。等待一個已知的內容節點 + 約 600ms。
  • 在結果字幕之前 d.settle(locator)。 提交後重新擷取的檢視會短暫空白;單純的 waitFor 會在第一次繪製時解析,結果字幕會在空白頁面上觸發。
  • 字幕是與游標動作綁定的祈使句;在結束場景中放置一個結果字幕(d.caption(...) 在步驟後期);修剪步驟字幕,使祈使句永遠不會懸掛在已完成的動作之上。
  • d.outro(title) 在最終場景之後,以平靜的結束畫面關閉可發布的剪輯。
  • 始終對最終狀態進行斷言 - 沒有斷言,管線會渲染一個關於中斷流程的精美影片。
  • 永遠不要發布一個包含 localhost URL、內部主機名稱、提供者名稱或真實憑證在螢幕上的剪輯。在 seed 中遮罩僅用於展示的字串(使用 window.open 修補和 MutationObserver 輸入重寫)。

在報告完成前進行驗證

  1. 在 engine/ 目錄下執行 pnpm typecheck && pnpm test。
  2. node scripts/score-motion.mjs out/timeline.json - FAIL 表示阻斷;WARN 縮放速率約 0.78/s 是可接受的穩定狀態;任何不連續性判定都是攝影機錯誤;dead-air WARN 表示靜態區段 >= 3.5 秒且游標移動少於 40 像素 - 請重新調整節奏或加上字幕。
  3. 引擎變更後執行 node scripts/prove-composition.mjs。
  4. 觀看實際渲染結果:執行 ffmpeg -i out/<name>-16x9.mp4 -vf fps=1 out/frames/%03d.png 並查看各幀。縮放裁剪、字幕延遲、鏤空不同步以及螢幕上的開發網址在綠色的測試執行中是不可見的。

常見問題

症狀原因 / 修復方法
Invalid demo viewport ... 中止幾何設定偏移 - 修正啟動旗標,永遠不要放鬆斷言。
游標偏移約 174 像素(垂直方向)Chrome 以分頁模式執行,而非 --app 模式。
找不到打板框架偵測器容許誤差為 64(外部擷取平均不夠純淨);如果仍然遺漏,請檢查擷取是否為黑色畫面(Chrome 使用了錯誤的 DISPLAY)。
字幕/游標在剪輯中漂移打板同步問題 - 不要使用牆鐘時間相減。
聚光燈鏤空偏離目標矩形與平滑滾動競速 - measureTarget 的穩定性迴圈應能固定此問題;如果再次發生,請提高其超時時間。
文字在裁切邊緣被切斷對於模態框,使用 zoomTo(locator, { padding: 120 })。
縮放將內容剪出畫面maximumScale 是品味問題(1.45 有效),不是夾具錯誤。

驗證引擎變更

從 engine/ 目錄執行:

pnpm typecheck && pnpm test
node scripts/prove-composition.mjs

相關技能