Jump to content
Search Community

GSAP x NextJS x Locomotive Scroll

adelcourte test
Moderator Tag

Recommended Posts

I'm trying to create a simple effect in Nextjs 13 but can't find a way to make nextjs, locoscroll and gsap work together.

Here's the wrapper in which all of my pages will be rendered :

 

'use client'

import { useEffect } from 'react'
import { gsap } from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'

export default function LocomotiveScrollProvider({ children }) {
    useEffect(() => {
        let locoScroll

        import('locomotive-scroll').then((locomotiveModule) => {
            gsap.registerPlugin(ScrollTrigger)

            locoScroll = new locomotiveModule.default({
                el: document.querySelector('[data-scroll-container]'),
                smooth: true,
                smoothMobile: false,
                resetNativeScroll: true,
                getDirection: true,
            })

            locoScroll.on('scroll', () => {
                ScrollTrigger.update()
            })

            ScrollTrigger.scrollerProxy('.smooth-scroll-gsap', {
                scrollTop(value) {
                    return arguments.length
                        ? locoScroll.scrollTo(value, 0, 0)
                        : locoScroll.scroll.instance.scroll.y
                },
                getBoundingClientRect() {
                    return {
                        top: 0,
                        left: 0,
                        width: window.innerWidth,
                        height: window.innerHeight,
                    }
                },

                pinType: document.querySelector('.smooth-scroll-gsap').style
                    .transform
                    ? 'transform'
                    : 'fixed',
            })

            ScrollTrigger.addEventListener('refresh', () => locoScroll.update())

            ScrollTrigger.refresh()
        })

        window.addEventListener('DOMContentLoaded', () => {
            locoScroll.update()
        })

        window.addEventListener('resize', () => {
            locoScroll.update()
        })
    }, [])

    return (
        <div data-scroll-container>
            <div className="smooth-scroll-gsap">{children}</div>
        </div>
    )
}

 

And here's my component code :

 

'use client'

import { useEffect, useRef } from 'react'
import { gsap } from 'gsap'

export default function Remember() {
    const containerRef = useRef(null)
    const cardRef = useRef(null)

    useEffect(() => {
        let ctx = gsap.context(() => {
            const tl = gsap.timeline({
                scrollTrigger: {
                    trigger: containerRef.current,
                    start: 'center center',
                    end: '+=100%',
                    scrub: true,
                    pin: true,
                    markers: true,
                    scroller: '.smooth-scroll-gsap',
                },
            })

            tl.from(cardRef.current, {
                yPercent: 100,
                top: '100%',
            }).to(cardRef.current, {
                yPercent: -50,
                top: '50%',
            })
        }, containerRef.current)

        return () => ctx.revert()
    }, [])

    return (
        <section
            data-scroll-section
            ref={containerRef}
            className="relative min-h-screen flex items-center justify-center"
        >
            <div className="row flex justify-center">
                <h2 className="text-[10vw] text-center w-2/3 leading-[0.8] font-bit">
                    REMEMBER YOUR WILDEST MEMORIES
                </h2>
            </div>
            <div
                ref={cardRef}
                className="w-[300px] h-[600px] bg-red-500 absolute left-1/2 -translate-x-1/2"
            ></div>
        </section>
    )
}

 

Basically I would like to have an effect like this :
 

  • There's a div with a text in the middle and a hidden card in absolute position
  • When the div reaches the middle of the viewport, scrolling stops and the card starts changing its top % value to overlay the text in the middle
  • Once done, the scroll starts again

 

But I can't find a way to make it work. Would anyone know about this type of effects ?

Link to comment
Share on other sites

Hi,

 

There is not a lot we can do without a minimal demo. We do have this collection of examples that use GSAP in Next apps:

https://stackblitz.com/@GreenSockLearning/collections/gsap-nextjs-starters

 

On top of that Locomotive is not a GSAP product so we can't really give any support for it. @akapowl, one of the superstars in these forums, came up with a solid resource for using Locomotive with React, it might be worth exploring that:

 

Hopefully this helps.

Happy Tweening!

  • Like 1
Link to comment
Share on other sites

Hi if you are using a NextJS @adelcourte you can't call / import the ScrollTrigger outside of the component because nextjs is static, so what you would want to do is something like this which is improvised of your code. 

 

        import('locomotive-scroll').then((locomotiveModule) => {
            import("ScrollTrigger/all").then(({ScrollTrigger}) => {
            	gsap.registerPlugin(ScrollTrigger)
            })
        })  
                                           

It is also applied in other gsap plugin so becareful when you using static html. 

 

  • Like 2
Link to comment
Share on other sites

Hello @Rodrigo thank you for the posts you shared. Saddly, either I couldn't make it work in my project or the solution is somewhat else. I created a sandbox to help anyone see the code as it is https://codesandbox.io/p/github/ntndlcrt/memoire-vive/

Not quite sure why locoscroll doesn't work well though, I think I will redo the project later with more time given.

I do appreciate your help however and hope I'll find a way to make it work.

Link to comment
Share on other sites

Hi there! Looks like you're running into some perf issues, from a brief glance I've spotted clip path, mix blend mode and blur in your codebase, as well as some pretty rendering intensive SVG filter and pattern effects.

A lot of performance problems are down to how browsers and graphics rendering work. It's very difficult to troubleshoot blind and performance is a DEEP topic, but here are some tips: 

 

  1. Try setting will-change: transform on the CSS of your moving elements. 
  2. Make sure you're animating transforms (like x, y) instead of layout-affecting properties like top/left. 
  3. Definitely avoid using CSS filters or things like blend modes or blur on animated elements. Those are crazy expensive for browsers to render. They can even cause issues when they're just drawn to large areas of the screen and not animated.
  4. Make sure you're not doing things on scroll that'd actually change/animate the size of the page itself (like animating the height property of an element in the document flow)
  5. Minimize the area of change. Imagine drawing a rectangle around the total area that pixels change on each tick - the bigger that rectangle, the harder it is on the browser to render. Again, this has nothing to do with GSAP - it's purely about graphics rendering in the browser. So be strategic about how you build your animations and try to keep the areas of change as small as you can.
  6. If you're animating individual parts of SVG graphics, that can be expensive for the browser to render. SVGs have to fabricate every pixel dynamically using math. If it's a static SVG that you're just moving around (the whole thing), that's fine - the browser can rasterize it and just shove those pixels around...but if the guts of an SVG is changing, that's a very different story. 
  7. data-lag is a rather expensive effect, FYI. Of course we optimize it as much as possible but the very nature of it is highly dynamic and requires a certain amount of processing to handle correctly.
  8. I'd recommend strategically disabling certain effects/animations and then reload it on your laptop and just see what difference it makes (if any). 

Ultimately there's no silver bullet, like "enable this one property and magically make a super complex, graphics-heavy site run perfectly smoothly even on 8 year old phones"

 

Quote

setting will-change properties breaks both scrub and pin on my elements

Is there any chance that you can provide a minimal demo showing this? I can't think of a reason why this would happen and I've never seen it before.

 

I hope this helps!  💚

Link to comment
Share on other sites

Hi @Cassie thank you very much for your advices. i do have svgs taking like... the entire page and apply blur and blend effects on them. It does seem like exporting the already blured svg could save some resources, maybe even not using it as an svg but a plain webp image maybe ?

However, I did try to do the entire animation without anything on my page other than the div with the clip-path animation and it was still laggy (which I'm sure has nothing to do with GSAP because it worked well in other projects and I see some examples where it works fine).

https://memoire-vive.vercel.app/gsap-playground/clip-path

You can find a simple clip path here (the page with huge lags but completely understandable after your feedback is the website index)

Thank you very much for your help, I truly appreciate it

  • Like 1
Link to comment
Share on other sites

Yep, an image may be a better plan. I can't say for sure. These things are often just 'test and see'.

I can't see the code at that link I'm afraid, if you need more input into that animation could you provide a link where we can see and edit the code?
But yeah, sadly clip path can be a bit laggy, depending on what's being clipped, the area that's changing and the browser being used. 

Thanks!

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...