The pack
gridCrawler
function gridCrawler(): Pack<{ gridCrawler: typeof kit; }>
Compose the grid crawler's rules, its two dungeons and its autopilot under game.gridCrawler.
Helpers
checkDungeon
function checkDungeon(d: CrawlerDungeon): string[]
Check a dungeon without playing it: every problem found, as sentences an editor can show, empty when it is sound.
Each floor's map goes through sector-map's checkMap; then the kinds, the party, the rules, the goal and every
feature: cells on the grid and open, wall props on a wall, stairs and pits that lead somewhere, actions that name
what exists. createCrawlerRun throws on the first few.
crawlerAutopilot
function crawlerAutopilot(run: CrawlerRun, pilot: CrawlerPilot, dt: number): string
Play the run for a frame, as a simple player would, before run.step(dt): fight what is ahead with every hand,
missile and spell that is ready, turn to face what attacks from the side, heal and eat when low, keep a torch lit
(fetching a light first when it has none, and one water cannot put out before wading), pick up what lies about,
use levers, buttons, locks it has the key for, alcoves (putting in what they need) and
sconces, weigh down plates that hold doors open with a spare item, explore every cell it can reach, hunt the goal's
monsters, and take the stairs down (or, with nothing else left, an open pit). It plans from the whole dungeon's
state, so it is for attract modes, demos and tests that prove a dungeon can be finished, not for an opponent.
Returns what it is doing.
crawlerRunes
const crawlerRunes: readonly string[]
The rune grid the crypt casts from, three by three.
createCrawlerPilot
function createCrawlerPilot(): CrawlerPilot
A fresh autopilot memory.
createCrawlerRun
function createCrawlerRun(dungeon: CrawlerDungeon): CrawlerRun
Start a run through a dungeon. Throws, naming the problems, on a dungeon checkDungeon finds fault with.
cryptSpells
function cryptSpells(): SpellDef[]
The crypt's spells, cast from crawlerRunes.
dirOf
const dirOf = (f: Facing): number=> …
A direction's index, 0 (north) to 3 (west).
facingBetween
function facingBetween(a: Cell, b: Cell): Facing | null
The direction from one cell to a neighbour, or null when they are not side by side.
facingOfDegrees
const facingOfDegrees = (deg: number): Facing=> …
The facing nearest compass degrees (clockwise from north).
FACINGS
const FACINGS: readonly Facing[]
The four directions, clockwise from north.
facingYaw
const facingYaw = (f: Facing): number=> …
The engine's yaw for a facing: forward is (−sin yaw, cos yaw), so north (−z) is π and east (+x) is −π/2.
floodedVault
function floodedVault(options: FloodedVaultOptions = {}): CrawlerDungeon
The Flooded Vault: one explorer alone, in the dark (no light without a flame), over two floors of a sunken cistern. Water slows every step and puts out a torch, so the oil lantern on a pedestal is the light to keep; a vault crab guards a bronze key for the grate before the stairs; a current in the pool carries the explorer off; a sinkhole drops to the floor below; a whirlpool spins; a scale holds the idol chamber's door while weighed with a rock; and lifting the idol stirs the drowned. No spells, a bigger pack, a one-by-one formation, other armour slots, faster hunger and slower steps. The goal: carry the idol back up to the square the explorer started on.
floorData
function floorData(def: CrawlerFloor): { data: SectorMapData; cell: number; origin: [number, number]; columns: number; rows: number; pitBase: Map<number, number>; charCells: (chars: string) => number[] }
The map data a floor plays: a grid painted into sectors (pits and secret walls given sectors of their own) or the
map as given, with the hidden triggers that carry its features' map actions. Throws nothing: checkMap judges it.
runeCrypt
function runeCrypt(options: RuneCryptOptions = {}): CrawlerDungeon
The Rune Crypt: a party of four (a fighter and a barbarian in front, a rogue with a bow and a mage behind) down three floors of a dark crypt. Levers raise gates, a plate holds a gate open while weighed down, a loose brick opens a secret nook, pits drop to the floor below until a lever closes them, a spinner turns the party, a teleporter shortcuts the ossuary, an iron key opens a lock, a barricade has to be broken and a nest breeds crawlers. A crystal heals before the last hall, a carved skull in an alcove opens it, and the Bone King, a guarding boss who throws green fire, waits with his wisps. Skeletons, archers, crawlers and wisps walk the grid; the mage casts from a three by three rune grid. The goal: kill the Bone King.
stepCell
const stepCell = (cell: Cell, f: Facing): Cell=> …
The cell one step from cell toward f.
turnFacing
const turnFacing = (f: Facing, turns: number): Facing=> …
The direction turns quarter turns clockwise of f (negative turns go anticlockwise).
Classes
CompiledFloor
class CompiledFloor
A floor ready to play.
readonly id: string— Its id.readonly index: number— Its place in the dungeon.readonly def: CrawlerFloor— The authored floor.readonly data: SectorMapData— The map data it plays, with the crawler's sectors and hidden triggers.map: SectorMap— The live map.readonly cell: number— Cell size, world units.readonly origin: [number, number]— Cell[0, 0]'s north-west corner.readonly columns: number— Columns.readonly rows: number— Rows.readonly sectorOf: Int32Array— The sector each cell is, or −1 for rock and solid sectors.readonly atCell: Map<number, CrawlerFeature[]>— Features standing in cells.readonly onWall: Map<number, WallFeature>— Wall features by cell and face.readonly zones: Map<number, ZoneFeature[]>— Zones by cell.readonly features: CrawlerFeature[]— Every feature on the floor.readonly pitBase: Map<number, number>— A pit cell's floor height when shut, by cell index.readonly exits: number[]— Cells where a map trigger ends the level.constructor(def: CrawlerFloor, index: number)key(cell: Cell): number— A cell's index.cellOf(k: number): Cell— The cell of an index.inside(cell: Cell): boolean— Whether a cell is on the grid.open(cell: Cell): boolean— Whether a cell is open floor (a sector that is not solid).centre(cell: Cell): [number, number]— A cell's centre,[x, z]in world units.cellAt(x: number, z: number): Cell— The cell a world point is in (it may be off the grid).floorOf(cell: Cell): number— A cell's floor height now; a pit cell's shut height.drawnFloor(cell: Cell): number— A cell's drawn floor height now (an open pit's bottom).ceilingOf(cell: Cell): number— A cell's ceiling height now.isDoor(cell: Cell): boolean— Whether a cell is a door sector.sectorId(cell: Cell): string | null— The sector id of a cell, or null.edge(cell: Cell, f: Facing): number— What lies between a cell and its neighbour towardf: −2 rock, −1 open (one sector), else the line between them.wallAt(cell: Cell, f: Facing): boolean— Whether the face of a cell towardfis rock (a wall to hang things on).passage(cell: Cell, f: Facing, body: { height: number; step: number; drop: number }): 'ok' | 'wall' | 'door' | 'height'— Whether a body can go from a cell to its neighbour towardfnow:'ok', or what stops it —'wall'(rock, a blocking edge),'door'(a door not open enough) or'height'(too high a step up or down, or no headroom).flies(cell: Cell, f: Facing, y: number): boolean— Whether something flying at heightycrosses from a cell towardf(walls and shut doors stop it).things(): FloorThing[]— The map's things on the grid.reset(): void— Rebuild the live map from its data (a fresh start).
CrawlerRun
class CrawlerRun
A run through a dungeon crawler: a party moving a whole cell at a time over sector-map floors, turning a quarter at
a time, with moves queued and timed so a presenter can glide the camera; characters with hit points, energy, food,
levels and two hands that attack on their own cooldowns (melee from the front rows, missiles and spells from any);
rune spells; torches that burn down; real-time monsters that walk the grid, see, hear, chase, guard and attack; and
the floor's pressure plates, levers, buttons, pits, stairs, teleporters, spinners, alcoves, secret walls, sconces,
locks, writing, spawners, crystals, obstacles and zones, wired to the map's doors and triggers. Headless and seeded.
Get one from createCrawlerRun.
readonly floors: CompiledFloor[]— The floors, compiled: each one's livemapis asector-mapfor the renderer.constructor(dungeon: CrawlerDungeon)get status(): CrawlerSave['status']—'playing','won'or'over'.get time(): number— Seconds played.get floor(): CompiledFloor— The party's floor, compiled; itsmapis the live sector map.get cell(): Cell— The party's cell (where it is going, while it moves).get facing(): Facing— The party's facing.get action(): PartyAction | null— What the party is doing, or null.get queued(): CrawlerMove[]— Moves waiting.get idle(): boolean— Whether the party is standing still with nothing queued.get characters(): CrawlerCharacter[]— The characters (copies).get held(): ItemInstance | null— The item in the party's hand, or null.get resting(): boolean— Resting.monsters(floor?: string): CrawlerMonster[]— Monsters on a floor (default the party's), alive.items(floor?: string): FloorItem[]— Items lying on a floor (default the party's).projectiles(): CrawlerProjectile[]— What is flying.feature(id: string): FeatureState | undefined— A feature's state, or undefined.featureDef(id: string): { def: CrawlerFeature; floor: string } | undefined— A feature's definition and floor id, or undefined.item(kind: string): ItemDef | undefined— An item kind.monster(kind: string): MonsterDef | undefined— A monster kind.get spells(): SpellDef[]— The spells.get runes(): string[]— The rune grid.floorById(id: string): CompiledFloor— A floor by id. Throws on one that does not exist.visited(floor?: string): Cell[]— Cells the party has stood in on a floor (default its own), for an automap.get stats(): CrawlerStats— The run's numbers so far.get goalSpec(): { kill: string[]; carry: string[]; reach: { floor: string; at: Cell }[]; needsReach: boolean }— What wins, resolved from the dungeon's goal or its default.get body(): { height: number; step: number; drop: number }— The body the party moves with: headroom, highest step up and deepest step down, in units.get formation(): { columns: number; rows: number; meleeRows: number }— The formation: columns, rows, and how many rows from the front fight hand to hand.get settings(): CrawlerSettings— The rules' numbers, resolved.get light(): CrawlerView['light']— The party's light now: radius in cells, the flame's share (0 to 1) and where it comes from.move(m: CrawlerMove): boolean— Queue a move: a step forward, back or sideways, or a quarter turn. It starts at once when the party is standing, else waits for the moves before it. Returns false when the queue is full (the rules'queue) or the party cannot move. Throws on an unknown move.stairsTarget(fl: CompiledFloor, f: StairsFeature): { floor: CompiledFloor; stairs: StairsFeature } | null— Where a stairs leads: the floor and the stairs there.pitTarget(fl: CompiledFloor, f: PitFeature): { floor: CompiledFloor; cell: Cell } | null— Where a pit drops to.rest(on: boolean): boolean— Rest: regenerate faster while nothing hunts the party; any move or attack ends it.arrange(order: number[]): void— Put the characters in new formation slots:order[i]is the slot for characteri. Throws unless it gives each a different slot inside the formation.attack(character: number, hand: 0 | 1): boolean— Use what a character holds in a hand: a weapon attacks (melee the cell ahead, from the front rows unless it has reach; ranged shoots the ammunition in the other hand; a throwable flies), food is eaten, a potion drunk, a scroll read; an empty hand punches. Each hand waits its own cooldown. Returns whether it acted. Throws on a character or hand that does not exist.cast(character: number, runes: string[]): boolean— Cast from the rune grid: the runes, in any order, name a spell; the character must be a caster of its level with the energy. A projectile flies from the party down the grid; a heal, light or shield takes effect at once. An unknown combination fizzles. Returns whether a spell was cast. Throws on a character that does not exist.interact(): CrawlerFeature['kind'] | 'door' | 'lift' | 'switch' | 'locked' | 'map' | 'nothing'— Use what is in front of the party: a lever, button, lock (with its key from the hand, the hands or the packs), writing, an alcove or a sconce on the wall of its own cell ahead (taking from or putting the held item in), a crystal in the cell ahead, or else the map's door, lift or switch ahead. Returns the feature's kind,'door','lift','switch'(a mapusetrigger),'locked','map'(anything else the map did) or'nothing'.carries(kind: string): boolean— Whether the party holds an item of a kind anywhere.keys(): string[]— The key names the party holds, for the map's locked doors.take(place: ItemPlace): boolean— Take an item into the party's hand (it must be empty): from the floor here or ahead (indexin the cell's list, default the last), the alcove or sconce ahead, or a character's hand, pack or worn slot. Returns whether it did.put(place: ItemPlace): boolean— Put the item in the party's hand somewhere: on the floor here or ahead, in the alcove or sconce ahead, or in a character's hand, pack or worn slot (swapping with what is there; armour only in its own slot; a stack of the same kind tops up). Returns whether it did.pickUp(where: 'here' | 'ahead' = 'here'): string | null— Pick up the top item here (or ahead) and stow it: a stack of its kind first, then an empty hand for a weapon or a torch, then the first free pack slot, front characters first. Returns the item's id, or null.stow(): boolean— Stow the item in the party's hand: into a stack, a free hand (weapons and torches), or a pack. Returns whether it found room.feed(character: number, from: 'held' | ItemPlace): boolean— A character eats or drinks food or a potion from the party's hand ('held') or from any character's hand, pack or worn slot. Returns whether it did. Throws on a character that does not exist.drop(): boolean— Drop the item in the party's hand on the floor here.throwHeld(character?: number): boolean— Throw the item in the party's hand down the grid, by a character (default the first alive). Returns whether it flew.goalState(): { kill: boolean; carry: boolean; reach: boolean }— Whether each part of the goal holds now.step(dt: number): CrawlerEvent[]— Run the dungeon on bydtseconds (0 to 0.25): the party's move and the next queued one, the characters' food, regeneration, cooldowns and torches, the monsters on the party's floor, what flies, plates, spawners, crystals, zones and the floor's map (doors, lifts, triggers). Floors the party is not on wait. Returns what happened since the last step, actions taken between steps included. Throws on adtout of range.camera(): CrawlerCamera— Where the camera is now, gliding through the party's move.view(): CrawlerView— Everything the presenter draws this frame on the party's floor.get state(): CrawlerSave— A copy of everything that changes: what a save needs.restore(save: CrawlerSave): void— Put back a saved state of this dungeon. Throws on one that does not fit.
Types
AlcoveFeature
interface AlcoveFeature
An alcove in a cell's wall face that holds items: placing what it needs does do, taking it away undo.
kind: 'alcove'—'alcove'.id: string— Unique id across the dungeon.at: Cell— The cell it is used from.face: Facing— The wall of that cell it is in.items?: ItemStack[]— Items in it at the start.capacity?: number— Most items it holds, 1 to 64; default 4.need?: string— The item kind that sets it off; default any item.do?: CrawlerAction[]— Actions when it comes to hold what it needs.undo?: CrawlerAction[]— Actions when it stops holding it.
ButtonFeature
interface ButtonFeature
A button on a cell's wall face: each press does do. A hidden one is a loose brick that opens a secret.
kind: 'button'—'button'.id: string— Unique id across the dungeon.at: Cell— The cell it is used from.face: Facing— The wall of that cell it is on.do?: CrawlerAction[]— Actions on a press.once?: boolean— Works once; default false.hidden?: boolean— Hard to see; default false.
Cell
type Cell = [number, number]
A cell of a floor's grid, [column, row]: column 0 is the west edge, row 0 the north edge.
CharacterDef
interface CharacterDef
One character of the party.
name: string— A name to show.role?: string— A class to show (fighter, mage…); the rules ignore it.hp: number— Most hit points, 1 to 1000000.energy: number— Most energy (mana), 0 to 1000000.food?: number— Most food, 1 to 1000000; default 100.level?: number— Starting level, 1 to 1000; default 1.caster?: boolean— Casts spells; default false.power?: number— Multiplies the damage it deals, 0 to 100; default 1.accuracy?: number— Added to its weapons' accuracy, −1 to 1; default 0.evasion?: number— Chance to dodge, 0 to 0.95; default 0.05.protection?: number— Protection of its own, 0 to 100000; default 0.slot?: number— Its place in the formation, 0 to columns × rows − 1; default its place in the list.perLevel?: { hp?: number; energy?: number; power?: number }— What each level up adds; default the rules'perLevel.hands?: [ItemStack | null, ItemStack | null]— Items in its hands at the start,[left, right].worn?: Record<string, string>— Item kinds worn at the start, by slot.pack?: ItemStack[]— Items in its pack at the start.
CrawlerAction
type CrawlerAction = | TriggerAction | { pit: string; open: boolean | 'toggle' } | { feature: string; on: boolean | 'toggle' } | { spawner: string } | { give: string; count?: number } | { place: string; at: Cell; floor?: string; count?: number } | { win: true }
Something a feature does: any sector-map trigger action (open a door, move a floor, switch lamps, a message, a
spawn, a teleport, the exit…), run on the feature's own floor, or one of the crawler's own:
{ pit, open }: open or close a pit ('toggle'flips it).{ feature, on }: switch a plate, teleporter, spinner or spawner on or off ('toggle'flips it).{ spawner }: that spawner brings out a monster now.{ give, count }: an item into the party's hand (or onto its cell when the hand is full).{ place, at, floor, count }: an item onto a cell.{ win: true }: the dungeon is won.
CrawlerCamera
interface CrawlerCamera
Where the camera is and how it glides, for the presenter.
x: number— Eye position, world units.y: number— Eye height, world units.z: number— Eye position, world units.yaw: number— The engine's yaw, gliding through turns the short way round.from: Cell— The cell the move started in.to: Cell— The cell it ends in.facing: Facing— The facing now (the new one, during a turn).progress: number— How far through the move, 0 to 1 (1 when standing).moving: PartyAction['kind'] | null— What is moving it:'step','turn','bump','fall'or null when standing.
CrawlerCharacter
interface CrawlerCharacter
What a character is now.
id: string— Its id,c0,c1… by its place in the party list.name: string— Its name.role: string— Its role.slot: number— Its formation slot.row: number— Its row, 0 the front.column: number— Its column, 0 the left.hp: number— Hit points.maxHp: number— Most hit points.energy: number— Energy.maxEnergy: number— Most energy.food: number— Food.maxFood: number— Most food.level: number— Level.xp: number— Experience.power: number— Damage multiplier.alive: boolean— Alive.caster: boolean— Casts spells.hands: [ItemInstance | null, ItemInstance | null]— Its hands, left and right.worn: Record<string, ItemInstance | null>— What it wears, by slot.pack: (ItemInstance | null)[]— Its pack.cooldown: [number, number]— Seconds until each hand is ready.castCooldown: number— Seconds until it can cast again.
CrawlerDungeon
interface CrawlerDungeon
A whole dungeon: floors, kinds, the party and the rules.
name?: string— A name to show.floors: CrawlerFloor[]— The floors, top first: stairs down and pits lead to the next.items: ItemDef[]— Item kinds.monsters: MonsterDef[]— Monster kinds.runes?: string[]— The rune grid, by name, in the order the presenter lays it out (Grimrock-style grids are 3 by 3); default none.spells?: SpellDef[]— Spells.party: PartyDef— The party.rules?: CrawlerRules— The rules' numbers.goal?: CrawlerGoal— What wins; default kill every boss kind placed, or else use a map exit.sounds?: Partial<Record<CrawlerEvent['type'], string>>— Sounds by event type: asoundevent comes with each event of that type, where it happened.seed?: number— The seed for every roll; default 1.meta?: Record<string, unknown>— Anything else the game keeps with the dungeon.
CrawlerEvent
type CrawlerEvent = | { type: 'step'; from: Cell; to: Cell; dir: Facing } | { type: 'bump'; dir: Facing; what: 'wall' | 'door' | 'monster' | 'obstacle' | 'height' } | { type: 'turn'; facing: Facing; by: 1 | -1 } | { type: 'attack'; by: string; hand: 0 | 1 | null; with: string; at: Cell } | { type: 'hit'; by: string; target: string; damage: number; at: Cell } | { type: 'miss'; by: string; target: string | null; at: Cell } | { type: 'damage'; target: string; amount: number; x: number; y: number; z: number; to: 'monster' | 'character' | 'obstacle' } | { type: 'spell'; character: string; spell: string } | { type: 'fizzle'; character: string; runes: string[] } | { type: 'refused'; character: string; reason: 'dead' | 'cooldown' | 'energy' | 'level' | 'reach' | 'ammo' | 'caster' | 'nothing' } | { type: 'projectile'; id: string; phase: 'launch' | 'burst' | 'stop'; what: string; x: number; y: number; z: number; splash: number } | { type: 'plate'; id: string; down: boolean } | { type: 'lever'; id: string; down: boolean } | { type: 'button'; id: string } | { type: 'pit'; id: string; open: boolean } | { type: 'fall'; who: string; from: string; to: string; at: Cell } | { type: 'door'; sector: string; phase: string } | { type: 'teleport'; who: string; floor: string; at: Cell } | { type: 'spin'; facing: Facing } | { type: 'stairs'; dir: 'up' | 'down'; floor: string; at: Cell } | { type: 'floor'; floor: string } | { type: 'pickup'; item: string; kind: string } | { type: 'put'; item: string; kind: string; where: string } | { type: 'eat'; character: string; item: string } | { type: 'drink'; character: string; item: string } | { type: 'read'; text: string; spell: string | null } | { type: 'unlock'; id: string } | { type: 'locked'; id: string; key: string } | { type: 'alcove'; id: string; filled: boolean } | { type: 'sconce'; id: string; lit: boolean } | { type: 'heal'; character: string; amount: number } | { type: 'crystal'; id: string } | { type: 'torch'; item: string; lit: boolean } | { type: 'level-up'; character: string; level: number } | { type: 'death'; who: string; kind: 'character' | 'monster' | 'obstacle' } | { type: 'notice'; monster: string } | { type: 'spawn'; monster: string; kind: string; at: Cell } | { type: 'secret'; id: string } | { type: 'message'; text: string } | { type: 'event'; name: string; data?: unknown } | { type: 'map'; event: MapEvent } | { type: 'win' } | { type: 'over' } | { type: 'sound'; sound: string; x: number; y: number; z: number }
What happened.
CrawlerFeature
type CrawlerFeature = | PlateFeature | LeverFeature | ButtonFeature | PitFeature | StairsFeature | TeleporterFeature | SpinnerFeature | AlcoveFeature | SecretFeature | SconceFeature | LockFeature | InscriptionFeature | SpawnerFeature | CrystalFeature | ObstacleFeature | ZoneFeature
Anything the crawler lays over a floor, keyed by cell.
CrawlerFloor
interface CrawlerFloor
One floor of the dungeon: a sector map on a grid of square cells, and the features on it. Things in the map place
the start ('start'), monsters (by kind id) and items (by item id); other things are scenery for the presenter.
id: string— Unique id.name?: string— A name to show.grid?: GridMap— The floor painted as characters (sector-map'sgridMap): the usual way.map?: SectorMapData— Or a map made another way, laid out on the grid.cell?: number— Withmap: the cell size in units, 0.5 to 64; default 2 (a grid uses its owncell).origin?: [number, number]— Withmap: where cell[0, 0]'s north-west corner is,[x, z]; default[0, 0].features?: CrawlerFeature[]— The crawler's features.items?: { item: string; at: Cell; count?: number }[]— Items lying on cells at the start, as well as the map's item things (which are one each).ambient?: number— The darkness: the light the party has with no torch or spell, in cells, 0 to 32; default the rules'ambient.meta?: Record<string, unknown>— Anything else the game keeps with the floor (music, a tint).
CrawlerGoal
interface CrawlerGoal
What wins the dungeon. Every part given must hold at once; a map exit action counts as reaching.
kill?: string[]— Kill every monster of these kinds or tags, wherever it is.carry?: string[]— Carry an item of each of these kinds.reach?: { floor: string; at: Cell }[]— Stand on one of these cells (or use a map exit).
CrawlerMonster
interface CrawlerMonster
A monster now.
id: string— Unique id,<kind>-<n>.kind: string— Its kind.floor: string— The floor it is on, by id.cell: Cell— Its cell (where it is going, while it moves).facing: Facing— Its facing.hp: number— Hit points.mode: 'idle' | 'wander' | 'hunt' | 'return' | 'dead'—'idle','wander','hunt','return'or'dead'.action: { kind: 'step' | 'turn' | 'attack'; t: number; time: number; from: Cell; fromFacing: Facing; dir: Facing } | null— What it is doing, or null between actions.cooldown: number— Seconds until it may attack again.wait: number— Seconds it waits before thinking again.alert: { cell: Cell; time: number } | null— Where it last saw or heard the party, and seconds left before it gives up.home: { cell: Cell; facing: Facing }— Its post and facing, for guards going back.walked: number— Cells walked, for the presenter's walk cycle.tag: string | null— A tag, forkilltriggers.spawner: string | null— The spawner it came from, or null.hurt: number— Seconds since it was last hurt, for a flinch.
CrawlerMove
type CrawlerMove = 'forward' | 'back' | 'left' | 'right' | 'turn-left' | 'turn-right'
A move the party can make: a step four ways, or a quarter turn.
CrawlerPilot
interface CrawlerPilot
An autopilot's memory between frames.
goal: string— What it is doing:'fight','heal','rest','loot','use','explore','plate','hunt','goal','stairs','pit','wait'or''.target: Cell | null— The cell it is heading for, or null.used: Record<string, number>— Times it has used each feature, by id.pressed: string[]— Plates it has pressed, by id.wait: number— Seconds before it decides again.stuck: number— Seconds without moving to a new cell.last: string— Where it was last frame, asfloor:column,row.skip: Record<string, number>— Targets it gave up on for now, by key, with seconds left.
CrawlerProjectile
interface CrawlerProjectile
Something flying down the grid.
id: string— Unique id.from: string— Who sent it: a character id or a monster id.side: 'party' | 'monster'—'party'or'monster': who it is against.what: string— What it is: a spell id, an item kind or a monster kind.floor: string— The floor it is on.cell: Cell— The cell it is leaving.dir: Facing— Its heading.t: number— How far toward the next cell, 0 to 1.def: ProjectileDef— Its flight.left: number— Cells it may still fly.y: number— Its height above the floor where it started, in world units.item: ItemInstance | null— The item it is (a thrown dagger, an arrow), left where it stops.power: number— Multiplies its damage (the thrower's power).
CrawlerProp
interface CrawlerProp
A wall prop or cell prop as the presenter draws it.
id: string— The feature's id.kind: CrawlerFeature['kind']— Its kind.cell: Cell— Its cell (for a wall prop, the cell it is used from).face: Facing | null— A wall prop's wall, or null.x: number— Where to draw it: a wall prop on the middle of its wall face, a cell prop at the cell's centre on its floor.y: number— Floor height at the prop, world units.z: number— Where to draw it.yaw: number— The engine's yaw it faces: a wall prop faces out of its wall into the cell.active: boolean— Plates and levers down, pits open, locks unlocked, buttons pressed.on: boolean— Plates, teleporters, spinners and spawners working.items: string[]— What an alcove holds, or a sconce's torch, by item kind.hidden: boolean— Hidden plates and buttons.text: string | null— Text of an inscription.dir: 'up' | 'down' | null— A stairs' way, or null.prop: string | null— An obstacle's prop name, or null.lit: boolean— A crystal that works now; a sconce holding a lit torch.
CrawlerRules
interface CrawlerRules
The rules' numbers. Every one has a default.
moveTime?: number— Seconds a step from one cell to the next takes, 0.02 to 10; default 0.4.turnTime?: number— Seconds a quarter turn takes, 0 to 10; default 0.25.bumpTime?: number— Seconds a bump into a wall holds the party, 0 to 10; default 0.25.fallTime?: number— Seconds a fall from a pit takes to land, 0 to 10; default 0.5.queue?: number— Most moves queued while one is under way, 0 to 16; default 2.hunger?: number— Food each character eats a second, 0 to 1000; default 0.04.starve?: number— Hit points a starving character loses a second, 0 to 1000; default 0.5.regen?: { hp?: number; energy?: number }— Hit points and energy regained a second, as a share of the most, 0 to 1; default 0.004 and 0.02.rest?: number— Multiplies regeneration and hunger while resting, 1 to 100; default 6.pitDamage?: [number, number]— Damage to each character from a fall,[min, max]; default[2, 6].levels?: number[]— Experience needed for each level after the first, in order (cumulative), each 1 to 1e12; default a gentle curve to level 10.perLevel?: { hp?: number; energy?: number; power?: number }— What a level up adds, unless a character says; default 6 hit points, 4 energy.xpShare?: 'each' | 'split'—'each'(every living character gets a kill's whole experience, the default) or'split'(shared among them).unarmed?: ItemAttack— A bare hand's attack; default[1, 3]damage every 1 second at 0.8 accuracy.noise?: { step?: number; attack?: number; spell?: number; bump?: number }— How far the party's noise carries, in cells, 0 to 64; default step 2, attack 4, spell 5, bump 3.ambient?: number— The light the party has with no torch or spell, in cells, 0 to 32; default 1.friendlyFire?: boolean— The party's own blasts hurt it; default true.reachAhead?: boolean— Items can be taken from and put on the cell ahead as well as the party's own; default true.
CrawlerSave
interface CrawlerSave
Everything that changes in a run; a save holds exactly this.
time: number— Seconds played.status: 'playing' | 'won' | 'over'—'playing','won'or'over'(the whole party dead).floor: string— The party's floor, by id.cell: Cell— The party's cell (where it is going, while it moves).facing: Facing— The party's facing (the new one, while it turns).action: PartyAction | null— What the party is doing, or null.queue: CrawlerMove[]— Moves waiting.held: ItemInstance | null— The item in the party's hand (the pointer's), or null.characters: CrawlerCharacter[]— The characters.light: { radius: number; time: number }— A light spell: radius in cells and seconds left.shield: { protection: number; time: number }— A shield spell: protection and seconds left.resting: boolean— Resting.monsters: CrawlerMonster[]— The monsters, on every floor.items: FloorItem[]— Items lying on floors.projectiles: CrawlerProjectile[]— What is flying.features: Record<string, FeatureState>— Every feature's state, by id.maps: Record<string, SectorMapState>— Each floor's map state, by floor id.visited: Record<string, number[]>— Cells the party has stood in, by floor id (cell indices, row × columns + column).secrets: string[]— Secrets found, by feature or sector id.kills: number— Monsters killed.steps: number— Steps taken.serial: number— The id counter.drain: Record<string, number>— Damage over time not yet a whole point, by character or monster id.rng: number[]— The random stream.
CrawlerSettings
interface CrawlerSettings
The rules' numbers with every default filled in (see CrawlerRules for what each means).
moveTime: number— Seconds a step takes.turnTime: number— Seconds a quarter turn takes.bumpTime: number— Seconds a bump holds the party.fallTime: number— Seconds a fall takes to land.queue: number— Most moves queued.hunger: number— Food eaten a second.starve: number— Hit points a starving character loses a second.regenHp: number— Hit points regained a second, as a share of the most.regenEnergy: number— Energy regained a second, as a share of the most.rest: number— Resting's multiplier.pitDamage: [number, number]— A fall's damage,[min, max].levels: number[]— Experience for each level after the first.perLevel: { hp: number; energy: number; power: number }— What a level adds.xpShare: 'each' | 'split'— How a kill's experience is shared.unarmed: ItemAttack— A bare hand's attack.noise: { step: number; attack: number; spell: number; bump: number }— How far noise carries, in cells.ambient: number— Light with no flame or spell, in cells.friendlyFire: boolean— The party's blasts hurt it.reachAhead: boolean— Items reach to the cell ahead.
CrawlerSkill
type CrawlerSkill = 'easy' | 'normal' | 'hard'
How hard a preset is: multiplies monsters' hit points and damage.
CrawlerStats
interface CrawlerStats
The run's numbers so far.
time: number— Seconds played.kills: number— Monsters killed.steps: number— Steps taken.secrets: number— Secrets found.secretsTotal: number— Secrets in the dungeon (secret walls and secret sectors).floors: number— Floors the party has been on.
CrawlerView
interface CrawlerView
A frame's worth of what to draw.
floor: string— The party's floor, by id.camera: CrawlerCamera— The camera and its glide.light: { radius: number; level: number; source: 'ambient' | 'torch' | 'spell' }— The party's light: radius in cells, the share of a full torch's flame (0 to 1), and where it comes from.monsters: { id: string; kind: string; x: number; y: number; z: number; yaw: number; cell: Cell; facing: Facing; action: 'idle' | 'step' | 'turn' | 'attack'; progress: number; walk: number; hp: number; maxHp: number; boss: boolean; hurt: number; mode: CrawlerMonster['mode'] }[]— Monsters on the floor: where they are, gliding, which way they face, and a walk phase.items: { id: string; kind: string; count: number; x: number; y: number; z: number; cell: Cell }[]— Items on the floor: spread over the cell's quarters.projectiles: { id: string; what: string; x: number; y: number; z: number; yaw: number; light: number; color: string | null }[]— What is flying.props: CrawlerProp[]— The crawler's props: levers, buttons, alcoves, sconces, locks, writing, plates, pits, stairs, teleporters, spinners, spawners, crystals, obstacles.scenery: { type: string; x: number; y: number; z: number; yaw: number }[]— The map's other things (scenery), by type.
CrystalFeature
interface CrystalFeature
A healing crystal standing in a cell: using it from the next cell heals and revives the party, then it dims a while.
kind: 'crystal'—'crystal'.id: string— Unique id across the dungeon.at: Cell— Its cell; nothing walks into it.cooldown?: number— Seconds before it works again, 0 to 100000; default 120.
Facing
type Facing = 'n' | 'e' | 's' | 'w'
A compass direction on the grid: north is up the rows (−z), east along them (+x).
FeatureState
interface FeatureState
A feature's state now.
on: boolean— Working (plates, teleporters, spinners, spawners).active: boolean— A plate or lever down; a pit open; a lock unlocked; a button pressed at least once.spent: boolean— Spent: aoncelever or button used, a lock opened, a latched plate pressed.items: ItemInstance[]— What an alcove holds, or a sconce's torch.timer: number— A crystal's seconds before it works again; a spawner's seconds to its next spawn.spawned: number— A spawner: how many it has brought out.hp: number— A breakable obstacle's hit points left; 0 for every other feature.broken: boolean— An obstacle broken: no longer in the way.used: boolean— Used by the party at least once (read, pulled, pressed, taken from).
FloodedVaultOptions
interface FloodedVaultOptions
Options for floodedVault.
skill?: CrawlerSkill— Monsters' toughness; default'normal'.seed?: number— The seed; default 1.
FloorItem
interface FloorItem
An item lying on a floor.
item: ItemInstance— The item.floor: string— The floor, by id.cell: Cell— Its cell.
FloorThing
interface FloorThing
A thing the map placed, on the grid.
type: string— Its type.cell: Cell— Its cell.facing: Facing— Its facing.tag: string | null— Its tag, or null.ambush: boolean— Placed in ambush (waits for sight).patrol: boolean— Placed to walk about.x: number— World position.z: number— World position.yaw: number— The engine's yaw.
InscriptionFeature
interface InscriptionFeature
Writing on a cell's wall face, read by using it.
kind: 'inscription'—'inscription'.id: string— Unique id across the dungeon.at: Cell— The cell it is read from.face: Facing— The wall of that cell it is on.text: string— The text.
ItemAttack
interface ItemAttack
An attack an item makes from a character's hand.
kind: 'melee' | 'ranged' | 'throw'—'melee'(the cell ahead, from the front rows),'ranged'(a projectile, needingammoin the other hand when it says) or'throw'(the item itself flies).damage: [number, number]— Damage,[min, max]whole numbers from 0 to 100000 (a ranged weapon's projectile has its own).cooldown: number— Seconds before this hand is ready again, 0.05 to 60.accuracy?: number— Chance to hit before the target's evasion, 0 to 1; default 0.85.reach?: boolean— Melee from any row (a spear); default false.ammo?: string— Ranged: the item kind it shoots, held in the other hand.projectile?: ProjectileDef— Ranged and throw: how the shot flies; default 6 cells a second, range 12.energy?: number— Energy it costs, 0 to 100000; default 0.
ItemDef
interface ItemDef
A kind of item.
id: string— Unique id; maps and features place it by this.name?: string— A name to show.kind: 'weapon' | 'armour' | 'shield' | 'food' | 'torch' | 'key' | 'scroll' | 'potion' | 'throwable' | 'ammo' | 'misc'— What it is: decides what using it does and where it can go.weight?: number— Weight on a plate, per item, 0 to 1000; default 1.stack?: number— Most in one stack, 1 to 999; default 1.attack?: ItemAttack— A weapon's or throwable's attack.slot?: string— Armour: the slot it is worn in (one of the party'sslots).protection?: number— Armour and shields: protection taken off each hit, 0 to 10000.evasion?: number— Armour and shields: added to the wearer's evasion, −1 to 1.food?: number— Food: how much it restores.effect?: ItemEffect— Potions (and food, besidesfood): what drinking it does.fuel?: number— Torch: seconds it burns in a hand, 1 to 1000000; default 300.light?: number— Torch: the light it gives at full flame, in cells, 0 to 32; default 4. It dims to half as it burns down.waterproof?: boolean— Torch: water does not put it out (a lantern); default false.opens?: string— Key: the key name asector-mapdoor'skeyasks for; default the item's id.text?: string— Scroll: its text.spell?: string— Scroll: the spell whose runes it shows.
ItemEffect
interface ItemEffect
What an item does when drunk, eaten or used.
hp?: number— Hit points restored (negative hurts).energy?: number— Energy restored.food?: number— Food restored.revive?: number— Brings a dead character back with this many hit points.
ItemInstance
interface ItemInstance
One item, or a stack of one kind.
id: string— Unique id,<kind>-<n>.kind: string— Its item kind.count: number— How many, 1 or more.fuel?: number— A torch's seconds of flame left.
ItemPlace
type ItemPlace = | { floor: 'here' | 'ahead'; index?: number } | { wall: true } | { character: number; hand: 0 | 1 } | { character: number; pack: number } | { character: number; worn: string }
Where an item is taken from or put.
ItemStack
type ItemStack = string | { item: string; count?: number }
An item kind, or a stack of one: 'arrow' or { item: 'arrow', count: 12 }.
LeverFeature
interface LeverFeature
A lever on a cell's wall face: pulled down and pushed back up, doing do and undo.
kind: 'lever'—'lever'.id: string— Unique id across the dungeon.at: Cell— The cell it is used from.face: Facing— The wall of that cell it is on.down?: boolean— Down at the start; default false.do?: CrawlerAction[]— Actions as it goes down.undo?: CrawlerAction[]— Actions as it goes up.once?: boolean— Pulled once, it stays; default false.
LockFeature
interface LockFeature
A lock on a cell's wall face: using it with its key does do.
kind: 'lock'—'lock'.id: string— Unique id across the dungeon.at: Cell— The cell it is used from.face: Facing— The wall of that cell it is on.key: string— The key's item kind.consume?: boolean— The key is used up; default true.do?: CrawlerAction[]— Actions on unlocking.
MonsterAttack
interface MonsterAttack
How a monster attacks.
kind: 'melee' | 'ranged'—'melee'(the next cell, through an open edge) or'ranged'(a projectile along a row or column in sight).damage: [number, number]— Damage,[min, max]whole numbers from 0 to 100000 (a ranged attack's projectile has its own).cooldown: [number, number]— Seconds between attacks,[min, max]from 0.1 to 60.windup?: number— Seconds from starting the attack to its landing, 0 to 10; default 0.4. A party that steps away in time is missed.accuracy?: number— Chance to hit before the target's evasion, 0 to 1; default 0.8.range?: number— Ranged: most cells away it shoots, 1 to 64; default 5.projectile?: ProjectileDef— Ranged: the projectile; default 5 cells a second with the attack's damage.
MonsterDef
interface MonsterDef
A kind of monster.
id: string— Unique id; maps and spawners place it by this.name?: string— A name to show.hp: number— Hit points, 1 to 1000000.moveTime: number— Seconds a step from one cell to the next takes, 0.05 to 60.turnTime?: number— Seconds a quarter turn takes, 0 to 60; default half itsmoveTime.attack: MonsterAttack— Its attack.sight?: number— How many cells it sees, 0 to 64; default 6.view?: 'front' | 'all'—'front'(the default: its front half, sides included) or'all'(eyes all round).hearing?: number— Multiplies how far it hears the party's noise, 0 (deaf) to 10; default 1.memory?: number— Seconds it keeps hunting where it last saw or heard the party, 0 to 600; default 8.float?: boolean— Floats: crosses open pits and does not press plates; default false.guard?: boolean— Holds its post: waits until it sees the party, and goes back when it loses them; default false.wander?: boolean— Roams when it has nothing to hunt; default true (false for guards).strafe?: boolean— Moves sideways and back without turning first; default false.step?: number— Highest step between cells it climbs, in units, 0 to 64; default the party'sstep.weight?: number— Weight on a plate, 0 to 1000; default 5 (0 when it floats).protection?: number— Protection taken off each hit, 0 to 100000; default 0.evasion?: number— Chance to dodge a hit, 0 to 0.95; default 0.1.xp?: number— Experience for killing it, shared as the rules'xpSharesays, 0 to 1e9; default 10.drops?: { item: string; chance?: number; count?: number }[]— What it may leave where it dies: an item kind, the chance (default 1) and how many (default 1).resist?: Record<string, number>— Damage multipliers by element ({ fire: 0.5, cold: 2 }), 0 to 10.boss?: boolean— A boss: the presenter shows its health, and the default goal is to kill every boss. Default false.sounds?: MonsterSounds— Its sounds.
MonsterSounds
interface MonsterSounds
Sounds a monster makes, by name, as sound events where it is.
see?: string— When it notices the party.attack?: string— As it starts an attack.pain?: string— When it is hurt and lives.death?: string— When it dies.step?: string— Each cell it walks.
ObstacleFeature
interface ObstacleFeature
Something solid in a cell (a statue, a barricade): nothing walks into it; with hit points it can be broken.
kind: 'obstacle'—'obstacle'.id: string— Unique id across the dungeon.at: Cell— Its cell.hp?: number— Hit points, above 0; default none: it cannot be broken.prop?: string— What the presenter draws, by name.drops?: string[]— Item kinds it leaves when broken.
PartyAction
interface PartyAction
What the party is doing: moving, turning, bumping, falling or arriving from stairs.
kind: 'step' | 'turn' | 'bump' | 'fall'—'step','turn','bump'or'fall'(landing on a floor below).t: number— Seconds it has taken so far.time: number— Seconds it takes.from: Cell— The cell it started from.to: Cell— The cell it ends in (the same for a turn or a bump).fromFacing: Facing— The facing it started with.dir: Facing— The direction of a step or bump.
PartyDef
interface PartyDef
The party: who is in it and how it stands and moves.
characters: CharacterDef[]— The characters, 1 tocolumns × rows.formation?: { columns: number; rows: number }— The formation's columns (across) and rows (front to back), 1 to 8 each; default 2 by 2.meleeRows?: number— How many rows from the front can fight hand to hand, 1 to 8; default 1.packSize?: number— Pack slots per character, 0 to 256; default 12.slots?: string[]— Armour slots; default['head', 'body', 'legs', 'feet'].weight?: number— The party's weight on plates, 0 to 1000; default 10.eye?: number— Eye height above the floor, in units, 0.1 to 64; default 1.3.height?: number— Headroom it needs, in units, 0.1 to 64; default 1.6.step?: number— Highest step up between cells, in units, 0 to 64; default 0.6.drop?: number— Deepest step down between cells, in units, 0 to 64; default 1.5.
PitFeature
interface PitFeature
A pit in a cell's floor, open or shut by actions: what walks onto it open falls to the floor below.
kind: 'pit'—'pit'.id: string— Unique id across the dungeon.at: Cell— Its cell.open?: boolean— Open at the start; default true.to?: { floor?: string; at?: Cell }— Where a fall lands: a floor (default the next in the list) and a cell (default the same).damage?: [number, number]— Damage to each character on a fall,[min, max]whole numbers; default the rules'pitDamage.depth?: number— How far its floor drops when open, in units, above 0; default 3. On a grid floor the cell becomes its own sector, named by the pit's id, so the map draws the hole.sector?: string— A floor made from map data: the sector (id or tag) to lower and raise; default none (the presenter draws the hole).
PlateBy
type PlateBy = 'party' | 'monster' | 'item'
Who weighs on a pressure plate.
PlateFeature
interface PlateFeature
A pressure plate on a cell's floor: down while the weight on it is at least its weight.
kind: 'plate'—'plate'.id: string— Unique id across the dungeon.at: Cell— Its cell.weight?: number— The weight that presses it, above 0; default 1. The party weighsPartyDef.weight, a monster its kind'sweight, an item itsweighttimes its count.by?: PlateBy[]— What presses it; default all three.do?: CrawlerAction[]— Actions as it goes down.undo?: CrawlerAction[]— Actions as it comes back up.latch?: boolean— Stays down once pressed; default false.hidden?: boolean— Hard to see: the presenter draws it faintly or not at all; default false.on?: boolean— Working at the start; default true. A{ feature, on }action switches it.
ProjectileDef
interface ProjectileDef
A projectile a weapon, a throw, a spell or a monster sends down the grid.
speed: number— Cells per second, 0.5 to 100.damage: [number, number]— Damage on a hit,[min, max]whole numbers from 0 to 100000.splash?: number— Burst reach in cells, 0 to 8: 0 hurts everything in the cell it bursts in, more spreads through open edges; default none (only what it hits).range?: number— Most cells it flies, 1 to 256; default 16.motion?: 'smooth' | 'cell'—'smooth'(the default) glides between cells;'cell'jumps a whole cell at a time.element?: string— Its element ('fire','cold'…), matched against a monster'sresist.light?: number— Light it gives off for the presenter, in cells, 0 to 32; default 0.color?: string— Colour for the presenter, CSS.
RuneCryptOptions
interface RuneCryptOptions
Options for runeCrypt.
floors?: 2 | 3— 3 floors (the default), or 2: the gate and the throne, with the ossuary left out.skill?: CrawlerSkill— Monsters' toughness; default'normal'.seed?: number— The seed; default 1.
SconceFeature
interface SconceFeature
A torch sconce on a cell's wall face: holds one torch, lit, that the party can take and put back.
kind: 'sconce'—'sconce'.id: string— Unique id across the dungeon.at: Cell— The cell it is used from.face: Facing— The wall of that cell it is on.torch?: boolean | string— Holding a torch at the start: true for the first torch kind, or a torch kind by id; default false.lamp?: string— A map light tag switched on while it holds a torch and off while it is empty.do?: CrawlerAction[]— Actions when a torch is put in.undo?: CrawlerAction[]— Actions when the torch is taken.
SecretFeature
interface SecretFeature
A secret wall: a cell that looks like rock until an action opens it ({ open: id }, from a hidden button).
kind: 'secret'—'secret'.id: string— Unique id across the dungeon; on a grid floor also the id of the door sector it becomes.at: Cell— Its cell (rock in the grid, or anything: it becomes a shut door).floor?: number— Floor height when open; default the map's.ceiling?: number— Ceiling height when open; default the map's.texture?: string— The wall texture its shut face shows; default the map's wall.sector?: string— A floor made from map data: the door sector it is (id); default the feature's id.
SpawnerFeature
interface SpawnerFeature
A monster spawner on a cell: brings out monsters on a timer or when an action says.
kind: 'spawner'—'spawner'.id: string— Unique id across the dungeon.at: Cell— Its cell.monster: string— The monster kind.every?: number— Seconds between spawns, above 0; default 0: only on a{ spawner }action.count?: number— Most it ever brings out, 1 to 10000; default 1.max?: number— Most of its monsters alive at once, 1 to 100; default 1.on?: boolean— Working at the start; default true.facing?: Facing— Which way its monsters face; default south.tag?: string— A tag its monsters carry, forkilltriggers.
SpellDef
interface SpellDef
A spell cast from the rune grid.
id: string— Unique id.name?: string— A name to show.runes: string[]— The runes that cast it, by name from the dungeon'srunes, in any order.energy: number— Energy it costs, 0 to 100000.level?: number— The caster's level it needs, 1 to 1000; default 1.cooldown?: number— Seconds before the caster casts again, 0 to 600; default 1.5.projectile?: ProjectileDef— A missile down the grid (a fireball, a frost bolt).heal?: [number, number]— Hit points restored,[min, max].target?: 'self' | 'party' | 'weakest'— Who a heal reaches:'self','party'or'weakest'(the default: the living character lowest by share).light?: { radius: number; time: number }— Light around the party: a radius in cells and seconds it lasts.shield?: { protection: number; time: number }— Protection for every character: how much and seconds it lasts.
SpinnerFeature
interface SpinnerFeature
A spinner on a cell: the party arriving on it is turned.
kind: 'spinner'—'spinner'.id: string— Unique id across the dungeon.at: Cell— Its cell.turn?: 1 | 2 | 3 | 'random'— Quarter turns clockwise, 1 to 3, or'random'(1 to 3, from the run's seed); default'random'.on?: boolean— On at the start; default true.
StairsFeature
interface StairsFeature
Stairs between floors: walking into the cell goes up or down.
kind: 'stairs'—'stairs'.id: string— Unique id across the dungeon.at: Cell— Its cell.dir: 'up' | 'down'— Up a floor (the one before in the list) or down (the one after).exit: Facing— The side it is entered from and left by: the party walks out of it this way.to?: { floor?: string; stairs?: string }— Where it leads: a floor (default bydir) and the stairs there (default the ones going the other way, nearest this cell).
TeleportBy
type TeleportBy = 'party' | 'monster' | 'item' | 'projectile'
Who a teleporter moves.
TeleporterFeature
interface TeleporterFeature
A teleporter on a cell: what enters it while it is on is moved to to.
kind: 'teleporter'—'teleporter'.id: string— Unique id across the dungeon.at: Cell— Its cell.to: { floor?: string; at: Cell; facing?: Facing }— Where to: a cell, on a floor (default this one), and the party's new facing (default unchanged).on?: boolean— On at the start; default true.by?: TeleportBy[]— What it moves; default all four.
WallFeature
type WallFeature = LeverFeature | ButtonFeature | AlcoveFeature | SconceFeature | LockFeature | InscriptionFeature
The features drawn on a wall face rather than standing in a cell.
ZoneFeature
interface ZoneFeature
A stretch of cells with its own rules: water that slows, puts out torches and hurts.
kind: 'zone'—'zone'.id: string— Unique id across the dungeon.cells?: Cell[]— Its cells.chars?: string— On a grid floor: every cell painted with one of these characters.slow?: number— Multiplies the time a step into or out of it takes, 0.1 to 10; default 1.douse?: boolean— Puts out torches that are not waterproof as the party enters; default false.damage?: number— Damage per second to each character standing in it, 0 to 1000; default 0.quiet?: boolean— Steps in it make no noise; default false.


