FORK

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
cubic-bezier(0.2, 0, 0, 1) 0.25s
Spring
cubic-bezier(0.34, 1.56, 0.64, 1) 0.4s
Linear
linear 0.4s
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.
Idle
5 - 10% opacity
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() with dampingRatio and stiffness. Android Views (non-Compose) use SpringAnimation from AndroidX DynamicAnimation with setDampingRatio() and setStiffness(). Both produce true spring dynamics — tune by eye to match iOS, not by raw values.
  • Web CSS spring() is not supported. Use cubic-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). Web cubic-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). Web cubic-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 setTimeout before adding .btn--loading.
  • Rubber banding/Max 8pt displacement, 0.15 elasticity. iOS Applied to lifted buttons during finger tracking. Android Use SpringAnimation with resistance factor for custom rubber banding. Android also has EdgeEffect for standard overscroll.
  • Haptics/iOS .soft impact on button tap. Android Use HapticFeedbackConstants.CONFIRM or VibrationEffect.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: use SpringAnimation from AndroidX DynamicAnimation with setDampingRatio() and setStiffness(). 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 EdgeEffect for standard overscroll. For custom rubber banding (lifted buttons), use SpringAnimation with a resistance factor.
  • Web CSS spring() is not supported. Use cubic-bezier() from CSS Equivalents spec card. Pair with explicit transition-duration — bezier curves need a duration, springs don't.
  • Web Implement gracetime delay in JS: setTimeout before adding .btn--loading. Do not show spinners for operations under 0.28s.