STAGE 1: Why Smooth Scrolling Needs Lenis
The Flaw in Discrete Browser Scrolling
Standard browser scrolling is discrete and rigid. Browsers jump scroll coordinates page by page, resulting in abrupt movement. While browsers have attempted smooth scrolling features, they lack consistency across devices (trackpads, mouse wheels, and touch screens) and operating systems.
The Lenis Non-Invasive Approach
Lenis is a lightweight, open-source smooth-scrolling library designed by Studio Freight. Unlike older scroll-jacking libraries, Lenis is non-invasive. It works on the main thread, preserves browser defaults, handles keyboard navigation gracefully, and respects CSS pointer events. Most importantly, it calculates physics-based scroll coordinates that we can leverage for visual tweens.
When you trigger scroll animations, GSAP's ScrollTrigger calculates element boundaries relative to the viewport. Under normal conditions, GSAP polls the browser’s scroll position. However, when Lenis recalculates the scroll animation loop inside a custom requestAnimationFrame loop, the visual elements and the browser's native scroll properties can fall out of sync, leading to stuttering, tearing, or lagging effects.
STAGE 2: Linking the Timelines (ScrollTrigger & Lenis Sync)
The Synchronization Bridge
To solve coordinate misalignment, we must configure a bridge that updates GSAP’s ScrollTrigger markers exactly when Lenis calculates a new scroll offset. This is done by adding Lenis's request animation frame updates to the GSAP ticker.
// 1. Initialize Lenis Smooth Scroll
const lenis = new Lenis({
duration: 1.2,
easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
orientation: 'vertical',
gestureOrientation: 'vertical',
smoothWheel: true,
wheelMultiplier: 1
});
// 2. Connect ScrollTrigger to Lenis Scroll Events
lenis.on('scroll', ScrollTrigger.update);
// 3. Use GSAP's Ticker to drive Lenis Updates
gsap.ticker.add((time) => {
lenis.raf(time * 1000); // convert time to milliseconds
});
// 4. Disable Lag Smoothing for immediate response
gsap.ticker.lagSmoothing(0);
Engine Execution Breakdown
First, the Lenis instance uses an exponential decay easing curve to make mouse wheel movement slide slowly to a stop. Next, lenis.on('scroll', ScrollTrigger.update) updates ScrollTrigger's geometric calculations immediately upon scroll. Finally, by wiring lenis.raf() to GSAP's ticker, we guarantee that scroll recalculations and tween rendering happen in the exact same paint frame.
STAGE 3: Advanced Scroll-Triggered Patterns
1. Element Reveal (Staggered Fade-Up)
Instead of elements popping in awkwardly, stagger their appearance as they scroll into view. Using gsap.fromTo with a scroll trigger triggers the animation cleanly when the element is 15% from the bottom of the viewport.
gsap.fromTo(".reveal-item",
{ opacity: 0, y: 50 },
{
opacity: 1,
y: 0,
stagger: 0.15,
duration: 1,
ease: "power3.out",
scrollTrigger: {
trigger: ".reveal-container",
start: "top 85%"
}
}
);
2. Horizontal Scroll Scrubbing
Scrubbing links the animation playhead directly to scroll progression. We can lock the screen in place (pinning) and slide a container horizontally as the user scrolls downwards.
gsap.to(".horizontal-track", {
x: () => -(document.querySelector('.horizontal-track').scrollWidth - window.innerWidth),
ease: "none",
scrollTrigger: {
trigger: ".horizontal-wrapper",
start: "top top",
end: () => "+=" + document.querySelector('.horizontal-track').scrollWidth,
scrub: true,
pin: true,
invalidateOnRefresh: true
}
});
STAGE 4: Performance & Optimization Guardrails
Hardware Optimization Practices
Animations should enhance, not degrade, usability. Keep these practices in mind to optimize execution speeds:
- CSS will-change: Use
will-change: transform, opacityon animated cards. This forces the browser to delegate rendering tasks directly to the GPU, minimizing layout calculations on the main CPU thread. - Invalidate on Refresh: Set
invalidateOnRefresh: trueinside triggers that use window heights. This forces GSAP to recalculate positions when layouts shift or screen sizes scale (especially on mobile orientation changes). - Destroy and Kill: Memory leaks quickly degrade browser performance. Always call
scrollTrigger.kill()andlenis.destroy()when unmounting web pages in modern frameworks.
Dynamic Digital Craftsmanship
Integrating GSAP and Lenis allows you to control motion, timeline, and input speed. By building layouts that adapt to user interaction, you elevate your web products from static pages to interactive, dynamic digital art.
If you're seeking to create a visually striking, smooth website for your business, check out my UI/UX designing and frontend services. Let's work together to create high-performance designs—you can contact me here to start planning your next custom project.