ai firework launcher

This sketch creates an interactive fireworks display where each mouse click launches a colorful rocket that explodes into glowing particles with physics-based motion. The particles fade and fall under gravity, leaving soft trails across a dark canvas to create a vibrant, animated light show.

🧪 Try This!

Experiment with the code by making these changes:

  1. Make fireworks fall slowly — Reducing the gravity strength makes particles float longer, creating a dreamy slow-motion effect
  2. Paint longer motion trails — Lowering the background alpha value preserves more previous frames, creating glowing trails that persist longer on screen
  3. Launch fireworks from the center — The rocket normally starts at a random horizontal position at the bottom; this forces it to always start from the canvas center
  4. Slow down explosion particle decay — Reducing the lifespan decrease rate makes explosion particles fade out much more slowly, extending the visible explosion
  5. Make rockets shoot faster — Increasing the upward velocity range makes rockets travel higher before exploding, creating taller fireworks
Prefer the full editor? Open it there →

📖 About This Sketch

This sketch creates a fully interactive fireworks display powered by two core classes: Firework and Particle. When you click the mouse, a rocket shoots upward from the bottom of the canvas with a randomized color. At its peak, it explodes into dozens of glowing sparks that burst outward, fade away, and fall back down under the pull of gravity. The dark background uses semi-transparency to paint motion trails, making the particles leave glowing lines as they move.

The code demonstrates three essential p5.js techniques working together: object-oriented programming with classes, physics simulation with forces and vectors, and particle systems that create complex visual effects from simple rules. By reading this sketch, you will learn how to build reusable Particle and Firework classes, apply gravity and velocity to create believable motion, manage arrays of objects in a game loop, and use HSB color mode to generate vibrant, varied hues with a single parameter.

⚙️ How It Works

  1. When the sketch loads, setup() creates a full-window canvas, sets gravity to a gentle downward force, switches to HSB color mode for easy color generation, and disables stroke outlines for cleaner particles.
  2. Every frame, draw() clears the canvas with a semi-transparent black background—this creates the motion-trail effect by not fully erasing previous frames. It then loops through all active fireworks, updating their positions and checking if they are finished so they can be removed.
  3. When you click the mouse, mousePressed() creates a new Firework object with a random hue value and adds it to the fireworks array. The Firework begins as a single rocket particle launched from the bottom of the canvas.
  4. The rocket particle rises upward, with gravity constantly pulling it down. The Firework checks its velocity each frame—when the rocket's upward speed becomes zero or positive (meaning it has reached its peak), the exploded flag flips to true.
  5. Once exploded, the Firework calls its explode() method, which spawns 50–150 new Particle objects at the rocket's position. These particles shoot outward in random directions with random speeds, all inheriting the rocket's hue so the explosion is a single color.
  6. Explosion particles experience gravity, air resistance (they slow down each frame), and fading lifespan. As their lifespan decreases, their alpha transparency fades them out. Once their lifespan reaches zero, they are removed from the array. When a Firework has no particles left, it is removed from the main fireworks array, freeing memory.

🎓 Concepts You'll Learn

Object-oriented programming with ES6 classesParticle systems and array managementPhysics simulation with forces and vectorsHSB color mode for color generationSemi-transparent backgrounds for motion trailsMouse interaction and event handling

📝 Code Breakdown

setup()

setup() runs once when the sketch starts. It is the perfect place to initialize variables, configure the canvas, and set up any global settings like color mode and gravity that will be used throughout the entire sketch.

function setup() {
  createCanvas(windowWidth, windowHeight);
  // Tip: Use windowWidth/windowHeight for responsive canvas
  
  // Set gravity
  gravity = createVector(0, 0.1); // Slightly less gravity for a floatier effect
  
  // No stroke for cleaner particles
  noStroke();
  // Use HSB color mode for easier color manipulation (hue 0-255)
  colorMode(HSB, 255); 
}
Line-by-line explanation (4 lines)

🔧 Subcomponents:

calculation Canvas Setup createCanvas(windowWidth, windowHeight);

Creates a canvas that fills the entire browser window and responds to resizing

calculation Gravity Initialization gravity = createVector(0, 0.1);

Defines a global gravity force that pulls all particles downward each frame

calculation HSB Color Mode colorMode(HSB, 255);

Switches from RGB to HSB color space, where the first number is hue (0-255 for any color), making color generation from a single value simple

createCanvas(windowWidth, windowHeight);
Creates a canvas that fills the entire browser window—using windowWidth and windowHeight instead of fixed numbers makes it responsive to window resizing
gravity = createVector(0, 0.1);
Creates a p5.Vector with x=0 (no horizontal pull) and y=0.1 (downward force). This vector will be applied to all particles each frame, simulating gravity
noStroke();
Disables outlines around shapes and points so particles appear as clean dots with no borders
colorMode(HSB, 255);
Switches to HSB (Hue-Saturation-Brightness) color mode where colors are defined by a hue value 0-255 (0=red, 85=green, 170=blue, etc.). This makes it easy to generate vibrant random colors with a single variable

draw()

draw() runs 60 times per second and is the main animation loop. Each frame, we clear (with a semi-transparent background for trails), update all objects, and redraw them. This cycle creates smooth motion.

function draw() {
  // Draw a semi-transparent black background to create trails
  background(0, 25); 
  
  // Update and display each firework
  for (let i = fireworks.length - 1; i >= 0; i--) {
    fireworks[i].update();
    fireworks[i].show();
    
    // If the firework has finished its explosion, remove it from the array
    if (fireworks[i].done()) {
      fireworks.splice(i, 1);
    }
  }
}
Line-by-line explanation (6 lines)

🔧 Subcomponents:

calculation Motion Trail Background background(0, 25);

Fills the canvas with black (0) at partial transparency (25/255), so previous frames remain faintly visible and create motion trails

for-loop Fireworks Update Loop for (let i = fireworks.length - 1; i >= 0; i--) {

Loops backward through all active fireworks, updating their state and drawing them each frame

conditional Dead Firework Removal if (fireworks[i].done()) {

Checks if a firework has completed its explosion and all particles have faded, then removes it to free memory

background(0, 25);
Draws a semi-transparent black background. The first argument (0) is the darkness value in HSB mode, and the second argument (25) is the alpha transparency. Using partial transparency instead of fully opaque creates the trailing effect where old particles fade out slowly
for (let i = fireworks.length - 1; i >= 0; i--) {
Loops through the fireworks array backwards (from last to first). We count backwards because we are about to remove items—removing from the end avoids index shifting problems that would cause us to skip items if we counted forward
fireworks[i].update();
Calls the update() method on each firework, which moves the rocket upward or moves all explosion particles, applies gravity, and checks if the rocket should explode
fireworks[i].show();
Calls the show() method on each firework, which draws the rocket particle or all explosion particles to the canvas
if (fireworks[i].done()) {
Checks whether the firework has finished (rocket exploded and all explosion particles have faded and disappeared). If true, we remove it from the array
fireworks.splice(i, 1);
Removes one item from the fireworks array at index i. This prevents dead fireworks from being updated and drawn, saving CPU time

mousePressed()

mousePressed() is a built-in p5.js function that runs every time the user clicks the mouse. It is the event handler that launches new fireworks on demand, making the sketch interactive.

function mousePressed() {
  // Launch a new firework from the bottom of the canvas
  // The hue is randomized for different colors
  fireworks.push(new Firework(random(255)));
}
Line-by-line explanation (1 lines)

🔧 Subcomponents:

calculation Firework Creation fireworks.push(new Firework(random(255)));

Creates a new Firework object with a random hue and adds it to the active fireworks array

fireworks.push(new Firework(random(255)));
Creates a new Firework object, passing random(255) as the hue argument. random(255) picks a random number between 0 and 255, giving the firework a different color each time you click. The push() method adds this new firework to the end of the fireworks array so it will be updated and drawn in the main loop

windowResized()

windowResized() is a built-in p5.js function that p5.js calls whenever the browser window or frame is resized. Always include resizeCanvas() inside it if you want your sketch to stay fullscreen and responsive.

function windowResized() {
  resizeCanvas(windowWidth, windowHeight);
  // Called when preview panel is resized
}
Line-by-line explanation (1 lines)

🔧 Subcomponents:

calculation Canvas Resize Handler resizeCanvas(windowWidth, windowHeight);

Updates the canvas dimensions when the browser window is resized, ensuring the sketch remains fullscreen

resizeCanvas(windowWidth, windowHeight);
When the user resizes their browser window or preview panel, this function is automatically called and resizes the canvas to match the new window dimensions. Without this, the canvas would stay its original size and stop responding to the full window

Particle class

The Particle class represents a single glowing spark. It stores position, velocity, acceleration, color, and lifespan. The core of particle physics happens in update(): forces change acceleration, acceleration changes velocity, and velocity changes position. This happens every frame, creating smooth, realistic motion.

🔬 The rocket always goes straight up (x=0), while explosion particles go in random directions. What happens if you change the rocket's x from 0 to random(-2, 2)? How would that change the rocket's path?

    if (this.firework) {
      // Rocket particle goes straight up with random initial speed
      this.vel = createVector(0, random(-10, -5)); 
    } else {
      // Explosion particles burst outwards with random velocity
      this.vel = p5.Vector.random2D(); // Random direction
      this.vel.mult(random(1, 6));     // Random speed
    }

🔬 Explosion particles are drawn as small dots with fading alpha. What happens if you change strokeWeight(2) to strokeWeight(5)? Or if you change the saturation (the 255 after this.hu) to 100?

      strokeWeight(2);
      stroke(this.hu, 255, 255, this.lifespan);
class Particle {
  constructor(x, y, hu, firework) {
    this.pos = createVector(x, y); // Position
    this.firework = firework;      // Is this particle part of the initial rocket or the explosion?
    this.lifespan = 255;           // How long the particle lives (alpha value)
    this.hu = hu;                  // Hue for its color
    
    // Initial velocity
    if (this.firework) {
      // Rocket particle goes straight up with random initial speed
      this.vel = createVector(0, random(-10, -5)); 
    } else {
      // Explosion particles burst outwards with random velocity
      this.vel = p5.Vector.random2D(); // Random direction
      this.vel.mult(random(1, 6));     // Random speed
    }
    
    this.acc = createVector(0, 0); // Acceleration
  }

  // Apply a force to the particle (e.g., gravity)
  applyForce(force) {
    this.acc.add(force);
  }

  // Update particle's position and lifespan
  update() {
    if (!this.firework) {
      // Explosion particles slow down due to air resistance (or just simple drag)
      this.vel.mult(0.9); 
      this.lifespan -= 5; // Fade out
    }
    
    this.vel.add(this.acc); // Add acceleration to velocity
    this.pos.add(this.vel); // Add velocity to position
    this.acc.mult(0);       // Reset acceleration for the next frame
  }

  // Check if the particle has died (lifespan is 0)
  done() {
    return this.lifespan < 0;
  }

  // Display the particle
  show() {
    colorMode(HSB, 255); // Ensure HSB mode for particle colors
    
    if (!this.firework) {
      // Explosion particles are smaller and fade out
      strokeWeight(2);
      stroke(this.hu, 255, 255, this.lifespan); // Color with fading alpha
    } else {
      // Rocket particle is brighter and has a tail
      strokeWeight(4);
      stroke(this.hu, 255, 255); // Bright color
    }
    
    point(this.pos.x, this.pos.y); // Draw a point at the particle's position
  }
}
Line-by-line explanation (18 lines)

🔧 Subcomponents:

calculation Particle Constructor constructor(x, y, hu, firework) {

Initializes a new Particle with position, hue, and velocity depending on whether it is a rocket or explosion particle

conditional Rocket vs Explosion Velocity if (this.firework) {

Rocket particles launch straight upward; explosion particles burst outward in random directions

calculation Force Application this.acc.add(force);

Accumulates forces (like gravity) by adding them to the acceleration vector

calculation Physics Integration this.vel.add(this.acc);

Applies acceleration to velocity, then velocity to position—the core physics loop

conditional Explosion Particle Decay if (!this.firework) {

Only explosion particles fade and slow down; rocket particles maintain brightness and speed until explosion

constructor(x, y, hu, firework) {
The constructor function runs when a new Particle is created. It receives x and y starting coordinates, hu (hue), and a boolean firework flag indicating whether this is a rocket or explosion particle
this.pos = createVector(x, y);
Stores the particle's starting position as a p5.Vector, which we will update every frame
this.firework = firework;
Saves the boolean flag so we can check later whether this is a rocket particle or an explosion particle—they behave differently
this.lifespan = 255;
Sets the particle's initial lifespan to 255. This value decreases over time and controls the alpha (transparency), so the particle gradually fades out
this.hu = hu;
Stores the hue value (0-255) so all particles in one explosion share the same color
this.vel = createVector(0, random(-10, -5));
Rocket particles start with zero horizontal velocity and a negative vertical velocity between -10 and -5, so they shoot straight upward at varying speeds
this.vel = p5.Vector.random2D();
Creates a random 2D unit vector, giving the explosion particle a random direction
this.vel.mult(random(1, 6));
Multiplies the velocity by a random number between 1 and 6, making each explosion particle burst outward at a different speed
this.acc = createVector(0, 0);
Initializes acceleration to zero. Acceleration will be updated each frame when gravity is applied via applyForce()
this.acc.add(force);
Adds a force vector (like gravity) to the acceleration, accumulating multiple forces if needed
this.vel.mult(0.9);
Multiplies explosion particle velocity by 0.9 each frame, simulating air resistance and drag so particles slow down as they float
this.lifespan -= 5;
Decreases the lifespan by 5 each frame, causing explosion particles to fade out—when lifespan reaches 0, the particle is removed
this.vel.add(this.acc);
Adds acceleration to velocity—this is how forces like gravity change the particle's speed
this.pos.add(this.vel);
Adds velocity to position, moving the particle each frame. This simple loop (force → acceleration → velocity → position) is the foundation of physics simulation
this.acc.mult(0);
Resets acceleration to zero at the end of the frame. Forces must be reapplied every frame—they do not persist automatically
return this.lifespan < 0;
Returns true if the particle's lifespan is below zero, meaning it has completely faded and should be removed from the simulation
stroke(this.hu, 255, 255, this.lifespan);
Sets the stroke color using HSB mode: hue is this.hu (the particle's assigned color), saturation is 255 (fully vibrant), brightness is 255 (fully bright), and alpha is this.lifespan (fades as lifespan decreases)
point(this.pos.x, this.pos.y);
Draws a single pixel at the particle's current position with the stroke color set above

Firework class

The Firework class orchestrates the entire lifecycle of a firework: launching the rocket, detecting its peak, creating the explosion, and managing all the resulting particles. It demonstrates how to compose multiple Particle objects into a more complex behavior and manage their states (before explosion vs. after explosion).

🔬 The rocket explodes when its upward velocity becomes zero or positive (>= 0), meaning it has peaked. What happens if you change >= 0 to >= -3? When would the explosion happen earlier or later?

      // If the rocket has reached its peak (velocity in Y direction becomes positive), explode!
      if (this.firework.vel.y >= 0) {
        this.exploded = true;
        this.explode();
      }

🔬 After explosion, this loop updates all particles and removes dead ones. What happens if you comment out the applyForce(gravity) line? How would particles behave without gravity pulling them down?

    } else {
      // If exploded, update all explosion particles
      for (let i = this.particles.length - 1; i >= 0; i--) {
        this.particles[i].applyForce(gravity); // Apply gravity to particles
        this.particles[i].update();
        
        // Remove dead particles from the array
        if (this.particles[i].done()) {
          this.particles.splice(i, 1);
        }
      }
    }
class Firework {
  constructor(hu) {
    this.hu = hu;                     // Hue for this firework
    this.firework = new Particle(random(width), height, this.hu, true); // The rocket particle
    this.exploded = false;            // Has the rocket exploded yet?
    this.particles = [];              // Array to hold explosion particles
  }

  // Check if the firework (and its explosion) is done
  done() {
    return this.exploded && this.particles.length === 0;
  }

  // Update the firework's state
  update() {
    if (!this.exploded) {
      this.firework.applyForce(gravity); // Apply gravity to the rocket
      this.firework.update();            // Update rocket position
      
      // If the rocket has reached its peak (velocity in Y direction becomes positive), explode!
      if (this.firework.vel.y >= 0) {
        this.exploded = true;
        this.explode();
      }
    } else {
      // If exploded, update all explosion particles
      for (let i = this.particles.length - 1; i >= 0; i--) {
        this.particles[i].applyForce(gravity); // Apply gravity to particles
        this.particles[i].update();
        
        // Remove dead particles from the array
        if (this.particles[i].done()) {
          this.particles.splice(i, 1);
        }
      }
    }
  }

  // Create explosion particles
  explode() {
    // Generate a random number of particles
    for (let i = 0; i < random(50, 150); i++) {
      // Each particle starts at the rocket's position
      this.particles.push(new Particle(this.firework.pos.x, this.firework.pos.y, this.hu, false));
    }
  }

  // Display the firework
  show() {
    if (!this.exploded) {
      // Display the rocket particle
      this.firework.show();
    } else {
      // Display all explosion particles
      for (let particle of this.particles) {
        particle.show();
      }
    }
  }
}
Line-by-line explanation (22 lines)

🔧 Subcomponents:

calculation Firework Constructor constructor(hu) {

Creates a new firework with a random hue and initializes a rocket particle

calculation Rocket Particle Creation this.firework = new Particle(random(width), height, this.hu, true);

Creates the initial rocket particle at a random horizontal position at the bottom of the canvas

conditional Explosion Trigger if (this.firework.vel.y >= 0) {

Detects when the rocket has reached its peak (velocity stops being negative) and triggers the explosion

for-loop Particle Burst Loop for (let i = 0; i < random(50, 150); i++) {

Creates 50-150 explosion particles at the rocket's final position, all with the firework's hue

for-loop Explosion Particles Update for (let i = this.particles.length - 1; i >= 0; i--) {

Updates all explosion particles each frame and removes the ones that have fully faded

constructor(hu) {
The constructor receives a hue value and initializes a new Firework object with that color
this.hu = hu;
Stores the hue so all explosion particles will inherit the rocket's color
this.firework = new Particle(random(width), height, this.hu, true);
Creates a new Particle at a random horizontal position (random(width)) at the bottom of the canvas (height), passes the hue, and sets the firework flag to true so it launches upward
this.exploded = false;
Tracks whether the rocket has exploded yet. Starts as false and becomes true when the rocket reaches its peak
this.particles = [];
Initializes an empty array that will hold all the explosion particles once the rocket explodes
return this.exploded && this.particles.length === 0;
Returns true only if the firework has exploded AND all its explosion particles have faded and been removed from the array—this signals it is safe to delete the Firework object
this.firework.applyForce(gravity);
Applies the global gravity force to the rocket particle, pulling it downward and slowing its upward motion
this.firework.update();
Updates the rocket particle's velocity and position each frame, applying the gravity force
if (this.firework.vel.y >= 0) {
Checks whether the rocket's vertical velocity has stopped being negative (upward) and has become zero or positive (starting to fall). This is the peak, the moment to explode
this.exploded = true;
Sets the exploded flag to true, switching the firework from rocket mode to explosion mode
this.explode();
Calls the explode() method to create all the explosion particles at the rocket's current position
for (let i = this.particles.length - 1; i >= 0; i--) {
Loops backward through the explosion particles array, updating and removing dead particles (same backward-loop pattern used in draw())
this.particles[i].applyForce(gravity);
Applies gravity to each explosion particle so they fall back down while fading out
this.particles[i].update();
Updates each explosion particle's position, velocity, acceleration, and lifespan
if (this.particles[i].done()) {
Checks if this explosion particle's lifespan has dropped below zero (fully faded)
this.particles.splice(i, 1);
Removes the dead particle from the array, freeing memory
for (let i = 0; i < random(50, 150); i++) {
Generates a random number between 50 and 150, so each firework explosion has a slightly different number of sparks
this.particles.push(new Particle(this.firework.pos.x, this.firework.pos.y, this.hu, false));
Creates a new Particle at the rocket's explosion position, assigns it the firework's hue, and sets the firework flag to false so it bursts outward rather than rising
if (!this.exploded) {
If the rocket hasn't exploded yet, display the rocket particle
this.firework.show();
Draws the rocket particle to the canvas
for (let particle of this.particles) {
If the rocket has exploded, loop through all explosion particles using a for-of loop (a cleaner way than indexed for-loops for simple iteration)
particle.show();
Draws each explosion particle to the canvas

📦 Key Variables

fireworks array

Stores all active Firework objects currently being animated on screen. New fireworks are added when the user clicks, and old ones are removed once their particles fade

let fireworks = [];
gravity p5.Vector

A global force vector pointing downward (0, 0.1) that is applied to all particles and rockets each frame, simulating gravitational pull

let gravity = createVector(0, 0.1);

🔧 Potential Improvements (4)

Here are some ways this code could be enhanced:

PERFORMANCE Particle.show() method

colorMode(HSB, 255) is called every frame for every particle, which is redundant since it was already set in setup()

💡 Remove the colorMode() call from show() since it is already set globally. This saves unnecessary function calls and improves performance when many particles are drawn

BUG Firework.update() explosion trigger

Using vel.y >= 0 to detect peak works but can miss the exact peak frame if gravity changes or velocity jumps over zero. Rockets that are already moving downward could theoretically miss the explosion trigger

💡 Track the previous frame's velocity sign to reliably detect when it crosses from negative to positive: if (this.firework.vel.y >= 0 && this.firework.vel.y - gravity.y < 0)

STYLE Particle constructor and Firework constructor

The property this.firework inside the Particle class is confusing—it is a boolean, but the Firework class uses this.firework as a Particle object. Reusing the same name creates confusion

💡 Rename the Particle property from this.firework to this.isRocket to make it clear it is a boolean flag, improving code readability

FEATURE mousePressed() function

All fireworks are launched from the bottom of the canvas; launching from the mouse position would make the interaction more intuitive

💡 Modify the Firework constructor to accept a y parameter and update mousePressed() to pass mouseY instead of always using height: fireworks.push(new Firework(random(255), mouseY))

🔄 Code Flow

Code flow showing setup, draw, mousepressed, windowresized, particle, firework

💡 Click on function names in the diagram to jump to their code

graph TD start[Start] --> setup[setup] setup --> draw[draw loop] draw --> semi-transparent-bg[semi-transparent-bg] draw --> gravity-vector[gravity-vector] draw --> color-mode[color-mode] draw --> fireworks-loop[fireworks-loop] fireworks-loop --> cleanup-check[cleanup-check] cleanup-check -->|if dead| fireworks-loop cleanup-check -->|if not dead| fireworks-loop fireworks-loop --> new-firework[new-firework] new-firework --> fireworks-loop click setup href "#fn-setup" click draw href "#fn-draw" click semi-transparent-bg href "#sub-semi-transparent-bg" click gravity-vector href "#sub-gravity-vector" click color-mode href "#sub-color-mode" click fireworks-loop href "#sub-fireworks-loop" click cleanup-check href "#sub-cleanup-check" click new-firework href "#sub-new-firework" draw --> particle-generation[particle-generation] particle-generation --> particle-constructor[particle-constructor] particle-constructor --> rocket-creation[rocket-creation] rocket-creation --> explosion-trigger[explosion-trigger] explosion-trigger -->|if triggered| explosion-particles-loop[explosion-particles-loop] explosion-particles-loop --> particle-fading[particle-fading] particle-fading -->|if faded| explosion-particles-loop particle-fading -->|if not faded| explosion-particles-loop click particle-generation href "#sub-particle-generation" click particle-constructor href "#sub-particle-constructor" click rocket-creation href "#sub-rocket-creation" click explosion-trigger href "#sub-explosion-trigger" click explosion-particles-loop href "#sub-explosion-particles-loop" click particle-fading href "#sub-particle-fading" windowresized --> canvas-resize[canvas-resize] canvas-resize -->|resize| canvas-creation[canvas-creation] click windowresized href "#fn-windowresized" click canvas-resize href "#sub-canvas-resize" click canvas-creation href "#sub-canvas-creation"

❓ Frequently Asked Questions

What visual experience does the ai firework launcher sketch provide?

The ai firework launcher creates a vibrant fireworks display, featuring colorful rockets that ascend and explode into glowing, fading sparks, leaving soft trails across a dark background.

How can users interact with the ai firework launcher sketch?

Users can interact with the sketch by clicking the mouse, which launches new colorful fireworks from the bottom of the canvas.

What creative coding techniques are showcased in the ai firework launcher?

This sketch demonstrates techniques such as particle systems for simulating fireworks, HSB color manipulation for vibrant visuals, and responsive canvas resizing.

Preview

ai firework launcher - p5.js creative coding sketch preview
Sketch Preview
Code flow diagram showing the structure of ai firework launcher - Code flow showing setup, draw, mousepressed, windowresized, particle, firework
Code Flow Diagram