Describe the bug
HyperFrames render process consistently freezes at 25% "Starting frame capture" phase when rendering a simple video element composition on a low-resource system (Intel i5-7200U, 8GB RAM, Intel HD 620 GPU, Lubuntu 24.04). Headless Chrome crashes, leading to "Protocol error (Runtime.callFunctionOn): Target closed".
Steps to reproduce
- System Configuration:
- OS: Lubuntu 24.04 (Linux x64)
- CPU: Intel(R) Core(TM) i5-7200U CPU @ 2.50GHz (4 cores)
- RAM: 8 GB (1.8 GB free reported by
hyperframes doctor)
- GPU: Intel HD Graphics 620
hyperframes CLI version: 0.6.43
- Composition: An HTML file with:
- A single
<video> element (8s, 1080x1920 MP4 or WEBM, muted, playsinline).
- Minimal GSAP timeline (registered as
window.__timelines["main"]).
- No complex CSS, animations, or overlays.
Exact composition content:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"><title>Mockup Video</title>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.15/dist/gsap.min.js"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { background: #000; overflow: hidden; }
#stage { width: 1080px; height: 1920px; margin: 0 auto; background: #000; }
video { width: 100%; height: 100%; object-fit: contain; }
</style>
</head>
<body>
<div id="stage" data-composition-id="mockup" data-width="1080" data-height="1920" data-start="0">
<video id="mockup-video" muted playsinline data-track-index="0" data-start="0" data-duration="8" src="assets/mockup.mp4"></video>
</div>
<script>
window.__timelines = window.__timelines || {};
window.__timelines['mockup'] = gsap.timeline({ paused: true });
</script>
</body>
</html>
- Command to reproduce:
npx hyperframes render index.html -o output.mp4 --fps 30 --quality standard --workers 1 --browser-args="--disable-dev-shm-usage"
(Also tried without browser-args and with/without --workers 1.)
- Observe:
- Render progresses to 25% ("Starting frame capture") then freezes.
- After ~30s, terminates: "Protocol error (Runtime.callFunctionOn): Target closed".
- Earlier: "Auto-worker calibration failed; using conservative worker budget".
Expected behavior
HyperFrames should render the HTML composition into a video, or gracefully fail with a clear error if memory is insufficient, instead of crashing silently.
Actual behavior
Crash at 25% progress ("Starting frame capture"). Headless Chrome exits with: Protocol error (Runtime.callFunctionOn): Target closed. No clear explanation about memory exhaustion is given. See debug output and clues below.
Environment
✓ Version 0.6.43 (latest)
✓ Node.js v22.22.2 (linux x64)
✓ CPU 4 cores · Intel(R) Core(TM) i5-7200U CPU @ 2.50GHz @ 2342MHz
✗ Memory 7.6 GB total · 1.8 GB free
Low memory — renders may fail. Close other apps or increase RAM.
✓ Disk 41.8 GB free
✓ /dev/shm 3907 MB
✓ Environment Native terminal
✓ FFmpeg ffmpeg version 6.1.1-3ubuntu5 Copyright (c) 2000-2023 the FFmpeg developers
✓ FFprobe ffprobe version 6.1.1-3ubuntu5 Copyright (c) 2007-2023 the FFmpeg developers
✓ Chrome cache: /home/anas/.cache/hyperframes/chrome/chrome-headless-shell/linux-131.0.6778.85/chrome-headless-shell-linux64/chrome-headless-shell
✓ Docker Docker version 29.1.3, build 29.1.3-0ubuntu3~24.04.2
✗ Docker running Not running
Start Docker Desktop or run: sudo systemctl start docker
◇ Some checks failed — see hints above
Additional context
Auto-worker calibration failed, conservative worker budget used. Rendering a simple video composition on a low-memory machine triggers Chrome crash (see error above). Likely cause: memory exhaustion from managing a large number of high-res frames as <img> elements (see injectVideoFramesBatch, syncVideoFrameVisibility in /packages/engine/src/services/screenshotService.ts).
Possible solutions:
-
Lazy Loading/Windowing: Only a small buffer of frames (e.g., current +/- 2–5) should be active in the DOM at once, substantially reducing memory and layout overhead compared to the current approach that accumulates hundreds of <img> elements per video.
-
Dynamic src Updates: Instead of new <img> elements per frame, maintain a single persistent <img> element (or a tiny pool). Changing its src attribute each frame minimizes DOM bloat and allows Chrome to efficiently garbage collect previous image data.
-
Off-screen Canvas Pre-loading: Preload upcoming frames into off-screen canvases or ImageBitmaps. This avoids oversized base64 data URIs, enables more efficient memory usage (raw pixel data is smaller), and can make frame display smoother on low-resource systems.
-
Aggressive Memory Monitoring & Adaptive Quality: Check free system memory before each render. If low, automatically reduce rendered frame resolution, switch to JPEG from PNG, or drop frame cache size – gracefully degrading quality so renders complete instead of crashing.
Describe the bug
HyperFrames render process consistently freezes at 25% "Starting frame capture" phase when rendering a simple video element composition on a low-resource system (Intel i5-7200U, 8GB RAM, Intel HD 620 GPU, Lubuntu 24.04). Headless Chrome crashes, leading to "Protocol error (Runtime.callFunctionOn): Target closed".
Steps to reproduce
hyperframes doctor)hyperframesCLI version: 0.6.43<video>element (8s, 1080x1920 MP4 or WEBM, muted, playsinline).window.__timelines["main"]).Exact composition content:
npx hyperframes render index.html -o output.mp4 --fps 30 --quality standard --workers 1 --browser-args="--disable-dev-shm-usage"Expected behavior
HyperFrames should render the HTML composition into a video, or gracefully fail with a clear error if memory is insufficient, instead of crashing silently.
Actual behavior
Crash at 25% progress ("Starting frame capture"). Headless Chrome exits with: Protocol error (Runtime.callFunctionOn): Target closed. No clear explanation about memory exhaustion is given. See debug output and clues below.
Environment
✓ Version 0.6.43 (latest) ✓ Node.js v22.22.2 (linux x64) ✓ CPU 4 cores · Intel(R) Core(TM) i5-7200U CPU @ 2.50GHz @ 2342MHz ✗ Memory 7.6 GB total · 1.8 GB free Low memory — renders may fail. Close other apps or increase RAM. ✓ Disk 41.8 GB free ✓ /dev/shm 3907 MB ✓ Environment Native terminal ✓ FFmpeg ffmpeg version 6.1.1-3ubuntu5 Copyright (c) 2000-2023 the FFmpeg developers ✓ FFprobe ffprobe version 6.1.1-3ubuntu5 Copyright (c) 2007-2023 the FFmpeg developers ✓ Chrome cache: /home/anas/.cache/hyperframes/chrome/chrome-headless-shell/linux-131.0.6778.85/chrome-headless-shell-linux64/chrome-headless-shell ✓ Docker Docker version 29.1.3, build 29.1.3-0ubuntu3~24.04.2 ✗ Docker running Not running Start Docker Desktop or run: sudo systemctl start docker ◇ Some checks failed — see hints aboveAdditional context
Auto-worker calibration failed, conservative worker budget used. Rendering a simple video composition on a low-memory machine triggers Chrome crash (see error above). Likely cause: memory exhaustion from managing a large number of high-res frames as
<img>elements (see injectVideoFramesBatch, syncVideoFrameVisibility in /packages/engine/src/services/screenshotService.ts).Possible solutions:
Lazy Loading/Windowing: Only a small buffer of frames (e.g., current +/- 2–5) should be active in the DOM at once, substantially reducing memory and layout overhead compared to the current approach that accumulates hundreds of
<img>elements per video.Dynamic src Updates: Instead of new
<img>elements per frame, maintain a single persistent<img>element (or a tiny pool). Changing itssrcattribute each frame minimizes DOM bloat and allows Chrome to efficiently garbage collect previous image data.Off-screen Canvas Pre-loading: Preload upcoming frames into off-screen canvases or ImageBitmaps. This avoids oversized base64 data URIs, enables more efficient memory usage (raw pixel data is smaller), and can make frame display smoother on low-resource systems.
Aggressive Memory Monitoring & Adaptive Quality: Check free system memory before each render. If low, automatically reduce rendered frame resolution, switch to JPEG from PNG, or drop frame cache size – gracefully degrading quality so renders complete instead of crashing.