SOURCE

const CANVAS = document.createElement("canvas"),
  CTX = CANVAS.getContext("2d"),
  NUM_BODIES = 15,
  COLOR_MULT = 255 / NUM_BODIES;

let animating = true,
  radius;

const setCanvasSize = () => {
  CANVAS.width = window.innerWidth;
  CANVAS.height = window.innerHeight;
  radius = CANVAS.width >= CANVAS.height
    ? CANVAS.height * 0.4
    : CANVAS.width * 0.4;
};

const drawTemplate = () => {
  CTX.beginPath();
  CTX.arc(CANVAS.width * 0.5, CANVAS.height * 0.5, radius, 0, Math.PI * 2);
  CTX.closePath();
  CTX.stroke();
}

const drawMain = delta => {
  let i = 1;
  let j = 1;
  let angleIncr = Math.PI / NUM_BODIES;
  
  // draw lines first
  for (i; i <= NUM_BODIES; i++) {
    let angle = i * angleIncr;
    
    CTX.beginPath();
    CTX.moveTo(
      CANVAS.width * 0.5 - radius * Math.cos(angle),
      CANVAS.height * 0.5 - radius * Math.sin(angle)
    );
    CTX.lineTo(
      CANVAS.width * 0.5 + radius * Math.cos(angle),
      CANVAS.height * 0.5 + radius * Math.sin(angle)
    );
    CTX.closePath()
    CTX.stroke();
  }
  
  // draw dots on top
  for (j; j <= NUM_BODIES; j++) {
    let angle = j * angleIncr;
    let node = [
      CANVAS.width * 0.5 + radius * Math.cos(angle) * Math.sin(delta + angle),
      CANVAS.height * 0.5 + radius * Math.sin(angle) * Math.sin(delta + angle)
    ];
    
    CTX.save();
    CTX.fillStyle = `rgb(${j * COLOR_MULT}, 0, ${j * COLOR_MULT})`;
    CTX.beginPath();
    CTX.arc(node[0], node[1], 10, 0, Math.PI * 2);
    CTX.closePath();
    CTX.fill();
    CTX.restore();
  }
}

const update = delta => {
  CTX.clearRect(0, 0, CANVAS.width, CANVAS.height);
  drawTemplate();
  drawMain(delta);
};

const render = delta => {
  if (!delta) delta = 0;
  delta *= 0.0015;
  update(delta);
  if (animating) requestAnimationFrame(render);
}

const onResize = () => {
  setCanvasSize();
  update();
};

const addEventListeners = () => {
  window.addEventListener("resize", onResize);
};

const init = () => {
  setCanvasSize();
  addEventListeners();
  document.body.appendChild(CANVAS);
  render();
};

init();
body {
  background-image: radial-gradient(circle at 50% 50%, #fff 0%, #666 120%);
}
console 命令行工具 X clear

                    
>
console