新影片:從錄影到成品
開始之前:確保 harness.config.json 中的 configured: true(否則會執行 setup 技能),然後執行 bash video/scripts/doctor.sh 確認沒有 MISSING。
請先閱讀 brand-kit.md、editing-taste.md、exemplars.md 中的「口味設定檔」、anti-patterns.md 以及 delivery-specs.md。
影片風格只能來自用戶設定檔: 是否有海報、卡牌、貼紙、B-roll、音效、圖形多寡、節奏快慢。
設定檔中沒提到的部分,請詢問用戶,不要自行決定。
程式碼的起點是目前的 video/src/。
如果 video/public/footage.mp4 是從上一支影片留下來且尚未封存到 edits/ 中,請先封存(步驟 11),然後再開始。
1. 檢查錄影
ffprobe -v error -show_entries format=duration:stream=width,height,r_frame_rate:stream_side_data=rotation -of default=nw=1 takes/1.MOV
請以 rotation 為準判斷方向,不要只看 width(iPhone 會把垂直影片記錄為 1920x1080 並加上旋轉旗標)。
用以下指令查看 3-4 個畫面:
ffmpeg -ss N -i … -frames:v 1 out/peek-N.jpg
除非是用手持拍攝,否則不要用 vidstab 穩定畫面——它反而會引入晃動。只有當畫面明顯是在手持情況下拍攝時,才需要對原始素材進行穩定處理(使用 vidstabdetect=shakiness=6:accuracy=15 和 vidstabtransform=smoothing=25:optzoom=1:interpol=bicubic,並加上 -c:a copy;需要內建 libvidstab 的 ffmpeg),然後再後續處理。
2. 重複片段與假開始——在剪輯前先處理
cd video && python3 scripts/chunks.py ../takes/1.MOV
整段逐字稿會隱藏重複內容,但觀眾立刻就能察覺。 請找出:相鄰且包含相同片語的段落(重複片段——保留最後一個);長度僅 1-2 個詞、且被下一段重新開始的段落(假開始)。 向用戶展示你將剪掉的清單,附上時間碼,等待用戶同意。 裁切邊界應落在停頓處。
3. 剪輯
cp public/captions.json out/captions.backup.json 2>/dev/null # cut.py 會覆蓋逐字稿
DROP="12.40-15.80" python3 scripts/cut.py ../takes/1.MOV
節奏取自設定檔中的 cut 參數(根據參考素材調整)。
腳本會輸出 DURATION、拼接畫面以及「拼接點落在語音上」的檢查結果。
如果拼接點太少,不符合用戶想要的節奏,請傳入低於設定檔的參數,例如 … 0.4 0.2(預設約 0.35 / 0.2);太多則調高。
完全沒有拼接點——若環境噪音很大,請用 QUIET=-46。
說話很快 / 節奏緩慢——請用 SPEED=1.1。
拼接點若落在語音上,請調整 DROP 或參數,不要置之不理。
4. 去背——請立即啟動(如果 style.poster.enabled 為 true)
TITLE_OUT 取自 cut.py 輸出中的第一個拼接點(海報會在該處出現),通常為 4-7 秒。
去背是最耗時的部分(CPU 上約 8 秒/幀,2 個工作者約 6 幀/分鐘),請在背景執行,然後一邊寫程式碼:
python3 scripts/matte.py <TITLE_OUT> 2 > out/matte.log 2>&1 # 在背景執行 (run_in_background)
去背進行時不要渲染靜止畫面,因為會拖慢速度。
等待完成的方式是透過 ps -axo command | grep "[m]atte.py",不要用 pgrep。
腳本會跳過已完成的幀——重新啟動時直接再次執行即可。
5. 逐字稿
打開 public/captions.json(w、s、e 以秒為單位,em):
- 修正聽錯的部分:人名、品牌、術語、外來語;縮寫請按照正確寫法(如
AI、ROI);Whisper 常在尾端安靜處產生「謝謝觀看」或「Thank you.」——請刪除; - 根據意義來設定「
em: 2」(如果style.captions.highlight是size或both)和「"accent": 1」(如果是color或both),且數量與用詞須與設定檔(brand-kit.md第 2、4 節)一致。 如果設定檔未描述,請詢問用戶哪些詞需要標示。
6. 節奏表
自行或透過子代理 script-beats(若影片較長)來撰寫 video/SCRIPT.md:
- 海報——僅當
style.poster.enabled為 true:使用用戶的用詞和語氣,重音和 kicker 須符合設定檔; - 卡牌——若
style.cards不為none,密度依照editing-taste.md第 3 節(數字決定count;步驟決定num+head;列舉則用head+lines或帶圖示的row);from為該片語的第一個單詞 + 4 幀; - 貼紙
FLOATS——僅當style.stickers為 true:用一個單詞作為標籤,並使用簡潔的圖示(ART_NAMES); - 卡牌若標註
pain: true——僅當用戶明確要求「避免這樣做」時才使用。
在寫程式碼之前,先向用戶簡要展示節奏表(出現什麼、出現在哪裡)——這是用戶的影片,由用戶決定。
7. 程式碼
src/Composition.tsx:設定DURATION、TITLE_OUT、KICKER、TITLE、BEATS、FLOATS;Captions from若有海報則為第二個片語的開始,否則為 0。src/ui/Footage.tsx:BEATS表格必須嚴格按照 cut.py 輸出的拼接點,並且以最大力度顯示(特寫約 1.16-1.21 倍,一般約 1.06-1.09 倍)——style.motion.punch會自行調整或關閉。特寫的位置依據editing-taste.md第 4 節;特寫後要拉回,否則特寫感會「卡住」;若有海報,則在第一個拼接點使用。- 只有當卡牌、貼紙、
Photo/Clip/Tag都無法表達時,才新增元件(此時使用scene-builder)。 - 如果已連結 Higgsfield 且設定檔要求 B-roll(
brand-kit.md第 5 節):透過<Clip>顯示(先裁切並靜音:ffmpeg -an -t <秒>),插入前請檢查生成畫面上的文字 / 臉 / 手。請先詢問用戶並告知價格。 - 音效——僅當
style.sfx為 true:缺少的音效(如card、count、end)請透過子代理audio-agent根據設定檔描述生成。 npm run lint必須乾淨。
8. 審稿畫面(去背完成後)
根據每個卡牌和貼紙,渲染一張完全組合好的靜止畫面、海報的中間時刻(最後一行文字位於頭髮上方)、幾句字幕、以及最後一個畫面:
npx remotion still MyComp out/key/f<N>.png --frame=<N> --scale=0.5 --timeout=120000
將這些畫面以每列 4 張的方式拼成一張圖,並加上編號標籤(使用 PIL;字型需支援西里爾字母,例如 /System/Library/Fonts/Supplemental/Arial Bold.ttf),然後向用戶顯示(SendUserFile)。
只有當用戶說「可以」之後,才能輸出最終影片。
審稿畫面只需幾分鐘,最終影片則需 10-20 分鐘。
在顯示之前自行檢查:關鍵文字不要落在畫面下方 15% / 上方 8% 以內;沒有任何元素重疊;貼紙與卡牌不交錯;最後一個畫面不空或不完整;一切都符合用戶設定檔,沒有多餘內容。
9. 最終影片
npm run master # 在背景執行;請監控程序,不要只看檔案是否出現
腳本會自動檢查裁剪處、計算幀數,並輸出 out/preview.mp4。
請檢查音量:
ffmpeg -i out/final-master.mp4 -af ebur128 -f null - 2>&1 | grep -A3 Summary
音量應接近 audio.lufs 的目標值。
將預覽影片傳送給用戶。
最終影片後的修改(例如「把這句剪掉」)——請直接修改最終影片(使用 ffmpeg 的 trim+concat 以靜音處為界),不要重新裁剪原始錄影或重新渲染全部;請提前告知預計完成時間。 檢查接合處:剪掉前後各 6 秒並用 whisper 跑一遍——應該只有所需的兩句話。
10. 封面圖
如果設定檔未指定,請詢問用戶需要哪種封面:從影片中選取的畫面(Cover)、影片海報(PosterCover)或自訂。
選擇畫面時請與用戶共同決定:提供 3-4 張清晰且人物睜開眼睛的畫面(ffmpeg -ss <秒> -i takes/1.MOV -frames:v 1 -q:v 2 out/cover-N.jpg)。
- 將選定的畫面複製為
public/cover-bg.jpg。 rembg i -m birefnet-portrait public/cover-bg.jpg out/cover-matte.pngpython3 scripts/cover-sticker.py public/cover-bg.jpg out/cover-matte.png public/cover-cutout.png 20- 在
Root.tsx中,設定Cover的defaultProps.lines:使用用戶的用詞作為標題,accent/em則依用戶喜好。字型大小會自動調整——請勿手動修改。 npx remotion still Cover out/cover.png --timeout=120000——然後顯示結果。
替代方案:PosterCover——使用影片海報作為封面(畫面及其去背結果分別放在 poster-bg.jpg / poster-cutout.png)。
11. 封存
將以下檔案放入 edits/<N>/(位於根目錄,而非 video/ 下):Composition.tsx、Footage.tsx、captions.json、SCRIPT.md、cover.png、final-master.mp4、preview.mp4。
如果用戶想要,後續可執行 publish 技能。