Newer
Older
gnexus-tasks / frontend / src / game / pixelart.ts
// Пиксель-арт утилиты: матрицы (массивы строк, символ → цвет палитры;
// символ без цвета в палитре — прозрачный пиксель) → canvas/dataURL.
// Файл НЕ импортирует pixi — используется и в DOM (чипы инвентаря),
// и в рендерере (textures.ts), чтобы pixi оставался в async-чанке.
export type Palette = Record<string, string>
export type Matrix = string[]

export function drawMatrix(rows: Matrix, palette: Palette, px: number): HTMLCanvasElement {
  const h = rows.length
  const w = rows[0]?.length ?? 0
  const cv = document.createElement('canvas')
  cv.width = w * px
  cv.height = h * px
  const ctx = cv.getContext('2d')!
  ctx.imageSmoothingEnabled = false
  for (let y = 0; y < h; y++) {
    const row = rows[y]!
    for (let x = 0; x < w; x++) {
      const color = palette[row[x]!]
      if (!color) continue
      ctx.fillStyle = color
      ctx.fillRect(x * px, y * px, px, px)
    }
  }
  return cv
}

/** Data URL пиксель-превью (чипы инвентаря, drag-ghost). px — размер «пикселя». */
export function dataUrlFor(rows: Matrix, palette: Palette, px = 4): string {
  return drawMatrix(rows, palette, px).toDataURL()
}

/** Впечатать patch в base по координатам (сборка больших спрайтов из частей). */
export function stamp(base: Matrix, patch: Matrix, x: number, y: number): Matrix {
  const out = base.map((row) => row.split(''))
  patch.forEach((pr, py) => {
    const target = out[y + py]
    if (!target) return
    pr.split('').forEach((ch, px2) => {
      if (px2 + x < target.length && ch !== ' ' && ch !== '.') target[px2 + x] = ch
    })
  })
  return out.map((row) => row.join(''))
}

/** Пустая матрица w×h (все пиксели прозрачны). */
export function blank(w: number, h: number): Matrix {
  return Array.from({ length: h }, () => ' '.repeat(w))
}

/** Зеркалирование по горизонтали. */
export function flipX(rows: Matrix): Matrix {
  return rows.map((row) => row.split('').reverse().join(''))
}

/** Строка из повторов символа (удобно для стен/полос). */
export function line(ch: string, n: number): string {
  return ch.repeat(n)
}