Repository navigation
Description
A reproducible deferred-DOM capture case on [email protected] (npm gitHead 76f8a567a5f4ff7b5b75b0c67c770b7152bf56b6). Related to #4435, but this is a GSAP + transparent PNG-sequence case and shows pending virtual-rAF work, rather than a duck-typed timeline/ProRes case.
The normal composition is clean. A composition that defers a DOM update through requestAnimationFrame renders successfully but drops visible text/image content from initial frames of each worker. Snapshot/browser checks look correct once deferred updates have settled.
A minimal way to expose the readiness boundary is an onUpdate callback that schedules a reveal through several rAF turns:
<!doctype html><html><head>
<script src="./node_modules/gsap/dist/gsap.min.js"></script>
<style>html,body{margin:0;background:transparent}#text{color:white;font:48px sans-serif}</style>
</head><body>
<div data-composition-id="main" data-start="0" data-duration="2" data-width="640" data-height="360">
<div id="text">A complete headline</div>
</div>
<script>
const text = document.getElementById('text');
const tl = gsap.timeline({paused:true,onUpdate(){
text.style.visibility='hidden';
let pending=10;
function reveal(){
if(--pending>0) requestAnimationFrame(reveal);
else text.style.visibility='visible';
}
requestAnimationFrame(reveal);
}});
tl.to('#text',{x:4,duration:2,ease:'none'},0);
window.__timelines={main:tl};
tl.seek(0);
</script></body></html>Install [email protected] and [email protected], then render with PRODUCER_FORCE_SCREENSHOT=true:
hyperframes render --format png-sequence --output frames --fps 24 --workers 2 --browser-gpu --experimental-fast-capture=falseMeasured with a fuller 48-frame regression fixture containing multiple text regions, an image card, and a locally bundled web font:
- Windows x64, Chrome Headless Shell 152.0.7977.30, Microsoft Basic Render Driver: 18/48 frames have missing content with two workers; 9/48 with one worker.
- Linux x64, same Chrome, AMD hardware WebGL renderer: 18/48 with two workers.
- Explicit software capture has the same deferred-work result.
- After draining finite deferred author callbacks at the current virtual time, waiting for fonts/image decode and two native paint frames: 0/48 missing frames with two workers on both platforms. Ordinary compositions and a deterministic timestamp-based continuous canvas loop also remain clean.
This is an adversarial readiness regression, not a claim that every real-world GPU missing-layer report has this cause. It makes the missing per-seek readiness boundary observable without depending on a random GPU failure.
In the published frame capture implementation, font/image readiness happens during initialization, while subsequent capture can follow the seek without a general native paint barrier. Also, window.requestAnimationFrame is virtualized: awaiting two ordinary rAF callbacks from the capture barrier can stall unless virtual callbacks are explicitly driven. Native compositor waits need the stored originalRequestAnimationFrame (or an equivalent explicit compositor commit).
Could the engine define and enforce a per-frame readiness contract here? A useful fix would settle finite deferred DOM work at the authored time, check newly active assets, commit paint before capture, and recapture/report suspected incomplete frames. Continuous deterministic rAF loops should remain supported. Unconditionally double-capturing every frame adds substantial cost, so confirmation can be reserved for startup or instability signals.
Activity
miguel-heygen commentedon Oct 24, 2026
Thanks for the minimal composition. It made this easy to confirm. I reproduced it on 0.8.193 on Linux x86_64 with your exact file and command, without
--browser-gpu. The render succeeds, but 18 of 48 frames have no text: frames 1-9 and 25-33, the first nine frames of each worker's range. Every other frame shows the headline. That matches your two-worker count.So capture after a seek doesn't wait for author
requestAnimationFramework that is still pending at that time. Each worker's first frames are taken before the deferred reveal has run. The open #6007 targets this, and review is continuing there, including the question of what per-frame readiness should guarantee.