Distinct from reel-builder:
- reel-builder generates the video itself (T2V) + can optionally burn its own captions.
- This skill takes an EXISTING video as input. No generation.
This skill does NOT:
- Generate the video — the input is yours.
- Auto-transcribe audio to captions — requires Whisper, planned for a separate
transcribe skill (see ROADMAP).
- Translate captions between languages — pass already-translated subtitles.
- Re-encode video at different resolutions / formats beyond what ffmpeg's drawtext requires (output matches input resolution + codec where possible).
- Add audio (TTS overlay) — use
voiceover-maker for that.
- Mix multiple subtitle tracks — single track per run.
Requires ffmpeg on PATH. install.sh offers to install it; otherwise brew install ffmpeg (Mac) / apt-get install -y ffmpeg (Debian).
ROLE
Read the input video + subtitle source → parse cues (SRT / VTT / plain text) → call ffmpeg drawtext filter for each cue with chosen styling → save the subtitled video → print the path.
PIPELINE
Resolve input video:
<video> path — local MP4 / MOV / WebM.
- Must exist + be readable.
Resolve subtitle source:
--subtitle <file> — SRT / VTT / TXT file
--inline "<text>" — single caption applied to the entire video
- File extension determines parser (
.srt / .vtt / .txt)
Parse cues:
- SRT: standard subtitle format with
index → timecode → text blocks.
- VTT: WebVTT with
WEBVTT header.
- TXT: plain text, one cue per line, distributed evenly across the video duration (ffprobe used for duration detection).
- Inline: one cue starting at 0:00, ending at end-of-video.
Apply style preset — see references/ffmpeg-styling.md:
modern (default): white text, black 60% backplate, lower-third, 48pt
minimal: white text, no backplate, lower-third, 42pt
bold: yellow text, dense black backplate, larger 56pt
- Custom: override per-flag (
--font-size, --font-color, --box-color)
Burn via ffmpeg — calls common.runners.ffmpeg.burn_captions. drawtext filter sequence, re-encodes video, copies audio.
Output:
<video-dir>/<video-stem>-subtitled<ext>
or --output <path> for explicit destination.
MODES
Burn
subtitle-burner burn <video> --subtitle <file>
subtitle-burner burn <video> --inline "<single caption>"
subtitle-burner burn <video> --subtitle <file> --style modern|minimal|bold
subtitle-burner burn <video> --subtitle <file> --font-size 56 --font-color white
subtitle-burner burn <video> --subtitle <file> --output ./final.mp4
Preview (no burn)
subtitle-burner preview --subtitle <file>
subtitle-burner preview --subtitle <txt-file> --video <video> # txt requires video for timing
subtitle-burner preview --inline "<text>"
Prints the parsed cue list (index, start/end timestamps, text) without burning. Useful to verify timing before committing.
REFERENCES (load on demand)
| File |
When to load |
| references/subtitle-formats.md |
SRT vs. VTT vs. plain-text — when to use which, format specifics, parsing edge cases |
| references/ffmpeg-styling.md |
Style presets + per-flag customization, font selection, multilingual glyph support |
| references/troubleshoot.md |
When captions don't render, font missing, sync drift, etc. |
EXAMPLES
See examples/before-after.md — 3 calibration runs: burn an SRT onto a TikTok export, plain-text captions distributed across a 30s reel, single inline caption for an entire 5s clip.
CONSTRAINTS
ffmpeg required. No API calls; the skill is a pure ffmpeg wrapper. install.sh detects + offers install at setup time.
Subtitle source parsing is strict. SRT must have valid timecodes (HH:MM:SS,mmm); VTT must have WEBVTT header; TXT must have ≥1 non-empty line.
Plain text is distributed evenly. N lines across the video duration. Works for short videos with clear logical breaks; less ideal for narrative content where timing must match audio cues. For audio-synced captions, use a real subtitle tool (Whisper / Premiere / DaVinci) to produce SRT first.
Output preserves video codec where possible. ffmpeg's drawtext requires re-encoding the video stream, so the output IS re-encoded (audio is copied as-is). For large files this can take seconds-to-minutes depending on duration.
Default font may lack non-Latin glyphs. Cyrillic / CJK / Arabic captions may render as boxes on systems with only Latin-only default fonts. Workaround: specify --font /path/to/font-with-coverage.ttf (currently planned — set FFMPEG_CAPTION_FONT env var as a workaround in v1).
Style presets are starting points. Most users want some tweak. The CLI accepts per-flag override (font-size, font-color, box-color).
Position is lower-third by default. Hardcoded in ffmpeg.py:burn_captions. To change position: edit the drawtext filter in common/runners/ffmpeg.py directly (or PR a --position flag).
Single text track per run. For multiple tracks (e.g., translation overlay + original): run twice, second time using the output of the first as input.
No subtitle file is generated. Captions are burned INTO the video pixels — not soft-subtitles you can toggle off in a player. For toggleable subtitles, embed as a separate track via ffmpeg's -c:s mov_text (not handled by this skill).
Never modifies the input file. Always writes to a new file (<video>-subtitled<ext> or --output).
INVOCATION HINTS
When the user says any of:
- "add subtitles to my video", "burn captions onto this MP4"
- "subtitle my reel", "caption this video"
- "make the captions yellow and bold" (style customization)
- "I have an SRT file, apply it to this video"
- "добавь субтитры к видео", "вшей субтитры"
- "сделай надписи на видео"
Defaults: burn <video> --subtitle <file> --style modern. If only --inline text is given (no file), default to single-caption-across-whole-video.
If the user mentions a STYLE preference ("bold yellow" → --style bold; "minimal no background" → --style minimal; default "modern with black backplate"):
If the user mentions an SRT/VTT file → use --subtitle <file>.
If the user mentions plain text (no file) AND a short list → use --inline for single caption OR write the text to a temp file and use it as --subtitle <tmp>.txt.
This skill is distinct from:
reel-builder — that GENERATES video + can burn captions inline. This is for existing video.
voiceover-maker — that generates audio. This burns visual captions.
subtitle-translator (planned, see ROADMAP) — translation; this is rendering.
1---2name: subtitle-burner3description: Burn captions / subtitles onto a video via ffmpeg. Supports SRT, WebVTT, plain text. Presets: modern (white on black lower-third), minimal, bold (yellow, denser). Subcommands: burn, preview. Pure ffmpeg. Use when: 'add subtitles to my video', 'burn captions onto this MP4', 'subtitle my reel', 'добавь субтитры к видео', 'жёстко вшей субтитры'.4license: MIT5---67<objective>8Burn captions onto an existing video file. The user has a video (their own recording, a downloaded clip, output from `reel-builder`) and either has a subtitle file (SRT / VTT) OR wants plain text distributed across the video timeline.910Distinct from `reel-builder`:11- reel-builder generates the video itself (T2V) + can optionally burn its own captions.12- This skill takes an EXISTING video as input. No generation.1314This skill does NOT:15- Generate the video — the input is yours.16- Auto-transcribe audio to captions — requires Whisper, planned for a separate `transcribe` skill (see ROADMAP).17- Translate captions between languages — pass already-translated subtitles.18- Re-encode video at different resolutions / formats beyond what ffmpeg's drawtext requires (output matches input resolution + codec where possible).19- Add audio (TTS overlay) — use `voiceover-maker` for that.20- Mix multiple subtitle tracks — single track per run.2122Requires `ffmpeg` on PATH. install.sh offers to install it; otherwise `brew install ffmpeg` (Mac) / `apt-get install -y ffmpeg` (Debian).23</objective>2425## ROLE2627Read the input video + subtitle source → parse cues (SRT / VTT / plain text) → call ffmpeg drawtext filter for each cue with chosen styling → save the subtitled video → print the path.2829## PIPELINE30311. **Resolve input video**:32 - `<video>` path — local MP4 / MOV / WebM.33 - Must exist + be readable.34352. **Resolve subtitle source**:36 - `--subtitle <file>` — SRT / VTT / TXT file37 - `--inline "<text>"` — single caption applied to the entire video38 - File extension determines parser (`.srt` / `.vtt` / `.txt`)39403. **Parse cues**:41 - SRT: standard subtitle format with `index → timecode → text` blocks.42 - VTT: WebVTT with `WEBVTT` header.43 - TXT: plain text, one cue per line, distributed evenly across the video duration (ffprobe used for duration detection).44 - Inline: one cue starting at 0:00, ending at end-of-video.45464. **Apply style preset** — see `references/ffmpeg-styling.md`:47 - `modern` (default): white text, black 60% backplate, lower-third, 48pt48 - `minimal`: white text, no backplate, lower-third, 42pt49 - `bold`: yellow text, dense black backplate, larger 56pt50 - Custom: override per-flag (`--font-size`, `--font-color`, `--box-color`)51525. **Burn via ffmpeg** — calls `common.runners.ffmpeg.burn_captions`. drawtext filter sequence, re-encodes video, copies audio.53546. **Output**:55 ```56 <video-dir>/<video-stem>-subtitled<ext>57 ```58 or `--output <path>` for explicit destination.5960## MODES6162### Burn6364```65subtitle-burner burn <video> --subtitle <file>66subtitle-burner burn <video> --inline "<single caption>"67subtitle-burner burn <video> --subtitle <file> --style modern|minimal|bold68subtitle-burner burn <video> --subtitle <file> --font-size 56 --font-color white69subtitle-burner burn <video> --subtitle <file> --output ./final.mp470```7172### Preview (no burn)7374```75subtitle-burner preview --subtitle <file>76subtitle-burner preview --subtitle <txt-file> --video <video> # txt requires video for timing77subtitle-burner preview --inline "<text>"78```7980Prints the parsed cue list (index, start/end timestamps, text) without burning. Useful to verify timing before committing.8182## REFERENCES (load on demand)8384| File | When to load |85|---|---|86| [references/subtitle-formats.md](references/subtitle-formats.md) | SRT vs. VTT vs. plain-text — when to use which, format specifics, parsing edge cases |87| [references/ffmpeg-styling.md](references/ffmpeg-styling.md) | Style presets + per-flag customization, font selection, multilingual glyph support |88| [references/troubleshoot.md](references/troubleshoot.md) | When captions don't render, font missing, sync drift, etc. |8990## EXAMPLES9192See [examples/before-after.md](examples/before-after.md) — 3 calibration runs: burn an SRT onto a TikTok export, plain-text captions distributed across a 30s reel, single inline caption for an entire 5s clip.9394## CONSTRAINTS9596- **ffmpeg required.** No API calls; the skill is a pure ffmpeg wrapper. install.sh detects + offers install at setup time.9798- **Subtitle source parsing is strict.** SRT must have valid timecodes (HH:MM:SS,mmm); VTT must have `WEBVTT` header; TXT must have ≥1 non-empty line.99100- **Plain text is distributed evenly.** N lines across the video duration. Works for short videos with clear logical breaks; less ideal for narrative content where timing must match audio cues. For audio-synced captions, use a real subtitle tool (Whisper / Premiere / DaVinci) to produce SRT first.101102- **Output preserves video codec where possible.** ffmpeg's drawtext requires re-encoding the video stream, so the output IS re-encoded (audio is copied as-is). For large files this can take seconds-to-minutes depending on duration.103104- **Default font may lack non-Latin glyphs.** Cyrillic / CJK / Arabic captions may render as boxes on systems with only Latin-only default fonts. Workaround: specify `--font /path/to/font-with-coverage.ttf` (currently planned — set `FFMPEG_CAPTION_FONT` env var as a workaround in v1).105106- **Style presets are starting points.** Most users want some tweak. The CLI accepts per-flag override (font-size, font-color, box-color).107108- **Position is lower-third by default.** Hardcoded in `ffmpeg.py:burn_captions`. To change position: edit the drawtext filter in `common/runners/ffmpeg.py` directly (or PR a `--position` flag).109110- **Single text track per run.** For multiple tracks (e.g., translation overlay + original): run twice, second time using the output of the first as input.111112- **No subtitle file is generated.** Captions are burned INTO the video pixels — not soft-subtitles you can toggle off in a player. For toggleable subtitles, embed as a separate track via ffmpeg's `-c:s mov_text` (not handled by this skill).113114- **Never modifies the input file.** Always writes to a new file (`<video>-subtitled<ext>` or `--output`).115116## INVOCATION HINTS117118When the user says any of:119120- "add subtitles to my video", "burn captions onto this MP4"121- "subtitle my reel", "caption this video"122- "make the captions yellow and bold" (style customization)123- "I have an SRT file, apply it to this video"124- "добавь субтитры к видео", "вшей субтитры"125- "сделай надписи на видео"126127Defaults: `burn <video> --subtitle <file> --style modern`. If only `--inline` text is given (no file), default to single-caption-across-whole-video.128129If the user mentions a STYLE preference ("bold yellow" → `--style bold`; "minimal no background" → `--style minimal`; default "modern with black backplate"):130131If the user mentions an SRT/VTT file → use `--subtitle <file>`.132133If the user mentions plain text (no file) AND a short list → use `--inline` for single caption OR write the text to a temp file and use it as `--subtitle <tmp>.txt`.134135This skill is distinct from:136- `reel-builder` — that GENERATES video + can burn captions inline. This is for existing video.137- `voiceover-maker` — that generates audio. This burns visual captions.138- `subtitle-translator` (planned, see ROADMAP) — translation; this is rendering.