JSFiddle - React, Tailwind, and code Playground

by schrodingers

HTML

<canvas id="canvas"></canvas>

CSS

canvas {
  background: #444;
  
}

JavaScript

/* LIQUID */
var MOUSE_INFLUENCE = 1,
  GRAVITY_X = 0,
  GRAVITY_Y = 0.001,
  
  MOUSE_REPEL = true,
  GROUPS = [50, 55, 50],
  
  GROUP_COLOURS = ['rgba(97,160,232'];

window.requestAnimFrame =
  window.requestAnimationFrame ||
  window.webkitRequestAnimationFrame ||
  window.mozRequestAnimationFrame ||
  window.oRequestAnimationFrame ||
  window.msRequestAnimationFrame ||
  function(callback) {
    window.setTimeout(callback, 1000 / 60);
  };


var fluid = function() {
    var ctx, width, height, num_x, num_y, particles, grid, meta_ctx, threshold = 120,
    
      play = false,  
      spacing = 45,
      radius = 30,
      limit = radius * 0.66,
      textures, num_particles;

    var mouse = {
      down: false,
      x: 0,
      y: 0
    };

    var process_image = function() {
      var imageData = meta_ctx.getImageData(0, 0, width, height),
      pix = imageData.data;
      for (var i = 0, n = pix.length; i < n; i += 4) {
        (pix[i + 3] < threshold) && (pix[i + 3] /= 6);
      }

      ctx.putImageData(imageData, 0, 0);
    };

    var run = function() {
      meta_ctx.clearRect(0, 0, width, height);
      for (var i = 0, l = num_x * num_y; i < l; i++)
        grid[i].length = 0;

      var i = num_particles;
      while (i--)
        particles[i].first_process();
      i = num_particles;
      while (i--)
        particles[i].second_process();

      process_image();

      if (mouse.down) {
        ctx.canvas.style.cursor = 'none';
        ctx.fillStyle = 'rgba(97, 160, 232, 0.05)';
        ctx.beginPath();
        ctx.arc(
          mouse.x,
          mouse.y,
          radius * MOUSE_INFLUENCE,
          0,
          Math.PI * 2
        );
        ctx.closePath();
        ctx.fill();

        ctx.fillStyle = 'rgba(97, 160, 232, 0.05)';
        ctx.beginPath();
        ctx.arc(
          mouse.x,
          mouse.y, (radius * MOUSE_INFLUENCE) / 3,
          0,
          Math.PI * 2
        );
        ctx.closePath();
        ctx.fill();
      }...