WebMotion: deterministic video, composed in the browserSkip to contentDocsGitHub<br>Product of SuperHQ
WebMotion v0.16<br>Browser-native, deterministic video composition
Toggle sound0:00.00SourceExport MP4
Figure 1. A live composition, not a video file. The frame number is drawn by the scene, so scrubbing anywhere keeps it honest.Read the docs →Sourcenpm install @superhq/webmotion
02The one rule
Everything visible is a pure function of the current frame. Nothing reads the wall clock: noDate.now(), no Math.random(), no requestAnimationFrame timestamps. Give the renderer a frame index and it draws exactly one image.<br>That single constraint is what the rest rests on. Seeking is exact because there is no state to wind forward. Frames are cacheable because a frame is determined by its index alone. And the export is trustworthy because the encoder walks frames far faster than wall time without anything drifting, so the MP4 is the preview, pixel for pixel.
03Export throughput
Rendering happens in the tab you are reading this in, so the honest way to report speed is to let you measure it. Each case below builds a composition, exports a real MP4, and reports what your machine managed.<br>CaseFrames per second
Run in this browserNothing measured yet.
04Authoring
A scene is markup. Below is not a sample of what the code looks like; it is the code, and Figure 2 is what it renders. Timing is structure rather than parameters: a shifts the frame origin for its subtree, so nesting them staggers beats with nothing to drift out of sync. Motion is tweens, each covering one property over one frame window. Everything that does not vary with the frame is ordinary CSS.
Figure 2. Rendered from the listing below, which is the same markup.w-composition width="960" height="540" fps="30" duration="130" loop autoplay><br>style><br>w-composition { font-family: -apple-system, sans-serif; }<br>.headline { font: 400 74px -apple-system, sans-serif; color: #e1e1e1; }<br>.subline { font: 400 25px ui-monospace, monospace; color: #a1a1a1; }<br>.divider { background: rgba(255, 255, 255, 0.18); }<br>style>
w-defs><br>w-animation name="in"><br>w-animate property="opacity" from="0" to="1"<br>start="0" end="16" easing="easeOutCubic">w-animate><br>w-animate property="y" from="24" to="0"<br>start="0" end="16" easing="easeOutCubic">w-animate><br>w-animation><br>w-defs>
w-rect x="0" y="0" width="960" height="540" fill="#0f0f0f">w-rect>
w-sequence from="8" label="Title"><br>w-text class="headline" motion="in" x="0" y="196" width="960" align="center"><br>Author in HTML.<br>w-text><br>w-sequence>
w-sequence from="34" label="Line"><br>w-text class="subline" motion="in" x="0" y="300" width="960" align="center"><br>a pure function of the frame<br>w-text><br>w-sequence>
w-sequence from="60" label="Rule"><br>w-el class="divider" x="330" y="368" width="300" height="1"><br>w-animate property="scale" from="0" to="1"<br>start="0" end="22" easing="easeOutCubic">w-animate><br>w-el><br>w-sequence><br>w-composition>
05What is in the box
Declarative elements, , , , . The scene is markup you can read in a diff.<br>A motion specTween windows in local sequence time, named animations, eleven easings plus any cubic-bezier(). The composition rules are written down rather than guessed.<br>Data templating stamps children from JSON with arithmetic placeholders. One scene, many personalised cuts, and no reactivity to reason about.<br>Sound on the same clock lives on the timeline like anything else. Export mixes it sample-exact through an OfflineAudioContext and muxes AAC.<br>3D that obeys the clock plays glTF clips on the frame index: turntables, studio lighting, runtime text on material slots, app-defined TSL shader effects.<br>Live overlaysLiveStage swaps the fixed timeline for event-driven props: OBS browser sources, stream alerts, persistent widgets. Idle cost is zero.
06Start
Add WebMotion to a project you already have, or scaffold the starter, which arrives with a live preview, a zoomable scrub timeline with section labels and an audio lane, and one-click export. Take whichever line fits; the starter already depends on the package.<br>existing projectnpm install @superhq/webmotionCopy command<br>new projectnpx degit superhq-ai/webmotion/template my-videoCopy command<br>for your agentnpx skills add superhq-ai/webmotionCopy command
An agent writing video is working blind: it can author three hundred frames of timing and never see a pixel. The skill teaches the format, andnpx webmotion shoot renders the key frames back as PNGs for the model to read, while npx webmotion lint catches what a contact sheet hides.<br>Read the scenes behind this page →