One-command share: `hyperframes publish` starts the preview server,
opens a public HTTPS tunnel to it, and prints a URL the user can paste
into Slack / Figma / iPhone Safari / anywhere. Token-gated, read-only
by default, explicit consent before exposure, auto-rebuilds the studio
if its assets are missing so users never see a broken tunnel.
- packages/cli/src/commands/publish.ts — new command. Consent prompt,
mint session token, start preview through a fetch wrapper that gates
the studio server, open the tunnel, print the URL. Ctrl-C reaps both
children cleanly.
- packages/cli/src/utils/tunnel.ts — provider detection
(cloudflared preferred, tuns.sh ssh fallback) and openTunnel that
spawns the child and resolves with the first emitted public URL.
- packages/cli/src/utils/publishSecurity.ts — shared-secret token gate,
mutation gate (read-only by default), read-only UI injection,
interactive consent prompt.
- packages/cli/src/server/studioServer.ts — StudioAssetsMissingError
thrown at construction if dist is missing (no lazy-500 at request
time). Fixed the dev-fallback path: was three levels up at
`hyperframes-oss/studio/dist`, now correctly two at
`packages/studio/dist`.
- packages/cli/scripts/build-copy.sh — replaces the old silent
`cp -r ../studio/dist/*`. Runs under `set -euo pipefail`, asserts
the source index.html exists before copying, asserts the
destination index.html exists after. A zero-file copy can no longer
ship a broken CLI bundle.
- Root package.json — build now serializes studio first, then the
rest in parallel. CLI dropped its nested `build:studio`; the two
parallel `vite build` invocations were clobbering each other's
packages/studio/dist.
- packages/cli/src/cli.ts, src/help.ts — register publish in the
CLI, add it to the Getting Started group and root examples.
- docs/packages/cli.mdx — documents the command, flags, and the
read-only security model.
Auto-picks the first available of:
1. cloudflared — Cloudflare's free quick tunnel. Most reliable.
`brew install cloudflared` (Linux/Windows binaries equivalent). No
account, no keys, no config.
2. tuns.sh — zero-install ssh -R fallback. Works on every machine
with OpenSSH.
`--provider cloudflared | tuns | auto` forces one.
The studio server was built for localhost and everything is
unauthenticated. PUT/POST/DELETE/PATCH on /api/projects/:id/files/*
reads and overwrites the project directory. Exposing that surface
unguarded over a public URL is how you ship a "drop a keylogger in
their index.html" bug. Four composed defences:
1. Token gate. On startup, mint a 32-byte base64url token via
crypto.randomBytes. Public URL is
`${tunnelUrl}/?t=${token}#project/${name}`. First hit validates in
constant time (timingSafeEqual), sets an httpOnly; Secure;
SameSite=Lax session cookie, and 302-redirects to a clean URL so
the token never lands in browser history or Referer. Every
subsequent request needs the cookie. Anything else returns 404
(deliberately, not 401/403 — do not advertise that a server is
here). Cookie TTL: 12 h. Implemented as a fetch wrapper rather
than a Hono middleware because the studio routes are registered
before publish gets the app; middlewares only apply to routes
registered after them. Wrapping fetch gates traffic at the HTTP
boundary and sidesteps ordering entirely.
2. Mutation gate. When --allow-edit is not set, refuse writes/deletes
on `/api/projects/:id/files/*`,
`POST /api/projects/:id/duplicate-file`, and
`POST /api/projects/:id/render`. Returns
`403 { "error": "forbidden", "reason": "…re-run with --allow-edit…" }`.
Authenticated reads still work.
3. Read-only UI enforcement. The mutation gate closes the server
side, but the studio UI does not know about the mode. Without
this layer, visitors would type into a Monaco editor whose saves
silently 403. Every response carries
`X-HF-Publish-Readonly: 1`. HTML responses from the SPA (NOT
`/api/*`, so the composition bundle served inside the player
iframe is untouched) get a small inline <style> + <script>
injected before `</head>`. The style neutralises Monaco /
CodeMirror surfaces via pointer-events: none,
caret-color: transparent, user-select: none. The script sets
window.__HF_PUBLISH_READONLY__ = true, renders a compact pill
centered at the top of the viewport ("READ-ONLY · Published
tunnel"), and monkey-patches window.fetch to short-circuit
mutating calls client-side so the UI does not loop through
doomed 403s.
4. Explicit consent on startup. Before the server binds, a clack
confirm prompt spells out the exposure: token-is-a-password
guidance, the 12 h session lifetime, and — when --allow-edit is
set — a warning that visitors can read/write/delete project
files. --yes / -y skips for scripts. In non-TTY environments
without --yes, publish refuses to proceed rather than silently
exposing.
Previously, running publish against a dev checkout without a built
studio produced "Studio not found. Rebuild with: pnpm run build" on
every request — after the tunnel was open and the URL shared. We
fix it instead: createStudioServer throws
StudioAssetsMissingError at construction, publish catches it,
spawns `bun run build` in packages/studio with a spinner, retries
createStudioServer once the build succeeds. The error surface only
fires when auto-rebuild itself fails (broken global install, etc.),
and lists every path searched plus the `bun install && bun run
build` guidance. End-to-end: deleting both packages/studio/dist
and packages/cli/dist/studio and running publish now rebuilds the
studio and opens the tunnel without user intervention.
- --port <n> Preview port (default 3002).
- --provider <p> cloudflared | tuns | auto.
- --allow-edit Remote visitors can write/delete files.
Off by default.
- --yes / -y Skip the consent prompt.
- No info leak on unauthenticated probes — random visitors see 404
whether a path exists or not.
- Token never leaves the first URL — redirect strips it before any
HTML is served, so no iframe Referer can leak it.
- Constant-time comparison for both token and cookie checks.
- No persisted state — token lives for the lifetime of the command,
Ctrl-C nukes it.
- Read-only cannot be bypassed by a malicious client; the
server-side 403 is the real stop.
- zero-file build:copy can no longer ship a broken CLI.
- src/utils/publishSecurity.test.ts — 23 cases: token exchange,
cookie flow, mutation-gate allow/deny matrix,
X-HF-Publish-Readonly header, HTML-injection + no-op on
--allow-edit / non-HTML / /api/* paths.
- src/utils/tunnel.test.ts — 7 cases for the URL extractor
(per-provider banner parsing, cross-provider contamination
guard) and provider picker semantics.
- src/server/studioServer.test.ts — StudioAssetsMissingError shape
and export for downstream catch blocks.
- Full CLI suite: 144/144 pass.
- tsc --noEmit clean, tsup build clean.
Write HTML. Render video. Built for agents.
Hyperframes is an open-source video rendering framework that lets you create, preview, and render HTML-based video compositions — with first-class support for AI agents.
Quick Start
Option 1: With an AI coding agent (recommended)
Install the HyperFrames skills, then describe the video you want:
npx skills add heygen-com/hyperframes
This teaches your agent (Claude Code, Cursor, Gemini CLI, Codex) how to write correct compositions and GSAP animations. In Claude Code, the skills register as slash commands — invoke /hyperframes to author compositions, /hyperframes-cli for CLI commands, and /gsap for animation help.
For Codex specifically, the same skills are also exposed as an OpenAI Codex plugin — sparse-install just the plugin surface:
codex plugin marketplace add heygen-com/hyperframes --sparse .codex-plugin --sparse skills --sparse assets
Try it: example prompts
Copy any of these into your agent to get started. The /hyperframes prefix loads the skill context explicitly so you get correct output the first time.
Cold start — describe what you want:
Using
/hyperframes, create a 10-second product intro with a fade-in title, a background video, and background music.
Warm start — turn existing context into a video:
Take a look at this GitHub repo https://github.com/heygen-com/hyperframes and explain its uses and architecture to me using
/hyperframes.
Summarize the attached PDF into a 45-second pitch video using
/hyperframes.
Turn this CSV into an animated bar chart race using
/hyperframes.
Format-specific:
Make a 9:16 TikTok-style hook video about [topic] using
/hyperframes, with bouncy captions synced to a TTS narration.
Iterate — talk to the agent like a video editor:
Make the title 2x bigger, swap to dark mode, and add a fade-out at the end.
Add a lower third at 0:03 with my name and title.
The agent handles scaffolding, animation, and rendering. See the prompting guide for more patterns.
Option 2: Start a project manually
npx hyperframes init my-video
cd my-video
npx hyperframes preview # preview in browser (live reload)
npx hyperframes render # render to MP4
hyperframes init installs skills automatically, so you can hand off to your AI agent at any point.
Requirements: Node.js >= 22, FFmpeg
Why Hyperframes?
- HTML-native — compositions are HTML files with data attributes. No React, no proprietary DSL.
- AI-first — agents already speak HTML. The CLI is non-interactive by default, designed for agent-driven workflows.
- Deterministic rendering — same input = identical output. Built for automated pipelines.
- Frame Adapter pattern — bring your own animation runtime (GSAP, Lottie, CSS, Three.js).
Hyperframes vs Remotion
Hyperframes is inspired by Remotion — we used Remotion at HeyGen in production, learned a ton from it, and kept attribution comments in the source for the patterns it pioneered (Chrome launch flags, image2pipe → FFmpeg streaming, frame buffering). Both tools drive headless Chrome and both are deterministic. They differ on one decision: what the primary author writes. Remotion's bet is React components; Hyperframes' bet is HTML.
| Hyperframes | Remotion | |
|---|---|---|
| Authoring | HTML + CSS + GSAP | React components (TSX) |
| Build step | None; index.html plays as-is |
Required (bundler) |
| Library-clock animations (GSAP, Anime.js, Motion One) | Seekable, frame-accurate | Plays at wall-clock during render |
| Arbitrary HTML / CSS passthrough | Paste and animate | Rewrite as JSX |
| Distributed rendering | Single-machine today | Lambda, production-ready |
Licensing: fully open source vs source-available
Hyperframes is completely open source under Apache 2.0 — an OSI-approved license. Use it commercially at any scale, with no per-render fees, no seat caps, no company-size thresholds.
Remotion is source-available, not open source. The code is on GitHub under a custom Remotion License that requires a paid company license above small-team thresholds. It's a great product with a real team behind it — but if open-source licensing matters to you (OSI compliance, redistribution rights, no per-use fees), that's a first-order decision point.
Full write-up with benchmarks, an honest list of where each tool wins, and a GSAP side-by-side: Hyperframes vs Remotion guide.
How It Works
Define your video as HTML with data attributes:
<div id="stage" data-composition-id="my-video" data-start="0" data-width="1920" data-height="1080">
<video
id="clip-1"
data-start="0"
data-duration="5"
data-track-index="0"
src="intro.mp4"
muted
playsinline
></video>
<img
id="overlay"
class="clip"
data-start="2"
data-duration="3"
data-track-index="1"
src="logo.png"
/>
<audio
id="bg-music"
data-start="0"
data-duration="9"
data-track-index="2"
data-volume="0.5"
src="music.wav"
></audio>
</div>
Preview instantly in the browser. Render to MP4 locally or in Docker.
Catalog
50+ ready-to-use blocks and components — social overlays, shader transitions, data visualizations, and cinematic effects:
npx hyperframes add flash-through-white # shader transition
npx hyperframes add instagram-follow # social overlay
npx hyperframes add data-chart # animated chart
Browse the full catalog at hyperframes.heygen.com/catalog.
Documentation
Full documentation at hyperframes.heygen.com/introduction — Quickstart | Guides | API Reference | Catalog
Packages
| Package | Description |
|---|---|
hyperframes |
CLI — create, preview, lint, and render compositions |
@hyperframes/core |
Types, parsers, generators, linter, runtime, frame adapters |
@hyperframes/engine |
Seekable page-to-video capture engine (Puppeteer + FFmpeg) |
@hyperframes/producer |
Full rendering pipeline (capture + encode + audio mix) |
@hyperframes/studio |
Browser-based composition editor UI |
@hyperframes/player |
Embeddable <hyperframes-player> web component |
@hyperframes/shader-transitions |
WebGL shader transitions for compositions |
Skills
HyperFrames ships skills that teach AI agents framework-specific patterns that generic docs don't cover.
npx skills add heygen-com/hyperframes
| Skill | What it teaches |
|---|---|
hyperframes |
HTML composition authoring, captions, TTS, audio-reactive animation, transitions |
hyperframes-cli |
CLI commands: init, lint, preview, render, transcribe, tts, doctor |
hyperframes-registry |
Block and component installation via hyperframes add |
website-to-hyperframes |
Capture a URL and turn it into a video — full website-to-video pipeline |
gsap |
GSAP animation API, timelines, easing, ScrollTrigger, plugins, React/Vue/Svelte, performance |
Contributing
See CONTRIBUTING.md for guidelines.
