---
name: captions-pro
description: Word-by-word animated captions burned into a video, TikTok / Reels / Shorts style - highlight (active word on an accent box), karaoke (spoken words fill with colour), pop, bounce (one big word), typewriter and minimal - from word timings, an ASS karaoke file, an SRT or a script. Also writes an .ass karaoke file and a word-timing JSON for editors, and a preview sheet before export. Use when the user wants viral-style captions, animated subtitles, karaoke text, Hormozi / MrBeast-style word highlights, or styled captions in a brand font on a Kenerate video.
compatibility: Python 3.9+ with Pillow and ffmpeg. The Kenerate MCP server for speech, avatars and add_subtitles.
metadata:
  author: kenerate
  version: "1.1"
  kenerate-tools: "add_subtitles generate_speech talking_avatar generate_video wait_for_generation"
---

# Captions pro (animated word-by-word captions)

`scripts/captions.py` renders the captions locally (only the frames that change) and burns them in. Rules:
[references/KENERATE.md](references/KENERATE.md) (models and voices: [references/MODELS.md](references/MODELS.md), or the free `pick_model` / `pick_voice` tools).

## When to use / not to use
- Use: "add captions like TikTok", "highlight each word", "karaoke subtitles", "captions in Bebas Neue".
- Not for: plain subtitles on a long video (use `video-editing --srt`), or Kenerate's own captions (`add_subtitles`,
  speech only, up to 4 min, needs the video online).

## Ask the user
1. The video (Kenerate url or file) and the words: an SRT / VTT, an ASS with `{\k}` tags, word timings (JSON), or
   the script. Exact word timings give the best sync; an SRT gives per-cue sync with estimated words.
2. Style (show the preview first), words on screen (2-3 for 9:16, 4-5 for 16:9), position, accent colour, font.
   A named font: `--font-family "Montserrat" --font-weight 800` (downloads a free OFL font once into ./fonts and
   records the licence) or a brand file with `--font`.

## 1. Timing source
- Word JSON: `[{"word","start","end"}]`, Whisper-style segments with `words`, or an ElevenLabs alignment object
  (`characters`, `character_start_times_seconds`, ...). Pass with `--words-json`.
- No captions yet and the clip has speech: ask whether to transcribe with a tool the user has, or use the script the
  voice was made from (`--text`, timed roughly) - the script then warns that timing is estimated. Never invent words.
- Voice-over made with `generate_speech`: the script text is the caption text.

## 2. Preview (free, fast)
```
python <skill-dir>/scripts/captions.py --video "<url>" --srt talk.srt --style highlight \
  --accent "#FFD60A" --max-words 3 --position lower --font-family "Montserrat" --font-weight 800 --preview-only
```
Show `*_preview.jpg` (six moments with the captions composited). Adjust `--size`, `--position`, `--offset` (sync),
style, then export.

## 3. Export
Same command without `--preview-only`. Output: `captioned.mp4` (audio untouched), `captioned.ass` (karaoke ASS for
editors / players), `captioned_words.json`, and a preview sheet taken from the burned file.
Styles: `highlight`, `karaoke`, `pop`, `bounce`, `typewriter`, `minimal`. `--keep-case` keeps the original casing.

## Progress and output
Steps: fetch → word timing (says how exact) → render overlays (percent per caption page) → burn in. Relay them.

## If something fails
"No words inside the video's time range" → the SRT belongs to another cut or needs `--offset`. Text too long for a
line shrinks automatically; long words in 9:16 read better with `--max-words 2`.

## Limits
Left-to-right scripts. Emoji are drawn only if the font has them. Rendering a 60 s 1080x1920 video takes about a minute.
