Communitygithub.com

businessbaum/vedit - 字幕生成與燒錄

此技能在用戶要求生成字幕或畫面文字時使用 - 涵蓋 ASS 字幕生成、德文字幕的像素寬度分組規則、字體表,以及透過 libass 進行字幕燒錄。

vedit - 字幕生成與燒錄 是什麼?

此技能用於自動生成 ASS 格式的字幕檔案,並將其燒錄到影片中。它專為德語設計,因為德語複合名詞(如 "Geschwindigkeitsbegrenzung")會超出傳統的字符數限制,因此採用像素寬度預算分組規則,而非簡單的 `max_chars` 限制。技能支援多種平台(如垂直短影音與 YouTube 長片),並提供不同的預設配置。其運作流程包括:選擇預設、生成 ASS 檔案、修正字幕文字(透過 `captions.overrides`,切勿修改原始轉錄稿)、最終透過 ffmpeg 燒錄字幕,並進行嚴格的字體載入驗證,以避免 libass 回退使用預設字體。技能也詳細說明了常見的失敗模式及其解決方案,如字體未正確載入、格式行錯誤、以及跨片段燒錄導致的字幕不同步問題。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/businessbaum/vedit/tree/HEAD/.agents/skills/captions

在你喜歡的 AI 中提問

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

說明文件


name: captions description: 此技能在用戶要求生成字幕或畫面文字時使用 - "brenn die Untertitel ein", "mach Untertitel", "Untertitel drauf", "leg Untertitel drüber", "brenn die Subs ein", "mach die Captions", "Wort für Wort Untertitel", "Karaoke-Untertitel", "korrigier den Untertitel-Text", "burn in the captions", "add subtitles", "burn the subs", "word-by-word captions", "fix a caption typo"。涵蓋 ASS 生成、德文的像素寬度分組規則、字體表,以及透過 libass 進行字幕燒錄。 argument-hint: [專案代碼] [預設名稱] arguments: [project, preset]

captions

根據逐字轉錄稿生成 ASS 字幕檔案,並將其燒錄到渲染輸出中。 參數:$project 專案代碼,$preset 來自 presets/captions/*.json 的預設名稱。完整的請求內容在 $ARGUMENTS 中。空的 $ 佔位符表示技能是自動觸發而非透過斜線指令呼叫:此時應從工作階段的 PIPELINE_STATE 中取得專案,並告知你選擇了哪一個。動詞名稱遵循建置合約;以 python engine/ve.py --help 為最終準則。

兩個決定此功能是否正常運作的德文特定規則

1. 切勿使用 max_chars 進行分組

德語複合名詞是無法分割的單一詞元,會超出任何字符數限制。 Geschwindigkeitsbegrenzung 有 26 個字符,在 1920 幀寬度、90 px 字體大小下約佔 60% 的寬度。max_chars: 22 的規則無法拆分它,導致它要麼超出畫面邊框,要麼分組器默默地產生一個它承諾不產生的行。

應改為依據 像素寬度預算 進行分組,並對單獨超過預算的單詞設置自動縮小規則。estimate_text_width_px() 負責測量;group_words() 負責預算分配。詳細資訊位於 docs/fonts.md 和 engine/vedit/captions.py 的模組文件字串中。

這是德文字幕最常見的錯誤,且完全是可以避免的。

2. 字體必須是靜態的單一粗細檔案,並以其精確的 nameID 1 命名

可變字體無法在 ASS 中選擇粗細。InterVariable.ttf 透過 libass 渲染時,其位元組與 Arial 完全一致 - 擁有相同的 md5 - 同時只記錄它載入了該檔案。 退出碼為 0,沒有任何警告。Style: D,Inter,...,Bold=-1 會讓你得到 DirectWrite 的 Arial,在輸出檔上傳到 YouTube 之前沒有人會注意到。

僅使用下列字體,並使用精確的 Fontname 字串和 Bold 值:

檔案ASS FontnameBold
Inter-Regular.ttfInter0
Inter-Bold.ttfInter-1
Inter-SemiBold.ttfInter SemiBold0
Inter-ExtraBold.ttfInter ExtraBold0
Montserrat-Bold.ttfMontserrat-1
Montserrat-ExtraBold.ttfMontserrat ExtraBold0

assets/fonts/ 目錄僅應包含字體檔案。 libass 會載入在其中找到的每個檔案,並對任何其他檔案報錯 - 一個多餘的 README.md 會產生 Error opening memory font 'README.md' 錯誤。 基於這個原因,該目錄在設定中屬於 ask 權限;如果文檔需要與字體放在一起,應放在 docs/fonts.md 中。

步驟 1 - 選擇預設

presets/captions/*.json 包含樣式、分組預算、位置和高亮行為。 根據 output.platform 選擇,而不是個人喜好:

  • 垂直平台需要大尺寸、置中、1-3 個單詞,並位於安全區域的高處 - 底部三分之一被平台自身 UI 佔據。
  • YouTube 長片需要兩行、底部錨定,尺寸需讓手機用戶能閱讀。

在生成前向用戶確認選擇,並說明哪些內容會變更。

步驟 2 - 生成 ASS 檔案

python engine/ve.py captions $project --preset $preset

兩個結構性要求,違反時都會默默失敗:

  • 23 欄位的 V4+ Style: Format: 行(從 Name 到 Encoding,libass 自己的欄位列表 - 第 24 個欄位 AlphaLevel 是 SSA v4,而非 ASS V4+)以及 10 欄位的 Events Format: 行必須是標準的,並且各自下方的資料行必須有完全相同的欄位數量。欄位數量不匹配會導致 libass 以退出碼 0 結束,在渲染的文字前方插入一個多餘的逗號,並默默地移除輪廓和粗體效果。 已透過 5 欄位的 Format 對應 6 欄位的 Dialogue 重現此問題。captions.validate_ass() 在任何燒錄前會檢查這兩個計數;它不可省略,且 burn_in() 在檢查失敗時會拒絕執行。
  • 檔案必須是 UTF-8 編碼。在該編碼下,德語變音符號可以透過 libass 正確地來回轉換 - Größe Straße Übermäßig äöüÄÖÜß 已透過端到端測試驗證。

側車檔案寫入 projects/<slug>/out/captions.ass,並從 captions.sidecar_path 引用。

時間碼來自與剪輯相同的詞彙列表,並透過 _computed 中的時間軸位置進行映射。因此,任何剪輯變更都會導致字幕失效 - 請在重新剪輯後重新生成,而非手動修補時間碼。

步驟 3 - 修正文字,而非轉錄稿

數字是可預測的問題。轉錄時必須使用 --suppress_numerals,因此當說話者說「20」時,轉錄稿會是「zwanzig」。應在 captions.overrides[] 中將其修正為 {word_index, text},切勿透過編輯轉錄稿來修正 - 轉錄稿是專案中所有詞彙範圍的錨點,重寫它會導致剪輯不同步。

專有名詞、產品名稱和「GmbH」風格的縮寫也應如此處理。透過掃描低 score 詞彙一次性收集它們:對齊分數作為填充詞信號用處不大,但它是「對齊器不確定這個詞是什麼」的良好信號,這正是一個專有名詞的特徵。

步驟 4 - 燒錄字幕

python engine/ve.py render $project

字幕燒錄在最終的封裝階段進行,只做一次,作用於拼接後的完整影片 - 絕對不在每個片段單獨燒錄。逐片段燒錄會在每個拼接點重新渲染相同的字幕,導致剪輯兩側出現不完整的行。

subtitles= 和 fontsdir= 的跳脫方式是精確且不直觀的。處處使用正斜線,並且數值需要用帶有單一跳脫磁碟冒號的引號括起來:

subtitles='C\:/Users/me/.../out/captions.ass':fontsdir='C\:/Users/me/.../assets/fonts'

vedit/ffmpeg.py 中的 escape_filter_path() 負責此轉義並返回包含其引號的字串 - 請勿自行添加引號。決定成敗的是引號,而不是巢狀深度:裸的單一跳脫形式會產生 No option name near '/Users/...' 錯誤,只有帶引號的形式才能在路徑中包含逗號、分號或括號時正常工作,這些字元在 Windows 上都是合法的。 escape_filter_path_nested() 為需要的人返回雙重反斜槓、不帶引號的 C\\:/... 變體,並記錄了該限制。

所有這些都通過 Python 的 argv 列表傳遞。同樣的路徑在 Git Bash 中建置會變成 C\;C:\Program Files\Git\Users\... - 這是現場重現的,而非理論假設。

設定 captions.enabled 和 captions.burn_in,並將 stage 設置為 "captions"。

步驟 5 - 證明字體已正確載入

QC 檢查 (e) 是強制的,這是捕捉靜默回退的唯一方法。 使用專案樣式渲染一個字幕幀,並使用 Arial 對照樣式渲染另一個幀,然後斷言兩者的雜湊值不同。相同的雜湊值意味著 libass 已回退,輸出將使用錯誤的字體。

然後也確認:Format: 行的欄位計數、沒有行超出像素預算、以及沒有字幕跨越片段邊界而留下殘片。

失敗模式

症狀原因修正方法
字幕看起來像 Arial可變字體,或錯誤的 Fontname使用靜態檔案 + 精確的 nameID 1 字串;執行 QC (e)
文字中出現多餘逗號,無輪廓錯誤的 Format: 行輸出標準的 24/10 欄位行
Error opening memory font 'README.md'assets/fonts/ 中有非字體檔案該目錄僅放字體
一個長單詞超出畫面邊框使用 max_chars 分組使用像素寬度預算加上單詞自動縮小
No option name near '/Users/...'fontsdir 使用了單一跳脫在冒號前使用雙反斜槓
字幕拼寫出數字--suppress_numerals,為設計行為在 captions.overrides 中新增條目
重新剪輯後字幕不同步舊的 ASS 檔案重新生成;切勿手動修補時間碼

Individual skills in this repo

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

businessbaum/vedit

This skill should be used when the user asks for mechanical tightening of material that is already selected - "mach den Rohschnitt", "bau den Rohschnitt", "schneid die Ähms raus", "nimm die Füllwörter raus", "entferne die Pausen", "kürz die Pausen", "schneid die Versprecher raus", "mach den Radioschnitt", "straff das", "build the rough cut", "cut the fillers", "remove the ums", "tighten the pauses", "trim the dead air", "cut the retakes", "radio edit". Turns kept story blocks into enabled segments in project.json. Does not decide what the video is about - that is cut-story.

businessbaum/vedit

This skill should be used when the user asks to decide what the video is actually about before any mechanical cutting - "bau die Story", "was soll ins Video", "was kann raus", "welche Themen bleiben", "kürz das auf 6 Minuten", "mach daraus ein kurzes Video", "wo ist der Hook", "sortier die Themen", "worum geht es hier eigentlich", "build the story", "decide what stays", "structure this", "cut this down to N minutes", "find the hook", "reorder the topics". This is the CONTENT-selection pass that writes the "story" block in project.json; it runs after transcribe and before cut-rough.

businessbaum/vedit

This skill should be used when the user asks for the finished video file - "exportier das", "render das fertig", "mach das final", "renderte das Video", "mach den Endexport", "bau das Video zusammen", "mach es fertig für YouTube", "gib mir die MP4", "export the final", "render the final cut", "make the master", "export for TikTok", "give me the mp4". Covers segment rendering with the cache, guarded concat, the one-pass audio, loudness normalisation and the single mux.

businessbaum/vedit

This skill should be used when the user asks for an on-screen graphic, title or overlay - "bau eine Bauchbinde", "mach ein Lower Third", "blend meinen Namen ein", "mach eine Titelkarte", "setz einen Text drüber", "brauch eine Grafik dazu", "zeig da eine Zahl an", "mach ein Intro-Insert", "build a lower third", "add a title card", "put a graphic over this", "overlay some text", "animate this number". Covers the HTML template contract, Chrome headless frame rendering, alpha-preserving movie encoding, and the overlays block in project.json.

相關技能