JSFiddle - React, Tailwind, and code Playground

by Josh Pullen

JavaScript

const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");

canvas.width = 640;
canvas.height = 480;
canvas.style.border = "1px solid black";

document.body.append(canvas);

let t = 0;

function cycle(cx, cy, r, startAngle = -Math.PI / 2, level = 0) {
  if (level < 3) {
    for (let i = 0; i < 3; i++) {
      const angle = startAngle + 2 * Math.PI * (i / 3);

      cycle(
        cx + Math.cos(angle) * r,
        cy + Math.sin(angle) * r,
        r * 0.5,
        angle + t * level * 3 * (level % 2 - 0.5),
        level + 1
      );
    }
  } else {
  	ctx.beginPath();
    // ctx.arc(cx, cy, r, 0, 2 * Math.PI);
    ctx.lineJoin = "round";
    ctx.lineCap = "round";
    for (let i = 0; i <= 3; i++) {
      const angle = startAngle + 2 * Math.PI * (i / 3);
      const x = cx + r * Math.cos(angle);
      const y = cy + r * Math.sin(angle);
      if (i === 0) {
      	ctx.moveTo(x, y);
      } else {
        ctx.lineTo(x, y);
      }
    }
    ctx.stroke();
  }
}

const startTime = Date.now();

function render() {
  requestAnimationFrame(render);

	ctx.fillStyle = "#148aff";
	ctx.fillRect(0, 0, canvas.width, canvas.height);
  
  t = (Date.now() - startTime) / 1000;
  // t = 2 * Math.PI;
  
  ctx.lineWidth = 6;
  ctx.strokeStyle = "#0759ab";
  cycle(
    canvas.width / 2,
    canvas.height / 2 + canvas.height / 12 + 2,
    canvas.height / 4
  );
  
  ctx.strokeStyle = "white";
  cycle(
    canvas.width / 2,
    canvas.height / 2 + canvas.height / 12,
    canvas.height / 4
  );
}

render();