確定性時間函數與生成式排版
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)隨樂句張力動態形變。
音訊分離
歌詞對齊
時序標記
場景渲染
次影格採樣
影像編碼
「Every frame is a deterministic function of song time, so the live preview in the browser and the offline 1080p60 (or 4K60) export are identical.」
本機預覽與依賴安裝
執行渲染引擎需要 Bun、Google Chrome(離線算圖透過 playwright-core 驅動)以及支援 libx264 的 FFmpeg。複製儲存庫後進入 app 目錄安裝依賴並啟動 Vite 開發伺服器:
cd app
bun install
bunx vite在瀏覽器開啟 http://localhost:5173 即可檢視即時畫面。網址加入 ?t=23 可直接跳轉至指定時間點(秒)。預覽介面支援以下鍵盤快捷鍵:
| 快捷鍵 | 控制操作 |
|---|---|
Space | 播放/暫停(Play / Pause) |
← / → | 跳轉 ±1 秒(按住 Shift 跳轉 ±5 秒) |
, / . | 單影格逐格前進/後退 |
[ / ] | 切換至上一個/下一個場景 |
l | 循環播放當前場景(Loop scene) |
h | 隱藏/顯示除錯 HUD 介面 |
音訊分析管線(選用)
若需自訂歌詞或重新分析音訊特徵,進入 analysis 目錄透過 uv 執行對齊工具:
cd analysis
uv run python align.py # 產出 data/lyrics.json
uv run python analyze.py # 產出 data/audio.json離線渲染器功能清單
專案透過 bun scripts/render.ts 驅動無頭 Chrome 與 FFmpeg,提供五種離線算圖、檢查與效能診斷模式。算圖腳本以 WebSocket 接收無損 raw RGBA 像素流,以 pipe 方式直接輸入 FFmpeg 編碼,避免磁碟暫存影格圖檔。
Render · 01
render.ts video
全片影音匯出
輸出完整 mp4 檔案,整合動態模糊、時間抗鋸齒與 AAC 音軌合成。
Render · 02
render.ts video --scale 2
真實 4K 母帶
以 3840×2160 物理解析度直接渲染所有著色器與髮絲線條,非放大升頻。
Inspect · 03
render.ts stills
精確時間點截圖
在指定秒數陣列擷取無損 PNG 影格,支援以 --only 隔離單一場景模組。
Inspect · 04
render.ts sheet
分鏡聯絡簿
以網格陣列排列多個時間點縮圖,支援 --cuts 自動抓取所有場景切換邊界。
Montage · 05
render.ts plates
場景代表圖集
為各場景產出代表性 JPEG 存入 public/plates/,供應片尾回溯蒙太奇。
Benchmark · 06
render.ts perf
影格耗時診斷
量測指定區間每影格平均耗時,包含 GPU 同步與像素讀回時間。
Engine · 07
AdaptiveSampling
自適應動態模糊
依畫面運動量自動選擇 12、36、108 或 324 次影格,誤差達標即停止取樣。
Pipeline · 08
analysis/align.py
音訊強制對齊
Demucs 分離人聲,搭配 CTC 聲學特徵與 Whisper 產出精確至字詞的起訖時間。
任務情境與指令參數決策表
| 任務情境 | 執行指令與模式 | 關鍵參數與說明 |
|---|---|---|
| 本機即時預覽與動效微調 | 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 超取樣,場景模組必須遵守以下核心設計原則。
RULE · 純函數時間軸契約
場景輸出必須僅相依於歌曲時間 f.t。引擎嚴格禁止場景維護跨影格狀態或計數 render() 調用,確保自適應取樣器能以任意順序且無副作用地插補次影格。
來源 · 官方 docs/ENGINE.md
RULE · 自適應次影格收斂階梯
--samples auto 依序按 4、12、36、108、324 階梯插補次影格。每次在現有採樣點兩側插入新點,當新舊均值最大差異低於 --tol(預設 3/255)即提前終止。
來源 · 官方 docs/ENGINE.md
RULE · 60 fps 抖動與 frameIdx
影格等級的隨機抖動與閃爍必須使用 frameIdx(t) 作為種子,禁止使用 Math.floor(t * 60)。後者在快門區間內會因時間截斷產生雙重曝光偽影。
來源 · 官方 docs/ENGINE.md
RULE · 4K 邏輯像素與物理解析度
--scale 2 分配 3840×2160 實體緩衝區,但場景座標一律以 1920×1080 邏輯像素計算。著色器需使用 FRAG_PX 與 pxLine() 確保髮絲線在 4K 下保持銳利。
來源 · 官方 docs/ENGINE.md
RULE · 旋轉網格超取樣(RGSS)分工
內嵌 4 點 RGSS 的著色器在離線匯出時,每次影格僅分配一個取樣點,利用快門時間的多次影格自動平滑,著色器計算負擔降低 75%。
來源 · 官方 docs/ENGINE.md
RULE · 字詞分段上色與 Kerning 保留
動態逐字高亮必須透過 glyphX() 取得絕對字元起點,禁止使用 measure(slice) 累加。後者會遺失字元對之間的 Kerning 數據導致字距崩壞。
來源 · 官方 docs/ENGINE.md
RULE · 動態發射器與粒子時序
粒子發射率若隨時間改變,必須將發射率以 birth time 函數傳入(含 rateMax)。以當前 t 讀取發射率會導致粒子在不同次影格中被錯誤重置時序。
來源 · 官方 docs/ENGINE.md
RULE · 多通道並行管線與無損拼接
4K 渲染耗時甚鉅。官方建議以 --from 與 --to 拆分時間區段在多個管線並行渲染,最後透過 FFmpeg 的 concat demuxer 進行無損合併。
來源 · 官方 README · 4K 算圖說明
從即時預覽到自適應 4K 算圖
以下演示如何在本地端啟動預覽伺服器、跳轉至特定時間點除錯、以聯絡簿模式檢查所有場景邊界,並執行具備自適應次影格動態模糊的 4K 母帶匯出。
$ user@workstation ~/pdoom-video/app › bunx vite
ok: [ready] three.js canvas initialized (1920x1080 logical) · audio loaded
$ user@workstation ~/pdoom-video/app › bun scripts/render.ts sheet --cuts --cols 4 --out ../out/cuts.png
0.00s open · 11.20s loss · 22.40s prompt · 31.80s hook · 42.10s room...
ok: [sheet] rendered 17 boundary frames to ../out/cuts.png ✓
$ user@workstation ~/pdoom-video/app › bun scripts/render.ts perf --only shoggoth --from 30 --to 35
avg frame time: 38.4ms | gpu-sync: 11.2ms | pixel readback: 8.6ms
ok: [perf] target 60 fps headroom: PASS ✓
$ user@workstation ~/pdoom-video/app › bun scripts/render.ts video --scale 2 --samples auto --shutter 0.2 --x264 aq-mode=3:rc-lookahead=30 --out ../out/pdoom-4k.mp4
t=00.00s (open): 12 sub-frames (converged tol=3)
t=32.40s (shoggoth zoom): 108 sub-frames (converged tol=3)
t=64.12s (leftturn whip): 324 sub-frames (converged tol=3)
ok: [export] render completed in 2h 28m → ../out/pdoom-4k.mp4 ✓
「The current code picks up to 324 sub-frames per frame where the motion needs them.」
離線確定性算圖的工程價值
傳統瀏覽器 WebGL 動畫受限於硬體垂直同步與每秒 60 影格的即時算力,無法直接輸出無瑕疵的高動態模糊與膠卷級顆粒。pdoom-video 將時間軸解耦為離線純函數,由無頭瀏覽器逐影格計算並透過 WebSocket 串流 RGBA 原始緩衝區至 FFmpeg,使 Web 技術能產出媲美專業後製軟體規格的 4K 母帶。
硬體負擔與授權邊界
自訂場景與延伸探索
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 管道實作。
「The words are part of the image, not subtitles on top.」