docs(hyperframes): document preview teardown to stop leaked Chrome workers

npx hyperframes preview starts a long-lived next-server that keeps
chrome-headless-shell render workers resident. On GPU-less hosts (WSL,
containers, CI) each idle worker falls back to software WebGL (swiftshader)
and busy-spins a CPU core; a preview left open stacks these up until the
host is wedged. The skill never said preview was long-lived, so leaking
was the default outcome.

Add a Cleanup section + pitfall to SKILL.md and a Runaway CPU
troubleshooting entry with diagnose/fix/avoid steps.
This commit is contained in:
Brooklyn Nicholson 2026-08-13 20:24:43 -05:00 committed by brooklyn!
parent 423f92e607
commit e50db44b12
2 changed files with 41 additions and 1 deletions

View File

@ -43,11 +43,13 @@ Do **not** use this skill for:
npx hyperframes init my-video # scaffold a project
cd my-video
npx hyperframes lint # validate before preview/render
npx hyperframes preview # live-reload browser preview (port 3002)
npx hyperframes preview # live-reload preview (long-lived server, port 3002)
npx hyperframes render --output final.mp4 # render to MP4
npx hyperframes doctor # diagnose environment issues
```
`preview` is a **long-lived** Next.js server that holds Chrome render workers open. Always stop it when done (see [Cleanup](#cleanup)) — a forgotten preview keeps idle `chrome-headless-shell` workers alive that, on GPU-less hosts (WSL, containers, CI), spin a CPU core each indefinitely via software WebGL (swiftshader).
Render flags: `--quality draft|standard|high` · `--fps 24|30|60` · `--format mp4|webm` · `--docker` (reproducible) · `--strict`.
Full CLI reference: [references/cli.md](references/cli.md).
@ -150,8 +152,23 @@ npx hyperframes render --quality high --output final.mp4 # final delivery
Use the 7-step capture-to-video workflow in [references/website-to-video.md](references/website-to-video.md): capture → DESIGN.md → SCRIPT.md → storyboard → composition → render → deliver.
## Cleanup
`render` is one-shot (workers exit when it finishes). `preview` is **not** — it runs a background Next.js server that keeps Chrome workers resident until you stop it. Never leave one running: on GPU-less hosts each idle worker's swiftshader process pegs a CPU core, and a preview left open for days stacks up multiple.
Stop a preview when the user is done reviewing (or before starting a new one):
```bash
pkill -f "hyperframes.*preview" # the Studio server (frees port 3002)
pkill -f chrome-headless-shell # its render workers; only safe if nothing else uses them
```
If unsure whether other tools use `chrome-headless-shell`, check first: `pgrep -af chrome-headless-shell`. Recover a wedged host (many idle workers spinning CPU) the same way — see [references/troubleshooting.md](references/troubleshooting.md#runaway-cpu-from-leftover-preview-workers).
## Pitfalls
- **Leaving `preview` running** — it's a long-lived server holding Chrome workers; on WSL/containers/CI those idle workers spin a CPU core each (software WebGL). Stop it when done — see [Cleanup](#cleanup).
- **`HeadlessExperimental.beginFrame' wasn't found`** — Chromium 147+ removed this protocol. Ensure you're on `hyperframes@>=0.4.2` (auto-detects and falls back to screenshot mode). Escape hatch: `export PRODUCER_FORCE_SCREENSHOT=true`. See [hyperframes#294](https://github.com/heygen-com/hyperframes/issues/294) and [references/troubleshooting.md](references/troubleshooting.md).
- **System Chrome (not `chrome-headless-shell`)** — renders hang for 120s then timeout. Run `npx puppeteer browsers install chrome-headless-shell` (setup.sh does this). `hyperframes doctor` reports which binary will be used.
- **`repeat: -1` anywhere** — breaks the capture engine. Always compute a finite repeat count.

View File

@ -132,6 +132,29 @@ npx hyperframes render --docker --docker-args "--cap-add=SYS_ADMIN"
The headless browser needs namespace permissions for sandboxing.
## Runaway CPU from leftover preview workers
**Symptom:** load average climbs and stays high; `top` shows several `chrome-headless-shell --type=gpu-process` at ~300%+ CPU each, alive for hours/days, even when you're not rendering.
**Cause:** `npx hyperframes preview` is a long-lived server that keeps Chrome render workers resident. On hosts with no real GPU (WSL, containers, most CI), each idle worker falls back to software WebGL (`swiftshader`) whose GPU process busy-spins a CPU core. A preview left open — or several started over time — stacks these up.
**Diagnose:**
```bash
pgrep -af chrome-headless-shell # list the workers + their parent flags
pgrep -af "hyperframes.*preview" # the preview server(s) holding them open
uptime # confirm elevated load average
```
**Fix:** stop the preview server and its workers (see [SKILL.md#cleanup](../SKILL.md)):
```bash
pkill -f "hyperframes.*preview"
pkill -f chrome-headless-shell # only if no other tool uses it — check pgrep first
```
**Avoid:** never leave a `preview` running after review; use `render` (one-shot, self-cleaning) for output. Keep `--workers` low on shared/GPU-less hosts.
## Bug reports
Include `npx hyperframes info` output + the full error log. File at [github.com/heygen-com/hyperframes](https://github.com/heygen-com/hyperframes/issues).