Over 10 years we helping companies reach their financial and branding goals. Onum is a values-driven SEO agency dedicated.

CONTACTS
Projects

Fireworks Launcher using HTML5 Canvas & JavaScript

Introduction

Do you want to add some fireworks magic to your web projects? ✨ In this tutorial, we’ll build an interactive Fireworks Launcher using HTML5 Canvas and JavaScript.
This project is fun, visual, and a great way to understand how animations work with the Canvas API.

👉 Try it yourself – move your mouse and click anywhere on the screen, you’ll see fireworks explode beautifully! 🎇

Tech Stack

  • HTML5 – for structure
  • CSS3 – for basic styling
  • JavaScript (Canvas API) – for animations & interactions

📌 Features

✔️ Fireworks animation with glowing particles
✔️ Mouse & touch controls
✔️ Works on any screen size
✔️ Smooth performance using requestAnimationFrame()


💻 Complete Code

Here’s the full source code:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="https://fonts.googleapis.com/css2?family=Great+Vibes&display=swap" rel="stylesheet">
    <title>Fireworks Launcher | Learn New Things</title>
    <style>
      body {
        background: #f50000;
        margin: 0;
        overflow: hidden;
      }

      @keyframes fadeIn {
        from {
          opacity: 0;
        }
        to {
          opacity: 1;
        }
      }
      @keyframes chill {
        from {
          opacity: 1;
        }
        to {
          opacity: 1;
        }
      }
      @keyframes fadeOut {
        from {
          opacity: 1;
        }
        to {
          opacity: 0;
        }
      }
      p {
        position: absolute;
        top: 36%;
        left: 50%;
        transform: translate(-50%, -50%);
        font-family: 'Playfair Display', cursive;
        font-size: 3.5rem;
        color: white;
        opacity: 0;
        font-family: "Source Sans Pro";
        animation: fadeIn 10s ease-out, chill 10s 10s, fadeOut 10s 10s;
      }
    </style>
  </head>
  <body>
    <canvas></canvas>
    <p>Fireworks For You</p>

    <script>
      var canvas = document.querySelector('canvas');
      var c = canvas.getContext('2d');

      canvas.width = window.innerWidth;
      canvas.height = window.innerHeight;

      var mouse = {
        x: window.innerWidth / 2,
        y: window.innerHeight / 2
      };

      var isMouseDown = false;

      window.addEventListener("mousemove", function(event) {
        mouse.x = event.clientX;
        mouse.y = event.clientY;
      });

      window.addEventListener("resize", function() {
        canvas.height = window.innerHeight;
        canvas.width = window.innerWidth;

        initializeVariables();
      });


      window.addEventListener("mousedown", function() {
        isMouseDown = true;
      });

      window.addEventListener("mouseup", function() {
        isMouseDown = false;
      });

      canvas.addEventListener("touchstart", function() {
        isMouseDown = true;
      });

      canvas.addEventListener("touchmove", function(event) {
        event.preventDefault();
        mouse.x = event.touches[0].pageX;
        mouse.y = event.touches[0].pageY;
      });

      canvas.addEventListener("touchend", function() {
        isMouseDown = false;
      });


      function Cannon(x, y, width, height, color) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.angle = 0;
        this.color = color;

        this.update = function() {
          desiredAngle = Math.atan2(mouse.y - this.y, mouse.x - this.x);
          this.angle = desiredAngle;
          this.draw();	
        };

        this.draw = function() {
          c.save();
          c.translate(this.x, this.y);
          c.rotate(this.angle);
          c.beginPath();
          c.fillStyle = this.color;
          c.shadowColor = this.color;
          c.shadowBlur = 3;
          c.shadowOffsetX = 0;
          c.shadowOffsetY = 0;
          c.fillRect(0, -this.height / 2, this.width, height);
          c.closePath();
          c.restore();
        };
      }

      function Cannonball(x, y, dx, dy, radius, color, cannon, particleColors) {
        this.x = x;
        this.y = y;
        this.dx = dx;
        this.dy = -dy;
        this.radius = radius;
        this.color = color;
        this.particleColors = particleColors;
        this.source = cannon;
        this.timeToLive = canvas.height / (canvas.height + 800);

        this.init = function() {
          // Initialize the cannonballs start coordinates (from muzzle of cannon)
          this.x = Math.cos(this.source.angle) * this.source.width;
          this.y = Math.sin(this.source.angle) * this.source.width;

          // Translate relative to canvas positioning
          this.x = this.x + (canvas.width / 2);
          this.y = this.y + (canvas.height);	

          // Determine whether the cannonball should be 
          // fired to the left or right of the cannon
          if (mouse.x - canvas.width / 2 < 0) {
            this.dx = -this.dx;
          }

          this.dy = Math.sin(this.source.angle) * 8;
          this.dx = Math.cos(this.source.angle) * 8;
        };

        this.update = function() {
          if (this.y + this.radius + this.dy > canvas.height) {
            this.dy = -this.dy;
          } else {
            this.dy += gravity;
          }

          this.x += this.dx;
          this.y += this.dy;
          this.draw();	

          this.timeToLive -= 0.01;
        };

        this.draw = function() {
          c.save();
          c.beginPath();
          c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
          c.shadowColor = this.color;
          c.shadowBlur = 5;
          c.shadowOffsetX = 0;
          c.shadowOffsetY = 0;
          c.fillStyle = this.color;
          c.fill();
          c.closePath();
          c.restore();
        };

        this.init();
      }

      function Particle(x, y, dx, dy, radius, color) {
        this.x = x;
        this.y = y;
        this.dx = dx;
        this.dy = -dy;
        this.radius = 5;
        this.color = color;
        this.timeToLive = 1;
        // this.mass = 0.2;

        this.update = function() {
          if (this.y + this.radius + this.dy > canvas.height) {
            this.dy = -this.dy;
          }

          if (this.x + this.radius + this.dx > canvas.width || this.x - this.radius + this.dx < 0) {
            this.dx = -this.dx;
          }
          // this.dy += gravity * this.mass;
          this.x += this.dx;
          this.y += this.dy;
          this.draw();

          this.timeToLive -= 0.01;
        };

        this.draw = function() {
          c.save();
          c.beginPath();
          c.arc(this.x, this.y, 2, 0, Math.PI * 2, false);
          c.shadowColor = this.color;
          c.shadowBlur = 10;
          c.shadowOffsetX = 0;
          c.shadowOffsetY = 0;
          c.fillStyle = this.color;
          c.fill();

          c.closePath();

          c.restore();
        };
      }


      function Explosion(cannonball) {
        this.particles = [];	
        this.rings = [];
        this.source = cannonball;

        this.init = function() {
          for (var i = 0; i < 10; i++) {

            var dx = (Math.random() * 6) - 3;
            var dy = (Math.random() * 6) - 3;

            // var hue = (255 / 5) * i;
            // var color = "hsl(" + hue + ", 100%, 50%)";
            var randomColorIndex = Math.floor(Math.random() * this.source.particleColors.length);
            var randomParticleColor = this.source.particleColors[randomColorIndex];


              this.particles.push(new Particle(this.source.x, this.source.y, dx, dy, 1, randomParticleColor));
          }

          // Create ring once explosion is instantiated
            // this.rings.push(new Ring(this.source, "blue"));
        };

        this.init();

        this.update = function() {
      for (var i = 0; i < this.particles.length; i++) {
              this.particles[i].update();

              // Remove particles from scene one time to live is up
              if (this.particles[i].timeToLive < 0) {
                this.particles.splice(i, 1);
              }
          }

          // Render rings
          for (var j = 0; j < this.rings.length; j++) {
            this.rings[j].update();

            // Remove rings from scene one time to live is up
              if (this.rings[j].timeToLive < 0) {
                this.rings.splice(i, 1);
              }
          }
        };
      }

      var gravity = -0.1;
      var desiredAngle = 0;
      var cannon, cannonballs, explosions, colors;

      function initializeVariables() {
        cannon = new Cannon(canvas.width / 2, canvas.height, 40, 20, "white");
        cannonballs = [];
        explosions = [];
        colors = [


          // Red / Orange
          {
            cannonballColor: "#affdf4",
            particleColors: [
              "#ff4747",
              "#00ceed",
              "#fff",
              "pink",
            ]
          }
        ];

      }

      initializeVariables();

      var timer = 0;
      var isIntroComplete = false;
      var introTimer = 0;


      function animate() {
        window.requestAnimationFrame(animate);

        c.fillStyle = "rgba(18, 18, 18, 0.2)";
        c.fillRect(0, 0, canvas.width, canvas.height);			
        cannon.update();

        if (isIntroComplete === false) {
          introTimer += 1;

          if (introTimer % 3 === 0) {
            var randomColor = Math.floor(Math.random() * colors.length);
            var color = colors[randomColor];

            cannonballs.push(new Cannonball(canvas.width / 2, canvas.height / 2, 2, 2, 4, color.cannonballColor, cannon, color.particleColors));
          }

          if (introTimer > 30) {
            isIntroComplete = true;
          }

        }


        // Render cannonballs
        for (var i = 0; i < cannonballs.length; i++) {
            cannonballs[i].update();

            if (cannonballs[i].timeToLive <= 0) {

              // Create particle explosion after time to live expires
              explosions.push(new Explosion(cannonballs[i]));

              cannonballs.splice(i, 1);

            }
        }

        // Render explosions
        for (var j = 0; j < explosions.length; j++) {
              //Do something
              explosions[j].update();

            // Remove explosions from scene once all associated particles are removed
            if (explosions[j].particles.length <= 0) {
              explosions.splice(j, 1);
            }
        }	


        if (isMouseDown === true) {
          timer += 1;
          if (timer % 3 === 0) {
            var randomParticleColorIndex = Math.floor(Math.random() * colors.length);
            var randomColors = colors[randomParticleColorIndex];

            cannonballs.push(new Cannonball(mouse.x, mouse.y, 2, 2, 4, randomColors.cannonballColor, cannon, randomColors.particleColors));
          }
        }
      }

      animate();
    </script>
  </body>
</html>

Or you can check the GitHub repo: Fireworks Launcher GitHub


📂 How It Works

1. Setting up Canvas

We first create a <canvas> element that fills the entire screen and prepare it for 2D drawing.

var canvas = document.querySelector('canvas');
var c = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

2. Creating the Cannon

We design a cannon that follows the mouse cursor.

function Cannon(x, y, width, height, color) {
  this.x = x;
  this.y = y;
  this.width = width;
  this.height = height;
  this.angle = 0;
  this.color = color;
}

3. Launching Cannonballs

When you click or tap, cannonballs are fired towards your mouse/touch position.

function Cannonball(x, y, dx, dy, radius, color, cannon, particleColors) {
  this.x = x;
  this.y = y;
  this.dx = dx;
  this.dy = -dy;
  this.radius = radius;
  this.color = color;
}

4. Explosions with Particles

When a cannonball reaches its destination, it explodes into colorful particles.

function Explosion(cannonball) {
  this.particles = [];
  for (var i = 0; i < 10; i++) {
    var dx = (Math.random() * 6) - 3;
    var dy = (Math.random() * 6) - 3;
    this.particles.push(new Particle(cannonball.x, cannonball.y, dx, dy, 1, "red"));
  }
}

5. Animating with requestAnimationFrame()

We use an animation loop to keep updating and drawing the fireworks smoothly.

function animate() {
  requestAnimationFrame(animate);
  c.fillStyle = "rgba(18, 18, 18, 0.2)";
  c.fillRect(0, 0, canvas.width, canvas.height);
  cannon.update();
  // update cannonballs & explosions
}
animate();

How to Run Locally

  1. Copy the above code into a file called index.html
  2. Open it in your browser
  3. Move your mouse & click → 🎆 Fireworks will launch!

📝 Things to Try

  • Change colors of particles
  • Increase/decrease number of explosions
  • Add background music for more fun 🎶

📜 Conclusion

This Fireworks Launcher is a fun way to learn about:
✅ Canvas drawing
✅ Mouse & touch interactions
✅ Animations with JavaScript

You can expand it by adding more features, like random patterns, sound effects, or even a fireworks show on special occasions 🎉.

👉 Full Code on GitHub: Fireworks Launcher

Leave a comment

Your email address will not be published. Required fields are marked *