// ===== Team Slider: Infinite + Smooth Momentum Drag ===== gsap.registerPlugin(Draggable); const teamTrack = document.querySelector(".team-track"); if (teamTrack) { if (!teamTrack.dataset.cloned) { teamTrack.innerHTML += teamTrack.innerHTML; teamTrack.dataset.cloned = "true"; } const totalWidth = teamTrack.scrollWidth / 2; const wrapX = gsap.utils.wrap(-totalWidth, 0); gsap.set(teamTrack, { x: 0 }); const loopTween = gsap.to(teamTrack, { x: -totalWidth, duration: 100, ease: "none", repeat: -1, modifiers: { x: x => `${wrapX(parseFloat(x))}px` } }); const proxy = document.createElement("div"); let currentX = 0; let lastX = 0; let velocity = 0; let momentumTween = null; function getTrackX() { return wrapX(gsap.getProperty(teamTrack, "x")); } function setTrackX(x) { currentX = wrapX(x); gsap.set(teamTrack, { x: currentX }); const progress = Math.abs(currentX / totalWidth); loopTween.progress(progress); } function resumeLoop() { loopTween.play(); gsap.fromTo( loopTween, { timeScale: 0 }, { timeScale: 1, duration: 1, ease: "power3.out" } ); } Draggable.create(proxy, { type: "x", trigger: teamTrack, dragResistance: 0.08, minimumMovement: 12, allowNativeTouchScrolling: true, onPress(e) { this.startPointerX = e.clientX || e.touches?.[0]?.clientX || 0; this.startPointerY = e.clientY || e.touches?.[0]?.clientY || 0; this.isHorizontalDrag = false; if (momentumTween) momentumTween.kill(); currentX = getTrackX(); lastX = currentX; velocity = 0; gsap.set(proxy, { x: currentX }); teamTrack.style.cursor = "grabbing"; }, onDrag(e) { const pointerX = e.clientX || e.touches?.[0]?.clientX || this.pointerX || 0; const pointerY = e.clientY || e.touches?.[0]?.clientY || this.pointerY || 0; const diffX = Math.abs(pointerX - this.startPointerX); const diffY = Math.abs(pointerY - this.startPointerY); if (!this.isHorizontalDrag) { if (diffY > diffX) return; if (diffX > 12 && diffX > diffY) { this.isHorizontalDrag = true; loopTween.pause(); } } if (!this.isHorizontalDrag) return; const x = gsap.getProperty(proxy, "x"); velocity = x - lastX; lastX = x; setTrackX(x); }, onRelease() { teamTrack.style.cursor = "grab"; if (!this.isHorizontalDrag) { resumeLoop(); return; } const startX = gsap.getProperty(proxy, "x"); const throwDistance = velocity * 10; momentumTween = gsap.to(proxy, { x: startX + throwDistance, duration: 0.75, ease: "power2.out", onUpdate() { setTrackX(gsap.getProperty(proxy, "x")); }, onComplete() { resumeLoop(); } }); } }); teamTrack.style.cursor = "grab"; teamTrack.addEventListener("mouseenter", () => { gsap.to(loopTween, { timeScale: 0.2, duration: 0.3, ease: "power3.out" }); }); teamTrack.addEventListener("mouseleave", () => { gsap.to(loopTween, { timeScale: 1, duration: 0.4, ease: "power3.out" }); }); } // ===== Inspiration Timeline Slider ===== document.addEventListener("DOMContentLoaded", function () { if (typeof gsap === "undefined" || typeof Draggable === "undefined") return; const slider = document.querySelector(".inspiration-overlay-slider"); const wrap = document.querySelector(".slider-wrapper"); if (!slider || !wrap) return; const cards = Array.from(slider.children); cards.forEach((card) => { slider.appendChild(card.cloneNode(true)); }); const totalWidth = slider.scrollWidth / 2; const wrapX = gsap.utils.wrap(-totalWidth, 0); gsap.set(slider, { x: 0 }); const tween = gsap.to(slider, { x: -totalWidth, duration: 160, ease: "none", repeat: -1, modifiers: { x: (x) => `${wrapX(parseFloat(x))}px` } }); const proxy = document.createElement("div"); let currentX = 0; let lastX = 0; let velocity = 0; let momentumTween = null; function getSliderX() { return wrapX(gsap.getProperty(slider, "x")); } function setSliderX(x) { currentX = wrapX(x); gsap.set(slider, { x: currentX }); const progress = Math.abs(currentX / totalWidth); tween.progress(progress); } function resumeLoop() { tween.play(); gsap.fromTo( tween, { timeScale: 0 }, { timeScale: 1, duration: 1, ease: "power3.out" } ); } Draggable.create(proxy, { type: "x", trigger: slider, dragResistance: 0.08, minimumMovement: 10, allowNativeTouchScrolling: true, onPress(e) { this.startPointerX = e.clientX || e.touches?.[0]?.clientX || 0; this.startPointerY = e.clientY || e.touches?.[0]?.clientY || 0; this.isHorizontalDrag = false; if (momentumTween) momentumTween.kill(); tween.pause(); currentX = getSliderX(); lastX = currentX; velocity = 0; gsap.set(proxy, { x: currentX }); wrap.classList.add("is-dragging"); }, onDrag(e) { const pointerX = e.clientX || e.touches?.[0]?.clientX || this.pointerX || 0; const pointerY = e.clientY || e.touches?.[0]?.clientY || this.pointerY || 0; const diffX = Math.abs(pointerX - this.startPointerX); const diffY = Math.abs(pointerY - this.startPointerY); if (!this.isHorizontalDrag) { if (diffY > diffX) return; if (diffX > 10 && diffX > diffY) { this.isHorizontalDrag = true; } } if (!this.isHorizontalDrag) return; const x = gsap.getProperty(proxy, "x"); velocity = x - lastX; lastX = x; setSliderX(x); }, onRelease() { wrap.classList.remove("is-dragging"); if (!this.isHorizontalDrag) { resumeLoop(); return; } const startX = gsap.getProperty(proxy, "x"); const throwDistance = velocity * 10; momentumTween = gsap.to(proxy, { x: startX + throwDistance, duration: 0.75, ease: "power2.out", onUpdate() { setSliderX(gsap.getProperty(proxy, "x")); }, onComplete() { resumeLoop(); } }); } }); wrap.addEventListener("mouseenter", () => { gsap.to(tween, { timeScale: 0.2, duration: 0.4, ease: "power3.out" }); }); wrap.addEventListener("mouseleave", () => { gsap.to(tween, { timeScale: 1, duration: 0.5, ease: "power3.out" }); }); }); // ===== Portfolio Slider: Infinite + Smooth Momentum Drag ===== document.addEventListener("DOMContentLoaded", function () { if (typeof gsap === "undefined" || typeof Draggable === "undefined") return; const slider = document.querySelector(".portfolio-slider"); const wrap = document.querySelector(".portfolio-slider-wrap"); if (!slider || !wrap) return; const originalSlides = Array.from(slider.children); originalSlides.forEach((slide) => { slider.appendChild(slide.cloneNode(true)); }); const totalWidth = slider.scrollWidth / 2; const wrapX = gsap.utils.wrap(-totalWidth, 0); gsap.set(slider, { x: 0 }); const loopTween = gsap.to(slider, { x: -totalWidth, duration: 55, ease: "none", repeat: -1, modifiers: { x: (x) => `${wrapX(parseFloat(x))}px` } }); const proxy = document.createElement("div"); let currentX = 0; let lastX = 0; let velocity = 0; let momentumTween = null; function getSliderX() { return wrapX(gsap.getProperty(slider, "x")); } function setSliderX(x) { currentX = wrapX(x); gsap.set(slider, { x: currentX }); const progress = Math.abs(currentX / totalWidth); loopTween.progress(progress); } function resumeLoop() { loopTween.play(); gsap.fromTo( loopTween, { timeScale: 0 }, { timeScale: 1, duration: 1.2, ease: "power3.out" } ); } Draggable.create(proxy, { type: "x", trigger: wrap, dragResistance: 0.08, minimumMovement: 12, allowNativeTouchScrolling: true, onPress(e) { this.startPointerX = e.clientX || e.touches?.[0]?.clientX || 0; this.startPointerY = e.clientY || e.touches?.[0]?.clientY || 0; this.isHorizontalDrag = false; if (momentumTween) momentumTween.kill(); loopTween.pause(); currentX = getSliderX(); lastX = currentX; velocity = 0; gsap.set(proxy, { x: currentX }); }, onDrag(e) { const pointerX = e.clientX || e.touches?.[0]?.clientX || this.pointerX || 0; const pointerY = e.clientY || e.touches?.[0]?.clientY || this.pointerY || 0; const diffX = Math.abs(pointerX - this.startPointerX); const diffY = Math.abs(pointerY - this.startPointerY); if (!this.isHorizontalDrag) { if (diffY > diffX) { return; } if (diffX > 12 && diffX > diffY) { this.isHorizontalDrag = true; wrap.classList.add("is-dragging"); } } if (!this.isHorizontalDrag) return; const x = gsap.getProperty(proxy, "x"); velocity = x - lastX; lastX = x; setSliderX(x); }, onRelease() { wrap.classList.remove("is-dragging"); if (!this.isHorizontalDrag) { resumeLoop(); return; } const startX = gsap.getProperty(proxy, "x"); const throwDistance = velocity * 12; momentumTween = gsap.to(proxy, { x: startX + throwDistance, duration: 0.8, ease: "power2.out", onUpdate() { setSliderX(gsap.getProperty(proxy, "x")); }, onComplete() { resumeLoop(); } }); } }); wrap.addEventListener("mouseenter", () => { gsap.to(loopTween, { timeScale: 0.25, duration: 0.45, ease: "power3.out" }); }); wrap.addEventListener("mouseleave", () => { gsap.to(loopTween, { timeScale: 1, duration: 0.65, ease: "power3.out" }); }); }); // ===== Mobile Services Slow Story Scroll ===== document.addEventListener("DOMContentLoaded", function () { if (typeof gsap === "undefined" || typeof ScrollTrigger === "undefined") return; if (window.innerWidth > 767) return; const wrapper = document.querySelector(".services-story-mobile-wrap"); const section = document.querySelector(".services-word-cloud"); const serviceWords = gsap.utils.toArray(".service-word"); if (!wrapper || !section || !serviceWords.length) return; let preview = document.querySelector(".mobile-service-preview"); if (preview) { document.body.appendChild(preview); } const scrollDistance = serviceWords.length * 180; function setActive(index) { serviceWords.forEach((word, i) => { word.classList.toggle("is-active", i === index); }); const img = serviceWords[index].querySelector("img"); if (img && preview) { preview.src = img.getAttribute("src"); preview.classList.add("is-visible"); } } ScrollTrigger.create({ trigger: wrapper, start: "top 20%", end: "+=" + scrollDistance, pin: section, pinSpacing: true, scrub: true, anticipatePin: 1, invalidateOnRefresh: true, // first activation only when pinned onEnter: () => { setActive(0); }, onEnterBack: () => { setActive(0); }, onUpdate: (self) => { const index = Math.min( serviceWords.length - 1, Math.floor(self.progress * serviceWords.length) ); setActive(index); }, onLeave: () => { if (preview) { preview.classList.remove("is-visible"); } serviceWords.forEach((word) => { word.classList.remove("is-active"); }); }, onLeaveBack: () => { if (preview) { preview.classList.remove("is-visible"); } serviceWords.forEach((word) => { word.classList.remove("is-active"); }); } }); ScrollTrigger.refresh(); }); // ===== Hero Video Scale On Scroll ===== document.addEventListener("DOMContentLoaded", function () { if (typeof gsap === "undefined" || typeof ScrollTrigger === "undefined") return; gsap.fromTo(".hero-video", { width: "70%", height: "75vh" }, { width: "100%", height: "100vh", ease: "none", scrollTrigger: { trigger: ".hero-area", start: "top 130%", end: "top top", scrub: 1 } } ); }); // ===== Awards Cursor Image Trail ===== document.addEventListener("DOMContentLoaded", function () { if (typeof gsap === "undefined") return; const section = document.querySelector(".about-area2"); if (!section) return; const flair = gsap.utils.toArray(".about-area2 .flair"); if (!flair.length) return; let gap = 100; let index = 0; let wrapper = gsap.utils.wrap(0, flair.length); let mousePos = { x: 0, y: 0 }; let lastMousePos = { x: 0, y: 0 }; let isInside = false; let idleTimeout; function playAnimation(shape) { gsap.timeline() .from(shape, { opacity: 0, scale: 0, ease: "elastic.out(1,0.3)", duration: 0.35 }) .to(shape, { rotation: "random([-360,360])" }, "<") .to(shape, { y: section.offsetHeight + 200, opacity: 0, ease: "power2.in", duration: 1.4 }, 0); } function hideAllFlair() { gsap.to(flair, { opacity: 0, duration: 0.25, overwrite: true }); } section.addEventListener("mouseenter", function (e) { isInside = true; const rect = section.getBoundingClientRect(); mousePos = { x: e.clientX - rect.left, y: e.clientY - rect.top }; lastMousePos = { ...mousePos }; }); section.addEventListener("mouseleave", function () { isInside = false; clearTimeout(idleTimeout); hideAllFlair(); }); section.addEventListener("mousemove", function (e) { clearTimeout(idleTimeout); const rect = section.getBoundingClientRect(); mousePos = { x: e.clientX - rect.left, y: e.clientY - rect.top }; idleTimeout = setTimeout(() => { hideAllFlair(); }, 180); }); gsap.ticker.add(function () { if (!isInside) return; let travelDistance = Math.hypot( lastMousePos.x - mousePos.x, lastMousePos.y - mousePos.y ); if (travelDistance > gap) { let wrappedIndex = wrapper(index); let img = flair[wrappedIndex]; gsap.killTweensOf(img); gsap.set(img, { clearProps: "all" }); gsap.set(img, { opacity: 1, left: mousePos.x, top: mousePos.y, xPercent: -50, yPercent: -50 }); playAnimation(img); lastMousePos = { ...mousePos }; index++; } }); }); // ===== Brand Dock Infinite Scroll + Mac Dock Effect ===== const dock = document.querySelector(".brand-dock"); if (dock && typeof gsap !== "undefined") { const originalItems = Array.from(dock.children); for (let i = 0; i < 4; i++) { originalItems.forEach(item => { dock.appendChild(item.cloneNode(true)); }); } const totalWidth = dock.scrollWidth / 5; const wrapX = gsap.utils.wrap(-totalWidth, 0); gsap.set(dock, { x: 0 }); gsap.to(dock, { x: -totalWidth, duration: 39.2, ease: "none", repeat: -1, modifiers: { x: x => `${wrapX(parseFloat(x))}px` } }); const allLogos = dock.querySelectorAll(".brand-dock-img"); dock.addEventListener("mousemove", (event) => { allLogos.forEach((logo) => { const rect = logo.getBoundingClientRect(); const center = rect.left + rect.width / 2; const distance = Math.abs(event.clientX - center); const maxDistance = 260; const minScale = 1; const maxScale = 1.45; const proximity = Math.max(0, 1 - distance / maxDistance); const scale = minScale + proximity * (maxScale - minScale); gsap.to(logo, { scale: scale, duration: 0.32, ease: "power3.out", overwrite: true }); }); }); dock.addEventListener("mouseleave", () => { gsap.to(allLogos, { scale: 1, duration: 0.4, ease: "power3.out", overwrite: true }); }); } // ===== Multiple H2 Word by Word Scroll Reveal ===== document.addEventListener("DOMContentLoaded", function () { if (typeof gsap === "undefined" || typeof ScrollTrigger === "undefined") return; const blocks = document.querySelectorAll( ".together-content h2, .together-content2 h2" ); blocks.forEach((block) => { const words = block.textContent.trim().split(" "); block.innerHTML = words .map(word => `${word} `) .join(""); const spans = block.querySelectorAll(".word-reveal-word"); gsap.to(spans, { color: "#4050FF", stagger: 0.08, ease: "power2.out", scrollTrigger: { trigger: block, start: "top 105%", end: "bottom 45%", scrub: 1.2 } }); }); }); // ===== Page Reveal ===== document.addEventListener("DOMContentLoaded", function () { const reveal = document.querySelector(".page-reveal"); const header = document.querySelector(".header"); if (!reveal || typeof gsap === "undefined") return; const headerHeight = header ? header.offsetHeight : 0; gsap.set(reveal, { top: headerHeight, scaleY: 1, transformOrigin: "top center" }); gsap.to(reveal, { scaleY: 0, duration: 1.5, ease: "expo.inOut", delay: 0.1, onComplete() { reveal.remove(); } }); }); // ===== Global Smooth Scroll / Lenis ===== document.addEventListener("DOMContentLoaded", function () { if (typeof Lenis === "undefined") return; const lenis = new Lenis({ duration: 1.2, smoothWheel: true, smoothTouch: true, touchMultiplier: 1.15, wheelMultiplier: 1, lerp: 0.08 }); function raf(time) { lenis.raf(time); requestAnimationFrame(raf); } requestAnimationFrame(raf); if (typeof ScrollTrigger !== "undefined") { lenis.on("scroll", ScrollTrigger.update); } }); document.addEventListener("DOMContentLoaded", function () { if (typeof gsap === "undefined") return; const awardContainer = document.querySelector(".award-container"); const awardsWrap = document.querySelector(".awards-wrap"); const awards = document.querySelectorAll(".awards-wrap img"); if (!awardContainer || !awardsWrap || !awards.length) return; gsap.set(awardContainer, { perspective: 1400 }); gsap.set(awardsWrap, { transformStyle: "preserve-3d" }); gsap.set(awards, { transformStyle: "preserve-3d" }); const wrapRotateX = gsap.quickTo(awardsWrap, "rotationX", { duration: 0.45, ease: "power2.out" }); const wrapRotateY = gsap.quickTo(awardsWrap, "rotationY", { duration: 0.45, ease: "power2.out" }); const wrapX = gsap.quickTo(awardsWrap, "x", { duration: 0.45, ease: "power2.out" }); const wrapY = gsap.quickTo(awardsWrap, "y", { duration: 0.45, ease: "power2.out" }); awardContainer.addEventListener("pointermove", function (e) { const rect = awardContainer.getBoundingClientRect(); const x = (e.clientX - rect.left) / rect.width; const y = (e.clientY - rect.top) / rect.height; const rotateY = gsap.utils.interpolate(-16, 16, x); const rotateX = gsap.utils.interpolate(12, -12, y); const moveX = gsap.utils.interpolate(-28, 28, x); const moveY = gsap.utils.interpolate(-22, 22, y); wrapRotateX(rotateX); wrapRotateY(rotateY); wrapX(moveX); wrapY(moveY); awards.forEach((award, i) => { const baseRotate = i % 2 === 0 ? 15 : -15; const strengthX = 8 + i * 2.5; const strengthY = 6 + i * 2; const depth = 20 + i * 6; const extraRotate = gsap.utils.interpolate(-4, 4, x); const driftX = gsap.utils.interpolate(-strengthX, strengthX, x); const driftY = gsap.utils.interpolate(-strengthY, strengthY, y); gsap.to(award, { x: driftX, y: driftY, z: depth, rotate: baseRotate + extraRotate, duration: 0.45, ease: "power2.out", overwrite: true }); }); }); awardContainer.addEventListener("pointerleave", function () { wrapRotateX(0); wrapRotateY(0); wrapX(0); wrapY(0); awards.forEach((award, i) => { const baseRotate = i % 2 === 0 ? 15 : -15; gsap.to(award, { x: 0, y: 0, z: 0, rotate: baseRotate, duration: 0.7, ease: "power3.out", overwrite: true }); }); }); }); document.addEventListener("DOMContentLoaded", function () { if (typeof gsap === "undefined" || typeof ScrollTrigger === "undefined") return; gsap.registerPlugin(ScrollTrigger); const awards = document.querySelectorAll(".awards-wrap img"); if (!awards.length) return; gsap.set(awards, { y: -180, z: -120, opacity: 0, rotate: (i) => (i % 2 === 0 ? 18 : -18), filter: "blur(8px)", force3D: true }); gsap.to(awards, { y: 0, z: 0, opacity: 1, rotate: (i) => (i % 2 === 0 ? 15 : -15), filter: "blur(0px)", duration: 1.15, ease: "power3.out", stagger: 0.1, force3D: true, scrollTrigger: { trigger: ".award-container", start: "top 82%", once: true } }); }); document.addEventListener("DOMContentLoaded", function () { const showcaseSlider = document.querySelector(".showcase-slider"); const sliderWrap = document.querySelector(".slider-wrap"); const showcaseItems = document.querySelectorAll(".slider-wrap .showcase-item"); if (!showcaseSlider || !sliderWrap || !showcaseItems.length) return; if (window.innerWidth <= 991) return; gsap.set(showcaseSlider, { perspective: 1200 }); gsap.set(sliderWrap, { transformStyle: "preserve-3d", transformPerspective: 1200 }); gsap.set(showcaseItems, { transformStyle: "preserve-3d" }); const wrapRotateX = gsap.quickTo(sliderWrap, "rotationX", { duration: 0.8, ease: "power3.out" }); const wrapRotateY = gsap.quickTo(sliderWrap, "rotationY", { duration: 0.8, ease: "power3.out" }); const wrapY = gsap.quickTo(sliderWrap, "y", { duration: 0.8, ease: "power3.out" }); function handleMove(e) { const rect = showcaseSlider.getBoundingClientRect(); const x = (e.clientX - rect.left) / rect.width; const y = (e.clientY - rect.top) / rect.height; const rotateY = gsap.utils.interpolate(-8, 8, x); const rotateX = gsap.utils.interpolate(6, -6, y); const moveWrapY = gsap.utils.interpolate(8, -8, y); wrapRotateX(rotateX); wrapRotateY(rotateY); wrapY(moveWrapY); showcaseItems.forEach((item) => { const img = item.querySelector("img"); if (!img) return; const isCenter = item.classList.contains("center"); const strength = isCenter ? 22 : 10; const zDepth = isCenter ? 35 : 0; const scale = isCenter ? 1.03 : 1; const moveX = gsap.utils.interpolate(-strength, strength, x); const moveY = gsap.utils.interpolate(-strength, strength, y); const imgRotate = isCenter ? gsap.utils.interpolate(-1.5, 1.5, x) : gsap.utils.interpolate(-0.6, 0.6, x); gsap.to(item, { z: zDepth, scale: scale, duration: 0.7, ease: "power3.out", overwrite: true }); gsap.to(img, { x: moveX, y: moveY, rotateZ: imgRotate, duration: 0.7, ease: "power3.out", overwrite: true }); }); } function handleLeave() { wrapRotateX(0); wrapRotateY(0); wrapY(0); showcaseItems.forEach((item) => { const img = item.querySelector("img"); if (!img) return; gsap.to(item, { z: 0, scale: 1, duration: 0.9, ease: "power3.out", overwrite: true }); gsap.to(img, { x: 0, y: 0, rotateZ: 0, duration: 0.9, ease: "power3.out", overwrite: true }); }); } showcaseSlider.addEventListener("pointermove", handleMove); showcaseSlider.addEventListener("pointerleave", handleLeave); }); (function ($) { "use strict"; $(document).ready(function () { // ===== Menu Toggle ===== $(".menu-trigger").click(() => $(".slide-menu").addClass("active")); $(".menu-close").click(() => $(".slide-menu").removeClass("active")); // ===== Sticky Header ===== // ===== Hide Header on Scroll Down / Show on Scroll Up ===== let lastScrollTop = 0; $(window).on("scroll", () => { const currentScroll = $(window).scrollTop(); const header = $(".header"); header.toggleClass("sticky", currentScroll >= 100); if (currentScroll > lastScrollTop && currentScroll > 120) { header.addClass("header-hidden"); } else { header.removeClass("header-hidden"); } lastScrollTop = currentScroll <= 0 ? 0 : currentScroll; }); // ===== Infinite Brand Slider ===== const brandTrack = document.querySelector(".slider-track"); if (brandTrack) { brandTrack.innerHTML += brandTrack.innerHTML; const totalBrandWidth = brandTrack.scrollWidth / 2; gsap.to(brandTrack, { x: -totalBrandWidth, duration: 20, ease: "none", repeat: -1 }); } // ===== Owl Carousel Sliders ===== // ===== Inspiration Overlay Slider ===== $('.showcase-gellary').owlCarousel({ loop: true, center: true, margin: 0, nav: false, dots: false, smartSpeed: 850, autoplay: false, autoplayTimeout: 63200, autoplayHoverPause: true, mouseDrag: true, touchDrag: true, pullDrag: true, responsive: { 0: { items: 1.15, stagePadding: 30 }, 768: { items: 2.2, stagePadding: 40 }, 1024: { items: 3, stagePadding: 50, margin: 15 } } }); }); // ===== Portfolio Filter (Multi-Select) ===== const filterButtons = document.querySelectorAll(".portfolio-filter button"); const projectCards = document.querySelectorAll(".project-card"); let activeFilters = new Set(); filterButtons.forEach(btn => { btn.addEventListener("click", () => { const filter = btn.dataset.filter; if (filter === "all") { activeFilters.clear(); filterButtons.forEach(b => b.classList.remove("active")); btn.classList.add("active"); projectCards.forEach(c => c.classList.remove("hide")); return; } activeFilters.has(filter) ? activeFilters.delete(filter) : activeFilters.add(filter); btn.classList.toggle("active"); document.querySelector(".portfolio-filter button[data-filter='all']").classList.remove("active"); projectCards.forEach(card => { const matches = [...activeFilters].some(f => card.classList.contains(f)); card.classList.toggle("hide", activeFilters.size > 0 && !matches); }); }); }); // ===== Portfolio Filter (Multi-Select) ===== // Beyond the Brief Card Infinite Slider Start // ===== Flip Card ===== let currentCard = null; function handleFlip(card) { if (currentCard === card) return card.classList.remove("active"), currentCard = null; if (currentCard) currentCard.classList.remove("active"); card.classList.add("active"); currentCard = card; } // ===== Branding Gallery Hover Effect ===== document.querySelectorAll(".branding-list h2").forEach(item => { const hoverImage = document.querySelector(".hover-image"); const hoverImgTag = hoverImage.querySelector("img"); item.addEventListener("mouseenter", () => { hoverImgTag.src = item.dataset.img; hoverImage.style.opacity = 1; }); item.addEventListener("mouseleave", () => hoverImage.style.opacity = 0); item.addEventListener("mousemove", e => { hoverImage.style.left = e.clientX + "px"; hoverImage.style.top = e.clientY + "px"; }); }); // ===== Text Vertical Slide ===== window.addEventListener("load", () => { document.querySelectorAll(".shkVrtx91A").forEach(container => { const items = container.querySelectorAll(".shk-vrtx-item-91A"); if (!items.length) return; container.appendChild(items[0].cloneNode(true)); const itemHeight = items[0].offsetHeight; const tl = gsap.timeline({ repeat: -1 }); items.forEach((_, i) => { tl.to(container, { y: -itemHeight * (i + 1), duration: 0.5, ease: "power2.inOut" }) .to({}, { duration: 1.2 }); // pause }); }); }); // ===== Scroll-triggered GSAP Animations ===== gsap.registerPlugin(ScrollTrigger, MorphSVGPlugin); // Awards fade in gsap.to(".awards-wrap", { opacity: 1, y: 0, duration: 1, ease: "power3.out", scrollTrigger: { trigger: ".awards-wrap", start: "top 80%", toggleActions: "play none none none" } }); // Showcase Items gsap.utils.toArray(".showcase-item").forEach(item => { gsap.set(item, { opacity: 0, y: 20 }); gsap.to(item, { opacity: 1, y: 0, stagger: 0.12, ease: "power1.out", scrollTrigger: { trigger: ".slider-wrap", start: "top 75%", end: "bottom 25%", toggleActions: "play none none none" } }); }); // Footer Shake Animation const down = 'M0-0.3C0-0.3,464,156,1139,156S2278-0.3,2278-0.3V683H0V-0.3z'; const center = 'M0-0.3C0-0.3,464,0,1139,0s1139-0.3,1139-0.3V683H0V-0.3z'; ScrollTrigger.create({ trigger: '.footer', start: 'top bottom', toggleActions: 'play pause resume reverse', onEnter: self => { const variation = self.getVelocity() / 10000; gsap.fromTo('#bouncy-path', { morphSVG: down }, { duration: 2, morphSVG: center, ease: `elastic.out(${1 + variation}, ${1 - variation})`, overwrite: 'true' }); } }); // ===== Interactive Movement Effects ===== function addPointerEffect(elements, options) { elements.forEach(el => { const rotX = gsap.quickTo(el, "rotationX", options); const rotY = gsap.quickTo(el, "rotationY", options); const moveX = gsap.quickTo(el, "x", options); const moveY = gsap.quickTo(el, "y", options); const scale = gsap.quickTo(el, "scale", options); el.addEventListener("pointermove", e => { const rect = el.getBoundingClientRect(); const x = (e.clientX - rect.left) / rect.width; const y = (e.clientY - rect.top) / rect.height; rotX(gsap.utils.interpolate(options.rotXMin, options.rotXMax, y)); rotY(gsap.utils.interpolate(options.rotYMin, options.rotYMax, x)); moveX(gsap.utils.interpolate(options.moveXMin, options.moveXMax, x)); moveY(gsap.utils.interpolate(options.moveYMin, options.moveYMax, y)); scale(options.scaleValue); }); el.addEventListener("pointerleave", () => { rotX(0); rotY(0); moveX(0); moveY(0); scale(1); }); }); } addPointerEffect(document.querySelectorAll(".showcase-item"), { duration: 0.6, ease: "power4.out", rotXMin: 25, rotXMax: -25, rotYMin: -25, rotYMax: 25, moveXMin: -40, moveXMax: 40, moveYMin: -40, moveYMax: 40, scaleValue: 1.08 }); addPointerEffect(document.querySelectorAll(".awards-wrap img"), { duration: 0.3, ease: "power3.out", rotXMin: 35, rotXMax: -35, rotYMin: -35, rotYMax: 35, moveXMin: -25, moveXMax: 25, moveYMin: -25, moveYMax: 25, scaleValue: 1.12 }); addPointerEffect(document.querySelectorAll(".team-card"), { duration: 0.2, ease: "power3.out", rotXMin: 25, rotXMax: -25, rotYMin: -25, rotYMax: 25, moveXMin: 0, moveXMax: 0, moveYMin: 0, moveYMax: 0, scaleValue: 1.1 }); // ===== Falling Buttons Animation ===== document.querySelectorAll(".ct-falling-btn-wrap a").forEach(btn => { const randomX = gsap.utils.random(-50, 50); const randomRot = gsap.utils.random(-25, 25); const randomDelay = gsap.utils.random(0, 0.5); gsap.fromTo(btn, { y: -200, x: 0, rotation: 0, opacity: 0 }, { y: 0, x: randomX, rotation: randomRot, opacity: 1, duration: 1.2, ease: "power3.out", delay: randomDelay, scrollTrigger: { trigger: ".branding-area", start: "top 85%", toggleActions: "play none none none" } } ); }); })(jQuery); // Text Vertical Slide Effect Start document.addEventListener("DOMContentLoaded", function () { const container = document.getElementById("ctVertical"); const items = container.children; container.appendChild(items[0].cloneNode(true)); const itemHeight = items[0].offsetHeight; const tl = gsap.timeline({ repeat: -1 }); for (let i = 0; i < items.length; i++) { tl.to(container, { y: -itemHeight * i, duration: 0.6, ease: "power2.inOut" }) .to({}, { duration: 1.5 }); // ⏸ pause time } }); // Text Vertical Slide Effect End // Falling buttons on About page gsap.registerPlugin(ScrollTrigger); ScrollTrigger.create({ trigger: ".branding-area", start: "top 99%", once: true, onEnter: () => { const buttons = document.querySelectorAll(".ct-falling-btn-wrap a"); buttons.forEach((btn) => { const randomX = gsap.utils.random(-70, 70); const randomY = gsap.utils.random(0, 20); const randomRot = gsap.utils.random(-15, 15); const randomDelay = gsap.utils.random(0, 0.4); gsap.fromTo( btn, { y: gsap.utils.random(-520, -400), x: 0, rotation: gsap.utils.random(-8, 8), opacity: 0, }, { y: randomY, x: randomX, rotation: randomRot, opacity: 1, duration: gsap.utils.random(1.6, 2.1), ease: "expo.out", delay: randomDelay, overwrite: "auto" } ); }); } });