Capability 02 — Pinned reveal

A sticky stage, six beats, one scroll.

Scroll slowly. The section below pins for its full duration. Each beat replaces the last as you move — no page jumps, no cuts, no scroll-hijacking. The reader stays in control the whole way.

01The frame

Pin the stage. Let the story move through it.

The section fixes its own viewport for the duration of a scroll. Scroll velocity is redirected from page distance into beat progression, so a single camera position can hold five ideas without ever cutting.

How this is built

The craft is in the teardown.

Eight primitives, composed. The hard parts aren’t the pin or the scrub — they’re the font-load refresh, the route- change cleanup, and the reduced-motion render path that makes the section fully legible without any motion at all. Every file below is open in the repo.

01ScrollTrigger — pinned sectionA single ScrollTrigger instance pins the viewport from top to bottom of a 6×100vh container. Scroll distance maps directly to beat progression.View source
02Scrubbed progress → active indexself.progress is multiplied by the beat count and floored. Active index updates only on change to avoid re-renders on every tick.View source
03Directional transitionsEach beat enters and exits in the direction of scroll — forward beats rise from below, reverse beats fall from above. Tiny detail, large legibility win.View source
04SplitHeading integrationOn activation, titles char-stagger in and body copy word-staggers with a short delay. The beat feels composed, not dumped.View source
05gsap.context() teardownThe entire scene lives inside a gsap.context(), so a route change reverts every listener and tween. No orphaned ScrollTriggers polluting later pages.View source
06ScrollTrigger.refresh on fonts + resizeFonts, images, and resizes can all shift the pinned section's measurements. createGsapScene re-runs ScrollTrigger.refresh() on each of those events.View source
07Reduced-motion static pathusePrefersReducedMotion short-circuits the pin entirely. All six beats render stacked with full body copy — nothing that was legible becomes hidden.View source
08Live counter + progress railA 01/06 counter and a thin vertical rail scale with self.progress, so the reader always knows where they are inside the pin — never lost, never confused.View source
Back to the showcase