Caption word reveal
Cloud-based agent skills for creating AI avatar talking-head videos and short-form reels (skills.sh format)
npx -y skills add puntorigen/avatar-skills --skill caption-word-revealAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 28 days oldThe repository was created 28 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Word-by-word ("karaoke") burned-in captions for avatar reels: each word appears at the instant it's spoken, building up the SAME phrase unit in place (frozen layout, no reflow), and the phrase clears when the next one begins. Use when the user wants captions/subtitles where words form the sentence as the narration says them (word-by-word reveal, karaoke captions, "las palabras van apareciendo") on any reel produced by the avatar-reel-composer pipeline.
SKILL.md
5.3 KB, ~1.3k tokens by cl100k_base, as published. Nobody here has run it
Caption word-by-word reveal
Karaoke-style captions for reels: instead of a whole phrase popping in at once, each aligned word appears the moment it's spoken, building the phrase up in place; already-spoken words stay lit and the phrase clears when the next phrase starts (same "replace" progression as the static captions).
This is already implemented in the avatar-reel-composer finishing pass
(finish_reel.py) — this skill is how to apply/tune it and the invariants to
keep. It is the default caption mode (caption_reveal="word").
When to use
- The user wants captions where the words form the sentence as they're spoken ("palabra por palabra formando la frase", karaoke captions, word reveal).
- Applying that look to a new reel, or re-captioning an already-finished reel without regenerating any video.
Requirements
- A reel folder produced by
compose_reel.py(hasvideo_track.mp4,narration.mp3,reel_manifest.json). - Word-level timings at
narration.align.json(faster-whisper alignment) — the reveal is driven by each word'sstart. Without it, captions are skipped.
How to apply
A) New reel — set it in the storyboard finish block
"finish": { "enabled": true, "subtitles": true, "caption_reveal": "word" }
Then compose normally; caption_reveal defaults to "word", so a finish
block already gets the reveal unless you set "phrase".
B) Any existing reel — re-caption in place (no re-render of video)
python3 .cursor/skills/avatar-reel-composer/scripts/finish_reel.py <reel_dir> \
--caption-reveal word --no-music
--no-music reuses the existing bed and only rebuilds the caption layer. Drop it
(or add --music-prompt "…") to also (re)build music. Re-running is idempotent.
To revert to static phrase-replace captions use --caption-reveal phrase.
If a polish pass (golden-flash / SFX) was applied, re-run it afterward so the
effects sit on top of the freshly captioned video (see avatar-reel-composer
Polish). Tune text with the same knobs as static captions: --max-words,
--no-emphasis, --casing, --fontsize, --y-frac, --regular-font,
--emph-font.
How it works (invariants — keep these when tuning)
The reveal reuses the SAME phrase units and setup/payoff styling as the static captions; only the presentation differs. Four properties keep it from looking janky — preserve them:
- Frozen layout, no reflow. The wrap, font size and every word's
x/yare computed ONCE from the FULL phrase, then frozen. Drawing the first k words reproduces the head of the finished line — words never recenter or jump as they arrive. (_reveal_fit_fslocks the size with the static fit rule;_positioned_tokensfreezes positions.) - Replace, not accumulate. A phrase clears to blank only when the next phrase begins — the viewer never reads stale, not-yet/already-spoken text stacked up.
- Frame-snapped timeline. Every reveal-state boundary is rounded to the fps grid and durations accumulate in whole frames, so the reveal can't drift against the frame-locked picture (same anti-drift discipline as the video assembly). Long reels stay in sync to the end.
- One lossless alpha overlay. All per-word states are baked into a SINGLE
transparent
qtrle(.mov) track via anffconcatlist and composited in oneoverlaypass — not ~hundreds of overlays. RLE +argbkeeps the serif edges crisp. (build_reveal_track→overlay_reveal_track.)
Styling matches the static captions: serif (Georgia), subtitle casing
(lowercase, intentional ALL-CAPS + accents kept, no trailing dot), white with a
soft shadow/outline; the breath-group payoff is bold-italic.
Verify
Extract a few frames spanning a phrase and confirm words accrue left→right without the line shifting, and that the last words land in sync near the reel's end (where drift would show first):
ffmpeg -y -ss <t> -i <reel_dir>/final.mp4 -frames:v 1 /tmp/rev_check.png
Files (in the avatar-reel-composer skill)
scripts/finish_reel.py_event_tokens— per-word display strings + spoken start times + payoff split._reveal_fit_fs/_positioned_tokens— lock font size + freeze full-phrase word positions.render_reveal_state— render one state (first k words lit).build_reveal_track— bake all states into one frame-snapped transparent qtrle track.overlay_reveal_track— composite the track over the base video in one pass.finish(..., caption_reveal="word"|"phrase")/ CLI--caption-reveal(defaultword).
scripts/compose_reel.py— passesfinish.caption_revealthrough tofinish().
See the avatar-reel-composer skill for the full finishing pass (caption phrasing, emphasis, music, polish).
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.