<canvas id="stage" width="512" height="512"></canvas>
html, body {
    height: 100%;
}

body {
   display: flex;
   align-items: center;
   justify-content: center;
   background: rgb(5, 26, 50);
}
View Compiled
// Set up canvas
let canvas = document.querySelector('#stage');

// High DPI Canvas
// https://www.html5rocks.com/en/tutorials/canvas/hidpi/
let devicePixelRatio = window.devicePixelRatio || 1;
let ctx = canvas.getContext('2d');
let backingStoreRatio =
    ctx.webkitBackingStorePixelRatio ||
    ctx.mozBackingStorePixelRatio ||
    ctx.msBackingStorePixelRatio ||
    ctx.oBackingStorePixelRatio ||
    ctx.backingStorePixelRatio ||
    1;
let ratio = devicePixelRatio / backingStoreRatio;
let ow = canvas.width;
let oh = canvas.height;
if (devicePixelRatio !== backingStoreRatio) {
   canvas.width = ow * ratio;
   canvas.height = oh * ratio;
   canvas.style.width = ow + 'px';
   canvas.style.height = oh + 'px';
}

ctx.translate(canvas.width / 2, canvas.height / 2);
   ctx.scale(ratio, ratio);

// initial draw
let {width: w, height: h} = canvas;
ctx.strokeStyle = 'rgba(87,225,255,0.01)';
ctx.fillStyle = 'rgba(87,225,255,0.04)';
ctx.lineWidth = 1;
ctx.lineCap = 'round';
ctx.globalCompositeOperation = 'lighter';

let k = 4; // control points to draw a spline
let N = 10;
let rings = 3;
let controlPtsGroups = [];
for (let o = 0; o < rings; o++) {
   // prepare controls point
   let r = ow / 6 + o * ow / 8;
   let controlPts = [];
   let n = N + o * 5;
   for (let i = 0; i < n; i++) {
      let rad = 2 * Math.PI * i / n;
      let x = Math.cos(rad) * r;
      let y = Math.sin(rad) * r;
      controlPts.push([x, y, x, y]); // [cx, cy, ox, oy]
   }
   controlPtsGroups.push(controlPts);
}

// The uniform bspline matrix
// http://graphics.cs.ucdavis.edu/~joy/ecs178/Unit-7-Notes/MatrixBSpline.pdf
let UNIFORM_BSPLINE_MATRIX = math.matrix([
   [1 / 6, 4 / 6, 1 / 6, 0],
   [-3 / 6, 0, 3 / 6, 0],
   [3 / 6, -6 / 6, 3 / 6, 0],
   [-1 / 6, 3 / 6, -3 / 6, 1 / 6],
]);

let SPLINE_SEGMENT = 20;

// render loop
requestAnimationFrame(function loop() {
   for (let o = 0; o < rings; o++) {
      let controlPts = controlPtsGroups[o];
      let n = controlPts.length;
      for (let i = 0; i < n; i += 1) {
          let controlMatrix = math.multiply(UNIFORM_BSPLINE_MATRIX, [
             controlPts[(i + 0) % n],
             controlPts[(i + 1) % n],
             controlPts[(i + 2) % n],
             controlPts[(i + 3) % n],
          ]);
         for (let j = 0; j < 1; j += 1 / SPLINE_SEGMENT) {
            let ts = [1, j, j * j, j * j * j];
            let p = math.multiply(ts, controlMatrix);
            ctx.fillRect(p.get([0]), p.get([1]), 1, 1);
         }
      }
      // spread
      for (let i = 0; i < n; i++) {
         let [cx, cy, ox, oy] = controlPts[i];
         let spread = 1 + Math.sqrt((cx - ox) * (cx - ox) + (cy - oy) * (cy - oy)) / 20;
         controlPts[i][0] += (Math.random() * 2 - 1) * spread;
         controlPts[i][1] += (Math.random() * 2 - 1) * spread;
      }
   }
   requestAnimationFrame(loop);
});
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://unpkg.com/mathjs@9.4.2/lib/browser/math.js