Skip to content
Back to skills

Animated Text Overlays

ASecurity

Add or fix animated text: typewriter or letter-by-letter reveals, word-by-word fades, slide-up, pop, gradient shine, lower-thirds, kinetic hooks and titles ('make the caption type out', 'the animated caption is cut off'). Load before hand-writing a code overlay that animates text. Not for subtitles synced to speech (speech-captions) or plain static text (a text overlay).

  • 2 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 19, 2026
ai-agentsgoexpressrails

Security analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned October 4, 2026

npx -y skills add Nagellabs/libi --skill animated-text-overlays --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Animated Text Overlays?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Animated Text Overlays
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/nagellabs-animated-text-overlays/badge)](https://www.skillsdirectory.com/skills/nagellabs-animated-text-overlays)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: animated-text-overlays
description: "Add or fix animated text: typewriter or letter-by-letter reveals, word-by-word fades, slide-up, pop, gradient shine, lower-thirds, kinetic hooks and titles ('make the caption type out', 'the animated caption is cut off'). Load before hand-writing a code overlay that animates text. Not for subtitles synced to speech (speech-captions) or plain static text (a text overlay)."
tags: [overlays, text, animation]
---

# Animated text overlays

Done looks like this: the text animates as asked, the whole text is visible by the end of the
reveal (never a truncated "Sa"), and the user can retune it in the inspector. Subtitles synced
to speech belong to `speech-captions`; plain static text is `libi.add_overlay({ kind: "text" })`.

## Set controller fields, not code

Build the look by setting declarative fields on a `kind: "text"` overlay: `reveal.mode` for
motion, `threeD` plus `place3d` / `transform3d` for depth, the style fields (`color`,
`background`, `stroke`, `shadow`, font) for the look. A field lands on the gizmo and the
inspector, stays tunable, and you can point the user at it with `libi.highlight_property`; a
look baked into a draw function is none of those.

- `reveal.mode`: `typewriter`, `fade-words`, `slide-up`, `pop`, `karaoke` (full line, active
  word in `reveal.highlightColor`), `word-current` (only the active word shows). The renderer
  paces them off the overlay's own window.
- `reveal: { mode: "flythrough", direction }` paints text on across a 3D plane. It requires
  `threeD`; `direction` is `ltr`, `rtl` or `through`, and `sideOffset` tunes the sweep angle.
- Extruded or tilted 3D text is still `kind: "text"` (`add_overlay`, then `update_overlay({
  place3d: true, transform3d })`, plus `threeD` for thickness). Only an arbitrary 3D object or
  scene, or text on moving geometry that tracks the footage, is `three-overlays`.

Captions are flat by default. Add depth or tilt only when the user explicitly asks for a 3D,
road or fly-through look. 2D in-plane rotation (`rotation`, Transform tab) is always safe. If
you are reproducing a source video's captions and cannot tell flat from 3D, `mimic-video-captions`
owns that call.

## Code overlay: the last resort

> STOP before `libi.add_overlay({ kind: "code" })` for text. If the reveal modes and style
> fields can express the look, use them. A code overlay is only for bespoke procedural motion:
> a custom kinetic path, a gradient shine you must draw, a multi-line stagger you must
> hand-tune. When you do write one, copy a tested body from `prompts/styles.md` and keep its
> pacing math; guessing whether `time` is overlay-local or composition-global is how the
> "Sa" bug happens.

A code overlay's draw function runs on element-local time: `progress` goes 0→1 across the
overlay's own window, `time` and `frame` start at 0 at its `startTime`, and `totalFrames` is its
own length. Pace every animation off `progress`, never off composition frames
(`prompts/timing-contract.md` has the context fields). Never hard-code a composition time in a
body: when it must know where it sits on the piece, use `compositionTime`, `overlayStart` or
`pieceDuration`, so retiming the overlay or the piece edits no code.

Matching an existing overlay's style: `libi.code_outline({ pieceId, overlayId })` lists its
functions, palette and fonts without running it. Outline first, read only the lines you will
reuse (`includeSource: { from, to }`), and never print a whole kit. To draw in that style, reuse the kit with
`include` on `libi.add_overlay` (`include: { fromOverlayId, names }`, or `libi.update_overlay` for an
overlay that exists): it copies just the helpers your body reads, and its result lists what it
copied and any `warnings` for a name still undefined. Don't copy a kit by hand.

1. Pick a style from `prompts/styles.md`, decide the window (`startTime`, `duration` in
   composition seconds), and fill the template's text, font and colour.
2. `libi.add_overlay({ pieceId, kind: "code", displayName, body, startTime, duration, rect,
   z })`. `displayName` is required (the timeline track label). It returns `codeFilePath`, the
   overlay's `draw.jsx`; refine the animation by editing that file directly. A watcher
   revalidates and updates the preview, and there is no code-string update tool.
3. Check the start, middle and end of the window, and that the full text shows by the end of
   the reveal.

## Guardrails

- The draw-function validator is regex-based and rejects bodies containing ` import `,
  `require(`, `eval(` and the like, even inside the displayed text. Rephrase the text, or use
  a static text overlay.
- Text does not wrap: a line wider than the canvas spills off both edges. Read `width` from
  `libi.get_composition` and keep `chars × 0.6 × fontPx ≤ 0.84 × width`; shrink the font or
  stack lines (`speech-captions`, `prompts/readability.md`).
- A caption that labels speech runs from the phrase's first word to after its last word (plus
  a short hold), with the end taken from the last word's timing, not a guessed duration
  (`speech-captions`, `prompts/timing-contract.md`).
- Over busy footage use a stroke or an opacity plate behind the text.
- One overlay per animated element: a multi-line template beats ten stacked code overlays.

When the user describes a specific look (font, colour, stroke, shadow), set it, and once it is
right offer to save it with `libi.caption_style({ action: "create" })` so it shows in the Style tab. Ask
first; never create styles unprompted.

When the result is not what they wanted, do not re-run blindly: point them at the governing
control and load `guiding-manual-edits`. Style and 3D fields can be flashed with
`libi.highlight_property`; the reveal itself lives in the Effects panel's Reveal tab, which you
name in chat.

Render and look before you tell the user it is done (`libi.render_overlay_frames`, see the
manual's "Putting results in front of the user").

Files in this skill

  • SKILL.md12.7 KB
  • prompts/styles.md2.1 KB
  • prompts/timing-contract.md1.3 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.