Skip to content

fix(engine,cli): download headless-shell instead of using system Chrome for local renders#131

Closed
miguel-heygen wants to merge 1 commit into03-29-fix_cli_improve_error_message_for_zero-duration_composition_rendersfrom
03-29-fix_engine_fall_back_to_screenshot_mode_when_system_chrome_is_not_headless-shell
Closed

fix(engine,cli): download headless-shell instead of using system Chrome for local renders#131
miguel-heygen wants to merge 1 commit into03-29-fix_cli_improve_error_message_for_zero-duration_composition_rendersfrom
03-29-fix_engine_fall_back_to_screenshot_mode_when_system_chrome_is_not_headless-shell

Conversation

@miguel-heygen
Copy link
Copy Markdown
Collaborator

@miguel-heygen miguel-heygen commented Mar 29, 2026

Summary

This was the #1 new-user friction pointnpx hyperframes render (without --docker) silently hung for 120s then timed out on machines with system Chrome but no cached chrome-headless-shell.

Root cause: Two issues working together:

  1. CLI (browser/manager.ts): ensureBrowser() returned system Chrome (/usr/bin/google-chrome) as a valid browser for rendering, but system Chrome doesn't support the HeadlessExperimental.beginFrame CDP command required for deterministic frame capture, and older versions are incompatible with the bundled puppeteer-core (protocol mismatch)
  2. Engine (browserManager.ts): acquireBrowser() assumed any binary passed via PRODUCER_HEADLESS_SHELL_PATH was chrome-headless-shell and selected beginframe capture mode

Fix (two layers):

  1. CLI: ensureBrowser() now skips system Chrome entirely for rendering — only uses env override, cached headless-shell, or auto-downloads headless-shell. findBrowser() still returns system Chrome for non-render use cases (dev server, etc.)
  2. Engine: acquireBrowser() now validates the binary path contains chrome-headless-shell before selecting beginframe mode. Falls back to screenshot mode otherwise — defense in depth.

Reproducer

# On a machine with system Chrome but no cached headless-shell
npx hyperframes init test --template blank --non-interactive
cd test && npx hyperframes render --output out.mp4
# Was: 120s silent hang → "Timed out after waiting 120000ms"
# Now: downloads headless-shell → renders successfully in ~6s

Verified

◇  Browser: download          ← first render downloads headless-shell
   507.5 KB · 5.8s · completed

◇  Browser: cache             ← subsequent renders use cached binary
   507.5 KB · 5.8s · completed

Stack

9/9 — Top of stack. Depends on #129.

🤖 Generated with Claude Code

…eadless-shell

The engine assumed any binary passed via PRODUCER_HEADLESS_SHELL_PATH
supported the HeadlessExperimental.beginFrame CDP command. When the
CLI resolved system Chrome (e.g. /usr/bin/google-chrome) instead of
chrome-headless-shell, the render would silently hang for 120s
then timeout — the #1 new-user friction point.

Now checks the binary path for "chrome-headless-shell" before
selecting beginframe capture mode. System Chrome falls back to
screenshot mode which works universally.

Reproducer:
  # On a machine with system Chrome but no chrome-headless-shell cached
  npx hyperframes init test --template blank --non-interactive
  cd test && npx hyperframes render --output out.mp4
  # Was: 120s hang, then "Timed out after waiting 120000ms"
  # Now: renders successfully via screenshot mode
@miguel-heygen miguel-heygen changed the title fix(engine): fall back to screenshot mode when system Chrome is not headless-shell fix(engine,cli): download headless-shell instead of using system Chrome for local renders Mar 29, 2026
@miguel-heygen miguel-heygen marked this pull request as ready for review March 29, 2026 12:12
@miguel-heygen
Copy link
Copy Markdown
Collaborator Author

Consolidated into fix/render-improvements.

@miguel-heygen miguel-heygen deleted the 03-29-fix_engine_fall_back_to_screenshot_mode_when_system_chrome_is_not_headless-shell branch April 6, 2026 23:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant