<svg class="canvas" viewBox="0 0 200 200"></svg>
<button>Regenerate</button>
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  height: 100vh;
  display: grid;
  place-items: center;
  background: hsl(0, 0%, 96%);
}

.canvas {
  width: 75vmin;
  height: 75vmin;
  background: hsl(0, 0%, 100%);
}

button {
  position: absolute;
  bottom: 1rem;
  right: 1rem;
  background: #111;
  color: #fff;
  padding: 0.5rem 1.75rem;
  border: none;
  -webkit-font-smoothing: antialiased;
  -mox-osx-font-smoothing: grayscale;
  cursor: pointer;
}
import { SVG } from "https://cdn.skypack.dev/@svgdotjs/svg.js";
import {
  spline,
  random
} from "https://cdn.skypack.dev/@georgedoescode/generative-utils@1.0.0";

const svg = SVG(".canvas");
const btn = document.querySelector("button");
const { width } = svg.viewbox();
const numSteps = 10;
const stepSize = width / numSteps;

function generate() {
  // clear the contents of the SVG
  svg.clear();

  const points = [];

  // plot 10 equally spaced points along the canvas width
  for (let x = 0; x <= width; x += stepSize) {
    // y = vertical center of the viewport (100) +/- 10
    const y = random(90, 110);

    // render an svg circle at the current { x, y } position
    svg.circle(4).cx(x).cy(y).fill("deeppink");

    // store the { x, y } coordinate to use later
    points.push({
      x,
      y
    });
  }

  // array of { x, y } coordinates, tension, "close" the shape
  const pathData = spline(points, 1, false);
  // render an svg <path> using the spline path data
  svg.path(pathData).stroke("#111").fill("none");
}

generate();

btn.addEventListener("click", () => {
  generate();
});

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.