script.js

3.77 KB
28/01/2026 03:41
JS
script.js
/**
 * 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)';
});