oxframe vs HyperFrames
Pick oxframe when the video is motion graphics an agent should check and render in seconds without a browser. Pick HyperFrames when the video is a web page: HTML, CSS, GSAP, Lottie or Three.js you already have, rendered in headless Chrome.
At a glance
| oxframe | HyperFrames | |
|---|---|---|
| Language | Rust | HTML, CSS and JavaScript (GSAP, Anime.js, WAAPI, Lottie, Three.js) |
| How a frame is drawn | Native renderer, CPU or GPU | Headless Chrome through Puppeteer, encoded by FFmpeg |
| License | MIT or Apache-2.0 | Apache-2.0 |
| Telemetry | None | Anonymous render telemetry in the CLI |
| Install | Rust and ffmpeg | Node.js 22+ and FFmpeg; Chrome is driven through Puppeteer |
| Timing model | Signals and an async timeline: wait_for, all, markers | data-start and data-duration on elements, plus a paused GSAP timeline |
| Live preview | oxframe dev: timeline, markers, tunables | hyperframes preview with live reload, and Studio |
| An agent sees the frames | oxframe check: storyboard and JSON report, MCP server | hyperframes check, skills and a Claude Code plugin |
| Frame shapes | 16:9, 9:16 and 1:1 from one scene | Resolution presets per project |
| Parallel rendering | render --jobs N, the same bytes for any N | Parallel Chrome workers, about 256 MB each |
| Web content in the frame | No | Anything a page can show |
One scene in both
The scene from the Remotion migration guide, written for HyperFrames as HTML and GSAP: a title that rises in and a counter from 0 to 100 %. Four seconds at 1080p and 30 fps.
HyperFrames
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { width: 1920px; height: 1080px; overflow: hidden; background: #141414; }
#root {
width: 100%; height: 100%; display: flex; flex-direction: column;
align-items: center; justify-content: center; color: white; font-family: sans-serif;
}
#card { width: 100%; height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; }
#title { font-size: 96px; opacity: 0; transform: translateY(60px); }
#line { font-size: 40px; opacity: 0; }
</style>
</head>
<body>
<!-- The Remotion "Release 2.0" scene from /docs/migrate/remotion, as HTML. -->
<div id="root" data-composition-id="main" data-start="0" data-duration="4" data-width="1920" data-height="1080">
<div id="card" class="clip" data-start="0" data-duration="4" data-track-index="0">
<h1 id="title">Release 2.0</h1>
<p id="line">0% faster builds</p>
</div>
</div>
<script>
const tl = gsap.timeline({ paused: true });
tl.to('#title', { opacity: 1, duration: 0.66, ease: 'none' }, 0);
tl.to('#title', { y: 0, duration: 0.8, ease: 'back.out(1.7)' }, 0);
tl.set('#line', { opacity: 1 }, 1);
const percent = { v: 0 };
tl.to(percent, {
v: 100, duration: 2, ease: 'none',
onUpdate: () => (document.getElementById('line').textContent = `${Math.round(percent.v)}% faster builds`),
}, 1);
tl.to({}, { duration: 1 }, 3);
window.__timelines['main'] = tl;
tl.seek(0);
</script>
</body>
</html>oxframe
use oxframe::prelude::*;
#[oxframe::scene]
pub async fn hello(view: View) {
let title = view.add(Txt::new().text("Release 2.0").h1().opacity(0.0).y(-20.0));
// Runs alongside the rest of the scene, like an element that is already mounted.
spawn(async move {
all((
title.opacity().to(1.0, 0.66),
title.y().to(-80.0, 0.8).ease(presets::OUT_BACK),
))
.await;
});
wait_for(1.0).await; // <Sequence from={30}> at 30 fps
let percent = Signal::new(0.0);
let line = view.add(Txt::new().body().y(40.0));
line.text().bind({
let percent = percent.clone();
move || format!("{:.0}% faster builds", percent.get())
});
percent.to(100.0, 2.0).await;
wait_for(1.0).await;
}
pub fn project() -> Project {
Project::new("hello").size(1920, 1080).fps(30).scene(hello())
}Render time
| Tool | Command | Time |
|---|---|---|
| HyperFrames 0.8.185 | npx hyperframes render --fps 30 (the Remotion scene as HTML) | 4.00 s |
| oxframe 0.20.4 | render --cpu | 0.53 s |
| oxframe 0.20.4 | render (GPU) | 1.46 s |
Each time is the whole render command, start to file. oxframe's scene is already compiled;
after a one-line edit, cargo build adds about 0.6 s. On a scene this short the
GPU spends more time starting than drawing, so the CPU renderer wins. The script is bench/vs/measure.sh: run it to time both on your machine.
A page that is filmed, or a scene that is drawn
HyperFrames, from HeyGen, treats a video as an HTML page with a timeline. Elements carry data-start and data-duration, a paused GSAP timeline holds the motion, and the renderer seeks the page frame by frame in headless Chrome before FFmpeg encodes it. Anything a browser can show can be in the video, and an agent that writes web pages already knows how to write one.
oxframe draws the frame itself. A scene is Rust code with signals: a title, a list, a chart, a code block, each a node with properties that animate in an async timeline. There is no page to lay out and no browser to start, so the same scene renders in a fraction of the time and the same code gives the same bytes on every machine.
The trade is plain. HyperFrames wins when the content is web content. oxframe wins when the content is motion graphics, the render runs in CI, and an agent has to check its own frames: oxframe check reports overflowing text, contrast, safe areas and motion that is too fast to read, with the node and the time of each problem.
When to pick HyperFrames
- The video reuses web content: HTML, CSS, Tailwind, Lottie or Three.js.
- Your agent works best in HTML and you do not want a compiled language.
- You want a large catalog of ready blocks and HeyGen in the pipeline.
When to pick oxframe
- Renders should take seconds and run without Chrome, on a laptop or a free CI runner.
- An agent should get a report of what is wrong in the frames, not just a video.
- You want no telemetry at all and byte-identical renders.
- One scene should give 16:9, 9:16 and 1:1.
Moving from HyperFrames
There is no HyperFrames guide yet. The Remotion guide covers the same ideas (a timeline of elements that fade, move and count) and the scene above is the same scene in both.
FAQ
Is HyperFrames open source?
Yes, Apache-2.0, with no per-render fees. oxframe is MIT or Apache-2.0. Both are free for companies; the difference is the renderer and the tooling, not the license.
Does HyperFrames need Chrome?
Yes. Its README says the renderer seeks each frame in headless Chrome and encodes with FFmpeg; it needs Node.js 22+ and FFmpeg. oxframe needs Rust and ffmpeg and no browser.
Which one is easier for an AI agent?
An agent writes HTML more fluently than Rust, which favors HyperFrames on the first draft. oxframe gives the agent a check: a storyboard and a JSON report of what is wrong, with the node and the time, so it can fix a frame without a human looking.
Does oxframe collect telemetry?
No. Neither the CLI nor the SDK sends anything. The browser playground compiles your scene on compile.oxframe.dev; nothing else leaves your machine.
Can oxframe render HTML or Lottie?
No. oxframe draws shapes, text, code, SVG, images, video clips, charts and 3D meshes. For web content, HyperFrames or Remotion is the better fit.
Sources
Checked on October 22, 2026. Found something out of date? Open an issue on oxframe-web.
- HyperFrames on GitHub
- HyperFrames docs
- hyperframes on npm
- oxframe license and what leaves your machine
- oxframe-sdk on GitHub