Black Rain

Black Rain by JavaScript.

by Tinytsunami

HTML

<canvas></canvas>

CSS

body {
  color: #000000;
  background: #20262e;
  margin: 0px;
}

canvas {
  height: 100%;
  border: none;
}

JavaScript

//=====================================================
// CONSTANT
//=====================================================
let CONSTANT = {
  FPS: 60,
  SCREEN_WIDTH: 800,
  SCREEN_HEIGHT: 449,
  TITLE_DUSTCLOUD_COUNT: 200,
  BACKGROUND_IMAGE: "https://i.imgur.com/0WK7Gsp.png",
  START_IMAGE: "https://i.imgur.com/MheHurM.png",
  LOGO_IMAGE: "https://i.imgur.com/AGaGWmX.png",
  DUST_COLOR: "rgba(0, 0, 0, 0.8)"
};

//=====================================================
// Math Extension
//=====================================================
Math.TAU = 2 * Math.PI;

Math.randInt = function(min, max) {
  return Math.floor(Math.random() * (max - min) + min);
};

Math.randLock = function(rate) {
  return Math.randInt(0, 100) <= rate;
};

Math.inRange = function(value, min, max) {
  return value >= min && value <= max;
};

Math.distance = function(x0, y0, x1, y1) {
  return Math.sqrt(Math.pow(x0 - x1, 2) + Math.pow(y0 - y1, 2));
};

Math.toHex = function(value) {
  let hex = value.toString(16);
  if (hex.length == 1) {
    return `0${hex}`;
  }
  return hex;
};

//=====================================================
// Accumulator
//=====================================================
function Accumulator(from, to, repeat) {
  this.triggers = [];
  this.from = from;
  this.to = to;
  this.repeat = repeat;
  this.now = this.from;
};

Accumulator.prototype.trigger = function(callback, time) {
  try {
    if (time == undefined) {
      time = Math.randInt(this.from, this.to);
    }
    if (!Math.inRange(time, this.from, this.to)) {
      throw new RangeError(`Accumulator: callback is NOT triggered, ${time} must is in [${this.from}, ${this.to}]`);
    }
    let obj = {
      time: time,
      callback: callback,
      active: true
    };
    this.triggers.push(obj);
    return obj;
  } catch (error) {
    console.error(`${error.name}: ${error.message}`);
  }
};

Accumulator.prototype.update = function() {
  if (this.repeat && this.now > this.to) {
    this.now =...