* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  height: 100vh;
  display: grid;
  place-items: center;
}

svg {
  width: 75vmin;
  height: 75vmin;
  overflow: visible;
}
import { SVG } from "https://cdn.skypack.dev/@svgdotjs/svg.js";
import {
  createVoronoiTessellation,
  random,
  randomBias
} from "https://cdn.skypack.dev/@georgedoescode/generative-utils";

let step = 0;

const width = 192;
const height = 192;

const svg = SVG().viewbox(0, 0, width, height).addTo("body");

let tessellation;
let points;

function animate() {
  if (step === 0) {
    svg.clear();

    points = [...Array(48)].map(() => ({
      x: random(0, width),
      y: random(0, height)
    }));

    tessellation = createVoronoiTessellation({
      width,
      height,
      points,
      relaxIterations: 4
    });

    tessellation.cells.forEach((c) => {
      svg.circle(2).fill("#000").cx(c.centroid.x).cy(c.centroid.y);
    });
  }

  if (step === 1) {
    tessellation.cells.forEach((c, index) => {
      svg.polygon(c.points).fill("none").stroke("#E6E5EB");
    });
  }

  if (step === 2) {
    svg.clear();

    tessellation.cells.forEach((c, index) => {
      svg
        .circle(c.innerCircleRadius * 2)
        .fill("#F4F3F6")
        .cx(c.centroid.x)
        .cy(c.centroid.y)
        .scale(0.7)
        .attr("class", "inner-circle");

      svg
        .polygon(c.points)
        .fill("none")
        .stroke("#D3D1DB")
        .attr("class", "cell");
    });
  }

  if (step === 3) {
    tessellation.cells.forEach((cell) => {
      if (random(0, 1) > 0.5) {
        svg
          .circle(cell.innerCircleRadius * 2)
          .cx(cell.centroid.x)
          .cy(cell.centroid.y)
          // Pick a random color for each circle's fill
          .fill(random(["#FFD53D", "#1D1934", "#7257FA"]))
          // Reduce each circle's size a little, to give the pattern some room
          .scale(0.7);

        if (random(0, 1) > 0.75) {
          svg
            .circle(cell.innerCircleRadius * 2)
            .cx(cell.centroid.x)
            .cy(cell.centroid.y)
            // Pick a random color for each circle's fill
            .fill("#fff")
            // Reduce each circle's size a little, to give the pattern some room
            .scale(0.375);
        }
      } else {
        svg
          .line(
            cell.centroid.x - cell.innerCircleRadius / 2,
            cell.centroid.y - cell.innerCircleRadius / 2,
            cell.centroid.x + cell.innerCircleRadius / 2,
            cell.centroid.y + cell.innerCircleRadius / 2
          )
          .stroke({
            width: cell.innerCircleRadius,
            // Pick a random color for each line's fill
            color: random([
              "#F25C54",
              "#48CB8A",
              "#FFD53D",
              "#1D1934",
              "#7257FA"
            ]),
            linecap: "round"
          })
          .scale(0.7)
          .rotate(random(0, 360));
      }
    });
  }

  if (step === 4) {
    document.querySelectorAll(".cell").forEach((c) => (c.style.opacity = 0));
    document
      .querySelectorAll(".inner-circle")
      .forEach((c) => (c.style.opacity = 0));
  }

  step < 6 ? step++ : (step = 0);

  setTimeout(animate, 750);
}

animate();
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.