VideoFlowcodeGitHubTry itCoreRenderersReact Video EditorPlaygroundExamplesDocscodeGitHubTry it
← Back to Blog

The Three-Renderer Rule: Building Unified Video Pipelines with VideoFlow

May 22, 2026 · By VideoFlowLearn how to eliminate pixel drift and reduce server costs by using VideoFlow's three-renderer architecture for unified video pipelines.The Three-Renderer Rule: Building Unified Video Pipelines with VideoFlow

The Three-Renderer Rule: Building Unified Video Pipelines with VideoFlow

For years, building a video-enabled SaaS meant maintaining two entirely different rendering stacks. You’d build a "preview" using HTML5 Canvas or CSS animations for the browser, and then a separate "export" pipeline using FFmpeg shell scripts or heavy After Effects templates on the server.

This fragmentation is the root of "pixel drift"—where the video your user sees in their dashboard doesn't quite match the MP4 they download. It’s a maintenance nightmare that slows down shipping and inflates server costs.

At VideoFlow, we solve this with what we call the Three-Renderer Rule. By decoupling the scene description from the execution environment, you can use the same code to drive a live preview, a browser-side export, and a headless server render—with byte-for-byte identical results.

1. The Portable Source of Truth: VideoJSON

The core of a unified video pipeline is portability. In VideoFlow, your video isn't a sequence of imperative commands or a React component tree; it is a VideoJSON document.

When you use the @videoflow/core builder, you are simply assembling a JSON schema that describes layers, timing, and keyframes. Because this document is plain JSON, it can be saved to a database, version-controlled, or passed between different microservices without losing its meaning. This makes video versioning and diffing as easy as managing any other configuration file.

The VideoFlow render pipeline showing data blocks flowing into a film strip

import VideoFlow from '@videoflow/core';

const $ = new VideoFlow({ width: 1920, height: 1080, fps: 30 });

$.addText({ 
  text: 'Unified Rendering', 
  fontSize: 6, 
  color: '#FF5A1F' 
}).fadeIn('500ms');

$.wait('3s');

// This compiles to a portable JSON object
const videoData = await $.compile();

2. Browser, Server, and DOM: The Three Official Renderers

Once you have your VideoJSON, the Three-Renderer Rule states that you should be able to execute that JSON anywhere. VideoFlow provides three official, Apache-2.0 licensed renderers to handle every stage of the product lifecycle:

The Preview Renderer (@videoflow/renderer-dom)

This is what you use inside your web app. It renders the VideoJSON to a DOM target at a smooth 60 fps. It is frame-accurate and supports scrubbing, making it the perfect engine for internal editors or customer-facing dashboards. You can try it out right now in the VideoFlow Playground.

The Browser Export Renderer (@videoflow/renderer-browser)

When a user hits "Download MP4," you don't necessarily need to spin up a server. This renderer uses WebCodecs to encode the video directly in the user's browser tab. It pushes the heavy lifting to a Web Worker, ensuring your UI stays responsive while generating a high-quality H.264 file with zero server cost.

The Server Renderer (@videoflow/renderer-server)

For batch jobs or automated content factories, the server renderer drives a headless Chromium instance via Playwright. It reuses the exact same rasterization logic as the browser renderers, ensuring that your automated "weekly recap" videos look exactly like the previews your users saw earlier.

A three-up split screen showing the same video frame being rendered in three different environments

3. Eliminating Pixel Drift

Traditional pipelines fail because FFmpeg and HTML5 Canvas handle things like text wrapping, GLSL effects, and blend modes differently. VideoFlow eliminates this by using a unified Motion Engine.

Whether you are applying a bloom effect or a blurResolve transition, every renderer uses the same GLSL shader registry and the same per-layer rasterization pipeline. When you define a transition in our transitions guide, you are defining it for all three environments simultaneously.

How VideoFlow Handles the Pipeline

By adopting VideoFlow, you move away from "stringly-typed" shell commands and toward a structured, typed architecture.

  • @videoflow/core: The builder that produces the VideoJSON.
  • @videoflow/renderer-server: The Node.js solution that renders without needing FFmpeg installed by default (using WebCodecs inside Chromium).
  • @videoflow/renderer-browser: The client-side powerhouse for zero-cost exports.

This architecture is particularly powerful for AI-driven workflows. Because VideoJSON is a structured schema, it is trivial for an LLM to emit a video timeline as data, which your pipeline can then render across any of the three targets.

Start Building Your Pipeline

Stop maintaining separate stacks for preview and export. Build your next video feature on a unified foundation that scales from a single browser tab to a global server cluster.

Explore the VideoFlow Documentation to get started, or dive into the source code on GitHub. If you are building a custom UI, check out the React Video Editor for a drop-in multi-track timeline component.

VideoFlow

Open-source toolkit for composing videos from code.

Product

CoreRenderersReact Video EditorPlayground

Learn

DocsAPI referenceExamplesvs. Remotionvs. FFmpeg

Project

GitHubLicenseContactTermsPrivacy

From the blog

All posts →How to Automate Loom-style Product Demos with TypeScriptAutomated Podcast Audiogram Generator: Turning Audio into Viral Video with TypeScriptHow to Turn Markdown Changelogs into Automated Product Update VideosAutomating Personalized Onboarding Videos with VideoFlow and TypeScriptAutomating YouTube Shorts: Build a Vertical Video Factory in 30 Lines of TypeScriptCinematic 3D Video with TypeScript: A Guide to Perspective and RotationCinematic GLSL Effect Stacking: Building High-End Visuals with CodeDiffable Video: Versioning Your Media Pipeline with VideoJSON
© 2026 VideoFlow. Apache-2.0 core.