Skip to main content

Search rules

Search all UI Guides rules by name, category, or source

animationsanimate-text

Transform Order Is Not Cosmetic

MUST

MUST: Compose transform as translate → rotate → scale, and keep that order everywhere in the system. transform is a right-to-left matrix chain, so a translate written after a scale is measured in the scaled space: scale(0.5) translateY(60px) travels 30px, and the distance grows as the scale animates, bending the path into an easing you never wrote. Hoist the order with the rest of the motion constants; this bug never throws.

translate-then-scale is a different result from scale-then-translate — the second scales the distance, so a 60px lift at scale 0.5 travels 30px

// bad — translate lives in the scaled space; 60px becomes 30px at scale 0.5
transform: scale(0.5) translateY(60px);
// good — translation first, scale last: 60px is 60px at every scale
transform: translate3d(0, 60px, 0) scale(0.5);

Bad

Good

Why it matters

The catalog does not argue this in prose — it pins the order in a machine-readable `rendering_contract` field on every one of its 24 effects, which is the tell: reproductions diverged until the order became part of the contract. The reason is that `transform` is a chain of matrix multiplications applied right to left, so every function operates inside the coordinate space the functions after it have already established.

Write `scale(0.5) translateY(60px)` and the translation happens in a space that is already half size, so the glyph rises 30px rather than 60 — and as the scale animates toward 1 the effective distance GROWS, which bends the path into an easing you never authored and cannot find in your easing constant. Write `translateY(60px) scale(0.5)` and the two are independent: 60px is 60px at every scale, which is why the catalog puts translation first and scale last.

The discipline generalises past text: pick one order, hoist it with the rest of the motion constants (animations-named-timing-constants), and never let two components in the same system disagree, because this bug does not throw — it just makes the motion quietly wrong in a way that reads as "the animation feels off". Distinct from animations-correct-transform-origin, which fixes WHERE a scale starts from; this fixes what every other function in the same chain means once a scale is in it.

The individual `translate` / `rotate` / `scale` properties avoid the ambiguity — the spec fixes their order — but they still compose with `transform` in a defined sequence, so mixing the two forms needs the same care.

Built by Gleb Stroganov, design engineer at Evil Martians.

The rules come from other people's skills and guidelines — Vercel, Rauno Freiberg, @Ibelick, impeccable, Emil Kowalski, Tailwind, RAMS — each one credited on the Sources page. The work here is extraction and wiring: every rule is pulled into one corpus, given a good and a bad example you can operate, a MUST/SHOULD/NEVER rule an agent can paste, and a link back to where it came from.