Snippet

Ripple cone

Full page view

Description

A series of circles which follow your pointer.

Created on 26 June 2026.

Code

<style>
  :root {
    color-scheme: light dark;
  }

  canvas {
    position: fixed;
    width: 100%;
    height: 100%;
    inset: 0;
    cursor: none;
    touch-action: none;
  }

  @media (prefers-color-scheme: dark) {
    canvas {
      filter: invert(1);
    }
  }
</style>

<canvas></canvas>

<script>
  const canvas = document.querySelector('canvas'),
    ctx = canvas.getContext('2d'),
    circles = [],
    resolution = devicePixelRatio;

  let x = innerWidth * resolution / 2, 
    y = innerHeight * resolution / 2;
  
  addEventListener('pointermove', ev => {
    x = ev.x * resolution;
    y = ev.y * resolution;
  });


  function move() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    circles.push({ x, y });
    if (circles.length > 20) circles.shift();
    let radius = 100 * resolution;
    ctx.lineWidth = resolution;
    for (const { x, y } of circles) {
      radius -= 5 * resolution;
      ctx.beginPath();
      ctx.ellipse(x, y, radius, radius, 0, 0, 2 * Math.PI);
      ctx.stroke();
    }
    requestAnimationFrame(move);
  }

  move();

  function resizeCanvas() {
    x = (canvas.width = innerWidth * resolution) / 2;
    y = (canvas.height = innerHeight * resolution) / 2;
  }
  resizeCanvas();
  addEventListener('resize', resizeCanvas);
</script>