Skip to content

Masked Scroll Highlight

Copy that resolves word by word as you scroll, mapped by real reading position rather than word index.

Proeditorialminimal
Category
Text Effects
Added
2026-09-21
Deps
none
Updated
2026-09-21

This is a viberdy Pro component

The live preview, the props panel and the write-up are open to everyone. The full source, the AI prompt and CLI install are part of Pro.

Preview

We design the parts people actually touch. The hinge, the handle, the moment a thing answers back. Everything else is decoration. 

scroll inside the panel

Props

1.1
0.22
No runtime dependencies
"use client";

import { useEffect, useRef } from "react";

/**
 * A block of copy that lights up word by word as it passes through the
 * viewport.
 *
 * The part that is usually wrong is the mapping. Driving each word from
 * `index / total` assumes every line holds the same number of words, so a
 * ragged right edge or a short final line makes the highlight run ahead of the
 * reader on some lines and behind on others. The position that matters is where
 * the word sits IN READING ORDER ACROSS THE BLOCK — its line number plus how
 * far along that line it starts.
 */
export function MaskedScrollHighlight({
  text = "We design the parts people actually touch. The hinge, the handle, the moment a thing answers back. Everything else is decoration.",
  feather = 1.1,

  // ---------------------------------------------------------------
  // Full source available with a viberdy Pro subscription.
  // https://viberdy.dev/pricing
  // ---------------------------------------------------------------
}
Notes

About this text effect

The scroll-linked reading highlight is a familiar effect with an unfamiliar amount of room to get wrong, and the mistake is almost always in the mapping. Driving each word from its index divided by the total quietly assumes that every line holds the same number of words; with a ragged right edge, or a short final line, the highlight runs ahead of the reader on some lines and behind on others, which is exactly the thing the effect exists to avoid. What matters is where a word sits in reading order across the block, so the words are measured, grouped into real lines by their rounded vertical position, and scored as their line number plus how far along that line they begin — then normalised by line count rather than word count. Two structural choices keep it robust. Progress comes from the section's own bounding rectangle rather than from a scroll position, so it behaves identically whether the page scrolls, an ancestor scrolls, or both, which is what lets it survive being dropped inside a modal or a split pane. And the animation frame loop is gated on an IntersectionObserver, because a scroll handler that fires for every block on a long page is how this pattern becomes the reason a site janks. Measurements are retaken once webfonts resolve, since metrics from the fallback face usually break lines somewhere else entirely.

Curator’s note

Map words by index and it desynchronises on every ragged line. Group them into real lines first and it tracks the eye.

Related

Pairs well with

Matched on shared tags and category — the entries most likely to be used alongside this one.

A scroll-triggered vertical timeline whose dots and cards reveal in sequence.

timelinescrollreveal

An image whose circular clip-path mask grows and shrinks in lockstep with scroll.

scrollimagemask
Pro

Reveals text one line at a time, each sliding up from behind its own clipping mask.

text-revealmaskscroll