mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 17:27:09 +00:00
* docs(studio): the browser editor in six pages, named the browser editor * docs(studio): mute where the editor has it, and no solo control The audio pages still described a solo control and a group-row mute that the editor does not render. Muting is the speaker button on an audio track (Mute track / Unmute track), the same toggle on a selected clip, and the Muted switch; a group is silenced through its members' tracks. The audio reference drops its solo section for the same reason.
200 lines
8.7 KiB
Plaintext
200 lines
8.7 KiB
Plaintext
---
|
||
title: "HyperFrames vs Remotion"
|
||
sidebarTitle: "vs Remotion"
|
||
description: "The same launch video made by an agent with Remotion and with HyperFrames, side by side; the same title card in both codes; and an honest read on which fits your project."
|
||
---
|
||
|
||
import { DocsVideo } from "/snippets/docs-video.jsx";
|
||
|
||
Both tools make video out of web pages. Both open a real browser, draw each
|
||
frame, and encode the result. The difference is what you write.
|
||
|
||
Remotion asks for a React component. HyperFrames asks for an HTML file.
|
||
|
||
## Same request, two agents
|
||
|
||
We gave Claude Code (Opus 5.5) the same one-paragraph request twice: once with only Remotion's official agent skills
|
||
installed, once with only HyperFrames'. One run each, no retries, nothing edited afterwards.
|
||
|
||
> Make a 15-second 1920x1080 launch video for a fictional note-taking app called Inkwell (tagline: "Write it down. Find
|
||
> it later."). Logo reveal, three short feature lines, then an end card with the tagline. No voice. Render the final MP4
|
||
> to out.mp4 in this folder. Don't ask me questions; make the choices yourself.
|
||
|
||
<div className="hf-versus">
|
||
<div>
|
||
<p><strong>Remotion</strong></p>
|
||
<DocsVideo title="Inkwell, made with Remotion" src="https://static.heygen.ai/hyperframes-oss/docs/films/vs-remotion-v1.mp4" poster="/public/images/films/vs-remotion-v1.jpg" />
|
||
</div>
|
||
<div>
|
||
<p><strong>HyperFrames</strong></p>
|
||
<DocsVideo title="Inkwell, made with HyperFrames" src="https://static.heygen.ai/hyperframes-oss/docs/films/vs-hyperframes-v1.mp4" poster="/public/images/films/vs-hyperframes-v1.jpg" />
|
||
</div>
|
||
</div>
|
||
|
||
| | Remotion | HyperFrames |
|
||
| --- | --- | --- |
|
||
| Time to a rendered MP4 | 12 min 30 s | 11 min 50 s |
|
||
| What it wrote | 10 TypeScript files, 1,037 lines | 4 HTML files, 822 lines |
|
||
| Installed into the project | about 950 MB of `node_modules` | nothing |
|
||
| Sound | none | a music bed and five sound effects it chose |
|
||
|
||
Both are good videos; a single run decides nothing about quality. The difference that lasts is what you are left
|
||
holding: a React project to keep building in code, or HTML files you can open in a browser, edit with an agent, or
|
||
keep changing in the [Studio app](/studio-app/index).
|
||
|
||
## The same title card, written both ways
|
||
|
||
Here is the same three seconds — a title that fades in, holds, and fades out —
|
||
written both ways. Neither version is padded or crippled to make a point.
|
||
|
||
|
||
**Remotion.** The component is a function of the current frame number. You do
|
||
the timing math yourself, in frames.
|
||
|
||
```tsx
|
||
import { AbsoluteFill, interpolate, useCurrentFrame } from "remotion";
|
||
|
||
export const TitleCard = () => {
|
||
const frame = useCurrentFrame();
|
||
|
||
// fade in over frames 0-15, hold to 75, fade out by 90
|
||
const opacity = interpolate(frame, [0, 15, 75, 90], [0, 1, 1, 0], {
|
||
extrapolateLeft: "clamp",
|
||
extrapolateRight: "clamp",
|
||
});
|
||
|
||
return (
|
||
<AbsoluteFill
|
||
style={{ backgroundColor: "#0a0a0a", justifyContent: "center", alignItems: "center" }}
|
||
>
|
||
<div style={{ fontSize: 160, fontWeight: 800, color: "#fff", opacity }}>HELLO</div>
|
||
</AbsoluteFill>
|
||
);
|
||
};
|
||
```
|
||
|
||
A `<Composition>` entry in another file registers it as 90 frames at 30fps,
|
||
1280×720.
|
||
|
||
**HyperFrames.** The markup declares when things are on screen. A GSAP timeline
|
||
declares how they move. Both live in one file.
|
||
|
||
```html
|
||
<style>
|
||
#stage { position: relative; width: 1280px; height: 720px; overflow: hidden; background: #0a0a0a; }
|
||
.clip { position: absolute; inset: 0; display: grid; place-items: center; }
|
||
#title { font-size: 160px; font-weight: 800; color: #fff; opacity: 0; }
|
||
</style>
|
||
|
||
<div id="stage" data-composition-id="title-card" data-start="0"
|
||
data-width="1280" data-height="720" data-duration="3" data-fps="30">
|
||
<div id="card" class="clip" data-start="0" data-duration="3" data-track-index="0">
|
||
<div id="title">HELLO</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
|
||
<script>
|
||
// same fade, written in seconds instead of frames
|
||
const tl = gsap.timeline({ paused: true });
|
||
tl.to("#title", { opacity: 1, duration: 0.5, ease: "none" }, 0);
|
||
tl.to("#title", { opacity: 1, duration: 2.0, ease: "none" }, 0.5);
|
||
tl.to("#title", { opacity: 0, duration: 0.5, ease: "none" }, 2.5);
|
||
|
||
window.__timelines = window.__timelines || {};
|
||
window.__timelines["title-card"] = tl;
|
||
</script>
|
||
```
|
||
|
||
That is the whole file apart from `<head>` boilerplate. Three rules make it
|
||
render: every visible slot carries `class="clip"` with an `id`, `data-start`,
|
||
`data-duration`, and `data-track-index`; the timeline is created **paused**; and
|
||
it is registered on `window.__timelines` under the same id as the root element.
|
||
Miss the last one and you get a still frame with no motion. The
|
||
[HTML schema](/reference/html-schema) lists every attribute.
|
||
|
||
|
||
Neither file is obviously better. The Remotion one is a pure function you can
|
||
reason about in your head. The HyperFrames one is a page you can open in a
|
||
browser and inspect with devtools.
|
||
|
||
## Where they actually differ
|
||
|
||
| | HyperFrames | Remotion |
|
||
| --- | --- | --- |
|
||
| What you write | HTML, CSS, and JavaScript | React and TypeScript |
|
||
| How motion is timed | The renderer pauses your animation and *seeks* it — jumps it to an exact moment — before capturing each frame | Your code reads the frame number and returns the values for that frame |
|
||
| Existing web material | HTML, CSS, and a GSAP or Lottie animation usually drop in close to as-is | Rewritten as React components |
|
||
| License | [Apache 2.0](https://github.com/heygen-com/hyperframes/blob/main/LICENSE) | Its own license — free for individuals and companies up to three people, paid above that. Check the [current terms](https://www.remotion.pro/license) |
|
||
|
||
The seeking model is the interesting one. Because HyperFrames drives the
|
||
animation rather than watching a clock, GSAP, Web Animations, Lottie, and other
|
||
browser runtimes render deterministically — the same frame comes out the same
|
||
every time. See [Frame adapters](/concepts/frame-adapters) and
|
||
[Deterministic rendering](/concepts/determinism).
|
||
|
||
Both projects ship a visual editor and both save changes back to source.
|
||
[The HyperFrames browser editor](/studio) edits the same DOM the renderer captures. Remotion
|
||
Studio edits React compositions. They are not interchangeable, and neither
|
||
replaces editing the source for real structural changes.
|
||
|
||
Both render on AWS Lambda. HyperFrames also renders locally, on HeyGen's hosted
|
||
cloud, and on Google Cloud Run — see [rendering paths](/deploy/overview).
|
||
|
||
## What Remotion does better
|
||
|
||
Say this plainly, because it matters if you are choosing today.
|
||
|
||
Remotion is older and much more established. It has more templates, more
|
||
tutorials, more answered questions, and far more production history. Remotion
|
||
Lambda in particular is a mature, heavily documented rendering system; ours is
|
||
newer.
|
||
|
||
If your team already writes React, Remotion gives you your components, your
|
||
design system, your charting libraries, and typed, validated composition inputs
|
||
for free. Nothing to translate.
|
||
|
||
And its model is genuinely simpler to hold in your head. One pure function of
|
||
the frame number, no timeline to register, no contract to get subtly wrong.
|
||
HyperFrames asks you to follow rules — paused timeline, no wall clocks, no
|
||
unseeded randomness — and breaks quietly if you don't.
|
||
|
||
## What HyperFrames does better
|
||
|
||
You do not need React, a build step, or a component rewrite. A website, an HTML
|
||
prototype, an exported design, or an existing browser animation is already
|
||
close to a composition.
|
||
|
||
It is built for an AI agent to author. The [agent skills](/guides/skills)
|
||
encode the framework's rules, so the agent writes valid compositions instead of
|
||
guessing, and a human can then edit the same file in the browser editor.
|
||
|
||
And Apache 2.0 means no seat count and no license review.
|
||
|
||
## Moving a Remotion project across
|
||
|
||
There is a real migration path, not a promise. Install the skill:
|
||
|
||
```bash
|
||
npx skills add heygen-com/hyperframes --skill remotion-to-hyperframes
|
||
```
|
||
|
||
Then ask your agent to port the composition. It maps `useCurrentFrame` and
|
||
`interpolate` onto timeline tweens, `Sequence` onto clips, and converts frames
|
||
to seconds.
|
||
|
||
The harder cases are the point of the skill. It refuses to translate what does not
|
||
fit: React state machines built on `useState` or `useEffect`, async metadata,
|
||
third-party React UI libraries. Those get flagged instead of silently
|
||
mistranslated. It also grades its own output — it renders both versions and
|
||
compares them frame by frame, and it writes down anything it dropped.
|
||
|
||
Migrate because your source material or your team fits better on this side. Not
|
||
because one framework looks newer.
|
||
|
||
## Related topics
|
||
|
||
- [How a HyperFrames composition works](/concepts/compositions)
|
||
- [Install and use the agent skills](/guides/skills)
|
||
- [Choose a rendering path](/deploy/overview)
|