<button id=restart>restart</button>
 * {
      margin: 0;
      overflow: hidden;
    }

button {
  position: fixed;
  color: white;
  background: transparent;
  border: none;
  font-face: Helvetica, sans-serif;
  padding: 2rem;
  font-size: 1.4rem;
  cursor: pointer;
  letter-spacing: 2px;
  transition: all 200ms ease-out;
}

button:hover {
  color: #00fff9;
  scale: 1.2;
}
const canvas = document.createElement('canvas')
const c = canvas.getContext('2d')

canvas.width = innerWidth
canvas.height = innerHeight 
document.body.append(canvas)

c.fillStyle = 'red'
c.fillRect(0, 0, canvas.width, canvas.height)

let grav = .11
let floor = innerHeight - innerHeight / 4

class Dot {
  constructor({
    first,
    x,
    y,
    r,
    idx
  }) {
    this.x = x
    this.y = y
    this.r = r
    this.vx = (first) ? Math.random() * 3 + 1 :
      Math.random() * 6 - 3

    this.vy = -Math.random() * 6 - 3

    this.a = 1
    this.idx = idx 
    this.floor = floor + Math.random() * (this.r / 2 + 150)
  }
  draw() {
    if (this.dead) {
      c.globalAlpha = this.a
      this.r += 3;
      this.a -= .04
      if (this.a < 0) {
        this.a = 0
        return
      }
      c.fillStyle = '#ff5700'
      c.beginPath()
      c.arc(this.x, this.y, this.r, 0, 7)
      c.fill()
      return
    }
    this.x += this.vx
    this.y += this.vy
    if (this.x + this.r >= innerWidth) {
      this.vx *= -1;
    }
    if (this.x - this.r < 0) { 
      this.vx *= -1;
    }

    this.vy += grav

    if (this.y > this.floor - this.r) {
      this.vy *= -.5
      this.y = this.floor - this.r
      this.vx *= .7
      if (dots.length < 400 ) {

        dots.push(new Dot({
          x: this.x,
          y: this.y,
          r: this.r * .6 
        }))
        dots.push(new Dot({
          x: this.x,
          y  : this.y,
          r: this.r * .6
        }))
        this.dead = true
      }
    }
    c.globalAlpha = 1 
    c.fillStyle = 'black'
    c.beginPath()
    c.arc(this.x, this.y, this.r, 0, 7)
    c.fill()
  }
}

let dots;

function spurn() { 
  dots = []

  dots[0] = new Dot({
    first: true,
    x: 150,
    y: innerWidth / 2,
    r: 100
  })
}
spurn()

restart.onclick = spurn


function loop() {
  c.fillStyle = 'rgba(255, 0, 0, 1)'
  c.fillRect(0, 0, canvas.width, canvas.height)
  dots.forEach(d => d?.draw?.())

  requestAnimationFrame(loop)
}
loop()

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.