Fireworks · laguna-xs-2.1
Create a fireworks display on a full-screen canvas where clicks launch shells that explode into gravity-affected, fading particle bursts.
transcript · 6 messages
Create a fireworks display on a full-screen canvas where clicks launch shells that explode into gravity-affected, fading particle bursts.
thinking
The user wants me to create a fireworks display web app with: 1. Full-screen canvas 2. Click to launch fireworks shells 3. Explosions that create gravity-affected, fading particle bursts I need to create a self-contained index.html file with: - CSS in a <style> tag - JS in a <script> tag - No external resources - Full-screen canvas - Click event handler to launch shells - Particle physics with gravity - Fading particles Let me design this: - Canvas fills the entire viewport - On click, create a firework shell that travels from bottom to the click position - At the target, explode into particles - Particles should have: - Velocity (spread outward) - Gravity (fall down) - Fade out over time - Random colors - Shell should have a trail I'll write this all in one file.
I'll create a self-contained fireworks display web app with gravity-affected particles. Let me write the complete index.html file.
/workspace/index.html (8983 bytes)Successfully wrote 8983 bytes to /workspace/index.html
thinking
I've created the fireworks display web app. Let me verify the file was written correctly by reading it.
{"path":"/workspace/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> * { margin: 0; padding: 0; box-sizing: border-box; } body { overflow: hidden; background: linear-gradient(135deg, #0a0a2a 0%, #1a0a2a 50%, #0a1a2a 100%); height: 100vh; cursor: pointer; } canvas { display: block; width: 100vw; height: 100vh; } .info { position: fixed; top: 20px; left: 20px; color: white; font-family: Arial, sans-serif; font-size: 14px; background: rgba(0, 0, 0, 0.3); padding: 10px 15px; border-radius: 5px; pointer-events: none; } </style> </head> <body> <canvas id="fireworks"></canvas> <div class="info">Click anywhere to launch fireworks</div> <script> const canvas = document.getElementById('fireworks'); const ctx = canvas.getContext('2d'); // Set canvas size canvas.width = window.innerWidth; canvas.height = window.innerHeight; // Resize handler window.addEventListener('resize', () => { canvas.width = window.innerWidth; canvas.height = window.innerHeight; }); // Fireworks arrays const shells = []; const particles = []; const trails = []; // Colors for fireworks const colors = [ '#ff5252', '#ffca28', '#69f0ae', '#536dfe', '#ff80ab', '#ff8000', '#d500f9', '#00e5ff', '#ff6400', '#76ff03', '#2979ff', '#ff4081' ]; // Utility functions function random(min, max) { return Math.random() * (max - min) + min; } function randomInt(min, max) { return Math.floor(random(min, max)); } // Firework shell class class FireworkShell { constructor(x, y, targetX, targetY) { this.x = x; this.y = y; this.targetX = targetX; this.targetY = targetY; this.speed = random(4, 8); this.color = colors[randomInt(0, colors.length)]; this.size = random(3, 6); this.exploded = false; this.angle = Math.atan2(targetY - y, targetX - x); } update() { const dx = this.targetX - this.x; const dy = this.targetY - this.y; const dist = Math.sqrt(dx * dx + dy * dy); if (dist < this.speed) { this.exploded = true; this.explode(); } else { this.x += Math.cos(this.angle) * this.speed; this.y += Math.sin(this.angle) * this.speed; // Create trail trails.push({ x: this.x, y: this.y, color: this.color, size: this.size * 0.5, alpha: 0.5, life: 20 }); } } explode() { const particleCount = randomInt(50, 100); for (let i = 0; i < particleCount; i++) { particles.push(new Particle(this.x, this.y, this.color)); } } draw() { if (!this.exploded) { ctx.fillStyle = this.color; ctx.beginPath(); ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2); ctx.fill(); } } } // Particle class class Particle { constructor(x, y, color) { this.x = x; this.y = y; this.color = color; this.size = random(2, 5); this.speed = random(2, 6); this.angle = random(0, Math.PI * 2); this.vx = Math.cos(this.angle) * this.speed; this.vy = Math.sin(this.angle) * this.speed; this.alpha = 1; this.gravity = 0.15; this.friction = 0.99; this.life = random(40, 80); } update() { this.vy += this.gravity; this.vx *= this.friction; this.vy *= this.friction; this.x += this.vx; this.y += this.vy; this.alpha -= 1 / this.life; this.life--; } draw() { ctx.fillStyle = this.color; ctx.globalAlpha = this.alpha; ctx.beginPath(); ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2); ctx.fill(); ctx.globalAlpha = 1; } isDead() { return this.alpha <= 0 || this.life <= 0; } } // Trail class class Trail { constructor(x, y, color) { this.x = x; this.y = y; this.color = color; this.size = random(2, 4); this.alpha = 0.5; this.life = 20; } update() { this.alpha -= 0.05; this.life--; } draw() { ctx.fillStyle = this.color; ctx.globalAlpha = this.alpha; ctx.beginPath(); ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2); ctx.fill(); ctx.globalAlpha = 1; } isDead() { return this.life <= 0; } } // Handle click canvas.addEventListener('click', (e) => { const rect = canvas.getBoundingClientRect(); const x = e.clientX; const y = e.clientY; const startX = randomInt(canvas.width * 0.3, canvas.width * 0.7); const startY = canvas.height + 20; shells.push(new FireworkShell(startX, startY, x, y)); }); // Animation loop function animate() { // Semi-transparent background for trail effect ctx.fillStyle = 'rgba(10, 10, 42, 0.2)'; ctx.fillRect(0, 0, canvas.width, canvas.height); // Update and draw shells for (let i = shells.length - 1; i >= 0; i--) { const shell = shells[i]; shell.update(); shell.draw(); if (shell.exploded) { shells.splice(i, 1); } } // Update and draw particles for (let i = particles.length - 1; i >= 0; i--) { const particle = particles[i]; particle.update(); particle.draw(); if (particle.isDead()) { particles.splice(i, 1); } } // Update and draw trails for (let i = trails.length - 1; i >= 0; i--) { const trail = trails[i]; trail.life--; trail.alpha = trail.life / 20; ctx.fillStyle = trail.color; ctx.globalAlpha = trail.alpha; ctx.beginPath(); ctx.arc(trail.x, trail.y, trail.size, 0, Math.PI * 2); ctx.fill(); ctx.globalAlpha = 1; if (trail.life <= 0) { trails.splice(i, 1); } } requestAnimationFrame(animate); } // Start animation animate(); // Add some initial fireworks for effect setTimeout(() => { for (let i = 0; i < 3; i++) { setTimeout(() => { const x = randomInt(canvas.width * 0.3, canvas.width * 0.7); const y = randomInt(canvas.height * 0.3, canvas.height * 0.7); shells.push(new FireworkShell( randomInt(canvas.width * 0.3, canvas.width * 0.7), canvas.height + 20, x, y )); }, i * 500); } }, 1000); </script> </body> </html>
thinking
The file has been created successfully. The fireworks display web app includes: 1. Full-screen canvas with a dark gradient background 2. Click anywhere to launch fireworks - shells travel from bottom to the click position 3. Explosions create 50-100 gravity-affected particles with: - Random velocities in all directions - Gravity pulling them down - Friction slowing them over time - Fading alpha for the fade-out effect 4. Colored particles with 12 vibrant colors 5. Trail effects behind the ascending shells 6. Semi-transparent background clear for persistent trails 7. Responsive to window resize 8. Initial demo fireworks at startup The file is now complete at /workspace/index.html
Created `/workspace/index.html` - a complete fireworks display web app with: **Features:** - **Full-screen canvas** with dark gradient background - **Click to launch** - shells travel from bottom to your click position - **Gravity-affected particles** - each explosion creates 50-100 particles with realistic physics - **Fading effect** - particles gradually fade as they expire - **Trail effects** - colored trails follow each ascending shell - **Vibrant colors** - 12 different firework colors - **Responsive** - adapts to window resize - **Demo fireworks** - 3 initial fireworks at startup **Physics:** - Particles have gravity (`vy += 0.15` per frame) - Friction (`0.99`) slows them down over time - Alpha decreases for fade-out effect - Particles are removed when alpha <= 0 or life expires
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
Clicking and scrolling launch fireworks that explode into fading particle bursts, but display is sparse and dim.
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.