/** * Valentine's Day Website Logic * Handles animations (Starfield, Confetti) and Interactions. */ // --- Canvas Setup --- const canvas = document.getElementById('starfield'); const ctx = canvas.getContext('2d'); let width, height; // Resize handling function resize() { width = window.innerWidth; height = window.innerHeight; canvas.width = width; canvas.height = height; } window.addEventListener('resize', resize); resize(); // --- Star Class --- class Star { constructor() { this.reset(); // Start with random progress to avoid "waves" this.progress = Math.random(); } reset() { this.x = Math.random() * width; this.y = Math.random() * height; this.size = Math.random() * 2 + 0.5; // 0.5 to 2.5 this.speed = Math.random() * 0.02 + 0.005; this.alpha = Math.random(); this.direction = Math.random() > 0.5 ? 1 : -1; } update() { this.alpha += this.speed * this.direction; if (this.alpha >= 1 || this.alpha <= 0) { this.direction *= -1; } } draw() { ctx.fillStyle = `rgba(255, 255, 255, ${this.alpha})`; ctx.beginPath(); ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2); ctx.fill(); } } // --- Confetti Class --- class Confetti { constructor() { this.reset(); this.y = Math.random() * -height; // Start above screen } reset() { this.x = Math.random() * width; this.y = -10; this.size = Math.random() * 10 + 5; this.color = `hsl(${Math.random() * 360}, 100%, 50%)`; this.speedY = Math.random() * 3 + 2; this.speedX = (Math.random() - 0.5) * 2; this.rotation = Math.random() * 360; this.rotationSpeed = (Math.random() - 0.5) * 10; } update() { this.y += this.speedY; this.x += this.speedX; this.rotation += this.rotationSpeed; if (this.y > height) { this.reset(); } } draw() { ctx.save(); ctx.translate(this.x, this.y); ctx.rotate(this.rotation * Math.PI / 180); ctx.fillStyle = this.color; ctx.fillRect(-this.size / 2, -this.size / 2, this.size, this.size); ctx.restore(); } } // --- Animation System --- const stars = Array.from({length: 200}, () => new Star()); let confettis = []; // Empty initially let isCelebrating = false; function animate() { ctx.clearRect(0, 0, width, height); // Draw Stars stars.forEach(star => { star.update(); star.draw(); }); // Draw Confetti if celebrating if (isCelebrating) { if (confettis.length < 150) { confettis.push(new Confetti()); } confettis.forEach(c => { c.update(); c.draw(); }); } requestAnimationFrame(animate); } animate(); // --- Interaction Logic --- const envelopeWrapper = document.getElementById('envelope-wrapper'); const yesBtn = document.getElementById('yesBtn'); const noBtn = document.getElementById('noBtn'); const celebrationOverlay = document.getElementById('celebration-overlay'); // Open Envelope envelopeWrapper.addEventListener('click', () => { if (!envelopeWrapper.classList.contains('open')) { envelopeWrapper.classList.add('open'); // Hide instruction document.querySelector('.click-instruction').style.display = 'none'; } }); // "No" Button Evasion noBtn.addEventListener('mouseover', () => { const maxX = 100; // Movement range inside the card/actions const maxY = 50; const randomX = (Math.random() - 0.5) * 2 * maxX; const randomY = (Math.random() - 0.5) * 2 * maxY; noBtn.style.transform = `translate(${randomX}px, ${randomY}px)`; }); // "Yes" Button Celebration yesBtn.addEventListener('click', (e) => { e.stopPropagation(); // Prevent bubbling if needed isCelebrating = true; celebrationOverlay.classList.add('active'); // Optional: Change background gradient aggressively document.body.style.background = 'radial-gradient(circle at center, #ff758c, #ff7eb3)'; });