Overlap a Text Swap; Never Hard-Cut the Slot
MUST: Rotating/replaced text must overlap its exit and enter (100–300ms, or at minimum a 28–85ms micro-delay) so no frame shows an empty slot, and both layers must share one grid cell (grid-area: 1/1) sized to the longest string so surrounding content never reflows. A looping swap also needs a pause control and a reduced-motion path.
A rotating word must start entering before the old one has finished leaving, in a slot sized so the line around it never moves
// bad — hard cut, slot resizes every tick
setInterval(() => setI(i => (i + 1) % words.length), 2000)
// good — stacked layers, enter starts before exit ends
<span style={{ display: "inline-grid" }}>
{words.map((w, i) => (
<span key={w} style={{ gridArea: "1 / 1" }} className={i === index ? "enter" : i === leaving ? "exit" : "invisible"}>{w}</span>
))}
</span>Bad
Good
Why it matters
The "Build ___ faster" rotating headline is usually a `setInterval` that swaps a string, and it fails twice on the same frame. First the cut: with no overlap there is a moment where the old word is gone and the new one has not arrived, and an empty slot reads as a bug, not a transition. The catalog overlaps 100–300ms on crossfade effects (soft-blur-in 300, mask-reveal-up 210, per-word-crossfade 170) and — this is the part that gets skipped — even the effects with `overlap_ms: 0` still insert a `micro_delay_ms` of 28–85ms rather than cutting at exactly t=0, because the beat is what makes a replacement read as choreography instead of a glitch.
Second the reflow: mount both layers in normal flow during the overlap and the line doubles in height, then snaps back. Stack them in one grid cell instead — a `grid` container with both children on `grid-area: 1 / 1` — which also sizes the slot to the WIDEST string automatically, so the words on either side stop shuffling every four seconds. Reserving that width is the same argument as performance-no-image-cls, one text node down.
And a swap that loops is looping text: content-moving-text-can-be-paused still applies, so it needs a reduced-motion path and a way to stop it.