SDK 1.4.0: WebMCP tool registration
GEO Docs
Design language

Motion

Four spring presets (snappy, smooth, gentle, bouncy) compiled to CSS linear(), fade and exit, choreography, six signature motions, the transition catalogue, reduced motion and performance.

Model

  • Springs (mass 1, described by response and damping ratio) drive position, scale and size. Parameters are compiled to a CSS linear() easing at build time, so the browser composites them without JS. Duration is the result of the spring settling, not a parameter.
  • Fades handle color, opacity and shadow.
  • Exits always use the exit curve: leaving is faster than arriving, and never uses a spring.

Stiffness = (2π / response)², damping = 4π · damping ratio / response.

Presets

PresetTokensResponse / damping ratioStiffness / dampingTo 95%Settled (= duration token)OvershootUse
Snappy--spring-snappy --dur-snappy0.30 / 0.82439 / 34.3168ms430ms1%Press, switch track, selection, indicators, focus ring, menus opening
Smooth--spring-smooth --dur-smooth0.40 / 1.0247 / 31.4303ms570ms0Layout changes, collapsing, drawers, sidebar collapse, making room, hover lift
Gentle--spring-gentle --dur-gentle0.52 / 1.0146 / 24.2394ms710ms0Large surfaces arriving: page content, dialogs, bottom sheets
Bouncy--spring-bouncy --dur-bouncy0.42 / 0.62224 / 18.6174ms720ms8%Arrivals worth noticing: switch thumb, count badges, success check, toast arrival
Fade--ease-fade --dur-fadecubic-bezier(0.2, 0, 0, 1) · 150msColor, opacity, shadow
Exit--ease-exit --dur-exitcubic-bezier(0.3, 0, 1, 1) · 150msEvery exit

"To 95%" is when people perceive the motion as done; the settle time is longer because the tail converges slowly and is invisible.

Spring curves (CSS linear(), 49 points)
--spring-snappy: linear(0, 0.017, 0.0596, 0.1197, 0.1907, 0.2675, 0.3462, 0.424, 0.4985, 0.5685, 0.633, 0.6915, 0.7438, 0.7875, 0.8281, 0.863, 0.8928, 0.9179, 0.9388, 0.956, 0.97, 0.9811, 0.9898, 0.9965, 1.0015, 1.005, 1.0075, 1.0091, 1.0101, 1.0104, 1.0104, 1.01, 1.0094, 1.0087, 1.008, 1.0071, 1.0063, 1.0056, 1.0048, 1.0041, 1.0035, 1.0029, 1.0024, 1.0019, 1.0016, 1.0012, 1.0009, 1.0007, 1);
--spring-smooth: linear(0, 0.0164, 0.0568, 0.1125, 0.1742, 0.2426, 0.3119, 0.3797, 0.4419, 0.5029, 0.5594, 0.6111, 0.6562, 0.6986, 0.7366, 0.7704, 0.7991, 0.8257, 0.849, 0.8694, 0.8866, 0.9023, 0.9159, 0.9277, 0.9375, 0.9464, 0.954, 0.9607, 0.9661, 0.9711, 0.9753, 0.9789, 0.9819, 0.9846, 0.9869, 0.9888, 0.9905, 0.9918, 0.9931, 0.9941, 0.995, 0.9957, 0.9964, 0.9969, 0.9974, 0.9978, 0.9981, 0.9984, 1);
--spring-gentle: linear(0, 0.0151, 0.0528, 0.1032, 0.1641, 0.2272, 0.2938, 0.3596, 0.4209, 0.481, 0.5352, 0.5871, 0.6345, 0.6761, 0.7151, 0.7488, 0.7801, 0.807, 0.8317, 0.8535, 0.8721, 0.889, 0.9033, 0.9163, 0.9277, 0.9372, 0.9459, 0.9531, 0.9596, 0.9651, 0.97, 0.9742, 0.9777, 0.9809, 0.9835, 0.9859, 0.9879, 0.9896, 0.9911, 0.9924, 0.9935, 0.9944, 0.9952, 0.9959, 0.9965, 0.997, 0.9974, 0.9978, 1);
--spring-bouncy: linear(0, 0.0252, 0.0871, 0.174, 0.276, 0.385, 0.4944, 0.5993, 0.6963, 0.7802, 0.858, 0.921, 0.9721, 1.0108, 1.0416, 1.0616, 1.075, 1.0814, 1.0827, 1.0801, 1.0744, 1.067, 1.0584, 1.0496, 1.0403, 1.0317, 1.0241, 1.017, 1.0108, 1.0057, 1.0018, 0.9985, 0.9962, 0.9947, 0.9937, 0.9932, 0.9932, 0.9934, 0.9939, 0.9946, 0.9953, 0.996, 0.9968, 0.9975, 0.9981, 0.9987, 0.9992, 0.9996, 1);
--dur-snappy: 430ms; --dur-smooth: 570ms; --dur-gentle: 710ms; --dur-bouncy: 720ms;

linear() support: Chrome 113+, Safari 17.2+, Firefox 112+. Elsewhere @supports not (transition-timing-function: linear(0, 1)) falls back to --ease-fade at 200 / 320ms.

Choreography

  1. Appear from the trigger: a popover's transform-origin points at its trigger; closing returns the same way.
  2. Dispersion: items in a group appear one after another, moving outward from the source, --stagger 30ms apart, up to 8 (from the 9th on they appear with the 8th). Grids run top-left to bottom-right, menus from the trigger outward, chart series in legend order.
  3. One main motion at a time: while a dialog opens, nothing else in the background animates.
  4. Keep distances short: page-level movement ≤ 16px; no full-page horizontal slides on desktop.
  5. Arrive slowly, leave quickly: exits use exit at 150ms, roughly half the perceived entrance time.

Interruption and direct manipulation

  • Reversible states (hover, selection, expansion, toggles) use transition, so a new state continues from the current value; never @keyframes.
  • Dragging tracks the pointer 1:1; on release, pick the target from the velocity-projected end point and hand the velocity to a spring (a JS spring using the parameters above).
  • Clicks are accepted while an animation runs; never ignore input because a motion hasn't finished.

Six signature motions

NameTriggerBehaviourPresetToken / class
RefractSelecting a chip, segment or list rowbrand-tint spreads in a circle from the click point (clip-path: circle()); the check grows from zero widthSnappy.chip::before, --rx --ry
DisperseA group appears for the first timeItems rise 8px and fade in one after another, outward from the sourceGentle, 30ms apart.disperse, child --i
Focus beamKeyboard focusThe ring converges from 6px outside, transparent, to a 2px offsetSnappyoutline on :focus-visible, @keyframes beam
SweepSkeleton loading; success confirmationA soft band of light passes across: skeletons loop every 1.6s (--specular); success plays once in dispersion colors, 600msFade.skel::after, @keyframes sweep
Lift & pressHovering / pressing clickable cards and buttonsHover +1 level, up 1px; press 0.97 (cards 0.99), −1 levelSmooth / snappy.lift, .btn:active
SpecularPointer moving over a clickable cardA 280px soft light that follows the pointerFade 150ms.lift::after, --mx --my

Transition catalogue

CaseEnterExitPresetUnder reduced motion
Page changeContent rises 8px + fades in; the shell stays stillOld content fades out in 100msGentleFade in only
Tab / segment switchThe indicator slides to the new item (leading edge snappy, trailing edge smooth with a 60ms delay); content cross-fades 150ms + 4px shift in the same direction—SnappyIndicator jumps; content cross-fades
Menu / dropdown / popoverFrom the trigger, 0.96 → 1 + fade in120ms fade + 0.98SnappyFade only
TooltipFade in + 2px shiftDisappears immediatelyFadeFade in only
DialogScrim fades in 200ms; panel 0.96 → 1 + rises 8px150ms fade + 0.98GentleFade only
DrawerSlides in from the edge, 100% → 0200ms exit curveSmoothFade only
Bottom sheet (compact)Rises from the bottom; can be dragged down to closeFollows the finger, or a 200ms exitSmoothFade only
ToastFrom 16px below + 0.9 → 1150ms fade + down 8pxBouncyFade only
BannerHeight expands + fade inHeight collapses + fade outSmoothFade only
Accordiongrid-template-rows: 0fr → 1fr; chevron rotates 180°ReverseSmooth / chevron snappyOpens instantly
List item addedRow height expands + brand-tint fill fades over 1s ("lit up")—SmoothNo height animation; keep the tint fade
List item removed—Height collapses + fades out, with an undo toastSmoothRemoved instantly
Reorder / make roomOther items FLIP to their new positions—SmoothJump into place
Skeleton → content200ms cross-fade (replaced in place, no rise)—FadeSame
NumbersFirst time, 0 → target over 600msOn refresh, only a brand-tint flashDecelerating curveShow the final value
ChartsLines draw over 600ms, areas fade in afterMorph over 400ms when the range changesSmoothShown immediately
Sidebar collapseWidth 256 ↔ 72; labels fade out in 100msReverseSmoothSwitches instantly
Theme switchWhole-page cross-fade, 200ms (View Transitions where supported)—FadeSwitches instantly
Bulk bar / save barRises from the bottom + fades in; count changes bounceSinks + 150ms fadeSmooth / bouncyFade only
Success confirmationThe check draws + one dispersion sweep—Bouncy / fadeCheck only

Reduced motion

With the system setting prefers-reduced-motion: reduce, or "Reduce motion" in the page or account settings (data-motion="reduce"):

  • Spring duration tokens become 1ms (positions arrive instantly).
  • Keep 120–150ms opacity fades so changes are still noticeable.
  • Turn off the dispersion stagger (--stagger: 0), sweep loops (skeletons become static), specular light, number counting (show final values) and the success sweep.
  • Keep pointer tracking while dragging: it's direct manipulation, not animation.

Performance

  • Animate only transform, opacity, clip-path and filter; change shadows by fading a pseudo-element; animate height with grid-template-rows.
  • At most 50 elements moving at once; in long lists, animate only rows in view.
  • Set will-change only while moving, and remove it afterwards.
  • Specular light only on hover: hover devices, with passive pointer listeners and at most one update per frame.