Remotion 卡點短影片流水線
目標:給定一個選題和一首 BGM,產出一條 88–90 秒 / 16:9 / 無配音 / 中英雙語字幕 / 每個場景切在樂句重拍上 的成片, 外加封面三版、發布包、待核事實清單。整套東西都是程式碼,改字幕就是改字串,重渲染一次約 35 分鐘。
何時使用
- 「把這個主題拍成一條抖音知識影片 / 博弈局解說」
- 「用某某 BGM 做一條卡點影片」
- 「把小説裡這一段做成影片」(虛構 IP,見
references/fact-check.md) - 需要成套交付:成片 + 封面 + 發布文案 + 事實核實
何時不使用
- 要配音旁白(本流程是無配音字幕敘事;要配音就得先出 TTS 軌再對齊)
- 要真人/AIGC 素材混剪(本流程是純程式碼 SVG 畫面)
- 只要圖文不要影片
〇、風格 DNA(先讀,全部是實測結論)
| 維度 | 規範 | 為什麼 |
|---|---|---|
| 畫幅 | 1920×1080 / 30fps(直版另開 Composition) | 帳號已鎖定 16:9,數據上內容效率更高 |
| 時長 | 88–90 秒(≈42 小節) | 落在「60–90s 單集」測試檔 |
| 聲音 | 無配音,BGM + 合成音效 | 風格要求;也避免 TTS 對齊成本 |
| 字幕 | 中英雙語兩行,中文 ≤22 字、每句停留 ≥2.2 秒 | 本帳號風格(抖音通用建議是單語,此條為帳號選擇) |
| 切入 | 第 1 秒 = 一句完整衝突句 + 一個具體物 | 2 秒跳出率是最大漏點 |
| 敘事 | 一個人 + 一個問題 + 一條因果鏈 | 忌「概念圖鑑」和「群像混剪」 |
| 結構 | 鉤子→片名→規則→陷阱→反擊→反噬→揭曉→昇華→收尾 | 見 references/script-template.md |
| 節奏 | 每個場景從樂句重拍硬切;關鍵動作落在拍點 | 卡點來自音樂結構,不是手動對齊 |
| 畫面 | 深色底 + 金屬/木/金色質感 + 大字型 + 少量標籤 | 手機縮放下可讀 |
| 安全區 | 場景元素 y ≤ 850;字幕 y≈870–1000;左上抬頭 y 50–95 | 實測最容易翻車的地方 |
| 結尾 | 必須給可截圖的清單(收藏點)+ 一句提問 | 收藏率是最大短板 |
| 嚴謹 | 虛構 IP 必須標「圖示為示意」;事實分層標註 | 見 references/fact-check.md |
一、八步流程(逐步執行,不可跳步)
第 1 步:立項(選題 + 確認)
- 使用者沒給選題時,先給 3 個候選(每個寫清:一句話核心 / 第 1 秒鉤子 / 憑什麼能畫 / 收藏點 / 風險),讓使用者點單。
- 候選必須先驗證存在性再提交:虛構 IP 要能查到章節名或條目;知識類要能查到出處。
- 使用者點單後,把該選題的原始資料要到手(原文段落最好;只有二手整理時必須標註來源層級,見第 8 步)。
第 2 步:音軌與節拍(決定一切時間)
# ① 抽音軌(mp4/mp3 都行;沒系統 ffmpeg 會自動用 imageio-ffmpeg 的二進位)
python scripts/extract_audio.py 輸入.mp4 work/ # → work/audio.f32 + work/music.mp3
# ② 節拍 / 重拍 / 段落 / 調性
python scripts/analyze_beats.py work/audio.f32 src/beats.json
# ③ 掃能量,選區段(關鍵一步)
python scripts/scan_energy.py src/beats.json work/audio.f32 --seconds 89
- 輸出會給出:START_BAR / END_BAR、逐小節能量圖、靜音坎落在視窗百分之幾。
- 把反轉放在靜音坎之後的第一記重拍上——這是全片最值錢的一秒。
- 視窗不要吃掉結尾的衰減段(那會留下死尾)。
- 若某首歌已被系列用過,優先挑沒被用過的後半段,避免觀感重複。
第 3 步:寫劇本(src/script.ts)
- 每個場景宣告
bars(佔幾小節),所有場景 bars 之和必須等於 END_BAR − START_BAR(否則placeScenes會按比例縮放並告警)。 - 字幕寫在
subs:{zh, en, at},at是場景內第幾拍(可寫 4.5 這種半拍)。一句佔 4–5 拍最舒服。 - 音效寫在
cues:{id, beat, sfx, vol, impact};impact:'big'= 白閃 + 震屏 + 色散 + 音樂側鏈讓位 40 幀。 - 節奏預算:
句子數 × 2.5–3 秒 ≈ 總時長。89 秒大約 30 句。
第 4 步:畫面零件與場景(src/*/kit.tsx + src/*/scenes.tsx)
- 先把零件寫全再寫場景:一個題材的零件通常 6–10 個(本例:鐵盒/鎖/鑰匙/粉碎機/微波爐/人物剪影/雕像/燈/彩券/櫃檯/道幣)。
- 零件全部純 SVG,座標寫死在 1920×1080 上,靠
translate/scale重用。 - 場景元件只負責按拍點排零件:
const bf = (n) => beatFrame(scene, n),進場一律用pp(f, bf(n), 8)這種緩動進度。 - 檢查清單見
references/visual-kit.md。
第 5 步:工程搭建
一個工程放多支片:src/<episode>/{script.ts,timeline.ts,fx.tsx,kit.tsx,scenes.tsx,Main.tsx},
在 src/Root.tsx 註冊第二個 <Composition>,各自用自己的 beats.json 和 music.mp3。
- 第二支必須帶自己的節拍外殼(
fx.tsx裡的 Shell/ImpactFlash 必須用本片的 cueFrame,否則衝擊點會錯位)。 - 音訊用
<Audio startFrom={OFF}>,內容整體<Sequence from={-OFF}>,這樣場景內部一律用「音樂幀」計時。 - 詳見
references/pipeline.md。
第 6 步:靜幀自檢(不過不渲染)
node <node> node_modules/@remotion/cli/remotion-cli.js still <Comp> out/s1.png --frame=<場景中點>
逐場景渲一張,肉眼過四件事:
- 字幕有沒有壓到場景元素(最常見)
- 元素重疊(標籤壓標籤、標籤壓圖形)
- 安全區(元素 y ≤ 850)
- 手機縮放下文字是否可讀(中文 ≥24px、主標題 ≥120px)
第 7 步:出片與成片自檢
node <node> node_modules/@remotion/cli/remotion-cli.js render <Comp> out/<name>.mp4 --codec=h264 --crf=18 --concurrency=6
python scripts/check_mp4.py out/<name>.mp4 # 時長 / 軌道數 / 解析度 / 音訊參數
check_mp4.py 不需要 ffprobe:直接解析 mp4 box,確認 vide + soun 雙軌、時長對得上、1920×1080、AAC 48kHz。
第 8 步:交付
python scripts/make_covers.py --src out/<某靜幀>.png --crop x0,y0,x1,y1 \
--title 主標題 --kicker 副標 --sub 一句話 --out-prefix out/封面_XXX
交付四件套:
- 成片 mp4(拷到工作區根目錄,檔名帶主題)
- 封面三版(16:9 / 3:4 / 9:16)——絕不用自動截幀
- 發布包(正文 + 置頂評論 + 封面方案 + 24 小時判定表),模板見
references/cover-and-publish.md - 待核事實清單(虛構 IP 必備)+ 劇本分鏡(時間碼表)
二、鐵律(全部是實測踩出來的)
- 第 1 幀不是片頭是鉤子:一張完整衝突句 + 一個具體物(「人質被鎖在微波爐裏,倒計時正在走」)。
- 字幕安全區:場景元素一律壓在 y ≤ 850,字幕在 870–1000。靜幀自檢時優先看這條。
- 一句字幕 ≤22 字、停留 ≥2.2 秒;中文主句 + 英文對照兩行。
- 結尾必須能截圖:一個三步/三訊號清單 + 「建議先存下來」;只給感慨的結尾拿不到收藏。
- 靜音坎 = 反轉點:
scan_energy.py會告訴你坎在第幾小節,把最強的反轉放它後面。 - 大衝擊要點:
impact:'big'會觸發白閃 + 震屏 + 色散 + 音樂讓位;全片 5–8 次足夠,多了就麻木。 - 不要勻速滑動:所有進場用緩動(
Easing.out(cubic)),標籤出場帶一點位移+縮放。 - 字型:不要用「按舊文案裁剪的子集字型」(新文案會缺字)——直接寫系統字型棧
'Noto Sans SC','Microsoft YaHei'。 - public/ 會被整體拷貝:只保留用到的音效(本例 148 → 16 個,每次渲染少拷 60MB)。
- Remotion 的 ETA 早期虛高:別被「剩餘 3 小時」嚇到;實測穩定在 ~1.35 幀/秒,2700 幀約 35 分鐘。
- 虛構 IP 三層標註:原著原文 / 讀者整理 / 我的推測——片子裡只寫前兩層的共識部分,其餘進待核清單。
- 不要在片子裡寫死數字(「四個生肖」→「好幾個生肖」)、不要寫死章節號(「第 359 章」→「約第 359 章前後」)。
三、目錄約定
<project>/
├── public/music.mp3 # 本片 BGM
├── public/music.f32(+.json) # 節拍分析用(可刪)
├── public/sfx/*.wav # 按調性合成的音效
├── src/beats.json # analyze_beats 輸出
├── src/script.ts # 文案總表(改內容只動這裏)
├── src/timeline.ts # 場景→重拍映射 + OFF/TOTAL
├── src/Root.tsx # 註冊 Composition
├── src/fx.tsx # 震屏/白閃/色散/雙語字幕
├── src/<episode>/** # 第二支及以後:獨立 script/timeline/fx/kit/scenes/Main
├── tools/ # 本 skill 的 scripts/
└── out/ # 靜幀 + 成片 + 封面
四、參考檔案
references/pipeline.md—— 環境搭建與命令全集(含這台機器的全部坑:沒有 ffmpeg / scipy / npm)references/script-template.md—— 劇本結構模板 + 拍點換算表 + 本次兩條片的真實時間碼references/visual-kit.md—— 畫面零件規範、安全區、配色、常見重疊陷阱references/sfx-and-mix.md—— 音效合成(按調性)、側鏈讓位、響度references/fact-check.md—— 虛構 IP 核實方法與「讀者複述」標註規範(含可用的 B 站介面)references/cover-and-publish.md—— 封面三版規範 + 發布包模板 + 24 小時判定examples/十日終焉-兩集.md—— 兩個真實案例的結構、數據與決策記錄
五、能力邊界(對使用者誠實)
- 本流程不產生配音;要旁白必須另配 TTS 並重新對齊字幕。
- 網路受限環境下(很多域名被 DNS 攔)虛構 IP 的規則細節可能只有二手來源 —— 此時必須走第 8 步的待核清單,不硬寫。
- 渲染是算力活:4 核筆電上一條 89 秒 1080p 約 35 分鐘;不要承諾「幾分鐘出片」。
- 版權:BGM 從抖音影片裏提取只適合自用參考;發佈時請掛站內曲庫/原聲卡片。