BLUR TO FOCUS
INTERACTION_031CSS
Blur To Focus Reveal
Copy resolves from a soft blur into perfect focus as it enters view.
Text / LightView
Each line slides up from behind an invisible mask, one after the other. Fully hidden below its own line mask before the trigger; translating each line from 100% to 0 inside its clipped wrapper once the section mounts or first enters view.
/* Masked Line Reveal — Each line slides up from behind an invisible mask, one after the other. */
.masked-line-reveal {
--dur: 800ms;
--ease: cubic-bezier(0.22, 1, 0.36, 1);
--stagger: 90ms;
will-change: transform, opacity;
}
.masked-line-reveal > * {
opacity: 0;
transform: translateY(14px);
animation: masked-line-reveal-in var(--dur) var(--ease) forwards;
animation-delay: calc(var(--i, 0) * var(--stagger));
}
/* fully hidden below its own line mask -> translating each line from 100% to 0 inside its clipped wrapper */
@keyframes masked-line-reveal-in {
to {
opacity: 1;
transform: none;
filter: none;
}
}
@media (prefers-reduced-motion: reduce) {
.masked-line-reveal > * {
opacity: 1;
transform: none;
animation: none;
}
}import { useEffect, useRef } from "react";
/** Masked Line Reveal — trigger: the section mounts or first enters view */
export function MaskedLineReveal({ children }: { children: React.ReactNode }) {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
const el = ref.current;
if (!el) return;
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
el.dataset["state"] = "in";
return;
}
const io = new IntersectionObserver(
([entry]) => {
if (entry?.isIntersecting) {
el.dataset["state"] = "in";
io.unobserve(el);
}
},
{ threshold: 0.2 },
);
io.observe(el);
return () => io.disconnect();
}, []);
return (
<div ref={ref} className="masked-line-reveal" data-state="out">
{children}
</div>
);
}Copy resolves from a soft blur into perfect focus as it enters view.
The hero headline arrives line by line from behind its own masks.
Words fade up in sequence so the sentence assembles as you read it.
Sentences in a block arrive one at a time with a calm rhythm.