Skip to content
Zumkai

Cinematic scroll with GSAP + Lenis in Claude Code: pin, scrub, and parallax (with Oryzo AI and Studio K95 cases)

Cinematic-scroll tutorial with GSAP ScrollTrigger and Lenis in Claude Code: pin, scrub, parallax, the ScrollSmoother vs Lenis call, ready prompts, and Oryzo AI and Studio K95 cases.

  • gsap scrolltrigger lenis claude code
  • gsap scroll pin scrub parallax
Dark navy cover with the title GSAP ScrollTrigger + Lenis with Claude Code in condensed type, a violet-to-pink gradient rule, and concentric rings on the right.
Contents
  1. What do pin, scrub, and parallax solve in scroll?
  2. How do I set the base with GSAP 3.15, ScrollTrigger, and Lenis?
  3. How do I build pin with scrub without breaking layout?
  4. ScrollSmoother or Lenis, which do I pick?
  5. How do I generate that scroll with Claude Code?
  6. What do the awarded cases teach?
  7. How do I hold fluidity and honor reduced motion?
  8. Frequently asked questions
  9. Conclusion: base, decision, and repertoire before the next scroll
  10. Sources

Cinematic scroll breaks when three controls fight over the page at once: the smooth handing inertia, the pin holding the section, the trigger firing the timeline. With no bridge between them, animations fire early and pins compute wrong positions.

This tutorial fixes that in order: concepts with a decision table, a base with GSAP 3.15 and Lenis 1.3.x, a hero with pin and scrub, the ScrollSmoother-versus-Lenis criterion, prompts for Claude Code, readings of the cases, and a close on fluidity plus reduced motion. For the full library map, return to the complete motion guide.

What do pin, scrub, and parallax solve in scroll?

Code in a dark editor standing in for a scroll-driven animation timeline
Photo: Negative Space via StockSnap (CC0).

Each effect answers one reading question. Pin answers which context stays valid while the rest advances. Scrub answers how much of the scene already advanced, because it ties timeline progress to scroll position. Parallax answers which layer moves faster, which builds depth without switching sections.

ScrollTrigger covers all three, with two extra features worth naming. Snap settles scroll onto set points, handy in screen-by-screen decks. Markers draws the triggers' start and end lines during development, which speeds up position work.

The table below compresses effect, owning plugin, and when to reach for each. It works as triage before any prompt.

EffectPluginWhen to use it
Section pinScrollTriggerHolding a hero or context while the timeline advances
Timeline scrubScrollTriggerTying animation progress to scroll position
Layered parallaxScrollTrigger or ScrollSmootherMoving back and front at distinct speeds with sync
Declarative parallaxScrollSmootherSetting speed per data-speed and data-lag attribute with no per-layer JS
Snap across screensScrollTriggerSettling scroll onto fixed deck points
Inertial smooth scrollLenis or ScrollSmootherGiving scroll physical feel before wiring triggers
Position debuggingScrollTrigger markersChecking start and end in development, removing before publishing

a three-question triage rule (is there a pin, is there a scrub, is there parallax at distinct speeds) settles CSS versus GSAP before the prompt; three no answers mean CSS scroll-driven suffices and the article ships lighter.

The triage settling CSS against GSAP

Three questions set the architecture. Is a pin holding content. Is a scrub tying a timeline to scroll. Is parallax at distinct speeds demanding per-pixel sync. Three no answers point at CSS scroll-driven, which covers reveals and plain parallax. One yes already justifies planning GSAP with ScrollTrigger, container names, and mobile behavior fixed before generating code.

How do I set the base with GSAP 3.15, ScrollTrigger, and Lenis?

Laptop with code and coffee in a GSAP and Lenis dev setup
Photo: Negative Space via StockSnap (CC0).

The base holds two parts: plugin registration plus a sync bridge. GSAP stays the narrative-scroll reference, and the commercial context changed the math: after Webflow bought GreenSock in Oct 2024, distribution went 100% free on Apr 30, 2025, at version v3.15.0, per gsap.com, noqode.fr from May 13, 2026, and artofstyleframe from May 25, 2026. With license friction gone, the criterion turns technical again.

Lenis enters as light smooth scroll. The 1.3.x line weighs about 3KB, carries MIT licensing and Darkroom maintenance, with the sync pattern documented across the community, per youngju.dev from May 16, 2026, adamarant from May 28, 2026, and snigdha from Jun 18, 2026. Install through npm with both packages, and register the plugin before any trigger.

js
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import Lenis from "lenis";

gsap.registerPlugin(ScrollTrigger);

const lenis = new Lenis({ lerp: 0.1 });
lenis.on("scroll", ScrollTrigger.update);

gsap.ticker.add((time) => lenis.raf(time * 1000));
gsap.ticker.lagSmoothing(0);

That short block carries three decisions. Lenis scroll events update ScrollTrigger, raf runs inside the GSAP ticker instead of a separate requestAnimationFrame, and zeroed lagSmoothing prevents jumps after tab switches. Without that bridge, pins compute wrong positions and timelines fire early.

How do I build pin with scrub without breaking layout?

Pin holds context while the timeline advances, and scrub turns scroll into a progress control. The common mistake fixes the section with no reserved space and no defined end, which shoves following content and flashes a visible jump.

The block below mounts a fixed hero with a scroll-tied timeline. The trigger starts at the viewport top and ends after 150% of scrolling, the pin holds the section, and scrub at 1 softens the scroll-to-timeline bond slightly.

js
gsap.timeline({
  scrollTrigger: {
    trigger: ".pinned-hero",
    start: "top top",
    end: "+=150%",
    pin: true,
    scrub: 1,
    markers: false
  }
})
  .to(".pinned-hero h1", { yPercent: -30, opacity: 0, ease: "none" })
  .to(".pinned-hero .scene", { scale: 1.15, ease: "none" }, "<");

Layered parallax follows the same logic with independent triggers. Each layer takes a proportional offset, ease none to hold the direct scroll bond. Distinct back-versus-front speeds build depth, and moderate values preserve text reading.

js
gsap.to(".layer-back", {
  yPercent: 15,
  ease: "none",
  scrollTrigger: {
    trigger: ".story-section",
    start: "top bottom",
    end: "bottom top",
    scrub: true
  }
});

During development, markers true draws the start and end lines and exposes overlapping triggers. Before publishing, switch markers off and check the pin's reserved space on narrow screens, where fixed content bursts first.

ScrollSmoother or Lenis, which do I pick?

Both settle scroll feel through distinct roads. ScrollSmoother lives native to GSAP and works with declared wrapper and content, attribute parallax, and scroll normalization, per the GSAP docs and annnimate. Lenis works at window level, demanding no wrapper, around 3KB with one-off ScrollTrigger integration.

js
gsap.registerPlugin(ScrollTrigger, ScrollSmoother);

ScrollSmoother.create({
  wrapper: "#smooth-wrapper",
  content: "#smooth-content",
  smooth: 1.2,
  effects: true,
  normalizeScroll: true
});

With effects on, data-speed and data-lag attributes apply declarative parallax straight in HTML, no per-layer timeline. That simplifies pages with many sections and uniform parallax.

The pick runs through stack and control. For GSAP-heavy pages with declarative per-section parallax, ScrollSmoother simplifies because it lives in the triggers' own world. For agnostic smooth scroll with one-off integration and a minimal bundle, Lenis does the job at about 3KB. Never combine both scroll drivers on one page: they fight over the same position and duplicate the math.

How do I generate that scroll with Claude Code?

Editor with code on a laptop screen during Claude Code generation
Photo: Marc Chouinard via StockSnap (CC0).

Good generation splits three roles: skill sets the standard, prompt sets the structure, MCP verifies the API. The start is the iart-ai/web-animation-skills repo on GitHub, with 9 skills including gsap-web, 60fps-animation, and accessible-animation, installed via npx skills add or marketplace, per the iart-ai repo. The GSAP skill pulls timelines and ScrollTrigger, the 60fps skill pulls transform and opacity, the accessible skill pulls reduced-motion preference.

The repo's example prompt for a GSAP hero runs direct: "Build a pinned hero section that scrubs a timeline to scroll with GSAP." That prompt works better with a structure chaser: section names, which layer takes the pin, scrub length, mobile behavior, and where Lenis enters. The more structure the prompt describes, the less architecture the model improvises.

To verify APIs before generating complex timelines, dedicated MCPs exist. The @vinhnguyen/gsap-mcp package on npm bridges into the docs, and the bl00dclot implementation on GitHub exposes 18 static tools with no runtime. In React, add the gsap-react skill with the useGSAP pattern cited on skillsplayground, which teaches timeline mount and cleanup in the component cycle and stops scroll-listener leaks.

The toolkit tied to wilwaldon organizes the rest of the flow, with Anthropic's official frontend-design, the freshtechbro collection at 23 skills, the jezweb skill for Motion, Playwright MCP and Chrome DevTools MCP for audits, plus Context7 for docs and Figma MCP for layout handoff. Ask for files split by responsibility, centralized easing and duration tokens, and a browser audit before publishing.

micro-interactions with Motion

What do the awarded cases teach?

Work desk with a laptop showing cinematic scroll code
Photo: Negative Space via StockSnap (CC0).

The period's awarded sites use scroll with a readable motive, not effect volume. Oryzo AI, SOTD from Apr 13, 2026 by the Lusion studio, pairs GSAP with Three.js to turn an AI product into a layered narrative, per the Awwwards animation picks. Studio K95 runs the same logic in a portfolio, with GSAP, Three, and Nuxt in layered entrances and type that answers scroll.

Made With GSAP, also a SOTD, works as the library's living catalog: hover cards, a drag hero, and text bursts show physics and cursor response with no video involved. Codrops Telescope, from Oct 2025, uses ScrollSmoother with ScrollTrigger for layered zoom, per the Codrops article, and serves as the direct reference whenever the doubt is Lenis versus ScrollSmoother.

Stacks across the 4 cited cases Horizontal bar chart counting stacks across the article's 4 cases: GSAP in 4, Three.js in 2, ScrollSmoother in 1, Nuxt in 1. A count of the cited cases, links under Sources. Stacks across the 4 cited cases GSAP core 4 of 4 Three.js 2 of 4 ScrollSmoother 1 of 4 Nuxt 1 of 4 Read: GSAP shows up everywhere; Three.js marks the 3D cases; ScrollSmoother shows up only in Telescope, that plugin's reference. Source: count of the cited cases (Awwwards and Codrops, 2025-2026)
Source: count of this article's cited cases, links under Sources (Awwwards and Codrops, 2025-2026).

The repeating pattern is restraint with motive. One idea per viewport, reveals honoring reading order, instant gesture response. No case demands an exotic stack. Every case demands decisions about what animates, when it animates, and why it animates.

How do I hold fluidity and honor reduced motion?

Fluidity follows a stable rule: animate transform and opacity, hold timelines short, reserve pin space, audit in the browser. A pin with no reserved space shifts layout, unsynced scroll fires early, an exit-less transition confuses. Playwright MCP plus Chrome DevTools MCP audits catch those mistakes before visitors do.

Accessibility holds the same bar with gsap.matchMedia. One branch serves no-preference users with full pin, scrub, and parallax. The other serves prefers-reduced-motion reduce with a legible static version and no lost content.

js
const mm = gsap.matchMedia();

mm.add("(prefers-reduced-motion: no-preference)", () => {
  // full pin, scrub, and parallax here
});

mm.add("(prefers-reduced-motion: reduce)", () => {
  // static version: visible content, no pin or scrub
});

Some animations deserve removal over optimization: long intros delaying reading, parallax fighting text, loops distracting from forms. If motion delays chores or spends attention explaining nothing, cut it and measure reading again.

performant 60fps motion and accessibility

Frequently asked questions

Are pin and scrub the same thing?

No. Pin fixes the section in the viewport while scroll advances, and scrub ties a timeline's progress to scroll position. This article's pattern pairs both: pin holds the hero, scrub drives the scene. Use pin without scrub for reading pauses, scrub without pin for continuous parallax.

May I run ScrollSmoother and Lenis on one page?

Not recommended. Both drive scroll position and the math duplicates, which fights pins and triggers. Pick ScrollSmoother when the page runs GSAP-heavy with declarative parallax through data-speed and data-lag, and pick Lenis when you need light smooth near 3KB with one-off integration through lenis.on(scroll, ScrollTrigger.update).

Which prompt do I send Claude Code for a pinned hero?

Start with the iart-ai repo's example prompt: "Build a pinned hero section that scrubs a timeline to scroll with GSAP." Then add structure: section names, which layer takes the pin, scrub length, mobile behavior, and where Lenis enters. Verify the API with the docs MCPs before generating long timelines.

How do I switch pin and scrub off for reduced-motion users?

Use gsap.matchMedia with two branches: the no-preference branch loads pin, scrub, and parallax, and the reduce branch delivers static, legible content with no pin or scrub. That split follows the same logic as the accessible skill in the iart-ai set, per the iart-ai repo.

Conclusion: base, decision, and repertoire before the next scroll

Cinematic scroll wants three hits in sequence. A base with GSAP 3.15, free since Apr 30, 2025, plus Lenis 1.3.x synced through the ticker bridge. A ScrollSmoother-versus-Lenis call on wrapper and stack criteria. Claude Code generation backed by skills, structured prompts, and docs MCPs. The Oryzo AI, Studio K95, Made With GSAP, and Telescope cases show where each pick pays.

The next step follows your project's bottleneck. For micro-interactions in React components, go deep on the Motion satellite. For a fluidity audit plus an accessibility checklist before publishing, go deep on the 60fps performance satellite.

Sources