Explainer
不露臉解說是一種語音旁白搭配一個連續、由程式碼建構的動畫世界(例如剖面圖、放大後的機制、手中持物),頂端有字幕,無音樂。輸出為 1080×1920 的 mp4 影片。
閱讀以下文件後再開始撰寫:
script-craft.md:腳本如何塑造(鉤子、轉折、想像、機制、翻轉、行動呼籲)及其節奏。craft-rules.md:讓視覺效果生動且有立體感的原則。一個稱職的初版通常會違反其中大部分規則。
最困難的部分是每個節拍的視覺隱喻。第二困難的是保持每一幀都在移動且有光線層次。程式碼反而是最簡單的部分。
模式
- 一鍵生成(預設): 從概念到最終影片不間斷。自行做出判斷,並在最後報告你的決定。
- 審查模式: 如果使用者要求審閱或批准,則暫停兩次:一次在腳本完成後,一次在故事板完成後。根據他們的意見修改並繼續。
環境設定(一次性)
確保 ffmpeg 在 PATH 中、remotion/node_modules 已存在(否則在 remotion/ 目錄下執行 npm install),以及 .env 檔案中包含 FISH_API_KEY(複製 .env.example)。如果沒有 API 金鑰,則使用 voice --placeholder 建立所有內容,並告知使用者最後一步是重新執行一次 voice 命令並進行渲染。
專案結構
projects/<概念>/(概念是 slug 格式,例如 how-fridges-work):
script.txt,storyboard.mdcomposition.tsx(圖層堆疊),timeline.ts(TL),captions.ts,words.ts(自動產生),scenes/S01.tsx…public/vo.wav,vo/(原始錄音與對齊結果),out/(渲染輸出、靜止幀)
核心程式庫為 remotion/src/core(場景透過 ../../../remotion/src/core 導入):
makeTimeline→TL.at("短語"),TL.end("短語")Captions,Drift,Bokeh,Vignette,handheld,Backdrop,Dust,FootnoteCamera(WorldSvg,camAt,toScreen),Label,Sparks,Snow/Rain- 緩動函數,
ramp,keys,rand, 字型SANS/MONO
工具:python3 bin/explainer.py …(執行 -h 查看幫助)
| 命令 | 功能說明 |
|---|---|
new <c> | 建立專案結構 |
voice <c> [--voice-id ID] [--speed 1.0] | 使用 Fish Audio 生成語音和時間戳記 → words.ts,以及調整為 −14 LUFS 的 public/vo.wav。印出每分鐘字數 (wpm) |
voice <c> --placeholder [--wpm 200] | 生成靜音音頻和合成時間點,無需 API 呼叫 |
stills <c> <秒數>… | 在指定秒數擷取畫面 → 在 out/ 中生成一張聯絡表。檢視它 |
studio <c> | 在 Remotion Studio 中即時預覽(供使用者使用) |
render <c> [--blur] | 在 out/ 中輸出 60 fps 的 mp4。--blur 以 240 fps 渲染並平均為 60 fps 以實現動態模糊(約慢 4 倍) |
qa <c> | 活躍度檢查:凍結畫面 < 10%,無連續凍結時間 ≥ 0.3 秒。失敗時退出碼為 1,並列出每個凍結片段的名稱 |
工作流程
-
腳本。 執行
new <c>。- 如果使用者提供了腳本,請逐字使用(僅將數字和符號修正為單字)。
- 否則根據
script-craft.md撰寫script.txt:預設為日常物品格式(270–320 字),產品和網路則使用系統格式。執行其檢查清單。 - 審查模式:停下來等待批准。
-
語音。 執行
voice <c>,然後檢查印出的 wpm(目標為 190–215;如果偏差過大,使用建議的--speed重新執行)。- 語音使用
--voice-id,否則使用FISH_VOICE_ID,否則使用 Fish 的預設語音。已複製的語音 ID 也能以相同方式使用。 - 模型使用
--model,否則使用FISH_MODEL,否則使用s2.1-pro。 - 以
words.ts為準,而非script.txt。 語音會拼出數字,而TL.at()和字幕短語必須與口語詞匹配。
- 語音使用
-
故事板(
storyboard.md)。先填寫世界部分,然後每個節拍一行。要為節拍構思隱喻時,請思考如果觀眾能夠這樣做,他們會看到什麼:- 放大: 一個剖面或分解視圖。
- X 光透視: 物體內部。
- 時間放慢: 傳播中的波、切換中的零件。
- 測量: 讀數上升或下降。
「想像」場景成為一個遊歷世界,每個機制節拍則返回主圖表。執行故事板檢查。
- 審查模式:停下來等待批准。
-
建構。 在
scenes/中為故事板的每個鏡頭撰寫一個場景檔案,並將每個場景加入composition.tsx。- 每個場景是一個以
t為參數的純函數,在其時間視窗之外返回null。 - 定時: 每個事件都對應到
TL.at("精確詞語")。切勿使用原始秒數。 - 連續性: 共享同一圖表的節拍應放在一個場景中,並使用一條攝影機路徑(A4)。
- 移動: 每個場景透過移動進入,並與前一場景的退出重疊(A2)。
- 為每個場景的 SVG ID 加上前綴。
- 每個場景是一個以
-
迭代。 在每個鏡頭的關鍵詞位置執行
stills,並根據工藝規則 A 和 B 檢視結果。然後執行render和qa。針對每個 FROZEN 片段,在其對應的鏡頭中賦予一個運動載體(A1b)來修復。手動撰寫captions.ts短語:每個短語包含一個主要名詞(琥珀色,說話時彈出)。 -
交付。 最終的
render必須通過qa(如果使用者追求極致品質,可使用--blur)。提供使用者:- mp4 檔案路徑
- 腳本
- 故事板每個節拍的一行摘要
- 任何仍需要真實錄音的佔位語音
紅旗警訊:停下來修正
| 想法 | 規則 |
|---|---|
| 「這個節拍換個新場景能保持新鮮感」 | C1:一個主要圖表加上 1–2 個遊歷世界。數一數 |
| 「在關鍵時刻保持完全靜止以營造懸念」 | A1c:讓主體停止,但攝影機和環境保持移動 |
| 「加上背景音樂、顆粒感或一個音效來強調」 | D, B8:只有語音,無顆粒感;深度來自光線 |
| 「淡入淡出」 / 「交叉淡入下一個場景」 | A2:透過移動來進入、退出和過渡 |
| 「整體的浮動效果就能保持畫面活力」 | A1b:每個鏡頭需要一個 10–60 px/s 的中型移動元素 |
| 「這個節拍切到更近的攝影機」(同一圖表) | A4:一個世界,一台攝影機;交接關鍵影格 |
| 「均勻照明沒關係,這只是個圖表」 | B1:光線向暗處漸變、邊緣光、暗角 |
| 「啟動時將整個畫面染色」 | B4:從原因開始傳播,要有前端和流向 |
| 「用矩形表示物體就夠了」 | B2:進行一次解剖建模;建構拉開後會顯露的結構 |
「看起來沒問題,跳過 qa」 | E:qa 必須 PASS;肉眼會忽略凍結畫面 |