Fireworks · gemini-3-flash-preview
Create a fireworks display on a full-screen canvas where clicks launch shells that explode into gravity-affected, fading particle bursts.
transcript · 4 messages
Create a fireworks display on a full-screen canvas where clicks launch shells that explode into gravity-affected, fading particle bursts.
thinking
**Developing Fireworks App** I'm currently focused on building a self-contained, single-page web app for a dynamic fireworks display. My efforts are concentrated on creating a full-screen canvas element that will host the entire visual experience, ensuring it's immersive and responsive.
index.html (5369 bytes)Successfully wrote 5369 bytes to index.html
thinking
**Launching fireworks, exploring code** I've successfully implemented the fireworks display in `index.html`. My focus has been on integrating the full-screen canvas and ensuring that user clicks or touches accurately trigger the launch of visually appealing, gravity-affected, and fading shells.
The fireworks display has been created in a single self-contained `index.html` file. This implementation includes: - A **full-screen canvas** that adjusts to window resizing. - **Shell physics**: Launching from the bottom and traveling toward the click location. - **Explosion system**: Bursting into multiple particles with unique colors using HSL for vibrancy. - **Particle physics**: Affected by gravity, air friction, and fading over time. - **Trail effect**: Using semi-transparent clearing to create a "motion blur" or light trail behind moving sparks. - **Auto-launch**: A background timer that occasionally starts fireworks to keep the screen alive. You can open `index.html` in any modern web browser to view the display. ```html <!-- index.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Fireworks Display</title> <style> body, html { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; background-color: #000; } canvas { display: block; } #instructions { position: absolute; top: 20px; left: 20px; color: rgba(255, 255, 255, 0.5); font-family: sans-serif; pointer-events: none; user-select: none; } </style> </head> <body> <div id="instructions">Click to launch fireworks!</div> <canvas id="canvas"></canvas> <script> const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); let width, height; function resize() { width = window.innerWidth; height = window.innerHeight; canvas.width = width; canvas.height = height; } window.addEventListener('resize', resize); resize(); class Particle { constructor(x, y, color) { this.x = x; this.y = y; this.color = color; const angle = Math.random() * Math.PI * 2; const speed = Math.random() * 5 + 2; this.vx = Math.cos(angle) * speed; this.vy = Math.sin(angle) * speed; this.alpha = 1; this.friction = 0.95; this.gravity = 0.15; this.decay = Math.random() * 0.015 + 0.015; } update() { this.vx *= this.friction; this.vy *= this.friction; this.vy += this.gravity; this.x += this.vx; this.y += this.vy; this.alpha -= this.decay; } draw() { ctx.save(); ctx.globalAlpha = this.alpha; ctx.fillStyle = this.color; ctx.beginPath(); ctx.arc(this.x, this.y, 2, 0, Math.PI * 2); ctx.fill(); ctx.restore(); } isAlive() { return this.alpha > 0; } } class Shell { constructor(tx, ty) { this.x = Math.random() * width; this.y = height; this.tx = tx; this.ty = ty; const angle = Math.atan2(ty - this.y, tx - this.x); const distance = Math.hypot(tx - this.x, ty - this.y); const speed = distance / 40; this.vx = Math.cos(angle) * speed; this.vy = Math.sin(angle) * speed; this.color = `hsl(${Math.random() * 360}, 100%, 60%)`; this.exploded = false; } update() { this.x += this.vx; this.y += this.vy; const distToTarget = Math.hypot(this.tx - this.x, this.ty - this.y); if (distToTarget < 10 || this.vy >= 0) { this.exploded = true; } } draw() { ctx.fillStyle = '#fff'; ctx.beginPath(); ctx.arc(this.x, this.y, 3, 0, Math.PI * 2); ctx.fill(); } } let shells = []; let particles = []; function launch(x, y) { shells.push(new Shell(x, y)); } canvas.addEventListener('mousedown', (e) => { launch(e.clientX, e.clientY); }); canvas.addEventListener('touchstart', (e) => { e.preventDefault(); launch(e.touches[0].clientX, e.touches[0].clientY); }); function animate() { ctx.fillStyle = 'rgba(0, 0, 0, 0.15)'; ctx.fillRect(0, 0, width, height); for (let i = shells.length - 1; i >= 0; i--) { const s = shells[i]; s.update(); s.draw(); if (s.exploded) { for (let j = 0; j < 80; j++) { particles.push(new Particle(s.x, s.y, s.color)); } shells.splice(i, 1); } } for (let i = particles.length - 1; i >= 0; i--) { const p = particles[i]; p.update(); p.draw(); if (!p.isAlive()) { particles.splice(i, 1); } } requestAnimationFrame(animate); } function autoLaunch() { if (shells.length < 3 && Math.random() < 0.05) { launch(Math.random() * width, Math.random() * (height * 0.5)); } } setInterval(autoLaunch, 500); animate(); </script> </body> </html> ```
TAKE IT TO CODE
A single self-contained HTML file — copy it and open in any browser, or reuse the prompt with your own pi-agent run.
RUN
EVALUATION
Click launches a shell that explodes into a colorful particle burst; keyboard input and drag have no visible effect.
Vision grade · anthropic/claude-sonnet-5
MEASUREMENTS
Raw readings from the capture, not a verdict — the grade above is the only judgement. Percentages are how much of the screen changed; the measure under-reports sparse motion on a dark background.