JSFiddle - React, Tailwind, and code Playground

HTML

<canvas id="canvas" width="500" height="300"></canvas>

CSS

body {
  background:#222222;
  text-align:center;
}
#sfcanvas {
  margin-left:auto;
  margin-right:auto;
  border-top:solid 2px white;
}

JavaScript

function fall (flakes,fmaxr) {
  step = 0.4;
  for ( i=0; i<flakes.length; i++ )
      flakes[i][1] += step*flakes[i][2];
}

function checkFlakesPosition(flakes,fmaxr,canvash) {
  for ( i=0; i<flakes.length; i++ )
  if ( flakes[i][1] > canvash+fmaxr ) {
      flakes[i][1] = -fmaxr;
      flakes[i][2] = Math.random()*fmaxr;
  }
}

function draw (flakes,canvasw,canvash,ctx) {
  ctx.clearRect(0,0,canvasw,canvash);
  for ( i=0; i<flakes.length; i++ ) {
      ctx.fillStyle = "rgba(255, 255, 255, " + .9 * ( canvash-flakes[i][1] )/canvash + ")"
      ctx.beginPath();
      ctx.arc(flakes[i][0], flakes[i][1], flakes[i][2], 0, Math.PI*2, true); 
      ctx.closePath();
      ctx.fill();
  }
}

function animation (flakes,fcount,fmaxr,canvasw,canvash,ctx)
{
  draw(flakes,canvasw,canvash,ctx);
  fall(flakes,fmaxr);
  checkFlakesPosition(flakes,fmaxr,canvash);
}

if (canvas.getContext)
{
  var ctx = document.getElementById('canvas').getContext('2d');

  var fcount  = 80;
  var flakes  = new Array();
  var fmaxr   = 10;
  var canvasw = 800; // must match the value of the HTML element
  var canvash = 400; // must match the value of the HTML element

  // init flakes
  for ( i=0; i<fcount; i++ )
  {
      flakes[flakes.length] = new Array();
      flakes[flakes.length-1][0] = 10+Math.random()*(canvasw-2*fmaxr); // x
      flakes[flakes.length-1][1] = -fmaxr; // y
      flakes[flakes.length-1][2] = 0.2*fmaxr + Math.random()*(0.8*fmaxr); // r
      flakes[flakes.length-1][3] = 0; // type
  }

  setInterval(function(){animation(flakes,fcount,fmaxr,canvasw,canvash,ctx)},50);
}