HyperFrames is a TypeScript framework that takes HTML, CSS, and GSAP animations and produces seekable MP4 files. It runs locally via CLI, integrates with AI agents through MCP and skills.sh, and ships with a hosted playground. The core promise is deterministic video output from code, which means agents can write HTML and get frame-perfect video without manual timeline editing.
The project has 42K stars and is trending #11 on GitHub for TypeScript. HeyGen built it to make video generation programmatically addressable. The architecture is Puppeteer for DOM rendering, GSAP for animation timing, and FFmpeg for encoding. The interesting part is how it guarantees determinism when each layer is async by default.
Most video generation tools target human designers. You drag keyframes, adjust curves, export. Agents need something different: a function that takes structured input and returns a file. HyperFrames treats video as a build artifact. You write HTML with animation code, run a command, get an MP4.
This shifts video from creative workflow to infrastructure. An agent can generate a data visualization, encode it as HTML with GSAP transitions, and call HyperFrames to render. No GUI, no manual export, no non-deterministic output. The same HTML always produces the same video.
The MCP server integration means agents can invoke HyperFrames as a tool. The skills.sh distribution packages it as a skill set that coding agents can install and call. This is video rendering as a first-class agent capability, not a side effect of screen recording.
HyperFrames chains three components:
The pipeline looks like this:
// Simplified flow (not actual HyperFrames source)
async function render(htmlPath: string, outputPath: string) {
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
await page.goto(`file://${htmlPath}`);
// Wait for GSAP timeline to be ready
await page.evaluate(() => window.gsap.timeline().totalDuration());
// Capture frames at fixed intervals
const frames = [];
for (let t = 0; t < duration; t += frameInterval) {
await page.evaluate((time) => window.gsap.globalTimeline.seek(time), t);
const screenshot = await page.screenshot({ encoding: 'binary' });
frames.push(screenshot);
}
await browser.close();
// Pipe frames to FFmpeg
const ffmpeg = spawn('ffmpeg', ['-framerate', '30', '-i', '-', outputPath]);
frames.forEach(frame => ffmpeg.stdin.write(frame));
ffmpeg.stdin.end();
}
The key is gsap.globalTimeline.seek(time)
. GSAP lets you jump to any point in the animation timeline without playing it in real time. Puppeteer captures a screenshot at each seek position. FFmpeg stitches the screenshots into video.
Determinism breaks if any of these layers drift:
t=1.5s
always produces the same visual state. CSS transitions or requestAnimationFrame
loops would not.The failure mode is async resource . If a web font or image loads after the first frame capture, the video will show a flash. HyperFrames mitigates this with preload checks and a configurable wait time.
Another failure mode is GSAP timeline complexity. If your animation uses random values or Date.now(), it is not deterministic. HyperFrames does not enforce purity. It assumes your HTML is reproducible.
HyperFrames ships an MCP server that exposes video rendering as a tool. The server accepts HTML strings or file paths, renders them, and returns MP4 URLs or base64 blobs.
The MCP server holds no persistent state between calls. Each render is a fresh Puppeteer instance. This avoids state leakage but means you cannot reuse browser sessions for performance. The trade-off is correctness over speed.
The skills.sh integration packages HyperFrames as a skill set. An agent can install it with npx skills add heygen-com/hyperframes
and then call /hyperframes
commands. The core skill set includes:
/hyperframes create
to generate a new project/hyperframes render
to produce MP4 from HTML/hyperframes preview
to open the playgroundThe skills are non-interactive. An agent can invoke them in a script without human input. This is the key difference from CLI tools that prompt for options.
HyperFrames defaults to H.264 in MP4 container. You can override with FFmpeg flags. Common options:
| Codec | Use Case | File Size | Compatibility |
|---|---|---|---|
| H.264 | Default, broad compatibility | Medium | High |
| H.265/HEVC | Smaller files, modern devices | Small | Medium |
| VP9 | Web-native, YouTube-friendly | Small | Medium |
| ProRes | Editing workflows, lossless | Large | Low |
The FFmpeg pipeline accepts custom codec strings. If you need alpha channel, you can use VP9 with transparency or ProRes 4444. HyperFrames does not abstract codec selection. You pass raw FFmpeg arguments.
The output shape is a single MP4 file. No intermediate frames are saved unless you specify a temp directory. This keeps disk usage low but makes debugging harder. If a frame looks wrong, you cannot inspect the raw screenshot.
HyperFrames surfaces three error classes:
The CLI logs each error with a stack trace. The MCP server returns error codes. There is no built-in retry logic. If Puppeteer crashes, the render fails. You must handle retries in the orchestration layer.
Observability is minimal. HyperFrames does not emit metrics or traces. You can wrap the CLI in a script that logs start/end times and file sizes. The MCP server does not expose health checks or render queue depth.
For production use, you would add:
HyperFrames is a library, not a service. It does not ship with these features.
HyperFrames runs wherever Node.js 22+ and FFmpeg are available. Common deployment patterns:
The Docker image is not official. You build your own with:
FROM node:22-slim
RUN apt-get update && apt-get install -y \
chromium \
ffmpeg \
fonts-liberation
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
CMD ["npx", "hyperframes", "render", "input.html", "output.mp4"]
Serverless is tricky. Puppeteer needs /tmp
write access for Chromium cache. FFmpeg writes temp frames. You must configure both to use /tmp
and clean up after each invocation.
HyperFrames executes arbitrary HTML in a headless browser. If an agent generates malicious HTML, it can:
The MCP server does not sandbox HTML. It trusts the agent. For untrusted input, you must:
FFmpeg is also a risk. It parses image and video files. A malicious image can exploit codec vulnerabilities. Keep FFmpeg updated and run it in a restricted user context.
Use HyperFrames when:
Avoid HyperFrames when:
HyperFrames makes video a build artifact. The Puppeteer + GSAP + FFmpeg pipeline is well-understood and deterministic. The MCP server and skills.sh integration position it as an agent tool, not a human tool.
The architecture is simple: no custom rendering engine, no GPU acceleration, no distributed job queue. This keeps the codebase small but limits performance. Rendering a 60-second video at 30fps means 1,800 Puppeteer screenshots. Expect minutes, not seconds.
The lack of built-in observability and error recovery means you will build your own orchestration layer. HyperFrames is a library. Treat it like FFmpeg: a powerful primitive that needs wrapping.
If your agent workflow generates data visualizations, social media clips, or explainer videos, HyperFrames is a strong fit. If you need real-time rendering or sub-second latency, look elsewhere.