A progress bar, counters that count up, a pinned reveal sequence, a staggered gallery — every motion below is driven by native CSS scroll-timelines. Our source ships zero JavaScript — the entire page is style rules. (View-source shows one <script>, but it isn't ours — it's Cloudflare's bot-detection beacon, injected at the edge. Our index.html has none.)
The stack: animation-timeline: scroll() / view() + @property for animatable counters + position: sticky for the pin. Chromium-first (Chrome/Edge/Arc); Safari and Firefox get a clean static fallback via @supports — nothing ever breaks.
No requestAnimationFrame, no IntersectionObserver — a CSS custom property with an integer syntax, animated by scroll position, rendered through a counter.
Each card's animation-range starts a touch later than the last — the stagger effect everyone reaches for a JS library to get.
01 · Entry
02 · Cover
03 · Exit
04 · Timeline
05 · RangeMost scrollytelling ships a library. This page is proof the platform caught up — for the right brief, that's a real performance and reliability win, not just a party trick.
Back to the Labs →