Modern Web Motion: GSAP and Lenis Scroll
I wanted smooth scrolling on my site. Not the janky default where scroll happens in chunks. I wanted that buttery feel where things glide.
Turns out you need two things: a smooth scroll library and an animation library that plays nice with it.
The Setup
Lenis handles the smooth scroll. GSAP handles the animations. You wire them together like this:
import Lenis from 'lenis';
import { gsap } from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
gsap.registerPlugin(ScrollTrigger);
const lenis = new Lenis({
duration: 1.2,
easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
});
lenis.on('scroll', ScrollTrigger.update);
gsap.ticker.add((time) => {
lenis.raf(time * 1000);
});
gsap.ticker.lagSmoothing(0);Lenis intercepts the native scroll, applies easing, and feeds the position back to ScrollTrigger so animations stay in sync.
What Actually Matters for Performance
Three things I learned the hard way:
Only animate
transformandopacity. Don't touchmargin,top,height— those trigger layout recalculations and kill your framerate.Group related scroll animations into one timeline instead of creating separate ScrollTrigger instances for each thing. Less listeners = smoother.
Disable custom cursors and hover effects on touch devices. Use
@media (pointer: coarse)in CSS. Touch devices don't need cursor tracking and it just wastes CPU.
That's really it. Smooth scroll isn't magic — it's just an event loop with easing on top.