Let's welcome the New Year with fireworks!



We'll keep the code short and simple, so our fireworks will not look very fancy or realistic - in fact, they will be more similar to the ones you saw on Geocities twenty years ago. But it's still a good coding exercise.

The main program [lines 5-31] first declares the variables and then creates an array of the firework objects. Each firework will have its own x and y coordinates, age (time elapsed since the explosion), phase (fly/explode) and an array of sparks.
Each spark in turn has its own horizontal (vx) and vertical (vy) velocity, weight, which determines how quickly it falls and a color (determined by red, green and blue components).

In [31], we kick off the main animation function - explode [40-75].
This function updates and draws each spark of each firework.
[44-62] is the explosion phase. In this phase, each spark has a trail of 10 rectangles. We calculate the position of each rectangle [45-48] based on the coordinates of the firework, the velocity of the spark, the 'age' of the explosion and the index of the rectangle. I did not use any ballistic formulas, instead, I came up with this weirdo [48] by trial and error.
[49-52] calculates the color of each rectangle, taking into account the fade factor, which is derived from the 'age' of the explosion - the older the explosion, the darker the color.
[53-56] draws the rectangle
In [60-61], there is a 5% chance of resetting the firework if the explosion is older than 100 frames.
The reset function [33-37] puts the firework back in a random place at the bottom of the screen and the 'fly' phase begins again.
In this phase [64-71], the firework moves up the screen [64] and an extremely rudimentary tail of sparks is drawn [65-69].


There is a .001 chance that the firework will explode (its phase changes) in a given frame [71]. It will explode for sure once the y coordinate reaches 200.

Happy New Year!

<html>
<body style='background-color:black'>
<canvas id='myCanvaswidth='800height='800'></canvas>
<script>
const max_fireworks = 5,
  max_sparks = 50;
let canvas = document.getElementById('myCanvas');
let context = canvas.getContext('2d');
let fireworks = [];
 
for (let i = 0i < max_fireworksi++) {
  let firework = {
    sparks: []
  };
  for (let n = 0n < max_sparksn++) {
    let spark = {
      vxMath.random() * 5 + .5,
      vyMath.random() * 5 + .5,
      weightMath.random() * .3 + .03,
      redMath.floor(Math.random() * 2),
      greenMath.floor(Math.random() * 2),
      blueMath.floor(Math.random() * 2)
    };
    if (Math.random() > .5spark.vx = -spark.vx;
    if (Math.random() > .5spark.vy = -spark.vy;
    firework.sparks.push(spark);
  }
  fireworks.push(firework);
  resetFirework(firework);
}
window.requestAnimationFrame(explode);
 
function resetFirework(firework) {
  firework.x = Math.floor(Math.random() * canvas.width);
  firework.y = canvas.height;
  firework.age = 0;
  firework.phase = 'fly';
}
 
function explode() {
  context.clearRect(00canvas.widthcanvas.height);
  fireworks.forEach((firework,index) => {
    if (firework.phase == 'explode') {
        firework.sparks.forEach((spark) => {
        for (let i = 0i < 10i++) {
          let trailAge = firework.age + i;
          let x = firework.x + spark.vx * trailAge;
          let y = firework.y + spark.vy * trailAge + spark.weight * trailAge * spark.weight * trailAge;
          let fade = i * 20 - firework.age * 2;
          let r = Math.floor(spark.red * fade);
          let g = Math.floor(spark.green * fade);
          let b = Math.floor(spark.blue * fade);
          context.beginPath();
          context.fillStyle = 'rgba(' + r + ',' + g + ',' + b + ',1)';
          context.rect(xy44);
          context.fill();
        }
      });
      firework.age++;
      if (firework.age > 100 && Math.random() < .05) {
        resetFirework(firework);
      }
    } else {
      firework.y = firework.y - 10;
      for (let spark = 0spark < 15spark++) {
        context.beginPath();
        context.fillStyle = 'rgba(' + index * 50 + ',' + spark * 17 + ',0,1)';
        context.rect(firework.x + Math.random() * spark - spark / 2firework.y + spark * 444);
        context.fill();
      }
      if (Math.random() < .001 || firework.y < 200firework.phase = 'explode';
    }
  });
  window.requestAnimationFrame(explode);
}
</script>
</body>
</html>



Check out these programming tutorials:

JavaScript:

Particle constellations (42 lines)

3d stereogram (0 lines)

Optical illusion (18 lines)

Spinning squares - visual effect (25 lines)

Oldschool fire effect (20 lines)

Fireworks (60 lines)

Animated fractal (32 lines)

Minesweeper game (80 lines)

Physics engine for beginners

Physics engine - interactive sandbox

Physics engine - silly contraption

Starfield (21 lines)

Yin Yang with a twist (4 circles and 20 lines)

Tile map editor (70 lines)

Sine scroller (30 lines)

Turtle graphics

Interactive animated sprites

Image transition effect (16 lines)

Wholla lotta quadratic curves (50 lines)

Your first program in JavaScript: you need 5 minutes and a notepad


Fractals in Excel

Python in Blender 3d:

Domino effect (10 lines)


Wrecking ball effect (14 lines)

3d fractal in Blender Python