# Motion tokens

Source: https://www.springs.studio/?e=sub*subtle*b.20.0.0.100*140*r70*40&e=std*standard*b.20.0.0.100*200*r70*40&e=emp*emphasized*b.20.0.0.100*280*r70*40&pu=sub.std.std.std.emp.emp.emp

## The set

3 motions, each shipping an entrance and an exit.

- `motion.subtle.enter` — 140ms, cubic-bezier(0.2, 0, 0, 1)
- `motion.subtle.exit` — 98ms, cubic-bezier(1, 0, 0.8, 1)
- `motion.standard.enter` — 200ms, cubic-bezier(0.2, 0, 0, 1)
- `motion.standard.exit` — 140ms, cubic-bezier(1, 0, 0.8, 1)
- `motion.emphasized.enter` — 280ms, cubic-bezier(0.2, 0, 0, 1)
- `motion.emphasized.exit` — 196ms, cubic-bezier(1, 0, 0.8, 1)

## Purposes

Aliases, not copies. Prefer these at call sites.

- `state` → `subtle` (enter and exit)
- `dropdown` → `standard` (enter and exit)
- `tooltip` → `standard` (enter and exit)
- `list` → `standard` (enter and exit)
- `drawer` → `emphasized` (enter and exit)
- `modal` → `emphasized` (enter and exit)
- `toast` → `emphasized` (enter and exit)

## Rules

1. **Entrances decelerate.** Fast at the start, settling into rest. An entrance that accelerates into its resting place is the most common way a set feels wrong, and neither the durations nor the stagger will tell you it is happening. Every token in the JSON reports a `direction` so this is checkable rather than a matter of taste.
2. **Exits are faster and flatter than entrances.** The exit curve is the mirror of the entrance — a spring exit loses its bounce entirely. An entrance introduces something; an exit removes something the user has already finished with, and lingering reads as lag.
3. **Reach for a purpose, not a raw duration.** The purpose aliases above say what a motion is for; the durations say only how long it is.
4. **Duration should grow with travel distance, sub-linearly.** Roughly `duration x (travel / 160px)^0.5`, clamped to 0.6x-1.8x. Apply it to motions that actually travel; a checkbox filling has no distance.
5. **Stagger falls off.** Each motion carries its own per-child offset — subtle 40ms, standard 40ms, emphasized 40ms — applied as `offset x index^0.85`, so a long list doesn't take proportionally long.
6. **Always ship the `prefers-reduced-motion` block.** It's in the CSS export already. In Framer Motion use `<MotionConfig reducedMotion="user">`.

## A spring has no duration

It approaches its target asymptotically and never arrives. Any duration you see for a spring is a *settling threshold* — the point at which the runtime decides it's close enough. Different runtimes pick differently, so the same spring honestly reports different durations on different platforms. The numbers above use Framer Motion's convention.

## Porting to platforms this tool doesn't export

Only `k/m` and `c/m` affect the motion, so normalising mass to 1 is lossless — not an approximation.

- **SwiftUI**: `response = 2π·√(m/k)`, `dampingFraction = c / (2·√(k·m))`. Beziers map to `.timingCurve(x1, y1, x2, y2, duration:)`.
- **Compose**: `stiffness = k/m`, `dampingRatio = c / (2·√(k·m))` — mass is fixed at 1 there, which the normalisation above makes exact. Beziers map to `CubicBezierEasing(x1, y1, x2, y2)`.

## Changing this set

Every parameter is optional; with none you get the default set.

```
e    Repeated once per motion, six fields separated by "*":
       id*name*easing*durationMs*exit*staggerMs
     easing is one of
       b.<x1>.<y1>.<x2>.<y2>   cubic-bezier, all four values x100,
                               so cubic-bezier(0.2,0,0,1) is b.20.0.0.100
       s.<stiff>.<damp>.<mass>.<velocity>
                               stiffness and damping as-is; mass and
                               velocity x100, so mass 1 is written 100
     exit is r<percent> (a share of the entrance) or a<ms> (absolute)
pu   One value: the entry id for each purpose in order, joined by "."
       state, dropdown, tooltip, list, drawer, modal, toast
xt   Tokens held out of the export: <entryId>*<enter|exit>, "." between
tol  Spring sampling tolerance, ten-thousandths, 1-2000. Default 100 (1%).
```

Full contract: https://www.springs.studio/llms.txt

## Getting the code

The ready-made CSS, Tailwind theme, Framer Motion transitions and DTCG file are not in this text. They are in the JSON at https://www.springs.studio/api/tokens, which takes the same query string as this page. If you are reading this as markdown, that JSON was stripped along with the script tag holding it — fetch the URL rather than rebuilding the stylesheet from the table above.

## Other tools in this family

Studio Tools — Small, free, agent-readable design utilities. No account, no API key, nothing stored.

```
  Ramps     Color scales & semantic tokens   https://www.ramps.studio/
            Perceptually-even OKLCH scales and accessible tokens from one brand color.
  Springs   Motion, easings & durations      https://www.springs.studio/  (this tool)
            Easing curves, springs and durations you can preview on real UI.
  Beeps     UI sounds & feedback             https://www.beeps.studio/
            A coherent set of interface sounds, synthesized rather than sampled.
  Depths    Elevation & shadows              not yet released
            Elevation levels and a shadow ramp derived from one light source.
  Texts     Type styles & scaling            not yet released
            Scales that interpolate with the viewport, and the text styles built on them.
  SVGs      Icon cleanup & alignment         not yet released
            Clean up exported SVGs and sit them on a consistent optical grid.
```