The Lenis ScrollTrigger gsap.ticker Fix for Frozen Animations
Struggling with frozen GSAP ScrollTrigger animations when using Lenis? Learn the cause and the simple gsap.ticker.add fix to sync them for smooth scrolling.
The Problem: Why Your Scrubbed Animations Freeze
If you build modern, interactive websites, you've likely combined the GreenSock Animation Platform (GSAP) with a smooth scrolling library like Lenis. GSAP's ScrollTrigger is powerful for creating animations that react to scroll position. Lenis provides a polished, fluid scrolling experience that native browser scroll often lacks.
The problem arises when you try to scrub a GSAP animation—that is, directly link its progress to the user's scroll position. You set up your timeline, configure ScrollTrigger with scrub: true, and it works perfectly. Then you add Lenis. Suddenly, the animation freezes. It might jump to its final state when you reach the end of the trigger, but it won't animate smoothly as you scroll. This is a common frustration, and it requires a specific Lenis ScrollTrigger gsap.ticker fix.
At JRV Systems, we encounter this exact scenario when developing highly interactive web experiences. The issue isn't a bug in either library; it's a conflict in how they handle updates.
The Core Issue: A Battle of Update Loops
To understand the fix, we first need to understand the conflict. It boils down to how each library gets its data.
- GSAP's ScrollTrigger listens to the browser's native
scrollevent by default. It uses this event to know the page's scroll position and update any linked animations. - Lenis disables the native scroll behavior. It listens for user input (like a mouse wheel or touch gesture) and then programmatically moves the page content, calculating the position with its own logic to create the smooth effect. Because it's not using the native scrollbar mechanism, it doesn't fire the native
scrollevent that ScrollTrigger is waiting for.
GSAP runs on its own internal timer, called gsap.ticker. This is essentially a requestAnimationFrame loop, which is the browser's standard way of running code efficiently just before the screen repaints (ideally 60 times per second). Since ScrollTrigger isn't getting any new scroll position data from the native event, the ticker has no new information to update the animation, and it appears frozen.
The Solution: The Lenis ScrollTrigger gsap.ticker Fix
The solution is to manually connect Lenis's scroll updates to GSAP's update loop. We need to tell GSAP's ticker to also run Lenis's update function on every frame. This ensures both systems are perfectly synchronized.
Here is the essential code snippet that resolves the conflict:
const lenis = new Lenis()
lenis.on('scroll', ScrollTrigger.update)
gsap.ticker.add((time)=>{
lenis.raf(time * 1000)
})
gsap.ticker.lagSmoothing(0)
Let's break this down:
const lenis = new Lenis(): This is the standard initialization for the Lenis library.lenis.on('scroll', ScrollTrigger.update): This line is crucial for non-scrubbed animations. It tells ScrollTrigger to perform its calculations whenever Lenis reports a scroll event. This helps with accurately triggering animations that just play once.gsap.ticker.add((time)=>{ lenis.raf(time * 1000) }): This is the heart of the fix for scrubbed animations. We are tapping into GSAP's central update loop (gsap.ticker). On every single tick (frame), we call Lenis'sraf(requestAnimationFrame) method. This forces Lenis to recalculate its smooth scroll position and then, because they are now in the same loop, ScrollTrigger can get that fresh position data to update the scrubbed animation.gsap.ticker.lagSmoothing(0): This is an optional but recommended optimization. It tells GSAP's ticker to not try and "catch up" after potential stutters or lag, which can sometimes interfere with smooth scroll libraries.
By adding these few lines to your project's JavaScript setup, you create a bridge between the two libraries, allowing them to share a single source of truth for timing and updates.
Implementation Details and Best Practices
When implementing this fix, there are a few other considerations to keep in mind for a robust and accessible website.
Handling Reduced Motion
Users can enable an operating system setting called prefers-reduced-motion to signal that they want to see less animation. It's a critical accessibility feature. You should respect this by disabling Lenis and potentially complex ScrollTrigger effects.
const lenis = new Lenis()
if (ScrollTrigger.isTouch !== 1 && !window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
lenis.on('scroll', ScrollTrigger.update)
gsap.ticker.add((time) => {
lenis.raf(time * 1000)
})
gsap.ticker.lagSmoothing(0)
}
This code wraps the fix in a condition that checks if the user prefers reduced motion. We also added a check for touch devices (ScrollTrigger.isTouch !== 1), as smooth scrolling can sometimes feel unnatural on mobile.
iOS Safari Considerations Mobile browsers, especially Safari on iOS, have unique scroll physics. While this fix generally works well, always test thoroughly on a real iPhone. The interaction between the browser's viewport, virtual keyboards, and programmatic scrolling can sometimes introduce jitter. The provided setup is the most reliable starting point we've found.
How We Verify the Fix is Working
How do you know the fix is correctly implemented? The most obvious sign is that your scrubbed animations work as expected. But for a more technical confirmation, you can use the browser's developer tools.
- Visual Inspection: Scroll up and down. The animation should smoothly follow your scroll position, moving forward as you scroll down and backward as you scroll up.
- Performance Monitoring: Open your browser's Performance monitor (e.g., in Chrome DevTools). When you scroll, you should see a consistent frame rate close to 60 frames per second (fps). If the animation is jerky, the frame rate graph will show frequent dips.
- Console Logging: Temporarily add a
console.loginside thegsap.ticker.addfunction. You should see it firing continuously as you scroll, confirming the loop is active.
As a software studio in Seremban, we apply these verification steps to ensure the websites we build for Malaysian businesses are not just visually appealing but also technically sound and performant on all common devices.