pdoom-video 是以 TypeScript 與 Three.js 建構的程式碼渲染音樂影片引擎。畫面每一幀皆為歌曲時間的確定性函數,保證瀏覽器即時預覽與 1080p60 / 4K60 離線匯出精確一致。專案包含音訊歌詞強制對齊工具、動態排版系統以及基於 Headless Chrome 的次影格動態模糊算圖管線。
pdoom-video 將整首歌曲的時間軸轉化為純數學函數,將視覺畫面定義為時間點 t 的確定性輸出。專案為歌曲《I'm Upping My P(doom)》製作,全程由 Claude(Opus 5.5)於 Claude Code 環境協同生成,涵蓋視覺概念、音訊對齊分析、引擎核心與 17 個場景模組。
架構分為兩個獨立層級:Python 音訊分析管線(使用 uv 管理 Demucs 音軌分離與 CTC 強制對齊),以及前端渲染引擎(Bun、Vite 與 Three.js)。渲染核心在瀏覽器內提供 60 fps 即時預覽,並透過 Headless Chrome 驅動離線算圖管線。
字型排版整合 Archivo、IBM Plex Mono、Cormorant Garamond 與單線繪圖字型(Single-stroke fonts)。歌詞依照字詞起訖時間逐字高亮,字體寬度(width 62–125)與字重(weight 300–900)隨樂句張力動態形變。
執行渲染引擎需要 Bun、Google Chrome(離線算圖透過 playwright-core 驅動)以及支援 libx264 的 FFmpeg。複製儲存庫後進入 app 目錄安裝依賴並啟動 Vite 開發伺服器:
在瀏覽器開啟 http://localhost:5173 即可檢視即時畫面。網址加入 ?t=23 可直接跳轉至指定時間點(秒)。預覽介面支援以下鍵盤快捷鍵:
| 快捷鍵 | 控制操作 |
|---|---|
Space |
播放/暫停(Play / Pause) |
← / → |
跳轉 ±1 秒(按住 Shift 跳轉 ±5 秒) |
, / . |
單影格逐格前進/後退 |
[ / ] |
切換至上一個/下一個場景 |
l |
循環播放當前場景(Loop scene) |
h |
隱藏/顯示除錯 HUD 介面 |
若需自訂歌詞或重新分析音訊特徵,進入 analysis 目錄透過 uv 執行對齊工具:
data/*.json 完整對齊資料。僅執行即時預覽與影片渲染無需安裝 Python 與 uv。
專案透過 bun scripts/render.ts 驅動無頭 Chrome 與 FFmpeg,提供五種離線算圖、檢查與效能診斷模式。算圖腳本以 WebSocket 接收無損 raw RGBA 像素流,以 pipe 方式直接輸入 FFmpeg 編碼,避免磁碟暫存影格圖檔。
| 任務情境 | 執行指令與模式 | 關鍵參數與說明 |
|---|---|---|
| 本機即時預覽與動效微調 | bunx vite |
網址帶入 ?t=<秒數>,按鍵 l 循環當前場景 |
| 輕量草稿匯出(快速確認分鏡) | bun scripts/render.ts video |
--samples 4 --crf 20 |
| 標準 1080p60 交付版本 | bun scripts/render.ts video |
--samples auto --shutter 0.2 --crf 16 |
| 4K60 極致解析度母帶匯出 | bun scripts/render.ts video |
--scale 2 --samples auto --shutter 0.2 --x264 aq-mode=3:rc-lookahead=30 |
| 場景切換接點與銜接驗收 | bun scripts/render.ts sheet |
--cuts --cols 4 --out ../out/cuts.png |
| 單一場景著色器效能評估 | bun scripts/render.ts perf |
--only shoggoth --from 30 --to 35 |
專案於 docs/ENGINE.md 制定了嚴格的無狀態與時間軸契約。為支援離線多影格動態模糊與 4K 超取樣,場景模組必須遵守以下核心設計原則。
場景輸出必須僅相依於歌曲時間 f.t。引擎嚴格禁止場景維護跨影格狀態或計數 render() 調用,確保自適應取樣器能以任意順序且無副作用地插補次影格。
--samples auto 依序按 4、12、36、108、324 階梯插補次影格。每次在現有採樣點兩側插入新點,當新舊均值最大差異低於 --tol(預設 3/255)即提前終止。
影格等級的隨機抖動與閃爍必須使用 frameIdx(t) 作為種子,禁止使用 Math.floor(t * 60)。後者在快門區間內會因時間截斷產生雙重曝光偽影。
--scale 2 分配 3840×2160 實體緩衝區,但場景座標一律以 1920×1080 邏輯像素計算。著色器需使用 FRAG_PX 與 pxLine() 確保髮絲線在 4K 下保持銳利。
內嵌 4 點 RGSS 的著色器在離線匯出時,每次影格僅分配一個取樣點,利用快門時間的多次影格自動平滑,著色器計算負擔降低 75%。
來源 · 官方 docs/ENGINE.md動態逐字高亮必須透過 glyphX() 取得絕對字元起點,禁止使用 measure(slice) 累加。後者會遺失字元對之間的 Kerning 數據導致字距崩壞。
粒子發射率若隨時間改變,必須將發射率以 birth time 函數傳入(含 rateMax)。以當前 t 讀取發射率會導致粒子在不同次影格中被錯誤重置時序。
4K 渲染耗時甚鉅。官方建議以 --from 與 --to 拆分時間區段在多個管線並行渲染,最後透過 FFmpeg 的 concat demuxer 進行無損合併。
以下演示如何在本地端啟動預覽伺服器、跳轉至特定時間點除錯、以聯絡簿模式檢查所有場景邊界,並執行具備自適應次影格動態模糊的 4K 母帶匯出。
傳統瀏覽器 WebGL 動畫受限於硬體垂直同步與每秒 60 影格的即時算力,無法直接輸出無瑕疵的高動態模糊與膠卷級顆粒。pdoom-video 將時間軸解耦為離線純函數,由無頭瀏覽器逐影格計算並透過 WebSocket 串流 RGBA 原始緩衝區至 FFmpeg,使 Web 技術能產出媲美專業後製軟體規格的 4K 母帶。
--crf 18(約 450 Mbit/s)或 --crf 20(約 230 Mbit/s)。
audio/pdoom.mp3)、歌詞原始檔(lyrics/)與字型(SIL OFL)保有各自版權,非 MIT 範圍,商業衍生需另行取得授權。
render() 調用次數。若破壞純函數約定,自適應次影格取樣器將拋出異常並拒絕匯出。
analysis/ 目錄下的 CTC 與 Demucs 音訊分離工具,PyTorch 權重將下載約 4 GB 至 analysis/.cache/,處理完成後建議手動清理。
pdoom-video 的場景與時間軸採模組化架構,所有場景皆為 src/scenes/ 目錄下的獨立 TypeScript 模組。開發者可透過擴充自訂著色器、更換音軌與重新對齊歌詞,建構專屬的程式碼生成式影音專案。
1. 自訂場景模組。在 src/scenes/ 建立新檔案並實作 Scene 介面,於 src/timeline.ts 註冊其時間區段,即可接入時間軸排程。
2. 替換音軌與自訂歌詞。將新音訊放入 audio/,編寫初始歌詞後透過 analysis/align.py 與 analysis/analyze.py 重新計算字詞級時間戳記與節拍網格。
3. 自訂單線繪圖字型。在 src/engine/stroke.ts 中載入新的單筆畫 SVG 字型,支援透過光標筆尖動態繪製書法或工程製圖風格文本。
4. 光線步進著色器調優。參考 src/scenes/paperclips-glsl.ts 與 src/scenes/ilya-glsl.ts,實作客製化距離場(SDF)與 4 點 RGSS 旋轉取樣著色器。
5. 多管線並行算圖加速。長篇專案可使用 --from 與 --to 參數啟動多個無頭 Chrome 處理程序,最後使用 FFmpeg 串接無損 mp4 片段。
① docs/TREATMENT.md — 視覺概念書、17 個分鏡場景設計規範與卡拉 OK 排版準則。
② docs/ENGINE.md — 渲染引擎核心、字型系統、GLSL 著色器與自適應次影格取樣演算法規格。
③ app/scripts/render.ts — 離線無頭 Chrome 驅動、WebSocket 原始像素串流與 FFmpeg 管道實作。