Kinetic Promo Video
從一段商業描述打造一個看起來像廣播節目的垂直宣傳影片。影片以一個由暫停的主時鐘驅動的單一 HTML 頁面創作,然後逐幀渲染並編碼。沒有編輯器、沒有素材庫、沒有時間軸應用程式——而且每個幀都可以通過時間戳重現。
輸入
$brief— 這是什麼、給誰用、有什麼不同。必填。從對話、儲存庫的 README 或直接詢問取得。$reference— 可選。一個影片網址或本地檔案,應與其外觀匹配。$brand— 可選。名稱、標語、網址、顏色、標誌。如果沒有,則使用明確標記的佔位符(切勿默默發明一個品牌並將其呈現為最終版本)。$duration— 可選。預設 30–35 秒(無聲),45–60 秒(有配音,由配音長度決定——請參閱references/audio.md)。短影音/Reels/TikTok 請保持在 60 秒以內。$audio— 預設:有配音,無音樂。 撰寫配音稿並圍繞它建立時間軸,除非用戶要求無聲片段。音樂是唯一未經明確要求就保持關閉的元素。
目標
promo.mp4 — 1080×1920,30 fps,H.264,第一次觀看時即可播放且正確——加上生成它的 scene.html、可重現它的 render.py、有配音片段的 voice.srt 字幕檔案,以及包含節拍表和品牌重新命名的常數的 README。成功並非「檔案存在」:而是你親眼看過的幀,這些幀清晰可讀,沒有重疊的文字、沒有在提示前出現的元素,也沒有空白時間。
步驟
1. 檢查工具鏈
which ffmpeg ffprobe yt-dlp python3
python3 -m venv .venv && .venv/bin/pip install -q playwright && .venv/bin/playwright install chromium
ffmpeg 和用於 Playwright 的 Chromium 是必要條件。yt-dlp 僅在參考影片分析時需要。建議使用 venv——用戶的系統 Python 可能由外部管理。
成功標準:ffmpeg -version 可運作,且 .venv/bin/python -c "from playwright.sync_api import sync_playwright; sync_playwright().start().chromium.executable_path" 會輸出路徑。
2. 建立視覺目標
兩種路徑——根據 $reference 是否存在來選擇。
2a. 有參考影片 → 進行分析
閱讀 references/teardown.md 並按照指示操作。簡而言之:下載它、探查它、提取 1 fps 的聯繫表、實際閱讀這些表單圖像,並在編寫任何程式碼之前記錄尺寸、持續時間、調色板、字體處理方式、節拍結構和動詞詞彙。
切勿描述你未曾逐幀查看的參考影片。頁面的標題或描述無法告訴你任何關於其動畫設計的資訊。
2b. 沒有參考影片 → 先推導主題本身的語言
暫時不要開啟 default-style.md。花兩分鐘回答關於實際主題的四個問題:
- 物體是什麼? 書籍、罐子、發票、臉孔、儀表板。這些是應該移動的東西。
- 它們生活在什麼光線中? 閱讀燈、展示室、月光、螢幕光、窗外的日光。
- 它們如何物理上移動? 有質量的物體會沉降。紙張會翻轉和折疊。液體會擴散。數據會瞬間移動。
- 主軸是什麼? 承載論點的一個重複出現的元素——倒數計時、跨越夜晚的時鐘、增長的收據、逐漸填滿的路線。理想情況下,它就是聲明本身,而不是裝飾。
如果這四個答案給了你一個連貫的外觀,那就據此構建。一個關於夜間修復的護膚品宣傳片會使用夜間調色板、襯線字體、緩慢靜止的運動和一個顯示晚上 10 點到早上 7 點的轉盤——而不是發光的環。
當主題本身沒有提示任何具體內容時(大多數 B2B 軟體、抽象服務),則回退到預設風格。然後閱讀 references/default-style.md 並按原樣使用:它是一個完整且經過驗證的規範(深藍色 + 藍色光暈、幾何無襯線字體、模糊入場的動態排版、發光的地平線、環形結尾)。用一行話告訴用戶你正在使用哪種樣式,並說明他們可以透過命名一個參考影片來替換它——然後繼續進行。不要為了獲得批准而停滯不前。
構建前的誠實檢查。如果你的節拍時間落在模板的約 0.5 秒內,並且標誌性鏡頭保留了下來——重複的單詞堆疊、環形綻放、地平線加平板卡片、模糊入場作為唯一的文字動畫——那麼你只是在重新裝飾模板,而不是為主題進行設計。當你有意識地選擇回退時,這樣做是可以的;而當你沒有選擇時,這就是一個缺陷。
成功標準:一個簡短的書面規範——畫布尺寸、fps、持續時間、調色板十六進位碼、字體以及你將使用的動詞動作——在構建時你可以回頭參考。如果你推導出了主題本身的語言,它也應命名主軸以及你刻意不使用的動作。
3. 編寫節拍表
首先閱讀 references/audio.md 並編寫配音音軌——預設情況下它是開啟的。配音主導時間軸:生成台詞、測量它們,並從測量結果推導節拍時間,而不是將語音塞入整數中。保留測量出的每行時間——它們將在交付時成為 voice.srt。僅在用戶要求無聲片段時才跳過此步驟。
閱讀 references/beats.md 了解結構和文案規則,然後將用戶的實際差異化因素映射到節拍上。中間三分之一是產品銷售的地方:它必須包含這個東西更好的具體原因,而不是形容詞。假設播放時靜音——大多數 Shorts/Reels 觀眾從未聽到配音——因此配音稿中的每個聲明也必須以螢幕文字的形式呈現,而不僅僅是旁白。
在編寫程式碼之前,將節拍表寫成表格形式(t-範圍 → 節拍)。場景構建完成後再修正節奏錯誤的代價要高得多。
產出物:包含明確秒數範圍的節拍表,這些範圍加起來等於 $duration。
成功標準:每個節拍都追溯到產品的真實事物,並且範圍是連續的,沒有大於 0.3 秒的間隙。
4. 從模板建立骨架
下面的 $SKILL 是此技能本身的目錄——即包含此 SKILL.md 的目錄。從你的技能清單中解析它,而不是猜測路徑;它通常以唯讀方式掛載,這沒關係,因為所有內容都會被複製出來。
mkdir -p video && cp "$SKILL/templates/render.py" video/
cp "$SKILL/templates/scene-starter.html" video/scene.html
bash "$SKILL/templates/fetch-fonts.sh" video/fonts # Poppins 子集,約 40 KB
scene-starter.html 已經包含動畫框架(seek、win、io、pop、swap、種子化 RNG、氛圍)以及七個範例節拍,涵蓋了所有值得複製的模式。不要重寫框架——它已經編碼了規則部分列出的錯誤。替換範例節拍;保留它們之上的所有內容。
成功標準:python render.py --contact 可從未修改的啟動器產生 contact.png。
5. 構建場景
每個節拍一個 IIFE,每個 IIFE 創建一個由 win(layer, tIn, tOut) 門控的 layer()。在內部,每個動畫元素只調用一次 io() / pop() / swap()。
將 UI 模型(儀表板、手機、筆記型電腦、卡片、晶片)構建為純 DOM + CSS,並將它們動畫化——它們帶來了純文字無法實現的「真實產品」感覺。圖表是 div 和內聯 SVG;沒有圖表庫、沒有圖像、沒有外部請求。
硬切換是一個合法的動作:兩個 win() 層共享一個精確的時間邊界,使用 steps(1,end) 進入,可以提供一個刻意的單幀切換——這是實現音調變化(例如故事世界 → 純品牌顏色)的正確工具。其他所有動作都使用緩動;硬切換之所以有衝擊力,是因為它是唯一的。
真實的多色標誌在深色場景和純品牌背景上通常難以辨識——將資產放在一個白色小板上,而不是重新著色。
規則:請參閱規則部分。它們不是風格偏好——每一條都是此技能已經遇到的特定失敗。
成功標準:python render.py --contact 無錯誤地渲染。
6. 預覽循環——查看每個幀
python render.py --contact # 24 幀概覽,約 20 秒
python render.py --at 6.2 12.0 19.5 # 特定時刻,全解析度
使用你的圖像閱讀工具——無論框架稱之為什麼——讀取生成的 PNG 並檢查它們。 然後修復並重複。在此處迭代直到聯繫表清晰——完整渲染的速度是 10 倍,所以切勿將其用作你的回饋迴圈。
兩種視圖回答不同的問題。 聯繫表用於結構:時序、重疊、空白幀、節拍順序。它是 270×480 每幀,並且系統性地低估了深色或低對比度的工作——在聯繫表上看起來模糊且破碎的片段通常在完整尺寸下是清晰的。僅從 --at 幀判斷對比度、調色板和可讀性,並且每當調色板較暗時,至少為每個節拍提取一張,以及為每個象形圖或插圖提取一張——可辨識性無法在縮略圖尺寸下判斷(請參閱規則 12)。不要為了修復聯繫表誇大的問題而提高亮度。
每次檢查時要尋找的內容:
- 在過渡中間同時可讀的兩段文字
- 在其提示前出現的任何內容(經典的
fill: 'both'錯誤——請參閱規則) - 讀起來像可辨識形狀而不是氛圍的背景元素
- 堆疊的半透明團塊——重疊的阿爾法圖層會合成為可見的交集弧線,看起來像圓盤;使用一個元素,其邊緣在其自身邊框內溶解,尺寸大於畫布
- 空白幀——螢幕上沒有任何內容的時刻
- 文字或模型擁擠在畫布邊緣,或對於手機螢幕來說太小
人工檢查點:沒有必要,但如果用戶在場,請在完整渲染之前向他們展示聯繫表——此時調整節奏和文案的成本最低。
成功標準:你已經查看了一個聯繫表,其中每個幀都清晰可讀,並且沒有上述缺陷。
7. 渲染與驗證
首先對編碼器進行煙霧測試。 渲染一個約 2 秒的片段——如果你的 render.py 副本有範圍標誌,否則暫時縮短持續時間常數——然後用 ffprobe 檢查結果。編碼器和混流問題會在幾秒鐘內顯現,而不是在耗時數分鐘的完整渲染之後。
python render.py # -> promo.mp4,每幀約 1 張截圖
# 有配音的片段:僅在編碼器程序退出後進行混流
ffmpeg -y -i promo.mp4 -i vo/voice.wav -c:v copy -c:a aac -b:a 192k promo_av.mp4
ffprobe -v error -show_entries format=duration \
-show_entries stream=codec_type,codec_name,width,height,nb_frames \
-of default=noprint_wrappers=1 promo_av.mp4
ffmpeg -y -v error -i promo_av.mp4 -vf "fps=1/1.2,scale=180:320,tile=10x3" -frames:v 1 verify.png
在背景中執行完整渲染。 它大約每幀 1 張截圖——一個 50 秒的影片約有 1500 幀,並且會輕鬆超過 600 秒的命令超時。輪詢渲染程序是否退出,而不是等待 mp4 出現:檔案在完成前很久就存在於磁碟上,過早混流會導致「moov atom not found」。
對於有配音的片段,根據在步驟 3 中測量的每行時間編寫 voice.srt——這些數字已經存在;這只是一個格式化步驟,而不是新的工作。
讀取 verify.png——驗證編碼後的輸出,而不是瀏覽器,是關鍵。然後刪除暫存表和幀目錄。
成功標準:ffprobe 報告預期的持續時間、預期的尺寸(除非用戶更改了長寬比,否則為 1080×1920),以及 nb_frames == fps × duration;對於有配音的片段,存在音頻流,持續時間與配音音軌匹配,並且 voice.srt 存在;verify.png 從頭到尾與節拍表匹配。一個缺少結尾的短檔案通常意味著 -shortest 遇到了一個過時的配音音軌——請參閱 references/audio.md。
8. 交付
在影片旁邊編寫一個 README,包含:節拍表、品牌重新命名的常數、渲染命令以及兩個框架注意事項。然後向用戶報告:
- 檔案位置及其精確規格(大小、持續時間、fps,以及是有配音還是無聲——加上使用的 TTS 語音,以便可以重新生成)
- 有配音片段的
voice.srt路徑,以及 Shorts/Reels/TikTok 接受將其作為影片上傳的附加上傳 - 節拍表
- 每個佔位符和發明的數字,明確指出——品牌名稱、網址以及模型中顯示的任何指標。清楚說明,如果聲明需要是可辯護的,則必須在發布前替換虛構的數據。
- 除非用戶要求託管,否則沒有可分享的連結——它是一個本地檔案
提供打開它的選項:open promo.mp4。
規則:未經明確批准,切勿提交或發布。切勿將影片上傳到任何地方作為生成它的副作用。
成功標準:用戶知道檔案路徑、什麼是佔位符以及如何更改它。
規則
硬性約束。每一條都是此流水線已經產生的失敗。
-
預設有配音,從不使用音樂。 除非用戶要求無聲片段,否則編寫配音稿並讓它主導時間軸。除非明確要求,否則音樂和音效設計保持關閉——你無法提供授權音軌,並且切勿從串流網站拉取音頻。無論如何,假設靜音播放:配音稿中的每個聲明都鏡像為螢幕文字,並且有配音的片段附帶
voice.srt。當你交付無聲片段時,在報告時說「無聲」,以便安靜播放不會被誤解為錯誤。 -
每個元素一個動畫,涵蓋進入 → 保持 → 退出。 兩個不同的 WAAPI 動畫使用
fill: 'both'會衝突:退出剪輯從t = 0開始應用其第一個關鍵幀,從而使該元素在整個影片中都保持可見。io()輔助函數的存在正是為了防止這種情況。症狀:場景中的所有內容在場景開始時同時出現,而不是動畫化進入。 -
連續的文字必須完全退出後,下一個才能進入。 在交叉淡入淡出期間,兩行可讀的文字同時出現在螢幕上,看起來像是渲染錯誤,而不是過渡效果。安排第 N 行文字的退出在第 N+1 行文字的進入開始之前完成。
-
確定性是不可協商的。 種子化 RNG。切勿調用
Date.now()、Math.random()或其他會引入非確定性的函數。產生的幀序列應完全可重現。
...
[後續規則因截斷而省略]