Skip to content

Commit 73ed13b

Browse files
Add files via upload
1 parent 0b933f1 commit 73ed13b

File tree

1 file changed

+271
-0
lines changed

1 file changed

+271
-0
lines changed

happy-mothers-day/index.html

Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Happy Mothers' Day</title>
5+
<style>
6+
body {
7+
margin: 0;
8+
padding: 0;
9+
font-family: consolas;
10+
background-color: black;
11+
overflow: hidden;
12+
}
13+
#fireworkCanvas {
14+
position: fixed;
15+
top: 0;
16+
left: 0;
17+
z-index: 1;
18+
}
19+
.message {
20+
position: fixed;
21+
top: 50%;
22+
left: 50%;
23+
transform: translate(-50%, -50%);
24+
color: white;
25+
font-size: 3em;
26+
text-align: center;
27+
z-index: 2;
28+
pointer-events: none;
29+
opacity: 1;
30+
transition: opacity 3s;
31+
}
32+
#fpsCounter {
33+
position: fixed;
34+
bottom: 10px;
35+
right: 10px;
36+
color: white;
37+
z-index: 3;
38+
}
39+
</style>
40+
</head>
41+
<body>
42+
<canvas id="fireworkCanvas"></canvas>
43+
<div class="message" id="message">Happy Mothers' Day!</div>
44+
<div id="fpsCounter"></div>
45+
46+
<script>
47+
(function() {
48+
// Performance monitoring
49+
let frameCount = 0;
50+
let lastFpsUpdate = 0;
51+
const fpsElement = document.getElementById('fpsCounter');
52+
53+
// Canvas setup
54+
const canvas = document.getElementById('fireworkCanvas');
55+
const ctx = canvas.getContext('2d');
56+
57+
// Particle system constants
58+
const MAX_PARTICLES = 2000;
59+
const FPS = 60;
60+
const frameInterval = 1000 / FPS;
61+
let lastTime = 0;
62+
63+
// Initialize canvas
64+
function initCanvas() {
65+
canvas.width = window.innerWidth;
66+
canvas.height = window.innerHeight;
67+
}
68+
initCanvas();
69+
window.addEventListener('resize', initCanvas);
70+
71+
// Particle pool
72+
const particlePool = [];
73+
let particles = [];
74+
let autoFireworkInterval;
75+
let isStopping = false;
76+
let currentInterval = 300; // Initial firework interval
77+
78+
// Get random color
79+
function getRandomColor() {
80+
const r = Math.floor(Math.random() * 205) + 50;
81+
const g = Math.floor(Math.random() * 205) + 50;
82+
const b = Math.floor(Math.random() * 205) + 50;
83+
return `rgb(${r}, ${g}, ${b})`;
84+
}
85+
86+
// Get particle from pool or create new
87+
function getParticle() {
88+
if (particlePool.length > 0) {
89+
return particlePool.pop();
90+
}
91+
return {
92+
x: 0, y: 0, radius: 0, color: '',
93+
velocity: { x: 0, y: 0 },
94+
alpha: 1, decay: 0, gravity: 0
95+
};
96+
}
97+
98+
// Recycle particle
99+
function recycleParticle(p) {
100+
if (particlePool.length < MAX_PARTICLES) {
101+
particlePool.push(p);
102+
}
103+
}
104+
105+
// Create firework with more random position
106+
function createFirework(x, y, isRandom = true) {
107+
if (particles.length > MAX_PARTICLES * 0.9) return;
108+
109+
// If position not specified, generate random position
110+
if (isRandom) {
111+
x = Math.random() * (canvas.width * 0.7) + canvas.width * 0.15;
112+
y = Math.random() * (canvas.height * 0.7) + canvas.height * 0.15;
113+
} else {
114+
x = Math.random() * canvas.width;
115+
y = Math.random() * canvas.height;
116+
}
117+
118+
const radius = Math.random() * 30 + 30;
119+
const particleCount = Math.min(Math.floor(radius * 8), MAX_PARTICLES - particles.length);
120+
const color = getRandomColor();
121+
122+
for (let i = 0; i < particleCount; i++) {
123+
const angle = Math.random() * Math.PI * 2;
124+
const speed = Math.random() * 5 + 2;
125+
126+
const p = getParticle();
127+
p.x = x;
128+
p.y = y;
129+
p.radius = Math.random() * 3 + 1;
130+
p.color = color;
131+
p.velocity.x = Math.cos(angle) * speed;
132+
p.velocity.y = Math.sin(angle) * speed;
133+
p.alpha = 1;
134+
p.decay = Math.random() * 0.01 + 0.005;
135+
p.gravity = 0.02 + Math.random() * 0.03;
136+
137+
particles.push(p);
138+
}
139+
}
140+
141+
// Start auto fireworks with better distribution
142+
function startAutoFireworks() {
143+
clearInterval(autoFireworkInterval);
144+
145+
autoFireworkInterval = setInterval(() => {
146+
if (isStopping) {
147+
// Gradually increase interval to slow down firework generation
148+
currentInterval += 50;
149+
if (currentInterval > 2000) {
150+
clearInterval(autoFireworkInterval);
151+
return;
152+
}
153+
clearInterval(autoFireworkInterval);
154+
startAutoFireworks();
155+
}
156+
157+
// Create firework at random position
158+
createFirework();
159+
160+
}, currentInterval);
161+
162+
// Initial fireworks in different positions
163+
createFirework(canvas.width * 0.2, canvas.height * 0.3, false);
164+
createFirework(canvas.width * 0.5, canvas.height * 0.4, false);
165+
createFirework(canvas.width * 0.8, canvas.height * 0.35, false);
166+
createFirework(canvas.width * 0.3, canvas.height * 0.25, false);
167+
createFirework(canvas.width * 0.7, canvas.height * 0.3, false);
168+
}
169+
170+
// Smoothly stop fireworks
171+
function stopFireworksSmoothly() {
172+
isStopping = true;
173+
174+
// After a while, increase particle decay to make them fade faster
175+
setTimeout(() => {
176+
particles.forEach(p => {
177+
p.decay += 0.01;
178+
});
179+
}, 2000);
180+
}
181+
182+
// Update particles
183+
function updateParticles() {
184+
for (let i = particles.length - 1; i >= 0; i--) {
185+
const p = particles[i];
186+
187+
p.x += p.velocity.x;
188+
p.y += p.velocity.y;
189+
p.velocity.y += p.gravity;
190+
p.velocity.y *= 0.99;
191+
p.alpha -= p.decay;
192+
193+
if (p.alpha <= 0) {
194+
recycleParticle(particles[i]);
195+
particles.splice(i, 1);
196+
}
197+
}
198+
}
199+
200+
// Draw particles
201+
function drawParticles() {
202+
ctx.save();
203+
for (let i = 0, len = particles.length; i < len; i++) {
204+
const p = particles[i];
205+
206+
ctx.beginPath();
207+
ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2);
208+
209+
const gradient = ctx.createRadialGradient(
210+
p.x, p.y, 0,
211+
p.x, p.y, p.radius
212+
);
213+
gradient.addColorStop(0, p.color.replace(')', `, ${p.alpha})`).replace('rgb', 'rgba'));
214+
gradient.addColorStop(1, 'rgba(0,0,0,0)');
215+
216+
ctx.fillStyle = gradient;
217+
ctx.fill();
218+
}
219+
ctx.restore();
220+
}
221+
222+
// Animation loop
223+
function animate(timestamp) {
224+
// Throttle FPS
225+
if (timestamp - lastTime < frameInterval) {
226+
requestAnimationFrame(animate);
227+
return;
228+
}
229+
lastTime = timestamp;
230+
231+
// Update FPS counter
232+
frameCount++;
233+
if (timestamp - lastFpsUpdate >= 1000) {
234+
fpsElement.textContent = `FPS: ${frameCount}`;
235+
frameCount = 0;
236+
lastFpsUpdate = timestamp;
237+
}
238+
239+
// Clear with trail effect
240+
ctx.fillStyle = 'rgba(0, 0, 0, 0.1)';
241+
ctx.fillRect(0, 0, canvas.width, canvas.height);
242+
243+
updateParticles();
244+
drawParticles();
245+
246+
requestAnimationFrame(animate);
247+
}
248+
249+
// Start animation
250+
startAutoFireworks();
251+
animate(0);
252+
253+
// Message fade out and start smooth stopping
254+
setTimeout(() => {
255+
document.getElementById('message').style.opacity = 0;
256+
setTimeout(stopFireworksSmoothly, 1000);
257+
}, 3000);
258+
259+
setTimeout(() => {
260+
document.getElementById('message').style.display = 'none';
261+
}, 6000);
262+
263+
// Click to create firework at mouse position
264+
canvas.addEventListener('click', (e) => {
265+
createFirework(e.clientX, e.clientY, false);
266+
});
267+
268+
})();
269+
</script>
270+
</body>
271+
</html>

0 commit comments

Comments
 (0)