To convert an HTML/CSS animation — including one Claude generated — to MP4, render it headlessly instead of screen-recording it: a headless Chrome instance drives the page's clock, captures each frame at an exact timestamp, and FFmpeg stitches the frames into video. That makes the output frame-perfect and identical on every run. The one-command path is htmlrec:
brew install dsplce-co/tap/htmlrec ffmpeg
hrec render animation.html -o out.mp4
Defaults: 1280×720, 30fps, 5s, MP4. Formats: MP4, WebM (VP9, optional alpha), and MOV (ProRes 4444, alpha). Override resolution and timing with --width, --height, --fps, and --duration, and add --transparent for an alpha channel.
So you asked Claude to animate something. Maybe a logo, a loading screen, a data viz. It spat out a neat HTML file with CSS keyframes, everything looks crisp in the browser — and now you need it as an MP4.
The obvious approach is screen recording. Open QuickTime or OBS, hit record, play the animation, stop, trim. Works, kind of. Except it's not frame-perfect. If your machine lags for half a second, that lag is baked into the video. The animation runs at whatever speed your CPU felt like that afternoon. Completely non-deterministic. And the moment you tweak something — wrong colour, timing off by 200ms — you're setting the whole thing up again, which is just tiring. Not to mention that every time you hit record you start at a slightly different frame, so swapping the asset in your video editor becomes a pain because nothing lines up the same way twice.
There's a better way.
You can use htmlrec — a CLI tool that renders HTML animations to video frame by frame, without touching your screen. It controls the browser clock directly, so every frame is captured at exactly the right moment regardless of your machine's load. Pixel-perfect, every single time.
Install it with:
brew install dsplce-co/tap/htmlrec ffmpeg
How do I convert an HTML/CSS animation to MP4?
The reliable way to convert an HTML animation to video is to render it headlessly, frame by frame, instead of screen-recording it. Point a tool at your HTML file, let it drive the browser clock, and capture each frame at an exact timestamp:
hrec render animation.html -o out.mp4
This works for any self-contained HTML/CSS animation — a logo reveal, a loading screen, a chart, or anything an LLM like Claude generated for you. The full step-by-step is below.
The workflow
1. Get your animation from Claude (skip if you already have an HTML animation)
Ask Claude for whatever you need. Something like:
"Create an HTML/CSS animation of a logo appearing with a fade and slight upward motion, black background, 3 seconds"
You'll get back a self-contained HTML file. Save it — let's call it animation.html.
2. Render it
hrec render animation.html -o out.mp4
That's it. By default you get a 1280×720, 30fps, 5-second MP4.
3. Adjust if needed
Custom resolution and duration:
hrec render animation.html -o out.mp4 --width 1920 --height 1080 --duration 3 --fps 60
Need transparency (for overlaying on other footage)?
hrec render animation.html -o out.webm --transparent
WebM with VP9 preserves the alpha channel. Works with .mov (ProRes 4444) too if you're in a video editing pipeline.
Example
Here's a minimal animation Claude might generate:
<!DOCTYPE html>
<html>
<head>
<style>
body { margin: 0; background: #000; display: grid; place-items: center; height: 100vh; }
.logo {
font-family: sans-serif;
font-size: 64px;
color: #fff;
opacity: 0;
transform: translateY(20px);
animation: appear 1s ease forwards;
}
@keyframes appear {
to { opacity: 1; transform: translateY(0); }
}
</style>
</head>
<body>
<div class="logo">dsplce</div>
</body>
</html>
Render it:
hrec render animation.html -o logo.mp4 --duration 2
Clean MP4, no screen recording, no lag, no manual trimming.
The whole point of htmlrec is to remove the friction between "Claude gave me an animation" and "I have a video file I can actually use." One command, done.
If you're generating HTML assets regularly — ad creatives, onboarding animations, motion graphics for social — this becomes part of your pipeline rather than a manual step every time. Turning something an AI generated into a deterministic, repeatable artifact you can actually ship is the same instinct we bring to whole products — it's the idea behind taking an AI prototype to production.
Source and docs: github.com/dsplce-co/htmlrec. More about htmlrec on our site, alongside the rest of our open-source work.
How do I convert a CSS animation to MP4?
CSS keyframe animations render to MP4 exactly like everything else — there's nothing special to configure. As long as the motion is driven by CSS animations (@keyframes, transition, animation), a headless renderer captures it deterministically. Match the duration to your animation and you're done:
hrec render animation.html -o out.mp4 --duration 3
The default is 30fps; pass --fps 60 for extra-smooth fast motion when your animation needs it. Either way the frames come from the browser's own clock, so a 3-second animation is exactly 3 seconds of video — no drift, no dropped frames.
Is the output deterministic (including in CI)?
"Deterministic" is the whole point: the same HTML always produces the same video, regardless of what your machine was doing while it rendered. A screen recorder can't promise that — it captures in real time, so any hiccup is baked into the file. A headless renderer steps the page forward one frame at a time and grabs each frame at a precise timestamp, then hands the sequence to FFmpeg:
hrec render animation.html -o out.mp4
That determinism is what makes this practical in a real pipeline. Tweak a colour or a timing value, re-render, and only the parts you changed change — the rest of the frames are identical to last time. Swapping the clip into a video editor lines up perfectly every time because nothing is recorded "live."
The same property makes it CI-friendly: it runs headless with no display, so the identical hrec render command produces the identical video on a build server as it does on your laptop — install Chromium and FFmpeg on the runner and wire it into your pipeline.
That same instinct — do the rigorous version, not the flaky one — is what separates an AI-built demo from an AI-built product. A demo comes together astonishingly fast; making it hold up under real users and constant change is the actual work. If you're staring at an AI-built app that won the demo and now fights every change, taking it the last mile to production is exactly what we do.
Do you need a framework like HyperFrames?
Short answer: it depends on how much you're building.
There's a growing category of open-source tools that turn HTML into video. HeyGen recently open-sourced HyperFrames, a renderer that converts HTML to video and is positioned as "built for agents" — meant to be driven programmatically inside LLM workflows. Under the hood it's the same core idea as the approach here: a headless browser renders the page and FFmpeg encodes the frames, deterministically. It runs locally (Node 22+ and FFmpeg) — there's no hosted service or signup.
So the real question isn't "platform vs. local tool" — both run on your machine. It's scope. HyperFrames is a larger Node framework: it ships adapters for GSAP, Lottie, and Three.js plus a timeline model for composing more complex, programmatic animations. If that's the kind of thing you're building, a framework that size earns its keep.
But for the common case — you already have a self-contained HTML/CSS animation and you just want a clean MP4 — you don't need a framework at all. The job is two well-understood pieces:
- Headless Chrome renders the page and steps the animation clock forward frame by frame.
- FFmpeg stitches those frames into a video.
That's exactly what htmlrec is: a single-purpose Rust CLI wrapping those two. Point it at an HTML file, get a deterministic MP4 — one command, nothing to compose, frame-perfect.
How to convert a Claude animation to MP4
hrec render animation.html -o out.mp4
MP4 is the safest choice for most use cases — universally supported, small file size, plays everywhere. No extra flags needed.
How do I convert a Claude animation to WebM?
hrec render animation.html -o out.webm
WebM is a good fit if you're embedding the animation on the web. Smaller than MP4 at comparable quality, and supported natively in Chrome, Firefox, and Edge (Safari's VP9 support is patchier, so test there).
How do I get a transparent (alpha) video from an HTML animation?
hrec render animation.html -o out.mov --transparent
MOV with ProRes 4444 is the most reliable format for transparency — virtually every video editor (Premiere, After Effects, Final Cut) handles it without issues.
WebM also supports an alpha channel:
hrec render animation.html -o out.webm --transparent
But in practice, a lot of editing software either doesn't support WebM at all, or silently drops the alpha channel when importing it. If you're taking the file into a video editor, stick with MOV.
Still, if you're embedding the animation directly on a web page rather than taking it into an editor, transparent WebM is a strong option — Chrome and Firefox handle it natively and the file size is a fraction of MOV. Safari's support for alpha-channel WebM is unreliable, though, so don't count on it there.
FAQ
How do I get a transparent (alpha) video from an HTML animation?
Add --transparent and pick an alpha-capable container: hrec render animation.html -o out.mov --transparent gives MOV (ProRes 4444), the most reliable in video editors, and -o out.webm --transparent gives VP9 with alpha for the web. Using --transparent with an .mp4 is rejected, because H.264 has no alpha channel. Many editors silently drop WebM's alpha on import, so prefer MOV for Premiere, After Effects, or Final Cut.
Can I set a custom resolution and frame rate?
Yes. --width, --height, and --fps override the defaults of 1280×720 at 30fps — e.g. hrec render animation.html -o out.mp4 --width 1920 --height 1080 --fps 60. Match --duration to your animation's length so nothing is cut off or padded.
What about long animations?
Set --duration to the real length in seconds; the default is 5. Frames are captured by stepping a virtual clock rather than playing back in real time, so a longer animation simply means more frames — not a longer wait tied to playback speed.
Does it work headless in CI?
Yes. It drives headless Chromium and shells out to FFmpeg with no display, so the same hrec render command runs in a CI container once Chromium and FFmpeg are installed on the runner. Because capture is clock-driven rather than real-time, the video is identical on every run regardless of CI load.
What about fonts and external assets?
Make the animation self-contained — inline the CSS, embed fonts, and base64 or co-locate images — so the headless browser renders exactly what you saw. A web font that hasn't finished loading when the first frame is captured falls back to a system face, so embed or preload anything the animation depends on.
Top comments (0)