← All notes
Engineering6 min read25 April 2026

Lenis + ScrollTrigger: one rAF to rule them all

Smooth scroll libraries and scroll-driven animation fight over the same frame. Here's the sync pattern that ends the war.


Lenis makes scrolling feel expensive. GSAP's ScrollTrigger makes scrolling do things. Run both naively and they each run their own requestAnimationFrame loop, disagree about scroll position mid-frame, and produce the exact jank you installed them to avoid.

The pattern

Drive Lenis from GSAP's ticker instead of its own loop: gsap.ticker.add((t) => lenis.raf(t * 1000)). Tell ScrollTrigger about every Lenis scroll: lenis.on('scroll', ScrollTrigger.update). Disable GSAP's lag smoothing so the two never drift: gsap.ticker.lagSmoothing(0). One loop, one source of truth, zero fights.

Where smooth scroll doesn't belong

Touch devices already have physics-based native scrolling that users trust. A JS scroll layer on mobile costs main-thread time and often feels worse. Gate Lenis behind a (hover: hover) and (pointer: fine) media query — desktops get the glide, phones keep their native feel and their battery.

Building something in Mumbai?

We design, build and maintain websites, web apps and online stores — fixed quotes, weekly staging links, honest advice.

Start a project
Chat with us