REEL-FROM-SCRIPT · v7 是做什麼的?
一個用於製作 9:16 比例的 Reels 技能,其成果看起來像是經過藝術指導,並且不會出錯——從一份不是你寫的腳本、一個你必須逆向工程的參考資料,以及一個對上一次對話毫無記憶的全新聊天開始。
v5 引入了佈局並將設計硬編碼到其中。v6 將每個數字移動到 PARAMS.json 中,並在渲染器前放置了一個驗證器。v7 是真實的兩個 Reels 教會 v6 的東西——六色場循環、封面海報、逐場景卡片動畫、連續場景跨度、自適應轉場、音訊陷阱,以及一個拒絕交出不良交付物的 ./build.sh + scripts/qc.py。
承諾: 人類唯一會編輯的檔案是
PARAMS.json。唯一被允許說「不」的是prepare.py/qc.py。其他一切都是生成的,並且每個生成的東西都可以透過一個命令重現。
0 · 如果你是新手:前 10 分鐘
export PATH=/home/user/node22/bin:$PATH # Node >= 22
cd <project> && ./build.sh --from render # 或者從頭開始遵循 §3
然後,按此順序閱讀:§1(外觀如何建構)→ §3(管線)→ §6(設計手冊)→ §9(故障目錄)。不要自行發明佈局:骨架就是設計。
絕對不要做這四件事: 輸入持續時間(測量畫外音)、將十六進位或像素值貼到合成中(更改 PARAMS.json)、手寫 index.html(生成它),或者在不查看聯絡表的情況下交付。
1 · 為什麼輸出看起來像是設計過的(七法則)
這些是在這個系列中每個良好畫面背後的實際決策。它們是規則,而非品味。
1. 一個錨點網格,底部固定。 引子 → 主體 → 內文 → 晶片 → 主持人。下半部永遠不會移動:晶片始終位於相同的 y 座標,主持人始終在相同位置被畫面裁剪。只有上半部會重新組合。這就是為什麼九個不同的場景讀起來像一部電影。
2. 主體是一個詞,不是一個句子。 1-3 個詞,使用緊湊的顯示字體,大小約為畫面寬度的 17-25%,行高緊湊 (0.88)。完整行放在晶片中(3-6 個詞,觀眾靜音時讀取的內容),細節放在卡片中。如果你不能用 3 個詞說清楚,那麼這個節拍就是兩個節拍。
3. 每個節拍都有一個不同的背景。 六個色場(奶油色 / 栗色 / 近黑色 / 鼠尾草色 / 海軍藍 / 薰衣草色)循環,確保相鄰兩個場景不相同。顏色的變化就是轉場的另一半。prepare.py 會在兩個連續場景共享一個色場時使建置失敗。
4. 證明,而非裝飾。 卡片的存在是為了展示東西:檔案列表、差異比較、瀏覽器、上傳、儀表。如果一個節拍沒有工件,它就是 type-led 型且沒有卡片。一張有兩行資料的卡片看起來像壞掉了;四到六行看起來是刻意的(或者一個佔據卡片 ≥ 55% 空間的模擬)。
5. 第一幀是一張海報。 場景 1 在 t=0 時組成(data-cover="1"):引子、主體、卡片和角色已在螢幕上,晶片在 0.65 秒時落下。以空白場開始的 Reels 會失去滾動觀看。
6. 動畫僅限於變形,並且提早完成。 入場時間為 0.24-0.34 秒,使用 power2/3/4.out 緩動,並且在節拍的前半段完成。永遠不要動畫文字內容,永遠不要補間數字,永遠不要讓一個 1.5 秒的場景花費 0.6 秒做轉場。主體上的緩慢漂移能讓最後一秒保持活力。
7. 聲音是標點符號,不是背景音樂。 每秒 ≤ 1 個提示音:每個切換有一個彈出聲、UI 上有按鍵滴答聲、兩個最大的轉折點有上升音、揭示時有鐘聲、CTA 上有通知/提示音。背景音樂在 -16 LUFS 的 VO 下設定為 0.15;主音量 -14 LUFS / ≤ -1 dBTP。
2 · 合約:什麼是固定的,什麼是你的
不變量——經驗證,不可憑感覺編輯
| 不變量 | 由誰強制執行 |
|---|---|
| 每對文字/背景都可讀 | WCAG ≥ 4.5:1 在 10 個渲染對 + 6 個色場對上 |
| 主體就是主體且總是適合 | ≥ 120 px,衍生大小,必須適合 --hero-lines 在 --hero-band 內 |
| 主體清除引子,從不觸碰卡片 | 衍生頻段 + --gap,硬性失敗 |
| 內文在手機上可讀 | ≥ 24 px 且 ≥ bodyMin |
| 沒有東西隱藏在平台 UI 下 | 晶片底部 ≤ 安全區底部,≥ 55% 可用空間 |
| 晶片永遠不會與卡片碰撞 | cardTop + cardHmax ≤ chipTop |
| 主持人被畫面裁剪,永遠不會蓋過晶片 | presenterTop + h > 1.0, presenterTop ≥ chipBottom |
| 兩個連續場景永遠不會共享一個色場 | 從每個合成讀取 data-field |
| 第 0 幀是一個封面 | data-cover + 快照閘 |
| 每個場景有不同的姿勢 | 每個場景一個姿勢檔案,審查時檢查 |
| 交付物可播放且夠大聲 | qc.py:解析度、幀率、幀數、LUFS、真實峰值、靜音漏洞 |
可變——真正屬於你的: 調色板值(6 個色場 + 4 種紙張色調,在對比度允許的情況下)· 格式(9:16, 4:5, 1:1, 720p)· 安全區內縮排· 地板內的每個網格和字體比例· 每個場景的原型· 場景數量· 文字· 持續時間· 姿勢集· 提示單· 磁碟上的字體。
如果你想要一個驗證器無法檢查的佈局,你就得改變骨架並添加檢查。這就是自由的代價,也是輸出不會變差的原因。
3 · 管線(順序不可協商)
| # | 步驟 | 命令 | 為什麼在這裡 |
|---|---|---|---|
| 0 | 逆向工程參考資料 | §4 | 你無法匹配一個你沒有測量過的外觀 |
| 1 | 事實 | — | 一個遲到的聲明會迫使重新錄音 |
| 2 | 腳本 → 章節 | assets/vo/sections.json | 每個節拍一個想法,1.2-9 秒 |
| 3 | 先處理 VO | python3 scripts/process_vo.py | timeline.json 是時鐘;畫面是根據它剪輯的 |
| 4 | 外觀 | PARAMS.json | 調色板、格式、網格、字體地板 |
| 5 | 閘門 | python3 scripts/prepare.py | 在對比度 / 字體 / 碰撞 / 色場節奏上失敗 |
| 6 | 場景 | ./scenes.sh | 每個節拍一個 new_scene.py 呼叫,注入記號 |
| 7 | 根目錄 | python3 scripts/build_index.py | 連續跨度、自適應轉場、無手寫 index.html |
| 8 | 語法檢查 | npx --yes [email protected] lint | 0 錯誤是一個閘門 |
| 9 | 查看它 | npx … snapshot --at "0,1.5,4,…" | 唯一能捕捉到「正確但難看」的步驟 |
| 10 | 渲染 | npx … render --output renders/_raw.mp4 | 32 秒 1080×1920 約需 1 分 45 秒,軟體 GL |
| 11 | 混合 | python3 scripts/mix_audio.py | VO + 背景音樂 + 提示音 → renders/master.wav (-14 LUFS) |
| 12 | 混流 + 交付 | build.sh 步驟 6-7 | mp4 + .srt + 縮圖,然後 qc.py |
./build.sh 一次執行 3 → 12 步驟。./build.sh --from render 在 VO 已測量時跳過 VO 步驟。
步驟 3 詳細說明 — VO 是時鐘
# 每個章節一個片段,命名為 vo1.mp3 … voN.mp3 放在 assets/vo/
python3 scripts/process_vo.py
它會修剪靜音,僅在設定了 script_target 時應用 atempo,將每個錄音標準化到 -16 LUFS,然後寫入 assets/vo/timeline.json:每個章節的開始/持續時間/結束 + root_duration。下游任何東西都不允許知道此檔案中沒有的持續時間。
使用天城文寫 say,並用拉丁字母寫英文技術詞(resume, job description, ATS score, DM)——印地語(印度)語音可以正確獲得語調,同時仍能說出英文單詞。caption 是 .srt 顯示的內容。
步驟 7 詳細說明 — 根目錄是機械式的
build_index.py 以數字順序找到 compositions/s*.html,讀取測量到的跨度,使它們連續(0 → 切換 → 切換 → … → 根目錄,這樣 VO 有 0.30 秒間隙的地方就不會出現黑洞),在每次切換前 0.36 秒觸發一個轉場,顏色為即將到來的場景的色場,並在音訊尾部保持最後一個場景。轉場會縮短到短場景長度的 34-62%——一個 1.4 秒的場景無法容納 0.62 秒的轉場。
步驟 11 詳細說明 — 兩個音訊陷阱
alimiter預設啟用level=true:它會自動將電平提升回天花板,因此你的「限制器」變成了一個壓縮器 + 補償增益,混合結果會達到 -12.5 LUFS,儘管你的目標是 -14。始終設定level=false。- 在一個線性通道中進行
loudnorm會超調。使用ebur128測量,精確移動target − measured,然後限制。你可以驗證的算術勝過一個猜測的濾波器。
4 · 階段 0 — 逆向工程參考影片
當簡報是「觀看這個並匹配它」時,測量它。十分鐘,五個命令:
ffprobe -v error -show_entries format=duration:stream=width,height,r_frame_rate,codec_type -of default=nw=1 ref.mp4
ffmpeg -i ref.mp4 -vf "fps=1,scale=400:-1,tile=6x6" -frames:v 1 sheet.jpg # 整部電影當作一張圖
python3 - <<'P' # 每秒的色場調色板
from PIL import Image; import glob
for f in sorted(glob.glob("frames/f_*.jpg"))[::2]:
im = Image.open(f).convert("RGB"); w,h = im.size
print(f[-7:-4], im.getpixel((3,3)), im.getpixel((w-4,3)))
P
ffmpeg -i ref.mp4 -vn -ac 1 -ar 16000 -c:a pcm_s16le audio.wav # 用於腳本
從中讀出:持續時間和剪輯節奏(每個節拍多長)、色場調色板(採樣角落,不是中間)、字體行為(緊湊大寫?逐詞建構?高亮框?)、佈局(角色坐在哪裡,文字區塊坐在哪裡)、UI 工件(哪些模擬)、聲音(提示音密度)。這六個數字就是整個藝術指導。
如果簡報給了你參考資料但沒有腳本,那麼參考資料就是腳本:轉錄音訊(faster-whisper, int8, base 模型 → 約 7 秒處理 32 秒的印地語英語混合語)並從幀中讀取螢幕上的文案。不要重寫文案——一個系列有自己的聲音。
翻譯,不要複製。 這裡的參考資料是 1280×720;交付物是 1080×1920。相同的調色板、相同的字體、相同的模擬——但主體頻段、晶片錨點和主持人裁剪是作為比例重新推導的。在 9:16 中,參考資料的 8-10 個詞塊低於 24 px 的內文下限,因此文案被不同地拆分:主體 1-3 個詞、晶片放行、卡片放細節。
5 · 檔案
PARAMS.json 唯一的設計檔案
tokens.css 生成的收據(請勿編輯)
index.html 由 build_index.py 生成(請勿編輯)
SKILL.md · COMPONENTS.md · README.md
build.sh 整個管線
scenes.sh 每個場景,可重現
components/ 7 個卡片主體,你可以用 --card-body @… 傳入
compositions/
_scene-base.html.tmpl 骨架 — 零個字面十六進位值,零個字面像素值
wipe.html 唯一的轉場
sN-*.html 由 new_scene.py 生成
_examples/ 三個實際場景(未掛載:build_index 只讀取 compositions/s*.html)
scripts/
process_vo.py VO → timeline.json
prepare.py 閘門:地板 + 記號注入
new_scene.py 基礎模板 → 正確的場景
build_index.py 時間線 + 場景 → 根目錄
mix_audio.py VO + 背景音樂 + 提示音 → master.wav
make_deliverables.py .srt + 縮圖
qc.py 一個命令,10 個閘門的 PASS/FAIL
cutout.py · gen_sfx.py 資產
assets/{fonts,presenter,vo,sfx,music}/
6 · 設計手冊(實際該選擇什麼)
節拍 → 原型。 證明 → card-led。一個數字 → stat-led(里程表,--digits)。一個陳述、一個過渡、一個品牌卡 → type-led。鉤子和 CTA 幾乎總是 card-led,因為兩者都需要一個工件(證明問題的檔案列表;證明 CTA 的評論串)。
節拍 → 色場。 交替暖色和冷色;永遠不要重複。六個色場的一個實用循環:accent → ground → ink → secondary → tertiary → quaternary。深色場(ink, tertiary)會使主持人消失,因此那裡的光暈設定為 0.20 → 0.42(骨架從 data-field 執行此操作);將它們用於工具揭示和「AI 完成工作」的節拍,在這些地方戲劇性有幫助。
節拍 → 姿勢。 同一個角色、同一套服裝、每個場景一個姿勢,與台詞的情感匹配:聳肩(提問)· 掩面(問題)· 呈現(提議)· 托腮(好奇)· 回憶(回想)· 豎大拇指(勝利)· 指點(一個步驟)· 靈感(頓悟)· CTA(請求)。從基礎圖像生成缺失的姿勢,並使用 cutout.py 進行遮罩;保持白色背景規則和半大腿裁剪,以便它們能被乾淨地分割。
螢幕上的文字。 主體:情感動詞或數字(SAME RESUME?, CUSTOMIZE KARO, TAILOR, ATS SCORE)。晶片:靜音觀看者需要的句子(har company mein bhej rahe ho?)。卡片標題:工件是什麼(applied / 12 companies)。卡片元資料:一個小事實(this week, matched 3 of 7)。
當一個節拍太短無法設計時(1-2 秒)。 保留場景,移除第二層:主體 + 晶片 + 主持人,type-led 型,一次揭示。不要將一個卡片和一個交錯列表塞進 1.4 秒——它會看起來像一個故障。
當一個節拍很長時(8-9 秒,通常是 CTA)。 分三個階段揭示,間隔 1.8-2 秒(留言 → DM → 連結),並讓一個緩慢的漂移帶動尾部。一個 8 秒的靜態幀是最常見的「它看起來廉價」的原因。
轉場。 一個轉場,0.34-0.62 秒,顏色 = 到來場景的色場,交替方向。沒有其他轉場類型:一致性是讓八個剪輯感覺像精心製作的原因。
最後一秒。 最終幀必須是一個帶有手柄和網站的設計幀——暫停在那裡的觀看者應該能夠採取行動。
7 · 音訊手冊
| 時機 | 提示音 | 增益 |
|---|---|---|
| 每次切換 | pop | 0.50 |
| 兩個最大的轉折點 | riser 在切換前 0.3 秒 | 0.28-0.30 |
| UI 元素著陸 | click, key | 0.38-0.45 |
| 列表逐項顯示 | key ×N,間隔 0.12 秒 | 0.40 |
| 揭示 / 分數 | chime | 0.36-0.42 |
| CTA | notify,然後 1.7 秒後 ping | 0.32-0.40 |
| 錯誤 / 拒絕 | error(節制使用——它只會讓人覺得好笑一次) | 0.30 |
提示音偏移量是相對於章節的,位於 assets/sfx/cues.json 中("vo7+1.68"),因此重新錄製的 VO 不會使設計無效。永遠不要讓提示音落在一個詞的第一個音節上;滴答聲屬於單詞開始後 20-60 毫秒。
[為便於翻譯而截斷]