Page API
What the renderer gives a page and what it reads from a page, from window.vawe to meta tags and data attributes.
This page lists the page APIThe page API is the window.vawe object that the renderer sets before your scripts run: aspect, width, height, fps, duration, onFrame and more.: what the renderer sets before your scripts run, and what it reads from your markup. The sources are harness/media/render-page.mjs, core/engine/page-seek.js, core/engine/page-api.js and harness/media/page-audio.mjs. For the idea behind it, read The page and Time and seek.
window.seek
Define window.seek(t) when the page paints in script. t is the film time in seconds and can be fractional. Paint frame t as a pure function of t. A promise that you return is awaited, so a texture can decode before the screenshot (core/engine/page-seek.js).
For each seek, the renderer does these steps in order:
- Wait for the page to be ready: no image decode,
fetchor font load is pending. - Set the virtual clockThe virtual clock is the code in core/engine/page-clock.js that controls Date, requestAnimationFrame, timers and Math.random during a render. to
t. - Call
window.seek(t)if the page defines it. - Pause every CSS, Web Animation and SVG animation and set its time to
t. - Call every
vawe.onFramehook.
window.vawe
The renderer sets these before any page script runs (installPageFrame, core/engine/page-seek.js).
| Name | Type | What it is |
|---|---|---|
vawe.aspect | string | The aspect of this render, for example "16:9" |
vawe.width, vawe.height | number | The CSS viewport in px. Always the full aspect size, also in a draft |
vawe.fps | number or undefined | The value of <meta name="fps">. It is the rate of your frame table, not the render rate |
vawe.duration | number or undefined | The value of <meta name="duration">. For auto, the length that the render measured |
vawe.onFrame(fn) | function | Register a hook fn(t) that runs after each seek. It may return a promise |
vawe.animationEnd() | function | { endS, infinite }: the end of the last animation. The renderer uses it to size an auto page |
One module adds more names. Import it from films/<name>/page.html as a module script:
<script type="module">
import '../../core/engine/page-api.js';
</script>It adds these names to window.vawe (core/engine/page-api.js):
| Name | What it does |
|---|---|
vawe.value(row, t) | Sample one timing row { at, dur, from, to, ease } as a number. ease is a CSS keyword or a name in core/motion/easings.js. An unknown name throws and lists the valid ones |
vawe.assert(t, fn, message) | The renderer runs fn after it seeks to t, at dev and ship. A falsy or throwing fn stops the render with exit 2, the time and message |
vawe.clock | The virtual clock, window.__pageClock |
vawe.three | The three.js helpers studio, extrude and material from core/three/index.js |
CSS variables and the html element
| Name | Set on | What it is |
|---|---|---|
data-aspect | <html> | The aspect of this render. Use it in selectors, for example [data-aspect="9:16"] h1 |
--vw | :root | The viewport width as a length, such as 1920px |
--vh | :root | The viewport height as a length, such as 1080px |
--ease-<name> | :root | The named eases as CSS linear() curves |
--vw and --vh hold a unit. Write calc(var(--vh) * 0.11), never * 0.11px. The named eases are land, land-soft, settle, swap, glide, carry, leave, launch, pop and nudge (EASE_HANDLES in core/motion/presets.js). A plain browser does not set them, so a page that uses them shows its end state there.
The canvas sizes are 16:9 1920x1080, 9:16 1080x1920, 1:1 1080x1080, 4:5 1080x1350 and 4:3 1440x1080. Any other ratio fits the long edge to 1920 (core/layout/aspects.js). See Aspect ratios.
Meta tags
The renderer reads these before the page loads, from the file. harness/lib/page-meta.mjs finds <meta name="..." content="...">.
| Meta | Value | What it does |
|---|---|---|
duration | seconds, or auto | The lengthThe duration is the film length in seconds, set by <meta name="duration" content="12.4">.. auto is the end of the last finite move plus a hold. See harness/media/page-duration.mjs |
aspect | W:H | The aspect when no --aspect flag is given. Default 16:9 |
fps | number | The rate of your frame table. The render rate is separate: 30 for a draft, 60 for a final |
message | text | The one thing to rememberThe message is the one thing that a viewer must remember, set by <meta name="message">.. The text checks read it |
spectacle | seconds | The second of the one big moment, the spectacleThe spectacle is the second of the one big moment in a film, set by <meta name="spectacle" content="6.2">.. Put quiet before it |
signature | band=...; ease=...; stagger=...; seam=...; palette=...; thread=... | The six dials of the film. The motion presets use band, ease and stagger as defaults, and dev reads all six (harness/lib/signature.mjs) |
loudness | LUFS number | Normalise the mix to this target. Without it, the mix is as written (harness/media/page-audio.mjs) |
loop | true | The loop-seam check compares the last frame with the first (quality/gates/page-check.mjs:378) |
blank | 0-0.4, 4.8-5 | Declare the seconds where an empty frame is intended. data-blank on <html> does the same (render-page.mjs:665) |
data attributes
On the page
| Attribute | On | What it does |
|---|---|---|
data-world="<id>" | an element | Marks one worldA world is the one element that holds one beat of the film, marked with data-world="<id>".. Lowercase id. frames, strip --cuts, the checks and data-on read it |
data-chrome | an element | Text inside is product UI shown as texture. The cap floor is 2.5% and it has no read hold |
data-ui | an element | Text inside is UI that is the subject. The cap floor is 3% |
data-texture="<why>" | an element | Real texture, with a reason. The reason needs at least 12 characters (taste/rules/readable-text-size.md) |
data-look="product" | <html> | The motion lint treats the page like data-chrome: uniform motion (harness/lib/motion-lint.mjs:53) |
Text inside aria-hidden="true" is also texture, and the text checks skip it.
On an audio tag
page-audio.mjs reads these from every <audio> element. The mix is offline and as written. See Audio and Fonts and sounds.
| Attribute | What it does |
|---|---|
src | The file, relative to the page. A <source> child also works |
loop | Marks the music bedA bed is a music track that plays under the whole film, marked by the loop attribute on an <audio> tag. (role music) |
data-synth="<name>" | A built-in voiceA voice is one of the built-in synth sounds, such as pluck or whoosh, chosen with data-synth="<voice>". instead of a file |
data-at="<s>" | The second where the cueA cue is one sound at one second, written as an <audio> tag with data-at. starts. Default 0 |
data-on="world:<id>" | data-at counts from the first second world <id> shows. It needs the page seek |
data-gain="<dB>" | The absolute level. It replaces the default of a voice |
data-fade-in, data-fade-out | Fade seconds. Default 0 |
data-trim, data-trim-end | Play the seconds data-trim to data-trim-end of the file |
data-role="vo" | A voice-over. It ducksTo duck is to lower the music while a voice speaks. the music by 18 dB while it plays |
data-length="<s>" | The seconds of the move, for the voices air and swoosh-long |
data-duck="<dB>" | Duck the music by this many dB while this track plays |
What a page may not do
The virtual clock owns Date, performance.now, requestAnimationFrame, setTimeout, setInterval and Math.random. Each one is a function of the seek time. Math.random restarts from the seek time on every seek, so the same t gives the same numbers (core/engine/page-clock.js). Keep no state between frames. See Determinism.
A module-level await of anything but an image decode, a fetch or document.fonts.ready is not tracked. Frame 0 can paint before your vawe.onFrame exists. Await those three, or register the hook first and await inside it.
A rule that you break on purpose goes into <script type="application/json" id="authoring">. See Waivers.
From the blogHTML to video format: the page contract · GSAP to MP4: export a timeline as video · Seed Math.random and freeze Date.now in JavaScript