<div>
  <canvas id="canvas" width="400px" height="400px'"></canvas>
</div>
:root {
  --background:  rgba(22,22,22,1);
}
body {
  background: var(--background);
}
div {
  width: 400px;
  margin: 0 auto;
}
View Compiled
// https://www.maissan.net/articles/javascript-spirograph
var canvas = document.getElementById("canvas");
var canvasWidth = canvas.width;
var canvasHeight = canvas.height;
var ctx = canvas.getContext("2d");
var canvasData = ctx.getImageData(0, 0, canvasWidth, canvasHeight);

// fun things to change
const backgroundColor = `rgba(22,22,22,1)`
const strokeWidth = 3;
var radius1 = 20;
var radius2 = 100;
var ratio = 10;
const color1 = chroma.random().hex();
const color2 = chroma.random().hex();
const color3 = chroma.random().hex();

document.documentElement.style
    .setProperty('--background', backgroundColor);

function drawSpirograph(context, cx, cy, radius1, radius2, ratio, color, limit = 2) {
  let x, y;
  let theta = 0;

  const draw = setInterval(() => {

    // Move to starting point (theta = 0)
    context.beginPath();
    if (!x) {
      context.moveTo(cx + radius1 + radius2, cy);
    } else {
      context.moveTo(x, y);
    }

    // Draw segments from theta = 0 to theta = 2PI
    var R = radius1;
    var r = radius2;
    var angle = theta;
    var d = ratio;
    x = cx + radius1 * Math.cos(theta) + radius2 * Math.cos(theta * ratio);
    y = cy + radius1 * Math.sin(theta) + radius2 * Math.sin(theta * ratio);
    
    context.lineTo(x, y);
    // Apply stroke
    ctx.strokeStyle = color;
    ctx.lineWidth = strokeWidth;
    context.stroke();

    if (theta > Math.PI * limit) {
      clearInterval(draw);
    }
    theta += 0.01;
  }, 0);
}



drawSpirograph(
  ctx,
  canvas.width / 2,
  canvas.height / 2,
  radius1,
  radius2,
  ratio,
  color1
);


drawSpirograph(
  ctx,
  canvas.width / 2,
  canvas.height / 2,
  radius1 * 5,
  radius2 - 20,
  ratio / 2,
  color2,
  
);


drawSpirograph(
  ctx,
  canvas.width / 2,
  canvas.height / 2,
  radius1 * 6,
  radius2 / 5,
  ratio * 60,
  color3,
  8
);
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/chroma-js/2.1.0/chroma.min.js