Communitygithub.com

mhuot/promo-video-skill

完全離線的約60秒旁白宣傳影片製作:Kokoro TTS + HyperFrames + FFmpeg + OpenMontage 治理。內含範本以及一段由該技能自行製作的技能介紹示範影片。

promo-video-skill 是什麼?

此技能定義了一套完全在本機、離線運行的宣傳影片製作流程,不需依賴任何雲端 API 或網路連線。它整合了 Kokoro TTS 產生旁白、HyperFrames 進行 HTML/CSS 動畫合成、FFmpeg 負責音訊合成與編碼,並透過 OpenMontage 進行管線治理與決策日誌記錄,確保每個環節都有清楚的決策依據。流程從研究與腳本鎖定開始,所有時間參數皆從實際錄製的旁白音檔測量推導,避免憑空猜測。支援 Claude Code、Cursor、Codex、Windsurf 等多種 AI 代理,並提供 `install.sh` 腳本進行本機工具鏈的安裝。最終輸出是約 60 秒、具有旁白與背景音樂的宣傳影片,並附有平台適配的封裝選項。

相容平台✓Claude Code✓Codex CLI✓Cursor✓Antigravity✓Windsurf
npx skills add mhuot/promo-video-skill

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

宣傳影片製作 (本機工具鏈)

與代理無關:專為任何能讀取檔案並執行 shell 命令的 AI 編碼代理所撰寫 — 透過 install.sh 原生安裝於 Claude Code、GitHub Copilot CLI / Microsoft Scout 及 Google Antigravity;亦可從 Cursor、Codex、Windsurf 及其他工具中作為純 Markdown 操作手冊使用。 此工具鏈首度由 Idan Shimon (Microsoft, github.com/idanshimon) 展示 — 他的一段 58 秒概念解釋影片,由 AI 代理在本機使用此技術棧以零成本製作,正是本技能的開發靈感來源。

請勿假設安裝位置:將 PROMO_VIDEO_SKILL_DIR 設定為包含此 SKILL.md 的目錄。其 scripts/ 目錄包含 TTS 腳本、縮寫發音輔助工具及固定的 TTS 依賴項;assets/ 目錄包含合成骨架、空間元件範本及決策日誌結構;references/ 目錄包含每台機器一次性的工具鏈啟動文件 (install.md)。

核心原則:腳本優先鎖定;後續的所有數字都必須從測量所得的旁白音檔推導,絕不憑空猜測。

宣傳,非解釋:此技能銷售的是「為什麼」— 對象、痛點、轉變、證明、一個行動呼籲。運作機制最多只能佔一個節拍,且僅在使用者要求時才納入;關於教導某事物如何運作的請求,屬於配套的 explainer-video 技能範疇。

工具簡介

工具位置已驗證版本授權角色呼叫方式
OpenMontage~/OpenMontage2026-07 檢出版本AGPLv3 (僅工具本身;影片中不包含任何其產出)管線治理:階段順序、決策日誌、閘門、渲染後自我審查紀律閱讀其 AGENT_GUIDE.md + pipeline_defs/animation.yaml;你 (代理) 是編排者 — 無需執行任何守護行程
KokoroPyPIKokoro-82M (hexgrad),kokoro==0.9.4程式碼 Apache-2.0;模型權重 Apache-2.0旁白 TTS,每個場景輸出 24 kHz 單聲道 WAVPython 3.12 venv;KPipeline(lang_code="a"),語音 af_heart,speed 參數
HyperFrames~/hyperframes0.7.57,從原始碼建置Apache 2.0HTML/CSS/GSAP 合成 → 透過無頭 Chrome 輸出確定性 MP4node ~/hyperframes/packages/cli/dist/cli.js <cmd>
FFmpeg~/FFmpeg 原始碼;建置目錄中的二進位檔git master (N-125608 時期)GPL 建置 (啟用 libx264)音樂合成 (aevalsrc)、編碼、ffprobe 品質檢查、音量、平台封裝將建置目錄置於 hyperframes 命令前的 PATH 中
bunnpm 全域1.3.14—建置 hyperframes 單一儲存庫npm i -g bun (brew cask 曾無聲失敗過一次)
Node.jsnvm24.x (需 ≥22)—執行 hyperframes CLI—
Pythonuv 管理3.12—Kokoro 推論務必使用 venv (uv venv --python 3.12 .venv);black + pylint 無錯誤
espeak-ngHomebrew 或 apt任何版本GPLKokoro G2P 後備方案 (必要)macOS:brew install espeak-ng;Debian/Ubuntu:sudo apt install espeak-ng
gsap供應商檔案3.x gsap.min.jsGSAP 標準授權合成內的時間軸動畫複製到 video/assets/ 中 — 絕不使用 CDN <script src> (離線確定性)

環境檢查 (每台機器一次)

export FFMPEG_BUILD_DIR="${FFMPEG_BUILD_DIR:-$HOME/ffbuild}"
export HYPERFRAMES_DIR="${HYPERFRAMES_DIR:-$HOME/hyperframes}"
export PATH="$FFMPEG_BUILD_DIR:$PATH"
node "$HYPERFRAMES_DIR/packages/cli/dist/cli.js" doctor

FFmpeg、FFprobe、Node 和 Chrome 必須全部通過才能進入正式製作階段 (其他 doctor 列出的項目為本技能未使用的可選元件)。如果其中任一項失敗,請遵循 $PROMO_VIDEO_SKILL_DIR/references/install.md — 完整的單機一次性啟動流程:系統套件 (macOS/Linux)、複製原始碼工具 (包括 OpenMontage 參考檢出)、從原始碼建置含 libx264 的 FFmpeg、建置 HyperFrames CLI,以及代理權限提示。當 doctor 已通過時,請勿載入該檔案。

Chrome:CLI 會自動使用 ~/.cache/puppeteer/ 下快取的 chrome-headless-shell (若無則下載一次)。首次 TTS 運行同樣會下載 Python 套件和 Kokoro-82M 權重。完成這些一次性下載後,合成、驗證、渲染和封裝流程即可離線執行。

專案結構 (每個影片建立一個,自有 git 儲存庫,原子提交)

<project>/
  .venv/                          # uv venv,python 3.12
  .gitignore                      # .venv/ __pycache__/ video/snapshots/ .DS_Store
  README.md                       # 製作方式 + 再現說明 (最後撰寫)
  production/
    research/research-brief.md    # 附來源的事實 + 誠實的競爭對手比較表
    proposal.md                   # 概念、場景清單、交付承諾、執行時間決策
    script/script.md              # 鎖定的旁白
    scene_plan/scene-plan.md      # 每個場景的視覺 + 動畫筆記
    checkpoints/decision-log.json # 僅附加;(類別, 主題) 為鍵值
    checkpoints/self-review.md    # 渲染後證據
    assets/audio/                 # kokoro WAV 檔案 + durations.json
    renders/                      # 主版本 + 平台衍生版本
    youtube/                      # metadata.md + thumbnail.jpg
  tools/tts_generate.py           # 從此技能複製,編輯 SCENE_NARRATIONS
  tools/tts_pronounce.py          # 從 scripts/ 複製,縮寫發音 (請勿編輯)
  tools/pronunciation.local.json  # 可選的專案自訂發音詞典
  video/
    index.html                    # 主要合成檔案
    assets/gsap.min.js            # 供應商檔案
    assets/audio/                 # WAV 檔案複本 (相對於合成檔案的路徑)

階段 1 — 研究 (優先離線)

挖掘主題本身的儲存庫/README/文件 — 尋找成果和證據 (數字、採用率、前後對比結果),而非架構。產出 research-brief.md,內容包含:

  • 定位區塊 (必要 — 腳本在鎖定前必須有此內容)。 每個項目一句話:對象 (此內容為誰而寫)、痛點 (他們目前感受到的困擾)、轉變 (對他們來說什麼改變了)、差異點 (選擇此方案的唯一理由)。這是核心訊息;後續每個階段都為此服務。
  • 產品事實,每個都需對照來源驗證 — 僅保留那些能支持效益的項目 (通過「所以呢?」測試:觀眾能得到什麼?)。
  • 競爭對手比較表 (弱點 → 主題如何應對)。誠實原則:坦承對手的真實優勢 (對手欄位中的一個 ✓ 可為你自己的主張增加可信度)。
  • 一份 「腳本可用主張」清單。

階段 2 — 提案 + 決策

撰寫 proposal.md:重申定位區塊、5–7 個場景概念、目標約 60 秒、交付承諾 (以動畫為主,非投影片)、工具鏈表。記錄到 decision-log.json — 從 $PROMO_VIDEO_SKILL_DIR/assets/decision-log.json 的空結構開始 (欄位:category, subject, selected, options_considered, rejected_because, confidence):pipeline_selection、render_runtime_selection (記錄 Remotion 作為被考慮的替代方案 — OpenMontage 為硬性規定)、composition_mode (主要作品使用 atelier)、voice_selection、music_selection、output_profile、approval_gates 以及 cta_selection — 恰好一個行動呼籲 (為儲存庫加星號 / 安裝 / 觀看示範 / 造訪網站);宣傳影片若以功能列表而非請求作為結尾便會失敗。如果使用者的簡報已固定某個選擇,則標記為 approved_by: "user brief"。稍後更改了決策?附加一個新的條目,使用相同的 (category, subject) — 絕不編輯舊條目。

階段 3 — 腳本 (鎖定點)

約 150–155 字 ≈ 60 秒,使用 kokoro af_heart 語速 1.1。宣傳弧線 (銷售「為什麼」):利害關係/痛點鉤子 → 揭露 (名稱 + 其承諾的轉變) → 觀眾世界中的效益 → 證明 (誠實比較、真實成果) → 願景 → 來自決策日誌的單一行動呼籲。功能僅作為效益的證據出現:每個句子都必須通過「所以呢?」測試 (觀眾能得到什麼?),否則改寫。至多一個「運作機制」節拍,且僅在使用者要求時才納入 — 教導機制是 explainer-video 技能的職責。語氣:第二人稱、現在式、簡潔有力的句子 ("you ship faster",而非 "it enables faster shipping")。在腳本和螢幕文字中自然地書寫縮寫 ("OID", "MCP", "AI") — 在合成時,tools/tts_pronounce.py 會根據其詞彙庫推導出口語形式 (逐詞 vs 逐字母朗讀),未知的縮寫則會逐字母拼出並回報。在可選的 tools/pronunciation.local.json 中分類領域術語 ({"NASA": "word", "ECG": "letters", "NGINX": "engine X"})。避免全大寫強調:全大寫單詞會被視為縮寫。每個場景的字數預算 ≈ 其佔 60 秒的比例 × 2.55 字/秒。

階段 4 — 旁白 + 時間推導 (承重技巧)

從隨附的固定直接依賴項建立專案的 Python 3.12 環境,複製通用範本,然後僅編輯 SCENE_NARRATIONS:

uv venv --clear --python 3.12 .venv
uv pip install --python .venv/bin/python \
  -r "$PROMO_VIDEO_SKILL_DIR/scripts/tts-requirements.txt"
mkdir -p tools
cp "$PROMO_VIDEO_SKILL_DIR/scripts/tts_generate.py" tools/tts_generate.py
cp "$PROMO_VIDEO_SKILL_DIR/scripts/tts_pronounce.py" tools/tts_pronounce.py
PYTORCH_ENABLE_MPS_FALLBACK=1 .venv/bin/python tools/tts_generate.py
mkdir -p video/assets
curl -fL https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js \
  -o video/assets/gsap.min.js

首次合成會下載 Kokoro-82M 權重 (~330 MB);後續運行使用快取,可離線執行。它會為每個場景寫入 WAV 檔案 + durations.json。如果運行時印出「未知縮寫」警告,請在 tools/pronunciation.local.json 中分類這些標記,然後在推導時間參數前重新執行。

將 150–155 字、語速 1.1 視為起始估算,而非校準基準。總時長 >62 秒?提高語速或刪減文字,然後再次測量。

推導時間軸 (場景間間隔約 0.3–0.5 秒):

n_start[0] = 0.5                       # 開頭引導
scene_start[i] = n_start[i] - 0.15..0.4   # 視覺元素比旁白稍早出現
n_start[i+1] = n_start[i] + dur[i] + 0.3..0.35
TOTAL = last n_end + 0.6..0.9 tail (淡出至黑)

這些數字必須出現在三個地方並保持一致:場景的 data-start/ data-duration、<audio data-start> 值,以及 JS 中的 const S1..Sn 時間軸常數。將 WAV 檔案複製到 video/assets/audio/。

階段 5 — 背景音樂 (無需下載)

使用從原始碼建置的 FFmpeg 生成確定性的合成背景音墊。將 TOTAL_SECONDS 設定為推導出的合成總時長;無需任何外部樣本或私有參考:

TOTAL_SECONDS=60.5
FADE_SECONDS=3.5
FFMPEG_BIN="${FFMPEG_BUILD_DIR:-$HOME/ffbuild}/ffmpeg"
FADE_OUT_START="$(awk -v total="$TOTAL_SECONDS" -v fade="$FADE_SECONDS" \
  'BEGIN { printf "%.3f", total - fade }')"
mkdir -p production/assets/audio
"$FFMPEG_BIN" -hide_banner -y \
  -f lavfi \
  -i "aevalsrc=0.07*(sin(2*PI*110*t)+0.65*sin(2*PI*110.7*t)+0.45*sin(2*PI*164.81*t)+0.30*sin(2*PI*220.9*t)):s=48000:d=${TOTAL_SECONDS}" \
  -af "highpass=f=55,lowpass=f=1200,afade=t=in:st=0:d=2,afade=t=out:st=${FADE_OUT_START}:d=${FADE_SECONDS},pan=stereo|c0=c0|c1=c0" \
  -c:a pcm_s16le production/assets/audio/music-bed.wav

保持稀疏;混音時設定 data-volume="0.12..0.16" 可營造氛圍 — 對於宣傳影片的能量感,請接近此範圍的上限,但絕不超過旁白音量。將 WAV 檔案複製到 video/assets/audio/ 並使用獨立的音軌。

階段 6 — 合成創作 (HyperFrames 合約)

從 $PROMO_VIDEO_SKILL_DIR/assets/composition-skeleton.html 開始 (它體現了以下所有規則);在撰寫 HTML 之前,先大致瀏覽 $HYPERFRAMES_DIR/skills/hyperframes-core/SKILL.md。 結構:獨立的 index.html,根元素 <div data-composition-id="X" data-start="0" data-duration="TOTAL" data-width="1920" data-height="1080">,場景為 <section class="clip" data-start data-duration data-track-index="1">,一個在 window.__timelines["X"] 同步註冊的 gsap.timeline({paused:true}),補間位置 = S<i> + local_offset。

以下是曾經耗費大量時間除錯的規則 — 請務必遵守:

  1. 每個 <video>/<audio> 都需要一個明確且非空的 id。 在 HyperFrames 中,沒有 id 的音訊可能在瀏覽器預覽中正常播放,但在渲染時會無聲 (lint 工具會發出錯誤;請勿忽略)。
  2. 絕不要在 CSS 中為 GSAP 補間的目標元素設定初始 transform: — 請使用 tl.fromTo(el, {y:24, opacity:0}, {y:0, opacity:1, ...});GSAP 完全掌管 transform。(單獨設定 opacity: 0 在 CSS 中對於僅使用 .to() 的顯示動畫是沒問題的。)
  3. 背景填充應放在一個全出血的子元素上 (position:absolute; inset:0),絕不放在根元素上 (根元素的背景可能渲染為黑色)。
  4. 媒體元素是根元素的直接子元素,使用 data-track-index 區分不同的音軌 (例如 7=旁白, 8=音樂)。
  5. 無無限重複 (repeat: -1 禁止 — 請使用有限次數,例如游標閃爍 repeat: 9, yoyo: true),無 Date.now/Math.random,無網路請求,無 CDN 腳本。
  6. 所有元素都需有唯一的 id;僅對 transforms/opacity 進行動畫 (加上 strokeDashoffset 用於 SVG 線條繪製)。
  7. 在中場出現的元素:隱藏初始狀態 + 在 S<i>+offset 處進行補間。fromTo 具有 immediateRender 屬性,因此在補間前進行時間軸搜尋會顯示 from 狀態 — 這正是使其搜尋安全的關鍵。
  8. 設計標記使用 :root CSS 變數 = 主題;交換 ground/ink/accent + 字型堆疊即可重新換膚。使用渲染器捆綁的字型 (JetBrains Mono) — 系統字型無論如何都會被替換 (lint 資訊會告訴你對應關係)。
  9. 保持次要文字在背景色上符合 WCAG AA 標準 — check 命令會在對比度不足時失敗,並列印出可用的合規顏色。
  10. 有意的重疊/滾動超出:使用 data-layout-allow-overflow/-overlap/-occlusion 標記,而不是留下未解釋的發現。

場景主題建議:展示結果狀態 — 觀眾世界的改善 (前/後對比、痛點消失、螢幕上的成果)。從主題的實際 UI/領域 (偽造的搜尋面板、終端機、樹狀圖、表格) 中提取輔助性的片段,作為效益的證據,而不是進行機制導覽。敘事弧線有範本;主題則不應受限。 $PROMO_VIDEO_SKILL_DIR/assets/composition-skeleton.html 包含範例場景和 GSAP 時間軸結構,可作為起點。

相關技能