SuperAPI AI Directory

burn-in-captions

Design & creation

View repository

Updated 10-15 21:54

About this skill

/burn-in-captions

Turns a raw clip into a captioned clip in a deterministic house style. Six presets, all driven from one word-level transcript.

Styles

preset look renderer status
frosted-subtle translucent dark pill, white active word + dim upcoming ASS ✅ shipped (default)
karaoke-fill bold all-caps, outline ghost fills word-by-word ASS ✅ shipped
kinetic-pop short 1-3 word chunks scale-pop in, accent color on the punch word ASS ✅ shipped
word-flash one big bold white word per beat, snaps in ASS ✅ shipped
bold-accent heavy white sans + lime bold-italic accent word, stacked two-tier ASS ✅ shipped
serif-accent elegant serif, white + gold italic accent word, stacked two-tier ASS ✅ shipped
clean-minimal minimal clean white caption, fade-in, with a faint serif ghost-echo word ASS ✅ shipped
neon-glow bold all-caps karaoke, white active / lavender upcoming, purple neon glow ASS ✅ shipped
clean-bubble light rounded pill, heavy text, per-word dark active / grey upcoming ASS ✅ shipped
clean-white plain static white text, no background — fallback / subtitle look ASS ✅ shipped
energy-pop light pill, heavy text, per-word dark active / grey upcoming, scale-pops in ASS ✅ shipped
neon-pop one big all-caps word per beat, accent on emphasis ASS ⏳ planned (template not built)
keyword-pill phrase line + brand-colored pill on the active word Remotion ⏳ planned (comp not built)
impact-italic italic condensed all-caps, stacked-echo gradient Remotion ⏳ planned (comp not built)

Default: frosted-subtle.

The "karaoke / kinetic" family — kinetic-pop, word-flash, bold-accent, serif-accent, clean-minimal, neon-glow, clean-bubble, energy-pop — are dynamic, fast-paced caption styles recreated from real reference videos. Each has a documented visual spec in references/caption-styles.md (font, color, animation, layout, and which reference it was modelled on). Pick any of them with --style.

Any planned style raises FileNotFoundError: missing template. Templates live in templates/ (one <style>.ass.jinja per ASS style); a body builder in scripts/ass_render.py and a preset in scripts/cue_builder.py complete the wiring. See references/caption-styles.md for how to add a style.

Accent color

--accent "#RRGGBB" overrides a style's accent color. If omitted, each style falls back to its signature color (declared in its cue_builder preset — e.g. bold-accent → lime #CBFD23, serif-accent → gold #FFF300, kinetic-pop → teal #20E0C8). --emphasis word1,word2 forces specific punch words for the styles that color one word per cue.

When to use

  • "caption this clip", "add subtitles to this video", "burn captions in"
  • "make karaoke captions", "make TikTok-style captions"
  • Any video deliverable that needs lower-third word-synced text

Pipeline (every invocation)

  1. Transcribe — scripts/transcribe.py extracts mono 16 kHz audio with ffmpeg, uploads to fal.ai (fal-ai/whisper with chunk_level: "word"), and writes words.json (canonical) plus .srt and .ass sidecars next to the source. 1b. Brand-name guard — Whisper transcribes phonetically and reliably mis-spells unusual brand names as common-word homophones (Bristle → Bristol, Klarify → Clarify). Pass --word-fix "Bristol:Bristle,Bristol's:Bristle's" to apply exact-match corrections to the transcript before cue-building; the fix is persisted back to words.json so a later re-run (without --force) keeps it. If you discover the error only after the burn, edit the word in words.json by hand and re-run without --force so the corrected transcript is reused, not overwritten by a re-transcribe.
  2. Build cues — scripts/cue_builder.py groups words per the style's words_per_cue and splits on long pauses; picks emphasis words (heuristic: longest non-stopword in each cue, or user override).
  3. Render — based on the preset's renderer:
    • ASS path: scripts/ass_render.py fills templates/<style>.ass.jinja and burns with ffmpeg -vf "ass=captions.ass:fontsdir=fonts/".
    • Remotion path: scripts/remotion_render.py writes remotion/src/cues.json and runs npx remotion render against the style's composition; the Remotion comp imports the source video and overlays captions in React.
  4. Sidecars — every run leaves words.json, captions.srt, captions.ass next to the output. The user gets soft subs for free even if they only asked for burn-in.
  5. Storyboard — if --storyboard (default on for multi-style runs), write storyboard.html with <video> tags for source + each rendered style. Layout matches gooseworks-ads/video-06-raise-a-goose/storyboard-clips-20s.html.

Usage

# Default (frosted-subtle, lowest-risk style)
python3 .claude/skills/burn-in-captions/scripts/caption.py \
    --video path/to/clip.mp4

# Kinetic creator-native captions with a brand accent color
python3 .claude/skills/burn-in-captions/scripts/caption.py \
    --video path/to/clip.mp4 \
    --style kinetic-pop --accent "#20E0C8" --emphasis "perplexity,nvidia"

# Render multiple styles in one pass (drives the storyboard preview)
python3 .claude/skills/burn-in-captions/scripts/caption.py \
    --video path/to/clip.mp4 \
    --style frosted-subtle,karaoke-fill,clean-bubble

# Correct a brand name Whisper mis-hears (homophone)
python3 .claude/skills/burn-in-captions/scripts/caption.py \
    --video path/to/clip.mp4 --style energy-pop \
    --word-fix "Bristol:Bristle,Bristol's:Bristle's"

Output layout

<source-dir>/<clip>.captions/
├── words.json                       # canonical word-level transcript
├── captions.srt                     # soft-sub sidecar
├── captions.ass                     # generic plain-style ASS sidecar
├── <clip>__frosted-subtle.mp4       # burned-in video
├── <clip>__frosted-subtle.ass       # the styled ASS used for the burn
└── storyboard.html                  # review surface

Requirements

  • ffmpeg, ffprobe on PATH (libass support is standard in Homebrew builds).
  • Python: fal_client, jinja2. The script auto-installs both with pip install --user if missing.
  • FAL_API_KEY (or FAL_KEY) in environment, or in the nearest .env (auto-loaded). The script aborts with a clear message if missing.
  • For Remotion styles: node ≥ 18 and npx. The skill bundles a remotion/ workspace and runs npm install lazily on first use.

Conventions this skill respects

  • 9:16 vertical assumed. Captions sit in the lower third (~y=72%) by default. Override with --position center or --y-pct 80.
  • 88% safe area — the motion-graphics rule. ASS templates use MarginL/MarginR=6% of frame width.
  • Pill / box styles clamp to a safe width. Any style that draws a background pill sized to the text (clean-bubble, energy-pop) must shrink-to-fit: if a cue's pill would exceed ~90% of frame width, the font is reduced for that cue. Long words ("recommendations", "opportunistic") are inevitable — never trust the transcript to stay short. A new pill/box style without shrink-to-fit is a bug.
  • Brand names get verified. Whisper mis-spells brand-name homophones; use --word-fix (see Pipeline step 1b) and eyeball the brand name in the burned output before shipping.
  • No placeholder anything. If transcription fails, the skill aborts with the actual error from Fal; it does not invent words.
  • Storyboard is the single review surface. Every multi-style run writes a storyboard.html so review happens visually, not in chat.