Reference · Components and layout
Ambient motion
This is a spec: descriptive guidance, not a checkable rule. It carries no forbidden and instead pair, and no jig check detector applies to it directly.
The spec
A third category of motion, alongside the two this system already had. Interaction motion answers an input; transition motion carries the user between states or views. Both are measured in milliseconds and both are covered by G-44. Ambient motion is neither: slow, looping, decorative movement that gives a surface atmosphere without ever asking to be looked at — smoke drifting, a sway, a slow colour shift. It is passive, it runs without input, and it never ends.
The distinction matters because the two categories pull in opposite directions. Interaction motion must finish before the user perceives a wait, so it is fast. Ambient motion must never be noticed, so it is slow — fast ambient motion reads as a glitch or a demand for attention, which is the one thing it must not be.
Mode variance is total, not a matter of degree. Ambient motion is editorial only. product and operator have none, and this is not a density setting to be turned down — a surface someone works in all day must not have anything moving on it that they did not cause. Motion in those modes always means something changed.
Rules
- Seconds, not milliseconds. 3–6s per cycle is the working range.
G-44's 100–300ms ceiling does not apply here and says so. - Use the tokens:
--duration-ambient-fast(3s),--duration-ambient-base(4.7s),--duration-ambient-slow(7.1s).H-47applies here like everywhere else — a raw6sin a keyframe rule is a hard-coded value past the token layer. Give each layer a *different* one. The three periods are mutually prime by construction so that layered loops never re-align into one visible pulse, which is the whole failure mode of layered ambient motion; picking the same token for every layer throws that away and is the one way to misuse them. - Keyframe percentages and
animation-delayoffsets stay literal. Those are composition, not design decisions reused across the system, and tokenising them would mean a token per animation. - Loop seamlessly. Match the first and last keyframe, or use
animation-direction: alternate. A hard reset is a flicker, and a flicker is noticed. - Layer several small movements rather than one large one. Varied periods and delays read as alive. One movement reads as a widget.
- Test it by not looking at it. If your eye is pulled to it while you read the page, it is too strong. Reduce until you would only catch it if you were looking for it.
aria-hidden="true"on purely decorative animated elements. They carry no information, so they are clutter in the accessibility tree.- Wrap it in
@media (prefers-reduced-motion: no-preference)— the whole declaration, so the reduced path is absence rather than a shortened loop (G-43). Ambient motion is the easiest case there is: it means nothing, so removing it costs nothing. - Animate
transformandopacity. These run on the compositor. A loop that runs forever on every frame the page is open cannot afford animatedblur,box-shadow, or anything that triggers layout — the cost is not paid once, it is paid continuously, on whatever device the reader has.G-162holds this for all motion; here the cost is simply paid forever.
Anti-pattern: ambient motion used to direct attention. It is atmosphere, not a signal. The moment it points at something it has become interaction motion badly done, and G-42 applies instead.
- Kind
- Spec
- Section
- Components and layout