Zero-dependency · Zero JavaScript

This page
scrolls itself.

A progress bar, counters that count up, a pinned reveal sequence, a staggered gallery — every motion below is driven by native CSS scroll-timelines. Open dev tools, search the source for <script>. You won't find one.

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.

scroll ↓

Counters that count themselves.

No requestAnimationFrame, no IntersectionObserver — a CSS custom property with an integer syntax, animated by scroll position, rendered through a counter.

of this page's motion is CSS-only
experiments now live in the Labs
lines of JavaScript on this page
Beat one

Keep scrolling.
This stays pinned.

Beat two

Three beats,
one sticky section.

Beat three

Then it
releases naturally.

A staggered gallery,
no library.

Each card's animation-range starts a touch later than the last — the stagger effect everyone reaches for a JS library to get.

> view-source verification
[GREP] grep -c "<script" index.html → 0
[CSS] animation-timeline: scroll(root) · view() · @property × 3 · position: sticky
[FALLBACK] @supports not (animation-timeline: view()) → static, fully readable, nothing broken

The browser
already knows how.

Most 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 →