Fixes the Format / Preflight CI checks on the new skill files. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
16 KiB
Motion-primitive catalog — the free-compose menu
The atomic layer: one anchor → one micro-move. Templates (template-catalog.md)
are built from these; when no template fits a group, the planner free-composes by naming
primitives from here, and the frame-worker realizes them. Two readers, one file:
- Planner (Step 3) — scan what it does + anchor to pick the primitives a free group rides. Selection only.
- Frame-worker (Step 4) — open the cited recipe and lift its tweens. Build only.
The recipe column says what to lift:
- ✓ — a runnable, lint-clean composition at
motion-primitives/<id>/index.html. Open it and lift the tweens. - ≈
<id>— no separate file; use that recipe, it's the same idea. - — — no file; implement inline from the description (a one-liner, e.g. a 0ms
tl.set, or a move a template realizes internally).
Timing & latency (applies to every primitive)
Quantified from frame-accurate reverse engineering of beat-synced reels:
- Hard hits are 0ms. Cuts, palette flips, content swaps, freezes are
tl.set(...)with no duration — the percussion is the motion. Easing a hit kills it. - Lead the anchor. A move that must land on a beat (a wipe covering the frame, a count-up locking, two blocks colliding) starts ~40–190ms early so it completes ON the anchor. Reactive entrances (something appearing because of the hit) fire 0–45ms after.
- Eased entrances: 300–500ms (scale punch, slides, camera pushes). Macro builds: 800–2000ms spanning a whole roll / silence.
- Magnitudes: scale-punch 0→1; weight pulse 1→1.06; hero fill up to 1→5; chromatic split ~20px, resolve clean in ≤150ms.
- Per-bar caps: one accumulating element per hit (not a burst); a camera move at most once per phrase, never per beat; a dense flip/strobe system runs ≤2–3s.
- Tension-builds lock. A count-up / sequential build / morph must resolve on a downbeat or hard_stop, never trail off mid-bar.
Catalog
Each runnable recipe is self-contained and lint-clean: showcase chrome stripped, system-font
fallback, shared ../assets/gsap.min.js, one paused timeline on window.__timelines["main"].
| id | anchor | what it does | recipe |
|---|---|---|---|
hypercut-whip |
beat / hard_stop | fast whip-pan hard cut between frames | ✓ |
kinetic-letter-in |
downbeat / phrase | per-letter kinetic entrance | ✓ |
braam-punch |
drop / surge | big "braam" impact — scale + weight slam | ✓ |
chromatic-split |
snare / glitch / surge | RGB channel split / glitch on a word | ✓ |
mask-reveal |
section_start / downbeat | clip-path mask wipe reveal | ✓ |
screen-shake |
drop / crash / kick | camera / screen shake jitter | ✓ |
binary-decrypt |
roll / build | scramble→decode text (binary → word) | ✓ |
dolly-zoom |
phrase / build | vertigo dolly-zoom (scale vs perspective) | ✓ |
iris-open |
section_start / reveal | circular iris-open reveal | ✓ |
electric-arc |
accent / glitch | electric arc / lightning accent | ✓ |
neon-flicker |
hold / texture | neon-sign flicker | ✓ |
chrome-sweep |
downbeat / reveal | metallic specular sweep across text | ✓ |
slot-machine-reveal |
roll → downbeat | slot-machine spin-to-land character reveal | ✓ |
liquid-morph |
phrase / transition | liquid / blob morph | ✓ |
gooey-metaball |
build / drop | gooey metaball merge field | ✓ |
3d-card-flip |
downbeat / swap | 3D card flip (rotateY) | ✓ |
crash-zoom-in |
drop / surge | violent crash zoom-in | ✓ |
spotlight-sweep |
reveal / hold | spotlight / gradient sweep over text | ✓ |
outline-to-fill |
downbeat / reveal | stroke outline → solid fill | ✓ |
counting-punch |
roll → downbeat | number count-up that punches & locks | ✓ |
particle-burst |
drop / crash | particle explosion burst | ✓ |
radial-burst-lines |
drop / surge | radial speed-lines burst | ✓ |
pixel-dissolve |
transition / hard_stop | pixelated dissolve | ✓ |
datamosh-smear |
glitch / transition | datamosh / motion smear | ✓ |
text-wave-distort |
hold / texture | wavy text distortion | ✓ |
bg-flow-field |
energy / whole span (bed) | generative WebGL curl-noise flow-field background bed — palette-driven, breathes on the energy envelope; compose any foreground move over it | ✓ |
blur-resolve |
stop / final hold | blur-in to crisp focus, then blur-out on the cut | ✓ |
chromatic-pressure |
snare / glitch | RGB split / digital tension on a transient | ≈ chromatic-split |
color-grid-shuffle |
onset | grid of cells recoloured by a deterministic index per onset | — |
content-swap |
beat | 0ms swap of stacked nodes — the workhorse percussive move | ≈ slot-machine-reveal |
directional-fill |
beat / reveal | directional wipe-fill (scaleX) sweeping across bars | ✓ |
flash-cut |
drop / crash | full-frame flash masking a word / colour state change | ✓ |
freeze-hold |
hard_stop | freeze the moving system and hold it (desaturate + vignette) | — |
hard-cut |
beat / hard_stop | sample-accurate 0ms colour-block + word cut | ✓ |
mosaic-pack |
beat / build | scattered tiles fly in and pack into a grid | ✓ |
negative-space-hold |
silence / hard_stop / final hold | kill busy layers, hold one readable mark in empty space | — |
overlay-pop |
accent | badge / lower-third overlay pops in over a base | — |
palette-flip |
section change | same layout re-skins via 0ms palette-variable flips | ✓ |
staggered-exit |
phrase / transition | ordered cascade-out clearing the frame | ✓ |
staggered-reveal |
build | ordered cascade-in of a stack / list | — |
system-replace |
drop / regime change | hard-cut the entire visual system, then boot the new one | — |
text-spectral-rays |
phrase / sweep (hero text) | volumetric spectral light-rays cast by a wordmark toward a sweeping light cursor — grain + RGB-split; WebGL hero-text system | ✓ |
tile-mosaic |
build / reveal | grid of tiles revealed in a diagonal sweep, assembling a poster | ✓ |
typewriter-reveal |
roll / build | char / word type-on, explicit per-span set (no stagger) + caret |
✓ |
value-counter |
roll → downbeat | count-up that locks on a downbeat / hard_stop | ≈ counting-punch |
word-grid-burst |
onsets → downbeat | grid of words revealed per onset, refocus one on a downbeat | ✓ |
Template-private verbs. Some templates declare moves realized only inside their own impl —
held_lockup,anchor_pop_in,word_slot_cycle,per_line_color,scene_palette_flip,beat_jitter_shake,box_zoom_wipe(split-anchor-word-slot),motion-blur(logo-split-lockup-pulse). Those live in the template'sindex.html, not here.
How to combine
- One dominant system per group; layer at most one texture recipe over one structural recipe.
- Structure on strong beats (cuts, camera,
system-replace→ downbeat / phrase / section_start); texture on weak / syncopated hits (content-swap, typewriter letters, chromatic accents). - A roll is an accumulation container — build during it, hard-cut to a clean layout on the downbeat that ends it.
drop≠downbeat: a downbeat is a cut within the regime; a drop is a regime change (system-replace, total clear, element-count jump).- Let silence remove density (
negative-space-hold). - Background beds are a layer, not a move. A bed (
bg-flow-field) runs the whole span on the energy / phrase channel, leaving the beat anchors free for the foreground — so it composes cleanly under any discrete primitive. One bed at a time; merge the bed's uniform tweens onto the group's master timeline (don't run a second timeline), bundle a localthree/WebGL (no CDN), repaint via the timeline'sonUpdate(no rAF). - WebGL "system" primitives come in two roles: a bed (
bg-flow-field, behind everything) and a hero-text treatment (text-spectral-rays, which rasterizes the wordmark and is the hero). Use at most one of each; feed text/raster locally (no CDN fonts), repaint viaonUpdate. text-spectral-raysrenders its OWN wordmark — never give the word a second source. It draws the solid letters AND the rays from one glyph mask (perfectly registered). Do NOT use it as a "rays-only" layer behind a separate DOM logo (or stackcontent-swap/chromatic-pressureon the same word): the two fonts/positions won't match and you get a doubled / ghosted wordmark — deleting the shader's letter terms does not fix it (the ray mask is still the second, misaligned copy). Let the shader be the wordmark; hide any DOM logo (keep it only as an invisible layout spacer). If you move the word off frame-center, move the light cursor'syby the same amount. Full recipe:motion-primitives/text-spectral-rays/USAGE.md.