Communitygithub.com

beachyphotoandfilm-arch/video-skills

為談話性影片建立動態品牌疊加圖層(動態圖形),並精準對齊講者的台詞時間點,同時產出 DaVinci Resolve 匯入檔案。

video-skills 是什麼?

此技能可將原始剪輯轉變為一組動態疊加圖層,每個圖層都會精準落在講者說出特定詞句的影格上,並產生 DaVinci Resolve 的匯入檔案。其核心設計哲學是「場景內文字」,也就是讓文字與圖形環繞在講者頭部周圍或後方,而不是使用卡片或全螢幕覆蓋。整個流程包含:本機轉錄影片以取得逐字時間碼、挑選適合加入疊加圖層的時刻、依據品牌風格指南渲染透明的 .mov 影片片段,最後產生一份可直接將所有片段放入時間軸正確位置的 FCPXML 檔案。此技能支援多種觸發方式,例如「為這部影片製作動畫」、「加入疊加圖層/動態圖形」等。它偏好直接透過 MCP 伺服器與 DaVinci Resolve 協作,但也能產出可供手動匯入的 FCPXML 檔案作為備案。此外,它還內建了預覽與驗證機制,確保疊加圖層在最終畫面中位置正確且不會遮擋講者。

相容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/beachyphotoandfilm-arch/video-skills/tree/HEAD/skills/video-overlays

在你喜歡的 AI 中提問

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

說明文件

影片疊加圖層

將原始剪輯轉變為一組動畫疊加圖層,每個圖層都精準落在講者說出該內容的影格上,並產出 Resolve 匯入檔案。

在此設定你的品牌

只需編輯一次,在 scripts/scene.html 中(頂端的 :root 區塊)。其他所有設定都會從這裡讀取。

設定CSS 變數預設值
強調色--brand-accent (+ --brand-accent-rgb 作為 r,g,b)#4a90e2
淺色文字顏色--brand-light (+ --brand-light-rgb)#f2f2f2
深色墨水顏色--brand-ink#0d131a
顯示字型(標題、數字)--font-display'Anton','Bebas Neue',Impact,sans-serif
主要字型--font-body'Inter',-apple-system,sans-serif

顯示字型必須在本機安裝(例如在 ~/Library/Fonts),因為影片片段會在無頭 Chrome 瀏覽器中離線渲染。Anton 和 Bebas Neue 可在 Google Fonts 免費取得。程式碼中的名稱 BLUE 只是代表「強調色」。

風格原則:場景內文字。 不使用卡片。文字與講者的頭部位於同一空間,大型標題環繞頭部兩側,提問內容隨著講者說出而逐字顯示。始終使用你的品牌顏色和顯示字型。

最重要的規則: 讓圖形保持在講者頭部後方或側邊。不要在臉部前方放置任何東西,也不要使用背景顏色。圖表同樣位於講者身旁的牆面上。所有內容都經過遮罩處理,因此講者的手可以穿過圖形前方。

一次執行會產出: N 個透明的 .mov 影片片段、PLACEMENT.txt、兩個 .fcpxml 檔案,以及一個簡短的 PREVIEW.mp4。

預設沒有聲音。 除非被要求,否則不要加入音樂或音效。

風格預設值(可依喜好調整)

  1. 沒有任何內容會在說出前出現。 將每個片段錨定到該短語的逐字時間碼,再加上約 0.12 秒,使其在文字說出後立即出現。章節層級的時間設定會被視為較早。
  2. 簡短。 2.5 到 6.5 秒。大部分約 3 秒。它應該像社群媒體影片一樣快速切換,而不是長時間停留。
  3. 位於頭部後方或側邊,絕不覆蓋講者。 不使用卡片、背景或變暗效果。這表示不再使用角落標籤、所有 full-* 卡片以及新影片的 define 類型。
  4. 仍然顯示機制。 在寫出句子之前,先使用圖表。使用場景內圖表類型(dots、flow、bars、compare、math),它們會位於講者身旁的牆面上。
  5. 將任何有兩部分內容的項目拆分開來。 舊方法和新方法是兩個片段。10% 和 20% 是兩個片段。三個選項就是三個片段,每個片段都會在它被提到時出現。
  6. 每一行都精準落在該詞上。 列表、側邊文字和逐字輸入的文字,每行都有各自的偏移量(at、t),這些偏移量來自於單字的時間碼,而不是平均分配。scripts/plan.example.py 示範了做法:引用短語,命名提示詞,它就會進行查詢。
  7. 良好的混合(約 48 個片段,持續 11 分鐘):大約四分之一是場景內圖表(主要是 flow),然後是 side、pair、type、list2、num。保留 pair 給重點結論。
  8. 大型標題要環繞頭部,而不是放在頭部後方。 pair 會將每一行在單詞邊界處分成兩半,分別位於頭部兩側,間距為臉部框寬度的 1.9 倍(包含頭髮和耳朵),並縮放以確保兩半都顯示在畫面內。因此每個 pair 行都需要 2 個或以上的單詞(例如「ONE HOUR」,而不是「HOUR」):單一單詞無法分割,最終會被隱藏。在 data 中設定 "around": false 可以恢復置中顯示。外框線條為 150px,帶有 5px 的筆觸和 35% 透明度的淺色強調填充,以確保可讀性。

開始之前:剪輯是否已鎖定?

疊加圖層是錨定在特定詞語上的,因此之後的任何修剪都會導致所有片段偏移。如果使用者提供的是原始素材,或者剪輯尚未鎖定,請先執行 paper-edit 技能,並將疊加圖層放置在其產生的時間軸上。

流程

1. 取得剪輯並進行探測

要求使用者從 Resolve 匯出(例如到 ~/Movies/),或者如果先進行紙本編輯,則要求原始素材在 <YOUR_FOOTAGE_DRIVE> 上。提供影片檔案即可,無需單獨匯出音訊。當 Resolve 開啟時,透過 MCP 讀取時間軸,而不是要求匯出。

ffprobe -v error -show_entries format=duration -show_entries stream=codec_type,r_frame_rate -of default=nw=1 "<file>"

注意影格率(渲染器預設為 23.976 = 24000/1001;如果使用其他影格率,請在 render.mjs 中更改 FPSN/FPSD),並詢問時間軸是從 00:00:00:00 還是 01:00:00:00 開始(Resolve 的預設值是 01)。

2. 使用逐字時間碼進行轉錄

ffmpeg -y -i "<file>" -ac 1 -ar 16000 -c:a pcm_s16le cut.wav
whisper-cli -m ~/.cache/whisper-models/ggml-small.en.bin -f cut.wav -oj -ml 1 -sow -of cut

-ml 1 -sow 參數為每個片段提供一個標記,這是實現精確錨定的關鍵。然後,透過比對 cut.json 中的標記序列(transcription[].offsets.from 單位為毫秒),找出每個短語的起始時間。

3. 挑選時刻

先閱讀完整的轉錄稿。目標是每 15 秒影片大約一個片段。針對每個片段,決定:錨點短語、類型,以及能讓動畫展現並有足夠呼吸空間的最短持續時間。

要根據實際說出的內容來決定,而不是書面筆記。如果筆記寫著「30 分鐘」,但鏡頭前說的是「大約半小時」,則以錄影內容為準,並向使用者標記此差異。

4. 撰寫 clips.json

複製 scripts/clips.example.json 作為模型。每個片段一個物件:

{"id":"06-math-10","start":52.96,"dur":3.6,"type":"dots","cue":"\"if 10 out of 100 meals are home cooked\"",
 "data":{"lit":10,"pct":"10%","count":"10 meals"}}

將它放在技能資料夾之外(臨時路徑即可),並使用 CLIPS= 傳遞。start 是短語的原始時間(秒);渲染器會自行加上 0.12 秒的提前量。id 的順序決定了檔案順序,因此請對它們進行編號。

5. 渲染乾淨的剪輯(場景內類型需要)

場景內類型會讀取頭部位置,並從一份沒有疊加圖層的剪輯副本中將講者挖出。從 Resolve 渲染已鎖定的時間軸,停用所有疊加圖層片段,使用 H.264 1080p,輸出到臨時路徑。在 API 中,SetTrackEnable 在 Resolve 19 中對 V2 軌道無效;應對軌道中的每個片段使用 item.SetClipEnabled(False)。原始素材必須在線,因此素材硬碟必須已掛載;如果未掛載,請要求使用者插入並監控掛載狀態,而不是渲染一個已完成的母版(舊的疊加圖層會被燒錄進去)。

6. 渲染

cd <skill>/scripts && npm i                   # 僅首次執行,安裝 puppeteer-core
swiftc -O person.swift -o person              # 僅首次執行,遮罩 + 頭部尋找器
TITLE="<video name>" CLIPS=/path/to/clips.json FOOTAGE=/path/to/clean.mp4 OUT_DIR="$HOME/Movies/<video-name>-overlays" node render.mjs
# 僅一個或少數幾個片段:
ONLY=06-math-10,07-math-30 OUT_DIR=... node render.mjs

每渲染一秒的疊加圖層,大約需要 10 到 15 秒的真實時間(pair 較慢,因為它需要對每個影格進行遮罩)。讓它在背景執行並定期檢查進度是正確的做法。它會在結束時寫入 PLACEMENT.txt 和兩個 .fcpxml 檔案。

在完整渲染之前,務必在真實素材上進行預覽。 node proof.mjs <clean.mp4> <clips.json> out.jpg [email protected] [email protected] ... 會為每個片段渲染一個影格(前綴@進入片段的秒數),並疊加在實際畫面上(包含遮罩),然後拼貼成一張圖片。檢查它。文字跑出畫面、標題穿過眼睛、文字疊在複雜背景上:這些在程式碼中看不見,但在圖片中一目了然。對於圖表,疊加在灰色背景上仍然可以接受。

預覽影格:先提取為 PNG。 使用 -ss 將 qtrle .mov 直接疊加到 lavfi 顏色來源上會得到空白影格。先將影格提取出來(ffmpeg -ss 2.8 -i clip.mov -frames:v 1 f.png),然後合成 PNG。

在 Resolve 中放置: 複製鎖定的時間軸並命名為 YouTube Final,將 mov 檔案匯入到 Overlays 素材箱中,然後對每個檔案使用 AppendToTimeline,設定 trackIndex: 2 以及來自 PLACEMENT.txt 中 IN 時間碼的 recordFrame(((h*3600+m*60+s)*24+ff),因此 01:00:00:00 = 86400)。一次解析 PLACEMENT.txt 中的一行(line.split()[0] 是 id,[1] 是時間碼)。使用整個檔案的正規表達式可能會將像「60-second」這樣的提示文字誤認為片段 id,並竊取下一行的時間碼,導致一個片段被靜默地遺漏。請確認已放置的片段數量等於片段總數。

7. 預覽,然後交付

在真實素材上建立一個 10-15 秒的預覽,以便使用者在將其加入之前進行判斷:

ffmpeg -y -ss <t> -t 11 -i "<cut>" -itsoffset <a> -i "<clip1>.mov" -itsoffset <b> -i "<clip2>.mov" \
  -filter_complex "[0:v][1:v]overlay=0:0:eof_action=pass[v1];[v1][2:v]overlay=0:0:eof_action=pass[vo];[vo]scale=1280:-2[v]" \
  -map "[v]" -map 0:a -c:v libx264 -crf 20 -preset veryfast -c:a aac PREVIEW.mp4

原始音訊會隨素材一起包含進來,這正是預覽所需的全部內容。 然後提供匯入步驟(檔案 > 匯入 > 時間軸 > 匯入 AAF、EDL、XML,選擇 starts-01 檔案,將片段複製到素材上方的一個軌道,起始時間為 01:00:00:00)。

直接在 Resolve 內部工作(當 Resolve 開啟時為首選)

如果已安裝 resolve MCP 伺服器(例如第三方的 barckley75/resolve-claude-mcp),它可以與 Resolve Studio 的腳本 API 通訊。如果 paper-edit 技能提供了 ensure_resolve.sh,請先執行它,以便在 Resolve 關閉時將其啟動。在 Preferences > System > General > External scripting using: Local 啟用的情況下,優先使用此方法而非匯出再匯入的繁瑣流程。

它會改變什麼:

  • 不需要匯出的剪輯。 讀取開啟時間軸的真實時間碼、影格率、起始時間碼和片段佈局,然後將疊加圖層錨定到這些資訊上。這解決了「每次重新修剪時間碼就會偏移」的問題。
  • 不需要手動匯入。 直接將渲染好的 .mov 片段放置到影片軌道上。
  • 更好的時刻選擇。 看到剪輯點的位置,意味著疊加圖層可以與剪輯協同而非對抗。
  • 它還可以在疊加圖層就緒後啟動渲染。

使用規則:

  1. 先讀取再寫入。 首先確認專案名稱、時間軸名稱、起始時間碼和影格率,並向使用者複述確認。
  2. 絕不寫入主時間軸。 先複製它,然後在副本上工作,這樣即使犯錯也毫無損失。
  3. 避免使用 execute_resolve_code,除非一般工具無法勝任。 它會針對使用者的專案執行任意 Python 程式碼。如果這是唯一的方法,請先顯示程式碼。
  4. 僅限本機工作階段。 Resolve 必須在這台 Mac 上執行,因此這在雲端或排程執行中永遠無法運作。在這種情況下,請回退到 FCPXML 路徑。
  5. FCPXML 路徑仍然有效且仍然是備案。 繼續產生兩個檔案;這只需要幾秒鐘。

音訊轉錄: 某些 Resolve MCP 伺服器附帶自己的 mlx-whisper 轉錄功能,但上述的 whisper.cpp 步驟已在此流程中得到驗證。

片段類型

以下所有內容在新影片中已不再使用(保留以便重新剪輯舊影片)。請使用下一節中的場景內類型。全螢幕類型會繪製一個純色墨水背景,帶有柔和的強調色光暈,因此它們會完全遮蓋講者。角落標籤位於左下角。

類型用途data
full-dots已廢棄,改用 dotslit、pct、count
full-flow已廢棄,改用 flowlabel、steps[]、good
full-compare已廢棄,改用 comparetitle、left{label,value,sub}、right{...,hi}、vs
full-bars已廢棄,改用 barstitle、bars[{label,value,value_label,hi}]
full-math已廢棄,改用 mathparts[](運算子 x = + → 以強調色渲染)、sub
full-pack已廢棄,改用 bars 或 sidename、note、size 0-1、hi
full-stat已廢棄,改用 pairlabel、value、sub、hi
full-title已廢棄,改用 pair 或 typetitle(允許 <br>)、size、sub
full-list已廢棄,改用 list2title、items[]、step 秒
chip已廢棄,改用 side 或 numnum、title、sub、hi
chip-stack已廢棄,改用 list2items[]

已廢棄的類型仍然可以渲染,用於重新剪輯舊影片。

場景內類型(預設)

不使用卡片,文字位於講者頭部旁的空間中,大型標題環繞頭部。

類型用途data
pair重點結論標題:頭部上方為外框線條,前額高度為實心線條top、bottom、outline(top/bottom)
side頭部旁邊的 2-3 行簡短文字,每行在其對應詞語出現時顯示lines[]、accent(索引,大號 + 強調色)、at[]
type隨著講者說出而逐詞出現的引言或問題words[{w,t,hi,br}]
define已廢棄:會使畫面變暗。改用 side 或 pairword、sub
num外框數字逐漸出現,旁邊有文字(例如「01 plan the week」)num、lines[]
list2在頭部左側和/或右側逐步建立的項目left[]、right[]、at[](按順序,先左後右)

場景內圖表(相同牆面位置和遮罩):

類型用途data
dots每 100 個中的比率,網格填充在講者旁邊lit、pct、count
flow流程,步驟由上而下串聯,最後一個使用強調色label、steps[]、at[](可選)
bars依大小排列的兩到三個數字title、bars[{label,value,value_label,hi}]
compare兩個選項,頭部兩側各一個left{label,value,sub}、right{...,hi}
math沿牆面閱讀的方程式,每行由運算子引導parts[]、sub

at 和 t 是從片段起始算起的秒數;根據單字時間碼建立它們,以便每一行都精準落在對應的詞語上。

這些需要 FOOTAGE=,即沒有疊加圖層的剪輯(從 Resolve 渲染時間軸,並停用疊加圖層片段)。渲染器會讀取每個片段的臉部框和背景亮度網格,以便文字找到空曠的牆面,如果文字超出畫面則翻轉側邊或縮小,並在淺色背景上使用深色文字,在深色背景上使用淺色文字。它會將講者從每個場景內片段(Apple Vision 人物分割、person.swift)的每個影格中遮罩出來,因此標題位於頭部後方,手部可以在圖形前方穿過。編譯一次:swiftc -O person.swift -o person。如果不提供 FOOTAGE,渲染器會回退到帶有黑色文字的全螢幕類型。

生命週期、資料格式和常見問題

重新渲染

再次使用完全相同的 clips.json 運行 render.mjs 是安全的——它會覆蓋輸出目錄中的 .mov 檔案,並重新產生 PLACEMENT.txt 和 .fcpxml 檔案。

要修剪或更改一個片段:在 clips.json 中更改物件,然後使用 ONLY= 僅運行那個片段。要刪除一個片段:從陣列中移除其物件並重新執行完整渲染。要重新排序:更改 id 字首的數字。id 的字母數字排序順序就是 FCPXML 中的匯入順序。

半途添加新類型:需要編輯 render.mjs 和相應的 .hbs 範本,然後重新運行。

data[].around 與經典 pair

"around": false 使 pair 回退到早期的置中雙行佈局。在 pair 上設定 "around": false 會使兩行置中,而不是環繞頭部分散。這對於非常寬的頭部或當頭部太靠近畫面邊緣時很有用,但提詞器文字同時佔據兩側仍然更好。

多個 pair 頭部

對於廣角鏡頭,person.swift 輸出第一個偵測到的臉部。如果講者身體右側有第二個人,他們的臉也會被偵測到但被忽略。對於兩個人的對話鏡頭,你無法同時環繞兩者——請求一個特寫鏡頭來補充,或者使用 full-* 類型。

遮罩故障

人物分割使用 VNGeneratePersonSegmentationRequest,它預測離散的遮罩。如果 person.swift 渲染出全白或全黑的遮罩,這通常是分割失敗——可能是因為鏡頭中長時間沒有人臉。如果你看到分割錯誤,請檢查原始影格:使用者可能正在螢幕分享、展示戴手套的手,或者鏡頭完全沒有人。

對於頭部側面或極度旋轉的頭部,遮罩有時會抖動。在哪些片段需要遮罩的材料處理中,這通常可以忽略,但如果你看到遮罩在語義上不正確,請輸出一個非 person 的對應版本,並手動疊加它。

對抗時間碼偏移

如果使用者說他們「裁剪了開頭一秒」,不要手動調整 clips.json 時間碼。所有時間碼都相對於檔案開始處。正確的做法是:重新渲染乾淨的剪輯,然後在 clips.json 上運行 render.mjs。裁剪會改變 ffprobe 的持續時間、轉錄時間戳以及乾淨剪輯的每個影格,因此需要重新渲染。唯一的捷徑:如果你有原始未裁剪剪輯的轉錄結果,你可以將其裁剪後的音訊與原始音訊進行交叉比對,然後重新對齊並更新 clips.json 中的 start 時間,但這僅在 .mov 仍然完美匹配且你願意手動重新對齊時才可行。對於一個被使用者多次裁剪的影片,這種做法會失敗得很慘。只要有可能,直接透過 MCP 在 Resolve 時間軸上操作。

Individual skills in this repo

This repo contains 7 individual skills — each has its own dedicated page.

beachyphotoandfilm-arch/video-skills

Sync camera footage to a separate lapel or field-recorder track (e.g. Tascam DR-10L and similar) and lay it up in DaVinci Resolve. Stitches the recorder's split files, finds each clip's exact place in the audio by matching words then waveforms, cuts one lapel slice per clip so every later skill works unchanged, checks for clipping, and builds a synced timeline in a new Resolve project. Trigger on "sync the lapel", "sync my audio", "line up the recorder", "I used a lav", or any shoot with a separate audio folder (live talks, events, workshops). Run it before paper-edit or video-reels.

beachyphotoandfilm-arch/video-skills

Turn raw talking-head footage into an assembled rough cut inside DaVinci Resolve. Pulls the clips off your footage drive, transcribes them locally, removes failed takes, restarts, asides and dead air, then creates a new Resolve project with two paper-edit timelines ready for your fine trim. Trigger on "paper edit", "cut my raw footage", "make a rough cut", "clean up this video", or when the user points at a folder of raw camera files for a YouTube video.

beachyphotoandfilm-arch/video-skills

Design a unique Instagram cover for each reel in your house style. Reads what the reel is about, writes a short hook headline, picks one of your own photos from a tagged photo library, lays it out like your existing covers, and proofs it in grid view at phone size. Renders locally, never with AI image generation. Can be called by a scheduling skill before reels are scheduled. Trigger on "make covers", "reel covers", "cover photo for this reel", "design the IG covers".

beachyphotoandfilm-arch/video-skills

Render finished reels out of DaVinci Resolve, write captions in the creator's voice, attach a custom Instagram cover from reel-covers, and schedule them to Instagram, TikTok and YouTube Shorts through Metricool. Handles the Drive upload hop, collision checks against the existing calendar, and cleanup. Trigger on "schedule the reels", "post these", "put these on the calendar", or after reels are approved.

beachyphotoandfilm-arch/video-skills

Cut vertical Instagram reels out of a long-form talking-head video, hook first. Picks the strongest standalone moments from the transcript, opens each reel on its punchiest line, builds vertical timelines in DaVinci Resolve framed on the speaker's face with the LUT applied, and finishes them: a hook (a held text card, or a word-by-word "build" hook with punch-in) and burned-look captions on V3; this-or-that reels get product graphics and a comment-keyword CTA card. You trim and render, nothing to import. Trigger on "make reels", "clip this for Instagram", "cut some verticals", or after a YouTube video is cut.

beachyphotoandfilm-arch/video-skills

Design YouTube thumbnails and titles for a talking-head video. Pulls graded full-res frames out of the raw footage, renders brand-styled variants in two proven layouts, and proofs them at phone size where the click actually gets decided. Trigger on "make thumbnails", "thumbnail for this video", "title and thumbnail", or after a video is cut.

beachyphotoandfilm-arch/video-skills

Run the whole YouTube video pipeline end to end, one stage at a time, stopping for the creator's approval at every gate. Paper edit, punch-ins, reels, reel covers, scheduling the reels, overlays, thumbnail and title, then scheduling the long-form video, all through Metricool. Keeps state per video so you can stop anywhere and pick up later. Trigger on "/youtube", "let's do the whole video", "run the video pipeline", "continue the <name> video", or when handed raw footage for a YouTube video.

相關技能