Generate an MP4 from a React component
Render a React component to a deterministic MP4. The trick is treating time as a prop, not a side effect.
There are two questions hiding inside "render React to MP4." The first is mechanical — how do you get pixels out of a React tree into a video file? The second is conceptual — how do you write a React component that is renderable in the first place? The mechanical answer is short. The conceptual one is the whole job.
Time as a prop
A React component that renders the same output for the same props is a pure function of its props. To render it to video, make time one of those props:
function HeroCard({ t, title, subtitle }: { t: number; title: string; subtitle: string }) {
const ease = (u: number) => 1 - Math.pow(1 - Math.min(1, u), 3);
const titleY = (1 - ease(t / 0.8)) * 40;
const subY = (1 - ease((t - 0.3) / 0.8)) * 30;
return (
<div className="hero">
<h1 style={{ transform: `translateY(${titleY}px)`, opacity: ease(t / 0.8) }}>{title}</h1>
<p style={{ transform: `translateY(${subY}px)`, opacity: ease((t - 0.3) / 0.8) }}>{subtitle}</p>
</div>
);
}That's the whole conceptual shift. t is a number, not a clock. The component renders the same DOM for t = 1.5 every time. No useEffect, no setInterval, no transition, no animation — all of those bind to wall time.
The render path
Once the component is t-driven, the path to MP4 is mechanical:
- Serve the component. A Next.js page route that reads
tfrom a query param (/render?t=0.5) works. So does a static HTML file withrender(t)exposed onwindow. - Open in headless Chromium. Load the page once. Wait for fonts.
- Seek and capture. For each frame index
iin0..N, sett = i / fps, wait one paint, screenshot. - Encode. Feed the frames to an MP4 muxer.
A Next.js project organizes the first step as a route group:
// app/render/[scene]/page.tsx
"use client";
export default function Scene({ searchParams }) {
const t = Number(searchParams.t ?? "0");
return <HeroCard t={t} title="HyperFrames" subtitle="Write HTML, render MP4." />;
}The component is now reachable at /render/hero?t=0.5 and the renderer points at that URL.
Where React doesn't help
A few things to avoid:
useEffectfor animation. If the effect runs once per mount and starts asetInterval, you've reintroduced the wall clock.framer-motiondefaults. They're great for product UIs and wrong for deterministic video. Either useframer-motion's explicittimeAPI or skip it.useStatefor animated values. If a value is purely a function oft, computing it inline is simpler and faster than storing it in state.
In practice, you write less React than you'd expect — the component becomes mostly markup and math, not effects and state.
Why bother
The win is that your video is your component. The same source that powers the live preview on your marketing page can be rendered to MP4 for an ad, a social card, an in-app intro. No second representation, no AE handoff, no .json file that someone else owns.
The second win is testing. A React testing-library snapshot at t = 0, t = 1, t = 2 catches motion regressions the same way any other snapshot catches DOM regressions. Try doing that with an After Effects file.
The longer argument is in HTML is the next video codec. The mechanics of frame capture are in from DOM to MP4. For the Next.js-route flavor specifically, see render video from a Next.js route.
The headline
Make t a prop. Everything else falls out of that one decision: determinism, caching, CI-renderability, source-controllability, testability. The components you write under that constraint look slightly different from product UI components — they have more math, fewer effects, and no transitions — but they are still React. They're just React you can render.
Cite this postBibTeX · APA · Markdown
@misc{tanaka2026generate,
author = {Kira Tanaka},
title = {Generate an MP4 from a React component},
year = {2026},
url = {https://hyperframes.video/blog/generate-mp4-from-react-component},
note = {HyperFrames blog}
}Kira Tanaka. (2026, May 19). Generate an MP4 from a React component. HyperFrames. https://hyperframes.video/blog/generate-mp4-from-react-component
[Generate an MP4 from a React component](https://hyperframes.video/blog/generate-mp4-from-react-component) — Kira Tanaka, 2026
Kira works on the render core: headless Chromium scheduling, frame capture, and the encoder pipeline. She cares about reproducible builds and small numbers next to the word "variance."
Programmatic video generation in Node.js
A walkthrough of generating MP4s from a Node.js process — headless Chromium, frame capture, encoding, and the pitfalls to avoid.
Recording video with Puppeteer (and what to use instead)
Puppeteer can record video — sort of. Here's the screencast API, its limits, and the deterministic alternative for real production work.
How to convert HTML to MP4 programmatically
An end-to-end recipe for turning a static HTML file into a deterministic MP4 — no timeline tool, no manual export, no headless-Chrome plumbing.
Building with HyperFrames? Come hang out.
We're on GitHub, in Discord, and the playground is one click away. Bring weird ideas — we collect them.