Render anywhere .
Browser → MP4 Blob
Render an MP4 entirely client-side. No server, no uploads.
Server → MP4 file
Render headlessly from Node. Perfect for batch jobs and APIs.
DOM → Live player
Mount a scrubbable 60 fps preview inside any element.
Render an MP4 in the browser.
BrowserRenderer turns a VideoJSON into an MP4 Blob directly in the page — no server round-trips. Cancel mid-render with an AbortController, stream progress, and offload work to a Web Worker to keep the main thread responsive.
✓ Progress callback
Drive progress bars with a per-frame 0 → 1 signal.
✓ AbortController
Cancel a long export cleanly mid-flight.
✓ Worker-accelerated
Off the main thread by default — UI stays snappy.
✓ Full effect & transition parity
All 27 transitions and 42 GLSL effects render via WebGL/WebCodecs.
import BrowserRenderer from '@videoflow/renderer-browser';
const ctrl = new AbortController();
renderBtn.addEventListener('click', async () => {
const blob = await BrowserRenderer.render(videoJSON, {
onProgress: (p) => { progressEl.value = p; },
signal: ctrl.signal,
worker: true,
});
const url = URL.createObjectURL(blob);
downloadBtn.href = url;
downloadBtn.hidden = false;
});
cancelBtn.addEventListener('click', () => {
ctrl.abort();
});Author once. Render everywhere.
Transitions, effects, groups, captions, audio mixing — every primitive renders byte-for-byte the same across the three backends. Preview in the DOM while you author, export an MP4 in the browser when the user clicks Save, queue a deterministic server render for batch jobs.
// 1. Author once
const json = await $.compile();
// 2. Preview live in the DOM
const dom = new DomRenderer(document.querySelector('#video-preview'));
await dom.loadVideo(json);
dom.play();
// 3. Export an MP4 blob in the browser
const blob = await BrowserRenderer.render(json);
// 4. Or queue a deterministic server render
await ServerRenderer.render(json, { output: 'out.mp4' });Render headlessly from Node.
import ServerRenderer from '@videoflow/renderer-server';
await ServerRenderer.render(videoJSON, {
outputType: 'file',
output: './out.mp4',
verbose: true,
onProgress: (p) => process.stdout.write(`\r${(p * 100).toFixed(1)}%`),
});
// → ./out.mp4 — deterministic on every machinePoint the server renderer at a VideoJSON and get an MP4 file on disk — or a Buffer you can stream. By default it encodes entirely inside headless Chromium via WebCodecs + MediaBunny — no ffmpeg dependency required. Pass { ffmpeg: true } to switch to the alternative per-frame ffmpeg pipeline when you need custom encoder flags.
✓ No ffmpeg required
Default pipeline encodes via WebCodecs in headless Chromium. ffmpeg is opt-in.
✓ Deterministic output
The same JSON renders identically on every machine.
✓ Queue-friendly
Ideal for worker queues, scheduled jobs, and CI pipelines.
✓ Fonts & captions
Google Fonts are fetched and embedded at render time.
✓ File or Buffer output
Write to disk, or stream the MP4 to S3 / your bucket of choice.
A live player for preview & scrubbing.
DomRenderer mounts a scrubbable, 60 fps live player inside any host element using a Shadow DOM root for style isolation. Ideal for previews, dashboards, or any interactive experience.
✓ Shadow DOM isolation
No style leaks in or out.
✓ Frame-accurate scrub
renderFrame(n) jumps precisely to any frame.
✓ Audio sync
Audio plays via an HTML element and stays in lock-step with frames.
✓ Powers the editor
The same renderer drives the live preview in @videoflow/react-video-editor.
import DomRenderer from '@videoflow/renderer-dom';
const renderer = new DomRenderer(document.querySelector('#video-preview'));
await renderer.loadVideo(videoJSON);
renderer.play();
// scrub: renderer.renderFrame(120);
// pause: renderer.pause();Two flows, three render targets.
The flows below are authored once and rendered through every backend. Click </> on any showcase to see the source.
Which renderer should I use?
| Use case | Renderer | Why |
|---|---|---|
| User clicks Export in a SaaS app | renderer-browser | No server cost, no upload, MP4 ready instantly. |
| Batch render 10k videos overnight | renderer-server | Run on a queue, deterministic, no ffmpeg dependency by default. |
| API endpoint that returns an MP4 | renderer-server | Streams a Buffer / writes a file on the host. |
| Live preview in an editor or dashboard | renderer-dom | 60 fps scrubbing with frame-accurate seeking. |
| LLM-authored video in an agent loop | renderer-server | JSON in, MP4 out, fully headless. |
| Embed a video player on a marketing page | renderer-dom | Drop-in <Shadow DOM> player with no style leaks. |