// ======================================== // Floating Hearts Animation // ======================================== function createFloatingHearts() { const heartsContainer = document.getElementById('heartsContainer'); const heartSymbols = ['❤️', '💕', '💖', '💗', '💓', '💝']; function addHeart() { const heart = document.createElement('div'); heart.className = 'floating-heart'; heart.textContent = heartSymbols[Math.floor(Math.random() * heartSymbols.length)]; heart.style.left = Math.random() * 100 + '%'; heart.style.animationDuration = (Math.random() * 5 + 8) + 's'; heart.style.fontSize = (Math.random() * 1.5 + 1) + 'rem'; heartsContainer.appendChild(heart); setTimeout(() => { heart.remove(); }, 12000); } // Create initial hearts for (let i = 0; i < 15; i++) { setTimeout(addHeart, i * 500); } // Continue creating hearts setInterval(addHeart, 1000); } // ======================================== // Particle System // ======================================== function initParticleSystem() { const canvas = document.getElementById('particleCanvas'); const ctx = canvas.getContext('2d'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; const particles = []; const particleCount = 50; class Particle { constructor() { this.x = Math.random() * canvas.width; this.y = Math.random() * canvas.height; this.size = Math.random() * 3 + 1; this.speedX = Math.random() * 2 - 1; this.speedY = Math.random() * 2 - 1; this.opacity = Math.random() * 0.5 + 0.2; } update() { this.x += this.speedX; this.y += this.speedY; if (this.x > canvas.width) this.x = 0; if (this.x < 0) this.x = canvas.width; if (this.y > canvas.height) this.y = 0; if (this.y < 0) this.y = canvas.height; } draw() { ctx.fillStyle = `rgba(255, 255, 255, ${this.opacity})`; ctx.beginPath(); ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2); ctx.fill(); } } function init() { for (let i = 0; i < particleCount; i++) { particles.push(new Particle()); } } function animate() { ctx.clearRect(0, 0, canvas.width, canvas.height); particles.forEach(particle => { particle.update(); particle.draw(); }); requestAnimationFrame(animate); } init(); animate(); window.addEventListener('resize', () => { canvas.width = window.innerWidth; canvas.height = window.innerHeight; }); } // ======================================== // Countdown Timer // ======================================== function initCountdown() { const daysEl = document.getElementById('days'); const hoursEl = document.getElementById('hours'); const minutesEl = document.getElementById('minutes'); const secondsEl = document.getElementById('seconds'); function updateCountdown() { const now = new Date(); const currentYear = now.getFullYear(); let valentinesDay = new Date(currentYear, 1, 14); // February 14 // If Valentine's Day has passed this year, count to next year if (now > valentinesDay) { valentinesDay = new Date(currentYear + 1, 1, 14); } const diff = valentinesDay - now; const days = Math.floor(diff / (1000 * 60 * 60 * 24)); const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)); const seconds = Math.floor((diff % (1000 * 60)) / 1000); daysEl.textContent = String(days).padStart(2, '0'); hoursEl.textContent = String(hours).padStart(2, '0'); minutesEl.textContent = String(minutes).padStart(2, '0'); secondsEl.textContent = String(seconds).padStart(2, '0'); } updateCountdown(); setInterval(updateCountdown, 1000); } // ======================================== // Scroll Reveal Animation // ======================================== function initScrollReveal() { const revealElements = document.querySelectorAll('.reveal-on-scroll'); const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('revealed'); } }); }, { threshold: 0.1, rootMargin: '0px 0px -50px 0px' }); revealElements.forEach(el => observer.observe(el)); } // ======================================== // Typewriter Effect // ======================================== function initTypewriter() { const messageEl = document.getElementById('loveMessage'); const message = `My Dearest Valentine, Every moment with you feels like a beautiful dream come true. Your smile lights up my world, and your laughter is the sweetest melody I've ever heard. From the first time we met, I knew you were special. You've brought so much joy, love, and meaning into my life. Every day with you is an adventure, and I cherish every single moment we share together. Thank you for being my partner, my best friend, and my greatest love. You make every day feel like Valentine's Day. I love you more than words can express, today and always. 💖`; let index = 0; function type() { if (index < message.length) { messageEl.textContent += message.charAt(index); index++; setTimeout(type, 30); } else { messageEl.classList.remove('typewriter'); } } // Start typing when element is in view const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting && index === 0) { type(); observer.unobserve(entry.target); } }); }, { threshold: 0.5 }); observer.observe(messageEl); } // ======================================== // Love Button Interaction // ======================================== function initLoveButton() { const loveButton = document.getElementById('loveButton'); const loveCount = document.getElementById('loveCount'); let count = 0; loveButton.addEventListener('click', function(e) { count++; loveCount.textContent = count; // Create floating hearts from button for (let i = 0; i < 5; i++) { createClickHeart(e.clientX, e.clientY); } // Add animation class loveButton.style.transform = 'scale(0.9)'; setTimeout(() => { loveButton.style.transform = ''; }, 200); }); function createClickHeart(x, y) { const heart = document.createElement('div'); heart.textContent = '❤️'; heart.style.position = 'fixed'; heart.style.left = x + 'px'; heart.style.top = y + 'px'; heart.style.fontSize = '2rem'; heart.style.pointerEvents = 'none'; heart.style.zIndex = '9999'; heart.style.animation = 'floatUpClick 2s ease-out forwards'; document.body.appendChild(heart); setTimeout(() => { heart.remove(); }, 2000); } // Add CSS animation for click hearts const style = document.createElement('style'); style.textContent = ` @keyframes floatUpClick { 0% { transform: translateY(0) scale(1); opacity: 1; } 100% { transform: translateY(-200px) scale(0.5); opacity: 0; } } `; document.head.appendChild(style); } // ======================================== // Smooth Scroll for Navigation // ======================================== 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' }); } }); }); } // ======================================== // Gallery Hover Effects // ======================================== function initGalleryEffects() { const galleryItems = document.querySelectorAll('.gallery-item'); galleryItems.forEach(item => { item.addEventListener('mouseenter', function() { this.style.transform = 'translateY(-10px) scale(1.02)'; }); item.addEventListener('mouseleave', function() { this.style.transform = ''; }); }); } // ======================================== // Mouse Trail Effect // ======================================== function initMouseTrail() { let lastTime = 0; const throttleDelay = 100; document.addEventListener('mousemove', function(e) { const currentTime = Date.now(); if (currentTime - lastTime < throttleDelay) { return; } lastTime = currentTime; if (Math.random() > 0.7) { const sparkle = document.createElement('div'); sparkle.textContent = '✨'; sparkle.style.position = 'fixed'; sparkle.style.left = e.clientX + 'px'; sparkle.style.top = e.clientY + 'px'; sparkle.style.fontSize = '1rem'; sparkle.style.pointerEvents = 'none'; sparkle.style.zIndex = '9999'; sparkle.style.animation = 'sparkle 1s ease-out forwards'; document.body.appendChild(sparkle); setTimeout(() => { sparkle.remove(); }, 1000); } }); // Add sparkle animation const style = document.createElement('style'); style.textContent = ` @keyframes sparkle { 0% { transform: scale(0) rotate(0deg); opacity: 1; } 100% { transform: scale(1.5) rotate(180deg); opacity: 0; } } `; document.head.appendChild(style); } // ======================================== // Initialize All Features // ======================================== document.addEventListener('DOMContentLoaded', function() { console.log('💖 Valentine\'s Day Website Loaded!'); // Initialize all features createFloatingHearts(); initParticleSystem(); initCountdown(); initScrollReveal(); initTypewriter(); initLoveButton(); initSmoothScroll(); initGalleryEffects(); initMouseTrail(); // Add entrance animation to body document.body.style.opacity = '0'; setTimeout(() => { document.body.style.transition = 'opacity 1s ease'; document.body.style.opacity = '1'; }, 100); }); // ======================================== // Performance Optimization // ======================================== // Pause animations when tab is not visible document.addEventListener('visibilitychange', function() { if (document.hidden) { // Pause heavy animations console.log('Tab hidden - reducing animations'); } else { // Resume animations console.log('Tab visible - resuming animations'); } });