import { gsap } from 'gsap'; import { ScrollSmoother } from 'gsap/ScrollSmoother'; import { ScrollTrigger } from 'gsap/ScrollTrigger'; gsap.registerPlugin(ScrollTrigger, ScrollSmoother); const mm = gsap.matchMedia(); mm.add('(min-width: 992px)', () => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const scroller = ScrollSmoother.create({ content: '#smooth-content', smooth: 0.75, effects: true, smoothTouch: 0.1, }); }); // Utility functions const createPillScrollTrigger = ( item: HTMLElement, index: number, textBlocks: HTMLElement[], pillDuration: number, offset: number ) => ({ trigger: item, start: `top-=${offset}px center`, end: 'bottom center', scrub: false, markers: false, onEnter: () => highlightPill(item, index, textBlocks, pillDuration), onLeave: () => resetPill(item, index, textBlocks, pillDuration), onEnterBack: () => highlightPill(item, index, textBlocks, pillDuration), onLeaveBack: () => resetPill(item, index, textBlocks, pillDuration), }); const highlightPill = ( item: HTMLElement, index: number, textBlocks: HTMLElement[], pillDuration: number ) => { gsap.to(item, { backgroundColor: 'var(--base-color-neutral--950)', color: 'var(--base-color-neutral--50)', duration: pillDuration, }); if (index !== 0) { gsap.to(textBlocks[0], { backgroundColor: '', color: '', duration: pillDuration }); } if (index !== textBlocks.length - 1) { gsap.to(textBlocks[textBlocks.length - 1], { backgroundColor: '', color: '', duration: pillDuration, }); } }; const resetPill = ( item: HTMLElement, index: number, textBlocks: HTMLElement[], pillDuration: number ) => { if (index !== textBlocks.length - 1 && index !== 0) { gsap.to(item, { backgroundColor: '', color: '', duration: pillDuration }); } }; const pinToBackAnimation = { z: -200, opacity: 0, filter: 'blur(5px)', }; // Animation functions const setupHeroTitleAnimation = () => { const heroTitleTimeline = gsap.timeline({ scrollTrigger: { trigger: '[gsap="title_trigger"]', start: 'clamp(center center)', scrub: true, pin: true, pinSpacing: false, markers: false, }, }); heroTitleTimeline .to('[gsap="nav_spacer"]', { minHeight: '4rem', duration: 0.25 }) .to('[gsap="title_target"]', pinToBackAnimation, '-=0.2'); const mm = gsap.matchMedia(); mm.add('(min-width: 992px)', () => { heroTitleTimeline.from('[gsap="nav_menu"]', { backgroundColor: '#2A2C33', duration: 0.25 }, 0); }); }; const setupHeroBackgroundAnimation = () => { const heroBackgroundTimeline = gsap.timeline({ scrollTrigger: { trigger: '[gsap="hero"]', start: '70% center', end: '100% center', scrub: true, markers: false, }, }); const navSpacer = '[gsap="nav_spacer"]'; heroBackgroundTimeline .to('[gsap="hero_background"]', { backgroundColor: '#f8f6f2' }) .to('[gsap="hero_text"]', { color: '#10121a' }, 0) .to(navSpacer, { backgroundColor: '#f8f6f2' }, 0) .to(navSpacer, { attr: { 'data-theme': 'light' } }, 0.175); }; const setupSidebarAnimation = () => { const toggleSidebar = (rightValue: string) => { gsap.to('[gsap="sidebar"]', { right: rightValue }); }; gsap.from('[gsap="sidebar"]', { right: '-100%', scrollTrigger: { trigger: '[gsap="sidebar_trigger"]', start: 'top bottom', end: 'bottom top', markers: false, onEnter: () => toggleSidebar('0%'), onLeave: () => toggleSidebar('-100%'), onEnterBack: () => toggleSidebar('0%'), onLeaveBack: () => toggleSidebar('-100%'), }, }); }; const setupCardsAnimation = () => { const triggers = document.querySelectorAll('[gsap="cards_trigger"]'); triggers.forEach((trigger) => { const topRow = trigger.querySelector('[gsap="cards_top_row"]'); if (topRow) { const cardsTimeline = gsap.timeline({ scrollTrigger: { trigger: trigger, start: 'center 40%', end: 'bottom top', scrub: true, pin: true, pinSpacing: false, markers: false, }, }); mm.add('(min-width: 767px)', () => { cardsTimeline.to(topRow, pinToBackAnimation); }); } }); }; const setupTestimonialAnimation = () => { const testimonialTimeline = gsap.timeline({ scrollTrigger: 'testimonial_trigger', start: 'center 40%', end: 'bottom top', scrub: true, pin: true, pinSpacing: false, markers: false, }); mm.add('(min-width: 767px)', () => { testimonialTimeline.to('testimonial_target', pinToBackAnimation); }); }; const setupStaggerAnimation = () => { const defaultBlurAnimation = { scale: 1.1, duration: 0.5, filter: 'blur(16px)', ease: 'power2.out', }; gsap.from('[gsap="stagger"]', { ...defaultBlurAnimation, stagger: 0.2, scrollTrigger: { trigger: '[gsap="stagger"]', start: 'top 95%', markers: false, }, }); }; const setupTabImageAnimations = () => { const images = gsap.utils.toArray('[gsap="tab_image"]') as HTMLElement[]; images.forEach((image) => { gsap.from(image, { scale: 1.1, duration: 0.5, filter: 'blur(16px)', ease: 'power2.out', scrollTrigger: { trigger: image, start: 'top 85%', markers: false, }, }); }); }; const setupPillAnimations = () => { const pillTimeline = gsap.timeline({ scrollTrigger: { trigger: '[gsap="pill_trigger"]', start: 'top center', end: 'bottom center', scrub: true, pin: true, anticipatePin: 1, markers: false, pinSpacing: false, }, }); const pillDuration = 0; const textBlocks = gsap.utils.toArray('[gsap="pill"]') as HTMLElement[]; mm.add('(min-width: 480px)', () => { const remValue = parseFloat((textBlocks[0].offsetHeight / 6.9).toFixed(4)); const totalRemValue = (textBlocks.length - 1) * remValue; pillTimeline.to(textBlocks, { yPercent: -100 * (textBlocks.length - 1), y: -1 * totalRemValue, ease: 'none', }); console.log(remValue); textBlocks.forEach((item, index) => { ScrollTrigger.create(createPillScrollTrigger(item, index, textBlocks, pillDuration, 16)); }); }); mm.add('(max-width: 479px)', () => { const remValue = parseFloat((textBlocks[0].offsetHeight / 3.9 / 2).toFixed(4)); const totalRemValue = (textBlocks.length - 1) * remValue; pillTimeline.to(textBlocks, { yPercent: -100 * (textBlocks.length - 1), y: -1 * totalRemValue, ease: 'none', }); textBlocks.forEach((item, index) => { ScrollTrigger.create( createPillScrollTrigger(item, index, textBlocks, pillDuration, remValue / 2) ); }); }); gsap.set(textBlocks[0], { backgroundColor: 'var(--base-color-neutral--950)', color: 'var(--base-color-neutral--50)', duration: pillDuration, }); ScrollTrigger.create({ trigger: '[gsap="pill_trigger"]', start: 'bottom center', end: 'bottom bottom', scrub: false, markers: false, onEnter: () => { gsap.to(textBlocks[textBlocks.length - 1], { backgroundColor: 'var(--base-color-neutral--950)', color: 'var(--base-color-neutral--50)', duration: pillDuration, }); }, onLeaveBack: () => { gsap.to(textBlocks[textBlocks.length - 1], { backgroundColor: '', color: '', duration: pillDuration, }); }, }); }; const setupCtaAnimations = () => { const ctaTimeline = gsap.timeline({ scrollTrigger: { trigger: '[gsap="cta_expand"]', start: 'top 90%', end: 'bottom center', scrub: true, markers: false, }, }); mm.add('(min-width: 479px)', () => { ctaTimeline.to('[gsap="cta_expand"]', { maxWidth: '100%', }); }); const ctaImageTimeline = gsap.timeline({ scrollTrigger: { trigger: '[gsap="cta_image_list"]', start: 'top 95%', end: 'center center', scrub: true, markers: false, }, }); const ctaImageAnimation = { z: -150, duration: 0.5, filter: 'blur(16px)', ease: 'power2.out', }; mm.add('(min-width: 479px)', () => { ctaImageTimeline .from('[gsap="cta_image_3"]', ctaImageAnimation, '+=0.1') .from('[gsap="cta_image_2"]', ctaImageAnimation, '-=0.25') .from('[gsap="cta_image_4"]', ctaImageAnimation, '-=0.5') .from('[gsap="cta_image_1"]', ctaImageAnimation, '-=0.25') .from('[gsap="cta_image_5"]', ctaImageAnimation, '-=0.5'); }); }; const setupNavAnimation = () => { gsap.to('[gsap="nav"]', { position: 'fixed', top: '-100%', scrollTrigger: { trigger: '[gsap="footer"]', scrub: true, start: 'top top', }, }); }; // Initialization document.addEventListener('DOMContentLoaded', () => { setupHeroTitleAnimation(); setupHeroBackgroundAnimation(); setupSidebarAnimation(); setupCardsAnimation(); setupStaggerAnimation(); setupTestimonialAnimation(); setupTabImageAnimations(); setupPillAnimations(); setupCtaAnimations(); setupNavAnimation(); });