JSFiddle - React, Tailwind, and code Playground

HTML

<html>
	<body>
		<canvas id="canvas"></canvas>
	</body>
</html>

CSS

body, html {
	margin: 0;
	padding: 0;
	background-color: #AAAAAA;
}

JavaScript

const WIDTH = 32;
const HEIGHT = 24;
const PIXEL_SIZE = 10;

const getPosition = (i) => {
  return {
    x: i % WIDTH,
    y: Math.floor(i / WIDTH),
  };
};

const pixels = Array.from({ length: WIDTH * HEIGHT }, (_, i) => {
  const { x, y } = getPosition(i);

  if ((x % 2 === 0 && y % 2 === 0) || (x % 2 !== 0 && y % 2 !== 0)) {
    return [204, 204, 204, 255];
  }

  return [255, 255, 255, 255];
}).flat();

const data = new ImageData(new Uint8ClampedArray(pixels), WIDTH, HEIGHT);

const canvas = document.getElementById("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const ctx = canvas.getContext("2d");
ctx.imageSmoothingEnabled = false;

const bufferCanvas = document.createElement("canvas");
bufferCanvas.width = WIDTH;
bufferCanvas.height = HEIGHT;
const bufferCtx = bufferCanvas.getContext("2d");

// controls how big the grid is
let scale = 1.5;

// controls where the grid is drawn, 
// starts exactly in the middle of the screen
let originX = canvas.width / 2 - (WIDTH * PIXEL_SIZE * scale) / 2;
let originY = canvas.height / 2 - (HEIGHT * PIXEL_SIZE * scale) / 2;

let offsetX = originX;
let offsetY = originY;


function zoom(event) {
  event.preventDefault();
  
  // Get the offset relative to the canvas element
  offsetX = event.x;
  offsetY = event.y;

  const wheel = event.deltaY < 0 ? 1 : -1;
  const z = Math.exp(wheel * 0.05);

  scale *= z;

  // this adjusts the scale just fine-ish
  // however, the origin needs to move in relation
  // to the cursor position
}

window.addEventListener("wheel", zoom, { passive: false });

function animate() {
  requestAnimationFrame(animate);
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  bufferCtx.putImageData(data, 0, 0);

  ctx.drawImage(
    bufferCanvas,
    originX - offsetX,
    originY - offsetY,
    WIDTH * PIXEL_SIZE * scale,
    HEIGHT * PIXEL_SIZE * scale
  );
}

animate();