BLUR TO FOCUS
INTERACTION_031CSS
Blur To Focus Reveal
Copy resolves from a soft blur into perfect focus as it enters view.
Text / LightView
Full phrases cross-fade in place without shifting the layout around them. The first phrase visible, the others at 0 opacity absolutely positioned before the trigger; cross-fading and lifting 6px between phrases once a 3 second interval while in view.
/* Rotating Phrases — Full phrases cross-fade in place without shifting the layout around them. */
.rotating-phrases {
--dur: 480ms;
--ease: cubic-bezier(0.22, 1, 0.36, 1);
--stagger: 60ms;
will-change: transform, opacity;
}
.rotating-phrases > * {
opacity: 0;
transform: translateY(14px);
animation: rotating-phrases-in var(--dur) var(--ease) forwards;
animation-delay: calc(var(--i, 0) * var(--stagger));
}
/* the first phrase visible, the others at 0 opacity absolutely positioned -> cross-fading and lifting 6px between phrases */
@keyframes rotating-phrases-in {
to {
opacity: 1;
transform: none;
filter: none;
}
}
@media (prefers-reduced-motion: reduce) {
.rotating-phrases > * {
opacity: 1;
transform: none;
animation: none;
}
}import { useEffect, useRef } from "react";
/** Rotating Phrases — trigger: a 3 second interval while in view */
export function RotatingPhrases({ 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="rotating-phrases" data-state="out">
{children}
</div>
);
}Copy resolves from a soft blur into perfect focus as it enters view.
Each line slides up from behind an invisible mask, one after the other.
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.