The Three-Renderer Rule: Why Your Video Pipeline Needs a Browser, a Server, and a DOM
August 22, 2026 · By VideoFlowLearn why a modern video-as-code architecture requires three distinct renderers for live preview, zero-cost browser export, and headless server automation.
The Three-Renderer Rule: Why Your Video Pipeline Needs a Browser, a Server, and a DOM
Building a video pipeline usually starts with a single question: "How do I turn this data into an MP4?" But as soon as you move beyond simple automation and into building real products—SaaS dashboards, in-app editors, or AI-driven creative tools—that single question becomes a complex architectural challenge.
You don't just need an MP4. You need to show the user what they are building in real-time. You need to let them export that video without waiting for a server queue. And you need a way to render batch jobs at scale in the cloud.
At VideoFlow, we solved this by implementing the Three-Renderer Rule. In this post, we’ll explore why having three distinct, byte-for-byte identical renderers is the secret to a modern video-as-code architecture.

The Problem with Single-Target Rendering
Most video libraries are built for a single environment. FFmpeg is built for the server. Lottie is built for the browser. Remotion is built for React.
When your rendering engine is tied to a specific runtime, you're forced to make compromises. If you use an FFmpeg-based API, your users can't preview their changes without a round-trip to the server. If you use a browser-only library, you're stuck when you need to generate 10,000 personalized videos in a background job.
VideoFlow's core philosophy is that the VideoJSON is the source of truth. Because our scenes are portable JSON documents, we can render them anywhere.
1. The DOM Renderer: Frame-Accurate Live Preview
For any application that includes a user interface—like an embeddable video editor—the first requirement is a live preview.
@videoflow/renderer-dom is designed for this exact purpose. It doesn't encode video; it renders the VideoJSON directly to a DOM target at a fluid 60 fps. It allows for frame-accurate scrubbing, playback, and real-time property updates.
When a user moves a slider in the VideoFlow Playground, the DOM renderer updates the scene instantly. There is no encoding overhead, no lag, and no server cost.
2. The Browser Renderer: Zero-Server-Cost Export
Once the user is happy with their creation, they need to download the MP4. Traditionally, this meant uploading the project to a server, waiting in a queue, and paying for cloud compute.
With @videoflow/renderer-browser, we use the WebCodecs API to encode the MP4 directly in the user's browser tab. We've written before about how this enables zero-server-cost video rendering, and it remains one of VideoFlow's most powerful features.
import BrowserRenderer from '@videoflow/renderer-browser';
import VideoFlow from '@videoflow/core';
const $ = new VideoFlow({ width: 1920, height: 1080, fps: 30 });
$.addText({ text: 'Client-Side Export' }).fadeIn('500ms');
$.wait('2s');
const json = await $.compile();
const blob = await BrowserRenderer.render(json);
This renderer runs inside a Web Worker, ensuring the UI stays responsive while the video encodes. It’s the ultimate way to scale your video features without scaling your infrastructure bill.
3. The Server Renderer: Headless Automation
There are times when the browser isn't enough. Maybe you're building a YouTube Shorts factory that generates videos on a cron job, or a SaaS that emails personalized recaps to users every Monday morning.
@videoflow/renderer-server brings the same rendering engine to Node.js. It uses Playwright to drive a headless Chromium instance, ensuring that the visual output is identical to what the user saw in the preview.

Crucially, VideoFlow renders on the server without an ffmpeg dependency by default. We use a specialized muxing layer called MediaBunny inside the browser to produce the MP4. This makes deployment to serverless environments like AWS Lambda or Vercel Functions significantly easier.
import ServerRenderer from '@videoflow/renderer-server';
// Render to a buffer for S3 upload
const buffer = await ServerRenderer.render(videoJSON, {
outputType: 'buffer',
onProgress: (p) => console.log(`Progress: ${p * 100}%`)
});
Why Identity Matters
The "Rule" isn't just about having three packages. It's about identity.
If you use a transition like blurResolve or an effect like chromaticAberration, it must look exactly the same in the DOM preview, the browser export, and the server render.
VideoFlow achieves this by sharing the same GLSL shader library and layout engine across all three renderers. Whether you are using @videoflow/core to build a scene or building a custom integration, you can trust that what you see is what you get.
Conclusion: Choosing Your Renderer
A modern video pipeline shouldn't be a monolith. By decoupling the scene definition (VideoJSON) from the rendering environment, VideoFlow gives you the flexibility to choose the right tool for the job:
- Building an editor? Use the DOM renderer for the canvas.
- Saving on cloud costs? Use the Browser renderer for user exports.
- Automating at scale? Use the Server renderer for background jobs.
Ready to see the Three-Renderer Rule in action? Head over to our documentation to get started, or explore the VideoFlow GitHub repository to see how it's built.