/** * SUDDENLY CREATIVE - MAIN JAVASCRIPT * Animations, interactions, dan utility functions */ // ================================================ // 1. PARALLAX EFFECT // ================================================ function initParallax() { const elements = document.querySelectorAll('[data-parallax]'); window.addEventListener('scroll', () => { elements.forEach(element => { const speed = element.dataset.parallax; const yPos = window.scrollY * speed; element.style.transform = `translateY(${yPos}px)`; }); }); } // ================================================ // 2. SMOOTH SCROLL BEHAVIOR // ================================================ function initSmoothScroll() { document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function (e) { e.preventDefault(); const target = document.querySelector(this.getAttribute('href')); if (target) { target.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }); }); } // ================================================ // 3. NAVBAR ANIMATION ON SCROLL // ================================================ function initNavbarScroll() { const navbar = document.querySelector('nav'); let lastScrollTop = 0; window.addEventListener('scroll', () => { let currentScroll = window.scrollY; // Add shadow on scroll if (currentScroll > 50) { navbar.style.borderBottomColor = 'rgba(147, 51, 234, 0.3)'; navbar.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'; } else { navbar.style.borderBottomColor = 'rgba(147, 51, 234, 0.1)'; navbar.style.backgroundColor = 'rgba(0, 0, 0, 0.3)'; } lastScrollTop = currentScroll; }); } // ================================================ // 4. GSAP ANIMATIONS SETUP // ================================================ function initGSAPAnimations() { if (typeof gsap === 'undefined') return; // Scroll trigger animations gsap.registerPlugin(ScrollTrigger); // Staggered animations for elements gsap.utils.toArray('.service-card').forEach((element, index) => { gsap.from(element, { opacity: 0, y: 30, delay: index * 0.1, duration: 0.6, scrollTrigger: { trigger: element, start: 'top 80%', toggleActions: 'play none none none' } }); }); // Parallax scroll effect gsap.to('[data-parallax]', { yPercent: -5, scrollTrigger: { trigger: 'body', scrub: true, markers: false } }); } // ================================================ // 5. BUTTON HOVER EFFECTS // ================================================ function initButtonEffects() { const buttons = document.querySelectorAll('button, a.btn-primary, .btn-primary'); buttons.forEach(button => { button.addEventListener('mouseenter', function() { this.style.transform = 'scale(1.05)'; }); button.addEventListener('mouseleave', function() { this.style.transform = 'scale(1)'; }); }); } // ================================================ // 6. AOS (ANIMATE ON SCROLL) INITIALIZATION // ================================================ function initAOS() { if (typeof AOS !== 'undefined') { AOS.init({ duration: 1000, once: true, offset: 100, easing: 'ease-in-out-quad' }); // Refresh AOS after dynamic content changes window.addEventListener('load', () => AOS.refresh()); } } // ================================================ // 7. FORM VALIDATION // ================================================ function initFormValidation() { const forms = document.querySelectorAll('form'); forms.forEach(form => { form.addEventListener('submit', function(e) { let isValid = true; // Check required fields const requiredFields = this.querySelectorAll('[required]'); requiredFields.forEach(field => { if (!field.value.trim()) { isValid = false; field.style.borderColor = '#ef4444'; field.style.backgroundColor = 'rgba(239, 68, 68, 0.1)'; } else { field.style.borderColor = 'rgba(147, 51, 234, 0.3)'; field.style.backgroundColor = 'rgba(255, 255, 255, 0.05)'; } }); if (!isValid) { e.preventDefault(); } }); // Clear error on focus const inputs = form.querySelectorAll('input, textarea'); inputs.forEach(input => { input.addEventListener('focus', function() { this.style.borderColor = 'rgba(147, 51, 234, 0.3)'; this.style.backgroundColor = 'rgba(255, 255, 255, 0.05)'; }); }); }); } // ================================================ // 8. COUNTER ANIMATION // ================================================ function initCounterAnimation() { const counters = document.querySelectorAll('.counter'); const animateCounter = (element) => { const target = parseInt(element.dataset.target); const duration = 2000; // 2 seconds const increment = target / (duration / 16); // 60fps let current = 0; const timer = setInterval(() => { current += increment; if (current >= target) { element.textContent = target; clearInterval(timer); } else { element.textContent = Math.floor(current); } }, 16); }; // Trigger animation when in view const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting && !entry.target.dataset.animated) { animateCounter(entry.target); entry.target.dataset.animated = 'true'; } }); }); counters.forEach(counter => observer.observe(counter)); } // ================================================ // 9. LAZY LOADING FOR IMAGES // ================================================ function initLazyLoading() { const images = document.querySelectorAll('img[data-src]'); const imageObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; img.src = img.dataset.src; img.removeAttribute('data-src'); imageObserver.unobserve(img); } }); }); images.forEach(img => imageObserver.observe(img)); } // ================================================ // 10. RESPONSIVE MENU TOGGLE // ================================================ function initMobileMenu() { const menuBtn = document.querySelector('[data-menu-toggle]'); const navbar = document.querySelector('nav'); if (menuBtn) { menuBtn.addEventListener('click', function() { navbar.classList.toggle('open'); }); } // Close menu on link click document.querySelectorAll('nav a').forEach(link => { link.addEventListener('click', () => { if (navbar.classList.contains('open')) { navbar.classList.remove('open'); } }); }); } // ================================================ // 11. REVEAL ANIMATION ON SCROLL // ================================================ function initRevealAnimation() { const reveals = document.querySelectorAll('[data-reveal]'); const revealObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { gsap.to(entry.target, { opacity: 1, y: 0, duration: 0.8, ease: 'power2.out' }); revealObserver.unobserve(entry.target); } }); }, { threshold: 0.1 }); reveals.forEach(element => { gsap.set(element, { opacity: 0, y: 30 }); revealObserver.observe(element); }); } // ================================================ // 12. UTILITY FUNCTIONS // ================================================ // Debounce function function debounce(func, delay) { let timeoutId; return function(...args) { clearTimeout(timeoutId); timeoutId = setTimeout(() => func(...args), delay); }; } // Add class to multiple elements function addClassToElements(selector, className) { document.querySelectorAll(selector).forEach(el => { el.classList.add(className); }); } // Get viewport height function getViewportHeight() { return Math.max(document.documentElement.clientHeight, window.innerHeight); } // ================================================ // 13. INITIALIZATION ON DOM READY // ================================================ document.addEventListener('DOMContentLoaded', function() { console.log('🚀 Suddenly Creative - JS Initialized'); // Initialize all features initParallax(); initSmoothScroll(); initNavbarScroll(); initGSAPAnimations(); initButtonEffects(); initAOS(); initFormValidation(); initCounterAnimation(); initLazyLoading(); initMobileMenu(); initRevealAnimation(); // Log initialization complete console.log('✅ All animations and effects are active!'); }); // ================================================ // 14. WINDOW RESIZE HANDLER // ================================================ window.addEventListener('resize', debounce(function() { console.log('Window resized:', { width: window.innerWidth, height: window.innerHeight }); }, 250)); // ================================================ // 15. PAGE VISIBILITY API // ================================================ document.addEventListener('visibilitychange', function() { if (document.hidden) { console.log('Page hidden'); } else { console.log('Page visible'); // Resume animations if (typeof AOS !== 'undefined') { AOS.refresh(); } } });