Capability 07 — Scroll scene
A choreography, scrubbed by scroll.
A single element moves through a multi-keyframe timeline while the page is pinned. Scale, y-position, rotation, opacity, blur, and the background gradient all advance together. Scroll forward and back — the timeline scrubs both directions.
Composition
A single gesture, scrubbed against the scroll.
Scale, y-position, rotation, opacity, and blur all change together. The background advances through four moods. Scroll up or down and the timeline scrubs both directions — GSAP ScrollTrigger treats scroll as the clock.
The code
What’s driving it.
The whole thing is one GSAP timeline with two tracks — card motion and background mood — bound to the scroll position of a pinned section. Scrub smooths it. Keyframes do the rest.
const tl = gsap.timeline({
scrollTrigger: {
trigger: section,
start: "top top",
end: "+=320%",
pin: true,
scrub: 0.6,
anticipatePin: 1,
},
});
// Keyframes: 0% → 25% → 70% → 100%
tl.to(card, {
keyframes: [
{ y: "40vh", scale: 0.6, rotation: 0, opacity: 0, filter: "blur(8px)" },
{ y: "0vh", scale: 1.0, rotation: -3, opacity: 1, filter: "blur(0px)" },
{ y: "0vh", scale: 1.2, rotation: 0, opacity: 1, filter: "blur(0px)" },
{ y: "-50vh", scale: 0.9, rotation: 2, opacity: 0.3, filter: "blur(2px)" },
],
ease: "none",
});
// A second track drives the background gradient through 4 moods.
tl.to(stage, {
keyframes: MOODS.map((bg) => ({ background: bg })),
ease: "none",
}, 0);How this is built
One timeline. Two tracks. Scroll is the clock.
The pin holds the section in view while the user scrolls. Scrub binds the timeline playhead to the scroll position, with a short lag to smooth fast gestures. Keyframes let a single property describe a four-point path without nested tweens.