Skip to the content

Durations

  • Transitions move something from one place or value to another, once: duration.sheet, duration.meter, duration.camera, duration.follow, duration.switch and duration.toast. A control pressed many times in a row, such as a switch, takes the short duration.switch, so the change keeps up with the hand. A toast slides up into its place and fades in on duration.toast, and slides down or away in the direction of its swipe as it leaves, so a message that arrives at the screen's edge is seen arriving.
  • Loops repeat while something is true. A new report pulses once around its vehicle (duration.report-pulse), a ring pulses around the selected vehicle (duration.selection-pulse), the follow indicator blinks while the camera follows (duration.blink), and a segment sweeps along a progress bar's track while how far its task has got is not known (duration.progress-sweep).
TokenValueReduced motion
duration.sheetBottom sheet open and close
320 ms
0.01 ms
duration.meterMeter and progress bar fill change
800 ms
0.01 ms
duration.cameraHow long the map camera takes to fly to a selection
750 ms
0.01 ms
duration.followCamera fly-to when following starts
500 ms
0.01 ms
duration.switchSwitch thumb slide and track fill
150 ms
0.01 ms
duration.toastToast slide and fade in and out
200 ms
0.01 ms
duration.blinkRecording dot blink while following
1400 ms
duration.report-pulseRing that expands when a vehicle reports its position
1100 ms
duration.selection-pulseRing around the selected vehicle
1600 ms
duration.progress-sweepSegment that sweeps along an indeterminate progress bar's track
1600 ms

Easing

The sheet has its own curve, which settles slowly so a long slide doesn't stop abruptly. Everything else eases with easing.standard, the browser's ease.

TokenValue
easing.sheetCurve of the bottom sheet opening and closing
cubic-bezier(0.2, 0.8, 0.2, 1)
easing.standardCSS ease (meters, the switch)
cubic-bezier(0.25, 0.1, 0.25, 1)

Reduced motion

When the system asks for less motion, the transition tokens take 0.01 ms: their values under prefers-reduced-motion: reduce are in the table's Reduced motion column. The value is 0.01 ms rather than 0, so transitionend and animation events still fire. CSS that reads the tokens needs nothing more.

  • Loops keep their durations in the tokens, because a loop at 0.01 ms would flicker. Each component that runs a loop stops it under reduced motion.
  • Vehicles move to each new report without gliding.

The values come from the resolver's motion modifier. Its default context, full, is empty, because base already holds the full-motion values; its reduced context points at packages/perron/tokens/motion-reduced.tokens.json. The build writes the overrides into each output:

OutputReduced motion
tokens.cssThe overrides inside @media (prefers-reduced-motion: reduce), on :root
tokens.tsmodifiers.motion.reduced, as CSS text and as numbers
penpot.tokens.jsonA motion-reduced set, and a Motion group with Full and Reduced themes

Timings in script

Script that animates, such as the map camera's fly-to, reads numeric from tokens.ts, and modifiers.motion.reduced.numeric when matchMedia('(prefers-reduced-motion: reduce)') matches. Both hold durations in milliseconds.