import type { RGB } from './types.js'; import { AsciiFrame } from './frame.js'; export declare const PALETTE_VERSION = "palette-v1"; /** Largest palette accepted. A GPU uniform carries it, so it has a ceiling. */ export declare const MAX_PALETTE_COLORS = 256; /** * Ordered dither by Bayer matrix size. Error diffusion (Floyd–Steinberg and * kin) is deliberately absent: it carries error from cell to cell in scan * order, which a GPU pass cannot do in parallel and stay exact. */ export type DitherKind = 'none' | 'bayer2' | 'bayer4' | 'bayer8'; export interface PaletteOptions { /** 1..256 colours. Ties between equally near entries go to the earlier one. */ colors: readonly RGB[]; /** Default 'none'. */ dither?: DitherKind; /** * Dither amplitude in 0..255 channel units, default 64: the threshold offsets * span roughly ±spread/2. Around the gap between neighbouring palette colours * is a good value; much more turns gradients into noise. */ spread?: number; } /** A palette reduced to what the per-cell step reads. */ export interface ResolvedPalette { /** Packed 0xBBGGRR, palette order. */ colors: Uint32Array; /** Bayer matrix side: 1 (no dither), 2, 4 or 8. */ size: number; /** Threshold offset per matrix position, row-major, size² entries. */ offsets: Int32Array; } /** Validate and pack a palette for {@link quantizeFrame} or a GPU upload. */ export declare function resolvePalette(palette: PaletteOptions): ResolvedPalette; /** * Snap one packed colour to the palette at cell (cx, cy). The alpha byte is * carried through; the result's RGB is always a palette entry. */ export declare function quantizeColor(c: number, cx: number, cy: number, palette: ResolvedPalette): number; /** * The frame with its colour planes snapped to `palette` (palette-v1, §22). * Glyphs, flags and grid are shared with the input, not copied. `mono` and * `glyph` frames have no per-cell colour to snap and come back as they are. */ export declare function quantizeFrame(frame: AsciiFrame, palette: PaletteOptions | ResolvedPalette): AsciiFrame;