Skip to content

superhq-ai/webmotion

Repository files navigation

WebMotion: deterministic video composition, rendered entirely in the browser

npm version license

WebMotion is a browser-native alternative to Remotion. No headless Chrome, no FFmpeg, no render farm: compose in the DOM or on a canvas, encode with WebCodecs, and download an MP4, all client-side.

It rests on one rule: everything visible is a pure function of the current frame. Seeking to frame N always produces the same image, whether it's the first frame rendered or the ten-thousandth, in preview or in export. That is what makes rendering seekable, cacheable, and frame-accurate without a server.

Install

npm install @superhq/webmotion

Write video in HTML

Import the elements entry once and the scene is just markup:

<script type="module">
  import "@superhq/webmotion/elements";
</script>

<w-composition width="1280" height="720" fps="30" duration="150" autoplay>
  <w-defs>
    <w-animation name="fade-up">
      <w-animate property="opacity" from="0"  to="1" start="0" end="18" easing="easeOutCubic"></w-animate>
      <w-animate property="y"       from="40" to="0" start="0" end="18" easing="easeOutCubic"></w-animate>
    </w-animation>
  </w-defs>

  <w-rect x="0" y="0" width="1280" height="720" fill="#0d101b"></w-rect>

  <w-sequence from="12">
    <w-text motion="fade-up" x="0" y="250" width="1280" align="center"
            font="700 96px system-ui" color="#f5f6f8">Author in HTML.</w-text>
  </w-sequence>
</w-composition>

A <w-sequence from duration> shifts the frame origin for its subtree; a <w-animate> is one tween of one property over a frame window, pure function of the local frame, so the live preview and the exported video are pixel-for-pixel the same scene. Tweens can be written inline as children for one-offs, or defined once in <w-defs> and applied by name with motion="...", class-like. The full rules (scoping, ordering, staggering through sequences) are in the motion spec. Repetition is declarative too: <w-for> stamps templated children from <w-data> JSON with {path + arithmetic} placeholders (template spec); sound is <w-audio> on the same timeline (audio spec).

The element drives itself:

const comp = document.querySelector("w-composition");
comp.play();
comp.seek(42); // deterministic: always the exact same image
const blob = await comp.export(); // MP4, encoded in the browser

Or write video in TypeScript

The programmatic API underneath is a small component contract: renderFrame receives a frame index and draws.

import { Composition, Runtime, Layer, Sequence, CanvasRenderer, interpolate, Easing } from "@superhq/webmotion";

const composition = new Composition({ width: 1280, height: 720, fps: 30, durationInFrames: 180 });

class Title {
  mount() {}
  renderFrame({ ctx, frame, width, height }) {
    ctx.globalAlpha = interpolate(frame, [0, 20], [0, 1], { easing: Easing.easeOutCubic, extrapolateRight: "clamp" });
    ctx.fillStyle = "#fff";
    ctx.font = "600 84px system-ui";
    ctx.textAlign = "center";
    ctx.fillText("WebMotion", width / 2, height / 2);
  }
  destroy() {}
}

const runtime = new Runtime({
  composition,
  renderer: new CanvasRenderer(1280, 720, { canvas }),
  layers: [new Layer({ component: new Title(), sequence: new Sequence({ from: 20 }) })],
});

await runtime.renderFrame(30); // draws exactly frame 30, every time

Prefer real DOM over canvas drawing? The @superhq/webmotion/html-in-canvas backend renders live HTML and rasterizes it per frame. It is named after, and tracks, the WICG html-in-canvas proposal: today a foreignObject rasterizer stands in as the polyfill, and the native APIs take over when browsers ship them. See the architecture notes for that and everything else.

Demos

Live: superhq-ai.github.io/webmotion

Or run locally:

git clone https://github.com/superhq-ai/webmotion && cd webmotion
npm install
npm run demo

Two launch-grade films, each authored entirely as markup with the source shown alongside: a keynote-style launch film (staged beats, letter-tracked reveal, generated imagery) and a stats film with deterministic count-up counters built on a custom component. Scrub, play, and export real MP4s in-browser. Needs a Chromium-based browser (WebCodecs H.264 and OffscreenCanvas).

AI skill

skills/webmotion/ is an installable agent skill that teaches AI coding agents to author WebMotion scenes: the element reference, motion rules, styling guidance, export wiring, and launch-film recipes with pacing craft.

Install with the skills CLI (works with Claude Code, Cursor, Copilot, and 15+ other agents):

npx skills add superhq-ai/webmotion

Or copy the folder directly for Claude Code:

npx -y degit superhq-ai/webmotion/skills/webmotion ~/.claude/skills/webmotion

Then ask for a video ("make me a 10 second launch film for X") and the agent knows the format.

Development

npm test           # unit tests (Node, no browser needed)
npm run typecheck
npm run build      # tsc -> dist/

License

MIT. The HTML rasterizer is a derivative of MIT-licensed work by repalash; see CREDITS.

About

Browser-native, deterministic video composition

Resources

License

Stars

2 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors