What Is HyperFrames?
HyperFrames is a free, open-source framework from HeyGen that turns HTML, CSS, media and seekable animations into MP4 video. You describe a video as an ordinary HTML page with a few timing attributes, and the renderer opens it in headless Chrome, captures it one frame at a time and encodes the result with FFmpeg. The project's own tagline is three short sentences: "Write HTML. Render video. Built for agents."
The last sentence explains the attention. HeyGen published the repository in March 2026 under the Apache 2.0 license, and it passed 70,000 GitHub stars in under eight months. Coding agents such as Claude Code, Codex and Cursor already write HTML well, so a video format that is just HTML is one they can produce without learning an editor. HyperFrames adds agent skills that teach them its rules, a CLI that never stops to ask questions, and a catalog of about 450 ready-made blocks.
It works without an agent too. Four commands scaffold a project, preview it and render it:
npx hyperframes init my-video
cd my-video
npx hyperframes preview
npx hyperframes renderYou need Node.js 22 or newer and FFmpeg. HeyGen says it uses HyperFrames in production, and the README lists tldraw and TanStack among the teams with community examples.
A Video Is an HTML File With Timing Attributes
A HyperFrames composition is a normal HTML file. The root element names the composition and fixes its size, and every element that appears on screen gets a start time, a duration and a track:
<div id="stage" data-composition-id="launch" data-start="0" data-width="1920" data-height="1080">
<video class="clip" data-start="0" data-duration="6" data-track-index="0" src="intro.mp4" muted playsinline></video>
<h1 id="title" class="clip" data-start="1" data-duration="4" data-track-index="1">Launch day</h1>
<audio data-start="0" data-duration="6" data-track-index="2" data-volume="0.5" src="music.wav"></audio>
</div>That says when things are on screen. How they move is left to an animation library. The README example creates a GSAP timeline in a paused state and registers it on the page:
const tl = gsap.timeline({ paused: true });
tl.from("#title", { opacity: 0, y: 40, duration: 0.8 }, 1);
window.__timelines = window.__timelines || {};
window.__timelines.launch = tl;GSAP is the default, but the runtime also seeks CSS animations, the Web Animations API, Lottie, Three.js, Anime.js and TypeGPU, and an experimental FrameAdapter interface lets you plug in anything else that can jump to a given frame. There is no build step: index.html plays as it is, so you can open a composition in a browser and inspect it with the same devtools you use for any web page.
The same file can target any shape. hyperframes init takes resolution presets for landscape (1920x1080), portrait (1080x1920), square and their 4K versions. If one idea has to become a YouTube video, a Short and a square post, an aspect ratio calculator gives you the matching dimensions before you lay anything out.
Seek, Never Play: Why the Same Input Gives the Same Frames
The design decision that matters most is stated in the project's determinism docs: rendering never plays your video. A screen recorder captures whatever happens on screen as time passes, so a slow frame becomes a dropped frame. HyperFrames asks for one frame at a time instead. For frame 90 at 30 fps it works out the time with integer math (floor(frame) / fps, never a clock), seeks every registered animation to exactly that moment, grabs the pixels in one atomic operation through Chrome's HeadlessExperimental.beginFrame, and passes the frame to FFmpeg.
Because the only thing that changes between frames is the frame number, the same composition produces the same video on every run. That is what makes it usable in CI, in regression tests and in pipelines where an agent edits a file and renders again. It also means an expensive scene never stutters in the output. The docs put it plainly: a composition that stutters in preview still renders perfectly, it just takes longer.
The guarantee comes with rules, and the docs list them:
- No wall clock. No
Date.now(), norequestAnimationFrame, no system timers. - No unseeded randomness.
Math.random()without a seed gives a different frame every run. - No fetching mid-render. Every asset loads before the first frame.
- Fixed output size. Frame rate, width and height are locked before frame 0.
- A finite length. Every composition has a known end.
One caveat is about machines rather than code. Fonts and Chrome builds differ between computers, so a local render can shift by a pixel from one machine to the next. npx hyperframes render --docker pins the Chromium version, the font set and the FFmpeg encoder when you need identical output everywhere.
We Rendered a Title Card: 3.7 Seconds, Byte-Identical Twice
To test the determinism claim, we rendered the three-second title card from HyperFrames' own Remotion comparison guide: a white "HELLO" on near-black that fades in over half a second, holds, and fades out, at 1280x720 and 30 fps. The machine was an Apple M5 MacBook with 16 GB of memory, Node.js 24 and FFmpeg 9, running HyperFrames 0.8.188 on 23 October 2026.
hyperframes initscaffolded the project in 0.5 seconds.- The first render took 87 seconds of wall time, mostly one-time setup. The CLI reported 6.4 seconds for the render itself.
- The second render took 3.7 seconds (4.6 seconds of wall time): 1.0 second of setup and 2.4 seconds capturing 90 frames, with encoding running alongside the capture.
- The output was a 16.2 KB H.264 MP4: 1280x720, 30 fps, 90 frames.
- The two files were byte-identical. The whole MP4 had the same MD5, and so did every one of the 90 frames (32 distinct images across the fade in, the hold and the fade out).
The renderer also labels what it writes. ffprobe shows two container metadata keys, hyperframes_renderer and hyperframes_version, and nothing about the project itself. They are not a watermark, and ffmpeg -i out.mp4 -map_metadata -1 -c copy clean.mp4 strips them.
A title card is the easy case. A composition with video clips, audio, shaders and dozens of layers takes far longer per frame, and the project's performance guide shows one CSS declaration moving a 300-frame 1080p render from 25.0 seconds to 9.8. The property that matters, the same input giving the same output, held exactly.
The One Line That Turns a Page Into a Video
The comparison guide warns that HyperFrames "breaks quietly" if you skip its rules, so we tested the easiest rule to forget: registering the timeline on window.__timelines. We deleted those two lines from the title card and rendered it again.
hyperframes lint caught the mistake straight away, with two errors (missing_timeline_registry and gsap_timeline_not_registered) and the fix printed underneath. hyperframes render reported the same errors and carried on anyway. It waited 45 seconds for a timeline that was never coming, then finished in 48.8 seconds with a three-second video in which all 90 frames were the same image: an empty dark background, because the title starts at zero opacity and nothing ever animated it. The process exited with code 0, so a script or CI job would have counted it as a success.
Two habits prevent this:
- Render with `--strict`. On the same broken file it stopped before rendering, exited with code 1 and wrote no video.
- Run `npx hyperframes check` before a long render. It runs lint, a headless runtime check and a layout inspection as one gate.
A composition that is deliberately driven by CSS animations rather than a GSAP timeline can mark its host element with data-no-timeline, which the renderer's own message suggests, so it skips the wait. This is also the job the agent skills do: they encode rules like this one, so an agent writes the registration every time.
Seven Skills for Claude Code, Codex and Cursor
The quickest way into HyperFrames is to let a coding agent drive it. For Claude Code, the README installs a versioned plugin:
claude plugin marketplace add heygen-com/hyperframes
claude plugin install hyperframes@hyperframesOther agents, including Codex, Cursor, Gemini CLI and OpenCode, install the skills with npx skills add heygen-com/hyperframes, or with npx hyperframes skills update, which pulls the current core set straight from the main branch. Then you ask for a video in plain language: a ten-second product intro with a fade-in title, a background video and quiet music, for example.
HyperFrames publishes seven skills. Four make up the core set:
- /hyperframes: the render contract and the work loop. Read first for any video request.
- /hyperframes-cli: the CLI by job, from scaffolding and checking to inspecting frames, editing the timeline, previewing, rendering and publishing.
- /hyperframes-registry: about 450 ready-made blocks and components, from transitions and kinetic type to captions, charts, maps and 3D.
- /media-use: music, sound effects, images, voiceover, avatars, transcripts and colour grades, using HeyGen or free local tools.
Three more install on demand: /figma for bringing in Figma designs and brand tokens, /slideshow for navigable decks rather than MP4s, and /remotion-to-hyperframes for porting existing video code.
hyperframes init also writes an AGENTS.md and a CLAUDE.md into every new project, so an agent that opens the folder finds the rules without being told. Two defaults are worth knowing before you script the CLI: it sends anonymous usage telemetry (turn it off with npx hyperframes telemetry disable, HYPERFRAMES_NO_TELEMETRY=1 or DO_NOT_TRACK=1), and init keeps the installed agent skills up to date from GitHub unless HYPERFRAMES_SKIP_SKILLS=1 is set.
Catalog, frame.md and Every Output Format
Most videos reuse the same pieces, and HyperFrames ships them as source you install into your project rather than as a locked library:
npx hyperframes add flash-through-white # shader transition
npx hyperframes add instagram-follow # social overlay
npx hyperframes add data-chart # animated chartframe.md takes the same idea to branding. The README's pitch is that every brand has a design.md and none of them were written for a camera. frame.md inverts a web design spec for the frame: the same tokens, rewritten for a fixed canvas so an agent can compose a promo without guessing at scale. Two small conversions come up in practice. A web design system's rem sizes have to become pixel values on a canvas 1920 pixels wide, which a px to rem converter works out in either direction. Brand colours often arrive as HEX when the composition's CSS variables want RGB or HSL, which is a job for a color converter.
Rendering goes well beyond MP4:
| Format | Use it for |
|---|---|
| MP4 | Normal sharing and delivery |
| MOV | A ProRes 4444 editing intermediate that keeps transparency |
| WebM | Web delivery, including transparent overlays |
| GIF | Short previews in issues, pull requests and docs |
| PNG sequence | Frame-by-frame handoff to compositing software |
| HLS | Streaming, with fixed-length segments |
Renders run locally by default, in Docker for a pinned environment, and on HeyGen's hosted cloud, AWS Lambda or Google Cloud Run for distributed work. Around the renderer sit Studio, a browser editor that changes the same DOM the renderer captures, a native desktop app for Mac and Linux, and the hyperframes.dev playground.
HyperFrames vs Remotion
HyperFrames says openly that it is inspired by Remotion, the established React framework for programmatic video. Both open a real browser, draw each frame and encode it with FFmpeg. The difference is what you write and how time works.
In Remotion, a component is a pure function of the frame number: you call useCurrentFrame() and compute each value yourself, usually with interpolate. In HyperFrames, you write HTML and an ordinary animation, and the renderer pauses that animation and seeks it to each frame. HyperFrames' comparison guide writes the same three-second title card both ways, and neither version is much longer than the other.
| HyperFrames | Remotion | |
|---|---|---|
| You write | HTML, CSS and JavaScript | React components |
| Timing | The renderer seeks your paused animation | Your code reads the frame number |
| Build step | None | Bundler required |
| Existing web work | GSAP, Lottie and CSS animations drop in | Rewritten as React |
| License | Apache 2.0 | Remotion License: free for individuals and companies of up to three people, paid above that |
The guide is unusually fair to its rival. It says Remotion is older, with more templates, tutorials and production history; that Remotion Lambda is the more mature cloud renderer; and that a team already writing React gets its components and design system for free. It also admits that the HyperFrames model asks you to follow rules and breaks quietly when you don't, which is exactly what our missing-registration test showed. HyperFrames' side of the case is no React, no build step and no rewrite, HTML that agents already write well, and an Apache 2.0 license with no seat count.
For teams moving across, the /remotion-to-hyperframes skill maps useCurrentFrame and interpolate onto timeline tweens and Sequence onto clips. The docs estimate that about 80% of a typical composition translates mechanically. The skill flags what it will not translate, such as React state built on useState or useEffect and third-party React UI, instead of guessing, then renders both versions and compares them frame by frame.
Installing HyperFrames and Rendering Your First Video
By hand, the loop is four commands:
npx hyperframes init my-video
cd my-video
npx hyperframes preview # browser preview with live reload
npx hyperframes render # writes an MP4 under renders/Before a final render, the docs recommend npx hyperframes lint and npx hyperframes check, and npx hyperframes doctor when something in the environment looks wrong. Render flags worth knowing:
--output final.mp4to name the file;--format webm,mov,gif,png-sequenceorhls;--quality draftfor quick reviews, orhighfor a master;--fps 60when the destination needs it;--dockerfor a pinned environment;--strictto stop on lint errors.
The requirements are Node.js 22 or newer and FFmpeg; the CLI manages the Chrome it renders with. If your video starts life as plain text, such as a script or a list of captions, a text to HTML converter turns it into paragraphs you can drop into a composition. Cloning the repository is only needed to contribute, and it needs Git LFS for about 240 MB of golden test videos.
Who Should Use HyperFrames, and Who Can Skip It
HyperFrames fits best when video has to be made repeatedly or by software: product announcements built from a template, PR walkthroughs with animated code diffs, data videos and chart races, captioned social clips, or a pipeline where an agent writes the composition and a CI job renders it. Web developers get the most from it, because what they already know about HTML, CSS and animation carries over, and determinism means a render can be tested like code.
It is a weaker fit if your team is already productive in Remotion and React, where switching buys little, or if you cut footage by hand and want a timeline editor first. Studio and the desktop app exist, but the project's center of gravity is the HTML file. It also asks for discipline: no clocks, no unseeded randomness, a registered timeline. Render with --strict and those rules stop being traps.



