JSFiddle - React, Tailwind, and code Playground

HTML

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

CSS

* { margin: 0px; overflow: hidden; }

JavaScript

c = document.getElementById("c");
w = c.width = innerWidth;
h = c.height = innerHeight;
d = c.getContext("2d");

function renderBackground(d) {
  d.fillStyle = "black";
  d.fillRect(0,0,w,h);
  d.fillStyle = "white";
  d.fillRect(0,0,w/2,h/2);
  d.beginPath();
  d.moveTo(-w/2,h);
  d.lineTo(0,3 * h/2);
  d.lineTo(3 * w/2, 0);
  d.lineTo(w, -h/2);
  d.closePath();
  d.fillStyle = "rgb(128,128,128)";
  d.fill();
}

// w : pixels / screen
// phase : div
function pathSeg(d, y, pixPerSeg, pixPerDiv, divPerCycle, pixPerAmp, c0, c1, phase) {
  const segPerDiv = Math.round(pixPerDiv / pixPerSeg);
  const segPerScreen = Math.ceil(segPerDiv * w / pixPerDiv);
  for (let i = 0; i <= segPerScreen; i++) { // i : segment
	 const x = i * pixPerDiv / segPerDiv; // x : pixels
	 const nextX = (i + 1) * pixPerDiv / segPerDiv;
	 const cyc = i / (segPerDiv * divPerCycle); // cyc : cycles
	 const nextCyc = (i + 1) / (segPerDiv * divPerCycle);
	 const div = Math.floor(i / segPerDiv + phase) // div : division;
	 d.beginPath();
	 d.moveTo(x, y - pixPerAmp * Math.sin(2 * Math.PI * cyc));
	 d.lineTo(nextX, y - pixPerAmp * Math.sin(2 * Math.PI * nextCyc));
	 d.lineWidth = 2;
	 d.strokeStyle = div % 2 ? c1 : c0;
	 d.stroke();
  }
}

let gphase = 0;

function render(d) {
  renderBackground(d);
  const NUM_WAVES = 7;
  const OFFSET = 8;
  const pixPerAmp = 6;
  const pixPerDiv = 30;
  const pixPerSeg = 2;
  const c0 = "rgb(64,64,64)";
  const c1 = "rgb(192,192,192)"
  for (let i = 0; i < NUM_WAVES; i++) {
	 const phase = gphase + (i % 2 ? 0.5 : 0);
	 pathSeg(d, OFFSET + (i + 0.5) * h / NUM_WAVES, pixPerSeg, pixPerDiv, 2, pixPerAmp, c0, c1, phase);
	 pathSeg(d, -OFFSET + (i + 0.5) * h / NUM_WAVES, pixPerSeg, pixPerDiv, 2, pixPerAmp, c0, c1, phase);
  }
  gphase -= 0.02;
  requestAnimationFrame(() => render(d));
}

render(d);