Fazbeeer commited on
Commit
ae8d839
·
verified ·
1 Parent(s): e912ee9

<canvas id="fireworksCanvas"></canvas>

Browse files

<style>
#fireworksCanvas {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
pointer-events: none; /* 👈 allows clicking through */
z-index: 9999; /* 👈 stays on top */
}
</style>
<script>
const canvas = document.getElementById('fireworksCanvas');
const ctx = canvas.getContext('2d');

function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
window.addEventListener('resize', resizeCanvas);
resizeCanvas();

const fireworks = [];
const particles = [];

class Firework {
constructor(x) {
this.x = x;
this.y = canvas.height;
this.targetY = Math.random() * canvas.height * 0.4 + canvas.height * 0.1;
this.speed = Math.random() * 4 + 4;
this.hue = Math.random() * 360;
}
update() {
this.y -= this.speed;
if (this.y <= this.targetY) {
explode(this.x, this.y, this.hue);
return false;
}
return true;
}
draw() {
ctx.fillStyle = `hsl(${this.hue}, 100%, 60%)`;
ctx.beginPath();
ctx.arc(this.x, this.y, 3, 0, Math.PI
<script>
const canvas = document.getElementById('fireworksCanvas');
const ctx = canvas.getContext('2d');

function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
window.addEventListener('resize', resizeCanvas);
resizeCanvas();

const fireworks = [];
const particles = [];

class Firework {
constructor(x) {
this.x = x;
this.y = canvas.height;
this.targetY = Math.random() * canvas.height * 0.4 + canvas.height * 0.1;
this.speed = Math.random() * 4 + 4;
this.hue = Math.random() * 360;
}
update() {
this.y -= this.speed;
if (this.y <= this.targetY) {
explode(this.x, this.y, this.hue);
return false;
}
return true;
}
draw() {
ctx.fillStyle = `hsl(${this.hue}, 100%, 60%)`;
ctx.beginPath();
ctx.arc(this.x, this.y, 3, 0, Math.PI * 2);
ctx.fill();
}
}

class Particle {
constructor(x, y, hue) {
this.x = x;
this.y = y;
const angle = Math.random() * Math.PI * 2;
const speed = Math.random() * 5 + 1;
this.vx = Math.cos(angle) * speed;
this.vy = Math.sin(angle) * speed;
this.alpha = 1;
this.hue = hue;
}
update() {
this.x += this.vx;
this.y += this.vy;
this.vy += 0.04;
this.alpha -= 0.015;
return this.alpha > 0;
}
draw() {
ctx.fillStyle = `hsla(${this.hue}, 100%, 60%, ${this.alpha})`;
ctx.beginPath();
ctx.arc(this.x, this.y, 2, 0, Math.PI * 2);
ctx.fill();
}
}

function explode(x, y, hue) {
for (let i = 0; i < 80; i++) {
particles.push(new Particle(x, y, hue));
}
}

function animate() {
// transparent fade for trails
ctx.clearRect(0, 0, canvas.width, canvas.height);

if (Math.random() < 0.05) {
fireworks.push(new Firework(Math.random() * canvas.width));
}

for (let i = fireworks.length - 1; i >= 0; i--) {
if (!fireworks[i].update()) fireworks.splice(i, 1);
}

for (let i = particles.length - 1; i >= 0; i--) {
if (!particles[i].update()) particles.splice(i, 1);
}

fireworks.forEach(f => f.draw());
particles.forEach(p => p.draw());

requestAnimationFrame(animate);
}

animate();
</script>

Files changed (2) hide show
  1. components/fireworks-animation.js +139 -0
  2. index.html +4 -2
components/fireworks-animation.js ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class FireworksAnimation extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ :host {
7
+ display: block;
8
+ position: fixed;
9
+ top: 0;
10
+ left: 0;
11
+ width: 100%;
12
+ height: 100%;
13
+ pointer-events: none;
14
+ z-index: 9997;
15
+ }
16
+ canvas {
17
+ display: block;
18
+ background: transparent;
19
+ }
20
+ </style>
21
+ <canvas id="fireworks"></canvas>
22
+ `;
23
+
24
+ const canvas = this.shadowRoot.getElementById('fireworks');
25
+ const ctx = canvas.getContext('2d');
26
+
27
+ function resize() {
28
+ canvas.width = window.innerWidth;
29
+ canvas.height = window.innerHeight;
30
+ }
31
+ resize();
32
+ window.addEventListener('resize', resize);
33
+
34
+ let rockets = [];
35
+ let particles = [];
36
+ let lastLaunch = Date.now();
37
+
38
+ class Rocket {
39
+ constructor() {
40
+ this.x = Math.random() * canvas.width;
41
+ this.y = canvas.height;
42
+ this.vy = -8 - Math.random() * 3;
43
+ this.exploded = false;
44
+ this.color = `hsl(${Math.random() * 60 + 0}, 100%, 50%)`;
45
+ }
46
+ }
47
+
48
+ class Particle {
49
+ constructor(x, y, color) {
50
+ this.x = x;
51
+ this.y = y;
52
+ const angle = Math.random() * Math.PI * 2;
53
+ const speed = Math.random() * 5 + 3;
54
+ this.vx = Math.cos(angle) * speed;
55
+ this.vy = Math.sin(angle) * speed;
56
+ this.life = 120;
57
+ this.alpha = 1;
58
+ this.color = color;
59
+ }
60
+
61
+ update() {
62
+ this.x += this.vx;
63
+ this.y += this.vy;
64
+ this.vy += 0.04; // gravity
65
+ this.life--;
66
+ this.alpha = this.life / 120;
67
+ }
68
+
69
+ draw(ctx) {
70
+ ctx.beginPath();
71
+ ctx.arc(this.x, this.y, 2, 0, Math.PI * 2);
72
+ ctx.fillStyle = `${this.color.replace(')', `, ${this.alpha})`).replace('hsl', 'hsla')}`;
73
+ ctx.shadowBlur = 10;
74
+ ctx.shadowColor = this.color;
75
+ ctx.fill();
76
+ }
77
+ }
78
+
79
+ function explode(x, y, color) {
80
+ const count = 180;
81
+ for (let i = 0; i < count; i++) {
82
+ const angle = (Math.PI * 2) * (i / count);
83
+ const speed = Math.random() * 5 + 3;
84
+ particles.push(new Particle(x, y, color));
85
+ }
86
+ }
87
+
88
+ function launchRocket() {
89
+ rockets.push(new Rocket());
90
+ lastLaunch = Date.now();
91
+ }
92
+
93
+ function animate() {
94
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
95
+
96
+ // Launch new rocket randomly
97
+ if (Date.now() - lastLaunch > 2000 + Math.random() * 3000) {
98
+ launchRocket();
99
+ }
100
+
101
+ // Update rockets
102
+ rockets.forEach((rocket, i) => {
103
+ rocket.y += rocket.vy;
104
+
105
+ // Draw rocket trail
106
+ ctx.beginPath();
107
+ ctx.moveTo(rocket.x, rocket.y + 30);
108
+ ctx.lineTo(rocket.x, rocket.y);
109
+ ctx.strokeStyle = "rgba(255,255,255,0.8)";
110
+ ctx.lineWidth = 2;
111
+ ctx.stroke();
112
+
113
+ // Check for explosion
114
+ if (rocket.y < canvas.height * (0.3 + Math.random() * 0.3)) {
115
+ explode(rocket.x, rocket.y, rocket.color);
116
+ rockets.splice(i, 1);
117
+ }
118
+ });
119
+
120
+ // Update particles
121
+ particles.forEach((p, i) => {
122
+ p.update();
123
+ p.draw(ctx);
124
+ if (p.life <= 0) particles.splice(i, 1);
125
+ });
126
+
127
+ requestAnimationFrame(animate);
128
+ }
129
+
130
+ // Initial launch and set timeout to remove element
131
+ setTimeout(launchRocket, 500);
132
+ animate();
133
+ setTimeout(() => {
134
+ this.remove();
135
+ }, 6000);
136
+ }
137
+ }
138
+
139
+ customElements.define('fireworks-animation', FireworksAnimation);
index.html CHANGED
@@ -397,14 +397,16 @@ Get Started Now
397
  <script src="components/fireworks.js"></script>
398
  <script src="components/amplify-2026.js"></script>
399
  <script src="components/newsletter.js"></script>
 
400
  <!-- Add i18next libraries -->
401
  <script src="https://unpkg.com/i18next/dist/umd/i18next.min.js"></script>
402
  <script src="https://unpkg.com/i18next-browser-languagedetector/i18nextBrowserLanguageDetector.js"></script>
403
  <script src="https://unpkg.com/i18next-http-backend/i18nextHttpBackend.js"></script>
404
-
 
405
  <script>
406
  // Initialize i18next with translations
407
- i18next
408
  .use(i18nextBrowserLanguageDetector)
409
  .init({
410
  fallbackLng: 'en',
 
397
  <script src="components/fireworks.js"></script>
398
  <script src="components/amplify-2026.js"></script>
399
  <script src="components/newsletter.js"></script>
400
+ <script src="components/fireworks-animation.js"></script>
401
  <!-- Add i18next libraries -->
402
  <script src="https://unpkg.com/i18next/dist/umd/i18next.min.js"></script>
403
  <script src="https://unpkg.com/i18next-browser-languagedetector/i18nextBrowserLanguageDetector.js"></script>
404
  <script src="https://unpkg.com/i18next-http-backend/i18nextHttpBackend.js"></script>
405
+ <fireworks-animation></fireworks-animation>
406
+
407
  <script>
408
  // Initialize i18next with translations
409
+ i18next
410
  .use(i18nextBrowserLanguageDetector)
411
  .init({
412
  fallbackLng: 'en',