| name | style-captions |
| description | design and render caption styles for video outputs. supports six named presets from caption-style-presets.json (bold-tiktok-hook, serif-wellness, handwritten-educator, mono-proof, pinned-comment-card, platform-default) as well as free-form ASS generation and caption PNG rendering. use when a video pipeline needs styled ASS subtitles, title-card PNGs, or captioned overlays. |
style-captions
Purpose
Design caption styles and render caption overlay variants for video outputs.
Supports two output paths:
- ASS subtitle file —
scripts/make_subtitles.py generates a .ass file from word timestamps (JSON) with karaoke-style word highlighting. Pass --preset <id> to load a named editorial style from references/caption-style-presets.json.
- Caption PNG —
scripts/make_caption_pngs.py renders rounded-pill caption images (used for music-only or silent-demo title cards).
- Loading dots PNG sequence —
scripts/make_loading_dots.py renders a 5-frame dots animation.
Named caption presets align with CREATOR_GRAMMAR.md §7 and the source of truth JSON at references/caption-style-presets.json:
| Preset ID | Label | Look | Position | Animation |
|---|
bold-tiktok-hook | Bold TikTok hook | Heavy Montserrat, white, large black stroke | upper-third | static-sentence |
serif-wellness | Serif wellness | Cormorant Garamond medium, white, soft stroke | upper-third | static-sentence |
handwritten-educator | Handwritten educator | Caveat bold, lowercase, white | upper-left | word-pop |
mono-proof | Monospace proof | JetBrains Mono on dark plate, light green | center | static-sentence |
pinned-comment-card | Pinned comment card | Inter semibold, dark text on white card | upper-third | static-sentence |
platform-default | Platform default | Inter bold, white, black stroke, lower-center | lower-center | karaoke-pop |
Inputs
make_subtitles.py
make_subtitles.py <words.json> <output.ass> [--accent-bgr=<BGR_HEX>] [--preset <id>]
words.json — {"words": [{"text": "Hello", "start": 0.0, "end": 0.4}, ...]}
output.ass — destination path for the generated ASS file.
--preset <id> (optional) — one of the six preset IDs above. Loads font/size/position/color from caption-style-presets.json. When omitted, the original Avenir Next karaoke style is used (backward-compatible).
--accent-bgr <BGR> (optional) — brand accent color in BGR hex; overrides the preset's fill_color. Default: 4D9AC1 (gold).
--list-presets — print available preset IDs and exit.
make_caption_pngs.py
Standalone script — run directly. Outputs PNG caption pills to edits/. Edit the render_text_only / render_with_emoji calls at the bottom to customize text.
make_loading_dots.py
Standalone script — outputs 5 dots_N.png frames to edits/loading_dots/.
Workflow
- Determine output type: ASS subtitle (VO/speech formats) or PNG title card (music-only / silent demo).
- Select preset or use defaults:
- If a named preset is requested, pass
--preset <id> to make_subtitles.py. The script loads references/caption-style-presets.json, resolves font/size/position/color, and writes a correctly-styled ASS file.
- If no preset is needed, omit
--preset — the script behaves exactly as before (Avenir Next, karaoke, lower-center).
- Run the appropriate script:
python3 scripts/make_subtitles.py words.json out.ass [--preset <id>] [--accent-bgr <BGR>]
python3 scripts/make_caption_pngs.py
- Validate output: for ASS files, open in a viewer or check that
[V4+ Styles] and [Events] sections are present. For PNGs, verify the file is non-empty and readable.
- Save outputs under the requested output folder or
skills/test-runs/<timestamp>/style-captions/ during tests.
- Write or update a
manifest.json with status, preset used, font, outputs, and any warnings.
Preset → ASS style mapping
The script maps preset fields to ASS Style parameters as follows:
| Preset field | ASS field |
|---|
font_family | Fontname |
font_size_pct × 1280 | Fontsize (pt) |
fill_color | PrimaryColour (highlight sweep) |
stroke_color / stroke_width_px | OutlineColour / Outline |
background = plate/card + background_color + background_opacity | BackColour + BorderStyle 3 |
position | Alignment + MarginV |
font_weight semibold/bold/extrabold | Bold = -1 |
Output
.ass subtitle file (from make_subtitles.py).
- Caption PNG(s) (from
make_caption_pngs.py).
- Loading dots PNG sequence (from
make_loading_dots.py).
manifest.json for executable runs.
verification.md or a short verification summary naming the checks performed.
Quality Checks
- ASS file contains
[V4+ Styles] and [Events] sections.
- Font name in ASS matches the preset's
font_family (or fallback).
- Alignment and MarginV values match the preset
position.
- Phrase timing: no overlapping dialogue events (each end ≤ next start - 0.02s).
- PNG outputs are non-zero size and loadable by Pillow/Preview.
- No ffmpeg/Pillow errors in stderr.
Failure Modes
references/caption-style-presets.json missing → --preset flag exits with error listing available IDs (empty if JSON not found). No-preset invocations are unaffected.
- Unknown preset ID → error message listing valid IDs; exit 1.
- Font not installed on the system → ASS Fontname is written correctly but the player/renderer falls back. The script does not validate font availability.
words.json missing or malformed → json.JSONDecodeError or KeyError; fix the input file.
- Pillow not installed →
make_caption_pngs.py fails; install with pip install Pillow.
requests not installed → make_caption_pngs.py emoji path fails; install with pip install requests.