code-video:讓大語言模型寫程式碼,逐幀畫出科普影片
畫面不是影片模型生成的,也不是拍的:模型寫一個網頁(Canvas / SVG / Three.js / WebGL),
頁面暴露 __render(t),腳本按幀號逐幀截圖,再用 ffmpeg 編碼成 mp4。
好處是可複現、可修改、文字和數字絕對準確、零生成費用。
整套做法只有三步:挑畫風 → 把提示詞寫細 → 先抽幀檢查,改好了再出全片。
0. 準備(第一次用)
cd <skill 目錄>
npm install # 裝 playwright-core
npx playwright-core install chromium-headless-shell # 或設定 CHROME=/path/to/chrome
# 需要 ffmpeg / ffprobe 在 PATH 上;中文字型建議裝 Noto Sans CJK(fonts-noto-cjk / noto-fonts-cjk)
pip install edge-tts numpy scipy # 可選:旁白、字幕、合成配樂
1. 挑畫風:畫風跟著題材走
先看題材屬於哪一類,再到 references/styles/ 讀對應畫風檔案(每個檔案有:適合什麼題、
精簡提示詞、完整提示詞、製作手記、事實依據,範例原始碼在 examples/<name>/)。
| 題材 | 先試 | 也可以 |
|---|---|---|
| 典故、歷史故事 | 皮影 piying | 像素 pixel、漫畫 comic |
| 低齡科普、自然生長 | 繪本 picturebook | 扁平 MG flatmg |
| 文字、器物、朝代 | 漢字演變 hanzi | 水墨 ink |
| 路線、出使、遷徙 | 古地圖 oldmap | 等距流程 isometric |
| 機械結構、產品拆解 | 3D 拆解 explode3d | 白板 whiteboard |
| 工序、生產線 | 等距流程 isometric | 扁平 MG flatmg |
| 大小、深度、距離 | 比例尺 scale | 數據資訊圖 infographic |
| 年代、數量級 | 數據資訊圖 infographic | 比例尺 scale |
| 定理、公式 | 數學視覺化 math | 線稿 lineart |
| 單一原理、因果 | 白板 whiteboard | 線稿 lineart |
| 口號、片頭片尾 | 卡點金句 kinetic | — |
全部 16 種見 references/styles/README.md。用戶點名某種畫風時直接讀那個檔案。
2. 把提示詞寫細:一句話只定了畫風
「做一段十秒皮影戲」這種一句話提示詞,模型只知道畫風,不知道演什麼、用哪些數、每段幾秒。 按下面的骨架把四件事寫清楚(畫風檔案裡的完整提示詞都是這個結構):
用 Canvas 逐幀繪製一段 1920×1080、30fps、約 12 秒的「畫風」科普動畫:配色、質感、字體分別怎麼定。
題材是「…… 」:分幾個鏡頭,每個鏡頭演什麼、螢幕上打出哪句字,結尾用一句話點破。
要用到的數字:……,來源寫進 notes.txt;沒把握的數不要精確到個位。
每幀只由時間 t 決定(不用計時器,亂數用固定種子)。
先抽 4–6 幀檢查字幕夠不夠大、標籤有沒有重疊或出畫,改完再全片渲染。
再補上題材裡會被畫錯的物理/事實規則。例子:曹沖稱象裡,船的吃水要按載重算, 否則記號和水線對不上,這條規則不寫,模型畫出來就是錯的。
3. 寫頁面:必須遵守的頁面合約
每段影片一個目錄 <work>/<name>/,至少有 index.html,建議同時寫 prompt.txt(用的提示詞)
和 notes.txt(數字和事實的來源)。可以從 templates/canvas/index.html 起步。
- 頁面固定 1920×1080,
overflow:hidden。 - 必須有這一行(render.sh 用正則讀):
const FPS = 30, DUR = 12; window.__info = { fps: FPS, duration: DUR, frames: Math.round(FPS * DUR) };window.__render = t => { ...; return { seg: '<鏡頭名>', tau: t.toFixed(2) }; }每一幀只由 t 決定:不用 CSS animation/transition、setTimeout、requestAnimationFrame、Date.now()、Math.random();亂數用固定種子(如 mulberry32);粒子、抖動、物理都要能由 t 直接算出, 幀與幀之間不累積狀態。- 字型和資源載完再設
window.__ready = true(WebGL 頁面在首幀渲染後再置 true)。 - 不訪問外網(截幀腳本會攔掉所有外部請求)。字型用系統已裝的字型。
- 手機上要看得清:正文標籤 ≥ 36px,標題 ≥ 64px,左下角頁腳小字可選。
- Three.js 頁面:
scripts/fetch_three.sh <name>下載到<name>/vendor/,然後<script type="importmap">{ "imports": { "three": "./vendor/three.module.js", "three/addons/": "./vendor/jsm/" } }</script>; renderer 設preserveDrawingBuffer: true,在__render(t)裡同步呼叫renderer.render()(或 composer)。
細節和常見坑見 references/page-contract.md。
4. 先抽幀給模型看,改好了再出全片
scripts/render.sh <work>/<name> 30,120,210,300 # 只截這幾幀 -> <work>/_preview/<name>/
用圖片查看工具逐張看,按這個清單挑問題,改完再抽一輪(至少迭代一輪):
- 文字:夠不夠大、有沒有重疊、出畫、被遮擋;中文是否都是真字型(沒有豆腐塊)。
- 事實:畫面上的數字、年代、地名、公式和 notes.txt 一致;示意性畫面標「示意圖」。
- 構圖:主體夠不夠大(遠景主角至少佔畫面高度的 1/4)、畫面是否太空、配色是否對題。
- 動作:關鍵動作是否真的發生了(看相鄰兩幀),轉場是否突兀。
- WebGL:有沒有黑塊/黑斑、閃爍。
沒問題再出全片:
scripts/render.sh <work>/<name> # -> <work>/<name>.mp4
N=8 scripts/render.sh <work>/<name> # 並行截幀行程數(預設 min(6, 核心數/2))
GPU_ANGLE=vulkan scripts/render.sh ... # WebGL 用顯示卡(更快,但連續截幀可能出黑斑,先抽幀確認)
編碼器自動選擇:能用 NVENC 就用 h264_nvenc,否則 libx264。
截幀主要吃 CPU;耗時大頭通常是「模型寫頁面、看截圖、改程式碼」,不是渲染本身。
5. 可選:旁白、字幕、配樂、預覽圖
# 旁白 + 字幕(預設免費的 edge-tts;整段旁白一次合成,聲音前後才一致)
python3 scripts/tts.py script.txt -o out/narration --voice zh-CN-YunyangNeural --rate -5%
# 配樂:自己合成(無版權問題),或用免版稅曲庫(見 references/narration.md)
python3 scripts/chiptune.py out/bgm.wav 30 # 8-bit 晶片音樂
python3 scripts/beat.py out/beat.wav --bpm 120 --beats 20 # 卡點鼓點,拍點對齊幀
# 合成:音樂自動避讓人聲,響度歸一到 -16 LUFS;--burn 把字幕燒進畫面
scripts/mux.sh out/<name>.mp4 out/<name>.final.mp4 --voice out/narration.mp3 --music out/bgm.wav --srt out/narration.srt --burn
# 預覽 GIF / 封面幀
scripts/gif.sh out/<name>.mp4 2.5 4 # 從 2.5 秒起 4 秒
scripts/gif.sh --poster out/<name>.mp4 6.0 # 抽一幀 jpg
要燒字幕的話,頁面底部 1/5 留空,別再畫自己的字幕條(或用 SUB_MARGIN=60 把字幕抬高);
響度目標 -16 LUFS,人聲峰值高時會略低一點(真峰值上限 -1.5 dBTP)。
聲音選擇、自建 TTS 接入、卡點對齊的做法見 references/narration.md。
6. 一次做多段(多畫風對比、系列影片)
每段一個目錄、一個提示詞,互不依賴,可以分給多個子代理(sub-agent)並行寫頁面和自檢, 主代理只負責最後統一渲染、拼接和檢查。給每個子代理的說明裡寫清:頁面合約、目錄約定、 抽幀自檢清單、事實要寫進 notes.txt、完成後回報時長和自評。
做之前先說清楚
- 事實類數字必須真實可核;做新聞/新品類題材時,只畫公開過的資訊,角上標「示意圖」。
- 不要把範例裡的題材數字當成通用事實複用;換題時重新核對。
- 模型生成的配樂(如 MusicGen 權重)多為非商用許可;商用發布請用自己合成或明確授權的音樂。