Skip to content

Render with -w auto deadlocks on shader+audio compositions (Runtime.callFunctionOn timeout) #521

@andretoledo1-lang

Description

@andretoledo1-lang

Summary

hyperframes render with the default parallel worker pool (-w auto) consistently deadlocks when a composition combines a HyperShader.init() transition with at least one <audio> clip. All workers eventually time out with Runtime.callFunctionOn timed out. Falling back to -w 1 renders the same composition cleanly.

Repro

Minimal composition with one shader transition between two anchor scenes plus an audio clip.

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/@hyperframes/core/dist/hyperframe.runtime.iife.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/@hyperframes/shader-transitions/dist/index.global.js"></script>
  <style>
    html,body{margin:0;width:1080px;height:1920px;background:#0a0a0c;color:#fff;overflow:hidden}
    .scene{position:absolute;inset:0;width:1080px;height:1920px}
    #s2{background:#f5efde;color:#0a0a0c}
  </style>
</head>
<body>
  <div id="root" data-composition-id="main" data-start="0" data-duration="6" data-width="1080" data-height="1920">
    <audio class="clip" data-start="0" data-duration="3" data-track-index="9" src="narration.wav"></audio>
    <div class="scene clip" id="s1" data-start="0" data-duration="3" data-track-index="0" style="opacity:0;">
      <h1 style="font-size:200px;text-align:center;margin-top:800px">SCENE 1</h1>
    </div>
    <div class="scene clip" id="s2" data-start="3" data-duration="3" data-track-index="0" style="opacity:0;">
      <h1 style="font-size:200px;text-align:center;margin-top:800px">SCENE 2</h1>
    </div>
  </div>
  <script>
    window.__timelines = window.__timelines || {};
    var tl = gsap.timeline({ paused: true });
    tl.set("#s1", { opacity: 1 }, 0);
    window.HyperShader.init({
      bgColor: "#0a0a0c",
      scenes: ["s1", "s2"],
      timeline: tl,
      transitions: [{ time: 2.75, shader: "cinematic-zoom", duration: 0.5 }]
    });
    window.__timelines["main"] = tl;
  </script>
</body>
</html>

Any short WAV/MP3 (~3s) at narration.wav is enough — the bug is independent of audio content.

# Fails (default — auto picks 8 workers on a 16-core M4 Max):
npx hyperframes render --quality high

# Succeeds (~2 min):
npx hyperframes render --quality high -w 1

Observed behavior

After ~12 minutes wall-clock, all workers fail with the same error:

[Parallel] Capture failed:
  Worker 0: Runtime.callFunctionOn timed out. Increase the 'protocolTimeout' setting in launch/connect calls for a higher timeout if needed.
  Worker 1: Runtime.callFunctionOn timed out. ...
  Worker 2: Runtime.callFunctionOn timed out. ...
  Worker 3: Runtime.callFunctionOn timed out. ...
  Worker 4: Runtime.callFunctionOn timed out. ...
  Worker 5: Runtime.callFunctionOn timed out. ...
✗ Render failed
   Try --docker for containerized rendering

Progress hangs at 25% Starting frame capture with [non-blocking] Failed to load resource: the server responded with a status of 404 (Not Found) lines (preconnect to fonts.gstatic.com failing in headless — those are benign, the deterministic @font-face injection takes over for actual rendering).

Expected

Same render pipeline that succeeds with -w 1 should succeed with -w auto (workers are stateless seekers — there's no obvious reason a worker count should change correctness).

Hypothesis

Race condition between:

  • HyperShader transition windows that require html2canvas snapshots of both anchor scenes during seek
  • The <audio> element's canplaythrough readiness gate that the runtime waits on before emitting a frame

When two workers happen to seek into the same shader window simultaneously, one ends up blocked waiting on a canvas snapshot while another is blocked waiting on the same audio element's readiness — both time out before either resolves.

This would explain why:

  • Pure-visual compositions (no audio) render fine in parallel
  • Audio-only compositions (no shader) render fine in parallel
  • Only the combination deadlocks

System

  • HyperFrames CLI: 0.4.31 (latest at time of report)
  • Node: v24.13.0 (darwin arm64)
  • macOS: 24.6.0
  • CPU: Apple M4 Max, 16 cores
  • RAM: 128 GB (>20 GB free during render)
  • Chrome: system, version 147.0.7727.117
  • FFmpeg: 8.1
  • Workers chosen by -w auto: 8 (per 16 cores detected)

Workaround

-w 1 reliably succeeds in ~2 min for a 12s composition with one shader and one audio clip. Trade-off is wall-clock time vs the parallel render's potential 5-8x speedup.

Suggested fixes (low confidence — open to discussion)

  1. Bump Puppeteer's protocolTimeout for shader-transition windows specifically — let workers wait longer when they're inside a shader range.
  2. Serialize seeks within each shader window even when using parallel workers (one worker at a time inside the [time, time+duration] interval).
  3. Detect the shader+audio combo at compile time and fall back to -w 1 automatically with a warning, rather than letting the user discover this via a 12-minute timeout.

Happy to share more logs, tests, or a public repo with a minimal repro if useful. Thanks for the framework — hyperframes has been a great experience overall, just hit this one sharp edge.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions