/** * Enhanced Animations and Interactions * Premium effects for modern web experience */ const EnhancedAnimations = { init() { this.initScrollAnimations(); this.initParallaxEffects(); this.initMagneticButtons(); this.initTextAnimations(); this.initCardTilt(); this.initSmoothScroll(); this.initCursorEffects(); this.initNumberCounters(); this.initRevealOnScroll(); this.initNavbarEffects(); }, // Smooth scroll with easing initSmoothScroll() { document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function (e) { e.preventDefault(); const target = document.querySelector(this.getAttribute('href')); if (target) { const offset = 100; const targetPosition = target.offsetTop - offset; window.scrollTo({ top: targetPosition, behavior: 'smooth' }); } }); }); }, // Parallax scrolling effects initParallaxEffects() { const parallaxElements = document.querySelectorAll('.parallax'); let ticking = false; function updateParallax() { const scrolled = window.pageYOffset; parallaxElements.forEach(element => { const speed = element.dataset.speed || 0.5; const yPos = -(scrolled * speed); element.style.transform = `translateY(${yPos}px)`; }); ticking = false; } function requestTick() { if (!ticking) { window.requestAnimationFrame(updateParallax); ticking = true; } } window.addEventListener('scroll', requestTick); }, // Magnetic button effects initMagneticButtons() { const magneticButtons = document.querySelectorAll('.primary-button, .secondary-button, .cta-button'); magneticButtons.forEach(button => { button.addEventListener('mousemove', (e) => { const rect = button.getBoundingClientRect(); const x = e.clientX - rect.left - rect.width / 2; const y = e.clientY - rect.top - rect.height / 2; button.style.transform = `translate(${x * 0.2}px, ${y * 0.2}px) scale(1.05)`; }); button.addEventListener('mouseleave', () => { button.style.transform = ''; }); }); }, // Advanced text animations initTextAnimations() { // Typewriter effect for hero title - DISABLED to prevent duplication // The title already has CSS animations applied /* Commented out to fix duplication issue const heroTitle = document.querySelector('.main-title'); if (heroTitle && !heroTitle.dataset.animated) { heroTitle.dataset.animated = 'true'; const text = heroTitle.textContent; heroTitle.textContent = ''; heroTitle.style.opacity = '1'; let index = 0; const typeWriter = () => { if (index < text.length) { heroTitle.textContent += text.charAt(index); index++; setTimeout(typeWriter, 50); } }; // Start typewriter after a short delay setTimeout(typeWriter, 500); } */ // Word-by-word reveal for hero text const heroText = document.querySelector('.hero-text'); if (heroText) { const words = heroText.textContent.split(' '); heroText.innerHTML = words.map(word => `${word}` ).join(' '); const wordSpans = heroText.querySelectorAll('.word-reveal'); wordSpans.forEach((word, index) => { setTimeout(() => { word.style.opacity = '1'; word.style.transform = 'translateY(0)'; }, 1000 + index * 100); }); } }, // 3D card tilt effect initCardTilt() { const cards = document.querySelectorAll('.tool-card, .value-card, .why-card'); cards.forEach(card => { card.addEventListener('mousemove', (e) => { const rect = card.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; const centerX = rect.width / 2; const centerY = rect.height / 2; const rotateX = (y - centerY) / 10; const rotateY = (centerX - x) / 10; card.style.transform = `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) scale(1.02)`; }); card.addEventListener('mouseleave', () => { card.style.transform = ''; }); }); }, // Custom cursor effects - DISABLED initCursorEffects() { // Cursor removed as requested return; }, // Animated number counters initNumberCounters() { const counters = document.querySelectorAll('.indicator-value'); const animationDuration = 2000; let hasAnimated = false; const animateCounters = () => { if (hasAnimated) return; counters.forEach(counter => { const target = parseFloat(counter.dataset.target); const start = 0; const increment = target / (animationDuration / 16); let current = start; const updateCounter = () => { current += increment; if (current < target) { counter.textContent = Math.floor(current); requestAnimationFrame(updateCounter); } else { counter.textContent = target % 1 === 0 ? target : target.toFixed(1); } }; updateCounter(); }); hasAnimated = true; }; // Trigger on scroll into view const observerOptions = { threshold: 0.5 }; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { animateCounters(); } }); }, observerOptions); const indicatorsSection = document.querySelector('.trust-indicators'); if (indicatorsSection) { observer.observe(indicatorsSection); } }, // Reveal elements on scroll initRevealOnScroll() { const revealElements = document.querySelectorAll('.about-panel, .tool-card, .value-card, .why-card, .competency-item'); revealElements.forEach((element, index) => { element.style.opacity = '0'; element.style.transform = 'translateY(50px)'; element.style.transition = 'all 0.8s cubic-bezier(0.4, 0, 0.2, 1)'; }); const revealOnScroll = () => { const windowHeight = window.innerHeight; revealElements.forEach((element, index) => { const elementTop = element.getBoundingClientRect().top; const elementVisible = 100; if (elementTop < windowHeight - elementVisible) { setTimeout(() => { element.style.opacity = '1'; element.style.transform = 'translateY(0)'; }, index * 50); } }); }; window.addEventListener('scroll', revealOnScroll); revealOnScroll(); // Check on initial load }, // Scroll-based animations initScrollAnimations() { let lastScrollY = window.scrollY; let ticking = false; function updateScrollAnimations() { const scrollY = window.scrollY; const scrollDirection = scrollY > lastScrollY ? 'down' : 'up'; // Hero parallax const hero = document.querySelector('.hero-content'); if (hero) { hero.style.transform = `translateY(${scrollY * 0.5}px)`; hero.style.opacity = 1 - (scrollY / 800); } // Video parallax const heroVideos = document.querySelector('.hero-video-container'); if (heroVideos) { heroVideos.style.transform = `translateY(${scrollY * 0.3}px) scale(${1 + scrollY * 0.0003})`; } lastScrollY = scrollY; ticking = false; } function requestTick() { if (!ticking) { window.requestAnimationFrame(updateScrollAnimations); ticking = true; } } window.addEventListener('scroll', requestTick); }, // Enhanced navbar effects initNavbarEffects() { const navbar = document.querySelector('.navbar'); let lastScrollY = window.scrollY; window.addEventListener('scroll', () => { const scrollY = window.scrollY; if (scrollY > 50) { navbar.classList.add('scrolled'); } else { navbar.classList.remove('scrolled'); } // Keep navbar always visible navbar.style.transform = 'translateY(0)'; lastScrollY = scrollY; }); } }; // Initialize when DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => EnhancedAnimations.init()); } else { EnhancedAnimations.init(); }