Hypernatural

TechniqueBy HypernaturalVersion 2, Oct 26, 2026

hn4a-compositor-in-scene-titles

Titles that live in the footage, rendered with hn4a-compositor: type behind people (a foreground cutout over the words), words that pop or pulse on spoken cues, light spilling on the set, glitches timed to the picture, typing with a caret, a phone ring, a drop, a focus pull, a screen powering on, a floor reflection, karaoke captions on the spoken word, a camera pushing into a product screen rebuilt as layers. Uses a small Python helper that writes the JSON layer spec. Use for kinetic, in-scene or 3D-looking titles over a finished cut.

SKILL.md

Compose in-scene titles

Give it a finished cut, its word timings, its cut times and the visual events to react to; get back the cut with titles that sit in the set and react to it, rendered frame-exact by hn4a-compositor. The effects are layers and keyframes in the ordinary compose spec (hn4a-compositor-motion-graphics has the format, the command line, previews and --into revisions); a small helper module writes them from cues so a build script stays a list of calls. For overlay layouts beside the footage (slides, lists, a presenter bubble), use hn4a-compositor-motion-graphics alone.

Inputs

  • The cut, and its speech-to-text (elevenlabs-speech-to-text, read with python-read-word-timings) for word cues.
  • Its shot boundaries from scene scores at the low threshold (ffmpeg-scene-cuts at 0.015): soft cuts and dissolves score 0.02–0.06, which a scene > 0.25 pass misses.
  • Visual events (a face tearing, a phone picked up, a screen glitching) from a 2 fps contact sheet of the shot, then frame-stepped in the preview.
  • A cutout for every shot where type goes behind people (birefnet-matte, snapped to that shot's cut times).
  • The brand's fonts and colours (here Brand Sans and Globex Lime #B8E62E).

Run it

  1. Write references/titles-fx.md's module into the job as titles/titles_fx.py, as is.
  2. Write titles/build_titles.py: the cues as constants, then the layers bottom first (the cut, then the type, then the cutout over the same span), dumped as JSON. references/worked-example.md is a complete one.
  3. Build and look:
exec python titles/build_titles.py --out titles/quiz_titles.json
exec hn4a-compositor page  titles/quiz_titles.json
exec hn4a-compositor still titles/quiz_titles.json titles/s_3.20.png --at 3.2
exec hn4a-compositor render titles/quiz_titles.json

(cwd the job folder.) Make a still at every effect, nudge boxes in the build script and rebuild. Then review_open with the spec as a {"compose": "titles/quiz_titles.json"} candidate, which plays live in its card, and the stills beside it as the row's refs, and get a yes on the title and caption design; only then render. The stills are your own check: they catch mistakes, they don't approve the look. A real job's script was a list of calls writing 81 layers; it rendered at 52 fps.

The effects

  • Type behind people. The cut, then the type, then cutout(src, start, end): the people and the furniture in front of the back wall cover the type. BiRefNet "General Use (Heavy)" keeps the podium and the chair, which is right when the type sits on the back wall. Place the type so a head or shoulder covers one letter or part of one, never a whole word: check the still and nudge the box.
  • One layout, many layers (line_html(parts, show)). Every layer carries the whole line in the same box, with the other words visibility:hidden, so the words line up exactly while each animates on its own. Set transformOrigin per layer to that word's centre. Words land on their cue with pop_keys, or pulse on beats with pulse_keys plus a spill (light on the set, under the cutout) driven by flash_keys.
  • Glitch (glitch plus hidden_during on the clean copy): three clip-path bands, each with a random x offset every frame on hold keys, plus red and cyan copies (screen blend) during each (start, duration) burst. Time the bursts to the picture's own glitch.
  • Typing (typing): one layer per prefix with uneven keystrokes, a solid caret while typing, then a blinking caret until the end. Pass the caret colour.
  • Ring (ring_keys on x, or on rotate with scale=0.25), drop (drop_keys, a receiver put down), focus pull (focus_keys, sharp on the word), a screen powering on (flicker_keys plus scan_bar).
  • Floor reflection (reflection(layer, floor_y)): the layer mirrored about where the wall meets a glossy floor, blurred and fading away from the wall. If the reflection lands off-frame, lower the type on the wall.
  • Karaoke captions (captions(words, box) on the STT words): each phrase builds word by word, and the spoken word sits on a pill and bounces. Two layers per word, so the words never shift. Pass the brand colour as pill. emphasis styles chosen words. skip leaves out spans where a full-screen title says the same words, and direction="rtl" builds Hebrew or Arabic phrases right to left.
  • A camera (camera(id, start, moves)): a group layer whose children (parent: id) zoom and pan as one, such as a product screen rebuilt as layers. Each move puts a point of the screen at the frame centre at a scale. hn4a-compositor-motion-graphics (references/spec-format.md, A camera over a group) has the rules. Keep it calm: one slow drift and one push per screen.

Tips and traps

  • Your own anim replaces the preset. If a layer's anim sets opacity or scale, the in/out presets skip that property, so write the whole curve yourself (hidden_during(..., end_at=) includes the fades).
  • The runtime owns transform and filter on every layer. Put perspective and scaleY(-1) mirrors on an inner div of the html, and use text-shadow, not filter: drop-shadow, for glow.
  • Name the font on the layer. The runtime checks the first family in the layer's own font (not the html's) has a loaded face; text_layer(..., font=) sets it. A family that isn't loaded stops the render.
  • Cutouts are per shot. A cutout's frame k is comp frame start × fps + k, so give it the same start as its shot and trim 0.
  • Pass the brand colour everywhere it shows (caret, spill, scan bar); the helpers default to white.

Check it

  • Stills at every cue, effect and cut, looked at: no whole word hidden by a head, the reflection in frame, the glitch only during the picture's glitch.
  • Play the preview through at full speed once; then render and check the frame count equals round(duration × fps) (exec ffprobe -v error -count_frames -select_streams v:0 -show_entries stream=nb_read_frames -of csv=p=0 <out.mp4>).

Go make something cool.

Install the app, open your agent, describe the video. That's the whole onboarding.

Sticker HypernaturalSticker BannerSticker TVBoy