Communitygithub.com

lleadbet/video-explainer-skill

建立資訊型解說影片 (MP4),透過以 HTML/SVG/CSS 搭配 GSAP 撰寫動畫 2D 場景,並使用無頭 Chromium 與 ffmpeg 逐幀渲染。

video-explainer-skill 是什麼?

此技能讓 AI 助理能像動態設計師一樣,以程式碼製作 2D 解說動畫影片。每個場景都是一個小型 JavaScript 模組,負責建構 DOM/SVG 元素並將動畫加入一個暫停的 GSAP 時間軸。渲染器會逐幀移動時間軸、截取畫面,並將畫面序列傳送給 ffmpeg 合成 MP4 影片。輸出結果是確定性的 (deterministic):相同的專案每次都會產生相同的畫面。支援完整的開發流程:故事板規劃、場景程式碼撰寫、語音旁白整合 (透過 OpenRouter MCP)、Lint 檢查、接觸式底片預覽,最後渲染出最終影片。此技能適用於 Claude Code、Cursor、Codex 等支援自訂技能的工具,特別適合需要產生動畫圖表、逐步解說或動畫流程圖的場景。

相容平台~Claude Code~Codex CLI~Cursor✓Gemini CLI
npx skills add https://github.com/lleadbet/video-explainer-skill/tree/HEAD

在你喜歡的 AI 中提問

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

說明文件

影片解說員 (Video Explainer)

您的創作方式如同動態設計師,但以程式碼實現:每個場景都是一個小型 JS 模組,負責建構 DOM/SVG 元素,並將動畫加入一個暫停的 GSAP 時間軸。渲染器會逐幀搜尋該時間軸 (t = frame / fps),截取每一幀,並將這些畫面傳送給 ffmpeg。輸出結果是確定性的:相同的專案永遠會渲染出相同的畫面。

SKILL_DIR 代表此技能的基底目錄 (即包含此檔案的資料夾)。

設定 (每部機器只需執行一次)

cd SKILL_DIR/scripts && npm install && npx playwright install chromium

您也需要將 ffmpeg 加入 PATH。如果缺少相依套件,所有腳本都會印出此安裝指令。

工作流程

  1. 先做故事板。 與使用者確認主題、目標觀眾、目標長度以及是否需要旁白,然後在 video.json 中撰寫場景清單。每個場景需包含 narration (旁白內容) 和 visual (畫面描述)。請先閱讀 reference/storyboard.md。在故事板本身合理之前,請勿撰寫任何場景程式碼。
  2. 建立專案框架: node SKILL_DIR/scripts/new.mjs <project-dir> --title "...",然後編輯 video.json,並在 scenes/<id>.js 中為每個場景撰寫一個模組。動畫範例請參考 reference/animation-patterns.md;版面、字體與色彩規範請參考 reference/design.md。如果有旁白,將場景持續時間設為 "auto",並使用 cue('phrase') 來配合動畫時機。以下是兩個完整的配音影片範例:examples/kubernetes-overview/ (使用 ElevenLabs) 和 examples/how-dns-works/ (使用 Gemini)。
  3. 旁白 (如果需要): 遵循 reference/voiceover.md 的步驟。簡而言之:在 video.json 中加入 "voice" 區塊,執行 node SKILL_DIR/scripts/narration.mjs status <project-dir>,針對列出的每個場景呼叫 OpenRouter MCP 的 generate-speech 工具 (參數必須完全依照輸出),然後使用 narration.mjs add 註冊每個儲存的音檔。請在檢查 (步驟 4) 之前完成此步驟,因為真實的音訊會改變場景長度與 cue() 的觸發時機。
  4. 檢查: node SKILL_DIR/scripts/lint.mjs <project-dir>。它會在 Chromium 中載入每個場景,並回報載入錯誤、動畫時間長於場景時間、在 tl 之外建立的動畫、超出畫面的元素、文字被截斷,以及旁白過長於所屬場景等問題。請修正所有警告,除非是刻意為之。
  5. 預覽: node SKILL_DIR/scripts/render.mjs <project-dir> --contact-sheet,然後檢視那張 PNG 圖片 (<project-dir>/out/contact-sheet.png)。檢查層次結構、重疊情況、可讀性、空白幀與時間安排。如需查看特定時間點,請使用 --stills 12.5,30。反覆調整直到視覺效果正確為止,然後在最後一次編輯後再執行一次 contact-sheet 的步驟。
  6. 渲染: node SKILL_DIR/scripts/render.mjs <project-dir> → <project-dir>/out/video.mp4。旁白音檔會自動混合進去。將輸出路徑、影片時長和場景清單提供給使用者。使用者也可以透過 node SKILL_DIR/scripts/serve.mjs <project-dir> 進行互動式預覽 (可拖曳時間軸、播放/暫停、播放旁白、按 c 切換字幕、按 m 靜音)。

實用的渲染選項:--out file.mp4 (指定輸出檔名)、--from 10 --to 20 (只渲染片段)、--scale 0.5 (快速草稿)、--workers N (並行處理數量)、--crf 18 (品質控制)、--audio track.mp3 (使用自訂音軌取代旁白)、--no-voice (靜音)、--audio-codec aac (預設為 MP3,此格式亦可在 VS Code 中播放)。

專案結構

my-video/
  video.json          # 包含標題、寬度、高度、fps、種子、轉場、主題、scenes[]
  scenes/<id>.js      # 每個場景一個模組
  assets/             # 圖片/SVG,引用為 '/assets/x.svg'
  audio/              # 旁白音檔 + manifest.json (由 narration.mjs 產生;請保留它們,因為重製需要成本)
  style.css           # 可選,若存在會自動載入
  out/                # 渲染輸出 (contact-sheet.png, stills/, video.mp4)

video.json 的場景欄位:id (必要,也是 scenes/<id>.js 的預設檔名)、duration (秒數,或 "auto":自動符合旁白音檔長度,或在音檔產生前以朗讀速度估算,且絕不會短於動畫長度)、narration、visual、可選的 file,以及可選的 transition ("fade" 為預設值,或 "cut")。頂層的 "voice" 區塊請參考 reference/voiceover.md。

場景合約 (Scene Contract)

import { h, reveal, pop } from '/__runtime/helpers.js';

export default function ({ el, tl, gsap, theme, width, height, random, onFrame, cue, voice }) {
  const title = h('div', { class: 'h1' }, 'Hello');
  el.append(h('div', { class: 'center' }, title));
  reveal(tl, title, { at: 0.3 });                       // tl 時間 0 = 此場景的開始
  tl.to(title, { color: 'var(--accent)', duration: 0.5 }, cue('the key idea'));  // 當旁白唸到該片語時觸發
}
  • el:此場景的容器。它涵蓋整個 1920×1080 的舞台,並且系統會自動為您顯示和隱藏。
  • tl:此場景的時間軸。所有動畫都必須加在 tl 上 (或是加到另一個能被加入 tl 的時間軸)。絕對不要直接使用 gsap.to(...)、CSS animation/transition、setTimeout、setInterval、requestAnimationFrame、<video>,或任何依賴於真實時間 (wall-clock time) 的機制。渲染器只會移動時間軸的播放頭,因此任何不在時間軸上的東西最終都會在 MP4 中凍結或不同步。
  • cue(phrase, offset = -0.15):回傳 phrase (不區分大小寫,且必須出現在此場景的旁白中) 被唸出時的場景時間。一旦音檔存在,它會對齊到音檔中測量到的停頓點,因此句子開頭的片語會精準落在該單詞被說出的時刻。如果找不到該片語則會拋出錯誤。對於每個需要與旁白同步的 at 時間點,都應該使用它。voice 物件提供 { start, duration, end, estimated },代表此場景中語音的相關資訊 (例如,讓一個循環動畫一直運行到 voice.end)。
  • 對於逐幀繪製 (例如 Canvas、程序化動畫),請使用 onFrame((sceneTime) => draw(sceneTime))。這個回呼函式會在場景可見期間的每一幀被呼叫。
  • 疊加層 (選擇性): 在 video.json 中設定 "overlay": "scenes/_overlay.js",可以加入一個在整個影片中繪製於每個場景之上的模組,例如時間碼、進度條、Logo 或邊框。它會收到 { el, tl, onFrame, scenes, duration, ... } 參數,其中 onFrame((t) => ...) 接收的是全域時間,而 scenes 會列出每個場景的 start / end。
  • random() 是每個場景獨立播種的,Math.random 也一樣,因此隨機版面是可重現的。
  • 此函式可以是 async (例如用來 fetch('/assets/data.json'))。字體會在場景執行前載入完畢,因此測量文字寬度等操作可以正常運作。
  • 主題顏色是 CSS 變數:var(--bg) --surface --surface2 --fg --muted --accent --accent2 --accent3 --accent4 --danger,以及 --font 和 --mono。可以在 video.json 中覆蓋它們:"theme": { "accent": "#ff3366" }。
  • GSAP 插件已全域註冊:DrawSVG, MotionPath, MorphSVG, SplitText, Text, ScrambleText, CustomEase。

品質標準 (Quality Bar)

  • 每個場景只傳達一個概念。畫面上應至少每 2–3 秒有物件移動或變化,並且每個動畫都應與其說明的旁白句子同步 (使用 cue();旁白語速約每秒 2.5 個單詞)。
  • 文字要夠大:在 1920×1080 的舞台中,主體內文 ≥ 40px,標籤 ≥ 26px。請確保文字位於安全區域內 (.safe,邊界為 96/128px)。
  • 逐步建構圖表,而不是直接展示完成的圖表。
  • 每個場景結束時,在淡出前保留短暫的停頓,以便觀眾閱讀最終狀態。

旁白 (Voiceover)

音訊來自 OpenRouter MCP 伺服器 (generate-speech);此技能僅負責規劃和記錄旁白。如果這些工具不可用,請告知使用者旁白功能需要連接 OpenRouter MCP 伺服器,並先在不包含旁白的情況下進行渲染。reference/voiceover.md 包含完整的流程、模型與語音選擇,以及相關成本。

相關技能