let lenis; function initGSAPPlugins() { gsap.registerPlugin(SplitText); gsap.registerPlugin(ScrollTrigger); } function initLenis() { lenis = new Lenis({ duration: 1.25, easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)), }); // lenis.on("scroll", ScrollTrigger.update); gsap.ticker.add((time) => { lenis.raf(time * 1000); }); // gsap.ticker.lagSmoothing(0); $("[data-lenis-start]").on("click", function () { lenis.start(); }); $("[data-lenis-stop]").on("click", function () { lenis.stop(); }); $("[data-lenis-toggle]").on("click", function () { $(this).toggleClass("stop-scroll"); if ($(this).hasClass("stop-scroll")) { lenis.stop(); } else { lenis.start(); } }); } function initLogoGrid() { $("[data-logo-grid=grid").each(function () { document.querySelector("[data-logo-grid=grid]").onmousemove = (e) => { for (const card of document.getElementsByClassName("card")) { const rect = card.getBoundingClientRect(), x = e.clientX - rect.left, y = e.clientY - rect.top; card.style.setProperty("--mouse-x", `${x}px`); card.style.setProperty("--mouse-y", `${y}px`); } }; }); } function initAccordionCSS() { document .querySelectorAll("[data-accordion-css-init]") .forEach((accordion) => { const closeSiblings = false; accordion.addEventListener( "mouseenter", (event) => { const toggle = event.target.closest("[data-accordion-toggle]"); if (!toggle) return; const singleAccordion = toggle.closest("[data-accordion-status]"); if (!singleAccordion) return; const isActive = singleAccordion.getAttribute("data-accordion-status") === "active"; // Open on hover if not already active if (!isActive) { singleAccordion.setAttribute("data-accordion-status", "active"); // Close siblings when opening if (closeSiblings) { accordion .querySelectorAll('[data-accordion-status="active"]') .forEach((sibling) => { if (sibling !== singleAccordion) sibling.setAttribute("data-accordion-status", "not-active"); }); } } }, true ); // Use capture phase to catch events on nested elements accordion.addEventListener( "mouseleave", (event) => { const toggle = event.target.closest("[data-accordion-toggle]"); if (!toggle) return; const singleAccordion = toggle.closest("[data-accordion-status]"); if (!singleAccordion) return; // Close on mouse leave singleAccordion.setAttribute("data-accordion-status", "not-active"); }, true ); }); } function initGlobalParallax() { const mm = gsap.matchMedia(); mm.add( { isMobile: "(max-width:479px)", isMobileLandscape: "(max-width:767px)", isTablet: "(max-width:991px)", isDesktop: "(min-width:992px)", }, (context) => { const { isMobile, isMobileLandscape, isTablet } = context.conditions; const ctx = gsap.context(() => { document .querySelectorAll('[data-parallax="trigger"]') .forEach((trigger) => { // Check if this trigger has to be disabled on smaller breakpoints const disable = trigger.getAttribute("data-parallax-disable"); if ( (disable === "mobile" && isMobile) || (disable === "mobileLandscape" && isMobileLandscape) || (disable === "tablet" && isTablet) ) { return; } // Optional: you can target an element inside a trigger if necessary const target = trigger.querySelector('[data-parallax="target"]') || trigger; // Get the direction value to decide between xPercent or yPercent tween const direction = trigger.getAttribute("data-parallax-direction") || "vertical"; const prop = direction === "horizontal" ? "xPercent" : "yPercent"; // Get the scrub value, our default is 'true' because that feels nice with Lenis const scrubAttr = trigger.getAttribute("data-parallax-scrub"); const scrub = scrubAttr ? parseFloat(scrubAttr) : true; // Get the start position in % const startAttr = trigger.getAttribute("data-parallax-start"); const startVal = startAttr !== null ? parseFloat(startAttr) : 20; // Get the end position in % const endAttr = trigger.getAttribute("data-parallax-end"); const endVal = endAttr !== null ? parseFloat(endAttr) : -20; // Get the start value of the ScrollTrigger const scrollStartRaw = trigger.getAttribute("data-parallax-scroll-start") || "top bottom"; const scrollStart = `clamp(${scrollStartRaw})`; // Get the end value of the ScrollTrigger const scrollEndRaw = trigger.getAttribute("data-parallax-scroll-end") || "bottom top"; const scrollEnd = `clamp(${scrollEndRaw})`; gsap.fromTo( target, { [prop]: startVal }, { [prop]: endVal, ease: "none", scrollTrigger: { trigger, start: scrollStart, end: scrollEnd, scrub, }, } ); }); }); return () => ctx.revert(); } ); } function initTextSplit() { $("[data-split=chars]").each(function () { const toSplit = $(this).children(); SplitText.create(toSplit, { type: "chars, words, lines", mask: "lines", wordsClass: "word", charsClass: "char", linesClass: "line", ignore: ".u-flex-noshrink", }); }); $("[data-split=words]").each(function () { const toSplit = $(this).children(); SplitText.create(toSplit, { type: "words, lines", mask: "lines", wordsClass: "word", linesClass: "line", }); }); $("[data-split=lines]").each(function () { const toSplit = $(this).children(); SplitText.create(toSplit, { type: "lines", mask: "lines", linesClass: "line", ignore: "ol", }); }); // $("[data-split=rich-lines]").each(function () { // const toSplit = $(this).children(); // SplitText.create(toSplit, { // type: "lines", // mask: "lines", // linesClass: "line", // }); // }); } function initStatements() { $("[data-statement=wrap]").each(function () { const topHeading = $(this).find("[data-anim-scroll=statement-top]"); const bottomHeading = $(this).find("[data-anim-scroll=statement-bottom]"); // topHeading.each(function () { // const element = $(this); // SplitText.create(element.children(), { // type: "lines, words, chars", // mask: "lines", // autoSplit: true, // linesClass: "line", // wordsClass: "word", // onSplit: function (instance) { // let ctx = gsap.context(() => { // let tl = gsap.timeline({ // scrollTrigger: { // trigger: element, // start: "top 90%", // // once: true, // toggleActions: "play none none reverse", // }, // }); // let fadeTl = gsap.timeline({ // scrollTrigger: { // scrub: true, // trigger: element, // start: "top 80%", // end: "bottom center", // }, // }); // tl.from(instance.words, { // yPercent: 110, // duration: 1.75, // stagger: { each: 0.05 }, // ease: "expo.out", // }); // tl.from( // element, // { // xPercent: 8.75, // duration: 1.5, // ease: "expo.inOut", // }, // "<.25" // ); // fadeTl.from(instance.chars, { // autoAlpha: 0.2, // stagger: 0.1, // ease: "linear", // }); // }); // return ctx; // }, // }); // }); topHeading.each(function () { const element = $(this); const words = element.find(".word"); const chars = element.find(".char"); let tl = gsap.timeline({ scrollTrigger: { trigger: element, start: "top 90%", // once: true, toggleActions: "play none none reverse", }, }); let fadeTl = gsap.timeline({ scrollTrigger: { scrub: true, trigger: element, start: "top 80%", end: "bottom center", }, }); tl.from(words, { yPercent: 110, duration: 1.75, stagger: { each: 0.05 }, ease: "expo.out", }); tl.from( element, { xPercent: 8.75, duration: 1.5, ease: "expo.inOut", }, "<.25" ); fadeTl.from(chars, { autoAlpha: 0.2, stagger: 0.1, ease: "linear", }); }); bottomHeading.each(function () { const element = $(this); const words = element.find(".word"); const chars = element.find(".char"); let tl = gsap.timeline({ scrollTrigger: { trigger: element, start: "top 90%", // once: true, toggleActions: "play none none reverse", }, }); let fadeTl = gsap.timeline({ scrollTrigger: { scrub: true, trigger: element, start: "top 80%", end: "bottom center", }, }); tl.from(words, { yPercent: 110, duration: 1.75, stagger: { each: 0.05 }, ease: "expo.out", }); tl.from( element, { xPercent: -12, duration: 1.5, ease: "expo.inOut", }, "<.25" ); fadeTl.from(chars, { autoAlpha: 0.2, stagger: 0.1, ease: "linear", }); }); }); } function initScrollReveals() { $("[data-anim-scroll=words]").each(function () { const el = $(this); const words = el.find(".word"); gsap.from(words, { yPercent: 110, duration: 1.5, stagger: { each: 0.075 }, ease: "expo.out", scrollTrigger: { trigger: el, start: "top 90%", // once: true, toggleActions: "play none none reverse", }, }); }); $("[data-anim-scroll=lines]").each(function () { const el = $(this); const lines = el.find(".line"); gsap.from(lines, { yPercent: 110, duration: 2, stagger: { each: 0.075 }, ease: "expo.out", scrollTrigger: { trigger: el, start: "top 90%", // once: true, toggleActions: "play none none reverse", }, }); }); $("[data-anim-scroll=stagger-children]").each(function () { const els = $(this).children(); gsap.from(els, { opacity: 0, yPercent: 25, duration: 1.75, ease: "expo.out", stagger: { each: 0.125, }, scrollTrigger: { trigger: $(this), start: "top 90%", // once: true, toggleActions: "play none none reverse", }, }); }); $("[data-anim-scroll=fade]").each(function () { const el = $(this); gsap.from(el, { opacity: 0, yPercent: 25, duration: 1.75, ease: "expo.out", scrollTrigger: { trigger: $(this), start: "top 90%", // once: true, toggleActions: "play none none reverse", }, }); }); $("[data-anim-scroll=fade-right]").each(function () { const el = $(this); gsap.from(el, { opacity: 0, xPercent: 17.25, duration: 2, ease: "expo.out", scrollTrigger: { trigger: $(this), start: "top 90%", // once: true, toggleActions: "play none none reverse", }, }); }); $("[data-anim-scroll=horizontal-line]").each(function () { const el = $(this); gsap.from(el, { scaleX: 0, duration: 1.5, ease: "expo.inOut", scrollTrigger: { trigger: $(this), start: "top 90%", // once: true, toggleActions: "play none none reverse", }, }); }); } function initHighlightText() { let splitHeadingTargets = document.querySelectorAll("[data-highlight-text]"); splitHeadingTargets.forEach((heading) => { const scrollStart = heading.getAttribute("data-highlight-scroll-start") || "top 90%"; const scrollEnd = heading.getAttribute("data-highlight-scroll-end") || "center 40%"; const fadedValue = heading.getAttribute("data-highlight-fade") || 0.2; // Opacity of letter const staggerValue = heading.getAttribute("data-highlight-stagger") || 0.1; // Smoother reveal let tl = gsap.timeline({ scrollTrigger: { scrub: true, trigger: heading, start: scrollStart, end: scrollEnd, }, }); tl.from(heading.find(".char"), { autoAlpha: fadedValue, stagger: staggerValue, ease: "linear", }); }); } function initReXLab() { $("[data-section=rex-lab]").each(function () { const section = $(this); document.addEventListener("colorThemesReady", () => { ScrollTrigger.create({ trigger: section, start: "top center", end: "bottom center", onEnter: () => { gsap.to("body", { ...colorThemes.getTheme("brand"), duration: 1, ease: "expo.inOut", }); }, onEnterBack: () => { gsap.to("body", { ...colorThemes.getTheme("brand"), duration: 1, ease: "expo.inOut", }); }, onLeave: () => { gsap.to("body", { ...colorThemes.getTheme("light"), duration: 1, ease: "expo.inOut", }); }, onLeaveBack: () => { gsap.to("body", { ...colorThemes.getTheme("light"), duration: 1, ease: "expo.inOut", }); }, }); }); function initCardStackEffect() { const cards = gsap.utils.toArray('[data-rex-lab="card"]'); cards.forEach((card, index) => { // First card has no previous card to animate if (index === 0) return; const wrapper = card.parentElement; const previousCard = cards[index - 1]; gsap.to(previousCard, { scale: 0.8, filter: "blur(16px)", opacity: 0.5, ease: "power1.in", scrollTrigger: { trigger: wrapper, start: "top 80%", end: "top top", scrub: true, // markers: true, }, }); gsap.from(card, { yPercent: 25, ease: "back.out", scrollTrigger: { trigger: wrapper, start: "top 80%", end: "top top", scrub: 0.5, // markers: true, }, }); }); } initCardStackEffect(); }); } function initMarqueeScrollDirection() { document .querySelectorAll("[data-marquee-scroll-direction-target]") .forEach((marquee) => { // Query marquee elements const marqueeContent = marquee.querySelector( "[data-marquee-collection-target]" ); const marqueeScroll = marquee.querySelector( "[data-marquee-scroll-target]" ); if (!marqueeContent || !marqueeScroll) return; // Get data attributes const { marqueeSpeed: speed, marqueeDirection: direction, marqueeDuplicate: duplicate, marqueeScrollSpeed: scrollSpeed, } = marquee.dataset; // Convert data attributes to usable types const marqueeSpeedAttr = parseFloat(speed); const marqueeDirectionAttr = direction === "right" ? 1 : -1; // 1 for right, -1 for left const duplicateAmount = parseInt(duplicate || 0); const scrollSpeedAttr = parseFloat(scrollSpeed); const speedMultiplier = window.innerWidth < 479 ? 0.25 : window.innerWidth < 991 ? 0.5 : 1; let marqueeSpeed = marqueeSpeedAttr * (marqueeContent.offsetWidth / window.innerWidth) * speedMultiplier; // Precompute styles for the scroll container marqueeScroll.style.marginLeft = `${scrollSpeedAttr * -1}%`; marqueeScroll.style.width = `${scrollSpeedAttr * 2 + 100}%`; // Duplicate marquee content if (duplicateAmount > 0) { const fragment = document.createDocumentFragment(); for (let i = 0; i < duplicateAmount; i++) { fragment.appendChild(marqueeContent.cloneNode(true)); } marqueeScroll.appendChild(fragment); } // GSAP animation for marquee content const marqueeItems = marquee.querySelectorAll( "[data-marquee-collection-target]" ); const animation = gsap .to(marqueeItems, { xPercent: -100, // Move completely out of view repeat: -1, duration: marqueeSpeed, ease: "linear", }) .totalProgress(0.5); // Initialize marquee in the correct direction gsap.set(marqueeItems, { xPercent: marqueeDirectionAttr === 1 ? 100 : -100, }); animation.timeScale(marqueeDirectionAttr); // Set correct direction animation.play(); // Start animation immediately // Set initial marquee status marquee.setAttribute("data-marquee-status", "normal"); // ScrollTrigger logic for direction inversion ScrollTrigger.create({ trigger: marquee, start: "top bottom", end: "bottom top", onUpdate: (self) => { const isInverted = self.direction === 1; // Scrolling down const currentDirection = isInverted ? -marqueeDirectionAttr : marqueeDirectionAttr; // Update animation direction and marquee status animation.timeScale(currentDirection); marquee.setAttribute( "data-marquee-status", isInverted ? "normal" : "inverted" ); }, }); // Extra speed effect on scroll const tl = gsap.timeline({ scrollTrigger: { trigger: marquee, start: "0% 100%", end: "100% 0%", scrub: 0, }, }); const scrollStart = marqueeDirectionAttr === -1 ? scrollSpeedAttr : -scrollSpeedAttr; const scrollEnd = -scrollStart; tl.fromTo( marqueeScroll, { x: `${scrollStart}vw` }, { x: `${scrollEnd}vw`, ease: "none" } ); }); } function initNav() { $("[data-animate-nav-to]").each(function () { document.addEventListener("colorThemesReady", () => { let theme = $(this).attr("data-animate-nav-to"); ScrollTrigger.create({ trigger: $(this), start: "top 7.5%", end: "bottom 7.5%", onToggle: (self) => { if (self.isActive) gsap.to("[data-nav=el]", { ...colorThemes.getTheme(theme), duration: 0.5, ease: "expo.out", }); }, }); }); }); $("[data-nav=el]").each(function () { ScrollTrigger.create({ trigger: "body", start: "top top-=1", toggleClass: { targets: '[data-nav="el"]', className: "is-scrolled", }, }); }); function initNavMove() { const wrap = $("[data-nav=el]"); if (wrap) { navMove = gsap .from(wrap, { yPercent: -100, paused: true, duration: 0.4, }) .progress(1); navMoveTrigger = ScrollTrigger.create({ start: "top top", end: "max", // markers: true, onUpdate: (self) => { if (navMove) { if (self.direction === -1) { navMove.play(); } else { navMove.reverse(); } } }, }); } } function initNavigation() { if (!initNavigation._hasResizeListener) { initNavigation._hasResizeListener = true; window.addEventListener("resize", debounce(initNavigation, 200)); } const isMobile = window.innerWidth < 768; if (isMobile && initNavigation._lastMode !== "mobile") { initMobileMenu(); initNavigation._lastMode = "mobile"; } else if (!isMobile && initNavigation._lastMode !== "desktop") { initDesktopDropdowns(); initNavigation._lastMode = "desktop"; } } function debounce(fn, delay) { let timer; return () => { clearTimeout(timer); timer = setTimeout(fn, delay); }; } function initMobileMenu() { const btn = document.querySelector("[data-menu-button]"); const nav = document.querySelector("[data-menu-status]"); if (!btn || !nav) return; btn.setAttribute("aria-expanded", "false"); btn.setAttribute("aria-controls", "mobile-navigation"); nav.setAttribute("id", "mobile-navigation"); nav.setAttribute("role", "navigation"); nav.setAttribute("aria-label", "Main navigation"); if (!btn._mobileClick) { btn._mobileClick = true; btn.addEventListener("click", () => { const open = nav.dataset.menuStatus === "open"; nav.dataset.menuStatus = open ? "closed" : "open"; btn.setAttribute("aria-expanded", !open); // Close all dropdowns when closing the menu if (open) { Array.from( document.querySelectorAll("[data-dropdown-toggle]") ).forEach((toggle) => { toggle.dataset.dropdownToggle = "closed"; toggle.setAttribute("aria-expanded", "false"); }); } }); } Array.from(document.querySelectorAll("[data-dropdown-toggle]")).forEach( (toggle, i) => { const dd = toggle.nextElementSibling; if (!dd || !dd.classList.contains("nav-dropdown")) return; if (toggle._mobileDropdownInit) return; toggle._mobileDropdownInit = true; toggle.setAttribute("aria-expanded", "false"); toggle.setAttribute("aria-haspopup", "true"); toggle.setAttribute("aria-controls", `dropdown-${i}`); dd.setAttribute("id", `dropdown-${i}`); dd.setAttribute("role", "menu"); dd.querySelectorAll(".nav-dropdown__link").forEach((link) => link.setAttribute("role", "menuitem") ); toggle.addEventListener("click", () => { const open = toggle.dataset.dropdownToggle === "open"; Array.from( document.querySelectorAll("[data-dropdown-toggle]") ).forEach((other) => { if (other !== toggle) { other.dataset.dropdownToggle = "closed"; other.setAttribute("aria-expanded", "false"); if (other === document.activeElement) other.blur(); } }); toggle.dataset.dropdownToggle = open ? "closed" : "open"; toggle.setAttribute("aria-expanded", !open); if (open && toggle === document.activeElement) toggle.blur(); }); } ); // Close mobile menu when clicking nav links Array.from(nav.querySelectorAll(".nav-link")).forEach((link) => { if (link._mobileNavClose) return; link._mobileNavClose = true; link.addEventListener("click", () => { nav.dataset.menuStatus = "closed"; btn.setAttribute("aria-expanded", "false"); }); }); // Close mobile menu when clicking nav links Array.from(nav.querySelectorAll("button")).forEach((link) => { if (link._mobileNavClose || link === btn) return; link._mobileNavClose = true; link.addEventListener("click", () => { nav.dataset.menuStatus = "closed"; btn.setAttribute("aria-expanded", "false"); }); }); } function initDesktopDropdowns() { const toggles = Array.from( document.querySelectorAll("[data-dropdown-toggle]") ); const links = Array.from( document.querySelectorAll(".nav-link:not([data-dropdown-toggle])") ); toggles.forEach((toggle, i) => { const dd = toggle.nextElementSibling; if (!dd || !dd.classList.contains("nav-dropdown") || toggle._desktopInit) return; toggle._desktopInit = true; toggle.setAttribute("aria-expanded", "false"); toggle.setAttribute("aria-haspopup", "true"); toggle.setAttribute("aria-controls", `desktop-dropdown-${i}`); dd.setAttribute("id", `desktop-dropdown-${i}`); dd.setAttribute("role", "menu"); dd.setAttribute("aria-hidden", "true"); dd.querySelectorAll(".nav-dropdown__link").forEach((link) => link.setAttribute("role", "menuitem") ); toggle.addEventListener("click", (e) => { e.preventDefault(); toggles.forEach((other) => { if (other !== toggle) { other.dataset.dropdownToggle = "closed"; other.setAttribute("aria-expanded", "false"); const otherDropdown = other.nextElementSibling; if (otherDropdown) otherDropdown.setAttribute("aria-hidden", "true"); } }); const open = toggle.dataset.dropdownToggle !== "open"; toggle.dataset.dropdownToggle = "open"; toggle.setAttribute("aria-expanded", "true"); dd.setAttribute("aria-hidden", "false"); if (open) { const first = dd.querySelector(".nav-dropdown__link"); if (first) first.focus(); } }); toggle.addEventListener("mouseenter", () => { const anyOpen = toggles.some( (x) => x.dataset.dropdownToggle === "open" ); toggles.forEach((other) => { if (other !== toggle) { other.dataset.dropdownToggle = "closed"; other.setAttribute("aria-expanded", "false"); const otherDropdown = other.nextElementSibling; if (otherDropdown) otherDropdown.setAttribute("aria-hidden", "true"); } }); if (anyOpen) { setTimeout(() => { toggle.dataset.dropdownToggle = "open"; toggle.setAttribute("aria-expanded", "true"); dd.setAttribute("aria-hidden", "false"); }, 20); } else { toggle.dataset.dropdownToggle = "open"; toggle.setAttribute("aria-expanded", "true"); dd.setAttribute("aria-hidden", "false"); } }); dd.addEventListener("mouseleave", () => { toggle.dataset.dropdownToggle = "closed"; toggle.setAttribute("aria-expanded", "false"); dd.setAttribute("aria-hidden", "true"); }); toggle.addEventListener("keydown", (e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); toggle.click(); } else if (e.key === "Escape") { toggle.dataset.dropdownToggle = "closed"; toggle.setAttribute("aria-expanded", "false"); dd.setAttribute("aria-hidden", "true"); toggle.focus(); } }); dd.addEventListener("keydown", (e) => { const items = Array.from(dd.querySelectorAll(".nav-dropdown__link")); const idx = items.indexOf(document.activeElement); if (e.key === "ArrowDown") { e.preventDefault(); items[(idx + 1) % items.length].focus(); } else if (e.key === "ArrowUp") { e.preventDefault(); items[(idx - 1 + items.length) % items.length].focus(); } else if (e.key === "Escape") { e.preventDefault(); toggle.dataset.dropdownToggle = "closed"; toggle.setAttribute("aria-expanded", "false"); dd.setAttribute("aria-hidden", "true"); toggle.focus(); } else if (e.key === "Tab" && !dd.contains(e.relatedTarget)) { toggle.dataset.dropdownToggle = "closed"; toggle.setAttribute("aria-expanded", "false"); dd.setAttribute("aria-hidden", "true"); } }); }); links.forEach((link) => { link.addEventListener("mouseenter", () => { toggles.forEach((toggle) => { toggle.dataset.dropdownToggle = "closed"; toggle.setAttribute("aria-expanded", "false"); const dd = toggle.nextElementSibling; if (dd) dd.setAttribute("aria-hidden", "true"); }); }); }); document.addEventListener("click", (e) => { const inside = toggles.some((toggle) => { const dd = toggle.nextElementSibling; return toggle.contains(e.target) || (dd && dd.contains(e.target)); }); if (!inside) { toggles.forEach((toggle) => { toggle.dataset.dropdownToggle = "closed"; toggle.setAttribute("aria-expanded", "false"); const dd = toggle.nextElementSibling; if (dd) dd.setAttribute("aria-hidden", "true"); }); } }); } initNavigation(); // initNavMove(); } function initLottieAnimations() { const reduceMotion = window.matchMedia( "(prefers-reduced-motion: reduce)" ).matches; document.querySelectorAll("[data-lottie]").forEach((target) => { let anim; // Store animation reference ScrollTrigger.create({ trigger: target, start: "top bottom+=50%", // Load lottie once it's half a viewport away from entering end: "bottom top-=25%", onEnter: handleEnter, onEnterBack: handleEnter, onLeave: handleLeave, onLeaveBack: handleLeave, }); function handleEnter() { // Handle first enter: create a lottie player if (!target.hasAttribute("data-lottie-fired")) { target.setAttribute("data-lottie-fired", "true"); anim = lottie.loadAnimation({ container: target, renderer: "svg", loop: true, autoplay: !reduceMotion, path: target.getAttribute("data-lottie-src"), }); // If reduced motion is ON, load the first frame as a static SVG image // Add [data-lottie-frame] with the number of your desired frame if not 0 anim.addEventListener("DOMLoaded", () => { if (reduceMotion) { const frame = parseInt( target.getAttribute("data-lottie-frame") || "0", 10 ); anim.goToAndStop(frame, true); } }); } else if (anim && !reduceMotion) { // If lottie enters view again, and is already created, simply play it anim.play(); } } function handleLeave() { if (anim && !reduceMotion) { anim.pause(); } } }); } function initPageLoad() { const isMobile = window.innerWidth <= 768; if (isMobile) return; let loadEls = document.querySelectorAll("[data-anim-load]"); loadEls.forEach((el) => { gsap.set(el, { autoAlpha: 1 }); }); let introTl = gsap.timeline({ delay: 1.5, }); const topHeading = $("[data-anim-load=heading-top]"); const bottomHeading = $("[data-anim-load=heading-bottom]"); const horizontalLine = $("[data-anim-load=horizontal-line]"); const heroRect = $("[data-anim-load=hero-rect]"); topHeading.each(function () { const element = $(this); introTl.from(element.find(".char"), { yPercent: 125, duration: 1.75, stagger: { each: 0.05 }, ease: "expo.out", }); introTl.from( element, { xPercent: -25, duration: 1.75, ease: "expo.inOut", }, "<" ); }); bottomHeading.each(function () { const element = $(this); introTl.from( element.find(".char"), { yPercent: 125, duration: 1.75, stagger: { each: 0.05 }, ease: "expo.out", }, "<" ); introTl.from( element, { xPercent: 25, duration: 1.75, ease: "expo.inOut", }, "<" ); }); heroRect.each(function () { introTl.fromTo( $(this), { clipPath: "circle(0.2% at 0% 0%)", // xPercent: -15, }, { clipPath: "circle(140% at 0% 0%)", // xPercent: 0, duration: 2.5, ease: "expo.inOut", }, "<" ); }); horizontalLine.each(function () { const el = $(this); introTl.from( el, { scaleX: 0, duration: 1, ease: "expo.out", }, "<1" ); }); $("[data-anim-load=words]").each(function () { const el = $(this); introTl.from( el.find(".word"), { yPercent: 110, duration: 1.5, stagger: { each: 0.05 }, ease: "expo.out", }, "<" ); }); $("[data-anim-load=lines]").each(function () { const el = $(this); introTl.from( el.find(".line"), { delay: 0.5, yPercent: 110, duration: 1.5, stagger: { each: 0.025 }, ease: "expo.out", }, "<" ); }); introTl.from( $("[data-anim-load=nav-child]"), { opacity: 0, xPercent: 100, duration: 1.75, ease: "expo.out", stagger: { each: 0.075, }, }, "<.25" ); $("[data-anim-load=nav-line]").each(function () { introTl.from( $(this), { scaleX: 0, duration: 1.5, ease: "expo.inOut", }, "<-.5" ); }); $("[data-anim-load=fade]").each(function () { const el = $(this); gsap.from(el, { delay: 1, opacity: 0, xPercent: 17.5, duration: 2, ease: "expo.inOut", }); }); } function initMyLens() { $("[data-section=my-lens]").each(function () { const section = $(this); const headingOne = $("#lens-heading-1"); const headingTwo = $("#lens-heading-2"); const headingThree = $("#lens-heading-3"); const numberOne = $("#lens-number-1"); const numberTwo = $("#lens-number-2"); const numberThree = $("#lens-number-3"); const answersOne = $("[data-lens-answers=1]").children(); const answersTwo = $("[data-lens-answers=2]").children(); const answersThree = $("[data-lens-answers=3]").children(); // let numbersTl = gsap.timeline({ // scrollTrigger: { // trigger: section, // start: "top center", // end: "bottom bottom", // scrub: 0.5, // }, // }); // numbersTl.fromTo( // numberOne, // { // clipPath: "polygon(0% 100%, 100% 100%, 100% 100%, 0% 100%)", // }, // { // clipPath: "polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)", // } // ); // numbersTl.fromTo( // numberTwo, // { // clipPath: "polygon(0% 100%, 100% 100%, 100% 100%, 0% 100%)", // }, // { // clipPath: "polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)", // } // ); // numbersTl.fromTo( // numberThree, // { // clipPath: "polygon(0% 100%, 100% 100%, 100% 100%, 0% 100%)", // }, // { // clipPath: "polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)", // } // ); let tl = gsap.timeline({ scrollTrigger: { trigger: section, start: "top center", end: "bottom bottom", scrub: 0.5, }, }); headingOne.each(function () { const el = $(this); tl.from(el.find(".word"), { yPercent: 110, duration: 1.5, stagger: { each: 0.075 }, ease: "power3.out", }); tl.from( answersOne, { opacity: 0, yPercent: 50, duration: 1, stagger: { each: 0.25, }, ease: "power3.out", }, "<.5" ); tl.fromTo( numberOne, { clipPath: "polygon(0% 100%, 100% 100%, 100% 100%, 0% 100%)", }, { duration: 1.5, clipPath: "polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)", }, ">-.66" ); tl.to( el.find(".word"), { yPercent: -150, duration: 1, stagger: { each: 0.075 }, ease: "power3.in", }, ">-.33" ); tl.to( answersOne, { opacity: 0, yPercent: -50, duration: 1, stagger: { each: 0.25, }, ease: "power3.in", }, "<" ); }); headingTwo.each(function () { const el = $(this); tl.from(el.find(".word"), { yPercent: 110, duration: 1.5, stagger: { each: 0.075 }, ease: "power3.out", }); tl.from( answersTwo, { opacity: 0, yPercent: 50, duration: 1, stagger: { each: 0.25, }, ease: "power3.out", }, "<" ); tl.fromTo( numberTwo, { clipPath: "polygon(0% 100%, 100% 100%, 100% 100%, 0% 100%)", }, { duration: 1.5, clipPath: "polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)", }, ">-.66" ); tl.to( el.find(".word"), { yPercent: -150, duration: 1, stagger: { each: 0.075 }, ease: "power3.in", }, ">-.33" ); tl.to( answersTwo, { opacity: 0, yPercent: -50, duration: 1, stagger: { each: 0.25, }, ease: "power3.in", }, "<" ); }); headingThree.each(function () { const el = $(this); tl.from(el.find(".word"), { yPercent: 110, duration: 1.5, stagger: { each: 0.075 }, ease: "power3.out", }); tl.from( answersThree, { opacity: 0, yPercent: 50, duration: 1, stagger: { each: 0.25, }, ease: "power3.out", }, "<" ); tl.fromTo( numberThree, { clipPath: "polygon(0% 100%, 100% 100%, 100% 100%, 0% 100%)", }, { duration: 1.5, clipPath: "polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)", }, ">-.66" ); }); }); } // Initialize Accordion CSS document.addEventListener("DOMContentLoaded", () => { initGSAPPlugins(); initLenis(); initGlobalParallax(); document.fonts.ready.then(() => { initTextSplit(); initPageLoad(); initStatements(); initScrollReveals(); initMyLens(); }); initNav(); // initHighlightText(); initLottieAnimations(); initReXLab(); initLogoGrid(); initAccordionCSS(); initMarqueeScrollDirection(); });