
Lenis는 부드러운 스크롤을 구현하는 JavaScript 라이브러리이다.
<script src="https://unpkg.com/lenis@1.1.18/dist/lenis.min.js"></script>
const lenis = new Lenis();
lenis.on('scroll', ScrollTrigger.update);
gsap.ticker.add((time) => {
lenis.raf(time * 700);
});
gsap.ticker.lagSmoothing(0);

<div class="group-text">
<div class="text-wrap">
<span class="text txt1">TAG HEUER</span>
</div>
<div class="text-wrap">
<span class="text txt2">FORMULA</span>
<span class="space"></span>
<span class="text txt3"> 1 | KITH</span>
</div>
</div>
const kithVideo = gsap.timeline({
scrollTrigger:{
trigger: ".sc-kith .sticky-wrapper",
start: "top top",
end: "100% 100%",
scrub: 0,
}
})
kithVideo
.to('.sc-kith .group-video .video-area',{
'clip-path': function(){
const sticky = document.querySelector('.sc-kith .sticky-wrapper .sticky');
const space = document.querySelector('.sc-kith .space');
const stickyRect = sticky.getBoundingClientRect();
const spaceRect = space.getBoundingClientRect();
const relativeTop = spaceRect.top - stickyRect.top;
const relativeLeft = spaceRect.left - stickyRect.left;
const relativeBottom = spaceRect.top - space.clientHeight;
const relativeRight = spaceRect.left;
return `inset(${relativeTop}px ${relativeLeft}px ${relativeBottom}px ${relativeRight}px )`
}
},'b')
.sticky에 height: 100vh;가 잡혀있었고,.space에 height값을 줬고,
const kithRow = gsap.timeline({
scrollTrigger:{
trigger: ".sc-kith .product-inner",
start: "top top",
end: "100% 100%",
scrub: 0,
}
});
kithRow.to('.sc-kith .group-product .product-list', {
x:0,
xPercent:-100,
ease: 'none',
});
textList = document.querySelectorAll('.sc-kith .group-product .text-item');
$('.sc-kith .group-product .product-item').each(function(i, el){
// product clock
const kithProd = gsap.timeline({
scrollTrigger:{
containerAnimation: kithRow,
trigger: el,
start: "left 100%",
end: "right 0%",
scrub: 0,
// markers: true,
},
})
kithProd
.to(el.querySelector('.product-case'), {
rotate: 360,
duration: 12,
}, 'prod')
.to(el.querySelector('.product-hours'), {
rotate: 360,
duration: 4,
}, 'prod')
.to(el.querySelector('.product-minute'), {
rotate: 360,
duration: 8,
}, 'prod')
.to(el.querySelector('.product-second'), {
rotate: 360,
duration: 12,
}, 'prod');
// product info text
const kithText = gsap.timeline({
scrollTrigger:{
containerAnimation: kithRow,
trigger: el,
start: "left 65%",
end: "right 50%",
scrub: 0,
// markers: true,
},
})
kithText
.from(textList[i],{
y: 30,
opacity: 0
})
.to(textList[i],{
y: 0,
opacity: 1
})
.to(textList[i],{
y: -30,
opacity: 0
})
});
.product-item에 도달하면 시계의 부품들이 돌아가도록 설정했고,.product-item에 도달하면 .text-item 해당 시계의 정보 텍스트가 나오도록 했다.
slide2 = gsap.to('.sc-collabo .group-slide .slide-item', {
duration: 10,
xPercent: 100,
ease: 'none',
overwrite: 'all',
paused:true,
repeat: -1,
onReverseComplete:function(){
slide1.restart();
}
});
slide1 = gsap.to('.sc-collabo .group-slide .slide-item', {
duration: 10,
xPercent: -100,
ease: 'none',
overwrite: 'all',
repeat: -1,
onReverseComplete:function(){
slide2.restart();
}
});
let up = false;
let firstLeftFlag = false;
let firstRightFlag = false;
ScrollTrigger.create({
trigger: '.area',
start: '0% 50%',
end: '100% 50%',
// markers:true,
onUpdate:function(self){
if(self.direction === 1 && firstLeftFlag === false){
if(slide1.isActive()){
slide1.reverse();
}
else{
slide2.play();
}
firstLeftFlag = true;
firstRightFlag = false;
}else if(self.direction === -1 && firstRightFlag === false){
if(slide2.isActive()){
slide2.reverse();
}else{
slide1.play();
}
firstLeftFlag = false;
firstRightFlag = true;
}
}
})
.sc-collabo .group-slide .slide-item 요소들이 왼쪽(slide1) 또는 오른쪽(slide2)으로 계속 이동하는 무한 슬라이드 애니메이션이다..area 섹션을 감지하여, 스크롤 방향에 따라 슬라이드 애니메이션의 방향을 변경되도록 했다.🌟 Point