import type { EditorVec3 } from "./types.js"; /** * How a grid layer's columns and rows map onto world axes. * - `"xz"` (default): columns advance +X, rows advance +Z — a top-down floor plan / board. * - `"xy"`: columns advance +X, rows advance +Y — a vertical slice / side-view board. * @capability editor-grids Choose how grid columns/rows project onto world axes. */ export type EditorGridAxes = "xz" | "xy"; /** * One selectable value in a grid layer's palette: the cell value id plus how it reads (label, * color) and how ASCII import/export maps it (`glyph`). Games register these so the editor and * the import adapters share one legend. `meta` carries the typed payload (cost, damage, tags, …) * a runtime attaches to every cell holding this value. * @capability editor-grids Register a cell value's legend, glyph, color, and typed payload. */ export interface EditorGridPaletteEntry { id: string; label?: string; /** Single character this value maps to for ASCII/glyph import/export. */ glyph?: string; color?: string; meta?: Record; } /** * A sparse, editor-owned tile grid serialized on the scene document. Only non-empty cells are * stored (a `col,row` → value-id map), so a mostly empty grid stays small no matter how large its * declared `cols`/`rows` bounds are. `kind` names the game schema the cells belong to (`room`, * `tactics`, `nav`, `farm`, …); `palette` carries the typed cell payloads by value id; `empty` * is the value id treated as background (cells holding it are dropped from `cells`). Runtime and * rendering both read the same layer through the query helpers in this module — renderers are * registered adapters over this data, never baked into it. * @capability editor-grids Serialize grid-addressed tile content on the scene document. */ export interface EditorGridLayer { id: string; kind: string; label?: string; /** World position of cell (0, 0)'s center; `cellSize` and `axes` place every other cell. */ origin: EditorVec3; /** Column/row → world-axis mapping; defaults to `"xz"` when absent. */ axes?: EditorGridAxes; /** World size of one cell along both grid axes. */ cellSize: number; cols: number; rows: number; /** Value id treated as empty/background; cells holding it are omitted from `cells`. Default `""`. */ empty?: string; /** Sparse cells keyed `"col,row"` → palette value id. Only non-empty, in-bounds cells appear. */ cells: Record; palette?: EditorGridPaletteEntry[]; visible?: boolean; /** Id of the object this layer is parented under (mirrors marker/volume/path parenting). */ parentId?: string; meta?: Record; /** Cell-semantics schema version; {@link migrateGridLayer} normalizes older layers forward. */ schemaVersion?: number; } /** One resolved cell of a grid layer — its column, row, and value id. */ export interface EditorGridCell { col: number; row: number; value: string; } /** A single paint/erase edit: set cell `col,row` to `value` (the layer's empty value erases it). */ export interface EditorGridCellEdit { col: number; row: number; value: string; } /** The grid-layer cell-schema version this build writes and migrates toward. */ export declare const CURRENT_GRID_SCHEMA_VERSION = 1; /** * The value id a layer treats as empty/background (default `""`). Cells holding this value are * never stored, so it is what {@link getGridCell} returns for any unset cell. * @capability editor-grids Resolve a grid layer's empty/background value id. */ export declare function gridEmptyValue(layer: EditorGridLayer): string; /** Builds the sparse-map key for a cell. @internal */ export declare function gridCellKey(col: number, row: number): string; /** * Parses a `"col,row"` sparse-map key back into integer coordinates, or `null` when malformed. * @capability editor-grids Decode a grid layer's sparse cell key. */ export declare function parseGridCellKey(key: string): { col: number; row: number; } | null; /** * True when `col,row` falls inside the layer's declared bounds. * @capability editor-grids Bounds-check a grid coordinate before reading or writing it. */ export declare function inGridBounds(layer: EditorGridLayer, col: number, row: number): boolean; /** * Reads the value id at `col,row`, returning the layer's empty value for any unset or * out-of-bounds cell. The one read path both gameplay and rendering share. * @capability editor-grids Read a grid cell's value id. */ export declare function getGridCell(layer: EditorGridLayer, col: number, row: number): string; /** * Samples the value id at `col,row` — the eyedropper. Identical to {@link getGridCell}, named for * the authoring op that picks up a cell's value to paint with. * @capability editor-grids Eyedrop (sample) a grid cell's value for painting. */ export declare function eyedropGridCell(layer: EditorGridLayer, col: number, row: number): string; /** * Returns a copy of the layer with `col,row` set to `value`, dropping the cell when `value` is the * empty value (that is the erase op). Out-of-bounds writes and no-op writes return the layer * unchanged, so callers can diff by identity. * @capability editor-grids Paint or erase a single grid cell (immutable). */ export declare function setGridCell(layer: EditorGridLayer, col: number, row: number, value: string): EditorGridLayer; /** * Erases `col,row` back to the layer's empty value — {@link setGridCell} with the empty value. * @capability editor-grids Erase a single grid cell (immutable). */ export declare function eraseGridCell(layer: EditorGridLayer, col: number, row: number): EditorGridLayer; /** * Applies a batch of cell edits in one pass, returning the same layer when nothing changed. The * op the editor uses for a drag stroke, a paste, or any multi-cell paint/erase. * @capability editor-grids Paint or erase many grid cells in one immutable update. */ export declare function paintGridCells(layer: EditorGridLayer, edits: readonly EditorGridCellEdit[]): EditorGridLayer; /** * Fills the inclusive rectangle spanning the two corners with `value` (the rectangle tool). Corners * may be given in any order; the clamped in-bounds portion is painted. * @capability editor-grids Fill a grid rectangle with one value (immutable). */ export declare function fillGridRect(layer: EditorGridLayer, col0: number, row0: number, col1: number, row1: number, value: string): EditorGridLayer; /** * Flood-fills the 4-connected region of cells sharing the seed cell's value, replacing it with * `value` (the bucket tool). Bounded by the layer's declared bounds, so it never scans the world. * @capability editor-grids Bucket flood-fill a contiguous grid region (immutable). */ export declare function floodFillGrid(layer: EditorGridLayer, col: number, row: number, value: string): EditorGridLayer; /** * Resizes the layer's bounds to `cols`×`rows`, dropping any cells that fall outside the new extent * (values are anchored at the origin corner). Negative or fractional sizes are floored to `≥ 0`. * @capability editor-grids Resize a grid layer's bounds, trimming out-of-range cells (immutable). */ export declare function resizeGridLayer(layer: EditorGridLayer, cols: number, rows: number): EditorGridLayer; /** * Every non-empty, in-bounds cell of a layer, sorted row-major (rendering-independent iteration). * @capability editor-grids Iterate a grid layer's non-empty cells, row-major. */ export declare function gridCellEntries(layer: EditorGridLayer): EditorGridCell[]; /** * Visits every non-empty cell of a layer row-major. Allocation-light convenience over * {@link gridCellEntries} for runtime scans that only need a callback. * @capability editor-grids Walk a grid layer's non-empty cells with a callback. */ export declare function forEachGridCell(layer: EditorGridLayer, visit: (cell: EditorGridCell) => void): void; /** * Counts the non-empty, in-bounds cells of a layer. * @capability editor-grids Count a grid layer's non-empty cells. */ export declare function gridCellCount(layer: EditorGridLayer): number; /** * Every in-bounds cell holding `value`, sorted row-major — the query gameplay uses to find all * spawns, hazards, gates, etc. of one kind without touching a renderer. * @capability editor-grids Query all grid cells holding a given value. */ export declare function gridCellsOfValue(layer: EditorGridLayer, value: string): EditorGridCell[]; /** * World-space center of cell `col,row`, honoring the layer's origin, cell size, and axis mapping. * The shared cell→world map for both placement and rendering. * @capability editor-grids Map a grid cell to its world-space center. */ export declare function gridCellToWorld(layer: EditorGridLayer, col: number, row: number): EditorVec3; /** * Inverse of {@link gridCellToWorld}: the nearest cell to a world point (may be out of bounds). * The shared world→cell map runtime uses to answer "which cell is the player standing on". * @capability editor-grids Map a world-space point to its nearest grid cell. */ export declare function worldToGridCell(layer: EditorGridLayer, x: number, y: number, z: number): { col: number; row: number; }; /** * The value id at the grid cell nearest a world point — {@link worldToGridCell} then * {@link getGridCell}. Answers "what tile is here" straight from a world position. * @capability editor-grids Read the grid value at a world-space point. */ export declare function getGridCellAtWorld(layer: EditorGridLayer, x: number, y: number, z: number): string; /** * Looks up a palette entry by value id. * @capability editor-grids Find a grid palette entry by value id. */ export declare function findGridPaletteEntry(layer: EditorGridLayer, value: string): EditorGridPaletteEntry | undefined; /** * Builds the value-id → glyph map from a layer's palette, for ASCII/glyph export. * @capability editor-grids Derive a value→glyph legend from a grid layer's palette. */ export declare function gridGlyphMap(layer: EditorGridLayer): Record; /** Fields accepted when constructing a grid layer; sensible defaults fill the rest. */ export interface CreateGridLayerInit { id: string; kind: string; cols: number; rows: number; label?: string; cellSize?: number; origin?: EditorVec3; axes?: EditorGridAxes; empty?: string; cells?: Record; palette?: readonly EditorGridPaletteEntry[]; visible?: boolean; meta?: Record; } /** * Creates a grid layer from a partial init, defaulting cell size to `1`, origin to the world * origin, and axes to `"xz"`. Runs the result through {@link migrateGridLayer} so it is normalized * and bounds-clean. * @capability editor-grids Create a normalized, empty grid layer to author into. */ export declare function createGridLayer(init: CreateGridLayerInit): EditorGridLayer; /** * Normalizes a grid layer forward to the current cell-schema version: clamps `cols`/`rows` to * non-negative integers, drops out-of-bounds and empty-valued cells, and stamps `schemaVersion`. * The single migration seam every loader and authoring op funnels new/old layers through, so a * layer from an older document or an import adapter always lands in a valid, minimal shape. * @capability editor-grids Migrate/normalize a grid layer to the current cell schema. */ export declare function migrateGridLayer(layer: EditorGridLayer): EditorGridLayer; /** * Deep-clones a grid layer so authoring edits and history snapshots never alias source cells. * @capability editor-grids Deep-clone a grid layer. */ export declare function cloneGridLayer(layer: EditorGridLayer): EditorGridLayer;