Skip to content

fix(three): drive demand-mode frameloop so looping animations don't freeze#2536

Merged
joshuaellis merged 1 commit into
nextfrom
fix/2402
Jun 10, 2026
Merged

fix(three): drive demand-mode frameloop so looping animations don't freeze#2536
joshuaellis merged 1 commit into
nextfrom
fix/2402

Conversation

@joshuaellis

Copy link
Copy Markdown
Member

Looping, sequenced, and delayed animations froze under @react-three/fiber's frameloop="demand". The goal: they should run to completion (and keep looping) with no invalidate()-in-events or useFrame workarounds, while the canvas still sleeps when nothing's animating.

Why it happened

The three target drives rafz from r3f's render loop, which only runs while frames are requested via invalidate(). At a segment boundary the spring goes idle for the microtask gap while the next segment is scheduled — r3f's loop stops and nothing restarts it. Event-driven invalidate() can't bridge it: from r3f's "before" phase it's cancelled by the same-frame frame-count decrement.

The fix

rafz exposes an onDemand signal that fires while it has pending frame work; the three target turns it into an invalidate() deferred a microtask, which restarts r3f's loop after it stops. Demand mode is preserved — once the animation settles, rafz goes idle and the canvas sleeps. A regression guard in @react-spring/core models a bare r3f demand host and asserts a loop: true animation keeps cycling.

Closes #2402.

…reeze

Under `frameloop="demand"` a looping/sequenced animation froze after ~1 segment: rafz is driven from r3f's render loop, which sleeps unless frames are requested, and the loop-restart scheduled in the microtask gap was never rendered. rafz now signals pending frame work via `onDemand`; the three target turns it into a deferred `invalidate()` that restarts r3f's loop. Demand mode is preserved (the canvas sleeps once settled). Closes #2402.
@changeset-bot

changeset-bot Bot commented Jun 10, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 0a44704

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 12 packages
Name Type
@react-spring/rafz Patch
@react-spring/shared Patch
@react-spring/three Patch
@react-spring/animated Patch
@react-spring/core Patch
@react-spring/mock-raf Patch
@react-spring/parallax Patch
@react-spring/types Patch
@react-spring/konva Patch
@react-spring/native Patch
@react-spring/web Patch
@react-spring/zdog Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@joshuaellis
joshuaellis merged commit 40baba5 into next Jun 10, 2026
21 checks passed
@joshuaellis
joshuaellis deleted the fix/2402 branch June 10, 2026 09:17
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.

[bug]: animations with r3f on frameloop="demand" freezing

1 participant