Scroll-linked per-character text reveal, in CSS. The split runs at build time, so nothing ships to the browser but markup and a stylesheet.
checking support…
npm i split-reveal
mode: rise
The word is masked, the characters are lifted into it. For headlines.
mode: rise, two lines
The stagger runs across the whole element, so later lines are still arriving while the first has landed.
mode: nudge, --split-travel: 0.3em
Hides with visibility instead of a mask, which is what frees the distance. In rise above, the travel is not a setting but a condition: the character has to clear the word mask or a sliver of it stands in the line the whole way, and that floors it at the glyph’s own height, about 1.36em. Here it is 0.3em. Same box per character as rise, so hyphenation is off in this mode too.
mode: fade
A scroll timeline has no time. Forty animation delays would all resolve to the same frame, so the stagger has to be a shift of the range instead.
Stepped, not faded: a character is either set or absent, never half transparent. Stays fully inline, so hyphenation and line breaking are untouched.
mode: fade, spread 38
The split happens while the page renders. Nothing measures the DOM at runtime, which is also why a resize, a rotation or a late font swap can never invalidate it: there is no measurement to invalidate.
spread is held constant while the per-character step is derived from it, so a short headline and a long paragraph finish over the same share of their own scroll.
mode: rise, step 0.25, eased
A written step keeps the same handful of characters in flight from the first word to the last, so a long paragraph still reads as a wave running through it.
The other trade. step writes the per-character distance instead of deriving it from spread, so the stagger keeps its density however long the copy gets: (end - start) / step characters are ever in flight, 40 here rather than all 127. --split-ease shapes that travel, here with the quadratic ease-out a tweening library would apply without being asked.