fast, normal, slow set to choose between — because a discrete ladder cannot express a user sitting halfway between full motion and none. A brand declares its base duration and its curve; the runtime scales the duration continuously.
The motion block
Both fields are required. An example, from the fictional Acme brand’sconfig.global.yaml:
duration-base— a bare number in milliseconds. This is the brand’s full-strength transition duration.easing— a CSS easing function, as a string. It reaches the browser as--easingon the brand selector.
Aurora’s 75ms linear is a deliberate choice for a transactional booking flow; Aurora Corporate quadruples it to 300ms and swaps in an eased curve for a slower, more formal surface. Cargo overrides only
duration-base and keeps the family’s linear easing — see Inheritance for how partial overrides merge.
The continuous model
The authored base is emitted per brand, and one global expression scales it. The shape of a brand’s generatedcss/brand.gen.css:
generated/global/css/tokens.gen.css:
--duration (through --surface-transition-duration) and --easing; nothing references a named speed tier, because none exists.
The motion factor
motionFactor is one of the seven axes on the runtime preference vector, running from 0 (instant) to 1 (the brand’s full authored duration). Two things about it are worth knowing:
It defaults to 0.75, not 1. The shipped default preference set deliberately runs motion at three-quarters strength. A brand that authors duration-base: 200 sees 150ms out of the box.
It is user-adjustable, within brand-set bounds. The flexibility.motion block is the brand’s policy on how far the slider may travel:
{ min: 0.5, max: 1 } would prevent users from disabling motion entirely — though allowing 0 is what makes the reduced-motion path work.
Reduced motion
Substrate does not emit aprefers-reduced-motion media block. The handling lives in the web runtime, which reads the media query and sets motionFactor to 0:
--duration is --duration-base times the factor, zeroing the factor zeroes every duration in the system at once — no per-token overrides, and no component-level checks. The runtime also listens for changes, so a user toggling the OS setting with the page open takes effect immediately rather than on next load.
Handling reduced motion through the preference vector rather than a media query is what lets the same mechanism serve a user who wants less motion rather than none. A media block is binary; the factor is continuous, so 0.3 is a reachable state.
Brand Config Overview
The full schema, including the
flexibility policy block that bounds every preference axis.Core Concepts
The preference vector in full, and why values are computed at runtime.