{"spec_id":"sudoku-basic","library":"chartjs","language":"javascript","code":"// anyplot.ai\n// sudoku-basic: Basic Sudoku Grid\n// Library: chartjs 4.4.7 | JavaScript 22.22.3\n// Quality: 89/100 | Created: 2026-06-25\n//# anyplot-orientation: square\n\nconst t = window.ANYPLOT_TOKENS;\n\n// Classic Sudoku puzzle (0 = empty cell, from Wikipedia's Sudoku article)\nconst grid = [\n  [5, 3, 0, 0, 7, 0, 0, 0, 0],\n  [6, 0, 0, 1, 9, 5, 0, 0, 0],\n  [0, 9, 8, 0, 0, 0, 0, 6, 0],\n  [8, 0, 0, 0, 6, 0, 0, 0, 3],\n  [4, 0, 0, 8, 0, 3, 0, 0, 1],\n  [7, 0, 0, 0, 2, 0, 0, 0, 6],\n  [0, 6, 0, 0, 0, 0, 2, 8, 0],\n  [0, 0, 0, 4, 1, 9, 0, 0, 5],\n  [0, 0, 0, 0, 8, 0, 0, 7, 9],\n];\n\n// Mount\nconst canvas = document.createElement(\"canvas\");\ndocument.getElementById(\"container\").appendChild(canvas);\n\n// Inline plugin — draws the 9×9 grid with thick box borders and thin cell borders\nconst sudokuPlugin = {\n  id: \"sudokuGrid\",\n  beforeDraw(chart) {\n    const ctx = chart.ctx;\n    ctx.save();\n    ctx.fillStyle = t.pageBg;\n    ctx.fillRect(0, 0, chart.width, chart.height);\n    ctx.restore();\n  },\n  afterDraw(chart) {\n    const ctx = chart.ctx;\n    const { left, top, right, bottom } = chart.chartArea;\n    const w = right - left;\n    const h = bottom - top;\n\n    // Centered square grid within the chart area\n    const gridSz = Math.min(w, h) * 0.95;\n    const startX = left + (w - gridSz) / 2;\n    const startY = top + (h - gridSz) / 2;\n    const cell = gridSz / 9;\n\n    ctx.save();\n\n    const boxSz = cell * 3;\n\n    // Grid background — full grid in pageBg\n    ctx.fillStyle = t.pageBg;\n    ctx.fillRect(startX, startY, gridSz, gridSz);\n\n    // Alternating 3×3 box region tints for visual depth\n    for (let br = 0; br < 3; br++) {\n      for (let bc = 0; bc < 3; bc++) {\n        ctx.fillStyle = (br + bc) % 2 === 1 ? t.elevatedBg : t.pageBg;\n        ctx.fillRect(startX + bc * boxSz, startY + br * boxSz, boxSz, boxSz);\n      }\n    }\n\n    // Thin cell lines — skip every 3rd (those are box boundaries)\n    ctx.strokeStyle = t.inkSoft;\n    ctx.lineWidth = 1;\n    ctx.lineCap = \"butt\";\n    ctx.beginPath();\n    for (let i = 1; i < 9; i++) {\n      if (i % 3 === 0) continue;\n      ctx.moveTo(startX + i * cell, startY);\n      ctx.lineTo(startX + i * cell, startY + gridSz);\n      ctx.moveTo(startX, startY + i * cell);\n      ctx.lineTo(startX + gridSz, startY + i * cell);\n    }\n    ctx.stroke();\n\n    // Thick box boundary lines at 0, 3, 6, 9 — square caps fill corners cleanly\n    ctx.strokeStyle = t.ink;\n    ctx.lineWidth = 4;\n    ctx.lineCap = \"square\";\n    ctx.beginPath();\n    for (let i = 0; i <= 3; i++) {\n      const d = i * 3 * cell;\n      ctx.moveTo(startX + d, startY);\n      ctx.lineTo(startX + d, startY + gridSz);\n      ctx.moveTo(startX, startY + d);\n      ctx.lineTo(startX + gridSz, startY + d);\n    }\n    ctx.stroke();\n\n    // Given numbers centered in each cell — Imprint palette[0] distinguishes clues\n    const fontSize = Math.floor(cell * 0.54);\n    ctx.font = `bold ${fontSize}px Arial, sans-serif`;\n    ctx.fillStyle = t.palette[0];\n    ctx.textAlign = \"center\";\n    ctx.textBaseline = \"middle\";\n    for (let r = 0; r < 9; r++) {\n      for (let c = 0; c < 9; c++) {\n        if (grid[r][c] !== 0) {\n          ctx.fillText(\n            String(grid[r][c]),\n            startX + c * cell + cell / 2,\n            startY + r * cell + cell / 2\n          );\n        }\n      }\n    }\n\n    ctx.restore();\n  },\n};\n\n// Chart — scatter with hidden axes; the custom plugin draws everything\nnew Chart(canvas, {\n  type: \"scatter\",\n  data: { datasets: [] },\n  plugins: [sudokuPlugin],\n  options: {\n    responsive: true,\n    maintainAspectRatio: false,\n    animation: false,\n    layout: {\n      padding: { top: 20, right: 40, bottom: 40, left: 40 },\n    },\n    plugins: {\n      title: {\n        display: true,\n        text: \"sudoku-basic · javascript · chartjs · anyplot.ai\",\n        color: t.ink,\n        font: { size: 24, weight: \"normal\" },\n        padding: { top: 12, bottom: 16 },\n      },\n      legend: { display: false },\n    },\n    scales: {\n      x: { display: false },\n      y: { display: false },\n    },\n  },\n});\n"}