Building a Fireworks Animation with HTML5 Canvas and JavaScript

Fireworks are a captivating visual spectacle, and you can bring this excitement to your website by creating a dynamic fireworks animation using HTML5 Canvas and JavaScript. In this tutorial, we’ll explore a step-by-step guide to understand and implement the provided code.
Before we get start you can download the project files below:
Demo
Take a look at what the code creates:
Requirements and prerequisites
The code is intended to be run in a web browser. Open the HTML file in a modern web browser such as Google Chrome, Mozilla Firefox, Safari, or Microsoft Edge.
Make sure that JavaScript is enabled in your web browser, as the entire animation is implemented in JavaScript.
The code relies on the HTML5 Canvas API. Ensure that the browser supports HTML5 and has Canvas API support.
The code can be hosted on a web server or executed locally. If you are running it locally, you may encounter security restrictions (CORS issues) when loading external scripts or assets. Hosting it on a server can help avoid such issues.
HTML Setup
Firstly, set up your HTML file by creating a canvas element where the fireworks will come to life.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
margin: 0;
overflow: hidden;
}
canvas {
display: block;
}
</style>
<title>Fireworks Animation</title>
</head>
<body>
<canvas id="fireworksCanvas"></canvas>
<script src="library.js"></script>
<script src="fireworks.js"></script>
</body>
</html>
JavaScript Setup
The code below creates objects the different parts of the fireworks such as the particle and fireworks objects. In the example files, this code is within the "library.js" file.
//fireworks object to create a fireworks
const fireworksObject = function(x,y,target){
this.x =x;
this.y=y;
this.direction=null;
this.target={x:target.x,y:target.y}
//number of particles to release on explosion;
this.count=20;
this.speed=10;
this.particle_life=[10,30];
this.particle_speed=[1,5];
this.segments=[];
this.segment_limit=5;
this.init()
}
fireworksObject.prototype={
init:function(){
this.segments.push({x:this.x,y:this.y});
var dx=this.target.x-this.x;
var dy=this.target.y-this.y;
var magnitude=Math.sqrt(dx*dx+dy*dy);
//normalized direction
var nx=dx/magnitude;
var ny=dy/magnitude;
this.direction={x:nx,y:ny};
},
explode:function(fireworks,particles,canvas){
var index=fireworks.findIndex(item =>item ==this);
fireworks.splice(index,1);
var i=0;
while(i<this.count){
var x0=Math.random(0,1)*canvas.width;
var y0=Math.random(0,1)*canvas.height;
var life=Math.random(0,1)*this.particle_life[1]+this.particle_life[0];
var speed=Math.random(0,1)*this.particle_speed[1]+this.particle_speed[0];
particles.push(create_particle(this.x,this.y,life,speed,{x:x0,y:y0}));
i++;
}
delete(this);
},
move:function(){
this.x+=this.speed*this.direction.x;
this.y+=this.speed*this.direction.y;
}
,
update:function(gl,fireworks,particles,canvas){
//move the fireworks
this.move();
//drawing the fire works;
gl.beginPath();
gl.strokeStyle=`hsl(${Math.random() * 5000}, 100%, 50%)`;
gl.lineWidth=Math.random(0,1)*2+1;
var last_pos=this.segments[this.segments.length-1];
gl.moveTo(last_pos.x, last_pos.y);
gl.lineTo(this.x,this.y);
gl.stroke();
gl.closePath();
this.segments.push({x:this.x,y:this.y})
if(this.segments.length>=this.segment_limit){
this.segments.splice(0,1);
}
var dx=this.target.x-this.x;
var dy=this.target.y-this.y;
var distance=Math.sqrt(dx*dx+dy*dy)
if(distance<=10){
this.explode(fireworks,particles,canvas);
}
}
}
function create_fireworks(x,y,target){
return new fireworksObject(x,y,target);
}
//particle object to create particles from the fireworks
const particle = function(x,y,life,speed,target){
this.x=x;
this.y=y;
this.life=life;
this.decay=1;
this.direction=null;
this.target={x:target.x,y:target.y};
this.speed=speed;
this.gravity=2;
this.segments=[];
this.segment_limit=5;
this.init();
}
particle.prototype={
init:function(){
this.segments.push({x:this.x,y:this.y});
var dx=this.target.x-this.x;
var dy=this.target.y-this.y;
var magnitude=Math.sqrt(dx*dx+dy*dy);
//normalized direction
var nx=dx/magnitude;
var ny=dy/magnitude;
this.direction={x:nx,y:ny};
},
end:function(particles){
var index=particles.findIndex(item =>item ==this);
particles.splice(index,1);
delete(this);
},
move:function(){
this.x+=this.speed*this.direction.x;
this.y+=this.speed*this.direction.y+this.gravity;
}
,
update:function(gl,particles){
//move the fireworks
this.move();
//drawing the fire works;
gl.beginPath();
gl.strokeStyle=`hsl(${Math.random() * 360}, 100%, 50%)`;
gl.lineWidth=Math.random(0,1)*2+1;
var last_pos=this.segments[this.segments.length-1];
gl.moveTo(last_pos.x, last_pos.y);
gl.lineTo(this.x,this.y);
gl.stroke();
gl.closePath();
this.segments.push({x:this.x,y:this.y})
if(this.segments.length>=this.segment_limit){
this.segments.splice(0,1);
}
this.life-=this.decay;
if(this.life<=0){
this.end(particles);
}
}
}
function create_particle(x,y,life,speed,target){
return new particle(x,y,life,speed,target);
}
Fireworks Object (fireworksObject
):
- The
fireworksObject
constructor initializes properties such as the initial position (x
,y
), target position, number of particles to release on explosion (count
), speed, particle life range, particle speed range, segments, and segment limit. - The
init
method calculates the normalized direction vector towards the target. - The
explode
method removes the current fireworks from the array and creates a specified number of particles with random positions, life, and speed. - The
move
method updates the position of the fireworks based on its speed and direction. - The
update
method is responsible for updating the state of the fireworks, moving it, drawing its trajectory, and triggering an explosion when it reaches the target.
Particle Object (particle
):
- The
particle
constructor initializes properties similar to the fireworks object, including position, life, decay, direction, target, speed, gravity, segments, and segment limit. - The
init
method calculates the normalized direction vector towards the target. - The
end
method removes the particle from the array when its life is exhausted. - The
move
method updates the position of the particle based on its speed, direction, and gravity. - The
update
method updates the state of the particle, moving it, drawing its trajectory, and triggering its removal when its life is exhausted.
Additional Functions:
create_fireworks
: A helper function to create a new instance of thefireworksObject
.create_particle
: A helper function to create a new instance of theparticle
.
Animating the fireworks
The code below renders the fireworks on the screen by firing it from a random position the below the screen to a random point on the screen. It also creates an explosion once the fireworks reaches the a target position. The result is a set of particles render on screen moving and falling under gravity. This code is within the "fireworks.js" file.
document.addEventListener("DOMContentLoaded", function () {
const canvas = document.getElementById("fireworksCanvas");
const gl = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const refresh_rate=50;
const particles=[];
const fireworks=[];
//delay to add fire works
const delay=500;
function clear(){
gl.beginPath();
gl.fillStyle="rgba(0,0,0,0.5)";
gl.fillRect(0,0,canvas.width,canvas.height);
gl.closePath()
}
function random_fireworks(){
console.log("fired")
//start position
var x0=Math.random(0.3,0.8)*canvas.width;
var y0=canvas.height+500;
//target
var x1=Math.random(0.5,0.6)*canvas.width;
var y1=Math.random(0.5,0.6)*canvas.height;
fireworks.push(create_fireworks(x0,y0,{x:x1,y:y1}));
}
function update(){
clear();
for(i in particles){
particles[i].update(gl,particles);
}
for(i in fireworks){
fireworks[i].update(gl,fireworks,particles,canvas);
}
setTimeout(update,refresh_rate);
}
update();
setInterval(random_fireworks,delay);
});
Here is breakdown of the JavaScript code that animates the fireworks:
- Initialization:
- The code waits for the DOM content to be fully loaded (
DOMContentLoaded
event). - It retrieves the canvas element with the id "fireworksCanvas" and sets its dimensions to match the window size.
- A refresh rate (
refresh_rate
) is defined for the animation loop. - Arrays
particles
andfireworks
are created to store instances of particle and fireworks objects.
- The code waits for the DOM content to be fully loaded (
- Canvas Clearing Function (
clear
):- The
clear
function is defined to clear the canvas on each animation frame. It fills the canvas with a semi-transparent black color, creating a fading effect to simulate trails.
- The
- Random Fireworks Function (
random_fireworks
):- This function is responsible for creating random fireworks at a certain interval (
delay
). - It generates random start and target positions for the fireworks and adds a new fireworks object to the
fireworks
array using thecreate_fireworks
helper function.
- This function is responsible for creating random fireworks at a certain interval (
- Update Function (
update
):- The
update
function is the main animation loop. - It clears the canvas, updates and draws each particle in the
particles
array, and updates and draws each firework in thefireworks
array. - The
setTimeout
function is used to call theupdate
function at regular intervals (refresh_rate
), creating a continuous animation loop.
- The
- Initial Animation Start:
- The
update
function is initially called to start the animation loop. - The
random_fireworks
function is set to be called at regular intervals to create new fireworks and keep the display dynamic.
- The