Repository navigation
Description
Describe the bug
Re-opening the #2477 symptom on 0.8.72: parallel capture emits a fully transparent frame at each worker shard's first frame. The fix PR #2489 was closed unmerged, and discardWarmupCapture still has zero call sites on current main (a3d7736) — only its definition in frameCapture.ts and the re-export in engine/src/index.ts.
Observed with a transparent ProRes 4444 render of a canvas/DOM overlay composition (120 frames @ 24fps, --workers auto → 4 workers, screenshot capture mode): frames 30, 60, 90 decode fully transparent — exactly shardStart = w * (totalFrames / workers) for workers 1–3. Worker 0's first frame is naturally identical to t=0 so it's invisible in the alpha scan. --workers 1 produces zero blank frames; the anomaly is deterministic in position across parallel runs but intermittent (some runs clean), matching the paint-settle race described in #2477.
Notable difference from the original report's setup: our composition registers a non-GSAP duck-typed RuntimeTimelineLike on window.__timelines ({duration, time, seek, totalTime, pause, paused, play, add, set} — pure seek→redraw, no GSAP). If the post-#2477 warm-up logic engages only for GSAP timelines or on a code path duck timelines don't reach, that would explain why the regression survives for this comp shape.
Steps to reproduce
The race is timing-sensitive — a heavier page (custom fonts, canvas setup, larger script payload) widens the window. Composition shape that fails for us ~half the time at 4 workers:
<div id="root" data-composition-id="repro" data-duration="4"
data-width="1920" data-height="1080">
<div id="box"></div>
</div>
<script>
var t = 0;
window.__timelines = window.__timelines || {};
window.__timelines["repro"] = {
duration: function(){ return 4; },
time: function(){ return t; },
seek: function(s){ // pure seek->redraw contract
t = Math.max(0, Number(s) || 0);
// visible whenever t>0; only t=0 state is blank
document.getElementById("box").style.opacity = t > 0.02 ? "1" : "0";
},
totalTime: function(s){ this.seek(s); },
pause: function(){}, paused: function(){ return true; },
play: function(){}, add: function(){}, set: function(){}
};
</script>Detection (alpha scan, same method as #2477):
ffmpeg -i out.mov -vf "alphaextract,signalstats,metadata=mode=print" -f null -
# frames at w * ceil(totalFrames/workers) show alpha mean ~0 between normal neighbors
Expected behavior
Every worker's first captured frame contains the seeked state — e.g. wire discardWarmupCapture into the parallel worker path (it already exists and is exported), or gate the first captureFrame on a post-seek paint commit rather than the seek alone.
Actual behavior
First frame of each non-zero worker shard captures the pre-seek page state (t=0). For fade-in/transparent overlays that state is fully transparent, producing visible flicker in the baked output.
Environment
hyperframes@0.8.72(managed npm install)- macOS arm64, chrome-headless-shell 152.0.7977.30 (CLI-managed cache)
screenshotcapture mode (drawelement not engaged for this comp)- Output:
--format mov(ProRes 4444, yuva444p12le),--fps 24
Additional context
Workaround confirmed on our side: --workers 1 removes the anomaly entirely (verified across a 37-template regression suite with per-frame RGBA diffing). Filing mainly so the #2477 fix can land — the reporter there already wrote it.
Activity
miguel-heygen commentedon Oct 24, 2026
Thanks for the detailed report and the duck-typed repro.
You're right about the code:
discardWarmupCapturestill has no call site on main.I couldn't reproduce the blank frames on 0.8.193, though. I rendered your timeline shape (box hidden only at t = 0, 5 s at 24 fps, so worker slices start at frames 30, 60 and 90) with
--format mov --fps 24 --workers 4, three times, on Linux x64 (screenshot capture, software GPU). The alpha scan showed only frame 0 transparent, which is correct for t = 0. Frames 30, 60 and 90 were normal in every run.Since this is a race and your machine differs from mine, could you:
npx hyperframes@latest(0.8.193 or later) on your Mac and say whether the boundary frames still go blank, and how often.screenshot capture · ...).With a composition that fails reliably, a fix can carry a regression test.