---
name: hyperframes-deploy
description: "Deploy and use HyperFrames — HTML-to-video rendering framework by HeyGen. Install, configure Chrome headless, preview, render MP4. Covers proxy pitfalls and onnxruntime issues."
tags: [video, html, rendering, puppeteer, ffmpeg, heygen, hyperframes]
triggers:
  - hyperframes
  - html to video
  - html video rendering
  - heygen video
---

# HyperFrames Deployment

Deploy HeyGen's open-source HTML-to-video rendering framework. Write HTML compositions, preview in browser, render to MP4 via headless Chrome + FFmpeg.

## Prerequisites

- Node.js >= 22
- FFmpeg (system-installed)
- ~200MB disk for Chrome Headless Shell

## Installation

```bash
npm install -g hyperframes --ignore-scripts
```

**⚠️ Pitfall: `--ignore-scripts` is required.** The `onnxruntime-node` dependency's post-install script fails when a proxy is active (HTTP 302 redirect treated as error). Skipping scripts is safe — onnxruntime is only needed for AI features (background removal), not core preview/render.

## Chrome Headless Shell Setup

`hyperframes browser ensure` often fails behind proxies. Manual setup:

```bash
# 1. Download
mkdir -p ~/.cache/hyperframes/chrome/chrome-headless-shell
cd ~/.cache/hyperframes/chrome/chrome-headless-shell
curl -L -o chrome-headless-shell-linux64.zip \
  "https://storage.googleapis.com/chrome-for-testing-public/131.0.6778.85/linux64/chrome-headless-shell-linux64.zip"

# 2. Extract
python3 -c "import zipfile; zipfile.ZipFile('chrome-headless-shell-linux64.zip').extractall('.')"

# 3. Place in expected path (critical!)
mkdir -p linux-131.0.6778.85/chrome-headless-shell-linux64
cp -r chrome-headless-shell-linux64/* linux-131.0.6778.85/chrome-headless-shell-linux64/
chmod +x linux-131.0.6778.85/chrome-headless-shell-linux64/chrome-headless-shell
```

**⚠️ Pitfall: Path must be exact.** Puppeteer looks for `~/.cache/hyperframes/chrome/chrome-headless-shell/linux-<VERSION>/chrome-headless-shell-linux64/chrome-headless-shell`. If the path is wrong, render fails with "Browser was not found at the configured executablePath".

## Project Init & Rendering

```bash
# Create project
hyperframes init my-video
cd my-video

# Preview (dev server, live reload)
hyperframes preview    # runs on http://localhost:3002

# Render to MP4
hyperframes render     # output in renders/ directory
```

## Key Concepts

| Command   | What it does                            | Output       |
|-----------|----------------------------------------|--------------|
| `preview` | Dev server with live reload             | HTTP server  |
| `render`  | Headless Chrome frame capture + FFmpeg  | MP4 file     |

- **preview and render can run simultaneously** — independent processes
- **render needs no visible browser** — uses headless Chrome in background
- **preview on headless server** — access via `http://server-ip:3002` from LAN or SSH tunnel

## Composition Structure

```html
<!doctype html>
<html>
<head>
  <script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
</head>
<body>
  <div id="root" data-composition-id="main" data-start="0" data-duration="10"
       data-width="1920" data-height="1080">
    <!-- Timed clips: class="clip" + data-start + data-duration + data-track-index -->
    <div id="title" class="clip" data-start="0" data-duration="5" data-track-index="0"
         style="font-size:128px; color:#fff; display:flex; align-items:center; justify-content:center; width:100%; height:100%; background:linear-gradient(135deg,#667eea,#764ba2);">
      Hello World
    </div>
  </div>
  <script>
    window.__timelines = window.__timelines || {};
    const tl = gsap.timeline({ paused: true });
    tl.from("#title", { opacity: 0, scale: 0.5, duration: 1 }, 0);
    window.__timelines["main"] = tl;
  </script>
</body>
</html>
```

**Rules:**
1. Every timed element needs `data-start`, `data-duration`, `data-track-index`
2. Visible timed elements **must** have `class="clip"`
3. GSAP timelines must be `paused: true` and registered on `window.__timelines`
4. No `Date.now()`, `Math.random()`, or network fetches (deterministic rendering)

## Proxy Pitfalls

When behind a proxy (e.g., mihomo/Clash on port 7890):

1. **npm proxy settings break puppeteer downloads** — unset before `hyperframes browser ensure`:
   ```bash
   npm config delete proxy
   npm config delete https-proxy
   unset HTTP_PROXY HTTPS_PROXY
   ```
2. **If npm proxy needed for other packages**, re-set after Chrome is installed
3. **onnxruntime-node always fails through proxy** — use `--ignore-scripts`

## Quick Lint

```bash
cd my-video
hyperframes lint        # check composition errors
hyperframes validate    # validate structure
hyperframes inspect     # detailed inspection
```
