產品影片即程式碼 是做什麼的?
將產品影片建立為程式碼:由確定性時間軸驅動的 HTML 投影片、AI 語音旁白、真實的產品螢幕錄製,以及 ffmpeg 音訊主控。一切皆可重現、可比對且可重新渲染,因此修訂只需要幾分鐘,而非重新製作。
這不是影片編輯器。這是一條管線。輸出為 MP4。
唯一重要的觀念
音訊優先,然後時間,再來畫面。
在決定任何畫面停留多久之前,先產生旁白。測量每個片段,從這些測量值推導場景持續時間,然後才渲染影格。替代方案——猜測持續時間,或為了配合固定腳本而編寫旁白——會產生與語音不同步的畫面,且每次改寫台詞時都必須重新渲染。
script.json ──► TTS ──► measure ──► timings.json ──► render ──► composite ──► mux ──► MP4
▲ ▲ ▲
assemble.py render.py composite.py
對於沒有旁白的影片(標題動畫、無聲循環、靜音社群短片),跳過第 1 階段,手動撰寫 timings.json。後續所有步驟保持不變。
管線
| 階段 | 腳本 | 產出 |
|---|---|---|
| 1. 旁白 | 自行選擇的 TTS 工具 | 每個場景一個 audio/vo_NN.mp3 |
| 2. 時間軸 + 語音音軌 | scripts/assemble.py | timings.json、out/voice.wav |
| 3. 畫面 | scripts/render.py | out/silent.mp4 |
| 4. 螢幕錄影 (選用) | scripts/capture/tour.py | capture/clips/*.mp4 |
| 5. 合成 (選用) | scripts/composite.py | out/composited.mp4 |
| 6. 音訊主控 | scripts/mux.py | 最終 MP4 |
閱讀 references/PIPELINE.md 了解逐步說明,references/AUDIO.md 了解語音與音樂,references/SCREEN-CAPTURE.md 了解產品畫面,以及在除錯任何問題前先閱讀 references/PITFALLS.md——它列出了這條管線實際遇過的失敗案例。
影片類型
整個管線相同;不同之處在於結構、節奏以及畫面中真實產品的比例。在撰寫任何一行之前,先確定你正在製作哪一種,因為它決定了所有其他事項。
| 類型 | 典型長度 | 結構 | 素材 |
|---|---|---|---|
| 產品說明 | 1-3 分鐘 | 問題 → 轉折 → 運作方式 → 證明 → 結尾 | 少量,作為證明 |
| 功能發布 | 30-90 秒 | 改變了什麼 → 為何重要 → 親眼看看 → 如何取得 | 中等 |
| 示範/逐步解說 | 2-5 分鐘 | 一個真實任務,從頭到尾 | 主導 |
| 教學 | 3-10 分鐘 | 步驟化、章節式、暫停以便跟上 | 主導 |
| 版本發布說明 | 30-90 秒 | 每個要點一項,資訊密集 | 螢幕截圖或短片段 |
| 新手引導 | 1-3 分鐘 | 使用者初次執行的路徑 | 主導 |
| 標題動畫/循環 | 5-20 秒 | 一個想法,通常無聲 | 無 |
| 社群短片 | 60 秒以下 | 鉤子開頭,從較長影片衍生 | 短而有力 |
根據類型衍生的經驗法則:
- 示範與教學以素材為優先。 投影片只是產品的邊框——標題卡、提示框、章節分隔線。不要旁白螢幕上已經說明的內容。
- 說明與發布以旁白為優先。 素材作為你剛剛提出的主張的證據出現;這種相鄰性讓它更有說服力。
- 教學需要留白。 每個步驟後留一個拍子。善用
--tail;觀眾正在跟著做,而非觀看。 - 版本發布說明資訊密集。 螢幕文字承載資訊,旁白摘要敘述。每個要點一項,不拖泥帶水。
- 社群短片是衍生物,絕不重寫。 將其建構為長影片的場景子集,這樣它們就不會產生偏差(請參閱 PIPELINE.md)。
快速入門
設定,只需一次:pip install -r requirements.txt && playwright install chromium。
ffmpeg 和 ffprobe 也必須在 PATH 中。
先測試無聲版本,確認投影片能正常渲染:
cp templates/deck.html .
python3 scripts/render.py --preview 2 8 18 # 靜止畫面
python3 scripts/render.py # -> out/silent.mp4
然後在有旁白的情況下執行完整管線:
cp templates/script.example.json script.json
# 產生 audio/vo_01.mp3 ... 每個場景一個,然後:
python3 scripts/assemble.py # timings.json + out/voice.wav
python3 scripts/render.py # out/silent.mp4
python3 scripts/mux.py --final out/final.mp4 # 加入語音(如果 audio/bed.mp3 存在則加入音樂)
assemble.py 是唯一需要音訊的階段;沒有音訊時,render.py 會使用投影片中宣告的持續時間。
讓它正常運作的規則
絕不依賴時鐘時間驅動時間軸。 渲染器會跳到明確的 t 並截圖。render.py 為每個影格呼叫 window.__seek(t),因此慢速機器產生的檔案與快速機器完全相同。任何使用 requestAnimationFrame 或 CSS 動畫播放的方式都會在截圖循環中造成影格撕裂或掉幀。
將每個動畫與旁白的拍點對齊。 如果語音在 4.2 秒說「三件事」,第三張卡片就在 4.2 秒出現。每次改寫後,重新檢查拍點——一句縮短了 3 秒的台詞會讓其對應的畫面無法銜接。這是決定結果看起來有導播意圖還是平淡無奇的最大單一因素。
以可恢復的區塊進行渲染。 render.py 會寫入 out/parts/part_NNN.mp4,並在重新執行時跳過已完成的區塊。一次截圖卡住只損失一個區塊,而非整個過程。絕不要對同一個 parts 目錄執行兩個渲染程序。
測量,不要假設。 用數字驗證,而非感覺:
- 空白影格偵測:計算暗色像素 (
(pixels < 200).mean()),而非標準差——一個正常白色多的 UI 頁面標準差也可能很小 - 發音:將產生的音訊透過語音轉文字工具反向辨識並閱讀
- 音量:每次都在最終檔案上執行
ffmpeg -af volumedetect - 幾何:從 DOM 讀取
getBoundingClientRect(),避免硬編碼
一個來源,多種剪輯版本。 使用查詢參數(deck.html?cut=short)從單一投影片中選取場景子集,這樣一個長示範影片和一個 40 秒的社群短片就不會產生偏差。請參閱 references/PIPELINE.md。
從產品的程式碼中匹配其品牌
如果產品有程式碼庫,直接從中讀取品牌資訊,而非詢問色碼:
python3 scripts/detect_brand.py ../their-product --css
它會讀取設計 Token 檔案、tailwind 配置、CSS 自訂屬性、SCSS 與 Less 變數、JS/TS 主題物件以及 Web Manifest,並回報找到的字型、圖示庫和標誌檔案。將它輸出的 :root 區塊貼到 deck.html 中。
由於 dist/ 資料夾充滿了非品牌元素的第三方元件庫 CSS,因此建置輸出會被跳過。調色盤也會檢查一致性,而非僅信任名稱匹配:一個為淺色主題定義 --surface、為深色主題定義 --bg 的儲存庫,否則會產出黑底白字的不一致畫面。拒絕的結果會印出,絕不會默默套用。
在渲染前,向使用者顯示偵測到的與被拒絕的內容。
設計指引
投影片是 HTML/CSS,因此設計完全由你決定。有兩件事值得知道:
社交和自動播放環境是靜音的。畫面上的標題必須獨自承載每個要點,鉤子必須在前一兩秒內抓住觀眾。將語音旁白視為增強效果,而非傳遞資訊的主要機制。
如果被要求做出視覺上獨特的效果,要以主題本身的領域——它的產物、工具和慣用語——為基礎,而非使用深色背景加一個亮色強調色,那是常見的通用輸出。Anthropic 的 frontend-design 技能在這方面做得很好,並且能與此技能順暢搭配。