On this site

Scroll Blur Reveal

Words come into focus as they reach your reading line.

GSAP · CSS filters

The Philosophy section reads like a slow exhale: each word sharpens from blur as it crosses the middle of the screen, pacing the reader without hijacking scroll.

Each word is measured against a band centred on the scroll panel's vertical middle. The distance from the word's centre to the band's lower edge, divided by the band height, gives a 0 to 1 reveal value that drives opacity and blur directly on the element. Geometry is read for all words first and styles written afterwards, once per animation frame per scroll event, with no React state involved. Words above the band stay revealed; words below it stay dim and blurred.

const panelRect = panel.getBoundingClientRect();
const bandHeight = band * panelRect.height;
const bandStart = panelRect.height / 2 - bandHeight / 2;
const bandEnd = panelRect.height / 2 + bandHeight / 2;

// read all geometry first...
const reveals = words.map((word) => {
  const rect = word.getBoundingClientRect();
  const wordCenter = rect.top - panelRect.top + rect.height * 0.5;
  return Math.min(1, Math.max(0, (bandEnd - wordCenter) / (bandEnd - bandStart)));
});

// ...then write styles
words.forEach((word, i) => {
  const reveal = reveals[i];
  word.style.opacity = (minOpacity + reveal * (1 - minOpacity)).toFixed(3);
  word.style.filter = reveal >= 1 ? "none" : `blur(${maxBlur * (1 - reveal)}px)`;
});