Grain animation

by mathiasisaksen

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Fiddle</title>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.min.js"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.9/dat.gui.min.js"></script>
</head>
<body>
</body>
</html>

CSS

html,
body {
  margin: 0;
  padding: 0;
  height: 100%;
}

body {
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: black;
  overflow: hidden;
}

main {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  width: 100%;
}

canvas {
  display: block;
}

JavaScript

let w;
let h;

let sketchGfx;
let grainImg;
let pd;
let counter;
let maxCount;

function setup() {
  w = windowWidth;
  h = windowHeight;
  createCanvas(w, h);

  pd = pixelDensity();
  
  sketchGfx = createGraphics(w, h);
  grainImg = createImage(2*pd*w, 2*pd*h);

  addGrain(grainImg);
  
  counter = 0;
  maxCount = 50;
  
  frameRate(50);
  
  const gui = new dat.GUI();
  const guiParams = { running: false, toggleRunning: () => {	  guiParams.running = !guiParams.running;
  	if (guiParams.running) {
      loop();
    } else {
      noLoop();
    }
  }  };
  gui.add(guiParams, "toggleRunning").name("Toggle animation").onChange(() => {	
  	if (guiParams.running) {
      loop();
    } else {
      noLoop();
    }
  });
  
  noLoop();
}

function draw() {
  background("white");
  
  drawSketch(sketchGfx);
  
  if (counter === 0) {
  	image(grainImg, 0, 0, w, h, 0, 0, pd*w, pd*h);
    counter++;
    return;
  }

  image(sketchGfx, 0, 0, w, h);
  //image(grainImg, 0, 0, w, h, 0, 0, pd*w, pd*h);

  blend(grainImg, 0, 0, pd*w, pd*h, 0, 0, w, h, OVERLAY);

  counter++;
}

function addGrain(img) {
  const nCols = img.width;
  const nRows = img.height;

  img.loadPixels();

  for (let row = 0; row < nRows; row++) {
    for (let col = 0; col < nCols; col++) {
      const ind = 4 * (row * nCols + col);

      const v = random();
      img.pixels[ind + 0] = 255 * v;
      img.pixels[ind + 1] = 255 * v;
      img.pixels[ind + 2] = 255 * v;
      img.pixels[ind + 3] = 255;
    }
  }
  img.updatePixels();
}

function drawSketch(gfx) {
  const r = w/8;
  gfx.ellipseMode(RADIUS);
  gfx.colorMode(HSL);
  const hue = 5*counter % 360;
  gfx.fill(hue, 100, 50);
  gfx.noStroke();
  gfx.circle(0.5*r + r + 0.1*r*(counter % maxCount), h/2, r);
}