-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.js
More file actions
238 lines (181 loc) · 6.61 KB
/
script.js
File metadata and controls
238 lines (181 loc) · 6.61 KB
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
const params = new URLSearchParams(window.location.search);
const name = params.get("name");
const msg = params.get("msg");
const nameEl = document.getElementById("name");
const toName = document.getElementById("toName");
const loveMessageEl = document.getElementById("loveMessage");
if (name && nameEl) nameEl.textContent = name;
if (name && toName) toName.textContent = name;
if (msg && loveMessageEl) loveMessageEl.textContent = msg;
const heartsRoot = document.getElementById("heartBurst");
function popHearts(count = 18) {
const emojis = ["❤️", "💗", "💘", "💞", "💖", "💕"];
const env = document.getElementById("envelopeBtn");
const rect = env.getBoundingClientRect();
// center of envelope
const cx = rect.left + rect.width / 2;
const cy = rect.top + rect.height / 2;
for (let i = 0; i < count; i++) {
const s = document.createElement("span");
s.className = "burst-heart";
s.textContent = emojis[Math.floor(Math.random() * emojis.length)];
// spawn at envelope center
s.style.left = `${cx}px`;
s.style.top = `${cy}px`;
// random burst direction
const angle = Math.random() * Math.PI * 2; // 0..2π
const distance = 90 + Math.random() * 140; // how far it flies
const dx = Math.cos(angle) * distance;
const dy = Math.sin(angle) * distance;
const upwardBias = 40 + Math.random() * 50;
s.style.setProperty("--dx", `${dx}px`);
s.style.setProperty("--dy", `${dy - upwardBias}px`);
// variation
s.style.setProperty("--dur", `${650 + Math.random() * 650}ms`);
s.style.fontSize = `${16 + Math.random() * 20}px`;
heartsRoot.appendChild(s);
s.addEventListener("animationend", () => s.remove());
}
}
const envelopeBtn = document.getElementById("envelopeBtn");
const yesBtn = document.getElementById("yesBtn");
const noBtn = document.getElementById("noBtn");
const result = document.getElementById("result");
let opened = false;
envelopeBtn.addEventListener("click", (e) => {
const target = e.target;
if (target && target.closest(".yn-row")) return;
opened = !opened;
envelopeBtn.classList.toggle("open", opened);
popHearts(opened ? 26 : 10);
});
const noFlash = document.getElementById("noFlash");
const noMessages = [
"Are you sure?",
"Really????.",
"Regan, please.",
"This is your last chance.",
"No option has been revoked. I love you ❤️"
];
let noClicks = 0;
let flashTimer = null;
function flashNoMessage(text) {
if (!noFlash) return;
noFlash.textContent = text;
noFlash.classList.remove("show");
// force reflow so the animation can retrigger each time
void noFlash.offsetWidth;
noFlash.classList.add("show");
clearTimeout(flashTimer);
flashTimer = setTimeout(() => noFlash.classList.remove("show"), 1100);
}
noBtn.addEventListener("click", (e) => {
e.stopPropagation();
noClicks += 1;
const idx = Math.min(noClicks - 1, noMessages.length - 1);
flashNoMessage(noMessages[idx]);
// On the 5th click: disappear entirely
if (noClicks >= 5) {
noBtn.style.display = "none";
popHearts(18);
return;
}
const body = document.querySelector(".letter-body");
const bodyRect = body.getBoundingClientRect();
const btnRect = noBtn.getBoundingClientRect();
const margin = 10;
const boxLeft = bodyRect.left + margin;
const boxRight = bodyRect.right - margin;
const boxTop = bodyRect.top + margin;
const boxBottom = bodyRect.bottom - margin;
// Compute the allowed top-left range for the button so it fully fits
const minX = boxLeft;
const maxX = boxRight - btnRect.width;
const minY = boxTop;
const maxY = boxBottom - btnRect.height;
if (maxX <= minX || maxY <= minY) return;
// Choose a random position where the button fully fits
const targetX = minX + Math.random() * (maxX - minX);
const targetY = minY + Math.random() * (maxY - minY);
const dx = targetX - btnRect.left;
const dy = targetY - btnRect.top;
noBtn.style.position = "relative";
noBtn.style.left = "0px";
noBtn.style.top = "0px";
noBtn.style.transform = `translate(${dx}px, ${dy}px)`;
popHearts(10);
});
yesBtn.addEventListener("click", (e) => {
e.stopPropagation();
result.hidden = false;
result.textContent = "YAY 💖 okay cool you’re stuck with me.";
// Big celebration: raining hearts
startHeartRain();
popHearts(55);
// After the celebration, reset everything back to the start
setTimeout(() => {
resetCardToStart();
}, 3000);
});
const heartRain = document.getElementById("heartRain");
function startHeartRain(durationMs = 2600, intensity = 80) {
if (!heartRain) return;
const emojis = ["❤️", "💗", "💘", "💞", "💖", "💕"];
heartRain.innerHTML = "";
document.body.classList.add("raining");
const heartsPerSecond = Math.min(70, Math.max(80, intensity));
const tickMs = 70; // spawn in little "bursts"
const heartsPerTick = Math.max(2, Math.round((heartsPerSecond * tickMs) / 1000));
// Hard cap to prevent lag
const MAX_HEARTS_ON_SCREEN = 180;
const spawnBatch = () => {
if (heartRain.childElementCount > MAX_HEARTS_ON_SCREEN) return;
for (let i = 0; i < heartsPerTick; i++) {
const h = document.createElement("span");
h.className = "rain-heart";
h.textContent = emojis[Math.floor(Math.random() * emojis.length)];
const x = Math.random() * window.innerWidth;
const drift = (Math.random() - 0.5) * 220;
const dur = 1200 + Math.random() * 900;
const size = 16 + Math.random() * 22;
const rot = (Math.random() - 0.5) * 520;
h.style.left = `${x}px`;
h.style.fontSize = `${size}px`;
h.style.setProperty("--drift", `${drift}px`);
h.style.setProperty("--dur", `${dur}ms`);
h.style.setProperty("--rot", `${rot}deg`);
heartRain.appendChild(h);
h.addEventListener("animationend", () => h.remove());
}
};
const timer = setInterval(spawnBatch, tickMs);
setTimeout(() => {
clearInterval(timer);
// Let remaining hearts finish, then clear
setTimeout(() => {
heartRain.innerHTML = "";
document.body.classList.remove("raining");
}, 900);
}, durationMs);
}
function resetCardToStart() {
// Reset envelope
opened = false;
envelopeBtn.classList.remove("open");
// Reset "Yes" result message
result.hidden = true;
result.textContent = "";
// Reset "No" behavior
if (typeof noClicks !== "undefined") noClicks = 0;
if (noBtn) {
noBtn.style.display = "";
noBtn.style.transform = "";
noBtn.style.position = "";
noBtn.style.left = "";
noBtn.style.top = "";
}
if (typeof noFlash !== "undefined" && noFlash) {
noFlash.textContent = "";
noFlash.classList.remove("show");
}
}