<section class="demo">
<div class="demo__list">
<div class="demo__item"><span>01</span>Fade up on scroll</div>
<div class="demo__item"><span>02</span>Staggered reveal</div>
<div class="demo__item"><span>03</span>Scroll reveal</div>
</div>
</section>.demo {
min-height: 180vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20vh 24px;
background: #0c0c0e;
color: #f2f2f0;
font-family: "Segoe UI", "Helvetica Neue", system-ui, sans-serif;
}
.demo__list {
width: min(560px, 86vw);
}
.demo__item {
display: flex;
align-items: baseline;
gap: 16px;
padding: 22px 4px;
border-top: 1px solid rgb(255 255 255 / 0.08);
font-size: clamp(20px, 3vw, 28px);
font-weight: 500;
letter-spacing: -0.03em;
opacity: 0;
transform: translateY(28px);
}
.demo__item:last-child {
border-bottom: 1px solid rgb(255 255 255 / 0.08);
}
.demo__item span {
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 11px;
letter-spacing: 0.08em;
font-variant-numeric: tabular-nums;
color: rgb(242 242 240 / 0.4);
}const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
const items = gsap.utils.toArray(".demo__item");
if (reduce) {
gsap.set(items, { opacity: 1, y: 0 });
} else {
items.forEach(function (item, index) {
gsap.to(item, {
opacity: 1,
y: 0,
duration: 0.8,
ease: "power3.out",
delay: index * 0.08,
scrollTrigger: {
trigger: item,
start: "top 88%",
toggleActions: "play none none reverse",
},
});
});
}