You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Spring easing for transitions and motion (stiffness/damping/mass) #196
The dock (react + motion) uses type: "spring" on every transition (stiffness 400–700, damping 12–30, mass 0.8–0.9), including overshooting entrance/squeeze effects. Our easing model (MotionEase in packages/react/src/types/host.ts, interpolation in packages/native/src/motion.rs:593-840) is keyword + cubic-bezier over a fixed duration only. A spring is physics-integrated with no fixed duration and can overshoot — not expressible as a single bezier.
Shape
MotionEase gains a spring variant: { type: "spring", stiffness, damping, mass, velocity? } accepted by both StyleTransition.easing and MotionTransition.ease (duration ignored/derived when spring, matching motion's semantics).
Native side: closed-form damped-spring solution in motion.rs (or settle-threshold integration), driving the existing interruptible track machinery. Interruption must carry velocity into the new spring, or it loses the main feel benefit.
Browser-mirror analogue: CSS linear() easing is the standard web encoding of sampled springs (and motion/framer-motion is itself a web library). Document the mapping.
Sequencing
Depends-on-in-spirit: #195 (scale) — the dock's springs animate scale; springs land with or after it. Implementation after wave 2, paused if defects come back.
Upstream prior art: remorses/gpuix#34 (open, unmerged) adds a native spring integrator + GELATIN preset. Assessment (2026-09-01): adopt its WIRE FORMAT ({ type: "spring", stiffness, damping, mass, velocity } — matches motion's API) for future-reconciliation convergence, but not its implementation. Compromises we don't take: parallel JS frame loop (onFrame/pumpFrames + JS stepSpring) alongside the native integrator; unit-blind rest threshold (0.05 — 5% on the opacity channel); springs only on motion.* transitions with nothing for StyleTransition (state styles — the whileHover/whileTap path the dock needs); author-taste defaults (36/8/1.2 vs motion's 100/10/1); untagged serde spring arm doesn't validate type; no scale/rotate.
Ideal shape stands as described above: spring as an easing variant driving the existing native interruptible track machinery for BOTH MotionTransition and StyleTransition, velocity carried across interruption, unit-aware settling thresholds. Watch item: if upstream merges #34, the next reconciliation round converges on the shared wire format.
Activity
Ernxst commentedon Sep 1, 2026
Upstream prior art: remorses/gpuix#34 (open, unmerged) adds a native spring integrator + GELATIN preset. Assessment (2026-09-01): adopt its WIRE FORMAT (
{ type: "spring", stiffness, damping, mass, velocity }— matches motion's API) for future-reconciliation convergence, but not its implementation. Compromises we don't take: parallel JS frame loop (onFrame/pumpFrames+ JSstepSpring) alongside the native integrator; unit-blind rest threshold (0.05 — 5% on the opacity channel); springs only on motion.* transitions with nothing forStyleTransition(state styles — the whileHover/whileTap path the dock needs); author-taste defaults (36/8/1.2 vs motion's 100/10/1); untagged serde spring arm doesn't validatetype; no scale/rotate.Ideal shape stands as described above: spring as an easing variant driving the existing native interruptible track machinery for BOTH MotionTransition and StyleTransition, velocity carried across interruption, unit-aware settling thresholds. Watch item: if upstream merges #34, the next reconciliation round converges on the shared wire format.
Stamp 0.6.0-fork.2