Skip to content

fix(core): floor adaptive precision at float resolution to let springs settle on sub-precision drift#2520

Merged
joshuaellis merged 1 commit into
nextfrom
fix/2208
May 23, 2026
Merged

fix(core): floor adaptive precision at float resolution to let springs settle on sub-precision drift#2520
joshuaellis merged 1 commit into
nextfrom
fix/2208

Conversation

@joshuaellis
Copy link
Copy Markdown
Member

Closes #2208.

Summary

When a caller passes a target value to controller.start() that differs from the current value by less than the smallest difference doubles can represent at that magnitude, the spring entered animation with an adaptive precision the math could never satisfy — so the animation never finished and the awaited start() promise never resolved. The original repro is layout code computing positions with Math.cos(Math.PI / 2): JS returns 6.12e-17 instead of 0, so a "logical 160" target arrives as 159.99999999999997. isEqual(160, 159.99999999999997) is false, the spring sees a non-zero distance, and the adaptive precision (|to - from| * 0.001 ≈ 3.5e-18) is unrepresentable. The spring drifts forever; frameLoop never goes idle.

The fix floors the adaptive default at max(|to|, |from|, 1) * Number.EPSILON — the smallest meaningful precision for the values being animated. Caller-supplied config.precision and the from === to fast path are unchanged.

Repro

const ctrl = new Controller({ x: 160, y: 0, scale: 1 })
const driftedTarget = 160 * Math.cos(Math.PI + Math.PI / 2) + 160
// 159.99999999999997 — sub-precision drift from 160

await ctrl.start({ x: driftedTarget, y: 110, scale: 0 })
// previously never resolved

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 23, 2026

🦋 Changeset detected

Latest commit: 6f96c9c

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/core Patch
@react-spring/animated Patch
@react-spring/mock-raf Patch
@react-spring/parallax Patch
@react-spring/rafz Patch
@react-spring/shared Patch
@react-spring/types Patch
@react-spring/konva Patch
@react-spring/native Patch
@react-spring/three 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

@vercel
Copy link
Copy Markdown

vercel Bot commented May 23, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
react-spring Error Error May 23, 2026 2:29pm

Request Review

@joshuaellis joshuaellis merged commit 831a1bd into next May 23, 2026
21 of 22 checks passed
@joshuaellis joshuaellis deleted the fix/2208 branch May 23, 2026 14:33
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]: Promise returned by Controller.start is not resolved consistently

1 participant