影片解說員 (Video Explainer)
您的創作方式如同動態設計師,但以程式碼實現:每個場景都是一個小型 JS 模組,負責建構 DOM/SVG 元素,並將動畫加入一個暫停的 GSAP 時間軸。渲染器會逐幀搜尋該時間軸 (t = frame / fps),截取每一幀,並將這些畫面傳送給 ffmpeg。輸出結果是確定性的:相同的專案永遠會渲染出相同的畫面。
SKILL_DIR 代表此技能的基底目錄 (即包含此檔案的資料夾)。
設定 (每部機器只需執行一次)
cd SKILL_DIR/scripts && npm install && npx playwright install chromium
您也需要將 ffmpeg 加入 PATH。如果缺少相依套件,所有腳本都會印出此安裝指令。
工作流程
- 先做故事板。 與使用者確認主題、目標觀眾、目標長度以及是否需要旁白,然後在
video.json中撰寫場景清單。每個場景需包含narration(旁白內容) 和visual(畫面描述)。請先閱讀reference/storyboard.md。在故事板本身合理之前,請勿撰寫任何場景程式碼。 - 建立專案框架:
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)。 - 旁白 (如果需要): 遵循
reference/voiceover.md的步驟。簡而言之:在video.json中加入"voice"區塊,執行node SKILL_DIR/scripts/narration.mjs status <project-dir>,針對列出的每個場景呼叫 OpenRouter MCP 的generate-speech工具 (參數必須完全依照輸出),然後使用narration.mjs add註冊每個儲存的音檔。請在檢查 (步驟 4) 之前完成此步驟,因為真實的音訊會改變場景長度與cue()的觸發時機。 - 檢查:
node SKILL_DIR/scripts/lint.mjs <project-dir>。它會在 Chromium 中載入每個場景,並回報載入錯誤、動畫時間長於場景時間、在tl之外建立的動畫、超出畫面的元素、文字被截斷,以及旁白過長於所屬場景等問題。請修正所有警告,除非是刻意為之。 - 預覽:
node SKILL_DIR/scripts/render.mjs <project-dir> --contact-sheet,然後檢視那張 PNG 圖片 (<project-dir>/out/contact-sheet.png)。檢查層次結構、重疊情況、可讀性、空白幀與時間安排。如需查看特定時間點,請使用--stills 12.5,30。反覆調整直到視覺效果正確為止,然後在最後一次編輯後再執行一次 contact-sheet 的步驟。 - 渲染:
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(...)、CSSanimation/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 包含完整的流程、模型與語音選擇,以及相關成本。