Ai Fireworks Code
This was made in Google Gemini app, within the Canvas using Gemini Pro
<!DOCTYPE html>
<div id="fireworks-container" style="width: 100%; height: 600px; background-color: transparent; overflow: hidden; position: relative;">
<canvas id="fireworks-canvas-block"></canvas>
<script>
// Use a self-executing function to keep variables local and avoid conflicts
(function() {
const container = document.getElementById('fireworks-container');
const canvas = document.getElementById('fireworks-canvas-block');
const ctx = canvas.getContext('2d');
// Define core variables, scoped locally
const rockets = [];
const particles = [];
const stars = [];
const GRAVITY = 0.05;
const FRICTION = 0.985;
let width, height;
/** Utility function to get a random number within a range. */
function randomRange(min, max) {
return Math.random() * (max - min) + min;
}
/** Utility function to generate a vibrant HSL color string. */
function randomColor() {
const h = randomRange(0, 360);
return `hsl(${h}, 95%, 70%)`;
}
// --- Star Class for Twinkling Background ---
class Star {
constructor(x, y, radius) {
this.x = x;
this.y = y;
this.radius = radius;
this.alpha = randomRange(0.2, 0.7);
this.oscillationSpeed = randomRange(0.005, 0.015);
this.oscillationOffset = Math.random() * Math.PI * 2;
}
update() {
// Subtle twinkling effect by oscillating alpha
// Using Date.now() for simple time-based oscillation without a global counter
this.alpha = randomRange(0.2, 0.7) + Math.sin(Date.now() * this.oscillationSpeed + this.oscillationOffset) * 0.2;
}
draw() {
ctx.save();
ctx.fillStyle = `rgba(255, 255, 255, ${this.alpha})`;
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
ctx.fill();
ctx.restore();
}
}
// --- Particle Class for Explosion Debris ---
class Particle {
constructor(x, y, color, angle, speed, friction, gravity, sizeMultiplier = 1) {
this.x = x;
this.y = y;
this.color = color;
this.friction = friction;
this.gravity = gravity;
this.alpha = 1;
this.decay = randomRange(0.015, 0.035);
this.size = randomRange(1, 3) * sizeMultiplier;
this.windX = randomRange(-0.01, 0.01);
this.velX = Math.cos(angle) * speed;
this.velY = Math.sin(angle) * speed;
}
update() {
this.velX = this.velX * this.friction + this.windX;
this.velY *= this.friction;
this.velY += this.gravity;
this.x += this.velX;
this.y += this.velY;
this.alpha -= this.decay;
}
draw() {
ctx.save();
ctx.globalAlpha = this.alpha;
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
}
}
// --- Rocket Class for Launching Firework ---
class Rocket {
constructor(startX, startY, targetX, targetY) {
this.x = startX;
this.y = startY;
this.targetX = targetX;
this.targetY = targetY;
this.color = randomColor();
const dx = targetX - startX;
const dy = targetY - startY;
const distance = Math.sqrt(dx * dx + dy * dy);
const speed = distance / randomRange(45, 70);
this.velX = dx / distance * speed;
this.velY = dy / distance * speed;
this.exploded = false;
this.trail = [];
// Determine a size multiplier for the resulting explosion (0.5 to 1.5)
this.sizeMultiplier = randomRange(0.5, 1.5);
}
update() {
if (this.exploded) return;
// Check for explosion condition
if (this.y < this.targetY || this.velY > 0) {
this.explode();
return;
}
this.velY += GRAVITY * 0.5;
this.x += this.velX;
this.y += this.velY;
// Add current position to trail
this.trail.push({ x: this.x, y: this.y, color: this.color });
if (this.trail.length > 8) {
this.trail.shift();
}
}
draw() {
if (this.exploded) return;
// Draw the trail
ctx.strokeStyle = this.color;
ctx.lineWidth = randomRange(1, 3) * Math.min(this.sizeMultiplier, 1);
ctx.beginPath();
if (this.trail.length > 1) {
ctx.moveTo(this.trail[0].x, this.trail[0].y);
for (let i = this.trail.length - 1; i >= 0; i--) {
ctx.globalAlpha = 0.1 + (i / this.trail.length) * 0.9;
ctx.lineTo(this.trail[i].x, this.trail[i].y);
}
}
ctx.stroke();
ctx.globalAlpha = 1;
// Draw the head of the rocket (brighter point with glow)
ctx.fillStyle = this.color;
ctx.shadowBlur = 15;
ctx.shadowColor = this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, 3, 0, Math.PI * 2);
ctx.fill();
ctx.shadowBlur = 0;
ctx.shadowColor = 'transparent';
}
explode() {
this.exploded = true;
const particleCount = Math.floor(randomRange(100, 200) * this.sizeMultiplier);
const color = this.color;
for (let i = 0; i < particleCount; i++) {
const angle = randomRange(0, Math.PI * 2);
const speed = randomRange(2, 12) * this.sizeMultiplier;
particles.push(new Particle(
this.x,
this.y,
color,
angle,
speed,
FRICTION,
GRAVITY,
this.sizeMultiplier
));
}
}
}
// --- Star Generation ---
function createStars(count) {
for (let i = 0; i < count; i++) {
stars.push(new Star(
randomRange(0, width),
randomRange(0, height * 0.7),
randomRange(0.5, 1.5)
));
}
}
function drawStars() {
for (let i = 0; i < stars.length; i++) {
stars[i].update();
stars[i].draw();
}
}
// --- Main Functions ---
function resizeCanvas() {
// Resize based on the container size, not the window
width = canvas.width = container.clientWidth;
height = canvas.height = container.clientHeight;
// Clear and recreate stars on resize
stars.length = 0;
createStars(200);
}
function draw() {
// Completely clear the canvas for transparency
ctx.clearRect(0, 0, width, height);
// Draw Stars (will stay static relative to the canvas)
drawStars();
// Update and Draw Rockets
for (let i = rockets.length - 1; i >= 0; i--) {
const rocket = rockets[i];
rocket.update();
rocket.draw();
if (rocket.exploded) {
rockets.splice(i, 1);
}
}
// Update and Draw Particles
ctx.shadowBlur = 10;
ctx.shadowColor = 'white';
for (let i = particles.length - 1; i >= 0; i--) {
const particle = particles[i];
particle.update();
particle.draw();
if (particle.alpha <= particle.decay) {
particles.splice(i, 1);
}
}
ctx.shadowBlur = 0;
ctx.shadowColor = 'transparent';
}
function animate() {
draw();
requestAnimationFrame(animate);
}
function launchFirework(x, y) {
const targetY = Math.min(y, height * 0.8);
rockets.push(new Rocket(
width / 2,
height,
x,
targetY
));
}
function autoLaunchFirework() {
// Random X coordinate (across the whole width)
const randomX = randomRange(width * 0.1, width * 0.9);
// Random Y coordinate (in the top half of the screen for explosion height)
const randomY = randomRange(height * 0.1, height * 0.5);
launchFirework(randomX, randomY);
}
/**
* Starts the animation loop and automatic launches.
*/
function startGame() {
// Start the automatic firework show loop
setInterval(autoLaunchFirework, randomRange(500, 1500));
// Start the animation loop
animate();
}
// --- Event Listeners and Initialization ---
// Observer to handle container resizing (e.g., if the user changes the column width in WP)
const resizeObserver = new ResizeObserver(entries => {
for (let entry of entries) {
if (entry.target === container) {
resizeCanvas();
}
}
});
resizeObserver.observe(container);
window.addEventListener('load', function() {
resizeCanvas(); // Initial setup
startGame();
});
})(); // End of self-executing function
</script>
</div>