Motion
Spring presets, press/release asymmetry, rubber banding, and dot effects
Live Demos
Motion is physics
Springs, not linear easing. Asymmetric press and release. Objects have weight. See it in action.
Spring Comparison
Three easings side by side. Fluent is fast and snappy. Spring overshoots then settles. Linear has no character — it exists here as a foil.
Fluent
Spring
Linear
Press / Release Asymmetry
Press is fast and stiff. Release is slow and bouncy. This creates the tactile responsiveness that makes FORK feel physical.
Interact to see asymmetry
Easing Curves
Visual representation of the three core timing functions. The dot traces the curve path to show how velocity changes over time.
Fluent
0.2, 0, 0, 1
Spring
0.34, 1.56, 0.64, 1
Press
0.4, 0, 0.2, 1
Dot Pattern States
The dot grid cycles through its three opacity states: idle, tap, and field. On native, these are Metal point sprites running at 60fps.
When to use
- Spring comparison/Reference for choosing between Fluent (snappy), Spring (bouncy), and linear (avoid). Default to Fluent for UI transitions.
- Press / release/All tappable elements. Press is fast (0.18s), release is slow and bouncy (0.25s). This asymmetry creates tactile feel.
- Easing curves/Visual reference for the three core timing functions. Match curve shape to interaction intent.
Platform notes
- iOS All demos above use true spring dynamics on native — UISpringTimingParameters with mass, stiffness, damping. Results differ visually from the CSS cubic-bezier approximations shown here.
- Android Compose uses
spring()withdampingRatioandstiffness. Android Views (non-Compose) useSpringAnimationfrom AndroidX DynamicAnimation withsetDampingRatio()andsetStiffness(). Both produce true spring dynamics — tune by eye to match iOS, not by raw values. - Web CSS
spring()is not supported. Usecubic-bezier()approximations from Motion Tokens below. The visual difference is subtle for most UI transitions.
Motion Tokens
Timing
Spring Presets iOS
Fluent
mass 1 · stiffness 555 · damping 44
Standard
mass 1 · stiffness 369 · damping 30
Chat input
mass 1 · stiffness 594 · damping 38
Presentation
stiffness 369 · damping 38
Compose Spring Android
Fluent
Spring(dampingRatio=1f, stiffness=400f)
Standard
Spring(dampingRatio=0.6f, stiffness=300f)
Note
Android uses stiffness+damping model. Tune by eye to match iOS.
CSS Equivalents Web
Fluent
cubic-bezier(0.2, 0, 0, 1) 0.25s
Spring
cubic-bezier(0.34, 1.56, 0.64, 1) 0.4s
Standard
cubic-bezier(0.4, 0, 0.2, 1) · duration varies
Press / Release
Standard 0.18s → Spring 0.25s
Note
CSS spring() not supported — use bezier approximations
Interaction
Highlight — Press
Scale factor
0.96× (down)
Timing
damping 0.9 · response 0.1
Duration
0.18s
Lift scale
1.04× (up) · iOS 26
Lift shadow
radius 12 · opacity 0.15
Highlight — Release
Scale release
damping 0.4 · response 0.3
Scale duration
0.25s
Lift release
damping 0.5 · response 0.35
Lift duration
0.30s
Release delay
0.06s
System
Loading & Transitions
Blur radius
4.5pt (content swap)
Blur delay factor
0.52 (52% into animation)
Gracetime (light)
1.2s
Gracetime (regular)
0.28s
Gracetime (heavy)
0s (immediate)
Rubber Banding
Max offset
8pt
Tracking speed
0.15
Default speed
0.55
Haptics
Button tap
.soft impact (touchUpInside)
Scroll-to-bottom
.soft impact
Chat scale
0.88× (iOS < 26)
Dot Pattern
Dot Effects
Ripple
speed 13 · width 10 · 3.0s
Ring (drag trail)
speed 2 · width 80 · 4.0s
Shockwave
speed 25 · width 6 · 1.2s
Bloom
speed 1.5 · radius 100 · 5.0s
Noise tint
speed 2 · width 300 · 8.0s
Dot Physics
Spring constant
0.03
Velocity damping
0.88
Relaxation
0.02
Falloff exponent
2.0
Gravity duration
0.4s (transient)
When to use
- Fluent spring/Fast, snappy — panel transitions, tab switches, navigation. iOS stiffness 555, damping 44. Android
Spring(dampingRatio=1f, stiffness=400f). Webcubic-bezier(0.2, 0, 0, 1) 0.25s - Standard spring/General-purpose bounce — content changes, card transforms, modal presentations. iOS stiffness 369, damping 30. Android
Spring(dampingRatio=0.6f, stiffness=300f). Webcubic-bezier(0.34, 1.56, 0.64, 1) 0.4s - Press → release asymmetry/Press is fast and stiff (0.18s). Release is slow and bouncy (0.25s). This creates tactile responsiveness. Works identically on all platforms. Android Use
Animatable.animateTo()with different spring specs for press (stiffer) and release (lower damping, more bounce). - Gracetime/Never show spinner for fast operations. Regular delay (0.28s) covers most API calls. Web Implement with
setTimeoutbefore adding.btn--loading. - Rubber banding/Max 8pt displacement, 0.15 elasticity. iOS Applied to lifted buttons during finger tracking. Android Use
SpringAnimationwith resistance factor for custom rubber banding. Android also hasEdgeEffectfor standard overscroll. - Haptics/iOS .soft impact on button tap. Android Use
HapticFeedbackConstants.CONFIRMorVibrationEffect.createPredefined(EFFECT_CLICK). Web No haptic API widely available — rely on visual feedback only.
Platform notes
- iOS Use UISpringTimingParameters with the mass/stiffness/damping values from the Spring Presets spec cards. True spring dynamics — not cubic-bezier approximations.
- Android Compose: use
spring(dampingRatio, stiffness)from the Compose Spring spec card. Views: useSpringAnimationfrom AndroidX DynamicAnimation withsetDampingRatio()andsetStiffness(). Both produce true spring dynamics. - Android Key difference: Android springs use a stiffness + dampingRatio model. iOS uses mass + stiffness + damping (or response + dampingFraction). The perceptual result should match — tune by eye, not by raw values.
- Android Press/release asymmetry: use
Animatable.animateTo()with a stiffer spring spec for press and a bouncier (lower damping ratio) spec for release. - Android Rubber banding: Android has
EdgeEffectfor standard overscroll. For custom rubber banding (lifted buttons), useSpringAnimationwith a resistance factor. - Web CSS
spring()is not supported. Usecubic-bezier()from CSS Equivalents spec card. Pair with explicittransition-duration— bezier curves need a duration, springs don't. - Web Implement gracetime delay in JS:
setTimeoutbefore adding.btn--loading. Do not show spinners for operations under 0.28s.