JSFiddle - React, Tailwind, and code Playground

by Yaroslav Samardak

HTML

<canvas id="canvas">

CSS

body {
  padding: 0;
  margin: 0;
  overflow: hidden;
}

canvas {
  width: 100dvw;
  height: 100dvh;
  background: black;
  margin: 0;
}

JavaScript

const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
const dpr = window.devicePixelRatio || 1
let cr = canvas.getBoundingClientRect()
let w = 0;
let h = 0;
let s = 1;
let mx = 0;
let my = 0;

function renderCursor() {
  const radius = 32 * s;

  ctx.save()
  ctx.beginPath()
  ctx.arc(mx, my, radius, 0, 2 * Math.PI)
  let x = Math.round(Date.now() / 10) % 512
  if (x > 256) x = 256 - (x - 256)

  ctx.strokeStyle = `rgba(${ x }, ${ 256 - x }, ${ 256 }, 1)`
  // ctx.strokeStyle = `rgba(${ x }, ${ 256 - x }, ${ (255 - x + 384) % 256 }, 1)`
  ctx.lineWidth = 5 * s
  ctx.stroke()
  ctx.restore()
}

canvas.addEventListener('mousemove', (event) => {
  const mouseX_css = event.clientX - cr.left
  const mouseY_css = event.clientY - cr.top

  // Scale by the ratio of canvas internal width to CSS width, and then by DPR
  mx = Math.floor(mouseX_css * (canvas.width / cr.width) * s)
  my = Math.floor(mouseY_css * (canvas.height / cr.height) * s)

  // If ctx.scale(dpr, dpr) was used, further divide by dpr
  // mx = Math.floor((mouseX_css * (canvas.width / rect.width)) / dpr)
  // my = Math.floor((mouseY_css * (canvas.height / rect.height)) / dpr)
})

function resizeCanvas() {
  cr = canvas.getBoundingClientRect()
  w = window.innerWidth * dpr
  h = window.innerHeight * dpr
  canvas.width = w
  canvas.height = h
}

window.addEventListener('resize', resizeCanvas, false)

function render() {
  ctx.clearRect(0, 0, w, h);

  renderCursor();
  window.requestAnimationFrame(render);
}

resizeCanvas()
render()