Skip to content

fix(web-animations-api): use bezier-easing 3.2 closed-form solver - #2256

Merged
hustcc merged 2 commits into
antvis:releasefrom
gre:bezier-easing-3
Oct 16, 2026
Merged

hustcc merged 2 commits into
antvis:releasefrom
gre:bezier-easing-3

Conversation

@gre

@gre gre commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Hi, this is @gre, I'm the author of bezier-easing, which is also embedded in this project (packages/g/src/plugins/web-animations-api/utils/bezier-easing.ts). The library was recently improved with better performance and more reliability, and I wanted to backport the benefits here.

This brings its 3.2 solver (closed-form, no sample table) to cubic-bezier(...) easings:

  • Fixes steep curves. For cubic-bezier(1, 0, 0, 1), 0.4996 returned 0.348 instead of 0.431, and the animation went backwards around the middle.
  • Exact. Error goes from up to ~1e-3 to ~1e-14 on regular curves.
  • Faster and smaller. No table is built when an easing is created, and the file goes from 647 to 404 bytes min+gz. The internal helpers it used to export are gone, since nothing else used them.
  • Progress outside [0, 1] now saturates to 0 / 1. The old search returned arbitrary values there.

Includes a patch changeset for @antv/g. The custom-easing and animation.timeline unit tests pass, and eslint and prettier are clean. Compared against bezier-easing 3.2 on ~7.6M values: bit-identical.

download

Replace the sample table + Newton-Raphson + bisection search with the
closed-form solver of bezier-easing 3.2: exact (~1e-14 instead of up to
~1e-3), no backward jump on steep curves such as (1, 0, 0, 1).

Progress outside [0, 1] now saturates to 0 / 1 instead of going through
the old search, which returned arbitrary values there.
@changeset-bot

changeset-bot Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

馃 Changeset detected

Latest commit: d38633b

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

This PR includes changesets to release 2 packages
Name Type
@antv/g Patch
@antv/react-g 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

@hustcc

hustcc commented Oct 10, 2026

Copy link
Copy Markdown
Member

@gre What impact might this bring?

@hustcc

hustcc commented Oct 10, 2026

Copy link
Copy Markdown
Member

@gre Can we just switch to using the bezier-easing package directly?

@gre

gre commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor Author

Hey @hustcc.

It should only affects cubic-bezier(...) easings, and notably it should fix them: today some steep curves are slightly off. For example cubic-bezier(1, 0, 0, 1) gives 0.348 at t=0.4996 when it should be 0.431, so you can see a little backwards jump in the middle of the animation. Named easings and the public API stay the same.

And yes, using the package directly makes sense. bezier-easing@3.2.0 has ESM, CJS and types, no deps, and it's tiny.

@wang1212
wang1212 changed the base branch from master to release October 14, 2026 11:37
@hustcc
hustcc merged commit de8f7d5 into antvis:release Oct 16, 2026
2 checks passed
wang1212 added a commit that referenced this pull request Oct 16, 2026
* perf(g): update animation promises once per frame (#2265)

* perf(g): update animation promises once per frame

Every animation started in a task queued its own no-op frame callback
(AnimationTimeline.tick, and restart() when seeking), and the timeline
wrapped each frame callback in two calls to updateAnimationsPromises,
which goes over every animation with promises. Starting N animations
in one task (G6 does this on every animated draw) therefore cost about
2路N虏 updatePromises calls in the next frame: 32 million for N = 4000.

Run updateAnimationsPromises once before and once after the frame's
callbacks instead. Nothing can change promise state between two
callbacks of the same frame, so the extra calls did nothing.

Tests: six traces of when ready/finished settle relative to frames and
playState, recorded on 6.3.1 and unchanged; three tests that the
bookkeeping stays linear when starting, or seeking paused or finished,
animations in one task (6.3.1: ~2 million calls for n = 1000).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(g): assert the finished read in the promise scaling tests

The helper read `animation.finished` only for its side effect (it puts
the animation on the timeline's promise list), which CodeQL reports as
an expression with no effect. Assert on it instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(web-animations-api): use bezier-easing 3.2 closed-form solver (#2256)

Replace the sample table + Newton-Raphson + bisection search with the
closed-form solver of bezier-easing 3.2: exact (~1e-14 instead of up to
~1e-3), no backward jump on steep curves such as (1, 0, 0, 1).

Progress outside [0, 1] now saturates to 0 / 1 instead of going through
the old search, which returned arbitrary values there.

Co-authored-by: hustcc <i@hust.cc>

* chore(release): bump version (#2268)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

---------

Co-authored-by: Ethan-Icet <80927118+Ethan-Icet@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: @greweb <renaudeau.gaetan@gmail.com>
Co-authored-by: hustcc <i@hust.cc>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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.

2 participants