File size: 3,955 Bytes
338bf07
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
// ---------- CONFIG ----------
const CORRECT_PASSWORD = "2507"; // Tayyaba's birthday, DDMM

// ---------- floating balloons ----------
const balloonColors = ["#b98ee8", "#d3b3f0", "#f6a6c1", "#ffffff", "#e8b64a", "#c9a6f2"];
const field = document.getElementById("balloonField");

function spawnBalloon() {
  const b = document.createElement("div");
  b.className = "balloon";
  const color = balloonColors[Math.floor(Math.random() * balloonColors.length)];
  b.style.background = color;
  b.style.left = Math.random() * 96 + "vw";
  const size = 50 + Math.random() * 40;
  b.style.width = size + "px";
  b.style.height = size * 1.25 + "px";
  const duration = 10 + Math.random() * 8;
  b.style.animationDuration = duration + "s";
  field.appendChild(b);
  setTimeout(() => b.remove(), duration * 1000);
}

// seed some balloons immediately, then keep spawning
for (let i = 0; i < 10; i++) {
  setTimeout(spawnBalloon, i * 700);
}
setInterval(spawnBalloon, 1400);

// ---------- popup controls ----------
const openBtn = document.getElementById("openBtn");
const passOverlay = document.getElementById("passOverlay");
const closeOverlay = document.getElementById("closeOverlay");
const passForm = document.getElementById("passForm");
const passInput = document.getElementById("passInput");
const oopsPopup = document.getElementById("oopsPopup");
const oopsRetry = document.getElementById("oopsRetry");
const homePage = document.getElementById("homePage");
const letterPage = document.getElementById("letterPage");

openBtn.addEventListener("click", () => {
  passOverlay.classList.remove("hidden");
  passInput.value = "";
  passInput.focus();
});

closeOverlay.addEventListener("click", () => {
  passOverlay.classList.add("hidden");
});

passForm.addEventListener("submit", (e) => {
  e.preventDefault();
  const val = passInput.value.trim();
  if (val === CORRECT_PASSWORD) {
    passOverlay.classList.add("hidden");
    homePage.classList.add("hidden");
    letterPage.classList.remove("hidden");
    window.scrollTo({ top: 0, behavior: "smooth" });
  } else {
    passOverlay.classList.add("hidden");
    oopsPopup.classList.remove("hidden");
  }
});

oopsRetry.addEventListener("click", () => {
  oopsPopup.classList.add("hidden");
  passOverlay.classList.remove("hidden");
  passInput.value = "";
  passInput.focus();
});

// ---------- synthesized birthday tune (Web Audio, no external file needed) ----------
let audioCtx;
const musicBtn = document.getElementById("musicBtn");

// a cheerful original little melody (note, duration in seconds)
const tune = [
  ["C5", 0.3], ["C5", 0.2], ["D5", 0.5], ["C5", 0.5], ["F5", 0.5], ["E5", 1.0],
  ["C5", 0.3], ["C5", 0.2], ["D5", 0.5], ["C5", 0.5], ["G5", 0.5], ["F5", 1.0],
  ["C5", 0.3], ["C5", 0.2], ["C6", 0.5], ["A5", 0.5], ["F5", 0.5], ["E5", 0.5], ["D5", 1.0],
  ["A#5", 0.3], ["A#5", 0.2], ["A5", 0.5], ["F5", 0.5], ["G5", 0.5], ["F5", 1.0]
];

const noteFreq = {
  "C5": 523.25, "D5": 587.33, "E5": 659.25, "F5": 698.46, "G5": 783.99,
  "A5": 880.00, "A#5": 932.33, "C6": 1046.50
};

function playTune() {
  if (!audioCtx) audioCtx = new (window.AudioContext || window.webkitAudioContext)();
  let t = audioCtx.currentTime + 0.05;
  tune.forEach(([note, dur]) => {
    const osc = audioCtx.createOscillator();
    const gain = audioCtx.createGain();
    osc.type = "triangle";
    osc.frequency.value = noteFreq[note];
    gain.gain.setValueAtTime(0.0001, t);
    gain.gain.exponentialRampToValueAtTime(0.25, t + 0.05);
    gain.gain.exponentialRampToValueAtTime(0.0001, t + dur);
    osc.connect(gain).connect(audioCtx.destination);
    osc.start(t);
    osc.stop(t + dur + 0.05);
    t += dur;
  });
}

let playing = false;
musicBtn.addEventListener("click", () => {
  playTune();
  musicBtn.textContent = "🎶 Playing...";
  const totalDuration = tune.reduce((sum, [, d]) => sum + d, 0) * 1000;
  setTimeout(() => { musicBtn.textContent = "🎵 Play Birthday Tune"; }, totalDuration);
});