Scenes

HTML scenes and canvas scenes, the meta, the frame rule, and why every frame renders the same.

A scene is one shot: an id, a duration, an entry, cues, and something that draws as a pure function of time. Any frame re-renders exactly, frames render in any order, and one scene renders in parallel chunks across Chrome pages. Authoring contract: writing scenes.

Two kinds

  • HTML scenes: one .html file of HTML, CSS, and pinned libraries, run in headless Chrome under rapid's virtual-time runtime. Every scenes/<id>.html in a project is one; the planner builds only these.
  • Canvas scenes: a .js, .mjs, or .ts module whose default export has a meta and a draw(g, t, d) that paints the whole frame from t. rapid render takes one by its extension.

The meta

SceneMeta and HtmlSceneMeta in contracts/src/scene.ts:

FieldTypeNotes
idida-z, 0-9, -, up to 64
kindhtml or canvashtml by default in an HTML scene
dursecondsfrom the scene's own timings, never padded
enter{ kind, dur, params? }cut, flood, mark, blob, slide, or fade; default { "kind": "cut", "dur": 0 }
place, clockstrings, up to 80 and 20drawn over the scene, never by it
whostring, up to 80optional
duckarray of [from, to]spans where the scene's full-frame type owns the clock's corner; default []
width, height, fpsHTML onlythe frame it draws, from its format; required
fontsHTML only, array of stringsfamilies drawn only on a <canvas>, which must load; default []
keyHTML only, secondsthe key frame: the hero, built and approved before the motion
holdsHTML only, array of [from, to]spans held still on purpose; the dead check skips them; default []
roomHTML only, 0–1the share of the key frame that may be empty field; the empty check allows up to it (default 0.4)

The frame rule

One function (contracts/src/frames.ts) says how many frames a duration has and which frame a time is in; every renderer, check, and sheet uses it.

  • Frame k starts at k / fps.
  • d seconds is ceil(d × fps) frames, at least one.
  • A time falls in the frame it is in (rounding down), clamped to the scene.
  • The poster is the start of the last frame: the node's thumbnail.

At 30 fps a 3.2 s scene has 96 frames; its poster is at 3.1667 s.

Determinism

The runtime loads before the scene's scripts and owns every clock the page can read: Date, performance.now, requestAnimationFrame, setTimeout, setInterval, Math.random, crypto.getRandomValues. The clock starts at 2026-01-01T00:00:00Z and moves only when the renderer seeks.

Same in any seek order:

  • code in rapid.frame(fn) that computes from its t;
  • GSAP timelines built at load;
  • CSS animations and transitions;
  • Web Animations made at load;
  • rapid.random() inside a frame callback (reseeded from the frame's time);
  • the pinned libraries.

Same only in a straight play: state a script keeps (a timer chain, a counter bumped per frame). Timers fire in virtual-time order as seeks move forward; a backwards seek rewinds the clocks but never un-fires a timer. A render seeks out of order across chunks, so compute from t.

Problems fail the render

The runtime collects uncaught errors, unhandled rejections, a throwing frame callback or timer, assets that fail to load, images still loading after 10 s, more than 10,000 callbacks in one seek, and fonts that didn't load, each with the time it first happened. A scene with any problem renders nothing; rapid render exits 1 naming it:

rapid: callback at 1.033s: frame: Error: oops

No network

A scene reaches nothing outside its folder (a project's scene: the project). An absolute address in its HTML or CSS is refused before the page loads; the page's content security policy blocks anything a script builds at run time. Relative addresses resolve against the scene's folder; rapid:style/<path> is the linked style's file.

What a render writes

Beside each MP4:

  • <name>.boxes.json: every data-el element on every frame: id, box in frame pixels, role, text, and for type its line height and font size. The checks read it.
  • <name>.cues.json: every cue the scene emitted, deduplicated by key. The mix plays them; review times are picked at them.