AVINN
← Back to Blog
2025-06-15Tutorial2 min read

Building Smooth Scroll Experiences

Smooth scrolling has become a hallmark of premium web experiences. In this post, I'll walk through how I integrate Lenis with GSAP ScrollTrigger to create that buttery-smooth feel you see on Awwwards-winning sites.

Why Lenis?

Native browser scrolling is fine for most websites, but when you're building something that needs to feel crafted, you need more control. Lenis gives us:

  • Consistent scroll behavior across browsers
  • Smooth momentum-based scrolling
  • Easy integration with animation libraries
  • Touch device support

The Setup

First, install the dependencies:

npm install lenis gsap @gsap/react

The key is syncing Lenis with GSAP's ticker so ScrollTrigger animations stay perfectly in sync with the scroll position:

import { ReactLenis } from "lenis/react";
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";

gsap.registerPlugin(ScrollTrigger);

function SmoothScroll({ children }) {
  const lenisRef = useRef(null);

  useEffect(() => {
    function update(time) {
      lenisRef.current?.lenis?.raf(time);
    }
    gsap.ticker.add(update);
    gsap.ticker.lagSmoothing(0);
    return () => gsap.ticker.remove(update);
  }, []);

  return (
    <ReactLenis ref={lenisRef} root options={{ lerp: 0.08 }}>
      {children}
    </ReactLenis>
  );
}

ScrollTrigger Animations

Once Lenis and GSAP are synced, you can create scroll-driven animations that feel natural:

gsap.to(".word", {
  opacity: 1,
  stagger: 0.1,
  scrollTrigger: {
    trigger: ".text-container",
    start: "top 80%",
    end: "bottom 40%",
    scrub: 1,
  },
});

The scrub: 1 parameter ties the animation directly to scroll position with a 1-second smoothing delay. This creates that satisfying feeling where content reveals as you scroll.

Performance Tips

  1. Use will-change sparingly — only on elements that are actively animating
  2. Prefer transform and opacity — these properties are GPU-accelerated
  3. Kill ScrollTriggers on unmount — memory leaks are real
  4. Use once: true for animations that should only play once

Smooth scrolling is one of those details that separates a good website from a great one. It's worth the extra setup.