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 ?