639 lines
23 KiB
JavaScript
639 lines
23 KiB
JavaScript
function getstart() {
|
|
window.location.href = "/contacts.php";
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const initPageAnimations = () => {
|
|
if (typeof gsap === 'undefined' || typeof ScrollTrigger === 'undefined') return;
|
|
|
|
gsap.registerPlugin(ScrollTrigger);
|
|
ScrollTrigger.config({ ignoreMobileResize: true });
|
|
|
|
const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
if (reduceMotion) {
|
|
gsap.set('[data-gsap-ready]', { clearProps: 'all' });
|
|
return;
|
|
}
|
|
|
|
const ease = 'power3.out';
|
|
const touchDevice = window.matchMedia('(hover: none), (pointer: coarse)').matches;
|
|
const sections = gsap.utils.toArray([
|
|
'.three-images-template-section',
|
|
'.our-products-section',
|
|
'.what-we-do-section'
|
|
].join(','));
|
|
|
|
const revealGroup = (trigger, targets, vars = {}) => {
|
|
const items = gsap.utils.toArray(targets);
|
|
if (!items.length || !document.querySelector(trigger)) return;
|
|
|
|
gsap.from(items, {
|
|
scrollTrigger: {
|
|
trigger,
|
|
start: vars.start || 'top 78%',
|
|
toggleActions: 'play none none none'
|
|
},
|
|
autoAlpha: 0,
|
|
y: vars.y ?? 46,
|
|
x: vars.x ?? 0,
|
|
scale: vars.scale ?? 0.96,
|
|
rotateX: vars.rotateX ?? 0,
|
|
transformPerspective: 900,
|
|
duration: vars.duration || 0.9,
|
|
stagger: vars.stagger ?? 0.12,
|
|
ease: vars.ease || ease,
|
|
clearProps: vars.clearProps || 'transform'
|
|
});
|
|
};
|
|
|
|
const revealImage = (trigger, target, vars = {}) => {
|
|
if (!document.querySelector(target) || !document.querySelector(trigger)) return;
|
|
|
|
gsap.from(target, {
|
|
scrollTrigger: {
|
|
trigger,
|
|
start: vars.start || 'top 75%',
|
|
toggleActions: 'play none none none'
|
|
},
|
|
autoAlpha: 0,
|
|
y: vars.y ?? 36,
|
|
x: vars.x ?? 0,
|
|
scale: vars.scale ?? 0.9,
|
|
rotate: vars.rotate ?? 0,
|
|
duration: vars.duration || 1.1,
|
|
ease: vars.ease || ease,
|
|
clearProps: vars.clearProps || 'transform'
|
|
});
|
|
};
|
|
|
|
const addHoverLift = (selector) => {
|
|
gsap.utils.toArray(selector).forEach((card) => {
|
|
card.style.willChange = 'transform';
|
|
|
|
card.addEventListener('mouseenter', () => {
|
|
gsap.to(card, {
|
|
y: -8,
|
|
scale: 1.015,
|
|
duration: 0.32,
|
|
ease: 'power2.out',
|
|
overwrite: 'auto'
|
|
});
|
|
});
|
|
|
|
card.addEventListener('mouseleave', () => {
|
|
gsap.to(card, {
|
|
x: 0,
|
|
y: 0,
|
|
rotateX: 0,
|
|
rotateY: 0,
|
|
scale: 1,
|
|
duration: 0.45,
|
|
ease: 'power2.out',
|
|
overwrite: 'auto'
|
|
});
|
|
});
|
|
|
|
card.addEventListener('mousemove', (event) => {
|
|
const bounds = card.getBoundingClientRect();
|
|
const relX = (event.clientX - bounds.left) / bounds.width - 0.5;
|
|
const relY = (event.clientY - bounds.top) / bounds.height - 0.5;
|
|
|
|
gsap.to(card, {
|
|
rotateY: relX * 5,
|
|
rotateX: relY * -5,
|
|
duration: 0.35,
|
|
ease: 'power2.out',
|
|
overwrite: 'auto'
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
const addDesktopParallax = (trigger, target, yPercent = -7) => {
|
|
if (!window.matchMedia('(min-width: 769px)').matches) return;
|
|
if (!document.querySelector(trigger) || !document.querySelector(target)) return;
|
|
|
|
gsap.to(target, {
|
|
yPercent,
|
|
ease: 'none',
|
|
scrollTrigger: {
|
|
trigger,
|
|
start: 'top bottom',
|
|
end: 'bottom top',
|
|
scrub: 0.8
|
|
}
|
|
});
|
|
};
|
|
|
|
const initGoldenPortalCards = () => {
|
|
const cards = gsap.utils.toArray('.three-images-template-section .tit-img-wrapper');
|
|
if (!cards.length) return;
|
|
|
|
const canHover = window.matchMedia('(hover: hover) and (pointer: fine)').matches;
|
|
|
|
gsap.set(cards, {
|
|
transformOrigin: 'center',
|
|
transformPerspective: 1400,
|
|
transformStyle: 'preserve-3d',
|
|
opacity: 0,
|
|
y: 72,
|
|
scale: 0.9,
|
|
rotateX: 10
|
|
});
|
|
|
|
cards.forEach((card) => card.classList.add('is-portal-ready'));
|
|
|
|
gsap.timeline({
|
|
scrollTrigger: {
|
|
trigger: '.three-images-template-section',
|
|
start: 'top 76%',
|
|
toggleActions: 'play none none none'
|
|
}
|
|
})
|
|
.to(cards, {
|
|
opacity: 1,
|
|
y: 0,
|
|
scale: 1,
|
|
rotateX: 0,
|
|
duration: 1.15,
|
|
stagger: 0.18,
|
|
ease: 'power3.out',
|
|
onStart: () => cards.forEach((card) => card.classList.add('is-portal-revealed'))
|
|
})
|
|
.fromTo(cards.map((card) => card.querySelector('img')).filter(Boolean), {
|
|
scale: 1.16,
|
|
yPercent: 5
|
|
}, {
|
|
scale: 1.01,
|
|
yPercent: 0,
|
|
duration: 1.25,
|
|
stagger: 0.18,
|
|
ease: 'power3.out'
|
|
}, '<');
|
|
|
|
if (!canHover) return;
|
|
|
|
cards.forEach((card) => {
|
|
const image = card.querySelector('img');
|
|
const glowTo = gsap.quickTo(card, '--portal-glow', { duration: 0.35, ease: 'power2.out' });
|
|
|
|
const updatePortalPosition = (event) => {
|
|
const bounds = card.getBoundingClientRect();
|
|
const relX = (event.clientX - bounds.left) / bounds.width;
|
|
const relY = (event.clientY - bounds.top) / bounds.height;
|
|
const clampedX = gsap.utils.clamp(0, 1, relX);
|
|
const clampedY = gsap.utils.clamp(0, 1, relY);
|
|
|
|
card.style.setProperty('--portal-x', `${clampedX * 100}%`);
|
|
card.style.setProperty('--portal-y', `${clampedY * 100}%`);
|
|
|
|
gsap.to(card, {
|
|
y: -10,
|
|
scale: 1.018,
|
|
rotateY: (clampedX - 0.5) * 8,
|
|
rotateX: (0.5 - clampedY) * 8,
|
|
duration: 0.38,
|
|
ease: 'power2.out',
|
|
overwrite: 'auto'
|
|
});
|
|
|
|
if (image) {
|
|
gsap.to(image, {
|
|
x: (clampedX - 0.5) * 8,
|
|
y: (clampedY - 0.5) * 8,
|
|
scale: 1.045,
|
|
duration: 0.45,
|
|
ease: 'power2.out',
|
|
overwrite: 'auto'
|
|
});
|
|
}
|
|
};
|
|
|
|
card.addEventListener('mouseenter', (event) => {
|
|
glowTo(1);
|
|
updatePortalPosition(event);
|
|
});
|
|
|
|
card.addEventListener('mousemove', updatePortalPosition);
|
|
|
|
card.addEventListener('mouseleave', () => {
|
|
glowTo(0);
|
|
gsap.to(card, {
|
|
x: 0,
|
|
y: 0,
|
|
rotateX: 0,
|
|
rotateY: 0,
|
|
scale: 1,
|
|
duration: 0.55,
|
|
ease: 'power3.out',
|
|
overwrite: 'auto'
|
|
});
|
|
|
|
if (image) {
|
|
gsap.to(image, {
|
|
x: 0,
|
|
y: 0,
|
|
scale: 1.01,
|
|
duration: 0.55,
|
|
ease: 'power3.out',
|
|
overwrite: 'auto'
|
|
});
|
|
}
|
|
});
|
|
});
|
|
};
|
|
|
|
const revealText = (trigger, targets) => {
|
|
const items = gsap.utils.toArray(targets);
|
|
if (!items.length || !document.querySelector(trigger)) return;
|
|
|
|
gsap.from(items, {
|
|
scrollTrigger: {
|
|
trigger,
|
|
start: 'top 80%',
|
|
toggleActions: 'play none none none'
|
|
},
|
|
autoAlpha: 0,
|
|
yPercent: 22,
|
|
duration: 0.95,
|
|
stagger: 0.08,
|
|
ease: 'power3.out',
|
|
clearProps: 'transform'
|
|
});
|
|
};
|
|
|
|
const animateCounters = () => {
|
|
const counters = gsap.utils.toArray([
|
|
'.spend-sense-total > div:nth-child(2)',
|
|
'.spend-sense-legend span[style*="font-weight: 700"]'
|
|
].join(','));
|
|
|
|
counters.forEach((counter) => {
|
|
const original = counter.textContent.trim();
|
|
const numeric = original.match(/[\d,.]+/);
|
|
if (!numeric) return;
|
|
|
|
const prefix = original.slice(0, numeric.index);
|
|
const suffix = original.slice(numeric.index + numeric[0].length);
|
|
const endValue = parseFloat(numeric[0].replace(/,/g, ''));
|
|
const decimals = numeric[0].includes('.') ? numeric[0].split('.')[1].length : 0;
|
|
const state = { value: 0 };
|
|
|
|
gsap.to(state, {
|
|
value: endValue,
|
|
duration: 1.4,
|
|
ease: 'power2.out',
|
|
scrollTrigger: {
|
|
trigger: counter.closest('section') || counter,
|
|
start: 'top 78%',
|
|
toggleActions: 'play none none none',
|
|
once: true
|
|
},
|
|
onUpdate: () => {
|
|
const value = state.value.toLocaleString('en-IN', {
|
|
minimumFractionDigits: decimals,
|
|
maximumFractionDigits: decimals
|
|
});
|
|
counter.textContent = `${prefix}${value}${suffix}`;
|
|
}
|
|
});
|
|
});
|
|
};
|
|
|
|
const initHorizontalShowcase = () => {
|
|
const productCards = gsap.utils.toArray('.our-products-section .product-card');
|
|
const layout = document.querySelector('.our-products-section .products-layout');
|
|
if (!layout || productCards.length < 3 || window.matchMedia('(max-width: 900px)').matches) return;
|
|
|
|
gsap.fromTo(productCards, {
|
|
xPercent: (index) => index % 2 === 0 ? -8 : 8
|
|
}, {
|
|
xPercent: 0,
|
|
ease: 'none',
|
|
scrollTrigger: {
|
|
trigger: '.our-products-section',
|
|
start: 'top bottom',
|
|
end: 'bottom top',
|
|
scrub: 0.9
|
|
}
|
|
});
|
|
};
|
|
|
|
const addCinematicMagnet = (selector, options = {}) => {
|
|
if (touchDevice) return;
|
|
|
|
const strength = options.strength || 10;
|
|
const lift = options.lift || -10;
|
|
const tilt = options.tilt || 5;
|
|
|
|
gsap.utils.toArray(selector).forEach((element) => {
|
|
element.style.willChange = 'transform, filter, box-shadow';
|
|
|
|
element.addEventListener('mouseenter', () => {
|
|
gsap.to(element, {
|
|
y: lift,
|
|
scale: 1.025,
|
|
filter: 'brightness(1.08) saturate(1.08)',
|
|
duration: 0.45,
|
|
ease: 'expo.out',
|
|
overwrite: 'auto'
|
|
});
|
|
});
|
|
|
|
element.addEventListener('mousemove', (event) => {
|
|
const bounds = element.getBoundingClientRect();
|
|
const relX = (event.clientX - bounds.left) / bounds.width - 0.5;
|
|
const relY = (event.clientY - bounds.top) / bounds.height - 0.5;
|
|
|
|
gsap.to(element, {
|
|
x: relX * strength,
|
|
y: lift + relY * strength,
|
|
rotateY: relX * tilt,
|
|
rotateX: relY * -tilt,
|
|
duration: 0.55,
|
|
ease: 'expo.out',
|
|
overwrite: 'auto'
|
|
});
|
|
});
|
|
|
|
element.addEventListener('mouseleave', () => {
|
|
gsap.to(element, {
|
|
x: 0,
|
|
y: 0,
|
|
rotateX: 0,
|
|
rotateY: 0,
|
|
scale: 1,
|
|
filter: 'brightness(1) saturate(1)',
|
|
duration: 0.75,
|
|
ease: 'elastic.out(1, 0.55)',
|
|
overwrite: 'auto'
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
const initAppleLoopMotion = () => {
|
|
const section = document.querySelector('.the-loop-section');
|
|
if (!section) return;
|
|
|
|
const container = section.querySelector('.loop-container');
|
|
const leftItems = gsap.utils.toArray('.the-loop-section .loop-left > *');
|
|
const orbit = section.querySelector('.loop-circle-container');
|
|
const orbitSvg = section.querySelector('.loop-circle-container > svg');
|
|
const robot = section.querySelector('.robot-center img');
|
|
const nodes = gsap.utils.toArray('.the-loop-section .loop-node');
|
|
const nodeIcons = nodes.map((node) => node.querySelector('div:first-child')).filter(Boolean);
|
|
const mobile = window.matchMedia('(max-width: 1024px)').matches;
|
|
|
|
gsap.set([container, orbit, orbitSvg, robot, ...leftItems, ...nodes, ...nodeIcons].filter(Boolean), {
|
|
transformOrigin: 'center',
|
|
transformPerspective: 1200,
|
|
force3D: true
|
|
});
|
|
|
|
const timeline = gsap.timeline({
|
|
defaults: {
|
|
ease: 'expo.out'
|
|
},
|
|
scrollTrigger: {
|
|
trigger: section,
|
|
start: 'top 76%',
|
|
toggleActions: 'play none none none',
|
|
once: true
|
|
}
|
|
});
|
|
|
|
timeline
|
|
.from(container, {
|
|
autoAlpha: 0,
|
|
y: 54,
|
|
scale: 0.97,
|
|
filter: 'blur(10px)',
|
|
duration: 1.08,
|
|
clearProps: 'filter'
|
|
})
|
|
.from(leftItems, {
|
|
autoAlpha: 0,
|
|
x: mobile ? 0 : -42,
|
|
y: mobile ? 28 : 18,
|
|
filter: 'blur(8px)',
|
|
stagger: 0.09,
|
|
duration: 0.78,
|
|
clearProps: 'filter'
|
|
}, '-=0.58')
|
|
.from(orbitSvg, {
|
|
autoAlpha: 0,
|
|
scale: 0.78,
|
|
rotate: -22,
|
|
duration: 1.15
|
|
}, '-=0.7')
|
|
.from(robot, {
|
|
autoAlpha: 0,
|
|
y: mobile ? 22 : 0,
|
|
scale: 0.66,
|
|
rotate: mobile ? 0 : 5,
|
|
filter: 'blur(12px)',
|
|
duration: 1.18,
|
|
ease: 'expo.out',
|
|
clearProps: 'filter'
|
|
}, '-=0.9')
|
|
.from(nodes, {
|
|
autoAlpha: 0,
|
|
scale: 0.78,
|
|
y: mobile ? 28 : 0,
|
|
filter: 'blur(9px)',
|
|
stagger: {
|
|
each: 0.14,
|
|
from: 'center'
|
|
},
|
|
duration: 0.88,
|
|
clearProps: 'filter'
|
|
}, '-=0.58')
|
|
.from(nodeIcons, {
|
|
scale: 0,
|
|
rotate: -24,
|
|
duration: 0.52,
|
|
stagger: 0.08,
|
|
ease: 'back.out(1.9)'
|
|
}, '-=0.42');
|
|
|
|
if (!mobile && orbit) {
|
|
gsap.to(orbit, {
|
|
rotate: 5,
|
|
ease: 'none',
|
|
scrollTrigger: {
|
|
trigger: section,
|
|
start: 'top bottom',
|
|
end: 'bottom top',
|
|
scrub: 1.1,
|
|
invalidateOnRefresh: true
|
|
}
|
|
});
|
|
}
|
|
|
|
if (robot) {
|
|
gsap.to(robot, {
|
|
y: mobile ? -8 : -16,
|
|
rotate: mobile ? 0 : -1.5,
|
|
duration: 2.8,
|
|
repeat: -1,
|
|
yoyo: true,
|
|
ease: 'sine.inOut'
|
|
});
|
|
}
|
|
|
|
if (!touchDevice && orbit) {
|
|
orbit.addEventListener('mousemove', (event) => {
|
|
const bounds = orbit.getBoundingClientRect();
|
|
const relX = (event.clientX - bounds.left) / bounds.width - 0.5;
|
|
const relY = (event.clientY - bounds.top) / bounds.height - 0.5;
|
|
|
|
if (robot) {
|
|
gsap.to(robot, {
|
|
x: relX * 14,
|
|
rotateY: relX * 7,
|
|
rotateX: relY * -5,
|
|
duration: 0.65,
|
|
ease: 'expo.out',
|
|
overwrite: 'auto'
|
|
});
|
|
}
|
|
|
|
gsap.to(nodes, {
|
|
x: relX * -8,
|
|
y: relY * -8,
|
|
duration: 0.75,
|
|
ease: 'expo.out',
|
|
overwrite: 'auto'
|
|
});
|
|
});
|
|
|
|
orbit.addEventListener('mouseleave', () => {
|
|
if (robot) {
|
|
gsap.to(robot, {
|
|
x: 0,
|
|
rotateX: 0,
|
|
rotateY: 0,
|
|
duration: 0.8,
|
|
ease: 'expo.out',
|
|
overwrite: 'auto'
|
|
});
|
|
}
|
|
|
|
gsap.to(nodes, {
|
|
x: 0,
|
|
y: 0,
|
|
rotateX: 0,
|
|
rotateY: 0,
|
|
duration: 0.8,
|
|
ease: 'expo.out',
|
|
overwrite: 'auto'
|
|
});
|
|
});
|
|
}
|
|
|
|
addCinematicMagnet('.the-loop-section .loop-node', {
|
|
strength: 8,
|
|
lift: -8,
|
|
tilt: 4
|
|
});
|
|
};
|
|
|
|
gsap.set([
|
|
'.product-card',
|
|
'.tit-img-wrapper',
|
|
'.loop-node'
|
|
].join(','), {
|
|
transformOrigin: 'center',
|
|
transformPerspective: 900
|
|
});
|
|
|
|
gsap.from([
|
|
'.elementor-element-55f3e96',
|
|
'.elementor-element-520d0b9',
|
|
'.elementor-element-bb1e9c1 img'
|
|
], {
|
|
autoAlpha: 0,
|
|
y: 36,
|
|
scale: 0.96,
|
|
duration: 1,
|
|
stagger: 0.16,
|
|
ease,
|
|
clearProps: 'transform'
|
|
});
|
|
|
|
revealText('.elementor-element-aaa9419', '.elementor-element-55f3e96 h1, .elementor-element-55f3e96 p');
|
|
|
|
sections.forEach((section) => {
|
|
gsap.from(section, {
|
|
scrollTrigger: {
|
|
trigger: section,
|
|
start: 'top 86%',
|
|
toggleActions: 'play none none none'
|
|
},
|
|
autoAlpha: 0,
|
|
y: 34,
|
|
duration: 0.85,
|
|
ease,
|
|
clearProps: 'transform'
|
|
});
|
|
});
|
|
|
|
initGoldenPortalCards();
|
|
|
|
revealGroup('.our-products-section', '.products-container > div:first-child, .products-container > div:nth-child(2)', {
|
|
y: 28,
|
|
stagger: 0.1
|
|
});
|
|
revealGroup('.our-products-section', '.product-card', { y: 56, scale: 0.94, stagger: 0.12 });
|
|
revealImage('.our-products-section', '.products-col-center img', { y: 46, scale: 0.86, duration: 1.15, ease: 'power3.out' });
|
|
initHorizontalShowcase();
|
|
|
|
initAppleLoopMotion();
|
|
|
|
addHoverLift('.product-card');
|
|
|
|
addDesktopParallax('.three-images-template-section', '.tit-img-wrapper:nth-child(1) img', -4);
|
|
addDesktopParallax('.three-images-template-section', '.tit-img-wrapper:nth-child(2) img', -7);
|
|
addDesktopParallax('.three-images-template-section', '.tit-img-wrapper:nth-child(3) img', -4);
|
|
addDesktopParallax('.our-products-section', '.products-col-center img', -6);
|
|
|
|
// What We Do Animations
|
|
revealText('.what-we-do-section', '.wwd-text > div:first-of-type, .wwd-text h2');
|
|
revealImage('.what-we-do-section', '.wwd-image img', {
|
|
x: 40,
|
|
scale: 0.85,
|
|
duration: 1.2,
|
|
start: 'top 70%'
|
|
});
|
|
revealGroup('.what-we-do-section', '.wwd-card', {
|
|
y: 40,
|
|
stagger: 0.15,
|
|
start: 'top 75%'
|
|
});
|
|
addHoverLift('.wwd-card');
|
|
addDesktopParallax('.what-we-do-section', '.wwd-image img', -5);
|
|
|
|
animateCounters();
|
|
|
|
ScrollTrigger.refresh();
|
|
};
|
|
|
|
setTimeout(initPageAnimations, 350);
|
|
|
|
let resizeTimer;
|
|
window.addEventListener('resize', () => {
|
|
window.clearTimeout(resizeTimer);
|
|
resizeTimer = window.setTimeout(() => {
|
|
if (typeof ScrollTrigger === 'undefined') return;
|
|
|
|
ScrollTrigger.getAll().forEach((trigger) => {
|
|
if (trigger.trigger && !document.documentElement.contains(trigger.trigger)) {
|
|
trigger.kill();
|
|
}
|
|
});
|
|
ScrollTrigger.refresh();
|
|
}, 180);
|
|
}, { passive: true });
|
|
});
|