Communitygithub.com

demo-reel

根據簡短腳本,錄製流暢、幀精確的 60 fps 示範影片 — 包含腳本化游標、高亮光暈、點擊波紋、字幕與角落徽章,並在虛擬時鐘上渲染以確保不卡頓,最終編碼為可在 PowerPoint、Keynote 或網頁上循環播放的 MP4。

demo-reel 是什麼?

demo-reel 是一款專為開發者設計的 AI 代理技能,能將網頁應用的腳本操作流程轉化為如同專業螢幕錄製般流暢的示範影片。它透過在無頭 Chromium 中注入虛擬時鐘來驅動真實應用,確保每一次幀繪製都精確對齊目標幀率(如 60 fps),從而避免傳統錄製工具因機器性能不足而產生的卡頓。支援多種平台(Claude Code、Cursor、Codex 等),適用於產品展示、功能導覽、前後對比、投影片片段或登陸頁面嵌入等場景。其工作流程包括:提供應用服務、編寫 JavaScript 場景腳本、執行錄製、以及透過聯繫表進行品質檢查。此外,demo-reel 還能自動添加游標光暈、點擊波紋、文字字幕和角落徽章等視覺元素,最終輸出 H.264 編碼的 MP4 檔案,確保在主流簡報工具與網頁中順暢播放。

相容平台~Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/hasuwini77/demo-reel/tree/main/skills/demo-reel

在你喜歡的 AI 中提問

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

預覽

來自技能 README

說明文件

demo-reel 是做什麼的?

將網頁應用的腳本操作流程轉換為宛如專業螢幕錄製的影片:流暢的 60 fps 畫面、帶有光暈的可見游標、點擊波紋與字幕。它驅動真實應用於無頭 Chromium 中運行 — 影片內容就是產品本身,而非模擬畫面。

為何影片如此流暢

一般的螢幕錄製工具在瀏覽器自然繪製時才擷取畫面;在效能較差的機器(或使用軟體 WebGL)上,通常只有約 10–15 fps 且會卡頓。demo-reel 則透過注入虛擬時鐘(scripts/inject.js)來解決:requestAnimationFrame、performance.now 和 Date 僅在錄製器指示時才前進,同時 CSS 與網頁動畫透過 document.getAnimations() 逐步推進。每個幀精確推進 1/fps,進行螢幕截圖,並傳送至 ffmpeg 編碼。無論一個幀需要多久時間渲染,最終結果都將完美流暢播放。

計時器(setTimeout/setInterval)刻意保持真實 — 偽造它們會導致載入器和排程器中的零延遲計時器鏈無限循環(這就是 Playwright 的 page.clock 在多個 WebGL 頁面上會卡住的原因)。

需求

  • Node 18+,ffmpeg 已加入 PATH。
  • 在此技能的目錄下執行一次:npm install && npx playwright install chromium。

工作流程

  1. 提供應用服務,讓使用者以他們看到的方式運行 — 理想上使用正式建置版本(vite build && vite preview、next build && next start)並搭配本地或模擬資料。開發伺服器雖然可用,但速度較慢且可能顯示開發工具覆蓋層。切勿錄製真實或敏感資料 — 請使用示範資料。
  2. 編寫腳本(*.scenario.mjs,詳見下方 API)。可從 examples/tasks.scenario.mjs 開始。將其規劃為一個故事:20–60 秒,每個字幕一個想法,每個結果後停留 1–2 秒讓觀眾閱讀。
  3. 錄製:node scripts/record.mjs my.scenario.mjs --out demo.mp4 一段 60 秒的 1080p 片段大約需要 3–10 分鐘(沉重的 WebGL 頁面最慢)。請在背景執行。
  4. 品質檢查:scripts/sheet.sh demo.mp4 會生成一張聯繫表(每 2.5 秒一個幀)。檢查:字幕與螢幕內容匹配,沒有載入旋轉圖示,沒有任何內容被字幕遮擋,徽章/游標可見。透過提取連續幾個幀來抽查流暢度 — 運動期間每個幀應略有不同。
  5. 交付(請參閱「使用影片」章節)。

腳本 API

export default {
  size: "1920x1080",          // 視埠 = 影片尺寸
  fps: 60,
  theme: { captionPosition: "bottom", haloFill: "rgba(250,204,21,.30)" }, // 可選
  async run(d) {
    await d.open("http://localhost:4173/");     // 導航 + 穩定(不錄製)
    d.badge("NEW", "#15803d");                  // 角落徽章(null 則隱藏)
    d.caption("全新的儀表板");                   // 字幕藥丸(null 則隱藏)
    await d.hold(1500);                          // 錄製 1.5 秒,保持原樣
    await d.click(d.page.getByRole("button", { name: "篩選器" }));
    d.caption("篩選器集中在一個面板");          // 在**動作之後**設定字幕
    await d.hold(1200);
    await d.type("Stockholm");                  // 人類速度打字
    await d.press("Enter");
    await d.scroll(600);                        // 平滑滾輪
    await d.step("可選部分", async () => { /* 失敗會被記錄,錄製繼續 */ });
  },
};
呼叫功能
d.open(url, { settle })導航,讓頁面穩定(不錄製,預設 2500 毫秒)。
d.hold(ms)錄製當前頁面狀態。
d.settle(ms)不錄製地推進時間 — 跳過載入狀態、懶加載塊、你不希望顯示的佈局動畫。
d.move(target, { ms }) / d.hover將游標平順(緩動)移動到目標。
d.click(target, { ms, button })移動、點擊並產生波紋。button: "right" 用於右鍵選單。
d.doubleClick(target)雙擊。
d.type(text, { delay })逐鍵輸入(預設每鍵 90 毫秒)。
d.press(key)鍵盤快捷鍵,例如 "Escape"、"Control+K"。
d.scroll(dy, { ms })平滑滾輪。
d.caption(text) / d.badge(text, color) / d.cursor(bool)疊加層狀態;在全頁導航後仍可保留。
d.step(name, fn)命名步驟;錯誤會被記錄,不會導致流程中斷。
d.page、d.point(target)、d.width、d.height逃生口。

目標可以是 Playwright Locator、CSS 選擇器字串、{ x, y } 物件,或非同步函數 (page) => ({ x, y })。

Canvas 渲染的 UI(圖表、地圖、圖形)中每個項目可能沒有對應的 DOM 元素 — 請傳入一個函數,向 UI 函式庫查詢螢幕座標。以下是 Cytoscape.js 的範例:

const node = (label) => (page) => page.evaluate((label) => {
  const el = [...document.querySelectorAll("div")].find((e) => e._cyreg?.cy);
  const n = el._cyreg.cy.nodes().filter((n) => n.data("label") === label)[0];
  const r = el.getBoundingClientRect(), p = n.renderedPosition();
  return { x: r.left + p.x, y: r.top + p.y };
}, label);
await d.click(node("Server A"));

撰寫良好示範的技巧

  • 字幕要誠實。只敘述畫面中實際顯示的內容。如果你想展示的 bug 在錄製中沒有重現,請修改字幕 — 不要保留原字幕。
  • 在動作之後設定字幕,而非之前 — 否則下一個畫面的字幕會覆蓋在前一個畫面上。
  • 展示結果,而非點擊過程。每個結果停留 1–2 秒;使用 d.settle 跳過載入時間。
  • 前後對比:使用相同故事和步驟錄製兩個腳本,分別標記爲 BEFORE/AFTER(紅色/綠色)徽章,並分別保存爲獨立檔案,也可選擇進行合併。
  • 英雄時刻(登陸頁面、動畫):給予 5–10 秒 — 觀眾需要時間來消化。
  • 保持游標平靜:每次移動 600–900 毫秒,在保持靜止時將游標移離內容區域。
  • 真實計時器在幀渲染期間(每個幀約 50–300 毫秒真實時間)持續運行,因此計時器驅動的 UI — 如提示訊息、防抖搜尋、自動消失的工具提示 — 在影片中可能比實際情況消失得更快。請在需要它們顯示之前立即觸發,或減少停留時間。

使用影片

  • PowerPoint:插入 → 影片 → 此裝置。播放索引標籤:開始:自動 和 循環直到停止。H.264 yuv420p MP4(demo-reel 的輸出格式)可在 Windows 和 macOS 上正常播放。
  • Keynote:拖入;影片 → 重複:循環。
  • 網頁:<video src="demo.mp4" autoplay loop muted playsinline></video>。
  • GIF(README、聊天):ffmpeg -i demo.mp4 -vf "fps=20,scale=960:-1:flags=lanczos,split[a][b];[a]palettegen[p];[b][p]paletteuse" demo.gif
  • 合併相同尺寸/幀率的片段:printf "file 'a.mp4'\nfile 'b.mp4'\n" > l.txt && ffmpeg -f concat -safe 0 -i l.txt -c copy both.mp4

故障排除

症狀解決方法
空白 / 「載入中…」幀在 d.open 中延長 settle 時間,或在導航點擊後使用 await d.settle(1500)。
目標不可見目標在畫面外或處於關閉選單內 — 先展開/滾動;對於 Canvas 項目,請使用點函數。
WebGL/3D 渲染為黑色保留預設啟動標誌(--use-angle=swiftshader);雖然慢(約 0.25 秒/幀)但正確。
影片比預期短或長長度是精確的:所有 hold 和移動時間的總和。settle 時間從不被錄製。
在 PowerPoint 中顏色看起來偏淡請勿在沒有 -pix_fmt yuv420p 的情況下重新編碼;demo-reel 的輸出已經是正確的。
文字稍微模糊使用 --png 擷取無失真幀(較慢、檔案較大)。

相關技能