Scene libraries
rapid:lib/shots@1, deterministic kinetic primitives for HTML scenes, and the other pinned libraries: camera, motion, fields, shapes, charts, and pictures.
rapid:lib/shots@1 is rapid's kit of kinetic primitives for HTML scenes: a spoken line landing word by word, a frosted-glass reply, file cards that fly in and out, fitted display type, field changes, and grain, each a few lines and each in the linked style's look. It loads beside or instead of GSAP.
<link rel="stylesheet" href="rapid:style">
<script src="rapid:lib/shots@1"></script>
It is pinned like GSAP: rapid:lib/shots@2 is refused.
What it promises
- A pure function of time. Each call builds its elements once, at load, and sets them every frame from
talone. Any frame re-renders the same, in any seek order, on any lane. Call every primitive from the scene's top-level script, never from a frame callback. - The linked style's look. Everything it makes wears the kit and the
--rapid-*properties, plus a fewshot-*classes whose defaults are built from those properties alone. The same scene renders inswiss,terminal,poster, or any style; a style may restyle anyshot-*class. - Checkable. Everything it makes carries
data-elanddata-role. Passidto name a primitive and keep it the same between rounds. - Sound. Each moment that should sound is a declared cue on its exact frame, in the library's kinds (
voice,reply,file-in,flood, ...). A style whose sound map has no instrument for one hears it as its generic kind (word,land,enter,exit,settle). A flood or a swatch carries its colour, so colour is the score. - Timing you can chain. Every call returns its times, so the next beat starts once the last has landed.
A scene in a dozen lines
This is the poster style's proof, whole.
<!doctype html>
<html>
<head>
<script type="application/json" id="rapid-meta">{"id": "proof", "kind": "html", "dur": 9.38, "width": 1080, "height": 1920, "fps": 30}</script>
<link rel="stylesheet" href="rapid:style">
<script src="rapid:lib/shots@1"></script>
</head>
<body class="field">
<script>
shots.pace({ wps: 3.6, cps: 38, hold: 0.6, lead: 0.25, think: 0.35 })
shots.place({ steps: [{ at: 0.3, place: 'studio,', clock: '10:02 am' }, { at: 1.1, place: 'studio,', clock: '10:03 am' }], out: 6.2 })
const L1 = shots.spoken(0.5, 'make me a poster for friday. loud, all type')
const R1 = shots.typed(shots.after(L1, 0.15), 'three ways in. the second one is loud.')
const card = shots.card({ id: 'card-poster', at: R1.end - 0.15, name: 'poster_friday.pdf', sub: 'poster · three directions', kind: 'pdf', y: 520, out: 5.95 })
shots.voice({ id: 'voice-1', line: L1, out: R1.end + 0.1, maxWidth: 660 })
shots.reply({ id: 'reply-1', typing: R1, y: 1000, out: card.out - 0.3 })
const F1 = shots.flood({ id: 'field-cream', at: card.gone - 0.1, color: 'cream', from: [440, 650], dur: 0.75 })
const D1 = shots.display({ id: 'title-1', at: F1.at + 0.3, text: 'say it', y: 330, measure: 888, reveal: 'glyph', color: 'red' })
const D2 = shots.display({ id: 'title-2', at: D1.at + 0.22, text: 'loud.', y: 760, measure: 888, reveal: 'glyph', color: 'red' })
const A1 = shots.display({ id: 'aside', at: D2.end - 0.2, text: 'the second one, all type.', y: 1300, cls: 'voice', fit: false, color: 'ink' })
shots.grain({ amount: 0.08 })
shots.lengthIs(shots.after(A1, 1.2))
</script>
</body>
</html>
Timing
Write the video's pacing in with shots.pace(...), so the scene's length never moves with the style it renders in; without it, the helpers read the linked style's motion.pacing.
| call | |
|---|---|
spoken(at, text) | when each word lands (land[]) and when the line has (end), at the speaking rate; a trailing … holds 0.4 s |
typed(at, text) | dots from at, the characters from start at the typing rate, done at end |
after(cue, gap) | the next beat: the cue's end plus a gap (the line hold by default) |
lengthIs(end) | fails the render when rapid-meta's dur is not where the cues end |
The primitives
| call | what it draws |
|---|---|
voice | the speaker's bubble, growing word by word; the arriving word shimmers from the accent into ink; a capsule waveform rides the speaker's level |
reply | the assistant's frosted-glass bubble: dots, then the text typing in, its lines never re-wrapping |
card | a file card at app scale: flies in from an edge, floats, flies out |
stack | files burst into a floating constellation, then collapse into one card |
send (toName) | the recipient set as type: "to" small and italic, hung at the x-height of the name set huge; a card arcs into it and is absorbed |
display | a line fitted to the measure, revealed by a rise, glyph by glyph (reveal: 'glyph', kerning kept), or a cut |
mask | display type seen through a vector shape (the style's mark, or the library's) |
overprint | display type with a mark printed across it in multiply |
texture | a phrase repeated as an environment, drifting, allowed off the edges |
lens | a sharp travelling magnifier that redraws what it passes over, scaled |
lockup | big and small: fitted masses stacked tight with small italic lines |
ticker | a phrase running across the frame |
palette | swatches fanning out like instruments, each sounding its colour |
board | tiles flying in from beyond the edges into a grid |
still | a picture as a rounded card, or full bleed |
field, flood, wipe, blob | a ground (flat or an OKLab gradient); a colour flooding from a point; the mark sweeping across; an organic shape sweeping in |
roll, place | characters rolling like an odometer; the place clock |
grain, wash | grain; the camera wash of drifting light and bokeh |
fit | sizes a line so its ink spans the measure, measured with the face it really draws in |
Helpers: ease (expo, quint, quart, and cubic ease-outs among them), at, span, color(token), mix(a, b, k) and gradient(stops, angle) in OKLab, inkOn(ground), measure, hash, and noise. The plugin's rapid-scene skill carries the full reference, every option and what each call returns, in shots.md.
Craft
- No crops. Fit big type, never size it by eye. Only a texture runs off the frame.
- Read the format's guides. In a reel, stop the measure at 960 for anything between y 900 and 1650, clear of the feed's buttons.
- Ration the type moves: one or two a scene, each because the moment asks for it.
- The mark only does jobs: a wipe, a mask, a stamp; never decoration.
- Big and small. Pair a fitted mass with a small italic aside.
- Motion: expo and quint ease-outs, exits off the frame edges, nothing jittering, and idle is still.
- Never land a cream card on a cream field. Time a flood after the cards that would sit on it have gone.
The other libraries
Pinned at @1 beside shots, each a pure function of t, each documented call by call in plugin/skills/rapid-scene/<name>.md. The blocks page plays a sample of the blocks, by level:
| Library | Draws |
|---|---|
rapid:lib/camera@1 | a camera over a data-camera world of layers at depths: pushes, pulls, pans, parallax, reframes, rack focus, a degree of roll or tilt, and the quick moves: a snap or crash zoom, a whip pan blurred along its motion, a dolly zoom (vertigo), an impact shake |
rapid:lib/motion@1 | secondary motion while the hero holds: breathe, drift, float, sweep, counter, underline, cursor, marquee, … |
rapid:lib/text@1 | type that does something: glyph effects by preset, rolls, loops, morphs, scrambles, shimmers, waves, glitches, digits on a spring |
rapid:lib/light@1 | light that moves: a glow of the palette behind a card or in type, a travelling spotlight, rays |
rapid:lib/fields@1 | generated grounds from the palette: a WebGL shader on a <canvas> (data-role="texture"), or the same math on a 2D canvas where there is no WebGL |
rapid:lib/shapes@1 | SVG drawn over time: self-drawing strokes, building diagrams, one path morphing into another, a few iconic marks, a blob |
rapid:lib/charts@1 | bars, a self-drawing line with its area, a donut, a comparison, number tiles, one big number counting up; tabular figures |
rapid:lib/pictures@1 | several shots from one photo: crops that push or reframe (in shares of the picture), splits, duotones, type cut out of it |
The quick camera moves are punctuation: a beat's hit on its cue, one or two in a video, with the slow travel around them still spanning its beat.
Starting points
A block is a quick name for a look, so nobody rebuilds the basics. It isn't the only code allowed. Call one as it is, tune its options, wrap or combine it, or copy its idea into the scene's own script and change it. When a look or a storyboard asks for something no block does, build it. The same goes for a style's components and the join's transitions. Hand-written motion keeps the same contract: drawn from t, tagged, styled from the style.