// Low-level pixel drawing helpers, shared by the canvas components and the procedural // art. Ported verbatim from the prototype's pixel.jsx so rendering stays pixel-accurate. export type Pal = Record | null | undefined /** Draw a string-grid map: rows of chars, each char a key in `pal`. */ export function drawMap( ctx: CanvasRenderingContext2D, map: string[], pal: Pal, px: number, ): void { for (let y = 0; y < map.length; y++) { const row = map[y] for (let x = 0; x < row.length; x++) { const c = row[x] if (c === '.' || c === ' ' || c == null) continue const col = pal ? pal[c] || c : c if (!col || col === '.') continue ctx.fillStyle = col ctx.fillRect(x * px, y * px, px, px) } } } /** Ordered 4x4 Bayer matrix for dithering. */ export const BAYER4 = [ [0, 8, 2, 10], [12, 4, 14, 6], [3, 11, 1, 9], [15, 7, 13, 5], ] /** Dither between two colors over a region; `t` in 0..1 is the `near` coverage. */ export function dither( ctx: CanvasRenderingContext2D, x0: number, y0: number, w: number, h: number, near: string, far: string, t: number, ): void { for (let y = 0; y < h; y++) { for (let x = 0; x < w; x++) { const thr = (BAYER4[y & 3][x & 3] + 0.5) / 16 ctx.fillStyle = thr < t ? near : far ctx.fillRect(x0 + x, y0 + y, 1, 1) } } } /** Vertical dither gradient from colTop to colBottom across height h. */ export function ditherGrad( ctx: CanvasRenderingContext2D, x0: number, y0: number, w: number, h: number, colTop: string, colBottom: string, ): void { for (let y = 0; y < h; y++) { const t = 1 - y / h for (let x = 0; x < w; x++) { const thr = (BAYER4[y & 3][x & 3] + 0.5) / 16 ctx.fillStyle = thr < t ? colTop : colBottom ctx.fillRect(x0 + x, y0 + y, 1, 1) } } }