Skip to content

chore(core): UIKit's spring, decay, rubber-band and projection math - #8054

Merged
cixzhang merged 29 commits into
meta:mainfrom
vjeux:wip/uikit-pr-m2
Oct 26, 2026
Merged

cixzhang merged 29 commits into
meta:mainfrom
vjeux:wip/uikit-pr-m2

Conversation

@vjeux

@vjeux vjeux commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Depends on #8053 (and its predecessors); review the last two commits. Until #8053 merges at its approved head, this branch also carries two table commits for it, press.highlightOutCurve (M-PR1) and the velocity note (spec:AST-100 FR2), and its merge with main.

User need

Touch presentations need UIKit's motion math: a sheet released at 1,200 pt/s must land on the detent UIKit would pick, with UIKit's spring and the finger's velocity, and a scroll-like surface must coast and resist like a scroll view.

Problem and solution fit

Pure functions for spec:AST-094 FR3:

  • spring.ts: the damped spring in closed form for all three regimes; conversions between SwiftUI's duration and bounce, response and damping ratio, Core Animation's mass, stiffness and damping, and UIKit's legacy usingSpringWithDamping (from UIKit's measured grid); Core Animation's settling duration; a spring chasing a target moving at constant speed. Overdamping clamps to critical, as Core Animation does.
  • decay.ts, rubberBand.ts, projection.ts: UIScrollView's coast, its resistance past an edge (and inverse), and the release target nearest the projected rest, paging included.
  • uikit/values.test.ts: plays the constants table through this math.

One intent at 2,050 lines: each module ships with the tests that pin it to independent references.

Current specification

spec:AST-094 FR3.

Public delta and caller burden

None: internal, not exported, and no component uses it yet. The changeset is [chore].

Design and alternatives

  • toSpring normalizes a description kept in its source's vocabulary.
  • The decay is the continuous exponential UIScrollView keeps (ln r per millisecond); the projection is WWDC18's geometric series, the target UIKit reports.
  • Rejected: numeric integration; interruption needs exact value and velocity at any time.

Evidence

  • Spring against an independent fourth-order Runge-Kutta integration over a sweep of damping ratios, responses and velocities, a port of WebKit's spring solver, and the WWDC23 conversion equations.
  • Against UIKit on the iOS 26.2 simulator: Core Animation's settlingDuration grid (underdamped to the last digit, critical within 0.02 %), the durations UIKit gives its spring APIs, and the legacy grid from ζ 0.1 to 1.
  • Decay against a per-millisecond simulation; rubber band against UIScrollView's measured overscroll (within 0.5 pt).

Scope

  • One capability is added.
  • Unrelated fixes, cleanup, and policy changes were removed or split.
  • Consumer docs, focused tests, and migration evidence ship with the feature.
  • Public text and artifacts contain no internal Meta context.

Testing

  • pnpm exec vitest run --project ui packages/core/src/motion: 7 files, 316 tests passed.
  • pnpm build, pnpm typecheck, ui and node suites, pnpm check:repo: clean.
  • pnpm -F @astryxdesign/core typecheck: clean.
  • ASTRYX_STRICT_LINT=1 pnpm exec eslint packages/core/src/motion: clean.
  • Prettier, pnpm check:changesets, pnpm check:repo (pre-commit): clean.
  • Size: 11 files, 2,066 lines added, 7 removed.

Stack, in merge order: #8053, #8058, #8059, #8060, #8061, #8054, #8257, #8055, #8056, #8067, #8258, #8071, #8072, #8073, #8074, #8076, #8340; #8067 also follows #8043, #8044, #8348, #8045 and #8446. #8062 is on main.

@vercel

vercel Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
astryx Ready Ready Preview Oct 26, 2026 2:54am UTC

Request Review

@astracat-bot

astracat-bot Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

AI review status for this pull request.

Review status Updated
🟢 Reviewed (for maintainers only) Oct 26, 2026, 3:15 AM UTC

@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

PR Analysis Report

📚 Storybook Preview

View Storybook for this PR

🧪 Sandbox Preview

View Sandbox for this PR

No new or modified components detected.

Bundle Size Summary

Gzip figures measure each package's entry file, not the code an import pulls in.

Package Entry (ESM) Entry gzip before Entry gzip after Delta
@astryxdesign/core 4.9KB 1.2KB 1.2KB 0B
Package stylesheet Gzip before Gzip after Delta
@astryxdesign/core 33.8KB 33.8KB 0B

Accessibility Audit

Status: No accessibility violations detected.

Visual Regression

48 of 502 shot(s) changed.

A change here is a question, not a failure: check whether the after is the
picture you intended. Record that review on the PR. Baseline maintenance is an
explicit dispatch of CI; this report never rewrites the baseline or adds a release gate.

component story theme mode pixels
Selector Indicator Space Bottom Sheet Narrow End RTL neutral light 753,933
Selector Indicator Space Bottom Sheet Wide Start neutral light 740,072
RichTextEditor Markdown parity: side by side probe dark 556,900
RichTextEditor Markdown parity: side by side probe light 538,816
Chat Full AI Chat probe light 230,823
Chat Full AI Chat probe dark 229,805
AppShell With Mobile Nav probe light 217,010
AppShell With Mobile Nav probe dark 216,960
Collapsible Dividers probe dark 66,445
Collapsible Dividers probe light 66,445
AppShell Playground neutral dark 65,198
AppShell Playground neutral light 63,788
Chat Default neutral dark 36,304
Chat Default neutral light 35,767
Chat Empty State probe light 23,531
Chat Empty State probe dark 22,622
ChatAutoScroll Scroll Behavior Comparison neutral dark 15,378
ChatAutoScroll Scroll Behavior Comparison neutral light 14,107
Chat With Attachments probe light 13,406
Chat With Attachments probe dark 11,232

and 28 more.


Generated by PR Enrichment workflow | Storybook | Sandbox | View full report

vjeux added a commit to vjeux/astryx that referenced this pull request Oct 26, 2026
The touch foundation's fold, mergeable against main cd4aca6: her chain
on main (meta#8058, meta#8054, meta#8059, meta#8060) and meta#8258's rework, which keeps touch
motion internal (no theme surface): the generated role table, its script and
the role kinds file are gone, and a table registers only the roles it lists.
The motion doc and its golden take meta#8076's side; the role kinds file stays
deleted.
cixzhang added a commit to vjeux/astryx that referenced this pull request Oct 26, 2026
…cation export reverted; overlap and borrow fixes)

Conflicts in animator.ts and the motion README: meta#8056's Reduce Motion plan
wins, which already carries a waiting move to the next call's invisible
moment and keeps a running dip's borrow. meta#8055's new tests run against the
plan, the re-timing one advancing the clock to the landing and the
preference change written through the media stub.
vjeux added a commit to vjeux/astryx that referenced this pull request Oct 26, 2026
meta#8076's head is F1's fold on the maintainer's chain now on main (meta#8058,
meta#8054, meta#8059, meta#8060): touch motion is internal (the tables register their
values as internal motion roles, with no theme surface), and the
`isRtlElement` resolver.

Conflicts, resolved:
- The theme-roles changeset and the motion guide take meta#8076's side; their
  sentence on ChatLayout's Reduce Motion cross-fade goes with the theme
  surface.
- The CLI goldens for the empty icon set take meta#8076's side and regenerate.
- keyboardModel.test.ts reads the internal role registry (`motionRoleIn`)
  now that the generated role-kind table is gone, and no longer names a
  theme.
vjeux added a commit to vjeux/astryx that referenced this pull request Oct 26, 2026
vjeux added a commit to vjeux/astryx that referenced this pull request Oct 26, 2026
vjeux added a commit to vjeux/astryx that referenced this pull request Nov 3, 2026
vjeux added a commit to vjeux/astryx that referenced this pull request Nov 3, 2026
vjeux pushed a commit to vjeux/astryx that referenced this pull request Nov 3, 2026
The only conflict is docs/specs/AST-094-touch-presentations/spec.md
(add/add): main's copy is the decided record (meta#8409, current), so it
replaces this branch's draft.
vjeux added a commit to vjeux/astryx that referenced this pull request Nov 3, 2026
…he animator

The README keeps this pull request's animator beside meta#8053's sentence on
who reads the table, and this pull request's tests and animator take the
presets' use names (spec:AST-094 FR4).
vjeux added a commit to vjeux/astryx that referenced this pull request Nov 3, 2026
…math) into the Reduce Motion policy

The animator, its tests, the README and the timing table take this pull
request's Reduce Motion policy, which already holds meta#8055's decisions: a
fade of 200 ms at most, no 'keep', every change at once on any other
pointer, and a decay that keeps moving (momentum continues a throw).
meta#8055's call option for the instant form gives way to this pull request's
rule that no call option changes the policy. meta#8055's coast, its curve type
and the presets' use names come through.
vjeux added a commit to vjeux/astryx that referenced this pull request Nov 3, 2026
scroll.ts keeps naming the coast (coast.ts), which this pull request adds.
vjeux added a commit to vjeux/astryx that referenced this pull request Nov 3, 2026
…to the theme motion roles

scroll.ts and timing.ts keep this pull request's registry import beside
meta#8053's DELAYS_CONTENT_TOUCHES_MS and press export; springs.viewChange keeps
its own copy of UIKit's default spring, so each role has its own leaf; the
reference-reading note on springs.menuReducedMotion also says it is not a
theme motion role. The role table is regenerated under the use names, and
this pull request's tests and docs take them (spec:AST-094 FR4).
vjeux added a commit to vjeux/astryx that referenced this pull request Nov 3, 2026
vjeux added a commit to vjeux/astryx that referenced this pull request Nov 3, 2026
vjeux added a commit to vjeux/astryx that referenced this pull request Nov 3, 2026
vjeux added a commit to vjeux/astryx that referenced this pull request Nov 3, 2026
vjeux added a commit to vjeux/astryx that referenced this pull request Nov 3, 2026
vjeux added a commit to vjeux/astryx that referenced this pull request Nov 3, 2026
… release curve, with main) into the theme motion roles

The tables take meta#8053's keys, which already carry spec:AST-094 FR4's use
names, beside this pull request's rename map; the role ids are the same
either way. The menu reduced-motion spring takes meta#8053's reference-reading
note. The role tests reach the table entries by their use names and keep
checking that the old preset and curve-shape names are no role ids.
vjeux added a commit to vjeux/astryx that referenced this pull request Nov 3, 2026
vjeux pushed a commit to vjeux/astryx that referenced this pull request Nov 3, 2026
vjeux added a commit to vjeux/astryx that referenced this pull request Nov 3, 2026
… the press curve pinned) into the animator
vjeux pushed a commit to vjeux/astryx that referenced this pull request Nov 3, 2026
…he animator

# Conflicts:
#	packages/core/src/motion/uikit/scroll.ts
vjeux pushed a commit to vjeux/astryx that referenced this pull request Nov 3, 2026
No conflicts. Brings main with meta#8058 landed and meta#8054 merged, plus meta#8060's
per-group pan and velocity imports and its FR19 decide-by-10-px fix.
vjeux pushed a commit to vjeux/astryx that referenced this pull request Nov 3, 2026
vjeux pushed a commit to vjeux/astryx that referenced this pull request Nov 3, 2026
… plan

MEASUREMENTS.md and the motion README take this branch's lines where they
conflict: its M-RM1 row (the played 200 ms fade) and the animator rows and
section that meta#8054 does not carry.
vjeux pushed a commit to vjeux/astryx that referenced this pull request Nov 3, 2026
vjeux pushed a commit to vjeux/astryx that referenced this pull request Nov 3, 2026
…cation export reverted; overlap and borrow fixes)

Conflicts in animator.ts and the motion README: meta#8056's Reduce Motion plan
wins, which already carries a waiting move to the next call's invisible
moment and keeps a running dip's borrow. meta#8055's new tests run against the
plan, the re-timing one advancing the clock to the landing and the
preference change written through the media stub.

This branch was successfully deployed

1 active deployment
Preview — 3dca43f6 Deployed Oct 26, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants