Skip to content

Instantly share code, notes, and snippets.

@jheitzeb
Created May 30, 2025 18:27
Show Gist options
  • Save jheitzeb/0171d64628d2a36e75082a0ab5a6bbc7 to your computer and use it in GitHub Desktop.
Save jheitzeb/0171d64628d2a36e75082a0ab5a6bbc7 to your computer and use it in GitHub Desktop.
Fireworks show
let lastFireworksTime = 0;
let originalBodyProperties = {};
function perform_fireworks_show() {
console.log("Starting fireworks show");
// Store original body properties
originalBodyProperties = {
backgroundColor: $("body").css("background-color"),
opacity: $("body").css("opacity")
};
// First, remove any existing fireworks elements
cleanup_fireworks();
// Create our container that will hold all fireworks
const container = document.createElement('div');
container.id = 'fireworks-container';
Object.assign(container.style, {
position: 'fixed',
top: '0',
left: '0',
width: '100vw',
height: '100vh',
pointerEvents: 'none',
zIndex: '2147483647', // Maximum z-index possible
overflow: 'visible'
});
document.body.appendChild(container);
console.log("Fireworks container created and appended to body");
// Dim the screen with a separate overlay
const overlay = document.createElement('div');
overlay.id = 'fireworks-background-overlay';
Object.assign(overlay.style, {
position: 'fixed',
top: '0',
left: '0',
width: '100vw',
height: '100vh',
backgroundColor: '#190000',
opacity: '0.9',
pointerEvents: 'none',
zIndex: '2147483646' // Just below the fireworks container
});
document.body.appendChild(overlay);
console.log("Background overlay created");
// Debounce
const now = Date.now();
if (now - lastFireworksTime < 500) {
return;
}
lastFireworksTime = now;
// Play sound if function exists
if (typeof play_fireworks_sound === 'function') {
play_fireworks_sound();
}
// Create fireworks
let fireworkCount = 0;
const maxFireworks = 10;
const displayDuration = 3000;
// Create an initial burst
for (let i = 0; i < 5; i++) {
setTimeout(() => {
console.log(`Creating initial firework ${i}`);
createFirework(container);
}, i * 100);
}
// Continue creating fireworks
const interval = setInterval(() => {
console.log(`Creating additional firework ${fireworkCount}`);
createFirework(container);
fireworkCount++;
if (fireworkCount >= maxFireworks) {
clearInterval(interval);
}
}, 200);
// End the show after the display duration
setTimeout(() => {
cleanup_fireworks();
// Restore original body properties
$("body").fadeTo(100, originalBodyProperties.opacity || 1);
$("body").css("background-color", originalBodyProperties.backgroundColor || "");
console.log("Fireworks show ended, original properties restored");
}, displayDuration);
}
// please download https://aitinkerers.org/assets/sounds/fireworks2.m4a and rehost it
function play_fireworks_sound() {
play_mp3("fireworks2.m4a", 0.8);
}
function createFirework(container) {
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
// Launch position
const startX = Math.random() * (viewportWidth * 0.8) + (viewportWidth * 0.1);
const startY = viewportHeight;
// Explosion position
const endX = startX + (Math.random() * 200 - 100);
const endY = viewportHeight * 0.3 + (Math.random() * viewportHeight * 0.4);
// Create firework element
const firework = document.createElement('div');
firework.className = 'firework';
Object.assign(firework.style, {
position: 'absolute',
width: '6px',
height: '6px',
borderRadius: '50%',
backgroundColor: 'white',
boxShadow: '0 0 10px 2px white',
left: `${startX}px`,
top: `${startY}px`
});
container.appendChild(firework);
console.log(`Firework created at ${startX},${startY} heading to ${endX},${endY}`);
// Animate the firework's ascent
const animation = firework.animate([
{ transform: 'translate(0, 0)', opacity: 1 },
{ transform: `translate(${endX - startX}px, ${endY - startY}px)`, opacity: 0.8 }
], {
duration: 700,
easing: 'cubic-bezier(0.5, 0, 0.5, 1)'
});
animation.onfinish = () => {
// Create explosion when firework reaches top
createExplosion(container, endX, endY);
firework.remove();
};
}
function createExplosion(container, x, y) {
console.log(`Creating explosion at ${x},${y}`);
// Pick a color for this explosion
const hue = Math.floor(Math.random() * 360);
// Create particles
for (let i = 0; i < 30; i++) {
const particle = document.createElement('div');
particle.className = 'particle';
Object.assign(particle.style, {
position: 'absolute',
width: '4px',
height: '4px',
borderRadius: '50%',
backgroundColor: `hsl(${hue}, 100%, 60%)`,
boxShadow: `0 0 8px 2px hsl(${hue}, 100%, 70%)`,
left: `${x}px`,
top: `${y}px`
});
container.appendChild(particle);
// Determine particle trajectory
const angle = (Math.PI * 2 * i) / 30;
const distance = 30 + Math.random() * 70;
const duration = 800 + Math.random() * 400;
const particleX = Math.cos(angle) * distance;
const particleY = Math.sin(angle) * distance;
// Animate particle
particle.animate([
{ transform: 'translate(0, 0) scale(1)', opacity: 1 },
{ transform: `translate(${particleX}px, ${particleY}px) scale(0)`, opacity: 0 }
], {
duration: duration,
easing: 'cubic-bezier(0, 0.5, 0.5, 1)'
}).onfinish = () => particle.remove();
}
}
function cleanup_fireworks() {
console.log("Cleaning up fireworks");
// Remove container and all fireworks
const container = document.getElementById('fireworks-container');
if (container) container.remove();
// Remove background overlay
const overlay = document.getElementById('fireworks-background-overlay');
if (overlay) overlay.remove();
// Remove any stray fireworks or particles
document.querySelectorAll('.firework, .particle').forEach(el => el.remove());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment