A Hard Cut Is steps(), Not a Fast Fade
MUST: Any effect whose identity is discreteness — typewriter, per-word hard cut, blinking caret — must use steps(1, end), not an eased opacity ramp. A fade puts every unit in a half-present state for its whole duration, so at a normal stagger several are ghosting at once and the line smears instead of typing. The rhythm belongs to the stagger; the duration is only a gate.
A typewriter or word-by-word cut needs a stepped easing — a 240ms opacity ramp per character is not typing, it is a smear resolving
// bad — 240ms ramp, ~5 glyphs half-present at a 46ms stagger
animation: fade 240ms ease-out both;
// good — struck or absent, never in between
animation: type 240ms steps(1, end) both;
animationDelay: `${i * 46}ms`;Bad
Good
Why it matters
Two of the catalog's 24 effects reach for `steps(1, end)`, and both are effects whose entire identity is discreteness. A typewriter is a machine setting one glyph at a time: the character is struck or it is not, and there is no state in between. Build it from a 240ms opacity ramp at a 46ms stagger and roughly five characters are half-present at any moment, so the line reads as a grey smear resolving rather than as typing — the effect you asked for is the one thing you cannot see.
`steps(1, end)` collapses the whole duration into a single transition at its end, which is also why a stepped effect survives being retimed: the RHYTHM lives entirely in the stagger and the duration is just a gate. The same argument covers `shared-axis-y`, a staircase of per-word hard swaps — ease it and a deliberate edit becomes a cross-dissolve. This is the one place in this corpus where an instant transition is the craft rather than the shortcut, and it is not in tension with animations-emil-no-ease-in: that rule chooses among CONTINUOUS curves and has nothing to say about a transition with no in-between. A stepped reveal is still motion, so `prefers-reduced-motion` should still land the whole string at once.