Mouse cursor snaps to the nearest grid intersection and shows a highlighted cell to prove placement/snap behavior.


Code for Above

<div style="max-width:1500px;margin:0 auto;">
<iframe
  title="POC — Grid Snap Cursor"
  scrolling="no"
  style="width:1500px;height:1500px;border:0;display:block;background:#000;border-radius:14px;box-shadow:0 20px 60px rgba(0,0,0,.5);"
  sandbox="allow-scripts allow-same-origin"
  srcdoc='
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>POC — Grid Snap Cursor</title>
<style>
  html, body { margin:0; width:100%; height:100%; overflow:hidden; background:#000; }
  canvas { display:block; outline:none; cursor:crosshair; }
  .hint { position:absolute; left:12px; bottom:12px; color:#aaa; font:14px system-ui; user-select:none; }
</style>
</head>
<body>
<canvas id="c" width="1500" height="1500"></canvas>
<div class="hint">Move mouse: snap to grid • Click: place marker • Right click: clear</div>

<script>
const c = document.getElementById("c");
const x = c.getContext("2d");
const W = 1500, H = 1500;

c.addEventListener("contextmenu", e => e.preventDefault());

const GRID = 75;

let mx = W/2, my = H/2;
let snapX = 0, snapY = 0;

const marks = [];

function canvasPos(e){
  const r = c.getBoundingClientRect();
  mx = (e.clientX - r.left) * (c.width / r.width);
  my = (e.clientY - r.top)  * (c.height / r.height);
}

c.addEventListener("mousemove", (e) => {
  canvasPos(e);
  snapX = Math.round(mx / GRID) * GRID;
  snapY = Math.round(my / GRID) * GRID;
});

c.addEventListener("click", () => {
  marks.push({ x: snapX, y: snapY });
});

c.addEventListener("mousedown", (e) => {
  if (e.button === 2) marks.length = 0; // right click clears
});

function draw(){
  x.clearRect(0,0,W,H);

  // grid
  x.strokeStyle = "rgba(255,255,255,0.06)";
  x.lineWidth = 1;
  for (let i=0;i<=W;i+=GRID){ x.beginPath(); x.moveTo(i,0); x.lineTo(i,H); x.stroke(); }
  for (let j=0;j<=H;j+=GRID){ x.beginPath(); x.moveTo(0,j); x.lineTo(W,j); x.stroke(); }

  // highlight snapped cell
  x.fillStyle = "rgba(255,255,255,0.06)";
  x.fillRect(snapX - GRID/2, snapY - GRID/2, GRID, GRID);

  // snapped crosshair
  x.strokeStyle = "rgba(255,255,255,0.28)";
  x.lineWidth = 2;
  x.beginPath();
  x.moveTo(snapX - 18, snapY); x.lineTo(snapX + 18, snapY);
  x.moveTo(snapX, snapY - 18); x.lineTo(snapX, snapY + 18);
  x.stroke();

  // placed markers
  x.fillStyle = "rgba(255,255,255,0.85)";
  for (const m of marks){
    x.beginPath();
    x.arc(m.x, m.y, 6, 0, Math.PI*2);
    x.fill();
  }

  // HUD
  x.fillStyle = "rgba(255,255,255,0.6)";
  x.font = "14px system-ui";
  x.fillText(`grid=${GRID}  mouse=(${mx|0},${my|0})  snap=(${snapX|0},${snapY|0})  marks=${marks.length}`, 12, 24);

  requestAnimationFrame(draw);
}
draw();
</script>
</body>
</html>
'></iframe>
</div>