Basic Sudoku Grid — Chart.js

A standard 9×9 Sudoku grid with proper visual hierarchy showing 3×3 box regions. Thick lines separate the nine boxes while thin lines divide individual cells. The clean black-and-white design is optimized for printing and solving puzzles.

Basic Sudoku Grid rendered with Chart.js

Renders

JavaScript source (Chart.js)

// anyplot.ai
// sudoku-basic: Basic Sudoku Grid
// Library: chartjs 4.4.7 | JavaScript 22.22.3
// Quality: 89/100 | Created: 2026-06-25
//# anyplot-orientation: square

const t = window.ANYPLOT_TOKENS;

// Classic Sudoku puzzle (0 = empty cell, from Wikipedia's Sudoku article)
const grid = [
  [5, 3, 0, 0, 7, 0, 0, 0, 0],
  [6, 0, 0, 1, 9, 5, 0, 0, 0],
  [0, 9, 8, 0, 0, 0, 0, 6, 0],
  [8, 0, 0, 0, 6, 0, 0, 0, 3],
  [4, 0, 0, 8, 0, 3, 0, 0, 1],
  [7, 0, 0, 0, 2, 0, 0, 0, 6],
  [0, 6, 0, 0, 0, 0, 2, 8, 0],
  [0, 0, 0, 4, 1, 9, 0, 0, 5],
  [0, 0, 0, 0, 8, 0, 0, 7, 9],
];

// Mount
const canvas = document.createElement("canvas");
document.getElementById("container").appendChild(canvas);

// Inline plugin — draws the 9×9 grid with thick box borders and thin cell borders
const sudokuPlugin = {
  id: "sudokuGrid",
  beforeDraw(chart) {
    const ctx = chart.ctx;
    ctx.save();
    ctx.fillStyle = t.pageBg;
    ctx.fillRect(0, 0, chart.width, chart.height);
    ctx.restore();
  },
  afterDraw(chart) {
    const ctx = chart.ctx;
    const { left, top, right, bottom } = chart.chartArea;
    const w = right - left;
    const h = bottom - top;

    // Centered square grid within the chart area
    const gridSz = Math.min(w, h) * 0.95;
    const startX = left + (w - gridSz) / 2;
    const startY = top + (h - gridSz) / 2;
    const cell = gridSz / 9;

    ctx.save();

    const boxSz = cell * 3;

    // Grid background — full grid in pageBg
    ctx.fillStyle = t.pageBg;
    ctx.fillRect(startX, startY, gridSz, gridSz);

    // Alternating 3×3 box region tints for visual depth
    for (let br = 0; br < 3; br++) {
      for (let bc = 0; bc < 3; bc++) {
        ctx.fillStyle = (br + bc) % 2 === 1 ? t.elevatedBg : t.pageBg;
        ctx.fillRect(startX + bc * boxSz, startY + br * boxSz, boxSz, boxSz);
      }
    }

    // Thin cell lines — skip every 3rd (those are box boundaries)
    ctx.strokeStyle = t.inkSoft;
    ctx.lineWidth = 1;
    ctx.lineCap = "butt";
    ctx.beginPath();
    for (let i = 1; i < 9; i++) {
      if (i % 3 === 0) continue;
      ctx.moveTo(startX + i * cell, startY);
      ctx.lineTo(startX + i * cell, startY + gridSz);
      ctx.moveTo(startX, startY + i * cell);
      ctx.lineTo(startX + gridSz, startY + i * cell);
    }
    ctx.stroke();

    // Thick box boundary lines at 0, 3, 6, 9 — square caps fill corners cleanly
    ctx.strokeStyle = t.ink;
    ctx.lineWidth = 4;
    ctx.lineCap = "square";
    ctx.beginPath();
    for (let i = 0; i <= 3; i++) {
      const d = i * 3 * cell;
      ctx.moveTo(startX + d, startY);
      ctx.lineTo(startX + d, startY + gridSz);
      ctx.moveTo(startX, startY + d);
      ctx.lineTo(startX + gridSz, startY + d);
    }
    ctx.stroke();

    // Given numbers centered in each cell — Imprint palette[0] distinguishes clues
    const fontSize = Math.floor(cell * 0.54);
    ctx.font = `bold ${fontSize}px Arial, sans-serif`;
    ctx.fillStyle = t.palette[0];
    ctx.textAlign = "center";
    ctx.textBaseline = "middle";
    for (let r = 0; r < 9; r++) {
      for (let c = 0; c < 9; c++) {
        if (grid[r][c] !== 0) {
          ctx.fillText(
            String(grid[r][c]),
            startX + c * cell + cell / 2,
            startY + r * cell + cell / 2
          );
        }
      }
    }

    ctx.restore();
  },
};

// Chart — scatter with hidden axes; the custom plugin draws everything
new Chart(canvas, {
  type: "scatter",
  data: { datasets: [] },
  plugins: [sudokuPlugin],
  options: {
    responsive: true,
    maintainAspectRatio: false,
    animation: false,
    layout: {
      padding: { top: 20, right: 40, bottom: 40, left: 40 },
    },
    plugins: {
      title: {
        display: true,
        text: "sudoku-basic · javascript · chartjs · anyplot.ai",
        color: t.ink,
        font: { size: 24, weight: "normal" },
        padding: { top: 12, bottom: 16 },
      },
      legend: { display: false },
    },
    scales: {
      x: { display: false },
      y: { display: false },
    },
  },
});

Part of Basic Sudoku Grid on anyplot.ai.

Other implementations