// ===== Team Slider: True Infinite + Seamless Snap To Card Drag ===== document.addEventListener("DOMContentLoaded", function () { if (typeof gsap === "undefined" || typeof Draggable === "undefined") return; gsap.registerPlugin(Draggable); const teamTrack = document.querySelector(".team-track"); if (!teamTrack || teamTrack.dataset.teamSliderInit === "true") return; teamTrack.dataset.teamSliderInit = "true"; const originalItems = Array.from(teamTrack.children); if (!originalItems.length) return; originalItems.forEach((item) => { item.dataset.teamOriginal = "true"; }); originalItems.forEach((item) => { const clone = item.cloneNode(true); clone.removeAttribute("data-team-original"); teamTrack.appendChild(clone); }); const proxy = document.createElement("div"); let originalWidth = 0; let wrapX; let rawX = 0; let lastX = 0; let velocity = 0; let autoSpeed = -0.28; let targetSpeed = -0.28; let isDragging = false; let momentumTween = null; function calculateOriginalWidth() { const originals = teamTrack.querySelectorAll("[data-team-original='true']"); const styles = window.getComputedStyle(teamTrack); const gap = parseFloat(styles.columnGap || styles.gap || 0); originalWidth = 0; originals.forEach((item, index) => { originalWidth += item.offsetWidth; if (index < originals.length - 1) { originalWidth += gap; } }); wrapX = gsap.utils.wrap(-originalWidth, 0); } function setTrackX(x) { rawX = x; gsap.set(teamTrack, { x: wrapX(rawX), force3D: true }); } function getCardPositionsNearCurrent() { const cards = Array.from(teamTrack.querySelectorAll(".team-card")); const positions = []; cards.forEach((card) => { const cardX = -card.offsetLeft; const loopsAround = Math.round((rawX - cardX) / originalWidth); positions.push(cardX + loopsAround * originalWidth); positions.push(cardX + (loopsAround - 1) * originalWidth); positions.push(cardX + (loopsAround + 1) * originalWidth); }); return [...new Set(positions.map((x) => Math.round(x)))] .sort((a, b) => b - a); } function getClosestCardRawX() { const positions = getCardPositionsNearCurrent(); let closestX = rawX; let closestDistance = Infinity; positions.forEach((candidate) => { const distance = Math.abs(rawX - candidate); if (distance < closestDistance) { closestDistance = distance; closestX = candidate; } }); return closestX; } function getNextCardRawX(direction) { const positions = getCardPositionsNearCurrent(); const currentClosest = getClosestCardRawX(); let currentIndex = positions.findIndex((x) => { return Math.abs(x - currentClosest) < 2; }); if (currentIndex === -1) { currentIndex = positions.findIndex((x) => { return direction < 0 ? x < rawX : x > rawX; }); } if (direction < 0) { return positions[currentIndex + 1] ?? currentClosest - 300; } return positions[currentIndex - 1] ?? currentClosest + 300; } calculateOriginalWidth(); gsap.set(proxy, { x: 0 }); setTrackX(0); gsap.ticker.add(function () { if (isDragging || !wrapX) return; autoSpeed += (targetSpeed - autoSpeed) * 0.06; setTrackX(rawX + autoSpeed); gsap.set(proxy, { x: rawX }); }); Draggable.create(proxy, { type: "x", trigger: teamTrack, dragResistance: 0, minimumMovement: 1, allowNativeTouchScrolling: true, onPress(e) { const pointer = e.touches ? e.touches[0] : e; this.startPointerX = pointer.clientX || 0; this.startPointerY = pointer.clientY || 0; this.startRawX = rawX; this.isHorizontalDrag = false; if (momentumTween) momentumTween.kill(); isDragging = true; gsap.set(proxy, { x: rawX }); lastX = rawX; velocity = 0; teamTrack.style.cursor = "grabbing"; }, onDrag(e) { const pointer = e.touches ? e.touches[0] : e; const pointerX = pointer.clientX || this.pointerX || 0; const pointerY = pointer.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 > 1 && diffX > diffY) { this.isHorizontalDrag = true; } } 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) { isDragging = false; return; } const dragAmount = rawX - this.startRawX; const threshold = 5; let targetX = getClosestCardRawX(); if (Math.abs(dragAmount) > threshold) { targetX = getNextCardRawX(dragAmount); } momentumTween = gsap.to(proxy, { x: targetX, duration: 0.65, ease: "power3.out", onUpdate() { setTrackX(gsap.getProperty(proxy, "x")); }, onComplete() { setTrackX(targetX); gsap.set(proxy, { x: rawX }); isDragging = false; } }); } }); teamTrack.style.cursor = "grab"; teamTrack.addEventListener("mouseenter", function () { targetSpeed = -0.08; }); teamTrack.addEventListener("mouseleave", function () { targetSpeed = -0.28; }); window.addEventListener("resize", function () { calculateOriginalWidth(); setTrackX(rawX); }); }); // ===== Inspiration Overlay Slider: Infinite + Smooth Drag + Flip Cards ===== document.addEventListener("DOMContentLoaded", function () { if (typeof gsap === "undefined" || typeof Draggable === "undefined") return; gsap.registerPlugin(Draggable); const slider = document.querySelector(".inspiration-overlay-slider"); const wrap = document.querySelector(".slider-wrapper"); if (!slider || !wrap || slider.dataset.inspirationInit === "true") return; slider.dataset.inspirationInit = "true"; const originalCards = Array.from(slider.children); if (!originalCards.length) return; originalCards.forEach((card) => { slider.appendChild(card.cloneNode(true)); }); const totalWidth = slider.scrollWidth / 2; const wrapX = gsap.utils.wrap(-totalWidth, 0); const proxy = document.createElement("div"); let currentX = 0; let velocity = -0.28; let dragVelocity = 0; let isDragging = false; let isHovering = false; let lastProxyX = 0; let momentumTween = null; let tapStartX = 0; let tapStartY = 0; let tapTarget = null; let didMove = false; function setSliderX(x) { currentX = wrapX(x); gsap.set(slider, { x: currentX }); } gsap.ticker.add(function () { if (isDragging) return; const targetSpeed = isHovering ? -0.06 : -0.28; velocity += (targetSpeed - velocity) * 0.06; setSliderX(currentX + velocity); }); Draggable.create(proxy, { type: "x", trigger: wrap, dragResistance: 0.08, minimumMovement: 10, allowNativeTouchScrolling: true, onPress(e) { const pointer = e.touches ? e.touches[0] : e; this.startPointerX = pointer.clientX || 0; this.startPointerY = pointer.clientY || 0; this.isHorizontalDrag = false; if (momentumTween) { momentumTween.kill(); momentumTween = null; } isDragging = true; dragVelocity = 0; gsap.set(proxy, { x: currentX }); lastProxyX = currentX; this.update(); wrap.classList.add("is-dragging"); }, onDrag(e) { const pointer = e.touches ? e.touches[0] : e; const pointerX = pointer.clientX || 0; const pointerY = pointer.clientY || 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; didMove = true; } } if (!this.isHorizontalDrag) return; const x = gsap.getProperty(proxy, "x"); dragVelocity = x - lastProxyX; lastProxyX = x; setSliderX(x); }, onRelease() { wrap.classList.remove("is-dragging"); isDragging = false; if (!this.isHorizontalDrag) return; const startX = currentX; const throwDistance = dragVelocity * 14; momentumTween = gsap.to( { x: startX }, { x: startX + throwDistance, duration: 0.85, ease: "power3.out", onUpdate() { setSliderX(this.targets()[0].x); }, onComplete() { momentumTween = null; } } ); } }); function startTap(e) { const pointer = e.touches ? e.touches[0] : e; const card = e.target.closest(".flip-card"); if (!card) return; tapTarget = card; tapStartX = pointer.clientX; tapStartY = pointer.clientY; didMove = false; } function endTap(e) { if (!tapTarget) return; const pointer = e.changedTouches ? e.changedTouches[0] : e; const moveX = Math.abs(pointer.clientX - tapStartX); const moveY = Math.abs(pointer.clientY - tapStartY); if (moveX <= 8 && moveY <= 8 && !didMove) { tapTarget.classList.toggle("active"); } tapTarget = null; } slider.addEventListener("mousedown", startTap, true); slider.addEventListener("mouseup", endTap, true); slider.addEventListener("touchstart", startTap, { passive: true, capture: true }); slider.addEventListener("touchend", endTap, { passive: true, capture: true }); wrap.addEventListener("mouseenter", function () { isHovering = true; }); wrap.addEventListener("mouseleave", function () { isHovering = false; }); }); // ===== Brand Dock True Infinite Scroll + Mac Dock Effect + Drag ===== document.addEventListener("DOMContentLoaded", function () { if (typeof gsap === "undefined") return; const dock = document.querySelector(".brand-dock"); if (!dock || dock.dataset.brandDockInit === "true") return; dock.dataset.brandDockInit = "true"; const originalItems = Array.from(dock.children); if (!originalItems.length) return; originalItems.forEach((item) => { item.dataset.brandOriginal = "true"; }); originalItems.forEach((item) => { const clone = item.cloneNode(true); clone.removeAttribute("data-brand-original"); dock.appendChild(clone); }); let originalWidth = 0; let wrapX; let rawX = 0; let isDragging = false; let startX = 0; let dragStartX = 0; let autoSpeed = -0.45; let targetSpeed = -0.45; const isMobile = window.innerWidth <= 767; const maxScale = isMobile ? 1.1 : 1.25; const maxDistance = isMobile ? 120 : 260; function calculateOriginalWidth() { const originals = dock.querySelectorAll("[data-brand-original='true']"); const styles = window.getComputedStyle(dock); const gap = parseFloat(styles.columnGap || styles.gap || 0); originalWidth = 0; originals.forEach((item, index) => { originalWidth += item.offsetWidth; if (index < originals.length - 1) { originalWidth += gap; } }); wrapX = gsap.utils.wrap(-originalWidth, 0); } function setDockX(x) { if (!wrapX) return; rawX = x; gsap.set(dock, { x: wrapX(rawX), force3D: true }); } function getAllItems() { return dock.querySelectorAll(".brand-dock-item"); } calculateOriginalWidth(); setDockX(0); gsap.ticker.add(function () { if (isDragging || !wrapX) return; autoSpeed += (targetSpeed - autoSpeed) * 0.06; setDockX(rawX + autoSpeed); }); dock.addEventListener("mousemove", function (event) { if (isDragging || !wrapX) return; getAllItems().forEach((item) => { const rect = item.getBoundingClientRect(); const center = rect.left + rect.width / 2; const distance = Math.abs(event.clientX - center); const proximity = Math.max(0, 1 - distance / maxDistance); const scale = 1 + proximity * (maxScale - 1); gsap.to(item, { scale: scale, duration: 0.25, ease: "power3.out", overwrite: true }); }); }); dock.addEventListener("mouseenter", function () { targetSpeed = -0.12; }); dock.addEventListener("mouseleave", function () { targetSpeed = -0.45; gsap.to(getAllItems(), { scale: 1, duration: 0.35, ease: "power3.out", overwrite: true }); }); function startDrag(clientX) { if (!wrapX) return; isDragging = true; startX = clientX; dragStartX = rawX; gsap.to(getAllItems(), { scale: 1, duration: 0.2, overwrite: true }); } function moveDrag(clientX) { if (!isDragging || !wrapX) return; const delta = clientX - startX; setDockX(dragStartX + delta); } function endDrag() { isDragging = false; } dock.addEventListener("mousedown", function (e) { e.preventDefault(); startDrag(e.clientX); }); window.addEventListener("mousemove", function (e) { moveDrag(e.clientX); }); window.addEventListener("mouseup", endDrag); dock.addEventListener("touchstart", function (e) { startDrag(e.touches[0].clientX); }, { passive: true }); dock.addEventListener("touchmove", function (e) { moveDrag(e.touches[0].clientX); }, { passive: true }); dock.addEventListener("touchend", endDrag); dock.addEventListener("touchcancel", endDrag); window.addEventListener("resize", function () { calculateOriginalWidth(); setDockX(rawX); }); }); // ===== Bunny Stream Video ===== document.addEventListener("DOMContentLoaded", function () { const video = document.querySelector(".bunny-stream-video"); if (!video) return; const streamUrl = "TUKAJ_TVOJ_PLAYLIST.m3u8"; if (video.canPlayType("application/vnd.apple.mpegurl")) { video.src = streamUrl; } else if (Hls.isSupported()) { const hls = new Hls({ autoStartLoad: true }); hls.loadSource(streamUrl); hls.attachMedia(video); } }); // ===== Black Hero Rotating Word Wave Animation ===== document.addEventListener("DOMContentLoaded", function () { if (typeof gsap === "undefined") return; const el = document.querySelector(".hero-rotating-word-black"); if (!el) return; const words = el.dataset.words .split(",") .map(word => word.trim()) .filter(Boolean); let currentWord = 0; function buildWord(word) { return word .split("") .map(char => { const safeChar = char === " " ? " " : char; return `${safeChar}`; }) .join(""); } function animateWord() { el.innerHTML = buildWord(words[currentWord]); const chars = el.querySelectorAll(".black-char"); gsap.set(chars, { yPercent: () => gsap.utils.random(120, 165), xPercent: () => gsap.utils.random(-8, 8), rotateZ: () => gsap.utils.random(-7, 7), scaleY: () => gsap.utils.random(0.88, 1.08) }); const tl = gsap.timeline({ onComplete() { currentWord++; if (currentWord >= words.length) { currentWord = 0; } animateWord(); } }); // IN tl.to(chars, { yPercent: 0, xPercent: 0, rotateZ: 0, scaleY: 1, duration: () => gsap.utils.random(0.46, 0.68), ease: "expo.out", stagger: { each: 0.010, from: "start" } }); // HOLD tl.to({}, { duration: 0.85 }); // OUT tl.to(chars, { yPercent: () => gsap.utils.random(-120, -165), xPercent: () => gsap.utils.random(-6, 6), rotateZ: () => gsap.utils.random(-7, 7), scaleY: () => gsap.utils.random(0.9, 1.08), duration: () => gsap.utils.random(0.42, 0.62), ease: "expo.in", stagger: { each: 0.010, from: "start" } }); } animateWord(); }); // ===== Pulse Services Stable Preview - DESKTOP ONLY ===== // No pin, no scrub. Preloaded videos stay alive and do not restart. document.addEventListener("DOMContentLoaded", function () { if (window.innerWidth <= 767) return; const wrapper = document.querySelector(".pulse-services-section"); const serviceWords = Array.from(document.querySelectorAll(".pulse-service-word")); const preview = document.querySelector(".pulse-preview-img"); if (!wrapper || !serviceWords.length || !preview) return; document.body.appendChild(preview); let activeIndex = -1; let activeHref = null; let ticking = false; const preloadedVideos = {}; serviceWords.forEach((word) => { if (word.dataset.previewType === "video" && word.dataset.previewSrc) { const src = word.dataset.previewSrc; const iframe = document.createElement("iframe"); iframe.src = src; iframe.loading = "eager"; iframe.allow = "accelerometer;gyroscope;autoplay;encrypted-media;picture-in-picture;"; iframe.allowFullscreen = true; iframe.tabIndex = -1; iframe.dataset.videoSrc = src; iframe.style.opacity = "0"; iframe.style.pointerEvents = "none"; preview.appendChild(iframe); preloadedVideos[src] = iframe; } }); function hideVideos() { Object.values(preloadedVideos).forEach((iframe) => { iframe.style.opacity = "0"; }); } function removeRenderedImages() { preview.querySelectorAll(".pulse-rendered-image").forEach((img) => { img.remove(); }); } function clearActive() { preview.classList.remove("is-visible", "is-video-preview"); hideVideos(); removeRenderedImages(); activeIndex = -1; activeHref = null; serviceWords.forEach((word) => { word.classList.remove("is-active"); }); } function renderPreview(activeItem) { const previewType = activeItem.dataset.previewType || "image"; const previewSrc = activeItem.dataset.previewSrc || ""; const img = activeItem.querySelector("img"); const imageSrc = img ? img.getAttribute("src") : ""; hideVideos(); removeRenderedImages(); if (previewType === "video" && previewSrc && preloadedVideos[previewSrc]) { preview.classList.add("is-video-preview"); preloadedVideos[previewSrc].style.opacity = "1"; return; } preview.classList.remove("is-video-preview"); if (imageSrc) { const image = document.createElement("img"); image.className = "pulse-rendered-image"; image.src = imageSrc; image.alt = ""; preview.appendChild(image); } } function setActive(index) { if (index === activeIndex) return; activeIndex = index; serviceWords.forEach((word, i) => { word.classList.toggle("is-active", i === index); }); const activeItem = serviceWords[index]; renderPreview(activeItem); activeHref = activeItem.dataset.url || null; preview.classList.add("is-visible"); } function updateActiveWord() { ticking = false; const wrapperRect = wrapper.getBoundingClientRect(); if ( wrapperRect.bottom < window.innerHeight * 0.2 || wrapperRect.top > window.innerHeight * 0.65 ) { clearActive(); return; } const centerY = window.innerHeight * 0.38; let closestIndex = 0; let closestDistance = Infinity; serviceWords.forEach((word, index) => { const rect = word.getBoundingClientRect(); const wordCenter = rect.top + rect.height / 2; const distance = Math.abs(centerY - wordCenter); if (distance < closestDistance) { closestDistance = distance; closestIndex = index; } }); setActive(closestIndex); } function requestUpdate() { if (ticking) return; ticking = true; requestAnimationFrame(updateActiveWord); } window.addEventListener("scroll", requestUpdate, { passive: true }); window.addEventListener("resize", requestUpdate); document.addEventListener("visibilitychange", function () { if (document.hidden) { clearActive(); } else { requestUpdate(); } }); window.addEventListener("blur", clearActive); preview.addEventListener("click", function () { if (activeHref) { window.location.href = activeHref; } }); serviceWords.forEach((word) => { word.addEventListener("click", function () { const url = word.dataset.url; if (url) { window.location.href = url; } }); }); requestUpdate(); }); // ===== Mobile Services Slow Story Scroll ===== // Supports image + preloaded Bunny video previews. // Video starts once on page load and NEVER resets. // We only fade it in/out with opacity. 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"); const preview = document.querySelector(".mobile-service-preview"); if (!wrapper || !section || !serviceWords.length || !preview) return; document.body.appendChild(preview); const scrollDistance = serviceWords.length * 400; let activePreviewKey = null; const preloadedVideos = {}; // ===== PRELOAD + AUTOPLAY VIDEO ON PAGE LOAD ===== serviceWords.forEach((word) => { if ( word.dataset.previewType === "video" && word.dataset.previewSrc ) { const src = word.dataset.previewSrc; const iframe = document.createElement("iframe"); iframe.src = src; iframe.loading = "eager"; iframe.allow = "accelerometer;gyroscope;autoplay;encrypted-media;picture-in-picture;"; iframe.allowFullscreen = true; iframe.setAttribute("tabindex", "-1"); iframe.dataset.videoSrc = src; iframe.style.position = "absolute"; iframe.style.top = "50%"; iframe.style.left = "50%"; iframe.style.width = "185%"; iframe.style.height = "185%"; iframe.style.minWidth = "100%"; iframe.style.minHeight = "100%"; iframe.style.transform = "translate(-50%, -50%)"; iframe.style.border = "0"; iframe.style.opacity = "0"; iframe.style.pointerEvents = "none"; preview.appendChild(iframe); preloadedVideos[src] = iframe; } }); function isWrapperVisible() { const rect = wrapper.getBoundingClientRect(); return ( rect.bottom > 0 && rect.top < window.innerHeight ); } function hideVideos() { Object.values(preloadedVideos) .forEach((iframe) => { iframe.style.opacity = "0"; }); } function removeImages() { preview .querySelectorAll( ".mobile-preview-rendered-img" ) .forEach((img) => { img.remove(); }); } function renderPreview(activeItem) { const previewType = activeItem.dataset.previewType || "image"; const previewSrc = activeItem.dataset.previewSrc || ""; const img = activeItem.querySelector("img"); const imageSrc = img ? img.getAttribute("src") : ""; const previewKey = `${previewType}:${previewSrc}:${imageSrc}`; if ( activePreviewKey === previewKey ) return; activePreviewKey = previewKey; removeImages(); hideVideos(); if ( previewType === "video" && previewSrc && preloadedVideos[previewSrc] ) { preloadedVideos[ previewSrc ].style.opacity = "1"; preview.classList.add( "is-video-preview" ); return; } preview.classList.remove( "is-video-preview" ); if (imageSrc) { const image = document.createElement( "img" ); image.className = "mobile-preview-rendered-img"; image.src = imageSrc; image.alt = ""; preview.appendChild( image ); } } function clearActive() { preview.classList.remove( "is-visible", "is-video-preview" ); activePreviewKey = null; removeImages(); // IMPORTANT: // videos stay alive // only opacity changes hideVideos(); serviceWords .forEach((word) => { word.classList.remove( "is-active" ); }); } function setActive(index) { if ( !isWrapperVisible() ) return; serviceWords .forEach( (word, i) => { word.classList.toggle( "is-active", i === index ); } ); renderPreview( serviceWords[index] ); preview.classList.add( "is-visible" ); } const trigger = ScrollTrigger.create({ trigger: wrapper, start: "top 20%", end: "+=" + scrollDistance, pin: section, pinSpacing: true, scrub: true, anticipatePin: 1, invalidateOnRefresh: true, onEnter: () => { if ( isWrapperVisible() ) { setActive(0); } }, onEnterBack: () => { if ( isWrapperVisible() ) { setActive(0); } }, onUpdate: (self) => { if ( !isWrapperVisible() ) { clearActive(); return; } const index = Math.min( serviceWords.length - 1, Math.floor( self.progress * serviceWords.length ) ); setActive( index ); }, onRefresh: () => { if ( !isWrapperVisible() ) { clearActive(); } }, onLeave: clearActive, onLeaveBack: clearActive }); requestAnimationFrame( () => { if ( !isWrapperVisible() || !trigger.isActive ) { clearActive(); } } ); setTimeout( () => { ScrollTrigger.refresh( true ); if ( !isWrapperVisible() || !trigger.isActive ) { clearActive(); } }, 400 ); }); // ===== Pink Hero Rotating Word Wave Animation ===== document.addEventListener("DOMContentLoaded", function () { if (typeof gsap === "undefined") return; const el = document.querySelector(".hero-rotating-word-pink"); if (!el) return; const words = el.dataset.words .split(",") .map(word => word.trim()) .filter(Boolean); let currentWord = 0; function buildWord(word) { return word .split("") .map(char => { const safeChar = char === " " ? " " : char; return `${safeChar}`; }) .join(""); } function animateWord() { el.innerHTML = buildWord(words[currentWord]); const chars = el.querySelectorAll(".pink-char"); gsap.set(chars, { yPercent: () => gsap.utils.random(120, 165), xPercent: () => gsap.utils.random(-8, 8), rotateZ: () => gsap.utils.random(-7, 7), scaleY: () => gsap.utils.random(0.88, 1.08) }); const tl = gsap.timeline({ onComplete() { currentWord++; if (currentWord >= words.length) { currentWord = 0; } animateWord(); } }); tl.to(chars, { yPercent: 0, xPercent: 0, rotateZ: 0, scaleY: 1, duration: () => gsap.utils.random(0.46, 0.68), ease: "expo.out", stagger: { each: 0.010, from: "start" } }); tl.to({}, { duration: 0.85 }); tl.to(chars, { yPercent: () => gsap.utils.random(-120, -165), xPercent: () => gsap.utils.random(-6, 6), rotateZ: () => gsap.utils.random(-7, 7), scaleY: () => gsap.utils.random(0.9, 1.08), duration: () => gsap.utils.random(0.42, 0.62), ease: "expo.in", stagger: { each: 0.010, from: "start" } }); } animateWord(); }); // ===== Creative Area Rotating Word Wave Animation ===== // Static text + rotating animated phrase next to it. document.addEventListener("DOMContentLoaded", function () { if (typeof gsap === "undefined") return; const el = document.querySelector(".ct-rotating-word"); if (!el) return; const words = el.dataset.words .split("|") .map(word => word.trim()) .filter(Boolean); let currentWord = 0; function buildWord(word) { return word .split("") .map(char => { const safeChar = char === " " ? " " : char; return `${safeChar}`; }) .join(""); } function animateWord() { const word = words[currentWord]; el.innerHTML = buildWord(word); const chars = el.querySelectorAll(".ct-char"); gsap.set(chars, { yPercent: () => gsap.utils.random(120, 165), xPercent: () => gsap.utils.random(-8, 8), rotateZ: () => gsap.utils.random(-7, 7), scaleY: () => gsap.utils.random(0.88, 1.08) }); const tl = gsap.timeline({ onComplete() { currentWord = (currentWord + 1) % words.length; animateWord(); } }); tl.to(chars, { yPercent: 0, xPercent: 0, rotateZ: 0, scaleY: 1, duration: () => gsap.utils.random(0.46, 0.68), ease: "expo.out", stagger: { each: 0.010, from: "start" } }); tl.to({}, { duration: 0.85 }); tl.to(chars, { yPercent: () => gsap.utils.random(-120, -165), xPercent: () => gsap.utils.random(-6, 6), rotateZ: () => gsap.utils.random(-7, 7), scaleY: () => gsap.utils.random(0.9, 1.08), duration: () => gsap.utils.random(0.42, 0.62), ease: "expo.in", stagger: { each: 0.010, from: "start" } }); } animateWord(); }); // ===== Hero Rotating Word Wave Animation ===== // Rotating words with per-letter wave animation. // More flowy character movement, slower reveal, clear left-to-right wave. document.addEventListener("DOMContentLoaded", function () { if (typeof gsap === "undefined") return; const el = document.querySelector(".hero-rotating-word"); if (!el) return; const words = el.dataset.words .split(",") .map(word => word.trim()) .filter(Boolean); let currentWord = 0; function buildWord(word) { return word .split("") .map(char => { const safeChar = char === " " ? " " : char; return `${safeChar}`; }) .join(""); } function animateWord() { const word = words[currentWord]; el.innerHTML = buildWord(word); const chars = el.querySelectorAll(".hero-char"); gsap.set(chars, { yPercent: () => gsap.utils.random(120, 165), xPercent: () => gsap.utils.random(-8, 8), rotateZ: () => gsap.utils.random(-7, 7), scaleY: () => gsap.utils.random(0.88, 1.08) }); const tl = gsap.timeline({ onComplete() { currentWord = (currentWord + 1) % words.length; animateWord(); } }); // IN animation tl.to(chars, { yPercent: 0, xPercent: 0, rotateZ: 0, scaleY: 1, duration: () => gsap.utils.random(0.46, 0.68), ease: "expo.out", stagger: { each: 0.010, from: "start" } }); // Hold tl.to({}, { duration: 0.85 }); // OUT animation tl.to(chars, { yPercent: () => gsap.utils.random(-120, -165), xPercent: () => gsap.utils.random(-6, 6), rotateZ: () => gsap.utils.random(-7, 7), scaleY: () => gsap.utils.random(0.9, 1.08), duration: () => gsap.utils.random(0.42, 0.62), ease: "expo.in", stagger: { each: 0.010, from: "start" } }); } animateWord(); }); // ===== Portfolio Slider: Infinite + Seamless Snap To Card 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 || slider.dataset.snapSliderInit === "true") return; slider.dataset.snapSliderInit = "true"; const originalSlides = Array.from(slider.children); if (!originalSlides.length) return; originalSlides.forEach((slide) => { slider.appendChild(slide.cloneNode(true)); }); const totalWidth = slider.scrollWidth / 2; const wrapX = gsap.utils.wrap(-totalWidth, 0); const proxy = document.createElement("div"); let rawX = 0; let lastX = 0; let velocity = 0; let momentumTween = null; let autoTween = null; function setSliderX(x) { rawX = x; gsap.set(slider, { x: wrapX(rawX), force3D: true }); } function startAutoLoop() { if (autoTween) autoTween.kill(); const pixelsPerSecond = 20; const duration = totalWidth / pixelsPerSecond; autoTween = gsap.to(proxy, { x: rawX - totalWidth, duration: duration, ease: "none", repeat: -1, onUpdate() { setSliderX(gsap.getProperty(proxy, "x")); } }); } function pauseAutoLoop() { if (autoTween) autoTween.pause(); } function resumeAutoLoop() { if (!autoTween) { startAutoLoop(); return; } autoTween.play(); gsap.to(autoTween, { timeScale: 1, duration: 1.2, ease: "power3.out" }); } function getSlidePositionsNearCurrent() { const slides = Array.from(slider.querySelectorAll(".portfolio-slide")); const positions = []; slides.forEach((slide) => { const slideX = -slide.offsetLeft; const loopsAround = Math.round((rawX - slideX) / totalWidth); positions.push(slideX + loopsAround * totalWidth); positions.push(slideX + (loopsAround - 1) * totalWidth); positions.push(slideX + (loopsAround + 1) * totalWidth); }); return [...new Set(positions.map((x) => Math.round(x)))] .sort((a, b) => b - a); } function getClosestSlideRawX() { const positions = getSlidePositionsNearCurrent(); let closestX = rawX; let closestDistance = Infinity; positions.forEach((candidate) => { const distance = Math.abs(rawX - candidate); if (distance < closestDistance) { closestDistance = distance; closestX = candidate; } }); return closestX; } function getNextSlideRawX(direction) { const positions = getSlidePositionsNearCurrent(); const currentClosest = getClosestSlideRawX(); let currentIndex = positions.findIndex((x) => { return Math.abs(x - currentClosest) < 2; }); if (currentIndex === -1) { currentIndex = positions.findIndex((x) => { return direction < 0 ? x < rawX : x > rawX; }); } if (direction < 0) { return positions[currentIndex + 1] ?? currentClosest - 300; } return positions[currentIndex - 1] ?? currentClosest + 300; } gsap.set(proxy, { x: 0 }); setSliderX(0); startAutoLoop(); Draggable.create(proxy, { type: "x", trigger: wrap, dragResistance: 0, minimumMovement: 1, allowNativeTouchScrolling: true, onPress(e) { this.startPointerX = e.clientX || e.touches?.[0]?.clientX || 0; this.startPointerY = e.clientY || e.touches?.[0]?.clientY || 0; this.startRawX = rawX; this.isHorizontalDrag = false; if (momentumTween) momentumTween.kill(); pauseAutoLoop(); gsap.set(proxy, { x: rawX }); lastX = rawX; velocity = 0; }, 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 > 1 && 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) { resumeAutoLoop(); return; } const dragAmount = rawX - this.startRawX; const threshold = 5; let targetX = getClosestSlideRawX(); if (Math.abs(dragAmount) > threshold) { targetX = getNextSlideRawX(dragAmount); } momentumTween = gsap.to(proxy, { x: targetX, duration: 0.65, ease: "power3.out", onUpdate() { setSliderX(gsap.getProperty(proxy, "x")); }, onComplete() { setSliderX(targetX); gsap.set(proxy, { x: rawX }); resumeAutoLoop(); } }); } }); wrap.addEventListener("mouseenter", () => { if (!autoTween) return; gsap.to(autoTween, { timeScale: 0.25, duration: 0.45, ease: "power3.out" }); }); wrap.addEventListener("mouseleave", () => { if (!autoTween) return; gsap.to(autoTween, { timeScale: 1, duration: 0.65, ease: "power3.out" }); }); }); // ===== 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() .fromTo( shape, { opacity: 1, scale: 0 }, { opacity: 1, scale: 1, ease: "elastic.out(1,0.3)", duration: 0.45 } ) .to(shape, { rotation: "random([-360,360])" }, "<") .to(shape, { y: section.offsetHeight + 200, opacity: 0, ease: "power2.in", duration: 2.1 }, 0.45); } 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(); }, 3050); }); 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++; } }); }); /// ===== Global Smooth Scroll / Lenis - iframe safe ===== 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, prevent: function (node) { return node.closest && node.closest("iframe"); } }); 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; let floatingShown = false; $(window).on("scroll", () => { const currentScroll = $(window).scrollTop(); const header = $(".header"); header.toggleClass("sticky", currentScroll >= 100); if (currentScroll > lastScrollTop && currentScroll > 120) { header.addClass("header-hidden"); if (!floatingShown) { $(".lets-talk-btn").addClass("is-visible"); $(".language-action").addClass("is-visible"); floatingShown = true; } } else { header.removeClass("header-hidden"); } // hide floating buttons again at top if (currentScroll <= 40) { $(".lets-talk-btn").removeClass("is-visible"); $(".language-action").removeClass("is-visible"); floatingShown = false; } 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 const awardsWrap = document.querySelector(".awards-wrap"); if (awardsWrap) { gsap.to(awardsWrap, { opacity: 1, y: 0, duration: 1, ease: "power3.out", scrollTrigger: { trigger: awardsWrap, 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" } ); }); } }); // ===== Separate H2 Word by Word Scroll Reveal ===== document.addEventListener("DOMContentLoaded", function () { if (typeof gsap === "undefined" || typeof ScrollTrigger === "undefined") return; function wordReveal(selector, options = {}) { const blocks = document.querySelectorAll(selector); blocks.forEach((block) => { // prevent double init if (!block.dataset.wordRevealInit) { const words = block.textContent.trim().split(" "); block.innerHTML = words .map(word => `${word} `) .join(""); block.dataset.wordRevealInit = "true"; } const spans = block.querySelectorAll(".word-reveal-word"); gsap.set(spans, { color: options.fromColor || "#F5F5F5" }); gsap.to(spans, { color: options.toColor || "#4050FF", stagger: options.stagger || 0.08, ease: "none", scrollTrigger: { trigger: block, start: options.start || "top 100%", end: options.end || "bottom 45%", scrub: options.scrub || 1, invalidateOnRefresh: true } }); }); } // ===== PRVI + TRETJI BLOCK ===== // začne normalno wordReveal( ".together-content h2, .together-content3 h2", { start: "top 100%", end: "bottom 45%", fromColor: "#F5F5F5", toColor: "#4050FF", scrub: 1 } ); // ===== DRUGI BLOCK ===== // začne prej + back scroll takoj reagira wordReveal( ".together-content2 h2", { start: "top 70%", end: "bottom 30%", fromColor: "#F5F5F5", toColor: "#4050FF", scrub: 0.4 } ); });