The three scroll verbs
- Reveal — content animates in as it crosses the viewport. The default; cheap and safe.
- Pin — a section stays put while the next chapter scrolls over it. High drama, needs restraint.
- Sync — progress through a scene is tied to scroll position (0–100%). The Scroll Lab pattern: enter → pin → exit.
Rules we hold ourselves to
Never animate layout-affecting properties in a scroll handler. transform and opacity only — width/height/top on scroll is how you get jank nobody can debug.
Reveal once, never re-trigger. Elements that re-animate when you scroll back up feel broken; let them settle.
Respect reduced motion by jumping to the final state, not freezing mid-story.
Keep the story skimmable: someone who scrolls fast should land on complete sections, not 47 half-animated states.
The choreography skeleton
// enter at 25% of the viewport, pin until 55%, exit by 80%
const scene = {
enter: 0.25, // opacity 0→1, translateY 60→0
pinAt: 0.55, // hold, scale to 1.06, add glow
exitAt: 0.80, // opacity →0, translateY →-40
};
// exported recipe (copy from the Scroll Lab):
// hero: enter cubic-bezier(.16,1,.3,1)
// pin: transform scale 1.06
// exit: fade up -40px
// prefers-reduced-motion: skip all, show final stateWhen pinning pays
Pin earns its keep when a single idea needs time to land: a product transforming, a number climbing, a route tracing. If the story has three competing pinned sections, you've built a slide deck — scroll should feel like reading, not presenting.