# Kinetic for WildflowerJS: the condensed reference
This file describes Kinetic 0.1.1, updated October 31, 2026.
> Kinetic (`@wildflowerjs/kinetic`) is a WildflowerJS extension that turns a
> web page into a video. This file is the condensed, single-fetch reference
> for code generation. The framework it extends has its own at
> https://www.wildflowerjs.com/llms.txt, and the full Kinetic corpus (every
> documentation page with every example) is at
> https://kinetic.wildflowerjs.com/llms-full.txt.
> A Kinetic page is a WildflowerJS page, and every framework attribute and
> API works in it: for anything about WildflowerJS itself (whether
> `data-bind-html` exists, what a checkbox's `data-model` writes), read
> https://www.wildflowerjs.com/llms.txt rather than guessing.
> The guide written for assistants ships in the npm package: read it at
> https://cdn.jsdelivr.net/npm/@wildflowerjs/kinetic@0.1/skills/wildflower-kinetic/SKILL.md,
> or where only the package registry is reachable, `npm pack @wildflowerjs/kinetic`
> and open package/skills/wildflower-kinetic/ in the tarball.
> Beside it, references/start.md has two complete pages to start from (a
> video, and an interactive lesson that is also its own video), and
> references/patterns.md has working patterns, one idea at a time.
## The smallest working page
`index.html`:
```html
```
`scenes.js`:
```javascript
const { scene, typewriter } = wildflower.kinetic;
scene('title', {
keyframes: {
heading: {
opacity: { at: [0, 0.5], to: [0, 1] },
translateY: { at: [0, 0.8], to: [40, 0], ease: 'spring' },
},
},
computed: {
line() { return typewriter(this.local - 0.6, 'A page that is also a video.', 20); },
},
});
```
Open `index.html` in Chrome, from disk or served: it loads only scripts.
`data-preview` adds the bar that plays, checks and renders it.
## Where the page will open
- **As one file:** put the page's own code in `
```
Interactive mode. `$kinetic.mode` is `'interactive'` or `'video'`. `config({ mode })` is
`'auto'` (the default: video with the preview bar up, interactive otherwise),
`'interactive'` or `'video'`; a renderer's runtime on the page, a render
capturing, `check()` and `render()` put the page in video mode whatever the
setting. In video mode the clock plays straight through and each step's
`script` writes its store paths on every seek; in interactive mode each step plays
and holds, and the learner's controls write the same paths. A step is a
clip with an `id` and `data-step` (chain them with `data-start="circle"`);
its range runs to the next step's start.
```javascript
wildflower.store('sine', { state: { angle: 30, choice: null }, computed: { answered() { return this.choice !== null; } } });
wildflower.kinetic.step('circle', {
wait: 2, // interactive: holds 2 s into the step; default the shorter of its range and its clip; false plays on
script: { 'sine.angle': { at: [2, 5.5], to: [30, 120], ease: 'power2.inOut' } }, // video: a track in the step's seconds
});
wildflower.kinetic.step('ask', {
wait: 1,
until: 'sine.answered', // interactive: once truthy, plays the rest of the step and holds on its last frame for Next; canAdvance waits for it
entry: { 'sine.choice': null }, // interactive: written as the step is entered
script: { 'sine.choice': { at: [0, 2], set: [null, 270] } }, // video: settings, strings, numbers, booleans or null
});
wildflower.kinetic.scene('sine-circle', { subscribe: ['sine'], follow: { angle: 'sine.angle' }, computed: { point() { return at(this.angle); } } });
wildflower.kinetic.next(); wildflower.kinetic.back(); wildflower.kinetic.go('ask'); // interactive: enter a step with its entry; video: seek to its start
wildflower.kinetic.config({ mode: 'video' }); wildflower.kinetic.play({ from: 0 }); // "watch it as a video"; config({ mode: 'interactive' }) gives the learner's values back
document.addEventListener('kinetic:step', (e) => { /* e.detail { step, index }: interactive mode, after the entering seek */ });
```
The store also has `step` and `stepIndex` (the step whose range holds
`time`, both modes, written in the seek's batch), `stepCount`, `stepStart`,
`stepLength`, `waiting` (interactive mode, true once the hold's seek has settled)
and `canAdvance`, which a Next button binds to: in interactive mode it
follows the step's `until` path (true when there is none), wherever the
step is; always true in video mode. `next()` enters the next step at once,
wherever the step is, the rest of it unplayed, and Kinetic never moves to
the next step by itself; Back always works. At a hold the clock stands
still, so `local` does too, and what the learner changes moves only through
`follow` springs or bindings to state: design a hold around a control and
what follows it. In interactive
mode `play()` plays on to the step's hold, and at or past it plays the step
again. With `autoplay` on, an interactive page with steps enters its first step when
readiness resolves, never when it fails. In video mode a path's value comes
from the scripts alone, never from the store, so any seek order gives the
same frame; a write to a scripted path by anything else is undone within a
microtask (KN-146), a watcher's write inside the script's own write too,
once per path between two seeks (a watcher that writes it again every time
keeps its value, with KN-146 printed), so disable every control that writes
a scripted path, and every quiz button, in video mode
(`data-bind-attr="{ disabled: $kinetic.mode === 'video' }"`). Switching to
video keeps the learner's values aside and switching back writes them
back; `check()` and `render()` seek back first, still in video mode. A
script path whose store does not exist, or that names a computed, fails
readiness (KN-100). `follow` eases toward a store path by a spring only
(`'spring'`, `{ spring: { stiffness, damping, mass } }` or `{ spring: {
duration, bounce } }`, `{ duration: 0.4 }` by default; another ease and
`overshootClamping` are KN-100): interactive, a sum of one step response per change
on the page's clock; video, the same spring on the target's script, sampled
on the root's `data-fps`. The script's writes are real store writes, so
interactive-only effects go in action handlers, `entry` or the `kinetic:step`
event, and a store with scripted paths has no `autoSave`. A step that
explains a change is a task the learner does, with `until` waiting for it.
Once `until` is truthy at the hold, interactive mode plays the rest of the
step's range and holds on its last frame, waiting for Next (a hold at the
range's end stays where it is), so a question holds before its explanation: `wait` earlier than
the step's end, the explanation a clip after it, and a wrong answer's
feedback a binding on the store shown during the hold. Hints and "try it"
prompts read the mode (`data-show="$kinetic.mode === 'interactive'"`), so
the video has none of them. `scripts/check.cjs --lesson` in the
skill walks each step and reports its hold (the last frame before its
`wait`) and its `until`.
A lesson page has no renderer runtime tag, and no `data-preview` unless it calls `config({ mode: 'interactive' })`, since under `'auto'` the bar puts it in video mode (KN-158). In interactive mode on a page with
steps KN-132 and KN-143 are off. KN-118 warns about a `data-step` with no
`id` or `data-start`, two steps with one `id`, a step inside a step, two
steps that start together and a first step after 0; KN-157 about `step()` for no element, an `until` or
`follow` store missing at readiness, a `wait` past the range and a settings
entry after 0 in the first step that scripts its path.
Diagnostics print as `[KN-nnn]` (through `wildflower.diagnostic()` with a development build of WildflowerJS, which keeps them in `wildflower.diagnostics`). The ranges are 10x install and the seek
channel, 11x the composition's markup, 12x tracks and eases, 13x inputs,
readiness and audio clips, 14x determinism hazards during a seek, 15x the scene definition,
16x `check()`, 17x seek cost, 18x Lottie and animated images, 19x Trillium and 20x `render()`. KN-100,
KN-120, KN-121, KN-200, KN-201, KN-203 (an audio encoder delay that
cannot be measured), KN-204 (media from another origin) and KN-206 (a
runtime player's frames miss the render's) throw on every build. KN-130, KN-131, KN-133, KN-135,
KN-180 (a Lottie animation's `data_failed`) and KN-181 (an animated image
that cannot be fetched or decoded) print a `console.error` and hold the
render at its readiness timeout on every build. Every other code is a development-only `console.warn`. Each
is listed at /docs/error-codes.