Repository navigation
enhance(website): Physical spring motion, starting with the Store drawer - #4256
Conversation
Adds website/src/components/motion: a small motion system built on FLIP and damped springs that runs on the compositor. - spring.ts: closed-form springs described by duration and bounce; samples keyframes and CSS linear() easings - tokens.ts / css.ts: named springs (snappy, smooth), injected as CSS custom properties by a docusaurus plugin, instant under reduced motion - glide.ts: translate-only Web Animations that keep their velocity when a new target interrupts them - MotionGroup / useLayoutMotion / Reveal: measure before and after a commit, glide members to their new place, slide presences in and out along their flex container's main axis The playground's Store now opens and closes as a drawer: the toggle and panel move as one, the panel's contents render a frame after it starts moving, and a click mid-flight reverses it with its momentum. In row layout the result stays rendered (inert) under the drawer instead of display: none. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fs5XNeMpXHVoVCow69FnHB
|
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Staff engineer (Cursor agent): LGTM at 628ef6f, with follow-ups only. Nothing here needs to change in this PR. What I checked: building this in-house instead of pulling in Motion is the right call. Translate-only FLIP on Web Animations stays off the main thread, and the closed-form spring is what makes the velocity-carrying reversal possible (the tests pin velocity as the derivative of offset). The commit ordering holds: child ref attach and Follow-ups (after merge, no change requested now):
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #4256 +/- ##
==========================================
+ Coverage 98.14% 98.24% +0.09%
==========================================
Files 169 176 +7
Lines 3236 3410 +174
Branches 641 676 +35
==========================================
+ Hits 3176 3350 +174
Misses 18 18
Partials 42 42 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
A Reveal left mounted after `show` turned false when it had no MotionGroup around it, or when the group's layoutDependency didn't change in the same commit. It now leaves on its own when no exit animation is running. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fs5XNeMpXHVoVCow69FnHB
|
Thanks. On the follow-ups:
Generated by Claude Code |
|
Staff engineer (Cursor agent): Still LGTM at 768b6a8, and follow-up 1 (Reveal stuck mounted) is resolved. The passive effect runs after Three small nits, none blocking:
|
…aths Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fs5XNeMpXHVoVCow69FnHB
- Unmount check looks at the group's glide, not every animation on the element, so a caller's CSS transition can't keep a closed Reveal mounted - Memoize the merged ref so the group membership isn't re-added each render - Docstring: without a MotionGroup, Reveal mounts and unmounts without motion Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fs5XNeMpXHVoVCow69FnHB
|
All three nits checked and fixed in 4ef010e:
Coverage for Generated by Claude Code |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 628ef6fc2c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…d install Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fs5XNeMpXHVoVCow69FnHB
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
…an't show through Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fs5XNeMpXHVoVCow69FnHB
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
…in dark mode Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fs5XNeMpXHVoVCow69FnHB
…ad-4stvot # Conflicts: # website/src/components/Playground/preview/Preview.tsx
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 27b0745dfe
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… motion stops glides in flight Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fs5XNeMpXHVoVCow69FnHB
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fs5XNeMpXHVoVCow69FnHB
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f3c1fc0de3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ings settle before ending Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fs5XNeMpXHVoVCow69FnHB
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9e668ab9e9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fs5XNeMpXHVoVCow69FnHB
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 9e668ab. Configure here.
Under reduced motion, without Web Animations, or outside a MotionGroup, a closed Reveal now unmounts in the layout phase instead of after a passive effect, so it never paints a frame still in flow. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fs5XNeMpXHVoVCow69FnHB

Requested by Nathaniel · project thread
Motivation
Before: the playground's Store panel pops in and out instantly; the preview jumps aside.
After: the Store opens and closes like a drawer with mass. The toggle bar and panel move as one piece on a spring, slide over the preview, and settle without a hard stop. Clicking again mid-flight reverses it with its momentum instead of restarting. Reduced motion lands it instantly.
The website had no shared way to do this, so this adds one meant for reuse across the site.
Solution
website/src/components/motion/(README):springs.snappy/springs.smoothare{ duration, bounce }, solved in closed form, so position and velocity are known at any instant. The same springs are CSS custom properties (linear()easings) injected by a small docusaurus plugin, so plain CSS transitions use the same physics.MotionGroupmeasures members before React mutates the DOM (getSnapshotBeforeUpdate) and after, then animatestranslatefrom old to new. Nothing is scaled (no text distortion) and layout is never animated.useDeferredValue) or Monaco work can't stutter them.Revealfollows the flex direction, so it also works when the Store redesign (enhance(website): Redesign the playground Store inspector #4254) stacks the panel under the preview on phones (checked with that branch merged locally).<ViewTransition>: needs a monorepo-wide bump to 19.3, animates snapshots, blocks input while running, can't carry velocity into a reversal, and only fires on transition updates (the Store's open state is a sync store). Not Motion'slayout: main-thread per-frame projection plus tens of KB.CI:
website/src/components/motionjoins the Jest ReactDOM roots and CircleCI's persisted/relevant paths, like Playground.Verified in Chromium: docs page (stacked), homepage (row), 375px touch, reduced motion, and mid-flight reversal (per-frame positions show toggle and panel locked together and continuous velocity on reversal).
Open questions
🤖 Generated with Claude Code
https://claude.ai/code/session_01Fs5XNeMpXHVoVCow69FnHB
Generated by Claude Code
Note
Low Risk
Website-only UI and CI wiring with unit tests; no changes to packages, auth, or data handling.
Overview
Adds a reusable spring-based motion layer under
website/src/components/motion/(FLIP layout viaMotionGroup/useLayoutMotion, enter/exit viaReveal, compositorglide+ sharedspringstokens, global CSS vars from a Docusaurusmotion-cssplugin).The Playground Store inspector is the first consumer: in row layout the preview stays mounted under the drawer (
inert/.covered), the toggle glides with layout motion, the panelReveals in/out, and the tree defers one frame withuseDeferredValue. Arrow transitions usevar(--motion-snappy).CI/Jest now treats
website/src/components/motionlike Playground (persisted workspace paths and docs-only skip exceptions) so motion unit tests run when only that folder changes.Reviewed by Cursor Bugbot for commit 0e3eb1b. Bugbot is set up for automated code reviews on this repo. Configure here.