程式化解說影片
環境
- 安裝 Manim:
uv tool install manim。如果報 pycairo 找不到 pkg-config,先執行brew install pkgconf。 - 配音和轉錄使用 MiniMax 的命令列工具
mmx。安裝:npm install -g mmx-cli,再使用mmx auth login --api-key <你的 MiniMax API Key>登入。如果mmx回報未登入或餘額不足,停下來告知使用者。 contact_sheet.py使用系統 Python 的 Pillow,還需要ffmpeg和ffprobe(brew install ffmpeg)。- macOS 預設使用 PingFang SC。Linux 請先安裝中文字型,例如 Debian/Ubuntu 的
fonts-noto-cjk。基底類別會檢查字型是否存在,缺失時會停止。自訂字型可使用EXPLAINER_CN_FONT和EXPLAINER_EN_FONT指定,字型必須支援內文中的字元。其他系統請使用對應的套件管理器安裝 Manim、Pillow 和 FFmpeg。 - 網路上的 3Blue1Brown 範例大多是使用
manimlib撰寫,API 與 Manim Community 不同,請勿直接照抄。 - 本技能的
scripts/:gen_audio.py:產生配音和逐字時間戳。explainer_base.py:場景基底類別、字幕分割、計時、排版和清理。contact_sheet.py:根據動畫節點及每段最長字幕抽幀拼圖,優先檢查兩行字幕的版面配置。verify_video.py:核對完整成片的字幕字形、配音時間和解碼結果。test_subtitles.py:使用真實 Manim 渲染重現舊有錯誤並驗證字幕回歸。
流程
專案目錄放在 ~/video-studio/explainers/<主題>/。
- 寫大綱。按照「提出問題 → 具體例子 → 例子怎麼變化 → 一般規則 → 用新例子檢驗 → 回答開頭的問題」的順序,拆成 5 到 10 段,每段只講一個重點。如果總長超過 3 分鐘,先把大綱發送給使用者確認。
- 寫
narration.json。鍵是段落名稱(s1、s2……),值是旁白。旁白寫成口語,短句,一句只講一件事。如果安裝了chinese-writing-style技能,則按照該技能撰寫,每段 3 到 6 句。如果 TTS 可能讀錯某個英文詞或縮寫,把值寫成{"text": "螢幕和對齊用的文字", "tts": "送給 TTS 的讀法"}。 - 執行
python3 <skill>/scripts/gen_audio.py <專案目錄>。講解旁白預設音色是Chinese (Mandarin)_Warm_Girl。年份、日期和其他數字在tts中寫成中文讀法,text保留螢幕上的阿拉伯數字。如果只想重新產生某幾段,加上--only s3,s5。如果輸出「轉錄和旁白不一致」,判斷是否 TTS 讀錯了關鍵詞。如果讀錯了,修改該段的tts,使用--only重新產生。缺少逐字時間戳時,請先補上轉錄,字幕不能按照整段字數比例估算時間後交付。 - 使用符號連結引入共享的
scripts/explainer_base.py,再寫scene.py。已有專案請先移除本機字幕實作及start/finish覆寫,保留畫面邏輯,然後備份舊基底類別、換成連結。專案只編寫講解畫面,旁白字幕由基底類別統一產生。 - 在專案目錄執行
manim -ql --disable_caching scene.py <類別名稱>。如果報「畫面跟不上旁白」,依照錯誤訊息縮短對應動畫的run_time或刪除動畫,再重新渲染。 - 執行
python3 <skill>/scripts/contact_sheet.py <預覽影片> <專案目錄>,檢視每張拼圖。檢查字幕版面配置、元素重疊和箭頭方向。需要估算時間的動畫短語,必須對照audio/<段名>.words.json中前後字的時間確認。 - 執行
manim --resolution 1920,1080 --frame_rate 30 --disable_caching scene.py <類別名稱>。-qh是 60 fps,請勿使用。使用安裝 Manim 的 Python 執行<skill>/scripts/verify_video.py <成片> <專案目錄>。uv tool install manim對應的直譯器是$(uv tool dir)/manim/bin/python。 - 校驗命令必須退出碼為 0,且
qa/video-check.json的passed為 true。字形、音軌時間或字幕定位失敗時,查看報告、截圖和對應的words.json,修復後重新渲染、校驗。估算字幕不能僅憑截圖放行。 - 校驗通過後複製為
<主題>-講解.mp4,將影片路徑告知使用者,若目前環境能傳送檔案則直接發送。刪掉media/下的低解析度預覽。
場景程式碼
from explainer_base import *
class Topic(ExplainerScene):
def s1(self):
self.start("s1") # 播放配音並自動顯示同步字幕
title = cn("學習率", 60, HI)
self.play(Write(title))
self.until("學習率太小") # 等旁白讀到這個短語
self.play(title.animate.to_edge(UP))
self.finish() # 等配音讀完,清理字幕並淡出畫面
- 每個段落寫一個和段落名稱同名的函式。
- 不要在專案內覆寫
start、finish或字幕 updater。使用者明確不要字幕時,設定類別屬性SUBTITLES = False。 - 段落內切換畫面時,只淡出或移除自己建立的物件,保留基底類別的字幕。不要對所有
self.mobjects清屏或呼叫self.clear()。 until的短語必須原樣出現在該段落旁白的text裡,並且只出現一次。- 中文使用
cn(),英文使用en()。字型大小不小於 22。 - 只使用基底類別的 4 個顏色:
MAIN主體,HI重點,OK正確,BAD錯誤。一個顏色在整部影片中只代表一種含義。 - 一螢幕最多放 3 組元素。新內容進來前,先淡出不再講解的內容。
- 畫面底部 20% 保留給旁白字幕,圖表和說明文字放在此區域上方。
- 旁白講到哪個東西,那個東西就出現、變色或移動。
常見陷阱
- 修改共享字幕程式碼後,使用安裝 Manim 的 Python 執行
test_subtitles.py。它必須通過真實等待、段落切換、兩行字幕、重複短句、長句分頁和不同讀法的對齊檢查。只手動修改renderer.time並呼叫 updater,無法驗證 Manim 的靜態等待行為。 Text不會自動換行,長句請使用\n斷行。- 放入外框的文字,使用
fit(文字, 外框寬度 * 0.8)限制寬度。 - 使用
Cross劃掉選項時,只叉文字,不叉箭頭,箭頭改成BAD顏色。 - 為句子裡的單字上色,使用
Text(..., t2c={"單字": 顏色})。