@adatechnology/game-floorplan 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/registry.ts","../src/rng.ts","../src/extensions.ts","../src/constants.ts","../src/geometry.ts","../src/parking.ts","../src/queries.ts","../src/grid.ts","../src/fill.ts","../src/legacy-seeds.ts","../src/context.ts","../src/locale.ts","../src/paths.ts","../src/zoning.ts","../src/plan.ts","../src/palette.ts","../src/slots.ts","../src/generate.ts","../../game-contracts/src/blast-shove.ts","../../game-contracts/src/impact-cost.ts","../../game-contracts/src/impact.ts","../../game-contracts/src/body.ts","../../game-contracts/src/spec.ts","../../game-contracts/src/weapons.ts","../../game-contracts/src/ignition.ts","../../game-contracts/src/seal.ts","../../game-contracts/src/twist.ts","../../game-contracts/src/animation.ts","../../game-contracts/src/tool-animation.ts","../../game-contracts/src/frame.ts","../../game-contracts/src/warn.ts","../../game-contracts/src/registry.ts","../../game-contracts/src/bench.ts","../../game-contracts/src/environment.ts","../../game-contracts/src/categories.ts","../../game-contracts/src/origin.ts","../../game-contracts/src/footprint.ts","../../game-contracts/src/foley.ts","../../game-contracts/src/index.ts","../src/ground-items.ts","../src/slot-kit.ts","../src/locales/en.json","../src/locales/pt-BR.json","../src/instance.ts","../src/silhouettes/random.ts","../src/silhouettes/builder.ts","../src/silhouettes/building.ts","../src/silhouettes/houses.ts"],"sourcesContent":["import { findsAnswer, findsFor } from './extensions'\nimport { generate, limitsOf, listTemplates, slots, validate } from './generate'\nimport { createFloorplan, defaultFloorplan, version } from './instance'\nimport type { CreateFloorplanOptions, FloorplanEngine, FloorplanPack } from './instance'\nimport { listLocales, registerLocale, translate } from './locale'\nimport { palette } from './palette'\nimport {\n registerViewerLayer,\n listStates,\n registerDecorProfile,\n registerFindsProvider,\n registerGroundOverlay,\n registerItem,\n registerItems,\n registerLibrary,\n registerLibraryAlias,\n registerPass,\n registerPaletteStyle,\n registerResultExtension,\n registerRoomColors,\n registerSeedKeys,\n registerState,\n registerStyle,\n registerTemplate,\n registerWallTop,\n setStateDistribution,\n} from './registry'\nimport { createRng, hashString, mulberry32 } from './rng'\nimport { slotKit } from './slot-kit'\nimport { checkLot, defineZone, getZone, listZones, registerPermeableGround } from './zoning'\nimport { overlaps, openingZones } from './geometry'\nimport { blocksWindow, windowZone } from './queries'\n\nexport { version, createFloorplan, defaultFloorplan }\nexport type { CreateFloorplanOptions, FloorplanEngine, FloorplanPack }\n\n/**\n * The global engine. Content packs take it as an argument (`register(engine)`), so that several bundles (ESM or IIFE) fill the same registries.\n * @deprecated use `createFloorplan({ packs, patch, remove })`, an engine of its own, or `defaultFloorplan()` for the shared one.\n */\nexport const engine: FloorplanEngine = defaultFloorplan()\n\nexport {\n generate,\n slots,\n validate,\n palette,\n limitsOf,\n listTemplates,\n listStates,\n registerItem,\n registerItems,\n registerLibrary,\n registerLibraryAlias,\n registerTemplate,\n registerStyle,\n registerPaletteStyle,\n registerRoomColors,\n registerDecorProfile,\n registerPass,\n registerGroundOverlay,\n registerWallTop,\n registerSeedKeys,\n registerState,\n setStateDistribution,\n registerLocale,\n registerResultExtension,\n registerFindsProvider,\n findsFor,\n findsAnswer,\n registerViewerLayer,\n blocksWindow,\n translate,\n listLocales,\n defineZone,\n getZone,\n listZones,\n checkLot,\n registerPermeableGround,\n slotKit,\n createRng,\n mulberry32,\n hashString,\n overlaps,\n windowZone,\n openingZones,\n}\nexport type * from './types'\nexport type { PaletteDraw, PaletteEarly, PaletteStyleDef } from './palette'\nexport * from './silhouettes'\n","import type {\n DecorPass,\n FindsProvider,\n ResultExtensionOptions,\n ResultExtensionRun,\n GroundOverlayRule,\n FurnitureDef,\n ItemInput,\n Json,\n RoomColorDef,\n SlotLibrary,\n StateContext,\n StatePlugin,\n StyleDef,\n TemplateDef,\n ViewerLayer,\n FloorplanLocale,\n ZoneDef,\n} from './types'\nimport type { PaletteStyleDef } from './palette'\n\n/** All content registries of one engine instance. Content packs fill them through the `register*` functions. */\nexport type Registries = {\n CATALOG: Record<string, FurnitureDef>\n LIBRARIES: Record<string, SlotLibrary>\n LIBRARY_ALIAS: Record<string, string>\n TEMPLATES: Record<string, TemplateDef>\n STYLES: Record<string, StyleDef>\n STYLE_ALIAS: Record<string, string>\n PALETTE_STYLES: Record<string, PaletteStyleDef>\n ROOM_COLORS: RoomColorDef[]\n PASSES: { name: string; run: DecorPass }[]\n DECOR_PROFILES: Record<string, Json>\n GROUND_OVERLAYS: GroundOverlayRule[]\n STATE_PLUGINS: Record<string, StatePlugin>\n WALL_TOP_HEIGHTS: Record<string, number>\n SEED_KEYS: { rooms: Record<string, string>; items: Record<string, string> }\n stateDistribution: { weights: Record<string, number> | null; seedKey: string }\n RESULT_EXTENSIONS: ResultExtension[]\n FINDS_PROVIDERS: FindsProvider[]\n VIEWER_LAYERS: ViewerLayer[]\n LOCALES: Record<string, FloorplanLocale>\n ZONES: Record<string, ZoneDef>\n PERMEABLE_GROUNDS: Set<string>\n}\n\nexport const createRegistries = (): Registries => ({\n CATALOG: {},\n LIBRARIES: {},\n LIBRARY_ALIAS: {},\n TEMPLATES: {},\n STYLES: {},\n STYLE_ALIAS: {},\n PALETTE_STYLES: {},\n ROOM_COLORS: [],\n PASSES: [],\n DECOR_PROFILES: {},\n GROUND_OVERLAYS: [],\n STATE_PLUGINS: { normal: { apply: () => [] } },\n WALL_TOP_HEIGHTS: { none: 0 },\n SEED_KEYS: { rooms: {}, items: {} },\n stateDistribution: { weights: null, seedKey: 'state' },\n RESULT_EXTENSIONS: [],\n FINDS_PROVIDERS: [],\n VIEWER_LAYERS: [],\n LOCALES: {},\n ZONES: {},\n PERMEABLE_GROUNDS: new Set(),\n})\n\nlet defaultRegistries: Registries | undefined\nlet activeRegistries: Registries | undefined\n\n/** The registries of the global (deprecated) engine, created on first use. */\nexport const getDefaultRegistries = (): Registries => (defaultRegistries ??= createRegistries())\n\n/** The registries the running call reads: the instance it was made through, or the default. */\nexport const registries = (): Registries => activeRegistries ?? getDefaultRegistries()\n\n/** Runs `run` with `scope` as the registries every module reads. Everything the engine does is synchronous, so the scope cannot leak between instances. */\nexport function withRegistries<TResult>(scope: Registries, run: () => TResult): TResult {\n const previous = activeRegistries\n activeRegistries = scope\n try {\n return run()\n } finally {\n activeRegistries = previous\n }\n}\n\nexport function registerItem(def: ItemInput): FurnitureDef {\n const h = def.h\n const item: FurnitureDef = Object.assign({ front: '+z', window: h <= 0.95, low: h <= 0.5, flat: false, deck: false, rim: 0 }, def) as FurnitureDef\n registries().CATALOG[def.type] = item\n return item\n}\nexport function registerItems(list: ItemInput[]): void {\n for (const d of list) registerItem(d)\n}\n\nexport function registerLibrary(id: string, library: SlotLibrary): void {\n registries().LIBRARIES[id] = library\n}\nexport function registerLibraryAlias(alias: string, id: string): void {\n registries().LIBRARY_ALIAS[alias] = id\n}\n\nexport function registerTemplate<T extends TemplateDef>(t: T): T {\n registries().TEMPLATES[t.id] = t\n return t\n}\n\nexport function registerStyle(style: StyleDef): void {\n registries().STYLES[style.id] = style\n for (const a of style.aliases || []) registries().STYLE_ALIAS[a] = style.id\n}\nexport function registerPaletteStyle(id: string, def: PaletteStyleDef): void {\n registries().PALETTE_STYLES[id] = def\n}\nexport function registerRoomColors(list: RoomColorDef[]): void {\n for (const d of list) {\n const i = registries().ROOM_COLORS.findIndex((x) => x.type === d.type)\n if (i >= 0) registries().ROOM_COLORS.splice(i, 1)\n registries().ROOM_COLORS.push(d)\n }\n registries().ROOM_COLORS.sort((a, b) => a.order - b.order)\n}\n\nexport function registerDecorProfile(styleId: string, profile: Json): void {\n registries().DECOR_PROFILES[styleId] = profile\n}\nexport function registerPass(name: string, run: DecorPass): void {\n const i = registries().PASSES.findIndex((p) => p.name === name)\n if (i >= 0) registries().PASSES[i] = { name, run }\n else registries().PASSES.push({ name, run })\n}\nexport function registerGroundOverlay(rule: GroundOverlayRule): void {\n registries().GROUND_OVERLAYS.push(rule)\n}\nexport function registerWallTop(id: string, height: number): void {\n registries().WALL_TOP_HEIGHTS[id] = height\n}\n/** Legacy RNG stream names for rooms and items, so seeds recorded before the English ids still reproduce. */\nexport function registerSeedKeys(keys: { rooms?: Record<string, string>; items?: Record<string, string> }): void {\n Object.assign(registries().SEED_KEYS.rooms, keys.rooms)\n Object.assign(registries().SEED_KEYS.items, keys.items)\n}\n\n/** Registers a house state. The engine only ships `normal`. */\nexport function registerState(name: string, plugin: StatePlugin): void {\n registries().STATE_PLUGINS[name] = plugin\n}\n/** Default state draw when `options.state` is absent: `{ state: weight }` on its own seeded stream. */\nexport function setStateDistribution(weights: Record<string, number> | null, seedKey = 'state'): void {\n registries().stateDistribution.weights = weights\n registries().stateDistribution.seedKey = seedKey\n}\nexport const listStates = (): string[] => Object.keys(registries().STATE_PLUGINS)\n\nexport function resolveStyleId(id: string | undefined): string {\n const s = id ?? ''\n return registries().STYLE_ALIAS[s] ?? s\n}\nexport function styleOf(id: string): StyleDef {\n return registries().STYLES[id] || registries().STYLES.budget || Object.values(registries().STYLES)[0]\n}\n\nexport type { StateContext }\n\nexport interface ResultExtension {\n name: string\n run: ResultExtensionRun\n after: string[]\n seedKey: string\n}\n\n/** Adds a named piece to every result, after the state and before the zoning report; its output lands in `result[name]`. */\nexport function registerResultExtension(name: string, run: ResultExtensionRun, options: ResultExtensionOptions = {}): void {\n const entry: ResultExtension = { name, run, after: options.after || [], seedKey: options.seedKey ?? name }\n const i = registries().RESULT_EXTENSIONS.findIndex((x) => x.name === name)\n if (i >= 0) registries().RESULT_EXTENSIONS[i] = entry\n else registries().RESULT_EXTENSIONS.push(entry)\n}\n\n/** Registers who answers what a container holds (the item packs, from phase 3 on). */\nexport function registerFindsProvider(provider: FindsProvider): void {\n registries().FINDS_PROVIDERS.push(provider)\n}\n\n/** Adds (or replaces, by id) a layer of the 2D viewer; drawn after the items, before the labels. */\nexport function registerViewerLayer(layer: ViewerLayer): void {\n const i = registries().VIEWER_LAYERS.findIndex((x) => x.id === layer.id)\n if (i >= 0) registries().VIEWER_LAYERS[i] = layer\n else registries().VIEWER_LAYERS.push(layer)\n}\n","/** Seeded random helpers. Same seed and key always produce the same stream. */\n\nexport type Rng = () => number\n\nexport function mulberry32(a: number): Rng {\n return function () {\n a |= 0\n a = (a + 0x6d2b79f5) | 0\n let t = Math.imul(a ^ (a >>> 15), 1 | a)\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n\nexport function hashString(input: string | number): number {\n const s = String(input)\n let h = 1779033703 ^ s.length\n for (let i = 0; i < s.length; i++) {\n h = Math.imul(h ^ s.charCodeAt(i), 3432918353)\n h = (h << 13) | (h >>> 19)\n }\n h = Math.imul(h ^ (h >>> 16), 2246822507)\n h = Math.imul(h ^ (h >>> 13), 3266489909)\n return (h ^ (h >>> 16)) >>> 0\n}\n\n/** Independent stream for a `(seed, key)` pair. */\nexport const createRng = (seed: string | number, key: string): Rng => mulberry32(hashString(seed + '|' + key))\n\n/** Picks a key of `{ key: weight }`. */\nexport function pickWeighted(rng: Rng, weights: Record<string, number>): string {\n const keys = Object.keys(weights)\n let total = 0\n for (const k of keys) total += weights[k]\n let x = rng() * total\n for (const k of keys) {\n x -= weights[k]\n if (x < 0) return k\n }\n return keys[keys.length - 1]\n}\n\n/** Weighted draw without replacement. */\nexport function weightedOrder<T extends { weight: number }>(candidates: T[], rng: Rng): T[] {\n const arr = candidates.slice()\n const out: T[] = []\n while (arr.length) {\n let total = 0\n for (const c of arr) total += c.weight\n let x = rng() * total\n let i = 0\n for (; i < arr.length - 1; i++) {\n x -= arr[i].weight\n if (x < 0) break\n }\n out.push(arr.splice(i, 1)[0])\n }\n return out\n}\n\nexport function shuffle<T>(arr: T[], rng: Rng): T[] {\n const a = arr.slice()\n for (let i = a.length - 1; i > 0; i--) {\n const j = Math.floor(rng() * (i + 1))\n ;[a[i], a[j]] = [a[j], a[i]]\n }\n return a\n}\n","import { registries } from './registry'\nimport type { ResultExtension } from './registry'\nimport { createRng } from './rng'\nimport type { FindsQuery, FindStack, FloorplanOptions, Json, Plan } from './types'\n\n/** Extensions in the order they run: registration order, with each one after the ones it names. */\nfunction orderOf(extensions: readonly ResultExtension[]): ResultExtension[] {\n const ordered: ResultExtension[] = []\n const visiting = new Set<string>()\n const visit = (extension: ResultExtension) => {\n if (ordered.includes(extension)) return\n if (visiting.has(extension.name)) throw new Error('Result extensions depend on each other: ' + extension.name)\n visiting.add(extension.name)\n for (const name of extension.after) {\n const before = extensions.find((x) => x.name === name)\n if (before) visit(before)\n }\n visiting.delete(extension.name)\n ordered.push(extension)\n }\n extensions.forEach(visit)\n return ordered\n}\n\n/** Runs the registered extensions and stores each output in `result[name]`. */\nexport function runResultExtensions(plan: Plan, result: Json, seed: number | string, options: FloorplanOptions): void {\n for (const extension of orderOf(registries().RESULT_EXTENSIONS)) {\n result[extension.name] = extension.run({ plan, result, seed, rng: createRng(seed, extension.seedKey), options })\n }\n}\n\n/** What a container holds, from the first registered provider that answers (`null` passes to the next); none answering means nothing. */\nexport function findsFor(query: FindsQuery): readonly FindStack[] {\n return answerOf(query) ?? []\n}\n\n/** Like `findsFor`, but `null` when no provider answered, so a pack can fall back to its own default. */\nexport function findsAnswer(query: FindsQuery): readonly FindStack[] | null {\n return answerOf(query)\n}\n\nfunction answerOf(query: FindsQuery): readonly FindStack[] | null {\n for (const provider of registries().FINDS_PROVIDERS) {\n const stacks = provider.findsFor(query)\n if (stacks !== null) return stacks\n }\n return null\n}\n","/** Structural wall thickness in metres. */\nexport const WALL_THICKNESS = 0.15\n/** Half a wall: the gap between a room rectangle and its usable interior. */\nexport const MARGIN = WALL_THICKNESS / 2\nexport const EPS = 1e-6\nexport const TOL = 1e-3\n/** Clear zone in front of doors and gates, in metres. */\nexport const DOOR_CLEARANCE = 0.9\n/** Radius of the player body: a disc this wide must still pass between doors and rooms once the furniture is placed. */\nexport const PLAYER_RADIUS = 0.24\n/** Clear wall from the edge of a door opening to a corner or a junction (measured from the wall axis). */\nexport const DOOR_EDGE_CLEARANCE = 0.12\n/** Clear wall from a window to a corner, a junction or a door. */\nexport const WINDOW_EDGE_CLEARANCE = 0.3\n/** Top of the wall cabinet (it hangs between 1.55 and 2.15 m). */\nexport const OVERHEAD_TOP = 2.15\n/** Room types that may stay without a window. */\nexport const WINDOWLESS_ROOM_TYPES: ReadonlySet<string> = new Set([\n 'stockroom', 'kitchen', 'laundry', 'bathroom', 'void', 'elevator', 'stairs', 'pantry', 'closet', 'corridor', 'hall', 'balcony', 'terrace', 'garage', 'storage', 'porch', 'tent', 'outhouse',\n])\n/** Default clearances of a parked car, in metres (driver side is the left of whoever looks along the front). */\nexport const CAR_CLEARANCE = { driver: 0.8, side: 0.6, end: 0.6 } as const\n","import { EPS, MARGIN, TOL, WALL_THICKNESS } from './constants'\nimport type { PlacedItem, Rect, Room, RoomDef, Vec2 } from './types'\n\nexport const r2 = (x: number): number => Math.round(x * 100) / 100\nexport const clamp = (x: number, a: number, b: number): number => Math.max(a, Math.min(b, x))\nexport const overlaps = (a: Rect, b: Rect, e = EPS): boolean => a[0] < b[2] - e && a[2] > b[0] + e && a[1] < b[3] - e && a[3] > b[1] + e\nexport const inner = (p: Rect): Rect => [p[0] + MARGIN, p[1] + MARGIN, p[2] - MARGIN, p[3] - MARGIN]\nexport const eq = (a: number, b: number): boolean => Math.abs(a - b) < TOL\nexport const inflate = (r: Rect, e: number): Rect => [r[0] - e, r[1] - e, r[2] + e, r[3] + e]\nexport const areaOf = (r: Rect): number => (r[2] - r[0]) * (r[3] - r[1])\nexport const topOf = (m: PlacedItem): number => (m.y || 0) + m.h\n\n/** Footprint of an item of `size` facing `f` (cardinal). */\nexport const extent = (size: Vec2, f: Vec2): Vec2 => (Math.abs(f[1]) === 1 ? [size[0], size[1]] : [size[1], size[0]])\nexport const cardinal = (dx: number, dz: number): Vec2 => (Math.abs(dx) > Math.abs(dz) ? [Math.sign(dx), 0] : [0, Math.sign(dz) || 1])\n\nexport function clearRect(r: Rect, f: Vec2, clearance: number): Rect {\n return f[1] === 1 ? [r[0], r[3], r[2], r[3] + clearance] : f[1] === -1 ? [r[0], r[1] - clearance, r[2], r[1]] : f[0] === 1 ? [r[2], r[1], r[2] + clearance, r[3]] : [r[0] - clearance, r[1], r[0], r[3]]\n}\n\nexport function insideUnion(r: Rect, inners: Rect[]): boolean {\n const e = 1e-4\n const points: Vec2[] = [\n [r[0] + e, r[1] + e],\n [r[2] - e, r[1] + e],\n [r[0] + e, r[3] - e],\n [r[2] - e, r[3] - e],\n [(r[0] + r[2]) / 2, (r[1] + r[3]) / 2],\n ]\n return points.every((p) => inners.some((q) => p[0] >= q[0] - 1e-6 && p[0] <= q[2] + 1e-6 && p[1] >= q[1] - 1e-6 && p[1] <= q[3] + 1e-6))\n}\n\nexport function cutIntervals(intervals: [number, number][], a: number, b: number): [number, number][] {\n const out: [number, number][] = []\n for (const [x, y] of intervals) {\n if (b <= x || a >= y) {\n out.push([x, y])\n continue\n }\n if (a > x) out.push([x, a])\n if (b < y) out.push([b, y])\n }\n return out\n}\n\nexport interface Edge {\n axis: 'u' | 'v'\n pos: number\n a0: number\n a1: number\n}\n\nexport function exteriorEdge(room: Room, side: string, w: number, d: number, c?: number | null): Edge | null {\n const cand: Edge[] = []\n for (const p of room.parts) {\n if (side === 'front' && eq(p[1], 0)) cand.push({ axis: 'u', pos: 0, a0: p[0], a1: p[2] })\n else if (side === 'back' && eq(p[3], d)) cand.push({ axis: 'u', pos: d, a0: p[0], a1: p[2] })\n else if (side === 'left' && eq(p[0], 0)) cand.push({ axis: 'v', pos: 0, a0: p[1], a1: p[3] })\n else if (side === 'right' && eq(p[2], w)) cand.push({ axis: 'v', pos: w, a0: p[1], a1: p[3] })\n }\n if (!cand.length) return null\n if (c != null) {\n const k = cand.find((x) => c >= x.a0 - TOL && c <= x.a1 + TOL)\n if (k) return k\n }\n return cand.sort((x, y) => y.a1 - y.a0 - (x.a1 - x.a0))[0]\n}\n\nexport function sharedEdge(A: Room, B: Room, c?: number | null): Edge | null {\n const cand: Edge[] = []\n for (const pa of A.parts)\n for (const pb of B.parts) {\n let o: [number, number]\n if (eq(pa[2], pb[0]) || eq(pa[0], pb[2])) {\n o = [Math.max(pa[1], pb[1]), Math.min(pa[3], pb[3])]\n if (o[1] - o[0] > TOL) cand.push({ axis: 'v', pos: eq(pa[2], pb[0]) ? pa[2] : pa[0], a0: o[0], a1: o[1] })\n }\n if (eq(pa[3], pb[1]) || eq(pa[1], pb[3])) {\n o = [Math.max(pa[0], pb[0]), Math.min(pa[2], pb[2])]\n if (o[1] - o[0] > TOL) cand.push({ axis: 'u', pos: eq(pa[3], pb[1]) ? pa[3] : pa[1], a0: o[0], a1: o[1] })\n }\n }\n if (!cand.length) return null\n if (c != null) {\n const k = cand.find((x) => c >= x.a0 - TOL && c <= x.a1 + TOL)\n if (k) return k\n }\n return cand.sort((x, y) => y.a1 - y.a0 - (x.a1 - x.a0))[0]\n}\n\nexport function openingZones(u: number, v: number, axis: 'u' | 'v', width: number, depth: number): Rect[] {\n const h = width / 2\n return axis === 'u' ? [[u - h, v - depth, u + h, v], [u - h, v, u + h, v + depth]] : [[u - depth, v - h, u, v + h], [u, v - h, u + depth, v + h]]\n}\nexport const openingDepth = (width: number, leaf: number): number => Math.max(0.9, leaf) + MARGIN\n\n/** Points 0.55 m on each side of an opening. */\nexport function entryPoints(ab: { axis: 'u' | 'v'; u: number; v: number }): Vec2[] {\n return ab.axis === 'u' ? [[ab.u, ab.v - 0.55], [ab.u, ab.v + 0.55]] : [[ab.u - 0.55, ab.v], [ab.u + 0.55, ab.v]]\n}\n\nexport function normalizeRoom(c: Partial<RoomDef> & { id: string; type: string; rect: number[] }, floorIndex: number): Room {\n const parts = [c.rect as number[]].concat(c.parts || []).map((p) => p.map(r2) as Rect)\n return {\n id: c.id,\n type: c.type,\n label: c.label,\n floor: floorIndex,\n parts,\n library: c.library || null,\n without: c.without || [],\n overrides: c.overrides || {},\n extras: c.extras || [],\n slots: c.slots || null,\n link: c.link || null,\n outdoor: !!c.outdoor,\n ceiling: c.ceiling || null,\n seedKey: c.seedKey,\n }\n}\n\n/**\n * Usable parts: each part inset by half a wall on every side, plus, for each stretch where it touches another part of the same room\n * (more than 0.3 m), a strip that reaches the shared edge. The inset stays at the ends of the stretch, where a real wall or corner stands.\n */\nexport function usableParts(room: Room, extra?: number): Rect[] {\n const m = MARGIN + (extra || 0)\n const out: Rect[] = []\n for (const p of room.parts) {\n out.push([p[0] + m, p[1] + m, p[2] - m, p[3] - m])\n for (let k = 0; k < 4; k++) {\n const spans: [number, number][] = []\n for (const q of room.parts) {\n if (q === p) continue\n if (k === 0 && eq(q[2], p[0])) spans.push([Math.max(q[1], p[1]), Math.min(q[3], p[3])])\n else if (k === 2 && eq(q[0], p[2])) spans.push([Math.max(q[1], p[1]), Math.min(q[3], p[3])])\n else if (k === 1 && eq(q[3], p[1])) spans.push([Math.max(q[0], p[0]), Math.min(q[2], p[2])])\n else if (k === 3 && eq(q[1], p[3])) spans.push([Math.max(q[0], p[0]), Math.min(q[2], p[2])])\n }\n spans.sort((x, y) => x[0] - y[0])\n const merged: [number, number][] = []\n for (const span of spans) {\n const last = merged[merged.length - 1]\n if (last && span[0] <= last[1] + TOL) last[1] = Math.max(last[1], span[1])\n else merged.push([span[0], span[1]])\n }\n for (const [a, b] of merged) {\n if (b - a <= 0.3) continue\n const x0 = a + m\n const x1 = b - m\n if (x1 <= x0) continue\n if (k === 0) out.push([p[0], x0, p[0] + m, x1])\n else if (k === 2) out.push([p[2] - m, x0, p[2], x1])\n else if (k === 1) out.push([x0, p[1], x1, p[1] + m])\n else out.push([x0, p[3] - m, x1, p[3]])\n }\n }\n }\n return out\n}\n\nexport const inRect = (room: Room, u: number, v: number): boolean => room.parts.some((p) => u > p[0] + EPS && u < p[2] - EPS && v > p[1] + EPS && v < p[3] - EPS)\n\nexport interface WallBuildDoor {\n axis: 'u' | 'v'\n pos: number\n at: number\n width: number\n}\n\n/** Walls of one storey, split where rooms meet and cut where doors open. */\nexport function buildWalls(rooms: Room[], doors: WallBuildDoor[], openPairs: [string, string][], floorIndex: number) {\n const groups: Record<string, { axis: 'u' | 'v'; pos: number; es: { a: number; b: number; id: string; side: number }[] }> = {}\n const add = (axis: 'u' | 'v', pos: number, a: number, b: number, id: string, side: number) => {\n const k = axis + '|' + pos.toFixed(2)\n ;(groups[k] = groups[k] || { axis, pos, es: [] }).es.push({ a, b, id, side })\n }\n for (const c of rooms)\n for (const p of c.parts) {\n add('u', p[1], p[0], p[2], c.id, 1)\n add('u', p[3], p[0], p[2], c.id, -1)\n add('v', p[0], p[1], p[3], c.id, 1)\n add('v', p[2], p[1], p[3], c.id, -1)\n }\n const par = (x: string, y: string) => openPairs.some((o) => (o[0] === x && o[1] === y) || (o[0] === y && o[1] === x))\n const typeOf: Record<string, string> = {}\n for (const c of rooms) typeOf[c.id] = c.type\n const out: Record<string, unknown>[] = []\n for (const g of Object.values(groups)) {\n const breaks = [...new Set(g.es.flatMap((e) => [r2(e.a), r2(e.b)]))].sort((x, y) => x - y)\n const segs: { A: string; B: string; p: number; q: number }[] = []\n for (let i = 0; i < breaks.length - 1; i++) {\n const p = breaks[i]\n const q = breaks[i + 1]\n const m = (p + q) / 2\n const after = g.es.find((e) => e.side === 1 && m > e.a && m < e.b)\n const before = g.es.find((e) => e.side === -1 && m > e.a && m < e.b)\n if (!after && !before) continue\n const A = before ? before.id : 'outside'\n const B = after ? after.id : 'outside'\n if (A === B || (A !== 'outside' && B !== 'outside' && par(A, B))) continue\n const last = segs[segs.length - 1]\n if (last && last.A === A && last.B === B && eq(last.q, p)) last.q = q\n else segs.push({ A, B, p, q })\n }\n for (const s of segs) {\n let pieces: [number, number][] = [[s.p, s.q]]\n for (const pt of doors) {\n if (pt.axis !== g.axis || !eq(pt.pos, g.pos)) continue\n const c0 = pt.at - pt.width / 2\n const c1 = pt.at + pt.width / 2\n const n: [number, number][] = []\n for (const [x, y] of pieces) {\n if (c1 <= x + TOL || c0 >= y - TOL) {\n n.push([x, y])\n continue\n }\n if (c0 > x + TOL) n.push([x, c0])\n if (c1 < y - TOL) n.push([c1, y])\n }\n pieces = n\n }\n for (const [x, y] of pieces) {\n const isOpen = (t: string) => t === 'balcony' || t === 'terrace' || t === 'porch'\n const isVoid = typeOf[s.A] === 'void' || typeOf[s.B] === 'void'\n if (isVoid && (s.A === 'outside' || s.B === 'outside')) continue\n const railing = isVoid || (isOpen(typeOf[s.A]) && s.B === 'outside') || (isOpen(typeOf[s.B]) && s.A === 'outside')\n out.push({\n floor: floorIndex,\n axis: g.axis,\n u0: g.axis === 'u' ? x : g.pos,\n v0: g.axis === 'u' ? g.pos : x,\n u1: g.axis === 'u' ? y : g.pos,\n v1: g.axis === 'u' ? g.pos : y,\n thickness: WALL_THICKNESS,\n sides: [s.A, s.B],\n exterior: s.A === 'outside' || s.B === 'outside',\n type: railing ? 'railing' : 'wall',\n h: railing ? 1.1 : 0,\n })\n }\n }\n }\n return out\n}\n","import { extent } from './geometry'\nimport type { CarClearance, FurnitureDef, Rect, Slot, Vec2 } from './types'\n\nconst STEP = 0.05\nconst MAX_CANDIDATES = 80\n\n/**\n * Where a car may stand in a parking slot: `rect` is the car, `clear` the car plus the space it must keep from walls\n * (the driver side, on the left of whoever looks along the front, keeps more than the passenger side). Candidates are sorted by\n * their distance to the slot centre; the car always stays whole inside the zone.\n */\nexport function carCandidates(slot: Slot, item: FurnitureDef, car: CarClearance): { rect: Rect; clear: Rect }[] {\n const front: Vec2 = [slot.frontU, slot.frontV]\n const zone: Rect = slot._cell.R\n const alongV = Math.abs(front[1]) === 1\n const [extentU, extentV] = extent([item.w, item.d], front)\n const across = alongV ? extentU : extentV\n const along = alongV ? extentV : extentU\n const a = alongV ? 0 : 1\n const b = alongV ? 1 : 0\n const driverSign = alongV ? front[1] : -front[0]\n const frontSign = alongV ? front[1] : front[0]\n const lowClear = driverSign < 0 ? car.driver : car.side\n const highClear = driverSign < 0 ? car.side : car.driver\n const lo = zone[a] + lowClear\n const hi = zone[a + 2] - highClear - across\n const alongLo = zone[b] + car.end\n const alongHi = zone[b + 2] - car.end - along\n if (hi < lo - 1e-6 || alongHi < alongLo - 1e-6) return []\n const preferred = (alongV ? slot.x : slot.z) - across / 2\n const alongStart = frontSign < 0 ? alongHi : alongLo\n const positions: number[] = []\n for (let p = lo; p <= hi + 1e-6; p += STEP) positions.push(Math.min(p, hi))\n positions.sort((x, y) => Math.abs(x - preferred) - Math.abs(y - preferred))\n return positions.slice(0, MAX_CANDIDATES).map((p) => {\n const rect: Rect = alongV ? [p, alongStart, p + across, alongStart + along] : [alongStart, p, alongStart + along, p + across]\n const clear: Rect = alongV ? [p - lowClear, alongStart - car.end, p + across + highClear, alongStart + along + car.end] : [alongStart - car.end, p - lowClear, alongStart + along + car.end, p + across + highClear]\n return { rect, clear }\n })\n}\n","import { EPS, MARGIN, OVERHEAD_TOP } from './constants'\nimport { eq, inRect } from './geometry'\nimport type { FurnitureDef, Json, Plan, Rect, Room } from './types'\n\n/** Door and path zones of a storey (storey -1 is the lot). */\nexport function zonesOfFloor(plan: Plan, floorIndex: number): Rect[] {\n const out: Rect[] = []\n if (floorIndex >= 0) {\n for (const p of plan.doors) if (p.floor === floorIndex) out.push(...p.zones)\n } else {\n for (const p of plan.doors) if (p.floor === 0 && p.exterior) out.push(...p.zones)\n for (const g of plan.gates) out.push(...g.zones)\n for (const c of plan.paths) out.push(...c.rects)\n out.push(...plan.reservations)\n }\n return out\n}\n\nexport function openingsOfFloor(plan: Plan, floorIndex: number): Json[] {\n if (floorIndex >= 0) return plan.doors.filter((p) => p.floor === floorIndex)\n return plan.doors.filter((p) => p.floor === 0 && p.exterior).concat(plan.gates)\n}\n\n/** Keep-out zone of a window (inside, or outside for the lot). */\nexport function windowZone(j: Json, outside?: boolean): Rect {\n const h = j.width / 2 + 0.1\n const depth = 0.5\n let n: [number, number]\n if (j.side === 'front') n = [0, 1]\n else if (j.side === 'back') n = [0, -1]\n else if (j.side === 'left') n = [1, 0]\n else n = [-1, 0]\n if (outside) n = [-n[0], -n[1]]\n const u = j.u\n const v = j.v\n if (j.axis === 'u') return n[1] > 0 ? [u - h, v - MARGIN, u + h, v + depth] : [u - h, v - depth, u + h, v + MARGIN]\n return n[0] > 0 ? [u - MARGIN, v - h, u + depth, v + h] : [u - depth, v - h, u + MARGIN, v + h]\n}\n\n/** `overheadOff`: the counter sits under the window without its wall cabinet. */\nexport function blocksWindow(it: Pick<FurnitureDef, 'window' | 'overhead' | 'windowHeight'> & { h: number }, win: Json, overheadOff?: boolean): boolean {\n const height = Math.max(it.h, it.windowHeight || 0, it.overhead && !overheadOff ? OVERHEAD_TOP : 0)\n return !it.window || it.h > 1.0 + EPS || height > win.y0 - 0.05 + EPS\n}\n\nexport function windowsOfRoom(plan: Plan, room: Room): Json[] {\n if (!room.outdoor) return plan.windows.filter((j) => j.room === room.id)\n return plan.windows.filter(\n (j) =>\n j.floor === 0 &&\n room.parts.some((p) => {\n if (j.side === 'front') return eq(p[3], j.pos) && j.u >= p[0] && j.u <= p[2]\n if (j.side === 'back') return eq(p[1], j.pos) && j.u >= p[0] && j.u <= p[2]\n if (j.side === 'left') return eq(p[2], j.pos) && j.v >= p[1] && j.v <= p[3]\n return eq(p[0], j.pos) && j.v >= p[1] && j.v <= p[3]\n }),\n )\n}\n\nexport function roomAt(plan: Plan, u: number, v: number, floorIndex: number): Room | null {\n const list = floorIndex < 0 ? plan.zones : plan.rooms\n return list.find((c) => c.floor === floorIndex && inRect(c, u, v)) || null\n}\n\nexport function isOpenSide(plan: Plan, room: Room, pu: number, pv: number): boolean {\n const o = roomAt(plan, pu, pv, room.floor)\n if (!o) return false\n if (o.id === room.id) return true\n if (room.outdoor) return true\n return (plan.openPairs[room.floor] || []).some((x) => (x[0] === room.id && x[1] === o.id) || (x[1] === room.id && x[0] === o.id))\n}\n","import { MARGIN } from './constants'\nimport { entryPoints, eq, inRect, inner, sharedEdge, usableParts } from './geometry'\nimport { openingsOfFloor } from './queries'\nimport type { Json, Plan, Rect, Room } from './types'\n\nexport interface Grid {\n gs: number\n u0: number\n v0: number\n nx: number\n nz: number\n inside: Uint8Array\n entries: [number, number][]\n center: [number, number]\n}\n\n/** Wall bodies of a storey (the wall line plus half a wall each side); a wall end that stops at a door opening has no extension there. */\nfunction wallBodies(plan: Plan, floor: number): Rect[] {\n const cache = (plan.wallBodies = plan.wallBodies || {})\n if (cache[floor]) return cache[floor]\n const doors = plan.doors.filter((p) => p.floor === floor)\n return (cache[floor] = plan.walls\n .filter((p) => p.floor === floor && (p.type === 'wall' || p.type === 'railing'))\n .map((p) => {\n const a0 = p.axis === 'u' ? p.u0 : p.v0\n const a1 = p.axis === 'u' ? p.u1 : p.v1\n const pos = p.axis === 'u' ? p.v0 : p.u0\n const atDoor = (x: number) => doors.some((q) => q.axis === p.axis && eq(q.pos, pos) && (eq(q.at - q.width / 2, x) || eq(q.at + q.width / 2, x)))\n const e0 = atDoor(a0) ? 0 : MARGIN\n const e1 = atDoor(a1) ? 0 : MARGIN\n return (p.axis === 'u' ? [a0 - e0, pos - MARGIN, a1 + e1, pos + MARGIN] : [pos - MARGIN, a0 - e0, pos + MARGIN, a1 + e1]) as Rect\n }))\n}\n\n/**\n * Walkability grid of a room (10 cm cells inside, 30 cm outside). Indoors a cell is walkable only when a player body of `radius`\n * fits between it and the walls. `ignored` lists opening ids to leave out of the entries.\n */\nexport function createGrid(plan: Plan, room: Room, ignored?: Set<string> | null, radius: number = plan.playerRadius): Grid {\n const gs = room.outdoor ? 0.3 : 0.1\n let u0 = 1e9\n let v0 = 1e9\n let u1 = -1e9\n let v1 = -1e9\n for (const p of room.parts) {\n u0 = Math.min(u0, p[0])\n v0 = Math.min(v0, p[1])\n u1 = Math.max(u1, p[2])\n v1 = Math.max(v1, p[3])\n }\n const nx = Math.ceil((u1 - u0) / gs)\n const nz = Math.ceil((v1 - v0) / gs)\n const insideCells = new Uint8Array(nx * nz)\n const insets = room.outdoor ? usableParts(room, 0.08) : room.parts\n // only the walls within reach of the room's box can be closer than the player's body to one of its cells (a tower floor has hundreds of them)\n const bodies = room.outdoor ? null : wallBodies(plan, room.floor).filter((r) => r[0] - radius <= u1 && r[2] + radius >= u0 && r[1] - radius <= v1 && r[3] + radius >= v0)\n const tooClose = (u: number, v: number) =>\n (bodies as Rect[]).some((r) => {\n const dx = Math.max(r[0] - u, 0, u - r[2])\n const dz = Math.max(r[1] - v, 0, v - r[3])\n return dx * dx + dz * dz < radius * radius - 1e-9\n })\n for (let j = 0; j < nz; j++)\n for (let i = 0; i < nx; i++) {\n const u = u0 + (i + 0.5) * gs\n const v = v0 + (j + 0.5) * gs\n if (insets.some((r) => u >= r[0] && u <= r[2] && v >= r[1] && v <= r[3]) && (room.outdoor || !tooClose(u, v))) insideCells[j * nx + i] = 1\n }\n const entries: [number, number][] = []\n for (const ab of openingsOfFloor(plan, room.floor) as Json[])\n if (!(ignored && ignored.has(ab.id)))\n for (const pt of entryPoints(ab)) {\n if (!inRect(room, pt[0], pt[1])) continue\n const i = Math.floor((pt[0] - u0) / gs)\n const j = Math.floor((pt[1] - v0) / gs)\n if (i >= 0 && j >= 0 && i < nx && j < nz && insideCells[j * nx + i]) entries.push([i, j])\n }\n if (!room.outdoor)\n for (const pair of plan.openPairs[room.floor] || []) {\n const otherId = pair[0] === room.id ? pair[1] : pair[1] === room.id ? pair[0] : null\n const other = otherId && plan.rooms.find((c) => c.id === otherId && c.floor === room.floor)\n if (!other) continue\n const edge = sharedEdge(room, other, null)\n if (!edge || edge.a1 - edge.a0 > 2.0) continue\n const mid = (edge.a0 + edge.a1) / 2\n for (const offset of [-0.4, 0.4]) {\n const pt = edge.axis === 'u' ? [mid, edge.pos + offset] : [edge.pos + offset, mid]\n if (!inRect(room, pt[0], pt[1])) continue\n const i = Math.floor((pt[0] - u0) / gs)\n const j = Math.floor((pt[1] - v0) / gs)\n if (i >= 0 && j >= 0 && i < nx && j < nz && insideCells[j * nx + i]) entries.push([i, j])\n }\n }\n const R = inner(room.parts[0])\n return { gs, u0, v0, nx, nz, inside: insideCells, entries, center: [(R[0] + R[2]) / 2, (R[1] + R[3]) / 2] }\n}\n\n/** True when the room centre and every entry stay connected once `solids` (inflated) are blocked. */\nexport function reachable(g: Grid, solids: Rect[], inflation: number): boolean {\n const { gs, u0, v0, nx, nz, inside } = g\n const blocked = new Uint8Array(nx * nz)\n for (const r of solids) {\n const i0 = Math.max(0, Math.floor((r[0] - inflation - u0) / gs))\n const i1 = Math.min(nx - 1, Math.floor((r[2] + inflation - u0) / gs))\n const j0 = Math.max(0, Math.floor((r[1] - inflation - v0) / gs))\n const j1 = Math.min(nz - 1, Math.floor((r[3] + inflation - v0) / gs))\n for (let j = j0; j <= j1; j++)\n for (let i = i0; i <= i1; i++) {\n const u = u0 + (i + 0.5) * gs\n const v = v0 + (j + 0.5) * gs\n if (u > r[0] - inflation && u < r[2] + inflation && v > r[1] - inflation && v < r[3] + inflation) blocked[j * nx + i] = 1\n }\n }\n let best = -1\n let bestDist = 1e9\n for (let j = 0; j < nz; j++)\n for (let i = 0; i < nx; i++) {\n const k = j * nx + i\n if (!inside[k] || blocked[k]) continue\n const dist = Math.hypot(u0 + (i + 0.5) * gs - g.center[0], v0 + (j + 0.5) * gs - g.center[1])\n if (dist < bestDist) {\n bestDist = dist\n best = k\n }\n }\n if (best < 0) return false\n if (!g.entries.length) return true\n for (const [i, j] of g.entries) if (blocked[j * nx + i]) return false\n const visited = new Uint8Array(nx * nz)\n const queue = new Int32Array(nx * nz)\n let h = 0\n let t = 0\n const s = g.entries[0][1] * nx + g.entries[0][0]\n visited[s] = 1\n queue[t++] = s\n while (h < t) {\n const k = queue[h++]\n const i = k % nx\n const j = (k - i) / nx\n for (const [di, dj] of [[1, 0], [-1, 0], [0, 1], [0, -1]]) {\n const a = i + di\n const b = j + dj\n if (a < 0 || b < 0 || a >= nx || b >= nz) continue\n const q = b * nx + a\n if (visited[q] || !inside[q] || blocked[q]) continue\n visited[q] = 1\n queue[t++] = q\n }\n }\n if (!visited[best]) return false\n for (const [i, j] of g.entries) if (!visited[j * nx + i]) return false\n return true\n}\n","import { EPS } from './constants'\nimport { carCandidates } from './parking'\nimport { clearRect, extent, insideUnion, overlaps, r2, usableParts } from './geometry'\nimport { createGrid, reachable } from './grid'\nimport { blocksWindow, windowZone, windowsOfRoom, zonesOfFloor } from './queries'\nimport { registries } from './registry'\nimport { weightedOrder } from './rng'\nimport type { Rng } from './rng'\nimport type { FurnitureDef, Json, PlacedItem, Plan, Rect, Room, Slot, Vec2, Weights } from './types'\n\nfunction candidatesOf(cats: Weights): { it: FurnitureDef; weight: number }[] {\n const out: { it: FurnitureDef; weight: number }[] = []\n for (const [cat, weight] of Object.entries(cats)) {\n const exact = cat[0] === '='\n const its = Object.values(registries().CATALOG).filter((i) => !i.decor && (exact ? i.type === cat.slice(1) : !i.exactOnly && (i.category === cat || i.type === cat)))\n for (const it of its) out.push({ it, weight: weight / its.length })\n }\n return out\n}\n\nfunction itemRect(slot: Slot, it: FurnitureDef, shift: number): Rect {\n const c = slot._cell\n const f: Vec2 = c.f\n const [extentU, extentV] = extent([it.w, it.d], f)\n const R: Rect = c.R\n // centre without rounding\n let u0 = (c.rect ? (c.rect[0] + c.rect[2]) / 2 : slot.x) - extentU / 2\n let v0 = (c.rect ? (c.rect[1] + c.rect[3]) / 2 : slot.z) - extentV / 2\n if (shift) {\n if (slot.side === 'left' || slot.side === 'right') v0 += shift\n else u0 += shift\n }\n for (const s of c.enclosed) {\n if (s === 'left') u0 = R[0]\n else if (s === 'right') u0 = R[2] - extentU\n else if (s === 'front') v0 = R[1]\n else if (s === 'back') v0 = R[3] - extentV\n }\n return [u0, v0, u0 + extentU, v0 + extentV]\n}\n\n/** Radius of the relaxed pass: a required item that did not fit settles for a narrower walkway. */\nconst RELAXED_RADIUS = 0.12\n\nconst MESH_FRONT: Record<string, Vec2> = { '+z': [0, 1], '-z': [0, -1], '+x': [1, 0], '-x': [-1, 0] }\n\n/** Rotation that makes a mesh whose front is `front` face `f`. */\nexport function rotationFor(f: Vec2, front: string): number {\n const meshFront = MESH_FRONT[front] || [0, 1]\n let ry = Math.atan2(f[0], f[1]) - Math.atan2(meshFront[0], meshFront[1])\n if (ry > Math.PI + EPS) ry -= 2 * Math.PI\n if (ry < -Math.PI - EPS) ry += 2 * Math.PI\n return r2(ry)\n}\n\n/** Fills the slots of one room with catalogue items, honouring clearances, doors, windows and reachability. */\nexport function fillRoom(plan: Plan, room: Room, slots: Slot[], rng: Rng): { items: PlacedItem[]; missing: { room: string; slot: string }[] } {\n const items: PlacedItem[] = []\n const missing: { room: string; slot: string }[] = []\n const state: Record<string, PlacedItem> = {}\n const solids: Rect[] = []\n const reserves: Rect[] = []\n const rims: Rect[] = []\n const inners = usableParts(room, 0)\n const grid = createGrid(plan, room)\n const relaxedGrid = room.outdoor ? grid : createGrid(plan, room, null, RELAXED_RADIUS)\n const zones = zonesOfFloor(plan, room.floor)\n const windowZones = windowsOfRoom(plan, room).map((j) => ({ z: windowZone(j, room.outdoor), j }))\n const inflation = room.outdoor ? 0.15 : plan.playerRadius\n interface Unit {\n group: string | null\n members: Slot[]\n required?: boolean\n }\n const units: Unit[] = []\n const seen: Record<string, Unit> = {}\n for (const s of slots) {\n if (s.group) {\n if (seen[s.group]) {\n seen[s.group].members.push(s)\n continue\n }\n const u: Unit = { group: s.group, members: [s] }\n seen[s.group] = u\n units.push(u)\n } else units.push({ group: null, members: [s] })\n }\n for (const u of units) u.required = u.members.some((m) => m.required)\n const queue = units.filter((u) => u.required).concat(units.filter((u) => !u.required))\n const dependencies = (u: Unit) =>\n u.members\n .flatMap((m) => [m.requires, m.on])\n .filter(Boolean)\n .filter((id) => slots.some((s) => s.id === id && !u.members.includes(s)))\n const done = new Set<string>()\n const ready = (u: Unit) => dependencies(u).every((id) => done.has(id as string))\n const make = (s: Slot, it: FurnitureDef, r: Rect, parent: PlacedItem | null, overheadOff?: boolean) => {\n const f: Vec2 = [s.frontU, s.frontV]\n const id = room.id + '.' + s.id\n const m: Json = {\n id,\n type: it.type,\n category: it.category,\n x: r2((r[0] + r[2]) / 2),\n z: r2((r[1] + r[3]) / 2),\n ry: rotationFor(f, it.front),\n w: it.w,\n d: it.d,\n h: it.h,\n y: parent ? r2((parent.y || 0) + parent.h) : 0,\n frontU: f[0],\n frontV: f[1],\n room: room.id,\n floor: room.floor,\n outdoor: !!room.outdoor,\n slot: s.id,\n on: parent ? s.on : null,\n mode: parent ? (s.anchor === 'inside' ? 'inside' : 'on') : null,\n clearance: s.clearance,\n flat: it.flat,\n low: it.low,\n aabb: r.map(r2),\n _r: r,\n _seedId: registries().SEED_KEYS.items[id] ?? id,\n }\n if (it.overhead) m.overhead = !overheadOff\n if (it.category === 'car') {\n m.driver = [f[1], -f[0]]\n m.carClearance = plan.carClearance\n }\n if (parent && s.anchor === 'inside') m.y = r2(parent.y || 0)\n if (room.link) m.link = { from: room.link[0], to: room.link[1] }\n state[s.id] = m\n items.push(m as PlacedItem)\n return m as PlacedItem\n }\n const tryFit = (s: Slot, relax: boolean, overheadOff?: boolean): PlacedItem | null => {\n const cands = weightedOrder(candidatesOf(s.cats), rng)\n if (s.anchor === 'on' || s.anchor === 'inside') {\n const parent = state[s.on as string]\n if (!parent) return null\n for (const { it } of cands) {\n if (it.w > parent.w + EPS || it.d > parent.d + EPS) continue\n const f: Vec2 = [parent.frontU, parent.frontV]\n const r: Rect = parent.aabb\n const [extentU, extentV] = extent([it.w, it.d], f)\n const cu = (r[0] + r[2]) / 2 - f[0] * (parent.d / 2 - it.d / 2)\n const cv = (r[1] + r[3]) / 2 - f[1] * (parent.d / 2 - it.d / 2)\n return make(s, it, [cu - extentU / 2, cv - extentV / 2, cu + extentU / 2, cv + extentV / 2], parent)\n }\n return null\n }\n for (const { it } of cands) {\n if (it.w > s.w + EPS || it.d > s.d + EPS) continue\n const f: Vec2 = [s.frontU, s.frontV]\n const slide = s.anchor === 'wall' ? (s.slide == null ? 2.0 : s.slide) : 0\n const shifts = [0]\n for (let k = 1; k * 0.1 <= slide + 1e-9; k++) shifts.push(k * 0.1, -k * 0.1)\n let found: { rect: Rect; cl?: Rect | null; rimRect?: Rect | null } | null = null\n const car = it.category === 'car' && !relax\n const tries: { rect: Rect; clear?: Rect }[] = car ? carCandidates(s, it, plan.carClearance) : shifts.map((shift) => ({ rect: itemRect(s, it, shift) }))\n for (const attempt of tries) {\n const r = attempt.rect\n if (!insideUnion(r, inners)) continue\n if (car && (!insideUnion(attempt.clear as Rect, inners) || solids.some((o) => overlaps(attempt.clear as Rect, o)))) continue\n if (it.flat) {\n found = { rect: r }\n break\n }\n if (zones.some((z) => overlaps(r, z))) continue\n if (windowZones.some(({ z, j }) => blocksWindow(it, j, overheadOff) && overlaps(r, z))) continue\n if (solids.some((o) => overlaps(r, o))) continue\n if (!it.deck && rims.some((a) => overlaps(r, a))) continue\n let cl: Rect | null = car ? (attempt.clear as Rect) : null\n if (!car && !relax && s.clearance > 0 && !it.low) {\n cl = clearRect(r, f, s.clearance)\n if (!insideUnion(cl, inners)) continue\n if (items.some((m) => !m.low && !m.flat && !m.on && overlaps(cl as Rect, m._r))) continue\n }\n if (!it.low && reserves.some((q) => overlaps(r, q))) continue\n let rimRect: Rect | null = null\n if (it.rim) {\n rimRect = [r[0] - it.rim, r[1] - it.rim, r[2] + it.rim, r[3] + it.rim]\n if (!insideUnion(rimRect, inners) || solids.some((o) => overlaps(rimRect as Rect, o)) || zones.some((z) => overlaps(rimRect as Rect, z))) continue\n }\n if (!(relax ? reachable(relaxedGrid, solids.concat([r]), RELAXED_RADIUS) : reachable(grid, solids.concat([r]), inflation))) continue\n found = { rect: r, cl, rimRect }\n break\n }\n if (!found) continue\n const { rect: r, cl, rimRect } = found\n if (it.flat) return make(s, it, r, null)\n const m = make(s, it, r, null, overheadOff)\n if (cl) reserves.push(cl)\n if (rimRect) rims.push(rimRect)\n solids.push(r)\n return m\n }\n return null\n }\n const process = (u: Unit) => {\n const pr = u.members[0].chance as number\n const x = rng()\n const arr = u.members.slice()\n const members: Slot[] = []\n while (arr.length) members.push(arr.splice(arr.length > 1 ? Math.floor(rng() * arr.length) : 0, 1)[0])\n const applicable = members.filter((m) => m.valid && (!m.requires || state[m.requires]) && (!m.on || state[m.on]))\n if (!u.required && x >= pr) return\n let ok = false\n for (const m of applicable) {\n if (tryFit(m, false)) {\n ok = true\n break\n }\n }\n if (!ok)\n for (const m of applicable) {\n if (tryFit(m, false, true)) {\n ok = true\n break\n }\n }\n if (!ok && u.required)\n for (const m of applicable) {\n if (tryFit(m, true, true)) {\n ok = true\n break\n }\n }\n if (!ok && u.required && (applicable.length || !u.members.some((m) => m.requires))) missing.push({ room: room.id, slot: u.group || u.members[0].id })\n }\n const pending = queue.slice()\n while (pending.length) {\n let i = pending.findIndex(ready)\n if (i < 0) i = 0\n const u = pending.splice(i, 1)[0]\n process(u)\n for (const m of u.members) done.add(m.id)\n }\n return { items, missing }\n}\n","/**\n * Names of the seeded random streams.\n *\n * These strings come from the Portuguese-language SDK this engine replaces. They are kept\n * verbatim on purpose: a stream is `hash(seed + '|' + name)`, so renaming one would change every\n * plan generated from an existing seed. They never appear in the output.\n */\nexport const STREAM = {\n facade: 'fachada',\n lot: 'lote',\n decor: 'decor',\n roomPrefix: 'c:',\n palettePrefix: 'paleta:',\n} as const\n","import { MARGIN, EPS } from './constants'\nimport {\n areaOf,\n clamp,\n clearRect,\n cutIntervals,\n extent,\n inflate,\n inner,\n insideUnion,\n overlaps,\n r2,\n topOf,\n usableParts,\n} from './geometry'\nimport { rotationFor } from './fill'\nimport { createGrid, reachable } from './grid'\nimport { STREAM } from './legacy-seeds'\nimport { blocksWindow, roomAt, windowZone, windowsOfRoom, zonesOfFloor } from './queries'\nimport { registries } from './registry'\nimport { createRng, pickWeighted, shuffle } from './rng'\nimport type { Rng } from './rng'\nimport type { Json, PlacedItem, Plan, PlacementContext, PlacementKit, Rect, Room, Vec2 } from './types'\n\n/** Geometry and grid helpers shared with decor passes and state plugins. */\nexport const placementKit: PlacementKit = {\n MARGIN,\n EPS,\n r2,\n clamp,\n overlaps,\n inner,\n inflate,\n areaOf,\n topOf,\n extent,\n insideUnion,\n usableParts,\n zonesOfFloor,\n windowsOfRoom,\n windowZone,\n roomAt,\n reachable: reachable as PlacementKit['reachable'],\n createGrid: createGrid as PlacementKit['createGrid'],\n clearRect,\n pickWeighted,\n createRng,\n roomSeedKey: (room: Room) => room.seedKey ?? registries().SEED_KEYS.rooms[room.id] ?? room.id,\n shuffle,\n facingRotation: (f: Vec2, type: string) => rotationFor(f, registries().CATALOG[type].front),\n cutIntervals,\n blocksWindow,\n}\n\n/** Builds the shared placement context over the items already placed by the slot fill. */\nexport function createPlacementContext(plan: Plan, items: PlacedItem[]): PlacementContext {\n const added: PlacedItem[] = []\n const counters: Record<string, number> = {}\n const make = (room: Room, type: string, r: Rect, f: Vec2, o?: Json): PlacedItem => {\n const it = registries().CATALOG[type]\n const n = (counters[room.id + type] = (counters[room.id + type] || 0) + 1)\n return Object.assign(\n {\n id: room.id + '.dec_' + type + n,\n type,\n category: it.category,\n x: r2((r[0] + r[2]) / 2),\n z: r2((r[1] + r[3]) / 2),\n ry: r2(Math.atan2(f[0], f[1])),\n w: it.w,\n d: it.d,\n h: it.h,\n y: 0,\n frontU: f[0],\n frontV: f[1],\n room: room.id,\n floor: room.floor,\n outdoor: !!room.outdoor,\n slot: 'dec_' + type + n,\n on: null,\n mode: null,\n clearance: 0,\n flat: !!it.flat,\n low: it.low,\n aabb: r.map(r2),\n _r: r,\n decor: true,\n mount: it.mount,\n },\n o || {},\n ) as PlacedItem\n }\n const add = (m: PlacedItem) => {\n added.push(m)\n items.push(m)\n return m\n }\n const itemsOfRoom = (c: Room) => items.filter((m) => m.room === c.id && m.floor === c.floor)\n const extraSolids: Record<string, Rect[]> = {}\n const solidsOfRoom = (c: Room): Rect[] =>\n itemsOfRoom(c)\n .filter((m) => !m.flat && !m.on && (!m.decor || m.mount === 'floor'))\n .map((m) => m._r as Rect)\n .concat(extraSolids[c.id] || [])\n const gridCache: Record<string, ReturnType<typeof createGrid>> = {}\n let ignored: Set<string> | null = null\n const gridOf = (c: Room) => gridCache[c.id] || (gridCache[c.id] = createGrid(plan, c, ignored))\n\n /** Places a floor item at a corner or along a wall; respects doors, windows, clearances and walkability. */\n function placeOnFloor(room: Room, type: string, rng2: Rng, optsIn?: Json): Rect | null {\n const opts = Object.assign({}, optsIn || {})\n const it0 = registries().CATALOG[type]\n if (it0.flat) opts.flat = true\n const it = registries().CATALOG[type]\n const inners = usableParts(room, 0)\n const solidList = solidsOfRoom(room)\n const zones = zonesOfFloor(plan, room.floor)\n const occupied = itemsOfRoom(room)\n const windowZones = windowsOfRoom(plan, room).map((j) => ({ z: windowZone(j, room.outdoor), j }))\n // the 1 m landing in front of a staircase stays free\n const landings: Rect[] = it0.flat\n ? []\n : items\n .filter((m) => m.type === 'stairs' && m.floor === room.floor && m.aabb)\n .map((m) => {\n const r = m.aabb\n return (m.frontV === 1 ? [r[0], r[3], r[2], r[3] + 1] : m.frontV === -1 ? [r[0], r[1] - 1, r[2], r[1]] : m.frontU === 1 ? [r[2], r[1], r[2] + 1, r[3]] : [r[0] - 1, r[1], r[0], r[3]]) as Rect\n })\n const cand: Rect[] = opts.cands ? opts.cands.slice() : []\n if (!opts.cands)\n for (const p of inners) {\n const extentU = opts.dim ? opts.dim[0] : it.w\n const extentV = opts.dim ? opts.dim[1] : it.d\n for (const [x, z] of [[p[0], p[1]], [p[2] - extentU, p[1]], [p[0], p[3] - extentV], [p[2] - extentU, p[3] - extentV]]) cand.push([x, z, x + extentU, z + extentV])\n for (let k = 0; k < 6; k++) {\n const t = rng2()\n const side = Math.floor(rng2() * 4)\n const x = side < 2 ? p[0] + t * Math.max(0, p[2] - p[0] - extentU) : side === 2 ? p[0] : p[2] - extentU\n const z = side >= 2 ? p[1] + t * Math.max(0, p[3] - p[1] - extentV) : side === 0 ? p[1] : p[3] - extentV\n cand.push([x, z, x + extentU, z + extentV])\n }\n }\n for (const r of opts.ordered ? cand : shuffle(cand, rng2)) {\n if (!insideUnion(r, inners)) continue\n if (zones.some((z) => overlaps(r, z)) || landings.some((z) => overlaps(r, z))) continue\n if (windowZones.some(({ z, j }) => blocksWindow(it, j) && overlaps(r, z))) continue\n if (solidList.some((o) => overlaps(r, o))) continue\n if (opts.flat) {\n if (!(opts.without && opts.without(r))) return r\n continue\n }\n if (occupied.some((m) => !m.low && !m.flat && !m.on && !m.decor && m.clearance > 0 && overlaps(r, clearRect(m._r as Rect, [m.frontU, m.frontV], m.clearance)))) continue\n if (opts.without && opts.without(r)) continue\n if (!reachable(opts.railing || gridOf(room), solidList.concat([r]), room.outdoor ? 0.16 : plan.playerRadius)) continue\n return r\n }\n return null\n }\n const roomById = (id: string) => plan.rooms.find((c) => c.id === id) || plan.zones.find((c) => c.id === id)\n return {\n make,\n add,\n placeOnFloor,\n itemsOfRoom,\n solidsOfRoom,\n gridOf,\n extraSolids,\n roomById,\n setIgnored: (s) => {\n ignored = s\n for (const k of Object.keys(gridCache)) delete gridCache[k]\n },\n added,\n }\n}\n\n/** Ground cover per lot zone: one piece per zone part, plus overlays registered by content packs (decks around pools...). */\nfunction groundCover(plan: Plan, items: PlacedItem[], ctx: PlacementContext) {\n if (!plan.lot) return\n const polygonOf = (r: Rect) => [[r[0], r[1]], [r[2], r[1]], [r[2], r[3]], [r[0], r[3]]].map((p) => [r2(p[0]), r2(p[1])])\n const groundPiece = (z: Room, type: string, r: Rect, layer: number, i: number) => {\n const m = ctx.make(z, type, r, [0, 1], {\n id: z.id + '.ground' + (layer ? '_overlay' : '') + i,\n slot: 'ground' + (layer ? '_overlay' : '') + i,\n w: r2(r[2] - r[0]),\n d: r2(r[3] - r[1]),\n h: 0,\n polygon: polygonOf(r),\n layer,\n zone: z.id,\n outdoor: true,\n floor: -1,\n })\n return ctx.add(m)\n }\n for (const z of plan.zones) {\n z.parts.forEach((p, i) => groundPiece(z, z.ground as string, p, 0, i))\n let k = 0\n const clip = (r: Rect): Rect | undefined =>\n z.parts\n .map((p) => [Math.max(r[0], p[0]), Math.max(r[1], p[1]), Math.min(r[2], p[2]), Math.min(r[3], p[3])] as Rect)\n .filter((q) => q[2] - q[0] > 0.3 && q[3] - q[1] > 0.3)\n .sort((a, b) => areaOf(b) - areaOf(a))[0]\n for (const rule of registries().GROUND_OVERLAYS) {\n const triggers = items.filter((m) => m.room === z.id && m.category === rule.category)\n if (rule.merge) {\n if (triggers.length && z.ground !== rule.unlessGround) {\n const u = triggers.reduce((a, m) => [Math.min(a[0], (m._r as Rect)[0]), Math.min(a[1], (m._r as Rect)[1]), Math.max(a[2], (m._r as Rect)[2]), Math.max(a[3], (m._r as Rect)[3])], [1e9, 1e9, -1e9, -1e9])\n const q = clip(inflate(u as Rect, rule.inflate))\n if (q) groundPiece(z, rule.ground, q, 1, k++)\n }\n } else {\n for (const m of triggers) {\n const q = clip(inflate(m._r as Rect, rule.inflate))\n if (q) groundPiece(z, rule.ground, q, 1, k++)\n }\n }\n }\n }\n}\n\n/** Runs the registered decor passes and the ground cover; returns the context for the state step. */\nexport function runPostProcess(plan: Plan, items: PlacedItem[], seed: number | string): PlacementContext {\n const ctx = createPlacementContext(plan, items)\n const rng = createRng(seed, STREAM.decor)\n for (const pass of registries().PASSES) pass.run({ plan, items, seed, rng, ctx, kit: placementKit, catalog: registries().CATALOG, profiles: registries().DECOR_PROFILES })\n groundCover(plan, items, ctx)\n return ctx\n}\n","import { registries } from './registry'\nimport type { FloorplanLocale } from './types'\n\ntype Namespace = keyof FloorplanLocale\n\n/** Registers (or extends) the strings of a language. Packs call this with their JSON files. */\nexport function registerLocale(code: string, table: FloorplanLocale): void {\n const { LOCALES: locales } = registries()\n const cur = (locales[code] = locales[code] || {})\n for (const ns of Object.keys(table) as Namespace[]) cur[ns] = Object.assign(cur[ns] || {}, table[ns])\n}\n\nexport const listLocales = (): string[] => Object.keys(registries().LOCALES)\n\n/** Looks a key up in a namespace. Falls back to English, then to the key itself. `{n}`-style variables are replaced. */\nexport function translate(ns: Namespace, key: string, locale = 'en', vars?: Record<string, string | number>): string {\n const { LOCALES: locales } = registries()\n const raw = locales[locale]?.[ns]?.[key] ?? locales.en?.[ns]?.[key] ?? key\n return vars ? raw.replace(/\\{(\\w+)\\}/g, (m, k) => (k in vars ? String(vars[k]) : m)) : raw\n}\n","import { r2 } from './geometry'\nimport type { Json, Plan, Rect, Room } from './types'\n\nexport interface ExteriorPathContext {\n gates: Json[]\n paths: Json[]\n zones: Room[]\n setback: number\n marginLeft: number\n marginRight: number\n backyard: number\n w: number\n /** Door the entrance path is named after (the template's `doorTarget`). */\n target?: { a: string; side: string }\n}\n\nconst CLOSE = 1e-6\nconst rounded = (r: Rect): Rect => r.map(r2) as Rect\nconst touches = (a: Rect, r: Rect): boolean => a[0] <= r[2] + CLOSE && a[2] >= r[0] - CLOSE && a[1] <= r[3] + CLOSE && a[3] >= r[1] - CLOSE\n\ninterface SideRoute {\n lane: { x: number; width: number; side: string }\n laneWidth: number\n half: number\n vertical: Rect\n horizontal: Rect | null\n frontStub: Rect | null\n cost: number\n rearStrip: number\n rearY: number\n frontY: number\n overlapsParking: boolean\n}\n\n/**\n * Every exterior door of the ground floor gets a paved pedestrian path to the pedestrian gate or to the nearest existing path.\n * Doors on the front go straight out; doors on the back or the sides run along the side yard, to the parking or to the front path.\n */\nexport function addExteriorDoorPaths(plan: Plan, c: ExteriorPathContext): void {\n const { gates, paths, zones, setback, marginLeft, marginRight, backyard, w } = c\n const social = gates.find((g) => g.type === 'pedestrian')\n const socialPath = social ? paths.find((p) => p.from === social.id && p.type === 'pedestrian') : null\n const parkingZone = zones.find((z) => z.id === 'parking')\n const parking: Rect | null = parkingZone ? parkingZone.parts[0] : null\n const midY = setback > 0 ? -setback / 2 : 0\n const joinToSocial = (x: number, width: number, rects: Rect[], points: number[][]) => {\n if (!socialPath) return\n const h = width / 2\n const horizontal = socialPath.rects.find((r: Rect) => midY >= r[1] - CLOSE && midY <= r[3] + CLOSE && r[2] - r[0] > r[3] - r[1]) || socialPath.rects[0]\n const targetX = x < horizontal[0] ? horizontal[0] + h : x > horizontal[2] ? horizontal[2] - h : x\n if (Math.abs(targetX - x) > CLOSE) {\n rects.push([Math.min(x, targetX) - h, midY - h, Math.max(x, targetX) + h, midY + h])\n points.push([targetX, midY])\n }\n }\n for (const door of plan.doors.filter((q) => q.floor === 0 && q.exterior)) {\n if (paths.some((p) => p.to === door.id)) continue\n const half = Math.max(1.0, Math.min(door.width, 2.0)) / 2\n const rects: Rect[] = []\n const points: number[][] = []\n const isTarget = c.target && door.a === c.target.a && door.side === c.target.side\n let fromId: string | null = social ? social.id : null\n let width = 1.0\n const id = isTarget ? 'entrance_path' : 'path_' + door.id\n if (door.side === 'front') {\n if (setback > 0) {\n const stub = Math.min(1.0, setback)\n rects.push([door.u - half, -stub, door.u + half, 0])\n points.push([door.u, 0], [door.u, -stub])\n if (-stub > midY) {\n rects.push([door.u - width / 2, midY - width / 2, door.u + width / 2, -stub])\n points.push([door.u, midY])\n }\n joinToSocial(door.u, width, rects, points)\n } else {\n rects.push([door.u - half, -1.2, door.u + half, 0])\n points.push([door.u, 0], [door.u, -1.2])\n }\n } else {\n const lanes: SideRoute['lane'][] = []\n if (marginLeft > 0.5) lanes.push({ x: -marginLeft / 2, width: marginLeft, side: 'left' })\n if (marginRight > 0.5) lanes.push({ x: w + marginRight / 2, width: marginRight, side: 'right' })\n const targets: Rect[] = paths.flatMap((p) => p.rects as Rect[]).concat(parking ? [parking] : [])\n let best: SideRoute | null = null\n for (const lane of lanes) {\n if ((door.side === 'left' && lane.side !== 'left') || (door.side === 'right' && lane.side !== 'right')) continue\n const laneWidth = Math.min(0.9, lane.width - 0.1)\n const h = laneWidth / 2\n const rearStrip = Math.min(0.8, backyard)\n const rearY = door.v + rearStrip + laneWidth / 2\n const overlapsParking = !!parking && lane.x + h > parking[0] && lane.x - h < parking[2]\n const frontY = overlapsParking || setback <= 0 ? 0 : -0.6\n let frontStub: Rect | null = null\n if (!overlapsParking && setback > 0) {\n const dir = social && social.u < lane.x ? -1 : 1\n const band = [-0.6 - h, -0.6 + h]\n let nearestX = social ? social.u : lane.x\n let nearestGap = Infinity\n for (const r of targets) {\n if (!(r[1] <= band[1] && r[3] >= band[0])) continue\n const edge = dir < 0 ? r[2] : r[0]\n const gap = Math.abs(edge - lane.x)\n if ((dir < 0 ? edge <= lane.x : edge >= lane.x) && gap < nearestGap) {\n nearestGap = gap\n nearestX = edge\n }\n }\n frontStub = [Math.min(lane.x, nearestX) - (dir < 0 ? 0 : h), -0.6 - h, Math.max(lane.x, nearestX) + (dir < 0 ? h : 0), -0.6 + h]\n }\n const vertical: Rect = [lane.x - h, frontY - (frontY < 0 ? h : 0), lane.x + h, (door.side === 'back' ? rearY : door.v) + laneWidth / 2]\n const horizontal: Rect | null = door.side === 'back' ? [Math.min(door.u, lane.x) - half, rearY - laneWidth / 2, Math.max(door.u, lane.x) + h, rearY + laneWidth / 2] : null\n const cost = (horizontal ? horizontal[2] - horizontal[0] : 0) + (frontStub ? frontStub[2] - frontStub[0] : 0)\n if (!best || cost < best.cost) best = { lane, laneWidth, half: h, vertical, horizontal, frontStub, cost, rearStrip, rearY, frontY, overlapsParking }\n }\n if (best) {\n const { lane, laneWidth, half: h, vertical, horizontal, frontStub, rearStrip, rearY, frontY, overlapsParking } = best\n width = laneWidth\n if (overlapsParking) fromId = (gates.find((g) => g.type === 'garage') || social || ({} as Json)).id || null\n if (door.side === 'back') {\n rects.push([door.u - half, door.v, door.u + half, door.v + rearStrip + laneWidth], horizontal as Rect, vertical)\n points.push([door.u, door.v], [door.u, rearY], [lane.x, rearY], [lane.x, frontY])\n } else {\n const x0 = door.side === 'left' ? lane.x - h : w\n const x1 = door.side === 'left' ? 0 : lane.x + h\n rects.push([Math.min(x0, x1), door.v - half, Math.max(x0, x1), door.v + half], vertical)\n points.push([door.u, door.v], [lane.x, door.v], [lane.x, frontY])\n }\n if (frontStub) {\n rects.push(frontStub)\n points.push([frontStub[0] < lane.x ? frontStub[0] : frontStub[2], -0.6])\n }\n } else {\n const stub = 1.0\n if (door.side === 'back') rects.push([door.u - half, door.v, door.u + half, door.v + Math.min(stub, backyard)])\n else rects.push(door.side === 'left' ? [-Math.min(stub, marginLeft), door.v - half, 0, door.v + half] : [w, door.v - half, w + Math.min(stub, marginRight), door.v + half])\n points.push([door.u, door.v])\n }\n }\n const reached = rects.slice()\n const pool: Rect[] = paths.flatMap((p) => p.rects as Rect[]).concat(parking ? [parking] : [])\n let grows = true\n while (grows) {\n grows = false\n for (const r of pool) {\n if (!reached.includes(r) && reached.some((a) => touches(a, r))) {\n reached.push(r)\n grows = true\n }\n }\n }\n const inside = (g: Json) => reached.some((r) => g.u >= r[0] - CLOSE && g.u <= r[2] + CLOSE && g.v >= r[1] - CLOSE && g.v <= r[3] + CLOSE)\n const gate = gates.find((q) => q.type === 'pedestrian' && inside(q)) || gates.find((q) => q.type !== 'cargo' && inside(q))\n if (gate) fromId = gate.id\n paths.push({ id, type: 'pedestrian', from: fromId, to: door.id, width, rects: rects.map(rounded), points: points.map((q) => q.map(r2)) })\n }\n}\n\n","import { registries } from './registry'\nimport { r2 } from './geometry'\nimport type { FloorplanOptions, Json, Plan, TemplateDef, ZoneAdjustment, ZoneDef, ZoneViolation } from './types'\n\n/** Registers an urban zone (zoning rules). Returns the stored definition. */\nexport function defineZone(zone: ZoneDef): ZoneDef {\n if (!zone || !zone.id) throw new Error('defineZone: id is required')\n registries().ZONES[zone.id] = zone\n return zone\n}\nexport const getZone = (id: string): ZoneDef | undefined => registries().ZONES[id]\nexport const listZones = (): ZoneDef[] => Object.values(registries().ZONES)\n\n/** Marks ground types (e.g. `lawn`, `dirt`) that count towards the permeable area of a lot. */\nexport function registerPermeableGround(...types: string[]): void {\n for (const t of types) registries().PERMEABLE_GROUNDS.add(t)\n}\n\nexport function resolveZone(z: string | ZoneDef | undefined): ZoneDef | null {\n if (!z) return null\n if (typeof z === 'string') {\n const found = registries().ZONES[z]\n if (!found) throw new Error('Unknown zone: ' + z)\n return found\n }\n return z\n}\n\nexport const floorsOfTemplate = (tpl: TemplateDef, op: FloorplanOptions): number => (tpl.floorsFn ? tpl.floorsFn(op) : tpl.floors || []).length\n\n/** Declared use of a template; templates without one are treated as `residential_single`. */\nexport const useOf = (tpl: TemplateDef): string => tpl.use || 'residential_single'\n\n/** Totals used by the checks: storeys, height, areas. Works on a generated result or an internal plan. */\nfunction measure(plan: Json) {\n const floors: { index: number; y0: number; ceiling: number }[] = plan.floors\n const top = floors.reduce((m, f) => Math.max(m, f.y0 + f.ceiling), 0)\n const number = plan.floorNumber != null ? plan.floorNumber : floors.length\n const rooms: { floor: number; parts: number[][] }[] = (plan.rooms || []).filter((r: Json) => r.floor >= 0)\n const area = (r: Json) => r.parts.reduce((s: number, p: number[]) => s + (p[2] - p[0]) * (p[3] - p[1]), 0)\n const footprint = plan.w * plan.d\n const built = rooms.reduce((s, r) => s + area(r), 0)\n return { storeys: number, height: r2(top), footprint, built }\n}\n\n/**\n * Checks a generated lot against a zone and returns the violations (empty when compliant).\n * `lot` is `result.lot` (may be null for apartments), `plan` is the result of `generate`.\n */\nexport function checkLot(zoneIn: string | ZoneDef, lot: Json, plan: Json): ZoneViolation[] {\n const zone = resolveZone(zoneIn) as ZoneDef\n const out: ZoneViolation[] = []\n const m = measure(plan)\n const use = plan.use || 'residential_single'\n if (!zone.allowedUses.includes(use)) out.push({ rule: 'use', actual: use, limit: zone.allowedUses.join(',') })\n if (m.storeys > zone.maxFloors) out.push({ rule: 'floors', actual: m.storeys, limit: zone.maxFloors })\n if (m.height > zone.maxHeight + 1e-9) out.push({ rule: 'height', actual: m.height, limit: zone.maxHeight })\n if (!lot) return out\n const [u0, v0, u1, v1] = lot.rect as number[]\n const width = r2(u1 - u0)\n const depth = r2(v1 - v0)\n const area = width * depth\n const party: string[] = plan.partyWalls || []\n const sides = [party.includes('left') ? Infinity : lot.sideYard.left, party.includes('right') ? Infinity : lot.sideYard.right]\n const left = sides[0]\n const right = sides[1]\n if (lot.setback < zone.setbacks.front - 1e-9) out.push({ rule: 'setback_front', actual: lot.setback, limit: zone.setbacks.front })\n if (Math.min(left, right) < zone.setbacks.side - 1e-9) out.push({ rule: 'setback_side', actual: Math.min(left, right), limit: zone.setbacks.side })\n if (lot.backyard < zone.setbacks.back - 1e-9) out.push({ rule: 'setback_back', actual: lot.backyard, limit: zone.setbacks.back })\n if (area < zone.minLot - 1e-9) out.push({ rule: 'min_lot', actual: r2(area), limit: zone.minLot })\n if (width < zone.minFrontage - 1e-9) out.push({ rule: 'min_frontage', actual: width, limit: zone.minFrontage })\n const ground = m.footprint\n const coverage = ground / area\n if (coverage > zone.maxCoverage + 1e-9) out.push({ rule: 'coverage', actual: r2(coverage), limit: zone.maxCoverage })\n const far = m.built / area\n if (far > zone.maxFar + 1e-9) out.push({ rule: 'far', actual: r2(far), limit: zone.maxFar })\n let permeable = 0\n for (const z of lot.zones as Json[]) if (registries().PERMEABLE_GROUNDS.has(z.ground)) for (const p of z.parts as number[][]) permeable += (p[2] - p[0]) * (p[3] - p[1])\n const permeability = permeable / area\n if (permeability < zone.permeableMin - 1e-9) out.push({ rule: 'permeable', actual: r2(permeability), limit: zone.permeableMin })\n return out\n}\n\n/** Clamps adjustable options (`floors`) to the zone before the plan is built. */\nexport function clampOptionsToZone(tpl: TemplateDef, op: FloorplanOptions, zone: ZoneDef, adjustments: ZoneAdjustment[]): FloorplanOptions {\n if (tpl.singleFloor) {\n // an apartment unit: the storey it sits on must exist in a building the zone allows\n const ceiling = (tpl.floors || tpl.floorsFn?.(op) || [])[0]?.ceiling ?? 2.8\n const current = op.floor || 3\n const limit = Math.max(1, Math.min(zone.maxFloors, Math.floor(zone.maxHeight / ceiling + 1e-9)))\n if (current <= limit) return op\n adjustments.push({ field: 'floor', from: current, to: limit, reason: current > zone.maxFloors ? 'max_floors' : 'max_height' })\n return Object.assign({}, op, { floor: limit })\n }\n if (!tpl.floorRange || !tpl.floorsFn) return op\n const current = floorsOfTemplate(tpl, op)\n const floors = tpl.floorsFn(op)\n const ceiling = floors.reduce((m, f) => Math.max(m, f.ceiling), 0) || 2.8\n const byHeight = Math.max(1, Math.floor(zone.maxHeight / ceiling + 1e-9))\n const limit = Math.max(tpl.floorRange[0], Math.min(zone.maxFloors, byHeight, tpl.floorRange[1]))\n if (current <= limit) return op\n adjustments.push({ field: 'floors', from: current, to: limit, reason: current > zone.maxFloors ? 'max_floors' : 'max_height' })\n return Object.assign({}, op, { floors: limit })\n}\n\n/** Raises lot setbacks to the zone minimums. */\nexport function clampLotToZone(cfg: Json, zone: ZoneDef, adjustments: ZoneAdjustment[], partyWalls: string[] = []): void {\n const raise = (field: string, key: string, min: number, reason: string) => {\n if (cfg[key] < min) {\n adjustments.push({ field, from: cfg[key], to: min, reason })\n cfg[key] = min\n }\n }\n raise('frontSetback', 'frontSetback', zone.setbacks.front, 'setback_front')\n if (!partyWalls.includes('left')) raise('marginLeft', 'marginLeft', zone.setbacks.side, 'setback_side')\n if (!partyWalls.includes('right')) raise('marginRight', 'marginRight', zone.setbacks.side, 'setback_side')\n raise('backyardDepth', 'backyardDepth', zone.setbacks.back, 'setback_back')\n}\n\nexport type { Plan }\n\n/** Lot zone types whose ground can be switched to a permeable one to meet the permeability rate. */\nconst ADJUSTABLE_ZONES = new Set(['garden', 'backyard', 'side_yard'])\n\n/**\n * Raises the permeable area of a lot to the zone's `permeableMin` by turning paved garden, yard\n * and side zones (largest first) into the first registered permeable ground. Reports each change.\n */\nexport function enforcePermeability(lot: Json, zones: Json[], zone: ZoneDef, adjustments: ZoneAdjustment[]): void {\n const target = [...registries().PERMEABLE_GROUNDS][0]\n if (!target) return\n const [u0, v0, u1, v1] = lot.rect as number[]\n const area = (u1 - u0) * (v1 - v0)\n const areaOfZone = (z: Json) => (z.parts as number[][]).reduce((s, p) => s + (p[2] - p[0]) * (p[3] - p[1]), 0)\n let permeable = zones.filter((z) => registries().PERMEABLE_GROUNDS.has(z.ground)).reduce((s, z) => s + areaOfZone(z), 0)\n if (permeable / area >= zone.permeableMin) return\n const candidates = zones.filter((z) => ADJUSTABLE_ZONES.has(z.type) && !registries().PERMEABLE_GROUNDS.has(z.ground)).sort((a, b) => areaOfZone(b) - areaOfZone(a))\n for (const z of candidates) {\n if (permeable / area >= zone.permeableMin) break\n adjustments.push({ field: 'ground:' + z.id, from: z.ground, to: target, reason: 'permeable_min' })\n z.ground = target\n permeable += areaOfZone(z)\n }\n}\n","import { CAR_CLEARANCE, DOOR_EDGE_CLEARANCE, MARGIN, PLAYER_RADIUS, TOL, WALL_THICKNESS, WINDOWLESS_ROOM_TYPES, WINDOW_EDGE_CLEARANCE } from './constants'\nimport { buildWalls, clamp, eq, exteriorEdge, inRect, normalizeRoom, openingDepth, openingZones, r2, sharedEdge } from './geometry'\nimport { STREAM } from './legacy-seeds'\nimport { createRng, pickWeighted } from './rng'\nimport { registries, resolveStyleId, styleOf } from './registry'\nimport { addExteriorDoorPaths } from './paths'\nimport { clampLotToZone, enforcePermeability } from './zoning'\nimport type { FloorDef, FloorplanOptions, Json, LotConfig, Plan, Rect, Room, StyleDef, TemplateDef, WindowDef, ZoneAdjustment, ZoneDef } from './types'\n\nexport const floorsOf = (tpl: TemplateDef, op?: FloorplanOptions): FloorDef[] => (tpl.floorsFn ? tpl.floorsFn(op || {}) : (tpl.floors as FloorDef[]))\n\nexport function clampSize(tpl: TemplateDef, w: number | undefined, d: number | undefined, op?: FloorplanOptions) {\n const L = tpl.limitsFn ? tpl.limitsFn(op || {}) : tpl.limits\n const P0 = tpl.defaultsFn ? tpl.defaultsFn(op || {}) : tpl.defaults\n const ww = w == null ? P0.w : clamp(w, L.w[0], L.w[1])\n const dd = d == null ? P0.d : clamp(d, L.d[0], L.d[1])\n return { w: r2(ww), d: r2(dd) }\n}\n\nexport interface BuildContext {\n zone?: ZoneDef | null\n adjustments?: ZoneAdjustment[]\n}\n\nexport function buildPlan(tpl: TemplateDef, wIn: number | undefined, dIn: number | undefined, opIn?: FloorplanOptions, bc: BuildContext = {}): Plan {\n const op = opIn || {}\n const { w, d } = clampSize(tpl, wIn, dIn, op)\n const styleId = resolveStyleId(op.style || (typeof tpl.style === 'function' ? tpl.style(op) : tpl.style) || 'budget')\n const FLOOR_DEFS = floorsOf(tpl, op)\n const style = styleOf(styleId)\n const plan: Plan = {\n w, d, tpl, floorDefs: FLOOR_DEFS, style: styleId, floors: [], rooms: [], zones: [], doors: [], windows: [], walls: [], gates: [], paths: [], lot: null, openPairs: {}, reservations: [], options: op,\n playerRadius: op.playerRadius ?? PLAYER_RADIUS,\n carClearance: Object.assign({}, CAR_CLEARANCE, op.carClearance),\n }\n FLOOR_DEFS.forEach((A, floorIndex) => {\n const floorNumber = tpl.singleFloor ? op.floor || 3 : floorIndex + 1\n plan.floors.push({\n index: floorIndex,\n name: tpl.singleFloor ? 'floor_n' : A.label,\n number: tpl.singleFloor ? floorNumber : undefined,\n y0: tpl.singleFloor ? (floorNumber - 1) * A.ceiling : tpl.cumulativeCeilings ? FLOOR_DEFS.slice(0, floorIndex).reduce((t, q) => t + q.ceiling, 0) : floorIndex * A.ceiling,\n ceiling: A.ceiling,\n })\n plan.openPairs[floorIndex] = A.openPairs || []\n const list = A.rooms(w, d, op).map((c) => normalizeRoom(c, floorIndex))\n for (const c of list) {\n if (plan.rooms.some((x) => x.id === c.id)) throw new Error('Duplicate room: ' + c.id)\n plan.rooms.push(c)\n }\n const byId: Record<string, Room> = {}\n for (const c of list) byId[c.id] = c\n const floorDoors: Json[] = []\n ;(A.doors(w, d, op) || []).forEach((sp, i) => {\n const a = byId[sp.a]\n if (!a) throw new Error('Door references a missing room: ' + sp.a)\n let edge\n if (sp.edge) edge = sp.edge\n else if (sp.b === 'outside') edge = exteriorEdge(a, sp.side as string, w, d, sp.at)\n else {\n const b = byId[sp.b]\n if (!b) throw new Error('Door references a missing room: ' + sp.b)\n edge = sharedEdge(a, b, sp.at)\n }\n if (!edge) throw new Error('Door without a wall: ' + sp.a + ' / ' + sp.b)\n const width = sp.width\n const margin = width / 2 + (sp.clearance ?? tpl.clearance?.door ?? DOOR_EDGE_CLEARANCE)\n if (edge.a1 - edge.a0 < width + 0.24) throw new Error('Wall too short for the door: ' + sp.a + ' / ' + sp.b)\n const c = clamp(sp.at != null ? sp.at : (edge.a0 + edge.a1) / 2, edge.a0 + margin, edge.a1 - margin)\n const exterior = sp.b === 'outside'\n const leaf = exterior && sp.steel ? 0 : width > 1.1 ? width / 2 : width\n const u = edge.axis === 'u' ? c : edge.pos\n const v = edge.axis === 'u' ? edge.pos : c\n floorDoors.push({\n id: 'd' + floorIndex + '_' + i,\n floor: floorIndex,\n u: r2(u),\n v: r2(v),\n axis: edge.axis,\n pos: edge.pos,\n at: r2(c),\n width,\n a: sp.a,\n b: sp.b,\n opensTo: sp.opensTo || sp.a,\n exterior,\n side: sp.side || null,\n leaves: exterior && sp.steel ? 0 : width > 1.1 ? 2 : 1,\n model: sp.model || (sp.steel ? 'steel' : width > 1.1 ? 'double' : 'single'),\n type: sp.type || 'door',\n steps: sp.steps || 0,\n hinge: 'start',\n zones: openingZones(u, v, edge.axis, width, openingDepth(width, leaf)),\n })\n })\n plan.doors.push(...floorDoors)\n const floorWalls = (tpl.noWalls ? [] : buildWalls(list, floorDoors, A.openPairs || [], floorIndex)).map((p) => Object.assign(p, { h: p.h || A.ceiling }))\n const windowsOut = placeWindows({ list, byId, floorWalls, windowDefs: A.windows(w, d, op) || [], floorIndex, ceiling: A.ceiling, w, d, clearance: tpl.clearance?.window ?? WINDOW_EDGE_CLEARANCE })\n plan.windows.push(...windowsOut)\n plan.walls.push(...floorWalls)\n })\n if (tpl.config) plan.config = tpl.config(op, w, d)\n if (tpl.reservations) tpl.reservations(plan)\n buildLot(plan, tpl, w, d, op, style, styleId, bc)\n return plan\n}\n\ninterface WindowGroup {\n wall: Json\n edge: { axis: 'u' | 'v'; pos: number }\n start: number\n end: number\n def: Json\n entries: { def: Json; centre: number; order: number }[]\n}\ninterface WindowParams {\n list: Room[]\n byId: Record<string, Room>\n floorWalls: Json[]\n windowDefs: WindowDef[]\n floorIndex: number\n ceiling: number\n w: number\n d: number\n clearance: number\n}\n\n/**\n * Each window lands on a stretch of exterior wall (between corners, junctions and doors) and is spread over it: a single window is centred,\n * several get equal gaps, and none comes closer than `clearance` to a corner, a junction or a door. A room that needs light but got no window gets one.\n */\nfunction placeWindows(params: WindowParams): Json[] {\n const { list, byId, floorWalls, windowDefs, floorIndex, ceiling, w, d, clearance } = params\n const stretches = floorWalls.filter((p) => p.exterior && p.type === 'wall')\n const found: Json[] = []\n const groups: WindowGroup[] = []\n let order = 0\n for (const def of windowDefs) {\n const room = byId[def.room]\n if (!room) throw new Error('Window references a missing room: ' + def.room)\n const edge = exteriorEdge(room, def.side, w, d, def.at)\n if (!edge) continue\n const centres = def.n ? Array.from({ length: def.n }, (_, i) => edge.a0 + ((edge.a1 - edge.a0) * (i + 1)) / (def.n! + 1)) : [def.at as number]\n for (const centre of centres) {\n const onEdge = stretches.filter((t) => t.axis === edge.axis && eq(edge.axis === 'u' ? t.v0 : t.u0, edge.pos) && t.sides.includes(def.room))\n const start = (t: Json) => (edge.axis === 'u' ? t.u0 : t.v0)\n const end = (t: Json) => (edge.axis === 'u' ? t.u1 : t.v1)\n const gap = (t: Json) => Math.min(Math.abs(centre - start(t)), Math.abs(centre - end(t)))\n const target = onEdge.find((t) => centre >= start(t) - TOL && centre <= end(t) + TOL) || onEdge.slice().sort((x, y) => gap(x) - gap(y))[0]\n if (!target) continue\n let group = groups.find((x) => x.wall === target && x.def.room === def.room)\n if (!group) groups.push((group = { wall: target, edge, start: start(target), end: end(target), def, entries: [] }))\n group.entries.push({ def, centre, order: order++ })\n }\n }\n for (const g of groups) {\n const room = byId[g.def.room]\n const bath = room.type === 'bathroom'\n const length = g.end - g.start\n const its = g.entries\n .slice()\n .sort((x, y) => x.centre - y.centre)\n .map((x) => ({ def: x.def, order: x.order, width: bath ? Math.min(x.def.width, 0.6) : x.def.width }))\n const fits = (l: typeof its) => l.reduce((t, x) => t + x.width, 0) + (l.length + 1) * clearance <= length + TOL\n while (its.length && !fits(its)) {\n const k = its.reduce((m, x, i, arr) => (x.width > arr[m].width ? i : m), 0)\n if (its[k].width > 0.6 + TOL) its[k] = Object.assign({}, its[k], { width: Math.max(0.6, r2(its[k].width - 0.1)) })\n else its.pop()\n }\n if (!its.length) continue\n const space = (length - its.reduce((t, x) => t + x.width, 0)) / (its.length + 1)\n let pos = g.start + space\n for (const x of its) {\n const c = pos + x.width / 2\n pos += x.width + space\n const u = g.edge.axis === 'u' ? c : g.edge.pos\n const v = g.edge.axis === 'u' ? g.edge.pos : c\n let y0 = x.def.y0 || 1.0\n let y1 = x.def.y1 || 2.15\n if (bath) {\n y0 = Math.max(y0, 2.1)\n y1 = Math.min(Math.max(y1, y0 + 0.4), ceiling - 0.25)\n }\n found.push({ id: '', floor: floorIndex, u: r2(u), v: r2(v), axis: g.edge.axis, pos: g.edge.pos, at: r2(c), width: x.width, y0: r2(y0), y1: r2(y1), room: x.def.room, side: x.def.side, _order: x.order })\n }\n }\n for (const room of list) {\n if (WINDOWLESS_ROOM_TYPES.has(room.type) || found.some((j) => j.room === room.id)) continue\n let best: { length: number; window: Json } | null = null\n for (const t of stretches) {\n if (!t.sides.includes(room.id)) continue\n const i0 = t.axis === 'u' ? t.u0 : t.v0\n const i1 = t.axis === 'u' ? t.u1 : t.v1\n const length = i1 - i0\n const width = Math.min(room.type === 'bathroom' ? 0.6 : 1.2, length - 2 * clearance)\n if (width < 0.6 - TOL || (best && best.length >= length)) continue\n const side = t.axis === 'u' ? (t.sides[0] === 'outside' ? 'front' : 'back') : t.sides[0] === 'outside' ? 'left' : 'right'\n const c = (i0 + i1) / 2\n const pos = t.axis === 'u' ? t.v0 : t.u0\n const bath = room.type === 'bathroom'\n best = { length, window: { id: '', floor: floorIndex, u: r2(t.axis === 'u' ? c : pos), v: r2(t.axis === 'u' ? pos : c), axis: t.axis, pos, at: r2(c), width: r2(width), y0: bath ? 2.1 : 1.0, y1: bath ? Math.min(2.5, ceiling - 0.25) : 2.15, room: room.id, side, _order: 1e6 + found.length } }\n }\n if (best) found.push(best.window)\n }\n found.sort((x, y) => x._order - y._order)\n found.forEach((j, i) => {\n delete j._order\n j.id = 'w' + floorIndex + '_' + i\n })\n return found\n}\n\n/** Facade and lot: zones, gates, paths and perimeter. */\nfunction buildLot(plan: Plan, tpl: TemplateDef, w: number, d: number, op: FloorplanOptions, style: StyleDef, styleId: string, bc: BuildContext) {\n const seed = op.seed == null ? 1 : op.seed\n const rFacade = createRng(seed, STREAM.facade)\n const facadeStyle = style.facade\n const palette = style.swatches\n const color = palette[Math.floor(rFacade() * palette.length)]\n const extra = tpl.facade || {}\n plan.facade = {\n style: styleId,\n color: { name: color[0], hex: color[1] },\n finish: pickWeighted(rFacade, facadeStyle.finish),\n grilles: rFacade() < facadeStyle.grilles,\n roof: pickWeighted(rFacade, facadeStyle.roof),\n balcony: !!extra.balcony,\n veranda: !!extra.veranda,\n steelDoor: !!extra.steelDoor,\n floors: plan.floorDefs.length,\n }\n if (tpl.facadeExtra) tpl.facadeExtra(plan.facade, rFacade, w, d, op)\n if (plan.floorDefs.length > 1 && plan.facade.roof === 'fiber_cement') plan.facade.roof = 'colonial'\n if (!tpl.lot) return\n const cfg: LotConfig = tpl.lot(w, d, style, op)\n if (bc.zone) clampLotToZone(cfg, bc.zone, bc.adjustments || [], tpl.partyWalls)\n const rLot = createRng(seed, STREAM.lot)\n const setback = cfg.frontSetback\n const marginL = cfg.marginLeft\n const marginR = cfg.marginRight\n const backDepth = cfg.backyardDepth\n const lot: Json = {\n rect: [-marginL, -setback, w + marginR, d + backDepth],\n setback,\n sideYard: { left: marginL, right: marginR },\n backyard: backDepth,\n style: styleId,\n zones: [],\n perimeter: [],\n gates: [],\n paths: [],\n pool: !!cfg.pool,\n }\n const ZONES: Room[] = []\n const libs = Object.assign({ garden: 'garden', backyard: 'backyard', parking: 'parking', sideYard: 'side_yard' }, cfg.libraries || {})\n const addZone = (id: string, type: string, label: string, parts: Rect[], library?: string) =>\n ZONES.push(Object.assign(normalizeRoom({ id, type, label, rect: parts[0], parts: parts.slice(1), library, outdoor: true }, -1), { floor: -1, outdoor: true }))\n if (setback > 0) {\n let parts: Rect[] = [[-marginL, -setback, w + marginR, 0]]\n if (cfg.parking) {\n const garageU = (cfg.garage as Json).u\n const vw = cfg.parking.width\n const x0 = Math.max(-marginL, garageU - vw / 2)\n const x1 = Math.min(w + marginR, garageU + vw / 2)\n parts = []\n if (x0 + marginL > 0.8) parts.push([-marginL, -setback, x0, 0])\n if (w + marginR - x1 > 0.8) parts.push([x1, -setback, w + marginR, 0])\n addZone('parking', 'parking', 'parking', [[x0, -setback, x1, 0]], libs.parking)\n if (!parts.length) parts = [[x1, -setback, w + marginR, 0]]\n }\n parts.sort((a, b) => b[2] - b[0] - (a[2] - a[0]))\n addZone('garden', 'garden', 'garden', parts, libs.garden)\n }\n const yard = cfg.yardZones\n if (backDepth > 0 && yard) {\n for (const q of yard) addZone(q.id, q.type, q.label || q.id, [[-marginL, d + q.v0, w + marginR, d + Math.min(backDepth, q.v1)]], q.library)\n } else if (backDepth > 0) addZone('backyard', 'backyard', 'backyard', [[-marginL, d, w + marginR, d + backDepth]], libs.backyard)\n for (const q of cfg.extraZones || []) addZone(q.id, q.type, q.label || q.id, q.parts, q.library)\n if (marginL > 0.5) addZone('side_left', 'side_yard', 'side_left', [[-marginL, 0, 0, d]], libs.sideYard)\n if (marginR > 0.5) addZone('side_right', 'side_yard', 'side_right', [[w, 0, w + marginR, d]], libs.sideYard)\n const gates: Json[] = []\n const addGate = (type: string, model: string, u: number, v: number, width: number, side: string, toTarget?: string | null) => {\n const g: Json = {\n id: 'g' + gates.length,\n type,\n model,\n u: r2(u),\n v: r2(v),\n axis: 'u',\n width,\n height: type === 'pedestrian' ? style.height : Math.min(style.height, 2.2),\n side,\n to: toTarget || null,\n material: 'iron',\n }\n g.zones = openingZones(u, v, 'u', width, openingDepth(width, type === 'pedestrian' ? width : 0))\n gates.push(g)\n return g\n }\n if (cfg.pedestrian && setback > 0) addGate('pedestrian', 'pedestrian', cfg.pedestrian.u, -setback, 1.0, 'front', 'door')\n if (cfg.garage && setback > 0) addGate('garage', pickWeighted(rLot, style.gate.garage), cfg.garage.u, -setback, cfg.garage.width, 'front', cfg.garage.to)\n if (cfg.cargo) addGate('cargo', 'sliding', cfg.cargo.u, d + backDepth, cfg.cargo.width, 'back', 'stockroom')\n plan.gates = gates\n lot.gates = gates\n const paths: Json[] = []\n const target = (a: string, side: string) => plan.doors.find((p) => p.exterior && p.a === a && p.side === side)\n for (const g of gates) {\n if (g.type === 'pedestrian' && cfg.doorTarget) {\n const pt = target(cfg.doorTarget.a, cfg.doorTarget.side)\n if (!pt) continue\n const gateU = g.u\n const dx = pt.u\n const ym = -setback / 2\n const L = 1.0\n const h = L / 2\n const rs: Rect[] = []\n if (Math.abs(gateU - dx) < 0.05) rs.push([dx - h, -setback, dx + h, 0])\n else {\n rs.push([gateU - h, -setback, gateU + h, ym + h])\n rs.push([Math.min(gateU, dx) - h, ym - h, Math.max(gateU, dx) + h, ym + h])\n rs.push([dx - h, ym - h, dx + h, 0])\n }\n paths.push({ id: 'pedestrian_path', type: 'pedestrian', from: g.id, to: pt.id, width: L, rects: rs.map((r) => r.map(r2)), points: [[gateU, -setback], [gateU, ym], [dx, ym], [dx, 0]] })\n } else if (g.type === 'garage' && g.to === 'inner_garage') {\n const pt = plan.doors.find((p) => p.exterior && p.side === 'front' && Math.abs(p.u - g.u) < 0.6 && p.width >= 2.5)\n if (!pt) continue\n const hw = Math.max(g.width, pt.width) / 2\n paths.push({ id: 'garage_path', type: 'vehicle', from: g.id, to: pt.id, width: hw * 2, rects: [[g.u - hw, -setback, g.u + hw, 0].map(r2)], points: [[g.u, -setback], [g.u, 0]] })\n } else if (g.type === 'cargo') {\n const pt = target('stockroom', 'back')\n if (!pt) continue\n const hw = Math.max(g.width, pt.width) / 2\n paths.push({ id: 'cargo_path', type: 'vehicle', from: g.id, to: pt.id, width: hw * 2, rects: [[g.u - hw, d, g.u + hw, d + backDepth].map(r2)], points: [[g.u, d + backDepth], [g.u, d]] })\n }\n }\n if (tpl.paths) paths.push(...tpl.paths(plan, { gates, setback, marginLeft: marginL, marginRight: marginR, backyard: backDepth, w, d }))\n else addExteriorDoorPaths(plan, { gates, paths, zones: ZONES, setback, marginLeft: marginL, marginRight: marginR, backyard: backDepth, w, target: cfg.doorTarget })\n plan.paths = paths\n lot.paths = paths\n const boundary = (rule: { type: Record<string, number>; top: Record<string, number> }) => {\n const type = pickWeighted(rLot, rule.type)\n const top = type === 'railing' ? 'none' : pickWeighted(rLot, rule.top)\n const wallHeight = type === 'railing' ? 1.2 : type === 'fence' ? (style.fenceHeight ?? 2.0) : style.height\n return { type, material: type === 'wall' ? 'block' : type === 'fence' ? 'wire_mesh' : 'iron', height: wallHeight, top, totalHeight: r2(wallHeight + registries().WALL_TOP_HEIGHTS[top]), thickness: WALL_THICKNESS }\n }\n const A: Record<string, Json> = { front: boundary(style.front), left: boundary(style.sideYard), right: boundary(style.sideYard), back: boundary(style.back) }\n const seg = (side: string, u0: number, v0: number, u1: number, v1: number) => {\n if (Math.abs(u1 - u0) + Math.abs(v1 - v0) < 0.05) return\n lot.perimeter.push(Object.assign({ id: 'm' + lot.perimeter.length, side, u0: r2(u0), v0: r2(v0), u1: r2(u1), v1: r2(v1) }, A[side]))\n }\n const cutRun = (side: string, de: number, to: number, vfix: number, gs: Json[]) => {\n let pieces: [number, number][] = [[de, to]]\n for (const g of gs) {\n const g0 = g.u - g.width / 2\n const g1 = g.u + g.width / 2\n const n: [number, number][] = []\n for (const [x, y] of pieces) {\n if (g1 <= x || g0 >= y) {\n n.push([x, y])\n continue\n }\n if (g0 > x) n.push([x, g0])\n if (g1 < y) n.push([g1, y])\n }\n pieces = n\n }\n for (const [x, y] of pieces) seg(side, x, vfix, y, vfix)\n }\n if (setback > 0)\n cutRun('front', -marginL, w + marginR, -setback, gates.filter((g) => g.side === 'front'))\n cutRun('back', -marginL, w + marginR, d + backDepth, gates.filter((g) => g.side === 'back'))\n const vi = setback > 0 ? -setback : 0\n if (marginL > 0.5) seg('left', -marginL, vi, -marginL, d + backDepth)\n else if (backDepth > 0) seg('left', 0, d, 0, d + backDepth)\n if (marginR > 0.5) seg('right', w + marginR, vi, w + marginR, d + backDepth)\n else if (backDepth > 0) seg('right', w, d, w, d + backDepth)\n for (const z of ZONES) z.ground = (cfg.grounds || {})[z.id] || (cfg.grounds || {})[z.type] || pickWeighted(rLot, style.grounds[z.type] || { concrete: 1 })\n if (bc.zone) enforcePermeability(lot, ZONES, bc.zone, bc.adjustments || [])\n plan.zones = ZONES\n lot.zones = ZONES\n plan.lot = lot\n}\n\nexport { inRect, MARGIN }\n","import { clamp } from './geometry'\nimport { STREAM } from './legacy-seeds'\nimport { registries, resolveStyleId } from './registry'\nimport { createRng } from './rng'\nimport type { Rng } from './rng'\nimport type { Hsl } from './types'\n\nexport const HIGH_SATURATION = 0.4\nexport const MIN_WALL_FLOOR_CONTRAST = 20\nexport const MIN_FABRIC_FLOOR_CONTRAST = 15\n\nconst SCHEMES = ['analogous', 'complementary', 'split_complementary', 'triad'] as const\nconst HARMONY_OFFSETS: Record<string, [number, number]> = { analogous: [-30, 30], complementary: [180, 165], split_complementary: [150, 210], triad: [120, 240] }\n\n/** Roles the contrast rules rely on. A palette recipe must produce them. */\nexport const ROLE_FABRIC_MAIN = 'fabric_main'\nexport const ROLE_FABRIC_ACCENT = 'fabric_accent'\nexport const ROLE_FLOOR_REFERENCE = 'floor_living'\n\n/** Tools handed to a style recipe. `jit` and `rng` draw from the style's seeded stream: draw order is part of the contract. */\nexport interface PaletteDraw {\n rng: Rng\n base: [string, number, number, number]\n H0: number\n H1: number\n H2: number\n jit(v: number, a: number): number\n hsl(h: number, s: number, l: number): Hsl\n}\nexport interface PaletteEarly {\n /** Accent mode: true saturates walls, false puts accents on objects. */\n wallMode: boolean\n /** Maximum wall saturation. */\n sMax: number\n /** Facade, wall, gate, roof, ceiling... in insertion order. */\n roles: Record<string, Hsl>\n /** General floor `[h, s, l]` for room types that do not define their own. */\n generalFloor: [number, number, number]\n}\nexport interface PaletteStyleDef {\n /** Legacy stream suffix; defaults to the style id. */\n seedKey?: string\n /** Facade colour table `[labelKey, h, s, l]`. */\n facadeColors: [string, number, number, number][]\n /** Draws up to the room colours (before the room loop). */\n early(d: PaletteDraw): PaletteEarly\n /** Draws the object roles (wood, fabrics, metal, ground colours) after the room loop. */\n late(d: PaletteDraw, e: PaletteEarly): Record<string, Hsl>\n}\n\nexport interface PaletteContext extends PaletteDraw {\n style: string\n sMax: number\n wallMode: boolean\n generalFloor: [number, number, number]\n}\n\nexport const hslToInt = (h: number, s: number, l: number): number => {\n h = ((h % 360) + 360) % 360\n s = clamp(s, 0, 1)\n l = clamp(l, 0, 1)\n const a = s * Math.min(l, 1 - l)\n const f = (n: number) => {\n const k = (n + h / 30) % 12\n return l - a * Math.max(-1, Math.min(k - 3, 9 - k, 1))\n }\n return (Math.round(f(0) * 255) << 16) | (Math.round(f(8) * 255) << 8) | Math.round(f(4) * 255)\n}\nexport const intToHsl = (n: number): Hsl => {\n const r = ((n >> 16) & 255) / 255\n const g = ((n >> 8) & 255) / 255\n const b = (n & 255) / 255\n const mx = Math.max(r, g, b)\n const mn = Math.min(r, g, b)\n const l = (mx + mn) / 2\n const d = mx - mn\n let h = 0\n let s = 0\n if (d > 1e-9) {\n s = d / (1 - Math.abs(2 * l - 1))\n h = mx === r ? (g - b) / d + (g < b ? 6 : 0) : mx === g ? (b - r) / d + 2 : (r - g) / d + 4\n h *= 60\n }\n return { h, s, l }\n}\n/** CIE L* lightness of a packed RGB colour. */\nexport const lstar = (n: number): number => {\n const linear = (c: number) => ((c /= 255) <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4))\n const Y = 0.2126 * linear((n >> 16) & 255) + 0.7152 * linear((n >> 8) & 255) + 0.0722 * linear(n & 255)\n return Y > 216 / 24389 ? 116 * Math.cbrt(Y) - 16 : (Y * 24389) / 27\n}\nexport const hexString = (n: number): string => '#' + (n >>> 0).toString(16).padStart(6, '0')\n\nexport interface PaletteOptions {\n seed?: number | string\n style?: string\n state?: string\n}\nexport type Palette = { meta: { seed: number | string; style: string; state: string; scheme: string; base: string; accentMode: 'wall' | 'object' } } & Record<string, number | object>\n\n/** Seeded colour-harmony palette: a facade base colour, a harmony scheme, role colours and contrast rules. */\nexport function palette(o?: PaletteOptions): Palette {\n const opt = o || {}\n let style = resolveStyleId(opt.style || 'budget')\n if (!registries().PALETTE_STYLES[style]) style = registries().PALETTE_STYLES.mid ? 'mid' : Object.keys(registries().PALETTE_STYLES)[0]\n const def = registries().PALETTE_STYLES[style]\n const state = opt.state || 'normal'\n const seed = opt.seed == null ? 1 : opt.seed\n const rng = createRng(seed, STREAM.palettePrefix + (def.seedKey ?? style))\n const table = def.facadeColors\n const base = table[Math.floor(rng() * table.length)]\n const scheme = SCHEMES[Math.floor(rng() * 4)]\n const offsets = HARMONY_OFFSETS[scheme]\n const jit = (v: number, a: number) => v + (rng() - 0.5) * a\n const hsl = (h: number, s: number, l: number): Hsl => ({ h: ((h % 360) + 360) % 360, s: clamp(s, 0, 1), l: clamp(l, 0, 1) })\n const H0 = base[1]\n const H1 = H0 + offsets[0]\n const H2 = H0 + offsets[1]\n const draw: PaletteDraw = { rng, base, H0, H1, H2, jit, hsl }\n const early = def.early(draw)\n const { wallMode, sMax } = early\n const R: Record<string, Hsl> = Object.assign({}, early.roles)\n const ctx: PaletteContext = Object.assign({ style, sMax, wallMode, generalFloor: early.generalFloor }, draw)\n for (const c of registries().ROOM_COLORS) {\n const [wh, wl] = c.wall(ctx)\n R['wall_' + c.type] = hsl(wh, c.neutral ? Math.min(0.16, sMax) : clamp(jit(sMax * 0.75, sMax * 0.5), 0.03, sMax), jit(wl, 0.03))\n const pi = c.floor || early.generalFloor\n R['floor_' + c.type] = hsl(pi[0], Math.min(pi[1], wallMode ? 0.18 : 0.3), jit(pi[2], 0.04))\n }\n Object.assign(R, def.late(draw, early))\n // state hook (e.g. dirt: desaturate and darken)\n registries().STATE_PLUGINS[state]?.adjustPalette?.(R)\n // anti-clash rules: floor never saturated if the wall is; minimum lightness separation\n const adjust = (color: Hsl, ref: Hsl, min: number, preferredDir?: number) => {\n for (let i = 0; i < 60; i++) {\n if (Math.abs(lstar(hslToInt(color.h, color.s, color.l)) - lstar(hslToInt(ref.h, ref.s, ref.l))) >= min) return\n const refL = lstar(hslToInt(ref.h, ref.s, ref.l))\n let dir = preferredDir || (refL > 50 ? -1 : 1)\n if ((dir < 0 && color.l <= 0.06) || (dir > 0 && color.l >= 0.94)) dir = -dir\n color.l = clamp(color.l + dir * 0.015, 0.04, 0.96)\n }\n }\n const types = registries().ROOM_COLORS.map((c) => c.type)\n for (const c of types) {\n const w = R['wall_' + c]\n const p = R['floor_' + c]\n if (w.s > 0.3) p.s = Math.min(p.s, 0.2)\n if (p.s > HIGH_SATURATION) p.s = HIGH_SATURATION - 0.05\n adjust(p, w, MIN_WALL_FLOOR_CONTRAST + 2, lstar(hslToInt(w.h, w.s, w.l)) > 50 ? -1 : 1)\n }\n const floorRef = R[ROLE_FLOOR_REFERENCE] || R['floor_' + types[0]]\n const fabric = R[ROLE_FABRIC_MAIN]\n adjust(fabric, floorRef, MIN_FABRIC_FLOOR_CONTRAST + 3)\n adjust(R[ROLE_FABRIC_ACCENT], floorRef, MIN_FABRIC_FLOOR_CONTRAST + 3)\n for (const c of types) {\n const p = R['floor_' + c]\n if (Math.abs(lstar(hslToInt(fabric.h, fabric.s, fabric.l)) - lstar(hslToInt(p.h, p.s, p.l))) < MIN_FABRIC_FLOOR_CONTRAST)\n adjust(p, fabric, MIN_FABRIC_FLOOR_CONTRAST + 2, lstar(hslToInt(fabric.h, fabric.s, fabric.l)) > 50 ? -1 : 1)\n }\n const out: Record<string, unknown> = { meta: { seed, style, state, scheme, base: base[0], accentMode: wallMode ? 'wall' : 'object' } }\n for (const k of Object.keys(R)) out[k] = hslToInt(R[k].h, R[k].s, R[k].l)\n // final contrast after rounding: fabric against every floor; search lightness for floor (then wall) satisfying both rules\n const num = (k: string) => out[k] as number\n const pairOk = (w: number, p: number) => Math.abs(lstar(w) - lstar(p)) >= MIN_WALL_FLOOR_CONTRAST + 1 && Math.abs(lstar(num(ROLE_FABRIC_MAIN)) - lstar(p)) >= MIN_FABRIC_FLOOR_CONTRAST + 1\n const search = (color: number, ok: (n: number) => boolean) => {\n const h = intToHsl(color)\n let bestValue: number | null = null\n let md = 9\n for (let l = 0.02; l <= 0.98; l += 0.005) {\n const n = hslToInt(h.h, h.s, l)\n if (ok(n) && Math.abs(l - h.l) < md) {\n md = Math.abs(l - h.l)\n bestValue = n\n }\n }\n return bestValue\n }\n for (const c of types) {\n if (pairOk(num('wall_' + c), num('floor_' + c))) continue\n const n = search(num('floor_' + c), (p) => pairOk(num('wall_' + c), p))\n if (n != null) {\n out['floor_' + c] = n\n continue\n }\n // no solution with the floor alone: move the wall\n const w = search(num('wall_' + c), (w2) => pairOk(w2, num('floor_' + c)))\n if (w != null) out['wall_' + c] = w\n }\n return out as Palette\n}\n","import { EPS, MARGIN, TOL } from './constants'\nimport { cardinal, clamp, eq, extent, inner, overlaps, r2 } from './geometry'\nimport { registries } from './registry'\nimport { isOpenSide, openingsOfFloor, windowsOfRoom, zonesOfFloor } from './queries'\nimport type { Json, Plan, Rect, Room, Slot, SlotDef, Vec2 } from './types'\n\nconst SIDE_NORMAL: Record<string, Vec2> = { left: [1, 0], right: [-1, 0], front: [0, 1], back: [0, -1] }\nconst FIXED_FACING: Record<string, Vec2> = { 'u+': [1, 0], 'u-': [-1, 0], 'v+': [0, 1], 'v-': [0, -1] }\nconst SIDE_OPPOSITE: Record<string, string> = { front: 'back', back: 'front', left: 'right', right: 'left' }\nconst WINDOW_SIDE: Record<string, string> = { front: 'front', back: 'back', left: 'left', right: 'right' }\n\n/** Slot definitions of a room after `without`, `overrides`, `extras` and `any`/window expansion. */\nexport function slotDefsOf(plan: Plan, room: Room): SlotDef[] {\n const name = room.library || room.type\n const key = registries().LIBRARY_ALIAS[name] || name\n const library = room.slots ? room.slots : registries().LIBRARIES[key]\n if (!library) return []\n const R = inner(room.parts[0])\n let defs = typeof library === 'function' ? library({ w: R[2] - R[0], d: R[3] - R[1] }) : library.slice()\n defs = defs.map((x) => Object.assign({}, x))\n for (const id of room.without || []) defs = defs.filter((x) => x.id !== id)\n for (const [id, aj] of Object.entries(room.overrides || {})) {\n const i = defs.findIndex((x) => x.id === id)\n if (i < 0) continue\n if (aj === null) defs.splice(i, 1)\n else defs[i] = Object.assign(defs[i], aj)\n }\n defs.push(...(room.extras || []).map((x) => Object.assign({}, x)))\n const out: SlotDef[] = []\n for (const def of defs) {\n def.parent = def.on\n if (def.anchor === 'wall' && def.side === 'any') for (const l of ['left', 'right', 'front', 'back']) out.push(Object.assign({}, def, { id: def.id + '@' + l, side: l as SlotDef['side'], group: def.group || def.id }))\n else if (def.anchor === 'corner' && def.corner === 'any') for (const l of ['front-left', 'front-right', 'back-left', 'back-right']) out.push(Object.assign({}, def, { id: def.id + '@' + l, corner: l, group: def.group || def.id }))\n else if (def.anchor === 'window' && def.n == null) {\n const windowList = windowsOfRoom(plan, room)\n windowList.forEach((_j, i) => out.push(Object.assign({}, def, { id: def.id + '@w' + i, n: i, group: def.group || def.id })))\n } else out.push(def)\n }\n return out\n}\n\nexport function resolveSlots(plan: Plan): Slot[] {\n const all: Slot[] = []\n for (const room of plan.rooms.concat(plan.zones)) {\n const defs = slotDefsOf(plan, room)\n const byId: Record<string, Slot> = {}\n // stairs: a door on any storey applies\n const zones = room.type === 'stairs' ? plan.floors.flatMap((_, floorIndex) => zonesOfFloor(plan, floorIndex)) : zonesOfFloor(plan, room.floor)\n for (const def of defs) {\n const s = resolveSlot(plan, room, def, byId, zones)\n byId[def.id] = s\n all.push(s)\n }\n }\n return all\n}\n\nexport function resolveSlot(plan: Plan, room: Room, def: SlotDef, byId: Record<string, Slot>, zones: Rect[]): Slot {\n const base: Json = {\n id: def.id,\n room: room.id,\n floor: room.floor,\n outdoor: room.outdoor,\n anchor: def.anchor,\n side: def.side || def.corner || null,\n cats: def.cats,\n slide: def.slide,\n required: !!def.required,\n chance: def.required ? 1 : def.chance == null ? 1 : def.chance,\n clearance: def.clearance == null ? 0.5 : def.clearance,\n front: def.facing || 'center',\n group: def.group || null,\n requires: def.requires || null,\n on: def.parent || null,\n target: def.target || null,\n valid: true,\n reason: null,\n }\n const invalid = (m: string): Slot => Object.assign(base, { valid: false, reason: m, x: 0, z: 0, ry: 0, w: 0, d: 0, frontU: 0, frontV: 1, aabb: [0, 0, 0, 0], _cell: null }) as Slot\n if (def.anchor === 'on' || def.anchor === 'inside') {\n const parent = byId[def.parent]\n if (!parent || !parent.valid) return invalid('invalid_parent')\n return Object.assign(base, { x: parent.x, z: parent.z, ry: parent.ry, w: parent.w, d: parent.d, frontU: parent.frontU, frontV: parent.frontV, aabb: parent.aabb, _cell: parent._cell }) as Slot\n }\n const size = def.size as Vec2\n const roomCenter = ((): Vec2 => {\n const R0 = inner(room.parts[0])\n return [(R0[0] + R0[2]) / 2, (R0[1] + R0[3]) / 2]\n })()\n const openings = openingsOfFloor(plan, room.floor)\n let point: Vec2 = [0, 0]\n const targetPoint = (rule: string): Vec2 => {\n if (rule === 'door') {\n let best: Json = null\n let bestDist = 1e9\n for (const ab of openings) {\n const dist = Math.hypot(ab.u - point[0], ab.v - point[1])\n if (dist < bestDist) {\n bestDist = dist\n best = ab\n }\n }\n return best ? [best.u, best.v] : roomCenter\n }\n if (rule === 'target') {\n const t = byId[def.target as string]\n return t && t.valid ? [t.x, t.z] : roomCenter\n }\n return roomCenter\n }\n const free = (rect: Rect) => !!def.floorFree || !zones.some((z) => overlaps(rect, z, room.type === 'stairs' ? -0.011 : EPS))\n const rule: string = def.facing || 'center'\n let R = inner(room.parts[Math.min(def.part || 0, room.parts.length - 1)])\n if (def.anchor === 'wall' || def.anchor === 'window') {\n let side = def.side as string\n let a: number | null = null\n let win: Json = null\n if (def.anchor === 'window') {\n const windowList = windowsOfRoom(plan, room)\n win = windowList[def.n as number]\n if (!win) return invalid('no_window')\n side = room.outdoor ? SIDE_OPPOSITE[win.side] : WINDOW_SIDE[win.side]\n const cand = room.parts\n .map(inner)\n .find(\n (r) =>\n (win.axis === 'u' ? win.u >= r[0] - TOL && win.u <= r[2] + TOL : win.v >= r[1] - TOL && win.v <= r[3] + TOL) &&\n ((side === 'left' && eq(r[0], win.pos + MARGIN)) || (side === 'right' && eq(r[2], win.pos - MARGIN)) || (side === 'front' && eq(r[1], win.pos + MARGIN)) || (side === 'back' && eq(r[3], win.pos - MARGIN))),\n )\n if (!cand) return invalid('window_outside_room')\n R = cand\n a = win.axis === 'u' ? win.u : win.v\n }\n const n = SIDE_NORMAL[side]\n if (!n) return invalid('invalid_side')\n const horizontal = side === 'front' || side === 'back'\n const a0 = horizontal ? R[0] : R[1]\n const a1 = horizontal ? R[2] : R[3]\n const len = a1 - a0\n const depth = size[1]\n if (depth > (horizontal ? R[3] - R[1] : R[2] - R[0]) + EPS) return invalid('larger_than_room')\n const hw = Math.min(size[0], len) / 2\n const cell = (ac: number): Rect =>\n side === 'left' ? [R[0], ac - hw, R[0] + depth, ac + hw] : side === 'right' ? [R[2] - depth, ac - hw, R[2], ac + hw] : side === 'front' ? [ac - hw, R[1], ac + hw, R[1] + depth] : [ac - hw, R[3] - depth, ac + hw, R[3]]\n const nominal = a != null ? a : a0 + hw + (def.pos == null ? 0.5 : def.pos) * Math.max(0, len - 2 * hw) + (def.shift || 0)\n const wp = side === 'left' ? R[0] - MARGIN : side === 'right' ? R[2] + MARGIN : side === 'front' ? R[1] - MARGIN : R[3] + MARGIN\n const pa = clamp(nominal, a0 + hw, a1 - hw)\n let found: number | null = null\n const steps = [0]\n if (def.anchor !== 'window') for (let k = 1; k <= 60; k++) steps.push(k, -k)\n for (const k of steps) {\n const ac = pa + k * 0.05\n if (ac - hw < a0 - EPS || ac + hw > a1 + EPS) continue\n if (free(cell(ac))) {\n found = ac\n break\n }\n }\n if (found == null) return invalid('blocked_by_door')\n const sp: Vec2 = horizontal ? [found, wp - n[1] * 0.1] : [wp - n[0] * 0.1, found]\n if (isOpenSide(plan, room, sp[0], sp[1])) return invalid('open_wall')\n const rect = cell(found)\n return Object.assign(base, { side, x: r2((rect[0] + rect[2]) / 2), z: r2((rect[1] + rect[3]) / 2), frontU: n[0], frontV: n[1], ry: r2(Math.atan2(n[0], n[1])), w: size[0], d: size[1], aabb: rect.map(r2), _cell: { rect, f: n, enclosed: [side], R, size } }) as Slot\n }\n if (def.anchor === 'corner') {\n const [cornerV, cornerU] = (def.corner as string).split('-')\n const normalV = SIDE_NORMAL[cornerV]\n const normalU = SIDE_NORMAL[cornerU]\n if (!normalV || !normalU) return invalid('invalid_corner')\n const kx = cornerU === 'left' ? R[0] : R[2]\n const kz = cornerV === 'front' ? R[1] : R[3]\n point = [kx, kz]\n let f: Vec2\n if (FIXED_FACING[rule]) {\n f = FIXED_FACING[rule]\n if (!((f[0] === normalU[0] && f[1] === normalU[1]) || (f[0] === normalV[0] && f[1] === normalV[1]))) f = normalU\n } else {\n const t = targetPoint(rule)\n f = Math.abs(t[0] - kx) >= Math.abs(t[1] - kz) ? normalU : normalV\n }\n const [extentU, extentV] = extent(size, f)\n if (extentU > R[2] - R[0] + EPS || extentV > R[3] - R[1] + EPS) return invalid('larger_than_room')\n const rect: Rect = [cornerU === 'left' ? R[0] : R[2] - extentU, cornerV === 'front' ? R[1] : R[3] - extentV, cornerU === 'left' ? R[0] + extentU : R[2], cornerV === 'front' ? R[1] + extentV : R[3]]\n if (!free(rect)) return invalid('blocked_by_door')\n for (const sp of [[kx - normalU[0] * (MARGIN + 0.1), (rect[1] + rect[3]) / 2], [(rect[0] + rect[2]) / 2, kz - normalV[1] * (MARGIN + 0.1)]]) if (isOpenSide(plan, room, sp[0], sp[1])) return invalid('open_wall')\n return Object.assign(base, { x: r2((rect[0] + rect[2]) / 2), z: r2((rect[1] + rect[3]) / 2), frontU: f[0], frontV: f[1], ry: r2(Math.atan2(f[0], f[1])), w: size[0], d: size[1], aabb: rect.map(r2), _cell: { rect, f, enclosed: [cornerU, cornerV], R, size } }) as Slot\n }\n if (def.anchor === 'center') {\n let cx = R[0] + (def.fx == null ? 0.5 : def.fx) * (R[2] - R[0]) + (def.dx || 0)\n let cz = R[1] + (def.fz == null ? 0.5 : def.fz) * (R[3] - R[1]) + (def.dz || 0)\n point = [cx, cz]\n let f: Vec2\n if (FIXED_FACING[rule]) f = FIXED_FACING[rule]\n else {\n const t = targetPoint(rule)\n const dx = t[0] - cx\n const dz = t[1] - cz\n f = Math.hypot(dx, dz) < 0.05 ? [0, 1] : cardinal(dx, dz)\n }\n const [extentU, extentV] = extent(size, f)\n if (extentU > R[2] - R[0] + EPS || extentV > R[3] - R[1] + EPS) return invalid('larger_than_room')\n cx = clamp(cx, R[0] + extentU / 2, R[2] - extentU / 2)\n cz = clamp(cz, R[1] + extentV / 2, R[3] - extentV / 2)\n const rect: Rect = [cx - extentU / 2, cz - extentV / 2, cx + extentU / 2, cz + extentV / 2]\n if (!free(rect)) return invalid('blocked_by_door')\n return Object.assign(base, { x: r2(cx), z: r2(cz), frontU: f[0], frontV: f[1], ry: r2(Math.atan2(f[0], f[1])), w: size[0], d: size[1], aabb: rect.map(r2), _cell: { rect, f, enclosed: [], R, size } }) as Slot\n }\n return invalid('unknown_anchor')\n}\n","import { DOOR_CLEARANCE } from './constants'\nimport { createPlacementContext, placementKit, runPostProcess } from './context'\nimport { runResultExtensions } from './extensions'\nimport { fillRoom } from './fill'\nimport { overlaps, openingZones, r2 } from './geometry'\nimport { STREAM } from './legacy-seeds'\nimport { translate } from './locale'\nimport { buildPlan, floorsOf } from './plan'\nimport { hexString, palette } from './palette'\nimport { registries } from './registry'\nimport { createRng, hashString } from './rng'\nimport { resolveSlots } from './slots'\nimport { checkLot, clampOptionsToZone, resolveZone, useOf } from './zoning'\nimport type { FloorplanOptions, ItemColor, Json, PlacedItem, Plan, Slot, TemplateDef, ZoneAdjustment } from './types'\nimport type { StateContext } from './types'\n\nexport function templateOf(t: string | TemplateDef): TemplateDef {\n if (typeof t === 'string') {\n if (!registries().TEMPLATES[t]) throw new Error('Unknown template: ' + t)\n return registries().TEMPLATES[t]\n }\n return t\n}\n\nconst cleanSlot = (s: Slot) => {\n const o: Json = {}\n for (const k of Object.keys(s)) if (k[0] !== '_') o[k] = s[k]\n o.cats = Object.keys(s.cats || {})\n return o\n}\n\n/** Recorded slots (resolved positions) of every storey and of the lot. */\nexport function slots(template: string | TemplateDef, options?: FloorplanOptions): Json[] {\n const tpl = templateOf(template)\n const o = options || {}\n const plan = buildPlan(tpl, o.w, o.d, o)\n const locale = o.locale || 'en'\n return resolveSlots(plan)\n .map(cleanSlot)\n .map((s) => (s.reason ? Object.assign(s, { reason: translate('reasons', s.reason, locale) }) : s))\n}\n\n/** Picks the house state: the requested one, else a seeded draw over the registered distribution, else `normal`. */\nexport function pickState(requested: string | undefined, seed: number | string): string {\n if (requested && registries().STATE_PLUGINS[requested]) return requested\n const dist = registries().stateDistribution.weights\n if (!dist) return 'normal'\n const x = createRng(seed, registries().stateDistribution.seedKey)()\n let acc = 0\n const keys = Object.keys(dist)\n for (const k of keys) {\n acc += dist[k]\n if (x < acc) return k\n }\n return keys[keys.length - 1]\n}\n\nfunction colorOf(m: Json, seed: number | string): number | string {\n const spec: ItemColor = m.colorSpec || registries().CATALOG[m.type]?.color || { role: 'wood' }\n if ('role' in spec) return spec.role\n if ('hex' in spec) return spec.hex\n return spec.pick[hashString(seed + '|' + (m._seedId ?? m.id)) % spec.pick.length]\n}\n\nfunction applyState(plan: Plan, items: PlacedItem[], ctx: ReturnType<typeof createPlacementContext>, seed: number | string, state: string): PlacedItem[] {\n const plugin = registries().STATE_PLUGINS[state]\n if (!plugin || state === 'normal') return []\n const c: StateContext = {\n plan,\n items,\n seed,\n state,\n rng: createRng(seed, plugin.seedKey ?? 'state:' + state),\n ctx,\n kit: placementKit,\n catalog: registries().CATALOG,\n wallTopHeights: registries().WALL_TOP_HEIGHTS,\n }\n return plugin.apply(c)\n}\n\nconst loc = (key: string | undefined, locale: string, ns: 'labels' | 'facadeColors' = 'labels', vars?: Record<string, string | number>) => (key ? translate(ns, key, locale, vars) : key)\n\n/** Generates a plan: building, lot, seeded item fill, decor, house state and palette. */\nexport function generate(template: string | TemplateDef, options?: FloorplanOptions): Json {\n const tpl = templateOf(template)\n const o = options || {}\n const seed = o.seed == null ? 1 : o.seed\n const locale = o.locale || 'en'\n let op: FloorplanOptions = Object.assign({}, o, { seed })\n const zone = resolveZone(o.zone)\n const adjustments: ZoneAdjustment[] = []\n if (zone) op = clampOptionsToZone(tpl, op, zone, adjustments)\n const plan = buildPlan(tpl, op.w, op.d, op, { zone, adjustments })\n const all = resolveSlots(plan)\n const items: PlacedItem[] = []\n const missing: { room: string; slot: string }[] = []\n for (const room of plan.rooms.concat(plan.zones)) {\n const sl = all.filter((s) => s.room === room.id && s.floor === room.floor)\n const r = fillRoom(plan, room, sl, createRng(seed, STREAM.roomPrefix + (room.seedKey ?? registries().SEED_KEYS.rooms[room.id] ?? room.id)))\n items.push(...r.items)\n missing.push(...r.missing)\n }\n const ctx = runPostProcess(plan, items, seed)\n const state = pickState(o.state, seed)\n const stateItemsAll = applyState(plan, items, ctx, seed, state)\n const colors = palette({ seed, style: plan.style, state })\n const strip = (m: Json) => {\n const x: Json = {}\n for (const k of Object.keys(m)) if (k[0] !== '_' && k !== 'colorSpec') x[k] = m[k]\n return x\n }\n const L = plan.lot\n const lot = L\n ? {\n rect: L.rect.map(r2),\n setback: r2(L.setback),\n backyard: r2(L.backyard),\n sideYard: L.sideYard,\n style: L.style,\n pool: L.pool,\n zones: plan.zones.map((z) => ({ id: z.id, type: z.type, label: z.label, name: loc(z.label, locale), parts: z.parts, ground: z.ground })),\n perimeter: L.perimeter.map((s: Json) => Object.assign({ color: 'wall' }, s)),\n gates: plan.gates.map((g) => ({ id: g.id, type: g.type, model: g.model, u: g.u, v: g.v, axis: g.axis, width: g.width, height: g.height, side: g.side, to: g.to, material: g.material, open: !!g.open, color: 'gate' })),\n paths: plan.paths.map((c) => ({ id: c.id, type: c.type, from: c.from, to: c.to, width: c.width, rects: c.rects, points: c.points })),\n }\n : null\n const facade = Object.assign({}, plan.facade, {\n color: { name: loc(colors.meta.base, locale, 'facadeColors'), key: colors.meta.base, hex: hexString(colors.facade as number) },\n roles: { facade: 'facade', detail: 'facade_detail', roof: 'roof', wall: 'wall', gate: 'gate' },\n })\n const itemsOut = items.map((m) => {\n const out = strip(m)\n out.color = colorOf(m, seed)\n return out\n })\n const stateItemsOut = stateItemsAll.map((m) => {\n const out = strip(m)\n if (m.category) out.color = colorOf(m, seed)\n return out\n })\n const result: Json = {\n template: tpl.id,\n name: translate('templates', tpl.id, locale),\n use: useOf(tpl),\n seed,\n style: plan.style,\n state,\n w: plan.w,\n d: plan.d,\n floors: plan.floors.map((f) => ({ index: f.index, label: f.name, name: f.number != null ? translate('labels', 'floor_n', locale, { n: f.number }) : loc(f.name, locale), number: f.number, y0: f.y0, ceiling: f.ceiling })),\n rooms: plan.rooms.map((c) => ({\n id: c.id,\n type: c.type,\n label: c.label,\n name: loc(c.label, locale),\n floor: c.floor,\n u0: c.parts[0][0],\n v0: c.parts[0][1],\n u1: c.parts[0][2],\n v1: c.parts[0][3],\n parts: c.parts,\n link: c.link,\n ceiling: c.ceiling || plan.floors[c.floor].ceiling,\n color: { wall: 'wall_' + c.type, floor: 'floor_' + c.type },\n })),\n walls: plan.walls,\n doors: plan.doors,\n windows: plan.windows,\n openPairs: ([] as Json[]).concat(...Object.values(plan.openPairs)),\n facade,\n lot,\n items: itemsOut,\n stateItems: stateItemsOut,\n colors,\n building: tpl.building ? tpl.building(plan.w, plan.d, op) : null,\n missing,\n }\n if (tpl.singleFloor) result.floorNumber = op.floor || 3\n result.partyWalls = tpl.partyWalls || []\n if (plan.config) result.config = plan.config\n runResultExtensions(plan, result, seed, op)\n if (zone) {\n const report = { zone: zone.id, adjustments, violations: checkLot(zone, lot, Object.assign({}, result, { rooms: plan.rooms })) }\n result.zoning = report\n }\n return result\n}\n\nconst isSolid = (m: Json) => !m.flat && !m.on && (!m.decor || m.mount === 'floor')\n\n/** Validates a result of `generate`; returns a list of messages (empty when valid). */\nexport function validate(result: Json, options?: { locale?: string }): string[] {\n const locale = options?.locale || result.locale || 'en'\n const t = (key: string, vars: Record<string, string | number>) => translate('messages', key, locale, vars)\n const errors: string[] = []\n const solids: Json[] = result.items.filter(isSolid)\n for (let i = 0; i < solids.length; i++)\n for (let j = i + 1; j < solids.length; j++)\n if (solids[i].floor === solids[j].floor && !solids[i].barricade && !solids[j].barricade && overlaps(solids[i].aabb, solids[j].aabb, 0.011)) errors.push(t('overlap', { a: solids[i].id, b: solids[j].id }))\n for (const m of solids) {\n if (m.barricade) continue\n for (const p of result.doors) if (p.floor === (m.outdoor ? 0 : m.floor) && p.zones.some((z: Json) => overlaps(m.aabb, z, 0.011))) errors.push(t('door_blocked', { id: m.id }))\n if (result.lot) for (const g of result.lot.gates) if (m.outdoor && openingZones(g.u, g.v, 'u', g.width, DOOR_CLEARANCE).some((z) => overlaps(m.aabb, z, 0.011))) errors.push(t('gate_blocked', { id: m.id }))\n }\n for (const f of result.missing) errors.push(t('missing_required', { room: f.room, slot: f.slot }))\n if (result.zoning) for (const v of result.zoning.violations) errors.push(t('zone_violation', { zone: result.zoning.zone, rule: v.rule, actual: v.actual, limit: v.limit }))\n return errors\n}\n\n/** Size limits and default size of a template (they can depend on options such as `tier`). */\nexport function limitsOf(template: string | TemplateDef, options?: FloorplanOptions) {\n const tpl = templateOf(template)\n const op = options || {}\n return { limits: tpl.limitsFn ? tpl.limitsFn(op) : tpl.limits, defaults: tpl.defaultsFn ? tpl.defaultsFn(op) : tpl.defaults }\n}\n\nexport function listTemplates(locale = 'en') {\n return Object.values(registries().TEMPLATES).map((t) => {\n const a = floorsOf(t, {})\n return {\n id: t.id,\n name: translate('templates', t.id, locale),\n use: useOf(t),\n style: typeof t.style === 'function' ? t.style({}) : t.style,\n limits: t.limits,\n defaults: t.defaults,\n floors: a.length,\n floorRange: t.floorRange || null,\n lot: !!t.lot,\n options: t.options || {},\n }\n })\n}\n\n","import type { Vec3 } from './destruction'\n\n/**\n * The numbers of the shove a blast gives to a body that moves (a loose item, a piece of furniture, a person): all of them a game value, with a default that reads well in a room,\n * not a physical table. A host reads them once and lends them to the modules that move their own bodies (`ModuleHost.blastShove`).\n */\nexport interface BlastShoveOptions {\n /**\n * The share of the blast energy that reaches a body as motion: the speed at the centre is `sqrt(2 * energy * coupling / mass)`, before the falloff (default 0.02).\n */\n readonly coupling?: number\n /** Fastest a body is thrown, in m/s, at the centre of the blast (default 20). */\n readonly maxSpeed?: number\n /** How much of the push goes up: the direction is `(away, lift)` normalised from the horizontal outward direction (default 0.3). */\n readonly lift?: number\n /** Below this speed (m/s) nothing moves: a heavy thing far from a small blast stays where it is (default 0.3). */\n readonly minSpeed?: number\n /** Exponent of the falloff `(1 - distance / radius) ^ power`, the same as the damage of the destruction world (default 2). */\n readonly falloffPower?: number\n}\n\n/** The defaults of `BlastShoveOptions`. */\nexport const DEFAULT_BLAST_SHOVE: Readonly<Required<BlastShoveOptions>> = { coupling: 0.02, maxSpeed: 20, lift: 0.3, minSpeed: 0.3, falloffPower: 2 }\n\n/** A blast as the shove reads it: where, how much energy (J) and how far it reaches (m). `reach` (0..1) is the share that got through what stood in the way. */\nexport interface BlastSource {\n readonly point: Vec3\n readonly energy: number\n readonly radius: number\n readonly reach?: number\n}\n\n/** What a blast does to one body: how fast it leaves (m/s), the unit direction it leaves in, and how far from the centre it was. */\nexport interface BlastShove {\n readonly speed: number\n readonly direction: Vec3\n readonly distance: number\n /** The falloff applied, 0..1. */\n readonly falloff: number\n}\n\n/**\n * The shove a blast gives to a body of `mass` kg whose centre is at `position`: away from the centre, lifted a little, with the speed\n * `min(maxSpeed, sqrt(2 * energy * reach * coupling / mass)) * (1 - distance / radius) ^ 2`. Undefined when the body is outside the radius or the speed is under `minSpeed`.\n * The same rule moves the loose items and furniture of the test room and the people of the characters module, so a game that tunes the options tunes all of them.\n */\nexport function blastShove(blast: BlastSource, target: { readonly position: Vec3; readonly mass: number }, options: BlastShoveOptions = {}): BlastShove | undefined {\n const o = { ...DEFAULT_BLAST_SHOVE, ...options }\n const dx = target.position[0] - blast.point[0]\n const dy = target.position[1] - blast.point[1]\n const dz = target.position[2] - blast.point[2]\n const distance = Math.hypot(dx, dy, dz)\n if (!(blast.radius > 0) || distance > blast.radius) return undefined\n const falloff = (1 - distance / blast.radius) ** o.falloffPower\n const mass = Math.max(target.mass, 0.05)\n const speed = Math.min(o.maxSpeed, Math.sqrt((2 * blast.energy * (blast.reach ?? 1) * o.coupling) / mass)) * falloff\n if (!(speed >= o.minSpeed)) return undefined\n // straight above or below the centre there is no \"away\": the push goes up\n const direction: Vec3 = distance > 1e-4 ? [dx / distance, dy / distance + o.lift, dz / distance] : [0, 1, 0]\n const length = Math.hypot(direction[0], direction[1], direction[2])\n return { speed, direction: [direction[0] / length, direction[1] / length, direction[2] / length], distance, falloff }\n}\n","export interface CostOptions {\n /** Reads of `state()` and of `describe()` to time. Default 10 000. */\n reads?: number\n /** Ceiling, in milliseconds, for all the reads of one method. Default 50 (5 microseconds per read). */\n ceilingMs?: number\n /** Ceiling of heap growth, in bytes, over all the reads of one method (only where `process.memoryUsage` exists). Default 1 MiB. */\n allocationBytes?: number\n}\n\nconst DEFAULT_COST_READS = 10_000\nconst DEFAULT_COST_CEILING_MS = 50\nconst DEFAULT_COST_ALLOCATION_BYTES = 1024 * 1024\n\nconst heapUsedBytes = (): number | undefined => {\n const nodeProcess = (globalThis as { process?: { memoryUsage?: () => { heapUsed: number } } }).process\n return nodeProcess?.memoryUsage?.().heapUsed\n}\n\ntype CheckReadCostParams = { readonly name: string; readonly read: () => unknown; readonly options: CostOptions; readonly problems: string[] }\n\nexport const checkReadCost = ({ name, read, options, problems }: CheckReadCostParams): void => {\n const reads = options.reads ?? DEFAULT_COST_READS\n const ceilingMs = options.ceilingMs ?? DEFAULT_COST_CEILING_MS\n const allocationBytes = options.allocationBytes ?? DEFAULT_COST_ALLOCATION_BYTES\n if (read() !== read()) problems.push(`${name}() returns a new object on each read: cache it between changes (cost contract)`)\n // a first pass lets the engine compile and optimise the loop: that code and its feedback are heap too, and would read as the method allocating\n for (let i = 0; i < reads; i++) read()\n const heapBefore = heapUsedBytes()\n const started = performance.now()\n for (let i = 0; i < reads; i++) read()\n const elapsedMs = performance.now() - started\n const heapAfter = heapUsedBytes()\n if (elapsedMs > ceilingMs) problems.push(`${name}() took ${elapsedMs.toFixed(1)} ms for ${reads} reads, over the ${ceilingMs} ms ceiling (cost contract)`)\n if (heapBefore !== undefined && heapAfter !== undefined && heapAfter - heapBefore > allocationBytes)\n problems.push(`${name}() grew the heap by ${heapAfter - heapBefore} bytes over ${reads} reads, over the ${allocationBytes} byte ceiling (cost contract)`)\n}\n","import { checkReadCost } from './impact-cost'\nimport type { CostOptions } from './impact-cost'\nimport type { DamageType, DestructibleSpec, DestructionEvent, Hit, JointSpec, ObjectState, ToolKind, Vec3 } from './destruction'\n\n/**\n * What a game module implements for an object whose behaviour it owns (a vehicle with its own panel deformation, a creature, a machine). The\n * world (`DestructionWorld.register`) hosts it next to its own objects: raycast, shoot, explode, hit, disassemble, extinguish, update, state,\n * reset and `on` all route to it.\n *\n * Space: the impl receives hits in WORLD space and returns events in WORLD space (it owns its transform; the transform given to `register` or\n * `setTransform` is only used by the world for raycasts and blast range). Every event must carry `object === id` and name parts listed by\n * `describe()`.\n */\n/** World-space ray for `DestructibleImpl.surfaceRay`. */\nexport interface SurfaceRay {\n readonly origin: Vec3\n readonly direction: Vec3\n readonly maxDistance: number\n ignored?(part: string): boolean\n}\n\nexport interface SurfaceRayHit {\n readonly part: string\n readonly point: Vec3\n readonly normal: Vec3\n readonly distance: number\n /** Thickness the ray crosses in this part, metres. */\n readonly pathLen: number\n}\n\nexport interface DestructibleImpl {\n readonly id: string\n readonly name?: string\n /**\n * Parts, joints and structure in the impl's local space, for raycast, inspector and log.\n * COST CONTRACT (D8): called per frame by the renderer, so it is O(1), allocation-free and cached between changes: the same object comes\n * back until a hit, tool, fire or pose change alters it. `checkDestructible(impl, { cost: true })` measures it.\n */\n describe(): DestructibleSpec\n /** Apply one hit (see `IMPACT_CONTRACT` for the fields per type) and return the events it caused. */\n hit(hit: Hit): DestructionEvent[]\n /**\n * The real surface a ray meets, for an impl whose drawn shape is not its boxes (a car body): the boxes of `describe()` only say where to look, and a shot that crosses\n * them without touching the drawn surface goes on. `ignored` answers for the parts the round already went through. Null when the ray meets nothing.\n */\n surfaceRay?(ray: SurfaceRay): SurfaceRayHit | null\n /** Advance fire, melting, collapse and other timed behaviour. */\n update?(dt: number): DestructionEvent[]\n /**\n * COST CONTRACT (D8): the host reads it per part per frame, so it is O(1), allocation-free and cached between changes (see `describe()`).\n * The cached object is shared with every reader: treat it as read-only, copy before changing it.\n */\n state(): Readonly<ObjectState>\n reset?(): void\n /** The world took the object out (`DestructionWorld.remove`): the impl lets go of what it joined (shared queues, listeners). */\n dispose?(): void\n /** Same contract as `DestructionWorld.disassemble`: progress 0..1, or -1 when the tool cannot undo the joint. */\n disassemble?(jointId: string, tool: ToolKind, dt: number): number\n extinguish?(partId?: string): void\n /** Optional: an animation moved a part; `position` / `rotation` (Euler XYZ, radians) are object-local. Keep raycast and hit shapes in sync. */\n setPartPose?(partId: string, position: Vec3, rotation?: Vec3): void\n /** Plain JSON of the impl's own state, stored in `DestructionSnapshot.impls`. */\n serialize?(): unknown\n load?(data: unknown): void\n}\n\n/** The fields a weapon or hazard must put in a `Hit`, per damage type. THE impact contract. */\nexport interface ImpactContract {\n required: string[]\n optional: string[]\n note: string\n}\n\nexport const IMPACT_CONTRACT: Record<DamageType, ImpactContract> = {\n ballistic: { required: ['type', 'point', 'direction', 'energy', 'caliber'], optional: ['space', 'source'], note: 'bullets and pellets: joules and diameter in millimetres' },\n blunt: { required: ['type', 'point', 'energy'], optional: ['direction', 'radius', 'space', 'source'], note: 'contact radius in metres (default 3 cm)' },\n slash: { required: ['type', 'point', 'energy'], optional: ['direction', 'radius', 'space', 'source'], note: 'axes, knives, machetes' },\n explosive: { required: ['type', 'point', 'energy', 'radius'], optional: ['lethalRadius', 'space', 'source'], note: 'point is the centre of the blast, radius the range in metres' },\n fire: { required: ['type', 'point', 'temperature', 'radius'], optional: ['duration', 'space', 'source'], note: 'flame temperature in °C; duration in seconds (call every frame with `dt`)' },\n heat: { required: ['type', 'point', 'temperature', 'radius'], optional: ['duration', 'space', 'source'], note: 'heat without flame (cutting torch, hot plate)' },\n}\n\n/** Problems with a hit according to the impact contract (empty when it is valid). */\nexport const checkHit = (hit: Hit): string[] => {\n const c = IMPACT_CONTRACT[hit.type]\n if (!c) return [`unknown damage type \"${String(hit.type)}\"`]\n const out: string[] = []\n for (const f of c.required) {\n const v = (hit as unknown as Record<string, unknown>)[f]\n if (v === undefined || (Array.isArray(v) ? v.some((n) => !Number.isFinite(n)) : typeof v === 'number' && !Number.isFinite(v))) out.push(`${hit.type} hit needs \"${f}\"`)\n }\n return out\n}\n\nexport interface CheckOptions {\n /**\n * Ids of every material the impl may use (the contracts package does not know the materials of your world: pass the ids of\n * `world.materials`, or the built-in plus your own). When omitted, the material check is skipped.\n */\n materials?: Iterable<string>\n /** Opt-in cost measurement (D8): `true` for the defaults, or the limits to use. */\n cost?: boolean | CostOptions\n}\n\nconst finiteJson = (v: unknown, path: string, out: string[]) => {\n if (typeof v === 'number') {\n if (!Number.isFinite(v)) out.push(`${path} is not a finite number`)\n } else if (Array.isArray(v)) v.forEach((x, i) => finiteJson(x, `${path}[${i}]`, out))\n else if (v && typeof v === 'object') for (const [k, x] of Object.entries(v)) finiteJson(x, `${path}.${k}`, out)\n else if (typeof v === 'function' || typeof v === 'symbol' || typeof v === 'bigint') out.push(`${path} is not JSON`)\n}\n\n/**\n * Contract checker for the test room (it needs no world): `describe()` is valid, a 500 J ballistic hit at a part centre returns well-formed events of this impl, `state()`\n * matches `describe()`, hit points never go negative, `update(0.016)` returns an array and every event is JSON-serializable. It hits the impl\n * (and calls `reset()` afterwards when there is one). With `options.cost` it also times `state()` and `describe()` (the cost contract of D8).\n */\nexport const checkDestructible = (impl: DestructibleImpl, options: CheckOptions = {}): { ok: boolean; problems: string[] } => {\n const problems: string[] = []\n const known = options.materials ? new Set(options.materials) : null\n let spec: DestructibleSpec | undefined\n try {\n spec = impl.describe()\n } catch (e) {\n return { ok: false, problems: [`describe() threw: ${String(e)}`] }\n }\n if (!spec || !Array.isArray(spec.parts) || spec.parts.length === 0) return { ok: false, problems: ['describe() must return at least one part'] }\n const ids = new Set<string>()\n for (const p of spec.parts) {\n if (ids.has(p.id)) problems.push(`duplicate part id \"${p.id}\"`)\n ids.add(p.id)\n if (known && !known.has(p.material)) problems.push(`part \"${p.id}\" has unknown material \"${p.material}\"`)\n if (!p.shape || !['box', 'cylinder', 'sphere'].includes(p.shape.kind)) problems.push(`part \"${p.id}\" has no valid shape`)\n if (!Array.isArray(p.position) || p.position.length !== 3) problems.push(`part \"${p.id}\" has no position`)\n }\n const jointIds = new Set<string>()\n for (const j of (spec.joints ?? []) as JointSpec[]) {\n if (!ids.has(j.a) || !ids.has(j.b)) problems.push(`joint \"${j.id ?? `${j.a}~${j.b}`}\" references an unknown part`)\n const jid = j.id ?? `${j.a}~${j.b}`\n if (jointIds.has(jid)) problems.push(`duplicate joint id \"${jid}\"`)\n jointIds.add(jid)\n }\n const checkState = (label: string) => {\n let st: ObjectState\n try {\n st = impl.state()\n } catch (e) {\n problems.push(`state() threw ${label}: ${String(e)}`)\n return\n }\n const sids = st.parts.map((p) => p.id).sort().join(',')\n if (sids !== [...ids].sort().join(',')) problems.push(`state() part ids do not match describe() ${label}`)\n for (const p of st.parts) if (!(p.hp >= 0)) problems.push(`part \"${p.id}\" has negative or invalid hp ${label}`)\n }\n const checkEvents = (events: unknown, label: string) => {\n if (!Array.isArray(events)) {\n problems.push(`${label} must return an array`)\n return\n }\n const evs = events as DestructionEvent[]\n evs.forEach((e, i) => {\n if (e.object !== impl.id) problems.push(`${label} event ${i} (${e.type}) has object \"${String(e.object)}\", expected \"${impl.id}\"`)\n const part = (e as { part?: string }).part\n if (part !== undefined && !ids.has(part)) problems.push(`${label} event ${i} (${e.type}) names unknown part \"${part}\"`)\n })\n const bad: string[] = []\n finiteJson(evs, 'events', bad)\n problems.push(...bad.map((b) => `${label}: ${b}`))\n try {\n const s = JSON.stringify(evs)\n if (JSON.stringify(JSON.parse(s)) !== s) problems.push(`${label} events do not survive a JSON round trip`)\n } catch (e) {\n problems.push(`${label} events are not JSON-serializable: ${String(e)}`)\n }\n }\n checkState('before the hit')\n const target = spec.parts[0]\n try {\n const hit: Hit = { type: 'ballistic', point: [target.position[0], target.position[1], target.position[2]], direction: [0, 0, -1], energy: 500, caliber: 9 }\n checkEvents(impl.hit(hit), 'hit()')\n } catch (e) {\n problems.push(`hit() threw: ${String(e)}`)\n }\n checkState('after the hit')\n if (impl.update) {\n try {\n checkEvents(impl.update(0.016), 'update()')\n } catch (e) {\n problems.push(`update() threw: ${String(e)}`)\n }\n checkState('after update')\n }\n try {\n impl.reset?.()\n } catch (e) {\n problems.push(`reset() threw: ${String(e)}`)\n }\n if (options.cost) {\n const cost = options.cost === true ? {} : options.cost\n try {\n checkReadCost({ name: 'state', read: () => impl.state(), options: cost, problems })\n checkReadCost({ name: 'describe', read: () => impl.describe(), options: cost, problems })\n } catch (e) {\n problems.push(`cost measurement threw: ${String(e)}`)\n }\n }\n return { ok: problems.length === 0, problems }\n}\n","/** The slots of a body an item can cover (the item slot vocabulary: game-items imports it from here). */\nexport type BodySlot = 'head' | 'eyes' | 'torso' | 'arms' | 'hands' | 'legs' | 'feet' | 'over'\n\n/** The 11 segments of the detailed body model (the Arsenal ids). */\nexport type SegmentKind = 'head' | 'jaw' | 'neck' | 'torso' | 'pelvis' | 'upperArm' | 'forearm' | 'hand' | 'thigh' | 'shin' | 'foot'\n\n/** The 6 regions of the crowd model (the game regions 0..5). */\nexport type BodyRegion = 'head' | 'torso' | 'armL' | 'armR' | 'legL' | 'legR'\n\n/** Bits of the `missing` mask of a body. The instanced body shader reads them, so the values are part of the contract. */\nexport const MISSING_BITS = {\n head: 1,\n armL: 2,\n armR: 4,\n legL: 8,\n legR: 16,\n armLBroken: 32,\n armRBroken: 64,\n legLBroken: 128,\n legRBroken: 256,\n jaw: 512,\n} as const\n","import type { DestructibleSpec, PartSpec } from './destruction'\n\nexport interface CheckSpecOptions {\n /** Known material ids. When given, every part's material must be one of them. */\n materials?: Iterable<string>\n}\n\nexport interface SpecReport {\n /** False when there is at least one problem (warnings do not count). */\n ok: boolean\n problems: string[]\n /** Things that are legal but probably wrong, e.g. structural parts that cannot reach an anchored part. */\n warnings: string[]\n}\n\nconst STRUCTURE_ROLES = ['foundation', 'column', 'beam', 'slab', 'wall', 'partition', 'roof', 'stair', 'none']\nconst BEARS = [true, false, 'a_on_b', 'b_on_a']\n\nconst finite = (n: unknown): n is number => typeof n === 'number' && Number.isFinite(n)\nconst positive = (n: unknown): boolean => finite(n) && n > 0\nconst vec3 = (v: unknown): boolean => Array.isArray(v) && v.length === 3 && v.every(finite)\nconst nonNegative = (n: unknown): boolean => n === undefined || (finite(n) && n >= 0)\n\nconst FACES = ['both', '+', '-']\nconst BONDS = ['running', 'stack']\n\n/** Layers, reinforcement, units and breach: known materials, finite positive sizes. */\nconst checkStagedFields = (p: PartSpec | undefined, label: string, materials: Set<string> | null, problems: string[]): void => {\n const known = (m: unknown, what: string): void => {\n if (materials && !materials.has(m as string)) problems.push(`${label} ${what} has unknown material \"${String(m)}\"`)\n }\n ;(p?.layers ?? []).forEach((l, i) => {\n known(l?.material, `layer ${i}`)\n if (!positive(l?.thickness)) problems.push(`${label} layer ${i} thickness must be finite and positive`)\n if (!FACES.includes(l?.faces)) problems.push(`${label} layer ${i} has an invalid faces \"${String(l?.faces)}\"`)\n })\n const r = p?.reinforcement\n if (r) {\n known(r.material, 'reinforcement')\n if (!positive(r.spacing) || !positive(r.diameter)) problems.push(`${label} reinforcement spacing and diameter must be finite and positive`)\n if (r.residualCapacity !== undefined && !(finite(r.residualCapacity) && r.residualCapacity >= 0 && r.residualCapacity <= 1)) problems.push(`${label} reinforcement residualCapacity must be between 0 and 1`)\n }\n const u = p?.units\n if (u) {\n known(u.mortar, 'units mortar')\n if (!vec3(u.size) || !u.size.every(positive)) problems.push(`${label} units size must be three finite positive numbers`)\n if (!BONDS.includes(u.bond)) problems.push(`${label} units has an invalid bond \"${String(u.bond)}\"`)\n }\n if (p?.breach && p.breach.area !== undefined && !positive(p.breach.area)) problems.push(`${label} breach area must be finite and positive`)\n}\n\n/**\n * Static checks on a `DestructibleSpec` (no world needed), for items that give a `spec` instead of an `impl`: unique part ids, known materials\n * (when `options.materials` is given), joints that reference existing, different parts, finite positive sizes, non-negative mass / hp / capacity,\n * valid structure roles and `bears` directions. A structural part with no path of joints to an anchored part is a warning, not a problem: it\n * is allowed, it just falls.\n */\nexport const checkSpec = (spec: DestructibleSpec, options: CheckSpecOptions = {}): SpecReport => {\n const problems: string[] = []\n const warnings: string[] = []\n const materials = options.materials ? new Set(options.materials) : null\n const parts = Array.isArray(spec?.parts) ? spec.parts : []\n if (!Array.isArray(spec?.parts) || parts.length === 0) problems.push('the spec needs at least one part')\n const ids = new Set<string>()\n for (const p of parts) {\n const id = String(p?.id ?? '')\n const label = `part \"${id}\"`\n if (id === '') problems.push('a part has no id')\n else if (ids.has(id)) problems.push(`duplicate part id \"${id}\"`)\n ids.add(id)\n if (materials && !materials.has(p?.material)) problems.push(`${label} has unknown material \"${String(p?.material)}\"`)\n else if (typeof p?.material !== 'string' || p.material === '') problems.push(`${label} needs a material`)\n const s = p?.shape\n if (s?.kind === 'box') {\n if (!Array.isArray(s.size) || s.size.length !== 3 || !s.size.every(positive)) problems.push(`${label} box size must be three finite positive numbers`)\n } else if (s?.kind === 'cylinder') {\n if (!positive(s.radius) || !positive(s.height)) problems.push(`${label} cylinder radius and height must be finite and positive`)\n } else if (s?.kind === 'sphere') {\n if (!positive(s.radius)) problems.push(`${label} sphere radius must be finite and positive`)\n } else problems.push(`${label} has an unknown shape`)\n if (!vec3(p?.position)) problems.push(`${label} needs a finite position [x, y, z]`)\n if (p?.rotation !== undefined && !vec3(p.rotation)) problems.push(`${label} has an invalid rotation`)\n for (const f of ['mass', 'hp', 'thickness'] as const) if (!nonNegative(p?.[f])) problems.push(`${label} ${f} must be a finite number >= 0`)\n if (p?.fill !== undefined && !(finite(p.fill) && p.fill >= 0 && p.fill <= 1)) problems.push(`${label} fill must be between 0 and 1`)\n if (p?.structure) {\n if (!STRUCTURE_ROLES.includes(p.structure.role)) problems.push(`${label} has an invalid structure role \"${String(p.structure.role)}\"`)\n if (!nonNegative(p.structure.capacity)) problems.push(`${label} structure capacity must be a finite number >= 0`)\n }\n if (p?.contains && !nonNegative(p.contains.liters)) problems.push(`${label} contains.liters must be a finite number >= 0`)\n checkStagedFields(p, label, materials, problems)\n }\n\n const jointIds = new Set<string>()\n const edges: Array<[string, string]> = []\n for (const j of spec?.joints ?? []) {\n const id = j.id ?? `${j.a}~${j.b}`\n const label = `joint \"${id}\"`\n if (jointIds.has(id)) problems.push(`duplicate joint id \"${id}\"`)\n jointIds.add(id)\n if (!ids.has(j.a)) problems.push(`${label} references unknown part \"${String(j.a)}\"`)\n if (!ids.has(j.b)) problems.push(`${label} references unknown part \"${String(j.b)}\"`)\n if (j.a === j.b) problems.push(`${label} joins part \"${String(j.a)}\" to itself`)\n if (j.bears !== undefined && !BEARS.includes(j.bears)) problems.push(`${label} has an invalid bears \"${String(j.bears)}\"`)\n if (!nonNegative(j.strength)) problems.push(`${label} strength must be a finite number >= 0`)\n if (!nonNegative(j.seconds)) problems.push(`${label} seconds must be a finite number >= 0`)\n if (j.bears !== false && ids.has(j.a) && ids.has(j.b) && j.a !== j.b) edges.push([j.a, j.b])\n }\n\n // structural parts must reach an anchored part over the joints (only when the spec lists its joints: otherwise they are inferred later)\n const structural = parts.filter((p) => p?.structure && p.structure.role !== 'none')\n if (structural.length && spec.joints) {\n const anchored = parts.filter((p) => p.anchored || p.structure?.role === 'foundation').map((p) => p.id)\n const adj = new Map<string, string[]>()\n for (const [a, b] of edges) {\n adj.set(a, [...(adj.get(a) ?? []), b])\n adj.set(b, [...(adj.get(b) ?? []), a])\n }\n const seen = new Set(anchored)\n const queue = [...anchored]\n while (queue.length) {\n for (const n of adj.get(queue.pop()!) ?? []) {\n if (seen.has(n)) continue\n seen.add(n)\n queue.push(n)\n }\n }\n const lost = structural.filter((p) => !seen.has(p.id)).map((p) => p.id)\n if (lost.length) warnings.push(`structural part(s) ${lost.map((i) => `\"${i}\"`).join(', ')} cannot reach an anchored part, so they will fall`)\n }\n return { ok: problems.length === 0, problems, warnings }\n}\n","import type { BallisticExtras, Hit, HitIgnition, Vec3 } from './destruction'\n\n/**\n * A ballistic shot (one per pellet) as a weapon module produces it. Plain data: any damage model can consume it (`shotToHit` makes the `Hit`).\n */\nexport interface Shot {\n origin: Vec3\n /** Unit vector. */\n direction: Vec3\n /** Muzzle energy in joules. */\n energy: number\n /** Bullet diameter in millimetres. */\n caliber: number\n /** snake_case calibre id, e.g. `9x19`. */\n caliberId: string\n /** Muzzle speed in m/s. */\n speed: number\n /** Projectile mass in grams (one pellet for a shotgun load). */\n mass?: number\n /** Energy at a distance in metres, with the calibre's drag. */\n energyAt(distance: number): number\n pellet: number\n /** snake_case weapon id. */\n weapon: string\n source?: string\n /** Kind of the round that was loaded (`fmj`, `hp`, `ap`, `buck`, `slug`, `incendiary`, `tracer`...). */\n ammo?: string\n /** Millimetres of steel, concrete, brick and wood the round goes through at the muzzle (the ammo table of the weapons module). `shotToHit` scales it by the energy left. */\n penetration?: Readonly<Record<string, number>>\n incendiary?: boolean\n tracer?: boolean\n /** Chances that the round lights flammable vapour or fuel. */\n ignition?: HitIgnition\n}\n\n/**\n * The fields of the round that a damage model takes besides the geometry: the penetration by material scaled by the energy that is left at `distance`\n * (linear in the energy: half the energy goes through half as much), the incendiary and tracer flags and the ignition chances. Pass it as the sixth\n * argument of `DestructionWorld.shoot` or spread it in a `Hit`.\n */\nexport const shotExtras = (shot: Shot, distance = 0): BallisticExtras => {\n const out: { -readonly [K in keyof BallisticExtras]: BallisticExtras[K] } = {}\n if (shot.penetration) {\n const k = shot.energy > 0 ? Math.min(1, Math.max(0, shot.energyAt(distance) / shot.energy)) : 1\n const scaled: Record<string, number> = {}\n for (const key of Object.keys(shot.penetration)) scaled[key] = shot.penetration[key]! * k\n out.penetration = scaled\n }\n if (shot.incendiary) out.incendiary = true\n if (shot.tracer) out.tracer = true\n if (shot.ignition) out.ignition = { spark: shot.ignition.spark, flame: shot.ignition.flame }\n return out\n}\n\n/** One use of a non-firearm (melee swing, flame tick, heat tick, throw, tool tick, extinguisher tick). */\nexport type Use =\n | { kind: 'melee'; damage: 'blunt' | 'slash'; energy: number; radius: number; reach: number; origin: Vec3; direction: Vec3 }\n | { kind: 'flame'; temperature: number; radius: number; range: number; cone: boolean; duration: number; origin: Vec3; direction: Vec3 }\n | { kind: 'heat'; temperature: number; radius: number; range: number; duration: number; origin: Vec3; direction: Vec3 }\n | {\n kind: 'throw'\n energy: number\n radius: number\n fuse: number\n velocity: Vec3\n origin: Vec3\n fire?: { temperature: number; radius: number; seconds: number }\n /** Explosive id (`m67`, `molotov`, `pg7v`...): the host looks the numbers up in the arsenal. Absent on a plain thrown object. */\n explosive?: string\n /** What sets it off: `timer` after `fuse` seconds, `impact` on the first hit once armed. */\n trigger?: 'timer' | 'impact'\n /** Metres the projectile must fly before an impact sets it off; closer, it hits without exploding (rocket launchers). */\n armDistance?: number\n /** Radius in metres of the wounding area (`radius` is the lethal one). */\n injuryRadius?: number\n /** Seconds the blast stuns whoever is inside the injury radius (flashbang). */\n stunSeconds?: number\n /** Seconds the thrower held it after pulling the pin: `fuse` is what was left of the full fuse when it left the hand. */\n cooked?: number\n /** Went off in the thrower's hand (held past the fuse): no velocity, `fuse` is 0 and the blast is at `origin`. */\n inHand?: boolean\n }\n /** An explosive set down where the trigger is pulled (mine, C4, charge): it waits for its trigger instead of flying. */\n | {\n kind: 'place'\n explosive: string\n /** `wire`: something trips it; `remote`: the player fires it; `timer`: after `fuse` seconds. */\n triggers: readonly ('timer' | 'wire' | 'remote')[]\n energy: number\n /** Lethal radius in metres. */\n radius: number\n injuryRadius: number\n /** Cone the blast goes through, in front of `direction` (mine); absent for a blast in every direction. */\n cone?: { halfAngleDeg: number; length: number }\n /** The wire a `wire` charge stretches from where it is set down: metres out, degrees from its facing (counter-clockwise from above) and metres above it. */\n tripwire?: { length: number; angleDeg: number; height: number }\n fuse?: number\n origin: Vec3\n direction: Vec3\n }\n /** The blast behind a rocket launcher: dangerous inside `radius` metres, in the cone around `direction` (pointing away from the target). */\n | { kind: 'backblast'; radius: number; halfAngleDeg: number; origin: Vec3; direction: Vec3 }\n | { kind: 'tool'; tool: string; reach: number; duration: number; origin: Vec3; direction: Vec3 }\n | { kind: 'extinguish'; range: number; coolC: number; duration: number; origin: Vec3; direction: Vec3 }\n | { kind: 'hand'; reach: number; origin: Vec3; direction: Vec3 }\n\n/**\n * The `Hit` a ballistic shot makes at `point` (world space): the energy is what is left of the shot at that distance from its origin\n * (`shot.energyAt`), the direction and calibre come from the shot. `normal` (the surface normal at the point, when the caller knows it) does not\n * change the hit; it is accepted so that callers can pass what their raycast returned and so that a stricter implementation could use it.\n */\nexport const shotToHit = (shot: Shot, point: Vec3, normal?: Vec3): Hit => {\n void normal\n const dx = point[0] - shot.origin[0]\n const dy = point[1] - shot.origin[1]\n const dz = point[2] - shot.origin[2]\n const distance = Math.hypot(dx, dy, dz)\n return {\n type: 'ballistic',\n point: [point[0], point[1], point[2]],\n direction: [shot.direction[0], shot.direction[1], shot.direction[2]],\n energy: shot.energyAt(distance),\n caliber: shot.caliber,\n ...(shot.mass === undefined ? {} : { mass: shot.mass }),\n ...shotExtras(shot, distance),\n source: shot.source ?? shot.weapon,\n }\n}\n\n/**\n * The `Hit` a non-firearm `Use` makes at `point` (world space), or `null` for uses that do not damage by themselves.\n *\n * - `melee` -> `blunt` / `slash` with the swing's `energy`, contact `radius` and `direction`;\n * - `flame` -> `fire` and `heat` -> `heat`, with `temperature`, `duration` and a contact radius of at most 0.3 m (one ray of the cone);\n * - `throw` -> the blast (`explosive`, `energy`, `radius`, centred on `point`, the place it detonates). A thrown item with no blast energy but\n * a `fire` patch (a molotov) gives that patch as a `fire` hit (`temperature`, `radius`, `seconds` as `duration`). No energy and no fire -> `null`;\n * - `tool`, `extinguish` and `hand` -> `null` (tools work on joints, the extinguisher cools, the hand only grabs).\n *\n * `normal` does not change the hit (same as `shotToHit`).\n */\nexport const useToHit = (use: Use, point: Vec3, normal?: Vec3): Hit | null => {\n void normal\n const p: Vec3 = [point[0], point[1], point[2]]\n switch (use.kind) {\n case 'melee':\n return { type: use.damage, point: p, direction: [use.direction[0], use.direction[1], use.direction[2]], energy: use.energy, radius: use.radius }\n case 'flame':\n case 'heat':\n return {\n type: use.kind === 'flame' ? 'fire' : 'heat',\n point: p,\n direction: [use.direction[0], use.direction[1], use.direction[2]],\n temperature: use.temperature,\n radius: Math.min(use.radius, 0.3),\n duration: use.duration,\n }\n case 'throw':\n if (use.energy > 0) return { type: 'explosive', point: p, energy: use.energy, radius: use.radius }\n if (use.fire) return { type: 'fire', point: p, temperature: use.fire.temperature, radius: use.fire.radius, duration: use.fire.seconds }\n return null\n default:\n return null\n }\n}\n","import type { Hit } from './destruction'\n\n/**\n * How a container of flammable fluid (a fuel tank, a jerrycan, a gas bottle) is set alight by what hits it. A normal bullet that goes through only\n * makes a leak; the leak lights when something supplies a flame: a spark of a hard round on metal, an incendiary or tracer round, a fire nearby\n * or a blast. These are the numbers of the target side; the numbers of the round (core, jacket, incendiary, tracer) are in the weapons module\n * (`rules.ignition` of `@adatechnology/game-weapons`) and reach the target in `Hit.ignition`. Every number is a default to be changed per game.\n */\nexport interface IgnitionRules {\n /**\n * How much of the spark and of the flame of a round reaches the vapour, by how full the container is: points `[filled, factor]`, `filled` 0..1\n * (litres over capacity), `factor` 0..1, linear between points. A full container holds a mixture too rich to burn (the vapour has no air) and\n * mostly leaks; a nearly empty one holds the vapour/air mixture of a flammable range and lights the easiest; a dry one has little vapour left.\n * Default: 0.6 empty, 1 at 10 percent, 0.6 at 35, 0.3 at 65, 0.15 at 90 and 0.12 full.\n */\n fillCurve: ReadonlyArray<readonly [number, number]>\n /** 0..1: how much of the fill factor also weighs on the flame of an incendiary or tracer (1: as much as on a spark; 0: not at all). Default 0.5. */\n flameFillInfluence: number\n /** Chance of the flame of a round that is flagged `incendiary` or `tracer` but carries no `ignition` numbers (a host that passes only the flags). */\n flameDefaults: { incendiary: number; tracer: number }\n /**\n * What a spark needs to strike: a factor 0..1 by material id of the struck part. A material that is not listed but is metal takes\n * `sparkMetalDefault`; a part that is not metal never sparks. Default: steel and iron 1, aluminium 0.25.\n */\n sparkTarget: Readonly<Record<string, number>>\n sparkMetalDefault: number\n /**\n * Factor 0..1 on the spark by fluid (default 1): diesel has a flash point of 52 degrees C and more, so a spark that lights petrol vapour does\n * not light it (a flame does). Default: diesel 0.15.\n */\n sparkFluid: Readonly<Record<string, number>>\n /** A leaking container of flammable fluid within `radius` metres of a burning part or a burning fuel stain lights at `chancePerSecond`. */\n fireNear: { radius: number; chancePerSecond: number }\n}\n\n/** Defaults of `IgnitionRules`. */\nexport const DEFAULT_IGNITION_RULES: IgnitionRules = {\n fillCurve: [\n [0, 0.6],\n [0.1, 1],\n [0.35, 0.6],\n [0.65, 0.3],\n [0.9, 0.15],\n [1, 0.12],\n ],\n flameFillInfluence: 0.5,\n flameDefaults: { incendiary: 0.7, tracer: 0.2 },\n sparkTarget: { steel: 1, iron: 1, aluminium: 0.25 },\n sparkMetalDefault: 0.5,\n sparkFluid: { diesel: 0.15 },\n fireNear: { radius: 1.5, chancePerSecond: 0.5 },\n}\n\n/** Merges a partial `IgnitionRules` over the defaults (an object is merged one level deep). */\nexport const resolveIgnitionRules = (rules?: Partial<IgnitionRules>): IgnitionRules => ({\n ...DEFAULT_IGNITION_RULES,\n ...rules,\n flameDefaults: { ...DEFAULT_IGNITION_RULES.flameDefaults, ...rules?.flameDefaults },\n sparkTarget: { ...DEFAULT_IGNITION_RULES.sparkTarget, ...rules?.sparkTarget },\n sparkFluid: { ...DEFAULT_IGNITION_RULES.sparkFluid, ...rules?.sparkFluid },\n fireNear: { ...DEFAULT_IGNITION_RULES.fireNear, ...rules?.fireNear },\n})\n\n/** Linear interpolation of the fill curve at `fill` (0..1); outside the points it keeps the first or the last. */\nexport const fillFactor = (fill: number, curve: IgnitionRules['fillCurve'] = DEFAULT_IGNITION_RULES.fillCurve): number => {\n if (curve.length === 0) return 1\n const f = Math.min(1, Math.max(0, fill))\n if (f <= curve[0]![0]) return curve[0]![1]\n for (let i = 1; i < curve.length; i++) {\n const [x1, y1] = curve[i]!\n const [x0, y0] = curve[i - 1]!\n if (f <= x1) return x1 === x0 ? y1 : y0 + ((y1 - y0) * (f - x0)) / (x1 - x0)\n }\n return curve[curve.length - 1]![1]\n}\n\n/** The factor of what a spark strikes: 0 when the struck part is not metal. */\nexport const sparkTargetFactor = (materialId: string, metal: boolean, rules: IgnitionRules = DEFAULT_IGNITION_RULES): number =>\n !metal ? 0 : rules.sparkTarget[materialId] ?? rules.sparkMetalDefault\n\n/**\n * Chance that one round that went through the wall of a container lights the fluid that leaks: the spark (only on metal) and the flame (any\n * wall), each weighed by the fill of the container; the two are independent. 0 when the round carries nothing (`Hit.ignition` absent and not\n * flagged `incendiary` or `tracer`): a plain bullet on a plain wall only leaks.\n */\nexport const ignitionChance = (hit: Pick<Hit, 'incendiary' | 'tracer' | 'ignition'>, target: { sparkTarget: number; fill: number; fluid?: string }, rules: IgnitionRules = DEFAULT_IGNITION_RULES): number => {\n const k = fillFactor(target.fill, rules.fillCurve)\n const spark = (hit.ignition?.spark ?? 0) * target.sparkTarget * (target.fluid === undefined ? 1 : rules.sparkFluid[target.fluid] ?? 1) * k\n const flameBase = hit.ignition?.flame ?? Math.max(hit.incendiary ? rules.flameDefaults.incendiary : 0, hit.tracer ? rules.flameDefaults.tracer : 0)\n const flame = flameBase * (1 - rules.flameFillInfluence * (1 - k))\n return 1 - (1 - Math.min(1, Math.max(0, spark))) * (1 - Math.min(1, Math.max(0, flame)))\n}\n","/**\n * The seal of a closed container (a food tin, a drink can, a jar, a bottle with a cap): what opens it and whether a breach spoils what is inside.\n * Plain data and one pure check, shared by the item rules (`resolveUse` of game-items) and any host that lets the player open and eat (the test room).\n */\nexport interface SealSpec {\n /** Ids of the tools that open it (items or weapons: `can_opener`, `knife`); any one of them is enough. */\n readonly openWith?: readonly string[]\n /** It opens by hand (a pull tab, a ring pull, a screw cap): no tool needed. */\n readonly byHand?: boolean\n /** A hole through the container or a leak spoils what is inside: it can no longer be eaten or drunk. */\n readonly spoilsWhenBreached?: boolean\n}\n\n/** The state of one container: opened, holed through (a shot, a blade) or leaking. */\nexport interface SealState {\n readonly opened?: boolean\n readonly breached?: boolean\n readonly leaked?: boolean\n}\n\n/** Why a sealed container cannot be eaten or drunk now. */\nexport type SealBlock = 'sealed' | 'breached' | 'leaked'\n\n/** Whether it can be opened with the tools at hand, and with which one (undefined when it opens by hand). */\nexport const sealOpener = (seal: SealSpec, tools: Iterable<string>): { readonly ok: boolean; readonly tool?: string } => {\n if (seal.byHand || !seal.openWith || seal.openWith.length === 0) return { ok: true }\n const have = new Set(tools)\n const tool = seal.openWith.find((id) => have.has(id))\n return tool === undefined ? { ok: false } : { ok: true, tool }\n}\n\n/** What stops eating or drinking it now, or undefined when nothing does. A spoiled container (breached, leaked) is blocked even once open. */\nexport const sealBlock = (seal: SealSpec, state: SealState): SealBlock | undefined => {\n if (seal.spoilsWhenBreached && state.breached) return 'breached'\n if (seal.spoilsWhenBreached && state.leaked) return 'leaked'\n if (!state.opened) return 'sealed'\n return undefined\n}\n","/** How a hand turns something round in strokes (a screw cap, a tap handle, a knob): what `twistStroke` answers for one moment of the turning. */\nexport interface TwistStroke {\n /** Radians the wrist is turned from the middle of its stroke, positive the way the part turns. */\n readonly angle: number\n /** Radians the part has turned in all, from 0 to `strokes * reach`. */\n readonly turned: number\n /** How closed the fingers are, 0 open to 1 closed: closed on the part while it turns, open while the wrist turns back. */\n readonly grip: number\n /** 0..1, how far the hand rises off the part while the wrist turns back (1 is `TWIST_LIFT` metres). */\n readonly lift: number\n}\n\nexport interface TwistOptions {\n /** Strokes of the wrist. Default 3. */\n readonly strokes?: number\n /** Radians the part turns in one stroke (a wrist turns about a quarter round with its hold). Default 1.6. */\n readonly reach?: number\n}\n\n/** Metres a hand rises off the part between two strokes. */\nexport const TWIST_LIFT = 0.012\n/** Share of each stroke spent turning the part; the rest turns the wrist back open. */\nconst TURNING = 0.7\n\nconst smooth = (k: number): number => k * k * (3 - 2 * k)\n\n/**\n * The hand turning a part round at `share` (0..1) of the whole turning: in each stroke the wrist turns with the part, then lets go, rises a little and turns back.\n * Pure and the same for every host, so first and third person turn the same hand the same way.\n */\nexport const twistStroke = (share: number, options: TwistOptions = {}): TwistStroke => {\n const strokes = Math.max(1, Math.round(options.strokes ?? 3))\n const reach = options.reach ?? 1.6\n const along = Math.min(1, Math.max(0, share)) * strokes\n const index = Math.min(strokes - 1, Math.floor(along))\n const phase = along - index\n if (phase <= TURNING) {\n const k = smooth(phase / TURNING)\n return { angle: reach * (k - 0.5), turned: reach * (index + k), grip: 1, lift: 0 }\n }\n const k = (phase - TURNING) / (1 - TURNING)\n return { angle: reach * (0.5 - smooth(k)), turned: reach * (index + 1), grip: 0.35, lift: Math.sin(k * Math.PI) }\n}\n","import type { Vec3 } from './destruction'\n\n/** Pose of one part (or of the whole item) at a key: position offset in metres and Euler XYZ rotation in radians, both relative to the rest pose. */\nexport interface AnimationPose {\n position?: Vec3\n rotation?: Vec3\n}\n\nexport interface AnimationKey {\n /** Seconds from the start of the clip. */\n t: number\n /** Pose of the item's root. */\n position?: Vec3\n rotation?: Vec3\n /** Poses of named parts: the key is a destruction part id (a pistol `reload` moves `mag`; a car door `open` rotates `door_l`). */\n parts?: Record<string, AnimationPose>\n}\n\nexport interface AnimationEventSpec {\n /** Seconds from the start of the clip. */\n t: number\n /** snake_case type the host maps (`sound`, `eject_casing`, `door_latch`...). */\n type: string\n data?: Record<string, unknown>\n}\n\n/** A use animation a module brings with its item. Poses between keys are interpolated by the player (the test room does it linearly). */\nexport interface AnimationClipSpec {\n /** snake_case: `reload`, `open`, `drink`... Unique within the item. */\n id: string\n /** Seconds. */\n duration: number\n keys: AnimationKey[]\n events?: AnimationEventSpec[]\n}\n\n/** What an item exposes when it brings its own animations. */\nexport interface ItemAnimationContract {\n animations: AnimationClipSpec[]\n}\n\nconst finite3 = (v: unknown): boolean => Array.isArray(v) && v.length === 3 && v.every((n) => typeof n === 'number' && Number.isFinite(n))\n\n/**\n * Problems with a clip (empty when it is valid): a snake_case id, a positive finite duration, at least one key, key and event times inside\n * `[0, duration]` and not going backwards, finite vectors, every named part one of `partIds`, event types that are non-empty strings and\n * JSON-serializable event data.\n */\nexport const checkAnimation = (clip: AnimationClipSpec, partIds: Iterable<string>): { ok: boolean; problems: string[] } => {\n const problems: string[] = []\n const parts = new Set(partIds)\n const id = String(clip?.id ?? '')\n if (!/^[a-z][a-z0-9_]*$/.test(id)) problems.push(`clip id \"${id}\" must be snake_case`)\n const label = `clip \"${id}\"`\n if (!(typeof clip?.duration === 'number' && Number.isFinite(clip.duration) && clip.duration > 0)) problems.push(`${label} needs a positive finite duration`)\n const dur = typeof clip?.duration === 'number' && clip.duration > 0 ? clip.duration : Infinity\n if (!Array.isArray(clip?.keys) || clip.keys.length === 0) {\n problems.push(`${label} needs at least one key`)\n return { ok: false, problems }\n }\n let prev = -Infinity\n clip.keys.forEach((k, i) => {\n if (!(typeof k.t === 'number' && Number.isFinite(k.t)) || k.t < 0 || k.t > dur + 1e-9) problems.push(`${label} key ${i} has t=${String(k.t)} outside 0..${dur}`)\n else if (k.t < prev) problems.push(`${label} key ${i} goes back in time (${k.t} < ${prev})`)\n else prev = k.t\n for (const f of ['position', 'rotation'] as const) if (k[f] !== undefined && !finite3(k[f])) problems.push(`${label} key ${i} has an invalid ${f}`)\n for (const [pid, pose] of Object.entries(k.parts ?? {})) {\n if (!parts.has(pid)) problems.push(`${label} key ${i} moves unknown part \"${pid}\"`)\n for (const f of ['position', 'rotation'] as const) if (pose?.[f] !== undefined && !finite3(pose[f])) problems.push(`${label} key ${i} part \"${pid}\" has an invalid ${f}`)\n }\n })\n let prevEv = -Infinity\n ;(clip.events ?? []).forEach((e, i) => {\n if (!(typeof e.t === 'number' && Number.isFinite(e.t)) || e.t < 0 || e.t > dur + 1e-9) problems.push(`${label} event ${i} has t=${String(e.t)} outside 0..${dur}`)\n else if (e.t < prevEv) problems.push(`${label} event ${i} goes back in time`)\n else prevEv = e.t\n if (typeof e.type !== 'string' || e.type === '') problems.push(`${label} event ${i} needs a type`)\n try {\n JSON.stringify(e.data ?? {})\n } catch {\n problems.push(`${label} event ${i} data is not JSON`)\n }\n })\n return { ok: problems.length === 0, problems }\n}\n","import type { AnimationClipSpec, AnimationEventSpec, AnimationPose } from './animation'\nimport { checkAnimation } from './animation'\nimport type { HostEvent } from './module'\n\n/** Clips a tool can bring, one per move of its cycle. A tool brings the ones it has; a missing clip is simply not played. */\nexport const TOOL_CLIP = {\n DRAW: 'draw',\n SHOT: 'shot',\n MISFIRE: 'misfire',\n EMPTY: 'empty',\n CYCLE: 'cycle',\n RELOAD: 'reload',\n FEED: 'feed',\n FAULT: 'fault',\n CLEAR: 'clear',\n SAFETY_ON: 'safety_on',\n SAFETY_OFF: 'safety_off',\n MODE: 'mode',\n /** A throwable with the pin out, held until it is thrown. */\n COOK: 'cook',\n /** The stock folds, unfolds, slides in or out (variants `fold`, `unfold`, `collapse`, `extend`). */\n STOCK: 'stock',\n /** A light or a laser is switched (variants `on`, `off`). */\n TOGGLE: 'toggle',\n} as const\nexport type ToolClipId = (typeof TOOL_CLIP)[keyof typeof TOOL_CLIP]\n\n/** What a renderer does when a rule event arrives. `variant` picks `<clip>_<variant>` when the tool has it, else `<clip>`. */\nexport type ToolAnimationStep =\n | { readonly type: 'play'; readonly clip: ToolClipId; readonly variant?: string; readonly duration?: number; readonly repeat?: number }\n /** Move the clip that is playing to the marker (a clip event `stage` with `data.stage`) the rule just reached. */\n | { readonly type: 'sync'; readonly stage: string }\n /** The rule says the phase is over: the clip jumps to its end if it is still running. */\n | { readonly type: 'finish'; readonly clip: ToolClipId }\n\nconst stockVariant = (event: Extract<HostEvent, { type: 'stock' }>): string => {\n const isFolding = event.kind === undefined ? false : event.kind.includes('fold')\n if (event.state === 'collapsed') return isFolding ? 'fold' : 'collapse'\n return isFolding ? 'unfold' : 'extend'\n}\n\n/** The move a host event asks of the tool in hand, or null when it has no motion. */\nexport const toolAnimationStep = (event: HostEvent): ToolAnimationStep | null => {\n switch (event.type) {\n case 'tool':\n return { type: 'play', clip: TOOL_CLIP.DRAW, ...(event.duration === undefined ? {} : { duration: event.duration }) }\n case 'shot':\n return { type: 'play', clip: TOOL_CLIP.SHOT, repeat: Math.max(1, event.rounds ?? 1) }\n case 'misfire':\n return { type: 'play', clip: TOOL_CLIP.MISFIRE }\n case 'empty':\n return { type: 'play', clip: TOOL_CLIP.EMPTY }\n case 'mode':\n return { type: 'play', clip: TOOL_CLIP.MODE, variant: event.mode }\n case 'fault':\n return { type: 'play', clip: TOOL_CLIP.FAULT, variant: event.fault }\n case 'clear':\n if (event.phase === 'end') return { type: 'finish', clip: TOOL_CLIP.CLEAR }\n return { type: 'play', clip: TOOL_CLIP.CLEAR, variant: event.fault, ...(event.duration === undefined ? {} : { duration: event.duration }) }\n case 'safety':\n return { type: 'play', clip: event.on ? TOOL_CLIP.SAFETY_ON : TOOL_CLIP.SAFETY_OFF }\n case 'cycle':\n if (event.phase === 'end') return { type: 'finish', clip: TOOL_CLIP.CYCLE }\n return { type: 'play', clip: TOOL_CLIP.CYCLE, ...(event.duration === undefined ? {} : { duration: event.duration }) }\n case 'reload':\n if (event.phase === 'end') return { type: 'finish', clip: TOOL_CLIP.RELOAD }\n return { type: 'play', clip: TOOL_CLIP.RELOAD, ...(event.kind === undefined ? {} : { variant: event.kind }), ...(event.duration === undefined ? {} : { duration: event.duration }) }\n case 'stage':\n return { type: 'sync', stage: event.stage }\n case 'feed':\n return { type: 'play', clip: TOOL_CLIP.FEED }\n case 'cook':\n if (event.phase === 'start') return { type: 'play', clip: TOOL_CLIP.COOK, duration: event.fuse }\n return { type: 'finish', clip: TOOL_CLIP.COOK }\n case 'stock':\n return { type: 'play', clip: TOOL_CLIP.STOCK, variant: stockVariant(event), ...(event.duration === undefined ? {} : { duration: event.duration }) }\n case 'toggle':\n return { type: 'play', clip: TOOL_CLIP.TOGGLE, variant: event.on ? 'on' : 'off' }\n default:\n return null\n }\n}\n\n/** Where a renderer puts the poses: every part of the tool by id (the ids the clips move), and the whole tool. Poses are offsets from rest. */\nexport interface ToolRig {\n setPartPose(partId: string, pose: AnimationPose): void\n setRootPose?(pose: AnimationPose): void\n}\n\n/** Clips by id, with the variants as `<clip>_<variant>`. */\nexport type ToolClipSet = Readonly<Record<string, AnimationClipSpec>>\n\n/** A renderer's tool animator: feed it the host events and the frame time. */\nexport interface ToolAnimator {\n handle(event: HostEvent): void\n update(dt: number): void\n /** Ids of the clips playing now. */\n readonly playing: readonly string[]\n dispose(): void\n}\n\nexport const STAGE_EVENT = 'stage'\n\n/** The clip with its times (keys and events) scaled so that it lasts `duration` seconds. */\nexport const scaleClip = (clip: AnimationClipSpec, duration: number): AnimationClipSpec => {\n const factor = clip.duration > 0 ? duration / clip.duration : 1\n return {\n ...clip,\n duration,\n keys: clip.keys.map((key) => ({ ...key, t: key.t * factor })),\n ...(clip.events ? { events: clip.events.map((event) => ({ ...event, t: event.t * factor })) } : {}),\n }\n}\n\nconst ZERO: [number, number, number] = [0, 0, 0]\nconst mix = (from: readonly number[], to: readonly number[], fraction: number): [number, number, number] => [\n (from[0] ?? 0) + ((to[0] ?? 0) - (from[0] ?? 0)) * fraction,\n (from[1] ?? 0) + ((to[1] ?? 0) - (from[1] ?? 0)) * fraction,\n (from[2] ?? 0) + ((to[2] ?? 0) - (from[2] ?? 0)) * fraction,\n]\n\n/** Pose of the whole tool (`partId` undefined) or of one part at `time`, linear between keys; a key that does not name it means rest. */\nexport const sampleClip = (clip: AnimationClipSpec, partId: string | undefined, time: number): { position: [number, number, number]; rotation: [number, number, number] } => {\n const points = clip.keys.map((key) => {\n const pose = partId === undefined ? key : key.parts?.[partId]\n return { t: key.t, position: pose?.position ?? ZERO, rotation: pose?.rotation ?? ZERO }\n })\n const first = points[0]\n if (!first || first.t > 0) points.unshift({ t: 0, position: ZERO, rotation: ZERO })\n const last = points[points.length - 1]\n if (!last) return { position: ZERO, rotation: ZERO }\n if (time >= last.t) return { position: mix(last.position, last.position, 0), rotation: mix(last.rotation, last.rotation, 0) }\n const index = Math.max(0, points.findIndex((point, i) => time >= point.t && time < (points[i + 1]?.t ?? Infinity)))\n const from = points[index]\n const to = points[index + 1]\n if (!from || !to) return { position: ZERO, rotation: ZERO }\n const fraction = to.t > from.t ? (time - from.t) / (to.t - from.t) : 0\n return { position: mix(from.position, to.position, fraction), rotation: mix(from.rotation, to.rotation, fraction) }\n}\n\n/** Problems with a clip set (empty when valid): each key is the clip id (or `<clip>_<variant>`), every clip passes `checkAnimation`, and a `stage` event names its stage. */\nexport const checkToolClips = (clips: ToolClipSet, partIds: Iterable<string>): { ok: boolean; problems: string[] } => {\n const parts = [...partIds]\n const problems: string[] = []\n for (const [key, clip] of Object.entries(clips)) {\n if (clip.id !== key) problems.push(`clip \"${key}\" has the id \"${clip.id}\"`)\n if (!(clip.duration > 0)) problems.push(`clip \"${key}\" has no duration`)\n problems.push(...checkAnimation(clip, parts).problems)\n for (const event of clip.events ?? []) if (event.type === STAGE_EVENT && typeof event.data?.stage !== 'string') problems.push(`clip \"${key}\" has a stage event without data.stage`)\n }\n return { ok: problems.length === 0, problems }\n}\n\ninterface Instance {\n readonly name: string\n readonly clip: AnimationClipSpec\n time: number\n delay: number\n fired: number\n}\n\nexport interface ToolClipPlayerOptions {\n clips: ToolClipSet\n rig: ToolRig\n /** Called for each clip event as its time passes (`eject_casing`, `drop_magazine`, `stage`...). */\n onEvent?(event: AnimationEventSpec, clip: string): void\n /** Seconds between the rounds of a `repeat` (a burst): default 0.1. */\n repeatInterval?(): number\n}\n\n/** The default player of a tool's clips: runs the steps of `toolAnimationStep` against a rig, scaled to the duration the rule gives. */\nexport interface ToolClipPlayer {\n apply(step: ToolAnimationStep): void\n update(dt: number): void\n readonly playing: readonly string[]\n /** The clips being played with the time each has reached and the clip itself (scaled to the duration the rule gave), for a renderer that has to follow what the clip does now (the hands working a part). */\n readonly running: ReadonlyArray<{ readonly name: string; readonly time: number; readonly clip: AnimationClipSpec }>\n}\n\nexport const createToolClipPlayer = (options: ToolClipPlayerOptions): ToolClipPlayer => {\n const { clips, rig, onEvent } = options\n let instances: Instance[] = []\n\n const find = (clip: string, variant?: string): { name: string; clip: AnimationClipSpec } | undefined => {\n const name = variant !== undefined && clips[`${clip}_${variant}`] ? `${clip}_${variant}` : clip\n const found = clips[name]\n return found ? { name, clip: found } : undefined\n }\n\n const render = (instance: Instance): void => {\n const time = Math.min(instance.time, instance.clip.duration)\n const root = sampleClip(instance.clip, undefined, time)\n if (instance.clip.keys.some((key) => key.position || key.rotation)) rig.setRootPose?.(root)\n const touched = new Set(instance.clip.keys.flatMap((key) => Object.keys(key.parts ?? {})))\n for (const id of touched) rig.setPartPose(id, sampleClip(instance.clip, id, time))\n }\n\n const fireEvents = (instance: Instance, upTo: number): void => {\n const events = instance.clip.events ?? []\n while (instance.fired < events.length && (events[instance.fired]?.t ?? Infinity) <= upTo + 1e-9) {\n const event = events[instance.fired]\n instance.fired += 1\n if (event) onEvent?.(event, instance.name)\n }\n }\n\n return {\n apply(step) {\n if (step.type === 'sync') {\n for (const instance of instances) {\n const marker = (instance.clip.events ?? []).find((event) => event.type === STAGE_EVENT && event.data?.stage === step.stage)\n if (marker && instance.time < marker.t) instance.time = marker.t\n }\n return\n }\n if (step.type === 'finish') {\n for (const instance of instances) {\n if (instance.name !== step.clip && !instance.name.startsWith(`${step.clip}_`)) continue\n fireEvents(instance, instance.clip.duration)\n instance.time = instance.clip.duration\n }\n return\n }\n const found = find(step.clip, step.variant)\n if (!found) return\n const clip = step.duration && step.duration > 0 ? scaleClip(found.clip, step.duration) : found.clip\n const interval = options.repeatInterval?.() ?? 0.1\n instances = instances.filter((existing) => existing.name !== found.name || existing.delay > 0)\n for (let round = 0; round < (step.repeat ?? 1); round++) {\n instances.push({ name: found.name, clip, time: 0, delay: round * interval, fired: 0 })\n }\n },\n update(dt) {\n for (const instance of instances) {\n const carried = instance.delay > 0 ? dt - instance.delay : dt\n if (instance.delay > 0) {\n instance.delay = Math.max(0, instance.delay - dt)\n if (instance.delay > 0) continue\n }\n instance.time += carried\n fireEvents(instance, instance.time)\n render(instance)\n }\n instances = instances.filter((instance) => instance.delay > 0 || instance.time < instance.clip.duration)\n },\n get playing() {\n return instances.map((instance) => instance.name)\n },\n get running() {\n return instances.filter((instance) => instance.delay <= 0).map((instance) => ({ name: instance.name, time: instance.time, clip: instance.clip }))\n },\n }\n}\n","export const FRAME_PHASES = ['input', 'fixedSimulate', 'lateSimulate', 'present', 'render', 'idle'] as const\nexport type FramePhase = (typeof FRAME_PHASES)[number]\n\n/**\n * Presentation work a system leaves for later frames, run in small units within a shared time budget.\n * Never simulation: nothing that consumes a seeded generator or decides an outcome may wait in a queue.\n */\nexport interface DeferredQueue {\n /** Stable name for stats and logs (see `DEFERRED_QUEUE_ID`). */\n readonly id: string\n /**\n * Units waiting. 0 means idle; the budget skips the queue without calling `run`. `frame` is the budget's frame counter: a queue may\n * report 0 for the rest of a frame (the crease queue does in the frame a panel was torn). Same value for repeated calls in one frame.\n */\n pending(frame?: number): number\n /**\n * Runs units in order until `clock() >= deadline`. Contract: when `pending() > 0` it runs **at least one** unit, even with a deadline\n * already past; it never runs a unit after it saw the deadline pass. Returns how many units it ran.\n */\n run(deadline: number, clock: () => number): number\n /** Runs everything now (synchronous step, clear, dispose). */\n flush(): void\n /**\n * Called by `budget.register`: from now on the owner stops draining on its own (no MessageChannel, no drain inside `update`).\n * Never called by a getter; a queue nobody registered keeps today's internal draining.\n */\n attach?(): void\n /** Called by the unregister function and by `budget.dispose`: the owner goes back to its internal draining. */\n detach?(): void\n}\n\n/** Where a module registers a deferred queue with the host's budget. */\nexport interface DeferredQueueOptions {\n /** Higher runs first. See DEFERRED_PRIORITY. */\n readonly priority: number\n /** `present` runs before the render (the work must show this frame); `idle` runs after it. Default `idle`. */\n readonly phase?: 'present' | 'idle'\n /** Starvation guard: the queue runs at least one unit every this many frames, even with the budget spent. Default 4. */\n readonly minEveryFrames?: number\n /** Milliseconds of every frame kept for this queue before the others share the rest (when it has work). Default 0. */\n readonly reserveMs?: number\n}\n\n/** The ids of the kit's queues: what `DeferredQueue.id` says and what `DEFERRED_PRIORITY` is keyed by. */\nexport const DEFERRED_QUEUE_ID = {\n DESTRUCTION_EVENTS: 'destruction.events',\n BREACH_PAINT: 'floorplan.breach-paint',\n AUDIO_VOICES: 'audio.voices',\n VEHICLE_CREASE: 'vehicles.crease',\n} as const\n\n/** Default priorities and reserves of the kit's queues; a host may override any of them. */\nexport const DEFERRED_PRIORITY = {\n [DEFERRED_QUEUE_ID.DESTRUCTION_EVENTS]: { priority: 300, phase: 'present' },\n [DEFERRED_QUEUE_ID.BREACH_PAINT]: { priority: 250, phase: 'present' },\n [DEFERRED_QUEUE_ID.AUDIO_VOICES]: { priority: 200, phase: 'idle', reserveMs: 1 },\n [DEFERRED_QUEUE_ID.VEHICLE_CREASE]: { priority: 100, phase: 'idle' },\n} as const satisfies Readonly<Record<string, DeferredQueueOptions>>\n\nexport interface DeferredQueueReport {\n readonly ok: boolean\n readonly problems: readonly string[]\n}\n\n/**\n * Checks the `DeferredQueue` contract. `fill` leaves the queue with at least two units waiting (the same call is made on a fresh queue).\n * It cannot prove the queue only carries presentation work: that is a rule of review.\n */\nexport function checkDeferredQueue(queue: DeferredQueue, fill: () => void): DeferredQueueReport {\n const problems: string[] = []\n fill()\n const waiting = queue.pending(1)\n if (waiting < 2) problems.push(`fill() must leave at least 2 units waiting (pending is ${waiting})`)\n if (queue.pending(1) !== waiting) problems.push('pending(frame) changed between two calls in the same frame')\n const ran = queue.run(0, () => 1)\n if (ran !== 1) problems.push(`run with a deadline already past must run exactly one unit (ran ${ran})`)\n if (waiting >= 2 && queue.pending(2) !== waiting - 1) problems.push(`one unit ran but pending went from ${waiting} to ${queue.pending(2)}`)\n try {\n queue.attach?.()\n queue.attach?.()\n queue.detach?.()\n queue.detach?.()\n } catch (error) {\n problems.push(`attach/detach must be idempotent: ${error instanceof Error ? error.message : String(error)}`)\n }\n queue.flush()\n if (queue.pending(3) !== 0) problems.push(`flush must leave nothing pending (pending is ${queue.pending(3)})`)\n if (queue.run(0, () => 1) !== 0) problems.push('run on an empty queue must run no unit')\n return { ok: problems.length === 0, problems }\n}\n","const WARNED_KEY = Symbol.for('@adatechnology/game-contracts.warned')\n\ntype WarnedHolder = { [WARNED_KEY]?: Set<string> }\n\nconst warnedKeys = (): Set<string> => {\n const holder = globalThis as WarnedHolder\n return (holder[WARNED_KEY] ??= new Set<string>())\n}\n\ndeclare const process: { readonly env: { readonly NODE_ENV?: string } }\n\n// The literal `process.env.NODE_ENV` is what bundlers replace; where there is no `process` the reference throws and counts as development.\nconst isProduction = (): boolean => {\n try {\n return process.env.NODE_ENV === 'production'\n } catch {\n return false\n }\n}\n\nconst isQuiet = (): boolean => (globalThis as { __GAME_KIT_QUIET__?: unknown }).__GAME_KIT_QUIET__ === true\n\n/**\n * Warns on the console the first time `key` is seen, and only outside production and when `globalThis.__GAME_KIT_QUIET__` is not `true`: for a silent fallback that keeps working (an adapter that made its own effects\n * world or audio engine because the host lent none). The seen keys live on `globalThis`, so several bundles of the kit on one page warn once together.\n */\nexport const warnOnce = (key: string, message: string): void => {\n if (isQuiet() || isProduction()) return\n const seen = warnedKeys()\n if (seen.has(key)) return\n seen.add(key)\n console.warn(`[game-kit] ${message}`)\n}\n\n/** Forgets what `warnOnce` has seen (tests that count warnings). */\nexport const resetWarnOnce = (): void => warnedKeys().clear()\n","import { warnOnce } from './warn'\n\ntype PlainObject = Record<string, unknown>\ntype Entry = { readonly id: string }\n\n/** Keys that would reach the prototype of the result when a patch comes from parsed JSON. */\nconst UNSAFE_KEYS: ReadonlySet<string> = new Set(['__proto__', 'constructor', 'prototype'])\n\nconst isPlainObject = (value: unknown): value is PlainObject =>\n typeof value === 'object' && value !== null && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype\n\n/** Recursively optional; arrays and functions are replaced as a whole, objects are merged. */\nexport type DeepPartial<TValue> = TValue extends (...args: never[]) => unknown\n ? TValue\n : TValue extends readonly unknown[]\n ? TValue\n : TValue extends object\n ? { [TKey in keyof TValue]?: DeepPartial<TValue[TKey]> }\n : TValue\n\n/** Merges `patch` over `base`: plain objects merge field by field, arrays, functions and primitives replace. `undefined` in the patch is ignored. */\nexport const deepMerge = <TBase extends object>(base: TBase, patch: object | undefined): TBase => {\n if (!patch) return base\n const result: PlainObject = { ...(base as PlainObject) }\n for (const [key, value] of Object.entries(patch)) {\n if (value === undefined || UNSAFE_KEYS.has(key)) continue\n const current = result[key]\n result[key] = isPlainObject(current) && isPlainObject(value) ? deepMerge(current, value) : value\n }\n return result as TBase\n}\n\n/** The shipped entries with the ones from `extra` added or, when the id exists, replaced. */\nexport const mergeById = <TEntry extends Entry>(shipped: readonly TEntry[], extra: readonly TEntry[] | undefined): Map<string, TEntry> => {\n const entries = new Map<string, TEntry>()\n for (const entry of [...shipped, ...(extra ?? [])]) entries.set(entry.id, entry)\n return entries\n}\n\n/** Applies `patch` by id; a patch for an id that does not exist is ignored (and warned about once, in development). */\nexport const applyPatches = <TEntry extends Entry>(entries: Map<string, TEntry>, patches: Readonly<Record<string, DeepPartial<TEntry> | Partial<TEntry>>> | undefined): void => {\n for (const [id, patch] of Object.entries(patches ?? {})) {\n const entry = entries.get(id)\n if (entry) entries.set(id, deepMerge(entry, patch))\n else warnOnce(`registry.patch.${id}`, `patch for \"${id}\" ignored: no entry has that id`)\n }\n}\n\n/** Takes the ids out; an id that does not exist is ignored (and warned about once, in development). */\nexport const removeIds = (entries: Map<string, unknown>, ids: readonly string[] | undefined): void => {\n for (const id of ids ?? []) {\n if (!entries.delete(id)) warnOnce(`registry.remove.${id}`, `remove of \"${id}\" ignored: no entry has that id`)\n }\n}\n","import type { Vec3 } from './destruction'\n\n/**\n * The bench of a module: controls, layers and counters it declares as data. The host keeps the values, draws them in a generic way and hands\n * every change back through `ModuleHost.bench`. Nothing here is specific to a kind of module.\n */\nexport type ControlValue = number | boolean | string\n\nexport interface ChoiceOption {\n readonly id: string\n readonly name: string\n /** Heading the host lists the option under (`optgroup`, a grouped row of buttons). Options of a group must sit next to each other. */\n readonly group?: string\n}\n\ninterface ControlBase {\n /** snake_case, unique across the module's controls, layers and metrics. */\n readonly id: string\n /** Display name, already translated for the locale the host asked for. */\n readonly name: string\n readonly hint?: string\n readonly hidden?: boolean\n /**\n * The change (or the press, for an action) takes a noticeable time, a third of a second or more: the host shows its loading indicator while it works, with this text, or the control's name for `true`.\n * Only the host's own controls panel does it; a change made through `TestRoom.bench().set / act` runs at once.\n */\n readonly slow?: boolean | string\n}\n\nexport interface NumberControl extends ControlBase {\n readonly kind: 'number'\n readonly min: number\n readonly max: number\n readonly step?: number\n readonly unit?: string\n readonly default: number\n}\n\nexport interface BooleanControl extends ControlBase {\n readonly kind: 'boolean'\n readonly default: boolean\n}\n\nexport interface ChoiceControl extends ControlBase {\n readonly kind: 'choice'\n readonly options: readonly ChoiceOption[]\n readonly default: string\n}\n\n/** A button: no value, only the press. */\nexport interface ActionControl extends ControlBase {\n readonly kind: 'action'\n}\n\nexport type ModuleControl = NumberControl | BooleanControl | ChoiceControl | ActionControl\n\n/** Something of the module the viewer turns on or off (smoke, flash, casings). */\nexport interface ModuleLayer {\n readonly id: string\n readonly name: string\n /** On unless `false`. */\n readonly default?: boolean\n}\n\n/** Pulled: the room calls read only when it samples (~4 Hz, or on TestRoom.metrics()). */\nexport interface ModuleMetric {\n readonly id: string\n readonly name: string\n readonly unit?: string\n /** Budget: the host shows a bar and warns past it. */\n readonly max?: number\n readonly digits?: number\n read(): number | string\n}\n\nexport type BenchChange =\n | { readonly kind: 'control'; readonly id: string; readonly value: ControlValue }\n | { readonly kind: 'layer'; readonly id: string; readonly on: boolean }\n | { readonly kind: 'action'; readonly id: string }\n\nexport interface ControlPatch {\n readonly hidden?: boolean\n readonly disabled?: boolean\n readonly options?: readonly ChoiceOption[]\n readonly value?: ControlValue\n}\n\n/** What the host lends a module that declares a bench: the current values and the changes. */\nexport interface ModuleBench {\n value(id: string): ControlValue | undefined\n layer(id: string): boolean\n /** Right after attach returns, the host sends one change per control (not actions) and per layer, in declaration order. */\n onChange(listener: (change: BenchChange) => void): () => void\n /** `value` sets without emitting (no echo loops); `options` falls back to the first option if the value is no longer offered. */\n patch(id: string, patch: ControlPatch): void\n /** Move the host camera (a near / middle / far choice). */\n look(eye: Vec3, target: Vec3): void\n /** Shows a sheet on the host's panel, or takes it down with `null`. A host without a sheet area ignores it. */\n sheet?(sheet: BenchSheet | null): void\n}\n\n/**\n * A card of text the module puts on the host's panel (the sheet of an effect, of a weapon): what it is, its numbers, its steps, its colours and,\n * optionally, a strip of segments over time. Names and texts are already translated for the host's locale.\n */\nexport interface BenchSheet {\n readonly kicker?: string\n readonly title: string\n readonly body?: string\n readonly facts?: readonly { readonly label: string; readonly value: string }[]\n readonly steps?: readonly { readonly at: string; readonly text: string }[]\n readonly swatches?: readonly { readonly color: string; readonly name: string }[]\n readonly note?: string\n /** A strip of named segments (seconds), with tick marks and a playhead that follows the module metric `metric`. */\n readonly timeline?: {\n readonly segments: readonly { readonly name: string; readonly start: number; readonly end: number; readonly color: string }[]\n readonly ticks: readonly number[]\n readonly metric: string\n }\n}\n\nexport interface BenchReport {\n readonly ok: boolean\n readonly problems: readonly string[]\n}\n\nexport interface BenchDeclaration {\n readonly controls?: readonly ModuleControl[]\n readonly layers?: readonly ModuleLayer[]\n readonly metrics?: readonly ModuleMetric[]\n}\n\nconst SNAKE_CASE = /^[a-z][a-z0-9_]*$/\nconst finite = (n: unknown): n is number => typeof n === 'number' && Number.isFinite(n)\n\nfunction checkControl(control: ModuleControl, problems: string[]): void {\n const label = `control \"${control.id}\"`\n if (control.kind === 'number') {\n if (!finite(control.min) || !finite(control.max) || control.min >= control.max) problems.push(`${label} needs min < max`)\n if (control.step !== undefined && !(finite(control.step) && control.step > 0)) problems.push(`${label} needs a step > 0`)\n if (!finite(control.default) || control.default < control.min || control.default > control.max) problems.push(`${label} default ${String(control.default)} is outside ${control.min}..${control.max}`)\n return\n }\n if (control.kind !== 'choice') return\n if (control.options.length === 0) {\n problems.push(`${label} needs at least one option`)\n return\n }\n const seen = new Set<string>()\n const groups = new Set<string>()\n let previousGroup: string | undefined\n for (const option of control.options) {\n if (seen.has(option.id)) problems.push(`${label} repeats option \"${option.id}\"`)\n seen.add(option.id)\n if (option.group !== undefined && (typeof option.group !== 'string' || option.group === '')) problems.push(`${label} option \"${option.id}\" has an empty group`)\n else if (option.group !== undefined && option.group !== previousGroup && groups.has(option.group)) problems.push(`${label} group \"${option.group}\" is split: its options must be next to each other`)\n if (typeof option.group === 'string' && option.group !== '') groups.add(option.group)\n previousGroup = option.group\n }\n if (!seen.has(control.default)) problems.push(`${label} default \"${control.default}\" is not among its options`)\n}\n\n/** snake_case ids unique across controls, layers and metrics; min < max; step > 0; default in range; options non-empty, unique, default among them, each group in one run; metric max > 0. */\nexport function checkBench(declared: BenchDeclaration): BenchReport {\n const problems: string[] = []\n const ids = new Set<string>()\n const claim = (kind: string, id: string): void => {\n if (!SNAKE_CASE.test(id)) problems.push(`${kind} id \"${id}\" must be snake_case`)\n if (ids.has(id)) problems.push(`duplicate id \"${id}\" across controls, layers and metrics`)\n ids.add(id)\n }\n for (const control of declared.controls ?? []) {\n claim('control', control.id)\n checkControl(control, problems)\n }\n for (const layer of declared.layers ?? []) claim('layer', layer.id)\n for (const metric of declared.metrics ?? []) {\n claim('metric', metric.id)\n if (metric.max !== undefined && !(finite(metric.max) && metric.max > 0)) problems.push(`metric \"${metric.id}\" needs a max > 0`)\n }\n return { ok: problems.length === 0, problems }\n}\n","/** The weather, light and ground as the world is right now. Written by whoever drives the weather, read by whoever reacts to it. */\nexport interface EnvironmentState {\n /** Rain in mm/h; 0 is dry. */\n readonly rain: number\n /** Wind in m/s along x and z, and its strength (the length of that vector). */\n readonly windX: number\n readonly windZ: number\n readonly windSpeed: number\n /** Strongest gust in m/s. */\n readonly gust: number\n /** Render fog far distance in metres. */\n readonly fogFar: number\n /** How far one can see for gameplay, in metres (not the render fog). */\n readonly visibility: number\n /** 0 is full daylight, 1 is the darkest night. */\n readonly nightFactor: number\n readonly temperatureC: number\n /** Wet ground, 0..1: rises with rain and dries after it stops. */\n readonly wetness: number\n}\n\nexport type EnvironmentKey = keyof EnvironmentState\n\n/** A calm dry day (the normal world, before anything went wrong). */\nexport const DEFAULT_ENVIRONMENT: EnvironmentState = {\n rain: 0,\n windX: 0,\n windZ: 0,\n windSpeed: 0,\n gust: 0,\n fogFar: 220,\n visibility: 220,\n nightFactor: 0,\n temperatureC: 20,\n wetness: 0,\n}\n\n/** The host's environment (`ModuleHost.environment`): a store the weather module writes to and the others read. */\nexport interface EnvironmentBus {\n get(): EnvironmentState\n /** Merges `patch` into the state; listeners hear it only when a value really changed. */\n set(patch: Partial<EnvironmentState>): void\n /** Hears every change with the keys that changed. Returns the unsubscribe function. */\n on(listener: (state: EnvironmentState, changed: readonly EnvironmentKey[]) => void): () => void\n}\n\n/** A plain store that implements the bus; the test room and tests use it, a game may bring its own. */\nexport function createEnvironmentBus(initial: Partial<EnvironmentState> = {}): EnvironmentBus {\n let state: EnvironmentState = { ...DEFAULT_ENVIRONMENT, ...initial }\n const listeners = new Set<(state: EnvironmentState, changed: readonly EnvironmentKey[]) => void>()\n return {\n get: () => state,\n set(patch) {\n const changed = (Object.keys(patch) as EnvironmentKey[]).filter((key) => patch[key] !== undefined && patch[key] !== state[key])\n if (changed.length === 0) return\n const next = { ...state } as { -readonly [Key in EnvironmentKey]: number }\n for (const key of changed) next[key] = patch[key] as number\n state = next\n for (const listener of [...listeners]) listener(state, changed)\n },\n on(listener) {\n listeners.add(listener)\n return () => void listeners.delete(listener)\n },\n }\n}\n","import { applyPatches, deepMerge, mergeById, removeIds } from './registry'\nimport type { DeepPartial } from './registry'\n\n/** One category (kind) of items. Defaults and required contracts are inherited from the `extends` chain. */\nexport interface CategoryDef<TDefaults extends object = Record<string, unknown>> {\n readonly id: string\n /** Parent category id; the child inherits its defaults and its required contracts. */\n readonly extends?: string\n /** Field values every entry of this kind starts with; objects merge down the chain, arrays replace. */\n readonly defaults?: DeepPartial<TDefaults>\n /** Contract ids (`ContractChecker.id`) every entry of this kind, or of a descendant, must satisfy. */\n readonly requires?: readonly string[]\n /** An abstract category only groups: entries cannot declare it directly, only its descendants. */\n readonly abstract?: boolean\n}\n\n/** Where a checker is being run: the entry's kind and the chain of categories root first. */\nexport interface ContractContext {\n readonly kind: string\n readonly chain: readonly string[]\n}\n\n/** A named contract: returns the problems of an entry, each a short phrase like `missing leftover.despawnSeconds`. Empty means it holds. */\nexport interface ContractChecker<TEntry> {\n readonly id: string\n check(entry: TEntry, ctx: ContractContext): string[]\n}\n\nexport interface CategoryOptions {\n /** Categories added to the shipped ones; the same id replaces. */\n readonly extra?: readonly CategoryDef[]\n /** Partial changes by id, applied after `extra`. */\n readonly patches?: Readonly<Record<string, DeepPartial<CategoryDef> | Partial<CategoryDef>>>\n /** Ids taken out of the tree (their children are then reported by `check()`). */\n readonly remove?: readonly string[]\n}\n\nexport interface CategoryRegistry {\n get(id: string): CategoryDef | undefined\n has(id: string): boolean\n ids(): string[]\n /** Root first, ending at `id`. Throws on an unknown id, an unknown parent or a cycle. */\n chain(id: string): string[]\n /** `defaults` merged along the chain, root first, so the closest category wins. */\n defaults(id: string): Record<string, unknown>\n /** Union of `requires` along the chain, order kept, without duplicates. */\n requires(id: string): string[]\n /** True when `id` is `ancestorId` or descends from it. */\n isA(id: string, ancestorId: string): boolean\n /** Problems in the tree itself: duplicate ids, unknown `extends`, cycles. */\n check(): string[]\n}\n\nexport interface CategorizedOptions {\n /** Field of the entry that names its category. Default `kind`. */\n readonly kindField?: string\n /** Known gaps by entry id: problems starting with one of these texts go to `allowed`, so the list can shrink over time. */\n readonly allow?: Readonly<Record<string, readonly string[]>>\n}\n\nexport interface CategorizedReport {\n readonly ok: boolean\n readonly problems: string[]\n readonly allowed: string[]\n}\n\nexport const defineCategories = (defs: readonly CategoryDef[], options: CategoryOptions = {}): CategoryRegistry => {\n const problems: string[] = []\n const duplicates = (list: readonly CategoryDef[]): void => {\n const ids = new Set<string>()\n for (const def of list) {\n if (ids.has(def.id)) problems.push(`duplicate category \"${def.id}\"`)\n ids.add(def.id)\n }\n }\n duplicates(defs)\n duplicates(options.extra ?? [])\n\n const entries = mergeById(defs, options.extra)\n applyPatches(entries, options.patches)\n removeIds(entries, options.remove)\n\n const chain = (id: string): string[] => {\n const path: string[] = []\n let current: string | undefined = id\n while (current !== undefined) {\n const def = entries.get(current)\n if (!def) throw new Error(path.length === 0 ? `unknown category \"${current}\"` : `category \"${path[0]}\" has unknown parent \"${current}\"`)\n if (path.includes(current)) throw new Error(`category cycle: ${[...path, current].reverse().join(' -> ')}`)\n path.push(current)\n current = def.extends\n }\n return path.reverse()\n }\n\n const registry: CategoryRegistry = {\n get: (id) => entries.get(id),\n has: (id) => entries.has(id),\n ids: () => [...entries.keys()],\n chain,\n defaults: (id) => chain(id).reduce<Record<string, unknown>>((acc, ancestor) => deepMerge(acc, entries.get(ancestor)?.defaults), {}),\n requires: (id) => {\n const out: string[] = []\n for (const ancestor of chain(id)) for (const contract of entries.get(ancestor)?.requires ?? []) if (!out.includes(contract)) out.push(contract)\n return out\n },\n isA: (id, ancestorId) => {\n try {\n return chain(id).includes(ancestorId)\n } catch {\n return false\n }\n },\n check: () => {\n const found = [...problems]\n for (const [id, def] of entries) {\n if (def.extends !== undefined && !entries.has(def.extends)) found.push(`category \"${id}\" extends unknown \"${def.extends}\"`)\n else {\n try {\n chain(id)\n } catch (error) {\n const message = (error as Error).message\n // The same cycle is found from each of its members; the dedupe keeps one line per distinct message.\n if (message.startsWith('category cycle') && !found.includes(message)) found.push(message)\n }\n }\n }\n return found\n },\n }\n return registry\n}\n\n/** The entry with the defaults of its category underneath: the entry wins, objects merge, arrays replace. */\nexport const resolveEntry = <TEntry extends object>(registry: CategoryRegistry, entry: TEntry, kindField = 'kind'): TEntry =>\n deepMerge(registry.defaults(String((entry as Record<string, unknown>)[kindField])) as TEntry, entry)\n\n/** Checks that each entry has a known, concrete kind and satisfies every contract its chain requires. */\nexport const checkCategorized = <TEntry extends { readonly id: string }>(\n entries: readonly TEntry[],\n registry: CategoryRegistry,\n checkers: readonly ContractChecker<TEntry>[],\n options: CategorizedOptions = {},\n): CategorizedReport => {\n const kindField = options.kindField ?? 'kind'\n const byId = new Map(checkers.map((checker) => [checker.id, checker]))\n const problems: string[] = [...registry.check()]\n const allowed: string[] = []\n\n for (const entry of entries) {\n const kind = String((entry as Record<string, unknown>)[kindField])\n if (!registry.has(kind)) {\n problems.push(`\"${entry.id}\" has unknown kind \"${kind}\"`)\n continue\n }\n if (registry.get(kind)?.abstract) {\n problems.push(`\"${entry.id}\" has abstract kind \"${kind}\"`)\n continue\n }\n let path: string[]\n try {\n path = registry.chain(kind)\n } catch (error) {\n problems.push(`\"${entry.id}\" (${kind}): ${(error as Error).message}`)\n continue\n }\n const resolved = resolveEntry(registry, entry, kindField)\n for (const contract of registry.requires(kind)) {\n const owner = path.find((ancestor) => registry.get(ancestor)?.requires?.includes(contract)) ?? kind\n const checker = byId.get(contract)\n if (!checker) {\n problems.push(`kind \"${kind}\" requires contract \"${contract}\" but no checker is registered`)\n continue\n }\n const prefix = `\"${entry.id}\" (${kind}): `\n for (const problem of checker.check(resolved, { kind, chain: path })) {\n const text = `${prefix}${problem}, required by ${owner}`\n if ((options.allow?.[entry.id] ?? []).some((start) => problem.startsWith(start))) allowed.push(text)\n else problems.push(text)\n }\n }\n }\n return { ok: problems.length === 0, problems: [...new Set(problems)], allowed }\n}\n","/**\n * Where a drawn object comes from. Every builder of the kit that draws a piece (a car of the fleet, a house or a wall, a piece of furniture, a person, an\n * animal, a plant, an item, a weapon) marks the root it returns, and every renderer that draws for the room (effects, debris, liquids, the room itself)\n * marks its own roots, so a host can tell a piece of the kit from something drawn on the spot. Duck-typed on three.js objects (`userData`, `parent`,\n * `children`), so the contracts stay free of three.js.\n */\nexport const KIT_ORIGIN_KEY = 'kitOrigin'\n\n/** What drew an object: the package and the kind of piece (`vehicle`, `structure`, `furniture`, `person`... or `effect`, `room` for what is not a piece). */\nexport interface KitOrigin {\n readonly owner: string\n readonly kind: string\n /** The catalogue id of the piece, when it has one. */\n readonly id?: string\n /** Drawn as a simple stand-in shape because the kit has no model of the piece yet (an item with no team model): a model still to make. */\n readonly standIn?: boolean\n}\n\ninterface Node {\n userData?: Record<string, unknown>\n parent?: Node | null\n children?: readonly Node[]\n name?: string\n visible?: boolean\n isMesh?: boolean\n isPoints?: boolean\n isLine?: boolean\n isSprite?: boolean\n}\n\n/** Marks `object` as drawn by `origin.owner` and returns it. */\nexport function markKitOrigin<T>(object: T, origin: KitOrigin): T {\n const node = object as unknown as Node\n node.userData = node.userData ?? {}\n node.userData[KIT_ORIGIN_KEY] = { ...origin }\n return object\n}\n\n/** The origin of the object or of its nearest marked ancestor; null when nothing up the tree is marked. */\nexport function kitOriginOf(object: unknown): KitOrigin | null {\n for (let node = object as Node | null | undefined; node; node = node.parent) {\n const origin = node.userData?.[KIT_ORIGIN_KEY] as KitOrigin | undefined\n if (origin && typeof origin.owner === 'string') return origin\n }\n return null\n}\n\n/** A drawn thing that no builder of the kit marked: what was drawn on the spot. */\nexport interface UnmarkedDrawing {\n /** The names of the object and its named ancestors, outermost first. */\n readonly path: string\n readonly object: unknown\n}\n\n/** Every visible mesh, line, point cloud or sprite under `root` with no marked ancestor (`root` itself not counted as one). */\nexport function unmarkedDrawings(root: unknown): UnmarkedDrawing[] {\n const out: UnmarkedDrawing[] = []\n const pathOf = (node: Node): string => {\n const names: string[] = []\n for (let n: Node | null | undefined = node; n && n !== root; n = n.parent) if (n.name) names.push(n.name)\n return names.reverse().join(' > ') || '(no name)'\n }\n const walk = (node: Node, marked: boolean): void => {\n if (node.visible === false) return\n const here = marked || (node !== root && Boolean((node.userData?.[KIT_ORIGIN_KEY] as KitOrigin | undefined)?.owner))\n if (!here && (node.isMesh || node.isPoints || node.isLine || node.isSprite)) out.push({ path: pathOf(node), object: node })\n for (const child of node.children ?? []) walk(child, here)\n }\n walk(root as Node, false)\n return out\n}\n","/** A floor rectangle in an object's own space, metres (x across, z along). */\nexport interface Footprint {\n readonly minX: number\n readonly maxX: number\n readonly minZ: number\n readonly maxZ: number\n}\n\n/** What `footprintBlocker` reads of an object: its world matrix (three.js `Object3D`, duck-typed so the contracts stay free of three.js). */\nexport interface FootprintObject {\n readonly matrixWorld: { readonly elements: ArrayLike<number> }\n readonly parent?: unknown\n updateWorldMatrix?(updateParents: boolean, updateChildren: boolean): void\n}\n\n/**\n * The `ModuleHost.addBlocker` function of a solid object standing on the floor: the walking player stays out of `footprint`, a rectangle in the object's own space,\n * so the object blocks turned with it and follows it when it moves. An object out of the scene (no parent) blocks nothing.\n */\nexport function footprintBlocker(object: FootprintObject | (() => FootprintObject | null | undefined), footprint: Footprint | (() => Footprint | null | undefined)): (x: number, z: number, radius: number) => boolean {\n return (x, z, radius) => {\n const o = typeof object === 'function' ? object() : object\n const fp = typeof footprint === 'function' ? footprint() : footprint\n if (!o || !fp || !o.parent) return false\n o.updateWorldMatrix?.(true, false)\n const e = o.matrixWorld.elements\n // the world point in the object's own floor axes: its x and z columns are at right angles, so a projection on each (over its squared length, for a scale) inverts the matrix\n const dx = x - (e[12] as number)\n const dz = z - (e[14] as number)\n const ax = (e[0] as number) ** 2 + (e[1] as number) ** 2 + (e[2] as number) ** 2\n const az = (e[8] as number) ** 2 + (e[9] as number) ** 2 + (e[10] as number) ** 2\n const lx = (dx * (e[0] as number) + dz * (e[2] as number)) / (ax || 1)\n const lz = (dx * (e[8] as number) + dz * (e[10] as number)) / (az || 1)\n return lx > fp.minX - radius && lx < fp.maxX + radius && lz > fp.minZ - radius && lz < fp.maxZ + radius\n }\n}\n","/**\n * The sounds of a body (footsteps, jumps, landings, blows, hurt), as ids every package agrees on: the rule that knows what the body did\n * (`game-player`, a host's own player) names the sound, and the bank that knows how it sounds (`game-audio`'s `BODY_FOLEY_BANK`) answers it.\n * A game swaps the sound of an id (a sample instead of the synthesis) without touching the rule.\n */\n\n/** What the feet touch, by how it sounds (not by what it is made of: a wooden floor and a plywood board both sound `wood`). */\nexport const SURFACE_IDS = ['concrete', 'asphalt', 'wood', 'tile', 'dirt', 'grass', 'gravel', 'sand', 'metal', 'water', 'glass', 'carpet'] as const\nexport type SurfaceId = (typeof SURFACE_IDS)[number]\n\n/** The surface a body stands on when nobody says (the test room's floor is a concrete slab). */\nexport const DEFAULT_SURFACE: SurfaceId = 'concrete'\n\n/** How the feet move: a run hits harder and shorter; a crouched step is the walk, quieter. */\nexport const GAIT_IDS = ['walk', 'run'] as const\nexport type GaitId = (typeof GAIT_IDS)[number]\n\n/** How hard a landing is: `light` for a jump on the spot or a step down (up to about 5 m/s), `heavy` for a drop of more than a metre and a half. */\nexport const LANDING_IDS = ['light', 'heavy'] as const\nexport type LandingId = (typeof LANDING_IDS)[number]\n\n/** The fall speed (m/s) from which a landing is `heavy`. */\nexport const HEAVY_LANDING_SPEED = 5.5\n\nexport type FootstepSoundId = `footstep_${SurfaceId}_${GaitId}`\nexport type LandSoundId = `land_${SurfaceId}_${LandingId}`\n\n/**\n * How a blow is struck, by the body part or the tool that does it. `blade` stabs or slashes, `blunt` is a club, a bat, a pipe or a hammer, `chop` an\n * axe or a machete driven down.\n */\nexport const BLOW_IDS = ['punch', 'kick', 'shove', 'blade', 'blunt', 'chop'] as const\nexport type BlowId = (typeof BLOW_IDS)[number]\n\n/** What the blow meets: a body (flesh and bone, the head apart), something else (the material answers with its own impact), or nothing. */\nexport type BlowTarget = 'body' | 'head' | 'object' | 'air'\n\n/** The sounds of the body that are not a footstep or a landing. */\nexport const BODY_SOUND_IDS = [\n 'jump',\n 'cloth_rustle',\n 'body_fall',\n 'fall_damage',\n 'player_hurt',\n 'player_breath_run',\n 'player_death',\n 'bite',\n 'grab',\n 'punch_swing',\n 'punch_hit_body',\n 'punch_hit_face',\n 'punch_hit_object',\n 'kick_swing',\n 'kick_hit',\n 'kick_hit_object',\n 'shove_two_hands',\n 'knife_swing',\n 'knife_stab',\n 'knife_slash',\n 'knife_hit_object',\n 'blunt_swing',\n 'blunt_hit',\n 'blunt_hit_object',\n 'axe_swing',\n 'axe_chop',\n 'axe_hit_object',\n] as const\nexport type BodySoundId = (typeof BODY_SOUND_IDS)[number]\n\n/** Every sound of a body: what a host plays for the player, a survivor or a zombie. */\nexport type BodyFoleyId = FootstepSoundId | LandSoundId | BodySoundId\n\nexport const footstepSoundId = (surface: SurfaceId, gait: GaitId): FootstepSoundId => `footstep_${surface}_${gait}`\nexport const landSoundId = (surface: SurfaceId, fallSpeed: number): LandSoundId => `land_${surface}_${fallSpeed >= HEAVY_LANDING_SPEED ? 'heavy' : 'light'}`\n\n/** Every footstep and landing id, in the order of the surfaces. */\nexport const FOOTSTEP_SOUND_IDS: readonly FootstepSoundId[] = SURFACE_IDS.flatMap((surface) => GAIT_IDS.map((gait) => footstepSoundId(surface, gait)))\nexport const LAND_SOUND_IDS: readonly LandSoundId[] = SURFACE_IDS.flatMap((surface) => LANDING_IDS.map((landing): LandSoundId => `land_${surface}_${landing}`))\nexport const BODY_FOLEY_IDS: readonly BodyFoleyId[] = [...FOOTSTEP_SOUND_IDS, ...LAND_SOUND_IDS, ...BODY_SOUND_IDS]\n\nconst SWING: Readonly<Record<BlowId, BodySoundId | null>> = {\n punch: 'punch_swing',\n kick: 'kick_swing',\n // two hands pushed out do not whistle: the shove is one sound, at the contact\n shove: null,\n blade: 'knife_swing',\n blunt: 'blunt_swing',\n chop: 'axe_swing',\n}\n\n/**\n * Seconds from the start of a swing's sound to its loudest point (the limb or the tool at full speed, just before the contact). A host that knows when the\n * blow lands starts the swing this long before; one that does not plays the swing now and the hit this long after.\n */\nexport const SWING_LEAD_SECONDS: Readonly<Record<BlowId, number>> = { punch: 0.07, kick: 0.09, shove: 0, blade: 0.05, blunt: 0.1, chop: 0.11 }\n\n/** The swing through the air, played as the blow starts (`null`: the blow has none). */\nexport const swingSoundId = (blow: BlowId): BodySoundId | null => SWING[blow]\n\nconst HIT: Readonly<Record<BlowId, Readonly<Record<Exclude<BlowTarget, 'air'>, BodySoundId>>>> = {\n punch: { body: 'punch_hit_body', head: 'punch_hit_face', object: 'punch_hit_object' },\n kick: { body: 'kick_hit', head: 'kick_hit', object: 'kick_hit_object' },\n shove: { body: 'shove_two_hands', head: 'shove_two_hands', object: 'shove_two_hands' },\n blade: { body: 'knife_stab', head: 'knife_stab', object: 'knife_hit_object' },\n blunt: { body: 'blunt_hit', head: 'blunt_hit', object: 'blunt_hit_object' },\n chop: { body: 'axe_chop', head: 'axe_chop', object: 'axe_hit_object' },\n}\n\n/**\n * The body's side of a blow that lands: the knuckles, the shoe, the blade or the club meeting what it hit. On an object the material's own impact\n * plays too (the wood, the metal); this is the part that says it was a punch and not a shot.\n */\nexport const hitSoundId = (blow: BlowId, target: Exclude<BlowTarget, 'air'>): BodySoundId => HIT[blow][target]\n\n/**\n * The surface a material sounds like underfoot, by the material ids of `game-destruction` and `game-terrain` (unknown ids: `fallback`). Data, so\n * a game with its own materials passes its own table to `surfaceOfMaterial`.\n */\nexport const MATERIAL_SURFACES: Readonly<Record<string, SurfaceId>> = {\n concrete: 'concrete',\n mortar: 'concrete',\n stone: 'concrete',\n brick: 'concrete',\n plaster: 'concrete',\n asphalt: 'asphalt',\n wood_soft: 'wood',\n wood_hard: 'wood',\n green_wood: 'wood',\n plywood: 'wood',\n mdf: 'wood',\n ceramic: 'tile',\n plastic: 'tile',\n soil: 'dirt',\n wax: 'dirt',\n flesh_fruit: 'dirt',\n turf: 'grass',\n foliage: 'grass',\n cactus: 'grass',\n gravel: 'gravel',\n sand: 'sand',\n steel: 'metal',\n cast_iron: 'metal',\n aluminium: 'metal',\n copper: 'metal',\n water: 'water',\n glass: 'glass',\n tempered_glass: 'glass',\n fabric: 'carpet',\n foam: 'carpet',\n leather: 'carpet',\n rubber: 'carpet',\n paper: 'carpet',\n}\n\nexport const isSurfaceId = (value: unknown): value is SurfaceId => typeof value === 'string' && (SURFACE_IDS as readonly string[]).includes(value)\n\n/** The surface of a material id; a surface id passes through. */\nexport function surfaceOfMaterial(material: string | undefined, table: Readonly<Record<string, SurfaceId>> = MATERIAL_SURFACES, fallback: SurfaceId = DEFAULT_SURFACE): SurfaceId {\n if (material === undefined) return fallback\n if (isSurfaceId(material)) return material\n return table[material] ?? fallback\n}\n","/**\n * @adatechnology/game-contracts: the contracts every game module (vehicles, furniture, plants, houses, weapons) depends on, and nothing else.\n * Types plus tiny pure checkers, no runtime dependencies. The default destruction world, the renderers and the test room are optional.\n */\nexport type {\n ChainDelay,\n Crack,\n DamageStage,\n DamageType,\n DebrisKind,\n Dent,\n DestructibleSpec,\n BlastOptions,\n BlastReport,\n ConfinementOptions,\n ExplosionChain,\n FragmentHitOptions,\n ShelterOptions,\n DestructionEvent,\n DestructionEventType,\n FluidKind,\n Fragment,\n FragmentMark,\n FractureStyle,\n BallisticExtras,\n Hit,\n HitIgnition,\n HitResult,\n Hole,\n JointKind,\n JointSpec,\n JointState,\n MaterialId,\n ObjectState,\n PartShape,\n PartSpec,\n PartBreach,\n PartState,\n PartStatus,\n PartUnits,\n Quat,\n RayHit,\n Reinforcement,\n TensionRebar,\n TunedMassDamper,\n WindExposure,\n WindState,\n PileSpec,\n SoilLayer,\n SoilProfile,\n SoilState,\n StructureRole,\n SurfaceLayer,\n ToolKind,\n Vec3,\n} from './destruction'\nexport type { BusyOptions, BusySink, BusyTask } from './busy'\nexport { blastShove, DEFAULT_BLAST_SHOVE } from './blast-shove'\nexport type { BlastShove, BlastShoveOptions, BlastSource } from './blast-shove'\nexport { IMPACT_CONTRACT, checkDestructible, checkHit } from './impact'\nexport type { CheckOptions, DestructibleImpl, ImpactContract, SurfaceRay, SurfaceRayHit } from './impact'\nexport type { CostOptions } from './impact-cost'\nexport { MISSING_BITS } from './body'\nexport type { BodyRegion, BodySlot, SegmentKind } from './body'\nexport { checkSpec } from './spec'\nexport type { CheckSpecOptions, SpecReport } from './spec'\nexport { shotToHit, shotExtras, useToHit } from './weapons'\nexport { DEFAULT_IGNITION_RULES, fillFactor, ignitionChance, resolveIgnitionRules, sparkTargetFactor } from './ignition'\nexport type { IgnitionRules } from './ignition'\nexport type { Shot, Use } from './weapons'\nexport type { ContainerSpec, ItemUseDef, LiquidId } from './fluids'\nexport { sealBlock, sealOpener } from './seal'\nexport type { SealBlock, SealSpec, SealState } from './seal'\nexport type { HandPose, HandTargetSource, HandTargets } from './hands'\nexport { TWIST_LIFT, twistStroke } from './twist'\nexport type { TwistOptions, TwistStroke } from './twist'\nexport type { EffectHandle, EffectRequest, EffectSink, Enclosure, EnclosureBox } from './effects'\nexport type { WarmUpProbes } from './warm-up'\nexport { checkAnimation } from './animation'\nexport type { AnimationClipSpec, AnimationEventSpec, AnimationKey, AnimationPose, ItemAnimationContract } from './animation'\nexport { STAGE_EVENT, TOOL_CLIP, checkToolClips, createToolClipPlayer, sampleClip, scaleClip, toolAnimationStep } from './tool-animation'\nexport type { ToolAnimationStep, ToolAnimator, ToolClipId, ToolClipPlayer, ToolClipPlayerOptions, ToolClipSet, ToolRig } from './tool-animation'\nexport { DEFERRED_PRIORITY, DEFERRED_QUEUE_ID, FRAME_PHASES, checkDeferredQueue } from './frame'\nexport type { DeferredQueue, DeferredQueueOptions, DeferredQueueReport, FramePhase } from './frame'\nexport type { FrameOptions, AreaPlacement, GroundLayout, GroundZone, HostEvent, HostGraphics, HostTool, HostToolAttachment, ModuleArea, ModuleHost, ModuleItemFluid, ModuleItemSeal, ModuleScenario, PlayerState, ItemSeat, TestableItem, TestableModule, Thumbnail, ToolCommand, ToolCommandResult, HostReach } from './module'\nexport { applyPatches, deepMerge, mergeById, removeIds } from './registry'\nexport type { DeepPartial } from './registry'\nimport { resetWarnOnce as resetWarnOnceForTests } from './warn'\n\nexport { warnOnce } from './warn'\n/** @deprecated Import it from `@adatechnology/game-contracts/testing`. */\nexport const resetWarnOnce = resetWarnOnceForTests\nexport { checkBench } from './bench'\nexport type {\n ActionControl,\n BenchChange,\n BenchDeclaration,\n BenchReport,\n BenchSheet,\n BooleanControl,\n ChoiceControl,\n ChoiceOption,\n ControlPatch,\n ControlValue,\n ModuleBench,\n ModuleControl,\n ModuleLayer,\n ModuleMetric,\n NumberControl,\n} from './bench'\nexport type { AudioListener, AudioSink, LoopHandle, SoundHandle, SoundRequest } from './audio'\nexport { DEFAULT_ENVIRONMENT, createEnvironmentBus } from './environment'\nexport type { EnvironmentBus, EnvironmentKey, EnvironmentState } from './environment'\nexport { checkCategorized, defineCategories, resolveEntry } from './categories'\nexport type { CategorizedOptions, CategorizedReport, CategoryDef, CategoryOptions, CategoryRegistry, ContractChecker, ContractContext } from './categories'\nexport { KIT_ORIGIN_KEY, kitOriginOf, markKitOrigin, unmarkedDrawings } from './origin'\nexport type { KitOrigin, UnmarkedDrawing } from './origin'\nexport { footprintBlocker } from './footprint'\nexport type { Footprint, FootprintObject } from './footprint'\nexport {\n BLOW_IDS,\n BODY_FOLEY_IDS,\n BODY_SOUND_IDS,\n DEFAULT_SURFACE,\n FOOTSTEP_SOUND_IDS,\n GAIT_IDS,\n HEAVY_LANDING_SPEED,\n LANDING_IDS,\n LAND_SOUND_IDS,\n MATERIAL_SURFACES,\n SURFACE_IDS,\n SWING_LEAD_SECONDS,\n footstepSoundId,\n hitSoundId,\n isSurfaceId,\n landSoundId,\n surfaceOfMaterial,\n swingSoundId,\n} from './foley'\nexport type { BlowId, BlowTarget, BodyFoleyId, BodySoundId, FootstepSoundId, GaitId, LandSoundId, LandingId, SurfaceId } from './foley'\n","import { registerItems } from './registry'\n\n/** Ground cover types the lot builder can draw. Colours come from the palette roles of the same purpose. */\nexport function registerGroundItems(): void {\n const flat = { category: 'ground_cover', w: 1, d: 1, h: 0, decor: true, mount: 'ground', flat: true } as const\n registerItems([\n { type: 'lawn', ...flat, color: { role: 'lawn' } },\n { type: 'tile_floor', ...flat, color: { role: 'exterior_floor' } },\n { type: 'concrete', ...flat, color: { role: 'exterior_floor' } },\n { type: 'deck_floor', ...flat, color: { role: 'deck_floor' } },\n { type: 'dirt', ...flat, color: { role: 'dirt' } },\n ])\n}\n","import type { SlotDef, SlotKit } from './types'\n\n/** Builders for the slot definitions of a room library. */\nexport const slotKit: SlotKit = {\n wall: (id, side, pos, size, cats, o) => Object.assign({ id, anchor: 'wall', side, pos, size, cats }, o) as SlotDef,\n corner: (id, corner, size, cats, o) => Object.assign({ id, anchor: 'corner', corner, size, cats }, o) as SlotDef,\n center: (id, fx, fz, size, cats, o) => Object.assign({ id, anchor: 'center', fx, fz, size, cats }, o) as SlotDef,\n windowSlot: (id, size, cats, o) => Object.assign({ id, anchor: 'window', size, cats }, o) as SlotDef,\n on: (id, parent, cats, o) => Object.assign({ id, anchor: 'on', on: parent, cats }, o) as SlotDef,\n inside: (id, parent, cats, o) => Object.assign({ id, anchor: 'inside', on: parent, cats }, o) as SlotDef,\n}\n","{\n \"labels\": {\n \"floor_n\": \"Floor {n}\",\n \"parking\": \"Parking\",\n \"garden\": \"Garden\",\n \"backyard\": \"Backyard\",\n \"side_left\": \"Left side\",\n \"side_right\": \"Right side\"\n },\n \"reasons\": {\n \"invalid_parent\": \"invalid parent\",\n \"invalid_side\": \"invalid side\",\n \"blocked_by_door\": \"blocked by a door\",\n \"open_wall\": \"open wall\",\n \"invalid_corner\": \"invalid corner\",\n \"no_window\": \"no window\",\n \"window_outside_room\": \"window outside the room\",\n \"larger_than_room\": \"slot larger than the room\",\n \"unknown_anchor\": \"unknown anchor\"\n },\n \"messages\": {\n \"overlap\": \"Overlap: {a} and {b}\",\n \"door_blocked\": \"Door blocked by {id}\",\n \"gate_blocked\": \"Gate blocked by {id}\",\n \"missing_required\": \"Required item missing: {room}/{slot}\",\n \"zone_violation\": \"Zone {zone}: {rule} is {actual}, limit {limit}\"\n },\n \"ui\": {\n \"title\": \"Floor plan viewer\",\n \"template\": \"Template\",\n \"seed\": \"Seed\",\n \"random_seed\": \"Random\",\n \"state\": \"State\",\n \"style\": \"Style\",\n \"zone\": \"Zone\",\n \"no_zone\": \"No zone (unrestricted)\",\n \"floor\": \"Floor\",\n \"outside\": \"Whole lot\",\n \"language\": \"Language\",\n \"width\": \"Width (m)\",\n \"depth\": \"Depth (m)\",\n \"auto_size\": \"Template default size\",\n \"options\": \"Options\",\n \"opt_floors\": \"Floors\",\n \"opt_elevator\": \"Elevator\",\n \"opt_tier\": \"Tier\",\n \"yes\": \"Yes\",\n \"no\": \"No\",\n \"default\": \"Default\",\n \"show_labels\": \"Labels\",\n \"show_items\": \"Items\",\n \"show_state\": \"State items\",\n \"show_lot\": \"Lot\",\n \"show_grid\": \"Grid\",\n \"legend\": \"Legend\",\n \"summary\": \"Summary\",\n \"rooms\": \"Rooms\",\n \"items\": \"Items\",\n \"state_items\": \"State items\",\n \"missing\": \"Missing required items\",\n \"none\": \"None\",\n \"validation\": \"Validation\",\n \"valid\": \"Valid plan\",\n \"zoning\": \"Zoning\",\n \"adjustments\": \"Adjustments\",\n \"violations\": \"Violations\",\n \"compliant\": \"Compliant with the zone\",\n \"hover\": \"Hover an item for details\",\n \"meters\": \"m\",\n \"use_label\": \"Use\",\n \"unit_floor\": \"Unit floor\",\n \"legend_wall\": \"Wall\",\n \"legend_door\": \"Door\",\n \"legend_window\": \"Window\",\n \"legend_gate\": \"Gate\",\n \"legend_path\": \"Path\",\n \"legend_item\": \"Furniture\",\n \"legend_state\": \"State item (outlined)\",\n \"rule_use\": \"Use not allowed\",\n \"rule_floors\": \"Too many floors\",\n \"rule_height\": \"Too tall\",\n \"rule_setback_front\": \"Front setback too small\",\n \"rule_setback_side\": \"Side setback too small\",\n \"rule_setback_back\": \"Back setback too small\",\n \"rule_min_lot\": \"Lot too small\",\n \"rule_min_frontage\": \"Frontage too narrow\",\n \"rule_coverage\": \"Coverage too high\",\n \"rule_far\": \"Floor area ratio too high\",\n \"rule_permeable\": \"Permeable area too small\",\n \"reason_max_floors\": \"Zone floor limit\",\n \"reason_max_height\": \"Zone height limit\",\n \"reason_setback_front\": \"Zone front setback\",\n \"reason_setback_side\": \"Zone side setback\",\n \"reason_setback_back\": \"Zone back setback\",\n \"reason_permeable_min\": \"Zone permeable area\"\n }\n}\n","{\n \"labels\": {\n \"floor_n\": \"Andar {n}\",\n \"parking\": \"Vaga\",\n \"garden\": \"Jardim\",\n \"backyard\": \"Quintal\",\n \"side_left\": \"Lateral esquerda\",\n \"side_right\": \"Lateral direita\"\n },\n \"reasons\": {\n \"invalid_parent\": \"pai inválido\",\n \"invalid_side\": \"lado inválido\",\n \"blocked_by_door\": \"bloqueado por porta\",\n \"open_wall\": \"parede aberta\",\n \"invalid_corner\": \"canto inválido\",\n \"no_window\": \"sem janela\",\n \"window_outside_room\": \"janela fora do cômodo\",\n \"larger_than_room\": \"slot maior que o cômodo\",\n \"unknown_anchor\": \"âncora desconhecida\"\n },\n \"messages\": {\n \"overlap\": \"Sobreposição: {a} e {b}\",\n \"door_blocked\": \"Porta bloqueada por {id}\",\n \"gate_blocked\": \"Portão bloqueado por {id}\",\n \"missing_required\": \"Item obrigatório ausente: {room}/{slot}\",\n \"zone_violation\": \"Zona {zone}: {rule} é {actual}, limite {limit}\"\n },\n \"ui\": {\n \"title\": \"Visualizador de plantas\",\n \"template\": \"Modelo\",\n \"seed\": \"Semente\",\n \"random_seed\": \"Aleatória\",\n \"state\": \"Estado\",\n \"style\": \"Estilo\",\n \"zone\": \"Zona\",\n \"no_zone\": \"Sem zona (livre)\",\n \"floor\": \"Andar\",\n \"outside\": \"Lote inteiro\",\n \"language\": \"Idioma\",\n \"width\": \"Largura (m)\",\n \"depth\": \"Profundidade (m)\",\n \"auto_size\": \"Tamanho padrão do modelo\",\n \"options\": \"Opções\",\n \"opt_floors\": \"Andares\",\n \"opt_elevator\": \"Elevador\",\n \"opt_tier\": \"Padrão\",\n \"yes\": \"Sim\",\n \"no\": \"Não\",\n \"default\": \"Padrão\",\n \"show_labels\": \"Rótulos\",\n \"show_items\": \"Móveis\",\n \"show_state\": \"Itens de estado\",\n \"show_lot\": \"Lote\",\n \"show_grid\": \"Grade\",\n \"legend\": \"Legenda\",\n \"summary\": \"Resumo\",\n \"rooms\": \"Cômodos\",\n \"items\": \"Móveis\",\n \"state_items\": \"Itens de estado\",\n \"missing\": \"Itens obrigatórios ausentes\",\n \"none\": \"Nenhum\",\n \"validation\": \"Validação\",\n \"valid\": \"Planta válida\",\n \"zoning\": \"Zoneamento\",\n \"adjustments\": \"Ajustes\",\n \"violations\": \"Violações\",\n \"compliant\": \"Em conformidade com a zona\",\n \"hover\": \"Passe o mouse sobre um item para ver detalhes\",\n \"meters\": \"m\",\n \"use_label\": \"Uso\",\n \"unit_floor\": \"Andar da unidade\",\n \"legend_wall\": \"Parede\",\n \"legend_door\": \"Porta\",\n \"legend_window\": \"Janela\",\n \"legend_gate\": \"Portão\",\n \"legend_path\": \"Caminho\",\n \"legend_item\": \"Móvel\",\n \"legend_state\": \"Item de estado (contorno)\",\n \"rule_use\": \"Uso não permitido\",\n \"rule_floors\": \"Andares demais\",\n \"rule_height\": \"Altura excedida\",\n \"rule_setback_front\": \"Recuo frontal insuficiente\",\n \"rule_setback_side\": \"Recuo lateral insuficiente\",\n \"rule_setback_back\": \"Recuo de fundos insuficiente\",\n \"rule_min_lot\": \"Lote pequeno demais\",\n \"rule_min_frontage\": \"Testada estreita demais\",\n \"rule_coverage\": \"Taxa de ocupação excedida\",\n \"rule_far\": \"Coeficiente de aproveitamento excedido\",\n \"rule_permeable\": \"Área permeável insuficiente\",\n \"reason_max_floors\": \"Limite de andares da zona\",\n \"reason_max_height\": \"Limite de altura da zona\",\n \"reason_setback_front\": \"Recuo frontal da zona\",\n \"reason_setback_side\": \"Recuo lateral da zona\",\n \"reason_setback_back\": \"Recuo de fundos da zona\",\n \"reason_permeable_min\": \"Área permeável da zona\"\n }\n}\n","import { applyPatches, removeIds } from '@adatechnology/game-contracts'\nimport type { DeepPartial } from '@adatechnology/game-contracts'\n\nimport { CAR_CLEARANCE, DOOR_CLEARANCE, DOOR_EDGE_CLEARANCE, OVERHEAD_TOP, PLAYER_RADIUS, WALL_THICKNESS, WINDOW_EDGE_CLEARANCE } from './constants'\nimport { findsAnswer, findsFor } from './extensions'\nimport { generate, limitsOf, listTemplates, slots, validate } from './generate'\nimport { overlaps, openingZones } from './geometry'\nimport { registerGroundItems } from './ground-items'\nimport { listLocales, registerLocale, translate } from './locale'\nimport { HIGH_SATURATION, MIN_FABRIC_FLOOR_CONTRAST, MIN_WALL_FLOOR_CONTRAST, hexString, intToHsl, lstar, palette } from './palette'\nimport { blocksWindow, windowZone } from './queries'\nimport {\n createRegistries,\n getDefaultRegistries,\n listStates,\n registerDecorProfile,\n registerFindsProvider,\n registerGroundOverlay,\n registerItem,\n registerItems,\n registerLibrary,\n registerLibraryAlias,\n registerPass,\n registerPaletteStyle,\n registerResultExtension,\n registerRoomColors,\n registerSeedKeys,\n registerState,\n registerStyle,\n registerTemplate,\n registerViewerLayer,\n registerWallTop,\n setStateDistribution,\n withRegistries,\n} from './registry'\nimport type { Registries } from './registry'\nimport { createRng, hashString, mulberry32 } from './rng'\nimport { slotKit } from './slot-kit'\nimport type { FurnitureDef, TemplateDef } from './types'\nimport { checkLot, defineZone, getZone, listZones, registerPermeableGround } from './zoning'\n\nimport enLocale from './locales/en.json'\nimport ptBrLocale from './locales/pt-BR.json'\n\nexport const version = '0.1.0'\n\n/** Registers `packs` and applies `patch` / `remove` over the catalogs, by id. Items are keyed by `type`, templates by `id`. */\nexport type CreateFloorplanOptions = {\n /** Content packs, applied in order: a function `(engine) => void` or an object with `register(engine)`. */\n readonly packs?: readonly FloorplanPack[]\n readonly patch?: { readonly items?: Readonly<Record<string, DeepPartial<FurnitureDef>>>; readonly templates?: Readonly<Record<string, DeepPartial<TemplateDef>>> }\n readonly remove?: { readonly items?: readonly string[]; readonly templates?: readonly string[] }\n}\n\nexport type FloorplanPack = ((engine: FloorplanEngine) => void) | { readonly register: (engine: FloorplanEngine) => void }\n\ntype Keyed = { id: string }\n\nfunction editCatalog<TDef extends object>(catalog: Record<string, TDef>, patch: Readonly<Record<string, DeepPartial<TDef>>> | undefined, remove: readonly string[] | undefined): void {\n if (!patch && !remove) return\n const entries = new Map<string, TDef & Keyed>(Object.entries(catalog).map(([key, definition]) => [key, { ...definition, id: key }]))\n applyPatches(entries, patch as Readonly<Record<string, DeepPartial<TDef & Keyed>>> | undefined)\n removeIds(entries, remove)\n for (const key of Object.keys(catalog)) {\n const edited = entries.get(key)\n if (!edited) delete catalog[key]\n else if (patch && key in patch) {\n const hadId = 'id' in catalog[key]!\n const next: TDef & Partial<Keyed> = { ...edited }\n if (!hadId) delete next.id\n catalog[key] = next\n }\n }\n}\n\nfunction buildEngine(scope: Registries) {\n const scoped = <TFunction extends (...args: never[]) => unknown>(fn: TFunction): TFunction =>\n ((...args: never[]) => withRegistries(scope, () => fn(...args))) as TFunction\n return {\n version,\n generate: scoped(generate),\n slots: scoped(slots),\n validate: scoped(validate),\n palette: scoped(palette),\n limitsOf: scoped(limitsOf),\n listTemplates: scoped(listTemplates),\n listStates: scoped(listStates),\n // content registration\n registerItem: scoped(registerItem),\n registerItems: scoped(registerItems),\n registerLibrary: scoped(registerLibrary),\n registerLibraryAlias: scoped(registerLibraryAlias),\n registerTemplate: scoped(registerTemplate),\n registerStyle: scoped(registerStyle),\n registerPaletteStyle: scoped(registerPaletteStyle),\n registerRoomColors: scoped(registerRoomColors),\n registerDecorProfile: scoped(registerDecorProfile),\n registerPass: scoped(registerPass),\n registerGroundOverlay: scoped(registerGroundOverlay),\n registerWallTop: scoped(registerWallTop),\n registerSeedKeys: scoped(registerSeedKeys),\n registerState: scoped(registerState),\n setStateDistribution: scoped(setStateDistribution),\n registerLocale: scoped(registerLocale),\n registerResultExtension: scoped(registerResultExtension),\n registerFindsProvider: scoped(registerFindsProvider),\n findsFor: scoped(findsFor),\n findsAnswer: scoped(findsAnswer),\n registerViewerLayer: scoped(registerViewerLayer),\n viewerLayers: scope.VIEWER_LAYERS,\n blocksWindow: scoped(blocksWindow),\n // zoning\n defineZone: scoped(defineZone),\n getZone: scoped(getZone),\n listZones: scoped(listZones),\n checkLot: scoped(checkLot),\n registerPermeableGround: scoped(registerPermeableGround),\n // kits and data\n slotKit,\n translate: scoped(translate),\n listLocales: scoped(listLocales),\n templates: scope.TEMPLATES,\n catalog: scope.CATALOG,\n libraries: scope.LIBRARIES,\n styles: scope.STYLES,\n paletteStyles: scope.PALETTE_STYLES,\n createRng,\n mulberry32,\n hashString,\n overlaps,\n windowZone,\n openingZones,\n color: { lstar, hex: hexString, hsl: intToHsl, HIGH_SATURATION, MIN_WALL_FLOOR_CONTRAST, MIN_FABRIC_FLOOR_CONTRAST },\n constants: { WALL_THICKNESS, DOOR_CLEARANCE, PLAYER_RADIUS, DOOR_EDGE_CLEARANCE, WINDOW_EDGE_CLEARANCE, OVERHEAD_TOP, CAR_CLEARANCE },\n }\n}\n\nexport type FloorplanEngine = ReturnType<typeof buildEngine>\n\nfunction seedBase(scope: Registries): void {\n withRegistries(scope, () => {\n registerGroundItems()\n registerPermeableGround('lawn', 'dirt')\n registerLocale('en', enLocale)\n registerLocale('pt-BR', ptBrLocale)\n })\n}\n\n/** An engine of its own: registries, zones and locales are not shared with any other engine on the page. */\nexport function createFloorplan(options: CreateFloorplanOptions = {}): FloorplanEngine {\n const scope = createRegistries()\n seedBase(scope)\n const instance = buildEngine(scope)\n for (const pack of options.packs ?? []) (typeof pack === 'function' ? pack : pack.register)(instance)\n editCatalog(scope.CATALOG, options.patch?.items, options.remove?.items)\n editCatalog(scope.TEMPLATES, options.patch?.templates, options.remove?.templates)\n return instance\n}\n\nlet defaultEngine: FloorplanEngine | undefined\n\n/** The engine the global `engine` stands for, created on first use. Content packs of the old `register(engine)` calls fill this one. */\nexport function defaultFloorplan(): FloorplanEngine {\n if (defaultEngine) return defaultEngine\n seedBase(getDefaultRegistries())\n defaultEngine = buildEngine(getDefaultRegistries())\n return defaultEngine\n}\n","import type { RandomSource } from './types'\n\n/** The page's own seeded generator (mulberry32), so a silhouette drawn from the same seed has the same windows and colours. */\nexport function createSilhouetteRandom(seed: number): RandomSource {\n let state = seed\n return () => {\n state |= 0\n state = (state + 0x6d2b79f5) | 0\n let t = Math.imul(state ^ (state >>> 15), 1 | state)\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n","import type { RandomSource, Silhouette, SilhouettePart, SilhouetteWindow } from './types'\n\nconst ROOT = -1\nconst MAX_BOX_RADIUS = 0.15\nconst BOX_RADIUS_RATIO = 0.22\nconst PLAIN_BOX_RADIUS = 0.012\n\ntype Options = { parent?: number; ry?: number; rz?: number; emissive?: boolean }\n\n/** Rounded-box radius the team page gives a box; below 1.2 cm it is a plain box. */\nexport function boxRadius(width: number, height: number, depth: number): number {\n const radius = Math.min(Math.min(width, height, depth) * BOX_RADIUS_RATIO, MAX_BOX_RADIUS)\n return radius < PLAIN_BOX_RADIUS ? 0 : radius\n}\n\n/** Collects the parts of one silhouette; the generators call it the way the team page calls its own helpers. */\nexport function createSilhouetteBuilder(random: RandomSource) {\n const parts: SilhouettePart[] = []\n const windows: SilhouetteWindow[] = []\n const pick = <T>(list: readonly T[]): T => list[Math.floor(random() * list.length)] as T\n const group = (x: number, y: number, z: number, ry = 0, parent = ROOT): number => parts.push({ shape: 'group', parent, x, y, z, ry }) - 1\n const box = (x: number, y: number, z: number, width: number, height: number, depth: number, color: number, o: Options = {}): void => {\n parts.push({ shape: 'box', parent: o.parent ?? ROOT, x, y: y + height / 2, z, width, height, depth, color, emissive: o.emissive ?? false, ry: o.ry ?? 0, rz: o.rz ?? 0, radius: boxRadius(width, height, depth) })\n }\n const prism = (x: number, y: number, z: number, width: number, height: number, depth: number, color: number, parent = ROOT): void => {\n parts.push({ shape: 'prism', parent, x, y, z, width, height, depth, color, ry: 0 })\n }\n const cylinder = (x: number, y: number, z: number, radiusTop: number, radiusBottom: number, height: number, color: number, parent = ROOT, segments = 14): void => {\n parts.push({ shape: 'cylinder', parent, x, y: y + height / 2, z, radiusTop, radiusBottom, height, color, segments })\n }\n const line = (points: [number, number, number][], color: number, parent = ROOT): void => {\n parts.push({ shape: 'line', parent, points, color })\n }\n const sign = (text: string, x: number, y: number, z: number, width: number, height: number, ry: number, colors: { background: string; foreground: string }, parent = ROOT): void => {\n parts.push({ shape: 'sign', parent, x, y, z, width, height, ry, text, ...colors })\n }\n const fence = (x0: number, z0: number, x1: number, z1: number, height: number, color: number, parent = ROOT): void => {\n const length = Math.hypot(x1 - x0, z1 - z0)\n const count = Math.ceil(length / 3)\n for (let index = 0; index <= count; index++) {\n const t = index / count\n cylinder(x0 + (x1 - x0) * t, 0, z0 + (z1 - z0) * t, 0.05, 0.05, height, color, parent, 5)\n }\n for (const level of [height * 0.35, height * 0.65, height * 0.98]) line([[x0, level, z0], [x1, level, z1]], 0x8a8c8e, parent)\n }\n const finish = (footprint: Silhouette['footprint']): Silhouette => ({ parts, windows, footprint })\n return { random, pick, group, box, prism, cylinder, line, sign, fence, windows, finish }\n}\n\nexport type SilhouetteBuilder = ReturnType<typeof createSilhouetteBuilder>\n","import { createSilhouetteBuilder } from './builder'\nimport { createSilhouetteRandom } from './random'\nimport type { RandomSource, Silhouette } from './types'\n\nconst STOREY_HEIGHT = 3\nconst SHOP_AWNING_HEIGHT = 4.5\nconst WINDOW_COLUMN_WIDTH = 2.6\nconst SHOP_SIGNS = ['FARMÁCIA', 'MAGAZINE', 'LOTÉRICA', 'PADARIA', 'ÓTICA', 'CALÇADOS', 'BAR'] as const\nconst SIGN_COLORS = ['#ffd27a', '#e8dfcf', '#c4483b'] as const\nconst DEFAULT_LIT_CHANCE = 0.07\n\nexport type CityBuildingParams = {\n x: number\n z: number\n width: number\n depth: number\n height: number\n color: number\n /** Chance of a ground-floor shop on both long faces; omitted means none. */\n shopChance?: number\n /** Chance that a window is lit. */\n litChance?: number\n random?: RandomSource\n seed?: number\n}\n\n/** City building: block, roof slab, maybe a vent, maybe a shop front, and window instances on the four faces. */\nexport function createCityBuilding(p: CityBuildingParams): Silhouette {\n const random = p.random ?? createSilhouetteRandom(p.seed ?? 7)\n const b = createSilhouetteBuilder(random)\n const { x, z, width: w, depth: d, height: h } = p\n b.box(x, 0, z, w, h, d, p.color)\n b.box(x, h, z, w + 0.3, 0.35, d + 0.3, 0x2a2a2c)\n if (random() < 0.4) b.cylinder(x + (random() - 0.5) * (w - 3), h + 0.35, z + (random() - 0.5) * (d - 3), 0.8, 0.8, 1.4, 0x4b4540)\n const hasShop = p.shopChance !== undefined && p.shopChance > 0 && random() < p.shopChance\n if (hasShop) {\n for (const face of [1, -1]) {\n const zFace = z + face * (d / 2)\n b.box(x, SHOP_AWNING_HEIGHT, zFace + face * 0.8, w, 0.2, 1.6, 0x2a2a2c)\n b.box(x, 0, zFace + face * 0.03, w * 0.6, 3.5, 0.05, 0x4a4c4e)\n const text = b.pick(SHOP_SIGNS)\n b.sign(text, x, 5.3, zFace + face * 0.12, Math.min(w * 0.7, 8), 1, face > 0 ? 0 : Math.PI, { background: '#1a1a1c', foreground: b.pick(SIGN_COLORS) })\n }\n }\n addWindows(b, p, hasShop ? SHOP_AWNING_HEIGHT : 0)\n return b.finish({ x, z, width: w, depth: d, height: h + 0.35 })\n}\n\nfunction addWindows(b: ReturnType<typeof createSilhouetteBuilder>, p: CityBuildingParams, base: number): void {\n const { x, z, width: w, depth: d, height: h } = p\n const floors = Math.max(1, Math.floor((h - 1) / STOREY_HEIGHT))\n const faces: [number, number, number, number][] = [[0, d / 2 + 0.03, w, 0], [0, -d / 2 - 0.03, w, Math.PI], [w / 2 + 0.03, 0, d, Math.PI / 2], [-w / 2 - 0.03, 0, d, -Math.PI / 2]]\n for (const [ox, oz, faceWidth, ry] of faces) {\n const columns = Math.max(1, Math.floor(faceWidth / WINDOW_COLUMN_WIDTH))\n for (let floor = 0; floor < floors; floor++) {\n const y = base + 1.8 + floor * STOREY_HEIGHT\n for (let column = 0; column < columns; column++) {\n const u = (column - (columns - 1) / 2) * WINDOW_COLUMN_WIDTH\n b.windows.push({ x: ox ? x + ox : x + u, y, z: ox ? z + u : z + oz, ry, width: 1.2, height: 1.4, isLit: b.random() < (p.litChance || DEFAULT_LIT_CHANCE) })\n }\n }\n }\n}\n","import { createSilhouetteBuilder } from './builder'\nimport { createSilhouetteRandom } from './random'\nimport type { RandomSource, Silhouette } from './types'\n\nconst LIT_WINDOW = 0xffb45e\nconst DARK_WINDOW = 0x10151b\nconst DEFAULT_ROOF = 0x5a3a2a\n\ntype Seeded = { random?: RandomSource; seed?: number }\n\nconst randomOf = (o: Seeded): RandomSource => o.random ?? createSilhouetteRandom(o.seed ?? 7)\n\n/** Window colour: a lit one glows (emissive), a dark one is a plain dark pane. */\nconst pane = (isLit: boolean) => ({ color: isLit ? LIT_WINDOW : DARK_WINDOW, emissive: isLit })\n\nexport type TwoStoreyParams = Seeded & { x: number; z: number; width: number; depth: number; color: number; roofColor?: number; ry?: number }\n\n/** Two-storey house with a balcony slab, pitched roof and four windows. */\nexport function createTwoStoreyHouse(p: TwoStoreyParams): Silhouette {\n const b = createSilhouetteBuilder(randomOf(p))\n const { width: w, depth: d } = p\n const g = b.group(p.x, 0, p.z, p.ry)\n b.box(0, 0, 0, w, 6, d, p.color, { parent: g })\n b.prism(0, 6, 0, w + 0.4, 1.4, d + 0.4, p.roofColor ?? DEFAULT_ROOF, g)\n b.box(0, 3.1, d / 2 + 0.5, w * 0.6, 0.15, 1, 0x6a6a66, { parent: g })\n for (const floor of [0, 1]) {\n for (const side of [-1, 1]) {\n const { color, emissive } = pane(b.random() < 0.12)\n b.box(side * w * 0.26, 1.1 + floor * 3, d / 2 + 0.03, 1.1, 1.2, 0.04, color, { parent: g, emissive })\n }\n }\n b.box(0, 0, d / 2 + 0.02, 1, 2.1, 0.05, 0x2a1d14, { parent: g })\n return b.finish({ x: p.x, z: p.z, width: w, depth: d, height: 7.4 })\n}\n\nexport type SlabHouseParams = Seeded & { x: number; z: number; width: number; depth: number; floors: number; color: number }\n\n/** Reinforced-concrete slab house of one to three floors, with water tank, side stair and sometimes rebar starters. */\nexport function createSlabHouse(p: SlabHouseParams): Silhouette {\n const b = createSilhouetteBuilder(randomOf(p))\n const { width: w, depth: d, floors } = p\n const g = b.group(p.x, 0, p.z, 0)\n for (let floor = 0; floor < floors; floor++) {\n const isTop = floor === floors - 1\n b.box(0, floor * 2.9, 0, w, 2.9, d, isTop && b.random() < 0.5 ? 0x9a6a50 : p.color, { parent: g })\n const { color, emissive } = pane(b.random() < 0.1)\n b.box(0, floor * 2.9 + 1.1, d / 2 + 0.03, 1, 1, 0.04, color, { parent: g, emissive })\n }\n b.cylinder(w * 0.25, floors * 2.9, -d * 0.2, 0.55, 0.55, 0.9, 0x2a5aa0, g, 10)\n for (let level = 0; level < floors; level++) b.box(w / 2 + 0.4, level * 2.9, 0, 0.8, 0.18, 1.2, 0x7a7a74, { parent: g })\n if (b.random() < 0.6) for (let index = 0; index < 4; index++) b.box(-w * 0.3 + index * 0.4, floors * 2.9, 0, 0.02, 1, 0.02, 0x8a8a8a, { parent: g })\n return b.finish({ x: p.x, z: p.z, width: w, depth: d, height: floors * 2.9 + 1 })\n}\n\nexport type ColonialParams = Seeded & { x: number; z: number; width: number; color: number; hasDoor: boolean }\n\n/** Colonial terrace house: parapet, roof behind it and a row of doors or windows. */\nexport function createColonialHouse(p: ColonialParams): Silhouette {\n const b = createSilhouetteBuilder(randomOf(p))\n const { width: w } = p\n const g = b.group(p.x, 0, p.z, 0)\n b.box(0, 0, 0, w, 4.2, 10, p.color, { parent: g })\n b.box(0, 4.2, 4.6, w, 0.8, 0.25, p.color, { parent: g })\n b.prism(0, 4.2, -0.4, w, 1.4, 9.6, 0x7a4a32, g)\n const count = Math.max(1, Math.floor(w / 2.2))\n for (let index = 0; index < count; index++) {\n const u = (index - (count - 1) / 2) * 2.2\n const isDoor = index === 0 && p.hasDoor\n const lit = isDoor ? false : b.random() < 0.15\n const color = isDoor ? 0x3a2416 : lit ? LIT_WINDOW : 0x2a3a4a\n b.box(u, 1.0, 5.02, 0.9, 2.0, 0.05, color, { parent: g, emissive: lit })\n }\n return b.finish({ x: p.x, z: p.z, width: w, depth: 10, height: 6 })\n}\n\nexport type ChaletParams = Seeded & { x: number; z: number; color?: number; ry?: number }\n\n/** Wooden chalet on a stone base with a steep roof and a chimney. */\nexport function createChalet(p: ChaletParams): Silhouette {\n const b = createSilhouetteBuilder(randomOf(p))\n const g = b.group(p.x, 0, p.z, p.ry)\n b.box(0, 0, 0, 7, 0.8, 9, 0x5a5650, { parent: g })\n b.box(0, 0.8, 0, 7, 4.2, 9, p.color ?? 0x6b4a30, { parent: g })\n b.prism(0, 5, 0, 7.6, 4, 9.6, 0x2c2a28, g)\n b.box(2.2, 5, -1, 0.8, 4.2, 0.8, 0x5a5650, { parent: g })\n const { color, emissive } = pane(b.random() < 0.3)\n b.box(0, 1.6, 4.52, 1.3, 1.3, 0.04, color, { parent: g, emissive })\n b.box(0, 6.2, 4.6, 1, 1, 0.04, DARK_WINDOW, { parent: g })\n return b.finish({ x: p.x, z: p.z, width: 7.6, depth: 9.6, height: 9 })\n}\n\nexport type CompanyHouseParams = Seeded & { x: number; z: number; color?: number }\n\n/** Company-town house with a low front fence. */\nexport function createCompanyHouse(p: CompanyHouseParams): Silhouette {\n const b = createSilhouetteBuilder(randomOf(p))\n const g = b.group(p.x, 0, p.z, 0)\n b.box(0, 0, 0, 6, 3, 9, p.color ?? 0xd8d0c0, { parent: g })\n b.prism(0, 3, 0, 6.4, 1.6, 9.4, 0x8a4a32, g)\n b.box(0, 0, 4.52, 0.9, 2.1, 0.05, 0x3a2a1c, { parent: g })\n b.box(1.8, 1.1, 4.52, 1, 1, 0.04, DARK_WINDOW, { parent: g })\n b.fence(-3.2, 6.5, 3.2, 6.5, 0.9, 0xe0d8c8, g)\n return b.finish({ x: p.x, z: p.z, width: 6.4, depth: 13, height: 4.6 })\n}\n\nexport type StiltHouseParams = Seeded & { x: number; z: number; color?: number }\n\n/** House on stilts with a ramp-like entry platform. */\nexport function createStiltHouse(p: StiltHouseParams): Silhouette {\n const b = createSilhouetteBuilder(randomOf(p))\n const g = b.group(p.x, 0, p.z, 0)\n for (const a of [-2, 2]) for (const c of [-3, 3]) b.cylinder(a, -1.5, c, 0.12, 0.12, 3.1, 0x3a2a1c, g, 6)\n b.box(0, 1.5, 0, 5, 0.2, 7, 0x5a4630, { parent: g })\n b.box(0, 1.7, 0, 4.6, 2.6, 6.4, p.color ?? 0x6a5a46, { parent: g })\n b.prism(0, 4.3, 0, 5.2, 1.1, 7, 0x7a7a78, g)\n b.box(0, 1.5, 5, 1.2, 0.15, 4, 0x5a4630, { parent: g })\n return b.finish({ x: p.x, z: p.z, width: 5.2, depth: 9, height: 5.4 })\n}\n\nexport type FarmhouseParams = Seeded & { x: number; z: number }\n\n/** Farm house with a long covered porch on six posts. */\nexport function createFarmhouse(p: FarmhouseParams): Silhouette {\n const b = createSilhouetteBuilder(randomOf(p))\n const g = b.group(p.x, 0, p.z, 0)\n b.box(0, 0, 0, 15, 3.2, 11, 0xd8cfb8, { parent: g })\n b.prism(0, 3.2, 0, 17, 2.2, 13, 0x8a4a32, g)\n b.box(0, 0, 6.8, 15, 0.25, 2.6, 0x6a5a46, { parent: g })\n for (let index = 0; index < 6; index++) b.cylinder(-7 + index * 2.8, 0, 7.8, 0.1, 0.1, 3.2, 0x5a4630, g, 6)\n b.box(-3, 1.0, 5.52, 1.2, 1.2, 0.04, LIT_WINDOW, { parent: g, emissive: true })\n return b.finish({ x: p.x, z: p.z, width: 17, depth: 13, height: 5.4 })\n}\n\nexport type DetachedHouseParams = Seeded & { x: number; z: number; width: number; depth: number; color: number; roofColor?: number; ry?: number; isBoarded?: boolean }\n\n/** One-storey detached house; boarded windows get two crossed planks each. */\nexport function createDetachedHouse(p: DetachedHouseParams): Silhouette {\n const b = createSilhouetteBuilder(randomOf(p))\n const { width: w, depth: d } = p\n const g = b.group(p.x, 0, p.z, p.ry)\n b.box(0, 0, 0, w, 3, d, p.color, { parent: g })\n b.prism(0, 3, 0, w + 0.5, 1.6, d + 0.5, p.roofColor ?? DEFAULT_ROOF, g)\n b.box(0, 0, d / 2 + 0.02, 1, 2.1, 0.05, 0x2a1d14, { parent: g })\n for (const side of [-1, 1]) {\n const { color, emissive } = pane(b.random() < 0.15)\n b.box(side * w * 0.28, 1.1, d / 2 + 0.03, 1.1, 1.1, 0.04, color, { parent: g, emissive })\n if (p.isBoarded || b.random() < 0.3) for (const k of [-1, 1]) b.box(side * w * 0.28, 1.5 + k * 0.25, d / 2 + 0.08, 1.3, 0.14, 0.04, 0x6b4a2a, { parent: g, rz: k * 0.15 })\n }\n return b.finish({ x: p.x, z: p.z, width: w + 0.5, depth: d + 0.5, height: 4.6 })\n}\n"],"mappings":"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","names":["slots","r","cl","m","rimRect","process","ceiling","current","limit","palette","rule"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/registry.ts","../src/rng.ts","../src/extensions.ts","../src/constants.ts","../src/geometry.ts","../src/parking.ts","../src/queries.ts","../src/grid.ts","../src/fill.ts","../src/legacy-seeds.ts","../src/context.ts","../src/locale.ts","../src/paths.ts","../src/zoning.ts","../src/plan.ts","../src/palette.ts","../src/slots.ts","../src/generate.ts","../../game-contracts/src/blast-shove.ts","../../game-contracts/src/blast-impulse.ts","../../game-contracts/src/blast-knock.ts","../../game-contracts/src/impact-cost.ts","../../game-contracts/src/impact.ts","../../game-contracts/src/body.ts","../../game-contracts/src/spec.ts","../../game-contracts/src/weapons.ts","../../game-contracts/src/ignition.ts","../../game-contracts/src/seal.ts","../../game-contracts/src/twist.ts","../../game-contracts/src/animation.ts","../../game-contracts/src/tool-animation.ts","../../game-contracts/src/frame.ts","../../game-contracts/src/warn.ts","../../game-contracts/src/registry.ts","../../game-contracts/src/bench.ts","../../game-contracts/src/environment.ts","../../game-contracts/src/categories.ts","../../game-contracts/src/origin.ts","../../game-contracts/src/footprint.ts","../../game-contracts/src/foley.ts","../../game-contracts/src/index.ts","../src/ground-items.ts","../src/slot-kit.ts","../src/locales/en.json","../src/locales/pt-BR.json","../src/instance.ts","../src/silhouettes/random.ts","../src/silhouettes/builder.ts","../src/silhouettes/building.ts","../src/silhouettes/houses.ts"],"sourcesContent":["import { findsAnswer, findsFor } from './extensions'\nimport { generate, limitsOf, listTemplates, slots, validate } from './generate'\nimport { createFloorplan, defaultFloorplan, version } from './instance'\nimport type { CreateFloorplanOptions, FloorplanEngine, FloorplanPack } from './instance'\nimport { listLocales, registerLocale, translate } from './locale'\nimport { palette } from './palette'\nimport {\n registerViewerLayer,\n listStates,\n registerDecorProfile,\n registerFindsProvider,\n registerGroundOverlay,\n registerItem,\n registerItems,\n registerLibrary,\n registerLibraryAlias,\n registerPass,\n registerPaletteStyle,\n registerResultExtension,\n registerRoomColors,\n registerSeedKeys,\n registerState,\n registerStyle,\n registerTemplate,\n registerWallTop,\n setStateDistribution,\n} from './registry'\nimport { createRng, hashString, mulberry32 } from './rng'\nimport { slotKit } from './slot-kit'\nimport { checkLot, defineZone, getZone, listZones, registerPermeableGround } from './zoning'\nimport { overlaps, openingZones } from './geometry'\nimport { blocksWindow, windowZone } from './queries'\n\nexport { version, createFloorplan, defaultFloorplan }\nexport type { CreateFloorplanOptions, FloorplanEngine, FloorplanPack }\n\n/**\n * The global engine. Content packs take it as an argument (`register(engine)`), so that several bundles (ESM or IIFE) fill the same registries.\n * @deprecated use `createFloorplan({ packs, patch, remove })`, an engine of its own, or `defaultFloorplan()` for the shared one.\n */\nexport const engine: FloorplanEngine = defaultFloorplan()\n\nexport {\n generate,\n slots,\n validate,\n palette,\n limitsOf,\n listTemplates,\n listStates,\n registerItem,\n registerItems,\n registerLibrary,\n registerLibraryAlias,\n registerTemplate,\n registerStyle,\n registerPaletteStyle,\n registerRoomColors,\n registerDecorProfile,\n registerPass,\n registerGroundOverlay,\n registerWallTop,\n registerSeedKeys,\n registerState,\n setStateDistribution,\n registerLocale,\n registerResultExtension,\n registerFindsProvider,\n findsFor,\n findsAnswer,\n registerViewerLayer,\n blocksWindow,\n translate,\n listLocales,\n defineZone,\n getZone,\n listZones,\n checkLot,\n registerPermeableGround,\n slotKit,\n createRng,\n mulberry32,\n hashString,\n overlaps,\n windowZone,\n openingZones,\n}\nexport type * from './types'\nexport type { PaletteDraw, PaletteEarly, PaletteStyleDef } from './palette'\nexport type { RecordedSlot } from './generate'\nexport type { ZoneCheckedLot, ZoneCheckedPlan } from './zoning'\nexport * from './silhouettes'\n","import type {\n DecorPass,\n FindsProvider,\n ResultExtensionOptions,\n ResultExtensionRun,\n GroundOverlayRule,\n FurnitureDef,\n ItemInput,\n Json,\n RoomColorDef,\n SlotLibrary,\n StateContext,\n StatePlugin,\n StyleDef,\n TemplateDef,\n ViewerLayer,\n FloorplanLocale,\n ZoneDef,\n} from './types'\nimport type { PaletteStyleDef } from './palette'\n\n/** All content registries of one engine instance. Content packs fill them through the `register*` functions. */\nexport type Registries = {\n CATALOG: Record<string, FurnitureDef>\n LIBRARIES: Record<string, SlotLibrary>\n LIBRARY_ALIAS: Record<string, string>\n TEMPLATES: Record<string, TemplateDef>\n STYLES: Record<string, StyleDef>\n STYLE_ALIAS: Record<string, string>\n PALETTE_STYLES: Record<string, PaletteStyleDef>\n ROOM_COLORS: RoomColorDef[]\n PASSES: { name: string; run: DecorPass }[]\n DECOR_PROFILES: Record<string, Json>\n GROUND_OVERLAYS: GroundOverlayRule[]\n STATE_PLUGINS: Record<string, StatePlugin>\n WALL_TOP_HEIGHTS: Record<string, number>\n SEED_KEYS: { rooms: Record<string, string>; items: Record<string, string> }\n stateDistribution: { weights: Record<string, number> | null; seedKey: string }\n RESULT_EXTENSIONS: ResultExtension[]\n FINDS_PROVIDERS: FindsProvider[]\n VIEWER_LAYERS: ViewerLayer[]\n LOCALES: Record<string, FloorplanLocale>\n ZONES: Record<string, ZoneDef>\n PERMEABLE_GROUNDS: Set<string>\n}\n\nexport const createRegistries = (): Registries => ({\n CATALOG: {},\n LIBRARIES: {},\n LIBRARY_ALIAS: {},\n TEMPLATES: {},\n STYLES: {},\n STYLE_ALIAS: {},\n PALETTE_STYLES: {},\n ROOM_COLORS: [],\n PASSES: [],\n DECOR_PROFILES: {},\n GROUND_OVERLAYS: [],\n STATE_PLUGINS: { normal: { apply: () => [] } },\n WALL_TOP_HEIGHTS: { none: 0 },\n SEED_KEYS: { rooms: {}, items: {} },\n stateDistribution: { weights: null, seedKey: 'state' },\n RESULT_EXTENSIONS: [],\n FINDS_PROVIDERS: [],\n VIEWER_LAYERS: [],\n LOCALES: {},\n ZONES: {},\n PERMEABLE_GROUNDS: new Set(),\n})\n\nlet defaultRegistries: Registries | undefined\nlet activeRegistries: Registries | undefined\n\n/** The registries of the global (deprecated) engine, created on first use. */\nexport const getDefaultRegistries = (): Registries => (defaultRegistries ??= createRegistries())\n\n/** The registries the running call reads: the instance it was made through, or the default. */\nexport const registries = (): Registries => activeRegistries ?? getDefaultRegistries()\n\n/** Runs `run` with `scope` as the registries every module reads. Everything the engine does is synchronous, so the scope cannot leak between instances. */\nexport function withRegistries<TResult>(scope: Registries, run: () => TResult): TResult {\n const previous = activeRegistries\n activeRegistries = scope\n try {\n return run()\n } finally {\n activeRegistries = previous\n }\n}\n\nexport function registerItem(def: ItemInput): FurnitureDef {\n const h = def.h\n const item: FurnitureDef = Object.assign({ front: '+z', window: h <= 0.95, low: h <= 0.5, flat: false, deck: false, rim: 0 }, def) as FurnitureDef\n registries().CATALOG[def.type] = item\n return item\n}\nexport function registerItems(list: ItemInput[]): void {\n for (const d of list) registerItem(d)\n}\n\nexport function registerLibrary(id: string, library: SlotLibrary): void {\n registries().LIBRARIES[id] = library\n}\nexport function registerLibraryAlias(alias: string, id: string): void {\n registries().LIBRARY_ALIAS[alias] = id\n}\n\nexport function registerTemplate<T extends TemplateDef>(t: T): T {\n registries().TEMPLATES[t.id] = t\n return t\n}\n\nexport function registerStyle(style: StyleDef): void {\n registries().STYLES[style.id] = style\n for (const a of style.aliases || []) registries().STYLE_ALIAS[a] = style.id\n}\nexport function registerPaletteStyle(id: string, def: PaletteStyleDef): void {\n registries().PALETTE_STYLES[id] = def\n}\nexport function registerRoomColors(list: RoomColorDef[]): void {\n for (const d of list) {\n const i = registries().ROOM_COLORS.findIndex((x) => x.type === d.type)\n if (i >= 0) registries().ROOM_COLORS.splice(i, 1)\n registries().ROOM_COLORS.push(d)\n }\n registries().ROOM_COLORS.sort((a, b) => a.order - b.order)\n}\n\nexport function registerDecorProfile(styleId: string, profile: Json): void {\n registries().DECOR_PROFILES[styleId] = profile\n}\nexport function registerPass(name: string, run: DecorPass): void {\n const i = registries().PASSES.findIndex((p) => p.name === name)\n if (i >= 0) registries().PASSES[i] = { name, run }\n else registries().PASSES.push({ name, run })\n}\nexport function registerGroundOverlay(rule: GroundOverlayRule): void {\n registries().GROUND_OVERLAYS.push(rule)\n}\nexport function registerWallTop(id: string, height: number): void {\n registries().WALL_TOP_HEIGHTS[id] = height\n}\n/** Legacy RNG stream names for rooms and items, so seeds recorded before the English ids still reproduce. */\nexport function registerSeedKeys(keys: { rooms?: Record<string, string>; items?: Record<string, string> }): void {\n Object.assign(registries().SEED_KEYS.rooms, keys.rooms)\n Object.assign(registries().SEED_KEYS.items, keys.items)\n}\n\n/** Registers a house state. The engine only ships `normal`. */\nexport function registerState(name: string, plugin: StatePlugin): void {\n registries().STATE_PLUGINS[name] = plugin\n}\n/** Default state draw when `options.state` is absent: `{ state: weight }` on its own seeded stream. */\nexport function setStateDistribution(weights: Record<string, number> | null, seedKey = 'state'): void {\n registries().stateDistribution.weights = weights\n registries().stateDistribution.seedKey = seedKey\n}\nexport const listStates = (): string[] => Object.keys(registries().STATE_PLUGINS)\n\nexport function resolveStyleId(id: string | undefined): string {\n const s = id ?? ''\n return registries().STYLE_ALIAS[s] ?? s\n}\nexport function styleOf(id: string): StyleDef {\n return registries().STYLES[id] || registries().STYLES.budget || Object.values(registries().STYLES)[0]\n}\n\nexport type { StateContext }\n\nexport interface ResultExtension {\n name: string\n run: ResultExtensionRun\n after: string[]\n seedKey: string\n}\n\n/** Adds a named piece to every result, after the state and before the zoning report; its output lands in `result[name]`. */\nexport function registerResultExtension(name: string, run: ResultExtensionRun, options: ResultExtensionOptions = {}): void {\n const entry: ResultExtension = { name, run, after: options.after || [], seedKey: options.seedKey ?? name }\n const i = registries().RESULT_EXTENSIONS.findIndex((x) => x.name === name)\n if (i >= 0) registries().RESULT_EXTENSIONS[i] = entry\n else registries().RESULT_EXTENSIONS.push(entry)\n}\n\n/** Registers who answers what a container holds (the item packs, from phase 3 on). */\nexport function registerFindsProvider(provider: FindsProvider): void {\n registries().FINDS_PROVIDERS.push(provider)\n}\n\n/** Adds (or replaces, by id) a layer of the 2D viewer; drawn after the items, before the labels. */\nexport function registerViewerLayer(layer: ViewerLayer): void {\n const i = registries().VIEWER_LAYERS.findIndex((x) => x.id === layer.id)\n if (i >= 0) registries().VIEWER_LAYERS[i] = layer\n else registries().VIEWER_LAYERS.push(layer)\n}\n","/** Seeded random helpers. Same seed and key always produce the same stream. */\n\nexport type Rng = () => number\n\nexport function mulberry32(a: number): Rng {\n return function () {\n a |= 0\n a = (a + 0x6d2b79f5) | 0\n let t = Math.imul(a ^ (a >>> 15), 1 | a)\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n\nexport function hashString(input: string | number): number {\n const s = String(input)\n let h = 1779033703 ^ s.length\n for (let i = 0; i < s.length; i++) {\n h = Math.imul(h ^ s.charCodeAt(i), 3432918353)\n h = (h << 13) | (h >>> 19)\n }\n h = Math.imul(h ^ (h >>> 16), 2246822507)\n h = Math.imul(h ^ (h >>> 13), 3266489909)\n return (h ^ (h >>> 16)) >>> 0\n}\n\n/** Independent stream for a `(seed, key)` pair. */\nexport const createRng = (seed: string | number, key: string): Rng => mulberry32(hashString(seed + '|' + key))\n\n/** Picks a key of `{ key: weight }`. */\nexport function pickWeighted(rng: Rng, weights: Record<string, number>): string {\n const keys = Object.keys(weights)\n let total = 0\n for (const k of keys) total += weights[k]\n let x = rng() * total\n for (const k of keys) {\n x -= weights[k]\n if (x < 0) return k\n }\n return keys[keys.length - 1]\n}\n\n/** Weighted draw without replacement. */\nexport function weightedOrder<T extends { weight: number }>(candidates: T[], rng: Rng): T[] {\n const arr = candidates.slice()\n const out: T[] = []\n while (arr.length) {\n let total = 0\n for (const c of arr) total += c.weight\n let x = rng() * total\n let i = 0\n for (; i < arr.length - 1; i++) {\n x -= arr[i].weight\n if (x < 0) break\n }\n out.push(arr.splice(i, 1)[0])\n }\n return out\n}\n\nexport function shuffle<T>(arr: T[], rng: Rng): T[] {\n const a = arr.slice()\n for (let i = a.length - 1; i > 0; i--) {\n const j = Math.floor(rng() * (i + 1))\n ;[a[i], a[j]] = [a[j], a[i]]\n }\n return a\n}\n","import { registries } from './registry'\nimport type { ResultExtension } from './registry'\nimport { createRng } from './rng'\nimport type { FindsQuery, FindStack, FloorplanOptions, FloorplanResult, Plan } from './types'\n\n/** Extensions in the order they run: registration order, with each one after the ones it names. */\nfunction orderOf(extensions: readonly ResultExtension[]): ResultExtension[] {\n const ordered: ResultExtension[] = []\n const visiting = new Set<string>()\n const visit = (extension: ResultExtension) => {\n if (ordered.includes(extension)) return\n if (visiting.has(extension.name)) throw new Error('Result extensions depend on each other: ' + extension.name)\n visiting.add(extension.name)\n for (const name of extension.after) {\n const before = extensions.find((x) => x.name === name)\n if (before) visit(before)\n }\n visiting.delete(extension.name)\n ordered.push(extension)\n }\n extensions.forEach(visit)\n return ordered\n}\n\n/** Runs the registered extensions and stores each output in `result[name]`. */\nexport function runResultExtensions(plan: Plan, result: FloorplanResult, seed: number | string, options: FloorplanOptions): void {\n for (const extension of orderOf(registries().RESULT_EXTENSIONS)) {\n result[extension.name] = extension.run({ plan, result, seed, rng: createRng(seed, extension.seedKey), options })\n }\n}\n\n/** What a container holds, from the first registered provider that answers (`null` passes to the next); none answering means nothing. */\nexport function findsFor(query: FindsQuery): readonly FindStack[] {\n return answerOf(query) ?? []\n}\n\n/** Like `findsFor`, but `null` when no provider answered, so a pack can fall back to its own default. */\nexport function findsAnswer(query: FindsQuery): readonly FindStack[] | null {\n return answerOf(query)\n}\n\nfunction answerOf(query: FindsQuery): readonly FindStack[] | null {\n for (const provider of registries().FINDS_PROVIDERS) {\n const stacks = provider.findsFor(query)\n if (stacks !== null) return stacks\n }\n return null\n}\n","/** Structural wall thickness in metres. */\nexport const WALL_THICKNESS = 0.15\n/** Half a wall: the gap between a room rectangle and its usable interior. */\nexport const MARGIN = WALL_THICKNESS / 2\nexport const EPS = 1e-6\nexport const TOL = 1e-3\n/** Clear zone in front of doors and gates, in metres. */\nexport const DOOR_CLEARANCE = 0.9\n/** Radius of the player body: a disc this wide must still pass between doors and rooms once the furniture is placed. */\nexport const PLAYER_RADIUS = 0.24\n/** Clear wall from the edge of a door opening to a corner or a junction (measured from the wall axis). */\nexport const DOOR_EDGE_CLEARANCE = 0.12\n/** Clear wall from a window to a corner, a junction or a door. */\nexport const WINDOW_EDGE_CLEARANCE = 0.3\n/** Top of the wall cabinet (it hangs between 1.55 and 2.15 m). */\nexport const OVERHEAD_TOP = 2.15\n/** Room types that may stay without a window. */\nexport const WINDOWLESS_ROOM_TYPES: ReadonlySet<string> = new Set([\n 'stockroom', 'kitchen', 'laundry', 'bathroom', 'void', 'elevator', 'stairs', 'pantry', 'closet', 'corridor', 'hall', 'balcony', 'terrace', 'garage', 'storage', 'porch', 'tent', 'outhouse',\n])\n/** Default clearances of a parked car, in metres (driver side is the left of whoever looks along the front). */\nexport const CAR_CLEARANCE = { driver: 0.8, side: 0.6, end: 0.6 } as const\n","import { EPS, MARGIN, TOL, WALL_THICKNESS } from './constants'\nimport type { PlacedItem, PlanWall, Rect, Room, RoomDef, Vec2 } from './types'\n\nexport const r2 = (x: number): number => Math.round(x * 100) / 100\nexport const clamp = (x: number, a: number, b: number): number => Math.max(a, Math.min(b, x))\nexport const overlaps = (a: Rect, b: Rect, e = EPS): boolean => a[0] < b[2] - e && a[2] > b[0] + e && a[1] < b[3] - e && a[3] > b[1] + e\nexport const inner = (p: Rect): Rect => [p[0] + MARGIN, p[1] + MARGIN, p[2] - MARGIN, p[3] - MARGIN]\nexport const eq = (a: number, b: number): boolean => Math.abs(a - b) < TOL\nexport const inflate = (r: Rect, e: number): Rect => [r[0] - e, r[1] - e, r[2] + e, r[3] + e]\nexport const areaOf = (r: Rect): number => (r[2] - r[0]) * (r[3] - r[1])\nexport const topOf = (m: PlacedItem): number => (m.y || 0) + m.h\n\n/** Footprint of an item of `size` facing `f` (cardinal). */\nexport const extent = (size: Vec2, f: Vec2): Vec2 => (Math.abs(f[1]) === 1 ? [size[0], size[1]] : [size[1], size[0]])\nexport const cardinal = (dx: number, dz: number): Vec2 => (Math.abs(dx) > Math.abs(dz) ? [Math.sign(dx), 0] : [0, Math.sign(dz) || 1])\n\nexport function clearRect(r: Rect, f: Vec2, clearance: number): Rect {\n return f[1] === 1 ? [r[0], r[3], r[2], r[3] + clearance] : f[1] === -1 ? [r[0], r[1] - clearance, r[2], r[1]] : f[0] === 1 ? [r[2], r[1], r[2] + clearance, r[3]] : [r[0] - clearance, r[1], r[0], r[3]]\n}\n\nexport function insideUnion(r: Rect, inners: Rect[]): boolean {\n const e = 1e-4\n const points: Vec2[] = [\n [r[0] + e, r[1] + e],\n [r[2] - e, r[1] + e],\n [r[0] + e, r[3] - e],\n [r[2] - e, r[3] - e],\n [(r[0] + r[2]) / 2, (r[1] + r[3]) / 2],\n ]\n return points.every((p) => inners.some((q) => p[0] >= q[0] - 1e-6 && p[0] <= q[2] + 1e-6 && p[1] >= q[1] - 1e-6 && p[1] <= q[3] + 1e-6))\n}\n\nexport function cutIntervals(intervals: [number, number][], a: number, b: number): [number, number][] {\n const out: [number, number][] = []\n for (const [x, y] of intervals) {\n if (b <= x || a >= y) {\n out.push([x, y])\n continue\n }\n if (a > x) out.push([x, a])\n if (b < y) out.push([b, y])\n }\n return out\n}\n\nexport interface Edge {\n axis: 'u' | 'v'\n pos: number\n a0: number\n a1: number\n}\n\nexport function exteriorEdge(room: Room, side: string, w: number, d: number, c?: number | null): Edge | null {\n const cand: Edge[] = []\n for (const p of room.parts) {\n if (side === 'front' && eq(p[1], 0)) cand.push({ axis: 'u', pos: 0, a0: p[0], a1: p[2] })\n else if (side === 'back' && eq(p[3], d)) cand.push({ axis: 'u', pos: d, a0: p[0], a1: p[2] })\n else if (side === 'left' && eq(p[0], 0)) cand.push({ axis: 'v', pos: 0, a0: p[1], a1: p[3] })\n else if (side === 'right' && eq(p[2], w)) cand.push({ axis: 'v', pos: w, a0: p[1], a1: p[3] })\n }\n if (!cand.length) return null\n if (c != null) {\n const k = cand.find((x) => c >= x.a0 - TOL && c <= x.a1 + TOL)\n if (k) return k\n }\n return cand.sort((x, y) => y.a1 - y.a0 - (x.a1 - x.a0))[0]\n}\n\nexport function sharedEdge(A: Room, B: Room, c?: number | null): Edge | null {\n const cand: Edge[] = []\n for (const pa of A.parts)\n for (const pb of B.parts) {\n let o: [number, number]\n if (eq(pa[2], pb[0]) || eq(pa[0], pb[2])) {\n o = [Math.max(pa[1], pb[1]), Math.min(pa[3], pb[3])]\n if (o[1] - o[0] > TOL) cand.push({ axis: 'v', pos: eq(pa[2], pb[0]) ? pa[2] : pa[0], a0: o[0], a1: o[1] })\n }\n if (eq(pa[3], pb[1]) || eq(pa[1], pb[3])) {\n o = [Math.max(pa[0], pb[0]), Math.min(pa[2], pb[2])]\n if (o[1] - o[0] > TOL) cand.push({ axis: 'u', pos: eq(pa[3], pb[1]) ? pa[3] : pa[1], a0: o[0], a1: o[1] })\n }\n }\n if (!cand.length) return null\n if (c != null) {\n const k = cand.find((x) => c >= x.a0 - TOL && c <= x.a1 + TOL)\n if (k) return k\n }\n return cand.sort((x, y) => y.a1 - y.a0 - (x.a1 - x.a0))[0]\n}\n\nexport function openingZones(u: number, v: number, axis: 'u' | 'v', width: number, depth: number): Rect[] {\n const h = width / 2\n return axis === 'u' ? [[u - h, v - depth, u + h, v], [u - h, v, u + h, v + depth]] : [[u - depth, v - h, u, v + h], [u, v - h, u + depth, v + h]]\n}\nexport const openingDepth = (width: number, leaf: number): number => Math.max(0.9, leaf) + MARGIN\n\n/** Points 0.55 m on each side of an opening. */\nexport function entryPoints(ab: { axis: 'u' | 'v'; u: number; v: number }): Vec2[] {\n return ab.axis === 'u' ? [[ab.u, ab.v - 0.55], [ab.u, ab.v + 0.55]] : [[ab.u - 0.55, ab.v], [ab.u + 0.55, ab.v]]\n}\n\nexport function normalizeRoom(c: Partial<RoomDef> & { id: string; type: string; rect: number[] }, floorIndex: number): Room {\n const parts = [c.rect as number[]].concat(c.parts || []).map((p) => p.map(r2) as Rect)\n return {\n id: c.id,\n type: c.type,\n label: c.label,\n floor: floorIndex,\n parts,\n library: c.library || null,\n without: c.without || [],\n overrides: c.overrides || {},\n extras: c.extras || [],\n slots: c.slots || null,\n link: c.link || null,\n outdoor: !!c.outdoor,\n ceiling: c.ceiling || null,\n seedKey: c.seedKey,\n }\n}\n\n/**\n * Usable parts: each part inset by half a wall on every side, plus, for each stretch where it touches another part of the same room\n * (more than 0.3 m), a strip that reaches the shared edge. The inset stays at the ends of the stretch, where a real wall or corner stands.\n */\nexport function usableParts(room: Room, extra?: number): Rect[] {\n const m = MARGIN + (extra || 0)\n const out: Rect[] = []\n for (const p of room.parts) {\n out.push([p[0] + m, p[1] + m, p[2] - m, p[3] - m])\n for (let k = 0; k < 4; k++) {\n const spans: [number, number][] = []\n for (const q of room.parts) {\n if (q === p) continue\n if (k === 0 && eq(q[2], p[0])) spans.push([Math.max(q[1], p[1]), Math.min(q[3], p[3])])\n else if (k === 2 && eq(q[0], p[2])) spans.push([Math.max(q[1], p[1]), Math.min(q[3], p[3])])\n else if (k === 1 && eq(q[3], p[1])) spans.push([Math.max(q[0], p[0]), Math.min(q[2], p[2])])\n else if (k === 3 && eq(q[1], p[3])) spans.push([Math.max(q[0], p[0]), Math.min(q[2], p[2])])\n }\n spans.sort((x, y) => x[0] - y[0])\n const merged: [number, number][] = []\n for (const span of spans) {\n const last = merged[merged.length - 1]\n if (last && span[0] <= last[1] + TOL) last[1] = Math.max(last[1], span[1])\n else merged.push([span[0], span[1]])\n }\n for (const [a, b] of merged) {\n if (b - a <= 0.3) continue\n const x0 = a + m\n const x1 = b - m\n if (x1 <= x0) continue\n if (k === 0) out.push([p[0], x0, p[0] + m, x1])\n else if (k === 2) out.push([p[2] - m, x0, p[2], x1])\n else if (k === 1) out.push([x0, p[1], x1, p[1] + m])\n else out.push([x0, p[3] - m, x1, p[3]])\n }\n }\n }\n return out\n}\n\nexport const inRect = (room: Room, u: number, v: number): boolean => room.parts.some((p) => u > p[0] + EPS && u < p[2] - EPS && v > p[1] + EPS && v < p[3] - EPS)\n\nexport interface WallBuildDoor {\n axis: 'u' | 'v'\n pos: number\n at: number\n width: number\n}\n\n/** Walls of one storey, split where rooms meet and cut where doors open. */\nexport function buildWalls(rooms: Room[], doors: WallBuildDoor[], openPairs: [string, string][], floorIndex: number): PlanWall[] {\n const groups: Record<string, { axis: 'u' | 'v'; pos: number; es: { a: number; b: number; id: string; side: number }[] }> = {}\n const add = (axis: 'u' | 'v', pos: number, a: number, b: number, id: string, side: number) => {\n const k = axis + '|' + pos.toFixed(2)\n ;(groups[k] = groups[k] || { axis, pos, es: [] }).es.push({ a, b, id, side })\n }\n for (const c of rooms)\n for (const p of c.parts) {\n add('u', p[1], p[0], p[2], c.id, 1)\n add('u', p[3], p[0], p[2], c.id, -1)\n add('v', p[0], p[1], p[3], c.id, 1)\n add('v', p[2], p[1], p[3], c.id, -1)\n }\n const par = (x: string, y: string) => openPairs.some((o) => (o[0] === x && o[1] === y) || (o[0] === y && o[1] === x))\n const typeOf: Record<string, string> = {}\n for (const c of rooms) typeOf[c.id] = c.type\n const out: PlanWall[] = []\n for (const g of Object.values(groups)) {\n const breaks = [...new Set(g.es.flatMap((e) => [r2(e.a), r2(e.b)]))].sort((x, y) => x - y)\n const segs: { A: string; B: string; p: number; q: number }[] = []\n for (let i = 0; i < breaks.length - 1; i++) {\n const p = breaks[i]\n const q = breaks[i + 1]\n const m = (p + q) / 2\n const after = g.es.find((e) => e.side === 1 && m > e.a && m < e.b)\n const before = g.es.find((e) => e.side === -1 && m > e.a && m < e.b)\n if (!after && !before) continue\n const A = before ? before.id : 'outside'\n const B = after ? after.id : 'outside'\n if (A === B || (A !== 'outside' && B !== 'outside' && par(A, B))) continue\n const last = segs[segs.length - 1]\n if (last && last.A === A && last.B === B && eq(last.q, p)) last.q = q\n else segs.push({ A, B, p, q })\n }\n for (const s of segs) {\n let pieces: [number, number][] = [[s.p, s.q]]\n for (const pt of doors) {\n if (pt.axis !== g.axis || !eq(pt.pos, g.pos)) continue\n const c0 = pt.at - pt.width / 2\n const c1 = pt.at + pt.width / 2\n const n: [number, number][] = []\n for (const [x, y] of pieces) {\n if (c1 <= x + TOL || c0 >= y - TOL) {\n n.push([x, y])\n continue\n }\n if (c0 > x + TOL) n.push([x, c0])\n if (c1 < y - TOL) n.push([c1, y])\n }\n pieces = n\n }\n for (const [x, y] of pieces) {\n const isOpen = (t: string) => t === 'balcony' || t === 'terrace' || t === 'porch'\n const isVoid = typeOf[s.A] === 'void' || typeOf[s.B] === 'void'\n if (isVoid && (s.A === 'outside' || s.B === 'outside')) continue\n const railing = isVoid || (isOpen(typeOf[s.A]) && s.B === 'outside') || (isOpen(typeOf[s.B]) && s.A === 'outside')\n out.push({\n floor: floorIndex,\n axis: g.axis,\n u0: g.axis === 'u' ? x : g.pos,\n v0: g.axis === 'u' ? g.pos : x,\n u1: g.axis === 'u' ? y : g.pos,\n v1: g.axis === 'u' ? g.pos : y,\n thickness: WALL_THICKNESS,\n sides: [s.A, s.B],\n exterior: s.A === 'outside' || s.B === 'outside',\n type: railing ? 'railing' : 'wall',\n h: railing ? 1.1 : 0,\n })\n }\n }\n }\n return out\n}\n","import { extent } from './geometry'\nimport type { CarClearance, FurnitureDef, Rect, Slot, Vec2 } from './types'\n\nconst STEP = 0.05\nconst MAX_CANDIDATES = 80\n\n/**\n * Where a car may stand in a parking slot: `rect` is the car, `clear` the car plus the space it must keep from walls\n * (the driver side, on the left of whoever looks along the front, keeps more than the passenger side). Candidates are sorted by\n * their distance to the slot centre; the car always stays whole inside the zone.\n */\nexport function carCandidates(slot: Slot, item: FurnitureDef, car: CarClearance): { rect: Rect; clear: Rect }[] {\n const front: Vec2 = [slot.frontU, slot.frontV]\n if (!slot._cell) throw new Error('Slot without a cell: ' + slot.id)\n const zone: Rect = slot._cell.R\n const alongV = Math.abs(front[1]) === 1\n const [extentU, extentV] = extent([item.w, item.d], front)\n const across = alongV ? extentU : extentV\n const along = alongV ? extentV : extentU\n const a = alongV ? 0 : 1\n const b = alongV ? 1 : 0\n const driverSign = alongV ? front[1] : -front[0]\n const frontSign = alongV ? front[1] : front[0]\n const lowClear = driverSign < 0 ? car.driver : car.side\n const highClear = driverSign < 0 ? car.side : car.driver\n const lo = zone[a] + lowClear\n const hi = zone[a + 2] - highClear - across\n const alongLo = zone[b] + car.end\n const alongHi = zone[b + 2] - car.end - along\n if (hi < lo - 1e-6 || alongHi < alongLo - 1e-6) return []\n const preferred = (alongV ? slot.x : slot.z) - across / 2\n const alongStart = frontSign < 0 ? alongHi : alongLo\n const positions: number[] = []\n for (let p = lo; p <= hi + 1e-6; p += STEP) positions.push(Math.min(p, hi))\n positions.sort((x, y) => Math.abs(x - preferred) - Math.abs(y - preferred))\n return positions.slice(0, MAX_CANDIDATES).map((p) => {\n const rect: Rect = alongV ? [p, alongStart, p + across, alongStart + along] : [alongStart, p, alongStart + along, p + across]\n const clear: Rect = alongV ? [p - lowClear, alongStart - car.end, p + across + highClear, alongStart + along + car.end] : [alongStart - car.end, p - lowClear, alongStart + along + car.end, p + across + highClear]\n return { rect, clear }\n })\n}\n","import { EPS, MARGIN, OVERHEAD_TOP } from './constants'\nimport { eq, inRect } from './geometry'\nimport type { FurnitureDef, Plan, PlanOpening, PlanWindow, Rect, Room } from './types'\n\n/** Door and path zones of a storey (storey -1 is the lot). */\nexport function zonesOfFloor(plan: Plan, floorIndex: number): Rect[] {\n const out: Rect[] = []\n if (floorIndex >= 0) {\n for (const p of plan.doors) if (p.floor === floorIndex) out.push(...p.zones)\n } else {\n for (const p of plan.doors) if (p.floor === 0 && p.exterior) out.push(...p.zones)\n for (const g of plan.gates) out.push(...g.zones)\n for (const c of plan.paths) out.push(...c.rects)\n out.push(...plan.reservations)\n }\n return out\n}\n\nexport function openingsOfFloor(plan: Plan, floorIndex: number): PlanOpening[] {\n if (floorIndex >= 0) return plan.doors.filter((p) => p.floor === floorIndex)\n return (plan.doors.filter((p) => p.floor === 0 && p.exterior) as PlanOpening[]).concat(plan.gates)\n}\n\n/** Keep-out zone of a window (inside, or outside for the lot). */\nexport function windowZone(j: Pick<PlanWindow, 'width' | 'side' | 'u' | 'v' | 'axis'>, outside?: boolean): Rect {\n const h = j.width / 2 + 0.1\n const depth = 0.5\n let n: [number, number]\n if (j.side === 'front') n = [0, 1]\n else if (j.side === 'back') n = [0, -1]\n else if (j.side === 'left') n = [1, 0]\n else n = [-1, 0]\n if (outside) n = [-n[0], -n[1]]\n const u = j.u\n const v = j.v\n if (j.axis === 'u') return n[1] > 0 ? [u - h, v - MARGIN, u + h, v + depth] : [u - h, v - depth, u + h, v + MARGIN]\n return n[0] > 0 ? [u - MARGIN, v - h, u + depth, v + h] : [u - depth, v - h, u + MARGIN, v + h]\n}\n\n/** `overheadOff`: the counter sits under the window without its wall cabinet. */\nexport function blocksWindow(it: Pick<FurnitureDef, 'window' | 'overhead' | 'windowHeight'> & { h: number }, win: Pick<PlanWindow, 'y0'>, overheadOff?: boolean): boolean {\n const height = Math.max(it.h, it.windowHeight || 0, it.overhead && !overheadOff ? OVERHEAD_TOP : 0)\n return !it.window || it.h > 1.0 + EPS || height > win.y0 - 0.05 + EPS\n}\n\nexport function windowsOfRoom(plan: Plan, room: Room): PlanWindow[] {\n if (!room.outdoor) return plan.windows.filter((j) => j.room === room.id)\n return plan.windows.filter(\n (j) =>\n j.floor === 0 &&\n room.parts.some((p) => {\n if (j.side === 'front') return eq(p[3], j.pos) && j.u >= p[0] && j.u <= p[2]\n if (j.side === 'back') return eq(p[1], j.pos) && j.u >= p[0] && j.u <= p[2]\n if (j.side === 'left') return eq(p[2], j.pos) && j.v >= p[1] && j.v <= p[3]\n return eq(p[0], j.pos) && j.v >= p[1] && j.v <= p[3]\n }),\n )\n}\n\nexport function roomAt(plan: Plan, u: number, v: number, floorIndex: number): Room | null {\n const list = floorIndex < 0 ? plan.zones : plan.rooms\n return list.find((c) => c.floor === floorIndex && inRect(c, u, v)) || null\n}\n\nexport function isOpenSide(plan: Plan, room: Room, pu: number, pv: number): boolean {\n const o = roomAt(plan, pu, pv, room.floor)\n if (!o) return false\n if (o.id === room.id) return true\n if (room.outdoor) return true\n return (plan.openPairs[room.floor] || []).some((x) => (x[0] === room.id && x[1] === o.id) || (x[1] === room.id && x[0] === o.id))\n}\n","import { MARGIN } from './constants'\nimport { entryPoints, eq, inRect, inner, sharedEdge, usableParts } from './geometry'\nimport { openingsOfFloor } from './queries'\nimport type { Plan, Rect, Room, WalkGrid } from './types'\n\nexport type Grid = WalkGrid\n\n/** Wall bodies of a storey (the wall line plus half a wall each side); a wall end that stops at a door opening has no extension there. */\nfunction wallBodies(plan: Plan, floor: number): Rect[] {\n const cache = (plan.wallBodies = plan.wallBodies || {})\n if (cache[floor]) return cache[floor]\n const doors = plan.doors.filter((p) => p.floor === floor)\n return (cache[floor] = plan.walls\n .filter((p) => p.floor === floor && (p.type === 'wall' || p.type === 'railing'))\n .map((p) => {\n const a0 = p.axis === 'u' ? p.u0 : p.v0\n const a1 = p.axis === 'u' ? p.u1 : p.v1\n const pos = p.axis === 'u' ? p.v0 : p.u0\n const atDoor = (x: number) => doors.some((q) => q.axis === p.axis && eq(q.pos, pos) && (eq(q.at - q.width / 2, x) || eq(q.at + q.width / 2, x)))\n const e0 = atDoor(a0) ? 0 : MARGIN\n const e1 = atDoor(a1) ? 0 : MARGIN\n return (p.axis === 'u' ? [a0 - e0, pos - MARGIN, a1 + e1, pos + MARGIN] : [pos - MARGIN, a0 - e0, pos + MARGIN, a1 + e1]) as Rect\n }))\n}\n\n/**\n * Walkability grid of a room (10 cm cells inside, 30 cm outside). Indoors a cell is walkable only when a player body of `radius`\n * fits between it and the walls. `ignored` lists opening ids to leave out of the entries.\n */\nexport function createGrid(plan: Plan, room: Room, ignored?: Set<string> | null, radius: number = plan.playerRadius): Grid {\n const gs = room.outdoor ? 0.3 : 0.1\n let u0 = 1e9\n let v0 = 1e9\n let u1 = -1e9\n let v1 = -1e9\n for (const p of room.parts) {\n u0 = Math.min(u0, p[0])\n v0 = Math.min(v0, p[1])\n u1 = Math.max(u1, p[2])\n v1 = Math.max(v1, p[3])\n }\n const nx = Math.ceil((u1 - u0) / gs)\n const nz = Math.ceil((v1 - v0) / gs)\n const insideCells = new Uint8Array(nx * nz)\n const insets = room.outdoor ? usableParts(room, 0.08) : room.parts\n // only the walls within reach of the room's box can be closer than the player's body to one of its cells (a tower floor has hundreds of them)\n const bodies = room.outdoor ? null : wallBodies(plan, room.floor).filter((r) => r[0] - radius <= u1 && r[2] + radius >= u0 && r[1] - radius <= v1 && r[3] + radius >= v0)\n const tooClose = (u: number, v: number) =>\n (bodies as Rect[]).some((r) => {\n const dx = Math.max(r[0] - u, 0, u - r[2])\n const dz = Math.max(r[1] - v, 0, v - r[3])\n return dx * dx + dz * dz < radius * radius - 1e-9\n })\n for (let j = 0; j < nz; j++)\n for (let i = 0; i < nx; i++) {\n const u = u0 + (i + 0.5) * gs\n const v = v0 + (j + 0.5) * gs\n if (insets.some((r) => u >= r[0] && u <= r[2] && v >= r[1] && v <= r[3]) && (room.outdoor || !tooClose(u, v))) insideCells[j * nx + i] = 1\n }\n const entries: [number, number][] = []\n for (const ab of openingsOfFloor(plan, room.floor))\n if (!(ignored && ignored.has(ab.id)))\n for (const pt of entryPoints(ab)) {\n if (!inRect(room, pt[0], pt[1])) continue\n const i = Math.floor((pt[0] - u0) / gs)\n const j = Math.floor((pt[1] - v0) / gs)\n if (i >= 0 && j >= 0 && i < nx && j < nz && insideCells[j * nx + i]) entries.push([i, j])\n }\n if (!room.outdoor)\n for (const pair of plan.openPairs[room.floor] || []) {\n const otherId = pair[0] === room.id ? pair[1] : pair[1] === room.id ? pair[0] : null\n const other = otherId && plan.rooms.find((c) => c.id === otherId && c.floor === room.floor)\n if (!other) continue\n const edge = sharedEdge(room, other, null)\n if (!edge || edge.a1 - edge.a0 > 2.0) continue\n const mid = (edge.a0 + edge.a1) / 2\n for (const offset of [-0.4, 0.4]) {\n const pt = edge.axis === 'u' ? [mid, edge.pos + offset] : [edge.pos + offset, mid]\n if (!inRect(room, pt[0], pt[1])) continue\n const i = Math.floor((pt[0] - u0) / gs)\n const j = Math.floor((pt[1] - v0) / gs)\n if (i >= 0 && j >= 0 && i < nx && j < nz && insideCells[j * nx + i]) entries.push([i, j])\n }\n }\n const R = inner(room.parts[0])\n return { gs, u0, v0, nx, nz, inside: insideCells, entries, center: [(R[0] + R[2]) / 2, (R[1] + R[3]) / 2] }\n}\n\n/** True when the room centre and every entry stay connected once `solids` (inflated) are blocked. */\nexport function reachable(g: Grid, solids: Rect[], inflation: number): boolean {\n const { gs, u0, v0, nx, nz, inside } = g\n const blocked = new Uint8Array(nx * nz)\n for (const r of solids) {\n const i0 = Math.max(0, Math.floor((r[0] - inflation - u0) / gs))\n const i1 = Math.min(nx - 1, Math.floor((r[2] + inflation - u0) / gs))\n const j0 = Math.max(0, Math.floor((r[1] - inflation - v0) / gs))\n const j1 = Math.min(nz - 1, Math.floor((r[3] + inflation - v0) / gs))\n for (let j = j0; j <= j1; j++)\n for (let i = i0; i <= i1; i++) {\n const u = u0 + (i + 0.5) * gs\n const v = v0 + (j + 0.5) * gs\n if (u > r[0] - inflation && u < r[2] + inflation && v > r[1] - inflation && v < r[3] + inflation) blocked[j * nx + i] = 1\n }\n }\n let best = -1\n let bestDist = 1e9\n for (let j = 0; j < nz; j++)\n for (let i = 0; i < nx; i++) {\n const k = j * nx + i\n if (!inside[k] || blocked[k]) continue\n const dist = Math.hypot(u0 + (i + 0.5) * gs - g.center[0], v0 + (j + 0.5) * gs - g.center[1])\n if (dist < bestDist) {\n bestDist = dist\n best = k\n }\n }\n if (best < 0) return false\n if (!g.entries.length) return true\n for (const [i, j] of g.entries) if (blocked[j * nx + i]) return false\n const visited = new Uint8Array(nx * nz)\n const queue = new Int32Array(nx * nz)\n let h = 0\n let t = 0\n const s = g.entries[0][1] * nx + g.entries[0][0]\n visited[s] = 1\n queue[t++] = s\n while (h < t) {\n const k = queue[h++]\n const i = k % nx\n const j = (k - i) / nx\n for (const [di, dj] of [[1, 0], [-1, 0], [0, 1], [0, -1]]) {\n const a = i + di\n const b = j + dj\n if (a < 0 || b < 0 || a >= nx || b >= nz) continue\n const q = b * nx + a\n if (visited[q] || !inside[q] || blocked[q]) continue\n visited[q] = 1\n queue[t++] = q\n }\n }\n if (!visited[best]) return false\n for (const [i, j] of g.entries) if (!visited[j * nx + i]) return false\n return true\n}\n","import { EPS } from './constants'\nimport { carCandidates } from './parking'\nimport { clearRect, extent, insideUnion, overlaps, r2, usableParts } from './geometry'\nimport { createGrid, reachable } from './grid'\nimport { blocksWindow, windowZone, windowsOfRoom, zonesOfFloor } from './queries'\nimport { registries } from './registry'\nimport { weightedOrder } from './rng'\nimport type { Rng } from './rng'\nimport type { FurnitureDef, PlacedItem, Plan, Rect, Room, Slot, Vec2, Weights } from './types'\n\nfunction candidatesOf(cats: Weights): { it: FurnitureDef; weight: number }[] {\n const out: { it: FurnitureDef; weight: number }[] = []\n for (const [cat, weight] of Object.entries(cats)) {\n const exact = cat[0] === '='\n const its = Object.values(registries().CATALOG).filter((i) => !i.decor && (exact ? i.type === cat.slice(1) : !i.exactOnly && (i.category === cat || i.type === cat)))\n for (const it of its) out.push({ it, weight: weight / its.length })\n }\n return out\n}\n\nfunction itemRect(slot: Slot, it: FurnitureDef, shift: number): Rect {\n const c = slot._cell\n if (!c) throw new Error('Slot without a cell: ' + slot.id)\n const f: Vec2 = c.f\n const [extentU, extentV] = extent([it.w, it.d], f)\n const R: Rect = c.R\n // centre without rounding\n let u0 = (c.rect ? (c.rect[0] + c.rect[2]) / 2 : slot.x) - extentU / 2\n let v0 = (c.rect ? (c.rect[1] + c.rect[3]) / 2 : slot.z) - extentV / 2\n if (shift) {\n if (slot.side === 'left' || slot.side === 'right') v0 += shift\n else u0 += shift\n }\n for (const s of c.enclosed) {\n if (s === 'left') u0 = R[0]\n else if (s === 'right') u0 = R[2] - extentU\n else if (s === 'front') v0 = R[1]\n else if (s === 'back') v0 = R[3] - extentV\n }\n return [u0, v0, u0 + extentU, v0 + extentV]\n}\n\n/** Radius of the relaxed pass: a required item that did not fit settles for a narrower walkway. */\nconst RELAXED_RADIUS = 0.12\n\nconst MESH_FRONT: Record<string, Vec2> = { '+z': [0, 1], '-z': [0, -1], '+x': [1, 0], '-x': [-1, 0] }\n\n/** Rotation that makes a mesh whose front is `front` face `f`. */\nexport function rotationFor(f: Vec2, front: string): number {\n const meshFront = MESH_FRONT[front] || [0, 1]\n let ry = Math.atan2(f[0], f[1]) - Math.atan2(meshFront[0], meshFront[1])\n if (ry > Math.PI + EPS) ry -= 2 * Math.PI\n if (ry < -Math.PI - EPS) ry += 2 * Math.PI\n return r2(ry)\n}\n\n/** Fills the slots of one room with catalogue items, honouring clearances, doors, windows and reachability. */\nexport function fillRoom(plan: Plan, room: Room, slots: Slot[], rng: Rng): { items: PlacedItem[]; missing: { room: string; slot: string }[] } {\n const items: PlacedItem[] = []\n const missing: { room: string; slot: string }[] = []\n const state: Record<string, PlacedItem> = {}\n const solids: Rect[] = []\n const reserves: Rect[] = []\n const rims: Rect[] = []\n const inners = usableParts(room, 0)\n const grid = createGrid(plan, room)\n const relaxedGrid = room.outdoor ? grid : createGrid(plan, room, null, RELAXED_RADIUS)\n const zones = zonesOfFloor(plan, room.floor)\n const windowZones = windowsOfRoom(plan, room).map((j) => ({ z: windowZone(j, room.outdoor), j }))\n const inflation = room.outdoor ? 0.15 : plan.playerRadius\n interface Unit {\n group: string | null\n members: Slot[]\n required?: boolean\n }\n const units: Unit[] = []\n const seen: Record<string, Unit> = {}\n for (const s of slots) {\n if (s.group) {\n if (seen[s.group]) {\n seen[s.group].members.push(s)\n continue\n }\n const u: Unit = { group: s.group, members: [s] }\n seen[s.group] = u\n units.push(u)\n } else units.push({ group: null, members: [s] })\n }\n for (const u of units) u.required = u.members.some((m) => m.required)\n const queue = units.filter((u) => u.required).concat(units.filter((u) => !u.required))\n const dependencies = (u: Unit) =>\n u.members\n .flatMap((m) => [m.requires, m.on])\n .filter(Boolean)\n .filter((id) => slots.some((s) => s.id === id && !u.members.includes(s)))\n const done = new Set<string>()\n const ready = (u: Unit) => dependencies(u).every((id) => done.has(id as string))\n const make = (s: Slot, it: FurnitureDef, r: Rect, parent: PlacedItem | null, overheadOff?: boolean) => {\n const f: Vec2 = [s.frontU, s.frontV]\n const id = room.id + '.' + s.id\n const m: PlacedItem = {\n id,\n type: it.type,\n category: it.category,\n x: r2((r[0] + r[2]) / 2),\n z: r2((r[1] + r[3]) / 2),\n ry: rotationFor(f, it.front),\n w: it.w,\n d: it.d,\n h: it.h,\n y: parent ? r2((parent.y || 0) + parent.h) : 0,\n frontU: f[0],\n frontV: f[1],\n room: room.id,\n floor: room.floor,\n outdoor: !!room.outdoor,\n slot: s.id,\n on: parent ? s.on : null,\n mode: parent ? (s.anchor === 'inside' ? 'inside' : 'on') : null,\n clearance: s.clearance,\n flat: it.flat,\n low: it.low,\n aabb: r.map(r2) as Rect,\n _r: r,\n _seedId: registries().SEED_KEYS.items[id] ?? id,\n }\n if (it.overhead) m.overhead = !overheadOff\n if (it.category === 'car') {\n m.driver = [f[1], -f[0]]\n m.carClearance = plan.carClearance\n }\n if (parent && s.anchor === 'inside') m.y = r2(parent.y || 0)\n if (room.link) m.link = { from: room.link[0], to: room.link[1] }\n state[s.id] = m\n items.push(m)\n return m\n }\n const tryFit = (s: Slot, relax: boolean, overheadOff?: boolean): PlacedItem | null => {\n const cands = weightedOrder(candidatesOf(s.cats), rng)\n if (s.anchor === 'on' || s.anchor === 'inside') {\n const parent = state[s.on as string]\n if (!parent) return null\n for (const { it } of cands) {\n if (it.w > parent.w + EPS || it.d > parent.d + EPS) continue\n const f: Vec2 = [parent.frontU ?? 0, parent.frontV ?? 1]\n const r: Rect = parent.aabb\n const [extentU, extentV] = extent([it.w, it.d], f)\n const cu = (r[0] + r[2]) / 2 - f[0] * (parent.d / 2 - it.d / 2)\n const cv = (r[1] + r[3]) / 2 - f[1] * (parent.d / 2 - it.d / 2)\n return make(s, it, [cu - extentU / 2, cv - extentV / 2, cu + extentU / 2, cv + extentV / 2], parent)\n }\n return null\n }\n for (const { it } of cands) {\n if (it.w > s.w + EPS || it.d > s.d + EPS) continue\n const f: Vec2 = [s.frontU, s.frontV]\n const slide = s.anchor === 'wall' ? (s.slide == null ? 2.0 : s.slide) : 0\n const shifts = [0]\n for (let k = 1; k * 0.1 <= slide + 1e-9; k++) shifts.push(k * 0.1, -k * 0.1)\n let found: { rect: Rect; cl?: Rect | null; rimRect?: Rect | null } | null = null\n const car = it.category === 'car' && !relax\n const tries: { rect: Rect; clear?: Rect }[] = car ? carCandidates(s, it, plan.carClearance) : shifts.map((shift) => ({ rect: itemRect(s, it, shift) }))\n for (const attempt of tries) {\n const r = attempt.rect\n if (!insideUnion(r, inners)) continue\n if (car && (!insideUnion(attempt.clear as Rect, inners) || solids.some((o) => overlaps(attempt.clear as Rect, o)))) continue\n if (it.flat) {\n found = { rect: r }\n break\n }\n if (zones.some((z) => overlaps(r, z))) continue\n if (windowZones.some(({ z, j }) => blocksWindow(it, j, overheadOff) && overlaps(r, z))) continue\n if (solids.some((o) => overlaps(r, o))) continue\n if (!it.deck && rims.some((a) => overlaps(r, a))) continue\n let cl: Rect | null = car ? (attempt.clear as Rect) : null\n if (!car && !relax && s.clearance > 0 && !it.low) {\n cl = clearRect(r, f, s.clearance)\n if (!insideUnion(cl, inners)) continue\n if (items.some((m) => !m.low && !m.flat && !m.on && overlaps(cl as Rect, m._r ?? m.aabb))) continue\n }\n if (!it.low && reserves.some((q) => overlaps(r, q))) continue\n let rimRect: Rect | null = null\n if (it.rim) {\n rimRect = [r[0] - it.rim, r[1] - it.rim, r[2] + it.rim, r[3] + it.rim]\n if (!insideUnion(rimRect, inners) || solids.some((o) => overlaps(rimRect as Rect, o)) || zones.some((z) => overlaps(rimRect as Rect, z))) continue\n }\n if (!(relax ? reachable(relaxedGrid, solids.concat([r]), RELAXED_RADIUS) : reachable(grid, solids.concat([r]), inflation))) continue\n found = { rect: r, cl, rimRect }\n break\n }\n if (!found) continue\n const { rect: r, cl, rimRect } = found\n if (it.flat) return make(s, it, r, null)\n const m = make(s, it, r, null, overheadOff)\n if (cl) reserves.push(cl)\n if (rimRect) rims.push(rimRect)\n solids.push(r)\n return m\n }\n return null\n }\n const process = (u: Unit) => {\n const pr = u.members[0].chance as number\n const x = rng()\n const arr = u.members.slice()\n const members: Slot[] = []\n while (arr.length) members.push(arr.splice(arr.length > 1 ? Math.floor(rng() * arr.length) : 0, 1)[0])\n const applicable = members.filter((m) => m.valid && (!m.requires || state[m.requires]) && (!m.on || state[m.on]))\n if (!u.required && x >= pr) return\n let ok = false\n for (const m of applicable) {\n if (tryFit(m, false)) {\n ok = true\n break\n }\n }\n if (!ok)\n for (const m of applicable) {\n if (tryFit(m, false, true)) {\n ok = true\n break\n }\n }\n if (!ok && u.required)\n for (const m of applicable) {\n if (tryFit(m, true, true)) {\n ok = true\n break\n }\n }\n if (!ok && u.required && (applicable.length || !u.members.some((m) => m.requires))) missing.push({ room: room.id, slot: u.group || u.members[0].id })\n }\n const pending = queue.slice()\n while (pending.length) {\n let i = pending.findIndex(ready)\n if (i < 0) i = 0\n const u = pending.splice(i, 1)[0]\n process(u)\n for (const m of u.members) done.add(m.id)\n }\n return { items, missing }\n}\n","/**\n * Names of the seeded random streams.\n *\n * These strings come from the Portuguese-language SDK this engine replaces. They are kept\n * verbatim on purpose: a stream is `hash(seed + '|' + name)`, so renaming one would change every\n * plan generated from an existing seed. They never appear in the output.\n */\nexport const STREAM = {\n facade: 'fachada',\n lot: 'lote',\n decor: 'decor',\n roomPrefix: 'c:',\n palettePrefix: 'paleta:',\n} as const\n","import { MARGIN, EPS } from './constants'\nimport {\n areaOf,\n clamp,\n clearRect,\n cutIntervals,\n extent,\n inflate,\n inner,\n insideUnion,\n overlaps,\n r2,\n topOf,\n usableParts,\n} from './geometry'\nimport { rotationFor } from './fill'\nimport { createGrid, reachable } from './grid'\nimport { STREAM } from './legacy-seeds'\nimport { blocksWindow, roomAt, windowZone, windowsOfRoom, zonesOfFloor } from './queries'\nimport { registries } from './registry'\nimport { createRng, pickWeighted, shuffle } from './rng'\nimport type { Rng } from './rng'\nimport type { PlaceOnFloorOptions, PlacedItem, Plan, PlacementContext, PlacementKit, Rect, Room, Vec2 } from './types'\n\n/** Geometry and grid helpers shared with decor passes and state plugins. */\nexport const placementKit: PlacementKit = {\n MARGIN,\n EPS,\n r2,\n clamp,\n overlaps,\n inner,\n inflate,\n areaOf,\n topOf,\n extent,\n insideUnion,\n usableParts,\n zonesOfFloor,\n windowsOfRoom,\n windowZone,\n roomAt,\n reachable: reachable as PlacementKit['reachable'],\n createGrid: createGrid as PlacementKit['createGrid'],\n clearRect,\n pickWeighted,\n createRng,\n roomSeedKey: (room: Room) => room.seedKey ?? registries().SEED_KEYS.rooms[room.id] ?? room.id,\n shuffle,\n facingRotation: (f: Vec2, type: string) => rotationFor(f, registries().CATALOG[type].front),\n cutIntervals,\n blocksWindow,\n}\n\n/** Builds the shared placement context over the items already placed by the slot fill. */\nexport function createPlacementContext(plan: Plan, items: PlacedItem[]): PlacementContext {\n const added: PlacedItem[] = []\n const counters: Record<string, number> = {}\n const make = (room: Room, type: string, r: Rect, f: Vec2, o?: Partial<PlacedItem>): PlacedItem => {\n const it = registries().CATALOG[type]\n const n = (counters[room.id + type] = (counters[room.id + type] || 0) + 1)\n return Object.assign(\n {\n id: room.id + '.dec_' + type + n,\n type,\n category: it.category,\n x: r2((r[0] + r[2]) / 2),\n z: r2((r[1] + r[3]) / 2),\n ry: r2(Math.atan2(f[0], f[1])),\n w: it.w,\n d: it.d,\n h: it.h,\n y: 0,\n frontU: f[0],\n frontV: f[1],\n room: room.id,\n floor: room.floor,\n outdoor: !!room.outdoor,\n slot: 'dec_' + type + n,\n on: null,\n mode: null,\n clearance: 0,\n flat: !!it.flat,\n low: it.low,\n aabb: r.map(r2) as Rect,\n _r: r,\n decor: true,\n mount: it.mount,\n },\n o || {},\n ) as PlacedItem\n }\n const add = (m: PlacedItem) => {\n added.push(m)\n items.push(m)\n return m\n }\n const itemsOfRoom = (c: Room) => items.filter((m) => m.room === c.id && m.floor === c.floor)\n const extraSolids: Record<string, Rect[]> = {}\n const solidsOfRoom = (c: Room): Rect[] =>\n itemsOfRoom(c)\n .filter((m) => !m.flat && !m.on && (!m.decor || m.mount === 'floor'))\n .map((m) => m._r as Rect)\n .concat(extraSolids[c.id] || [])\n const gridCache: Record<string, ReturnType<typeof createGrid>> = {}\n let ignored: Set<string> | null = null\n const gridOf = (c: Room) => gridCache[c.id] || (gridCache[c.id] = createGrid(plan, c, ignored))\n\n /** Places a floor item at a corner or along a wall; respects doors, windows, clearances and walkability. */\n function placeOnFloor(room: Room, type: string, rng2: Rng, optsIn?: PlaceOnFloorOptions): Rect | null {\n const opts: PlaceOnFloorOptions = Object.assign({}, optsIn || {})\n const it0 = registries().CATALOG[type]\n if (it0.flat) opts.flat = true\n const it = registries().CATALOG[type]\n const inners = usableParts(room, 0)\n const solidList = solidsOfRoom(room)\n const zones = zonesOfFloor(plan, room.floor)\n const occupied = itemsOfRoom(room)\n const windowZones = windowsOfRoom(plan, room).map((j) => ({ z: windowZone(j, room.outdoor), j }))\n // the 1 m landing in front of a staircase stays free\n const landings: Rect[] = it0.flat\n ? []\n : items\n .filter((m) => m.type === 'stairs' && m.floor === room.floor && m.aabb)\n .map((m) => {\n const r = m.aabb\n return (m.frontV === 1 ? [r[0], r[3], r[2], r[3] + 1] : m.frontV === -1 ? [r[0], r[1] - 1, r[2], r[1]] : m.frontU === 1 ? [r[2], r[1], r[2] + 1, r[3]] : [r[0] - 1, r[1], r[0], r[3]]) as Rect\n })\n const cand: Rect[] = opts.cands ? opts.cands.slice() : []\n if (!opts.cands)\n for (const p of inners) {\n const extentU = opts.dim ? opts.dim[0] : it.w\n const extentV = opts.dim ? opts.dim[1] : it.d\n for (const [x, z] of [[p[0], p[1]], [p[2] - extentU, p[1]], [p[0], p[3] - extentV], [p[2] - extentU, p[3] - extentV]]) cand.push([x, z, x + extentU, z + extentV])\n for (let k = 0; k < 6; k++) {\n const t = rng2()\n const side = Math.floor(rng2() * 4)\n const x = side < 2 ? p[0] + t * Math.max(0, p[2] - p[0] - extentU) : side === 2 ? p[0] : p[2] - extentU\n const z = side >= 2 ? p[1] + t * Math.max(0, p[3] - p[1] - extentV) : side === 0 ? p[1] : p[3] - extentV\n cand.push([x, z, x + extentU, z + extentV])\n }\n }\n for (const r of opts.ordered ? cand : shuffle(cand, rng2)) {\n if (!insideUnion(r, inners)) continue\n if (zones.some((z) => overlaps(r, z)) || landings.some((z) => overlaps(r, z))) continue\n if (windowZones.some(({ z, j }) => blocksWindow(it, j) && overlaps(r, z))) continue\n if (solidList.some((o) => overlaps(r, o))) continue\n if (opts.flat) {\n if (!(opts.without && opts.without(r))) return r\n continue\n }\n if (occupied.some((m) => !m.low && !m.flat && !m.on && !m.decor && (m.clearance ?? 0) > 0 && overlaps(r, clearRect(m._r as Rect, [m.frontU ?? 0, m.frontV ?? 1], m.clearance ?? 0)))) continue\n if (opts.without && opts.without(r)) continue\n if (!reachable(opts.railing || gridOf(room), solidList.concat([r]), room.outdoor ? 0.16 : plan.playerRadius)) continue\n return r\n }\n return null\n }\n const roomById = (id: string) => plan.rooms.find((c) => c.id === id) || plan.zones.find((c) => c.id === id)\n return {\n make,\n add,\n placeOnFloor,\n itemsOfRoom,\n solidsOfRoom,\n gridOf,\n extraSolids,\n roomById,\n setIgnored: (s) => {\n ignored = s\n for (const k of Object.keys(gridCache)) delete gridCache[k]\n },\n added,\n }\n}\n\n/** Ground cover per lot zone: one piece per zone part, plus overlays registered by content packs (decks around pools...). */\nfunction groundCover(plan: Plan, items: PlacedItem[], ctx: PlacementContext) {\n if (!plan.lot) return\n const polygonOf = (r: Rect) => [[r[0], r[1]], [r[2], r[1]], [r[2], r[3]], [r[0], r[3]]].map((p) => [r2(p[0]), r2(p[1])])\n const groundPiece = (z: Room, type: string, r: Rect, layer: number, i: number) => {\n const m = ctx.make(z, type, r, [0, 1], {\n id: z.id + '.ground' + (layer ? '_overlay' : '') + i,\n slot: 'ground' + (layer ? '_overlay' : '') + i,\n w: r2(r[2] - r[0]),\n d: r2(r[3] - r[1]),\n h: 0,\n polygon: polygonOf(r),\n layer,\n zone: z.id,\n outdoor: true,\n floor: -1,\n })\n return ctx.add(m)\n }\n for (const z of plan.zones) {\n z.parts.forEach((p, i) => groundPiece(z, z.ground as string, p, 0, i))\n let k = 0\n const clip = (r: Rect): Rect | undefined =>\n z.parts\n .map((p) => [Math.max(r[0], p[0]), Math.max(r[1], p[1]), Math.min(r[2], p[2]), Math.min(r[3], p[3])] as Rect)\n .filter((q) => q[2] - q[0] > 0.3 && q[3] - q[1] > 0.3)\n .sort((a, b) => areaOf(b) - areaOf(a))[0]\n for (const rule of registries().GROUND_OVERLAYS) {\n const triggers = items.filter((m) => m.room === z.id && m.category === rule.category)\n if (rule.merge) {\n if (triggers.length && z.ground !== rule.unlessGround) {\n const u = triggers.reduce((a, m) => [Math.min(a[0], (m._r as Rect)[0]), Math.min(a[1], (m._r as Rect)[1]), Math.max(a[2], (m._r as Rect)[2]), Math.max(a[3], (m._r as Rect)[3])], [1e9, 1e9, -1e9, -1e9])\n const q = clip(inflate(u as Rect, rule.inflate))\n if (q) groundPiece(z, rule.ground, q, 1, k++)\n }\n } else {\n for (const m of triggers) {\n const q = clip(inflate(m._r as Rect, rule.inflate))\n if (q) groundPiece(z, rule.ground, q, 1, k++)\n }\n }\n }\n }\n}\n\n/** Runs the registered decor passes and the ground cover; returns the context for the state step. */\nexport function runPostProcess(plan: Plan, items: PlacedItem[], seed: number | string): PlacementContext {\n const ctx = createPlacementContext(plan, items)\n const rng = createRng(seed, STREAM.decor)\n for (const pass of registries().PASSES) pass.run({ plan, items, seed, rng, ctx, kit: placementKit, catalog: registries().CATALOG, profiles: registries().DECOR_PROFILES })\n groundCover(plan, items, ctx)\n return ctx\n}\n","import { registries } from './registry'\nimport type { FloorplanLocale } from './types'\n\ntype Namespace = keyof FloorplanLocale\n\n/** Registers (or extends) the strings of a language. Packs call this with their JSON files. */\nexport function registerLocale(code: string, table: FloorplanLocale): void {\n const { LOCALES: locales } = registries()\n const cur = (locales[code] = locales[code] || {})\n for (const ns of Object.keys(table) as Namespace[]) cur[ns] = Object.assign(cur[ns] || {}, table[ns])\n}\n\nexport const listLocales = (): string[] => Object.keys(registries().LOCALES)\n\n/** Looks a key up in a namespace. Falls back to English, then to the key itself. `{n}`-style variables are replaced. */\nexport function translate(ns: Namespace, key: string, locale = 'en', vars?: Record<string, string | number>): string {\n const { LOCALES: locales } = registries()\n const raw = locales[locale]?.[ns]?.[key] ?? locales.en?.[ns]?.[key] ?? key\n return vars ? raw.replace(/\\{(\\w+)\\}/g, (m, k) => (k in vars ? String(vars[k]) : m)) : raw\n}\n","import { r2 } from './geometry'\nimport type { LotPath, Plan, PlanGate, Rect, Room, Vec2 } from './types'\n\nexport interface ExteriorPathContext {\n gates: PlanGate[]\n paths: LotPath[]\n zones: Room[]\n setback: number\n marginLeft: number\n marginRight: number\n backyard: number\n w: number\n /** Door the entrance path is named after (the template's `doorTarget`). */\n target?: { a: string; side: string }\n}\n\nconst CLOSE = 1e-6\nconst rounded = (r: Rect): Rect => r.map(r2) as Rect\nconst touches = (a: Rect, r: Rect): boolean => a[0] <= r[2] + CLOSE && a[2] >= r[0] - CLOSE && a[1] <= r[3] + CLOSE && a[3] >= r[1] - CLOSE\n\ninterface SideRoute {\n lane: { x: number; width: number; side: string }\n laneWidth: number\n half: number\n vertical: Rect\n horizontal: Rect | null\n frontStub: Rect | null\n cost: number\n rearStrip: number\n rearY: number\n frontY: number\n overlapsParking: boolean\n}\n\n/**\n * Every exterior door of the ground floor gets a paved pedestrian path to the pedestrian gate or to the nearest existing path.\n * Doors on the front go straight out; doors on the back or the sides run along the side yard, to the parking or to the front path.\n */\nexport function addExteriorDoorPaths(plan: Plan, c: ExteriorPathContext): void {\n const { gates, paths, zones, setback, marginLeft, marginRight, backyard, w } = c\n const social = gates.find((g) => g.type === 'pedestrian')\n const socialPath = social ? paths.find((p) => p.from === social.id && p.type === 'pedestrian') : null\n const parkingZone = zones.find((z) => z.id === 'parking')\n const parking: Rect | null = parkingZone ? parkingZone.parts[0] : null\n const midY = setback > 0 ? -setback / 2 : 0\n const joinToSocial = (x: number, width: number, rects: Rect[], points: number[][]) => {\n if (!socialPath) return\n const h = width / 2\n const horizontal = socialPath.rects.find((r: Rect) => midY >= r[1] - CLOSE && midY <= r[3] + CLOSE && r[2] - r[0] > r[3] - r[1]) || socialPath.rects[0]\n const targetX = x < horizontal[0] ? horizontal[0] + h : x > horizontal[2] ? horizontal[2] - h : x\n if (Math.abs(targetX - x) > CLOSE) {\n rects.push([Math.min(x, targetX) - h, midY - h, Math.max(x, targetX) + h, midY + h])\n points.push([targetX, midY])\n }\n }\n for (const door of plan.doors.filter((q) => q.floor === 0 && q.exterior)) {\n if (paths.some((p) => p.to === door.id)) continue\n const half = Math.max(1.0, Math.min(door.width, 2.0)) / 2\n const rects: Rect[] = []\n const points: number[][] = []\n const isTarget = c.target && door.a === c.target.a && door.side === c.target.side\n let fromId: string | null = social ? social.id : null\n let width = 1.0\n const id = isTarget ? 'entrance_path' : 'path_' + door.id\n if (door.side === 'front') {\n if (setback > 0) {\n const stub = Math.min(1.0, setback)\n rects.push([door.u - half, -stub, door.u + half, 0])\n points.push([door.u, 0], [door.u, -stub])\n if (-stub > midY) {\n rects.push([door.u - width / 2, midY - width / 2, door.u + width / 2, -stub])\n points.push([door.u, midY])\n }\n joinToSocial(door.u, width, rects, points)\n } else {\n rects.push([door.u - half, -1.2, door.u + half, 0])\n points.push([door.u, 0], [door.u, -1.2])\n }\n } else {\n const lanes: SideRoute['lane'][] = []\n if (marginLeft > 0.5) lanes.push({ x: -marginLeft / 2, width: marginLeft, side: 'left' })\n if (marginRight > 0.5) lanes.push({ x: w + marginRight / 2, width: marginRight, side: 'right' })\n const targets: Rect[] = paths.flatMap((p) => p.rects as Rect[]).concat(parking ? [parking] : [])\n let best: SideRoute | null = null\n for (const lane of lanes) {\n if ((door.side === 'left' && lane.side !== 'left') || (door.side === 'right' && lane.side !== 'right')) continue\n const laneWidth = Math.min(0.9, lane.width - 0.1)\n const h = laneWidth / 2\n const rearStrip = Math.min(0.8, backyard)\n const rearY = door.v + rearStrip + laneWidth / 2\n const overlapsParking = !!parking && lane.x + h > parking[0] && lane.x - h < parking[2]\n const frontY = overlapsParking || setback <= 0 ? 0 : -0.6\n let frontStub: Rect | null = null\n if (!overlapsParking && setback > 0) {\n const dir = social && social.u < lane.x ? -1 : 1\n const band = [-0.6 - h, -0.6 + h]\n let nearestX = social ? social.u : lane.x\n let nearestGap = Infinity\n for (const r of targets) {\n if (!(r[1] <= band[1] && r[3] >= band[0])) continue\n const edge = dir < 0 ? r[2] : r[0]\n const gap = Math.abs(edge - lane.x)\n if ((dir < 0 ? edge <= lane.x : edge >= lane.x) && gap < nearestGap) {\n nearestGap = gap\n nearestX = edge\n }\n }\n frontStub = [Math.min(lane.x, nearestX) - (dir < 0 ? 0 : h), -0.6 - h, Math.max(lane.x, nearestX) + (dir < 0 ? h : 0), -0.6 + h]\n }\n const vertical: Rect = [lane.x - h, frontY - (frontY < 0 ? h : 0), lane.x + h, (door.side === 'back' ? rearY : door.v) + laneWidth / 2]\n const horizontal: Rect | null = door.side === 'back' ? [Math.min(door.u, lane.x) - half, rearY - laneWidth / 2, Math.max(door.u, lane.x) + h, rearY + laneWidth / 2] : null\n const cost = (horizontal ? horizontal[2] - horizontal[0] : 0) + (frontStub ? frontStub[2] - frontStub[0] : 0)\n if (!best || cost < best.cost) best = { lane, laneWidth, half: h, vertical, horizontal, frontStub, cost, rearStrip, rearY, frontY, overlapsParking }\n }\n if (best) {\n const { lane, laneWidth, half: h, vertical, horizontal, frontStub, rearStrip, rearY, frontY, overlapsParking } = best\n width = laneWidth\n if (overlapsParking) fromId = (gates.find((g) => g.type === 'garage') || social || ({} as Partial<PlanGate>)).id || null\n if (door.side === 'back') {\n rects.push([door.u - half, door.v, door.u + half, door.v + rearStrip + laneWidth], horizontal as Rect, vertical)\n points.push([door.u, door.v], [door.u, rearY], [lane.x, rearY], [lane.x, frontY])\n } else {\n const x0 = door.side === 'left' ? lane.x - h : w\n const x1 = door.side === 'left' ? 0 : lane.x + h\n rects.push([Math.min(x0, x1), door.v - half, Math.max(x0, x1), door.v + half], vertical)\n points.push([door.u, door.v], [lane.x, door.v], [lane.x, frontY])\n }\n if (frontStub) {\n rects.push(frontStub)\n points.push([frontStub[0] < lane.x ? frontStub[0] : frontStub[2], -0.6])\n }\n } else {\n const stub = 1.0\n if (door.side === 'back') rects.push([door.u - half, door.v, door.u + half, door.v + Math.min(stub, backyard)])\n else rects.push(door.side === 'left' ? [-Math.min(stub, marginLeft), door.v - half, 0, door.v + half] : [w, door.v - half, w + Math.min(stub, marginRight), door.v + half])\n points.push([door.u, door.v])\n }\n }\n const reached = rects.slice()\n const pool: Rect[] = paths.flatMap((p) => p.rects as Rect[]).concat(parking ? [parking] : [])\n let grows = true\n while (grows) {\n grows = false\n for (const r of pool) {\n if (!reached.includes(r) && reached.some((a) => touches(a, r))) {\n reached.push(r)\n grows = true\n }\n }\n }\n const inside = (g: { u: number; v: number }) => reached.some((r) => g.u >= r[0] - CLOSE && g.u <= r[2] + CLOSE && g.v >= r[1] - CLOSE && g.v <= r[3] + CLOSE)\n const gate = gates.find((q) => q.type === 'pedestrian' && inside(q)) || gates.find((q) => q.type !== 'cargo' && inside(q))\n if (gate) fromId = gate.id\n paths.push({ id, type: 'pedestrian', from: fromId, to: door.id, width, rects: rects.map(rounded), points: points.map((q) => q.map(r2) as Vec2) })\n }\n}\n\n","import { registries } from './registry'\nimport { r2 } from './geometry'\nimport type { FloorplanOptions, Lot, LotConfig, Plan, Room, TemplateDef, ZoneAdjustment, ZoneDef, ZoneViolation } from './types'\n\n/** What the zone checks read from a plan: a generated result or the internal plan. */\nexport interface ZoneCheckedPlan {\n floors: { y0: number; ceiling: number }[]\n floorNumber?: number | null\n rooms?: { floor: number; parts: readonly (readonly number[])[] }[]\n w: number\n d: number\n use?: string\n partyWalls?: string[]\n}\n\n/** What the zone checks read from a lot (`result.lot`). */\nexport interface ZoneCheckedLot {\n rect: readonly number[]\n setback: number\n sideYard: { left: number; right: number }\n backyard: number\n zones: { ground?: string; parts: readonly (readonly number[])[] }[]\n}\n\ntype LotSetbackKey = 'frontSetback' | 'marginLeft' | 'marginRight' | 'backyardDepth'\n\n/** Registers an urban zone (zoning rules). Returns the stored definition. */\nexport function defineZone(zone: ZoneDef): ZoneDef {\n if (!zone || !zone.id) throw new Error('defineZone: id is required')\n registries().ZONES[zone.id] = zone\n return zone\n}\nexport const getZone = (id: string): ZoneDef | undefined => registries().ZONES[id]\nexport const listZones = (): ZoneDef[] => Object.values(registries().ZONES)\n\n/** Marks ground types (e.g. `lawn`, `dirt`) that count towards the permeable area of a lot. */\nexport function registerPermeableGround(...types: string[]): void {\n for (const t of types) registries().PERMEABLE_GROUNDS.add(t)\n}\n\nexport function resolveZone(z: string | ZoneDef | undefined): ZoneDef | null {\n if (!z) return null\n if (typeof z === 'string') {\n const found = registries().ZONES[z]\n if (!found) throw new Error('Unknown zone: ' + z)\n return found\n }\n return z\n}\n\nexport const floorsOfTemplate = (tpl: TemplateDef, op: FloorplanOptions): number => (tpl.floorsFn ? tpl.floorsFn(op) : tpl.floors || []).length\n\n/** Declared use of a template; templates without one are treated as `residential_single`. */\nexport const useOf = (tpl: TemplateDef): string => tpl.use || 'residential_single'\n\n/** Totals used by the checks: storeys, height, areas. Works on a generated result or an internal plan. */\nfunction measure(plan: ZoneCheckedPlan) {\n const floors = plan.floors\n const top = floors.reduce((m, f) => Math.max(m, f.y0 + f.ceiling), 0)\n const number = plan.floorNumber != null ? plan.floorNumber : floors.length\n const rooms = (plan.rooms || []).filter((r) => r.floor >= 0)\n const area = (r: { parts: readonly (readonly number[])[] }) => r.parts.reduce((s: number, p) => s + (p[2] - p[0]) * (p[3] - p[1]), 0)\n const footprint = plan.w * plan.d\n const built = rooms.reduce((s, r) => s + area(r), 0)\n return { storeys: number, height: r2(top), footprint, built }\n}\n\n/**\n * Checks a generated lot against a zone and returns the violations (empty when compliant).\n * `lot` is `result.lot` (may be null for apartments), `plan` is the result of `generate`.\n */\nexport function checkLot(zoneIn: string | ZoneDef, lot: ZoneCheckedLot | null | undefined, plan: ZoneCheckedPlan): ZoneViolation[] {\n const zone = resolveZone(zoneIn) as ZoneDef\n const out: ZoneViolation[] = []\n const m = measure(plan)\n const use = plan.use || 'residential_single'\n if (!zone.allowedUses.includes(use)) out.push({ rule: 'use', actual: use, limit: zone.allowedUses.join(',') })\n if (m.storeys > zone.maxFloors) out.push({ rule: 'floors', actual: m.storeys, limit: zone.maxFloors })\n if (m.height > zone.maxHeight + 1e-9) out.push({ rule: 'height', actual: m.height, limit: zone.maxHeight })\n if (!lot) return out\n const [u0, v0, u1, v1] = lot.rect\n const width = r2(u1 - u0)\n const depth = r2(v1 - v0)\n const area = width * depth\n const party: string[] = plan.partyWalls || []\n const sides = [party.includes('left') ? Infinity : lot.sideYard.left, party.includes('right') ? Infinity : lot.sideYard.right]\n const left = sides[0]\n const right = sides[1]\n if (lot.setback < zone.setbacks.front - 1e-9) out.push({ rule: 'setback_front', actual: lot.setback, limit: zone.setbacks.front })\n if (Math.min(left, right) < zone.setbacks.side - 1e-9) out.push({ rule: 'setback_side', actual: Math.min(left, right), limit: zone.setbacks.side })\n if (lot.backyard < zone.setbacks.back - 1e-9) out.push({ rule: 'setback_back', actual: lot.backyard, limit: zone.setbacks.back })\n if (area < zone.minLot - 1e-9) out.push({ rule: 'min_lot', actual: r2(area), limit: zone.minLot })\n if (width < zone.minFrontage - 1e-9) out.push({ rule: 'min_frontage', actual: width, limit: zone.minFrontage })\n const ground = m.footprint\n const coverage = ground / area\n if (coverage > zone.maxCoverage + 1e-9) out.push({ rule: 'coverage', actual: r2(coverage), limit: zone.maxCoverage })\n const far = m.built / area\n if (far > zone.maxFar + 1e-9) out.push({ rule: 'far', actual: r2(far), limit: zone.maxFar })\n let permeable = 0\n for (const z of lot.zones) if (z.ground && registries().PERMEABLE_GROUNDS.has(z.ground)) for (const p of z.parts) permeable += (p[2] - p[0]) * (p[3] - p[1])\n const permeability = permeable / area\n if (permeability < zone.permeableMin - 1e-9) out.push({ rule: 'permeable', actual: r2(permeability), limit: zone.permeableMin })\n return out\n}\n\n/** Clamps adjustable options (`floors`) to the zone before the plan is built. */\nexport function clampOptionsToZone(tpl: TemplateDef, op: FloorplanOptions, zone: ZoneDef, adjustments: ZoneAdjustment[]): FloorplanOptions {\n if (tpl.singleFloor) {\n // an apartment unit: the storey it sits on must exist in a building the zone allows\n const ceiling = (tpl.floors || tpl.floorsFn?.(op) || [])[0]?.ceiling ?? 2.8\n const current = op.floor || 3\n const limit = Math.max(1, Math.min(zone.maxFloors, Math.floor(zone.maxHeight / ceiling + 1e-9)))\n if (current <= limit) return op\n adjustments.push({ field: 'floor', from: current, to: limit, reason: current > zone.maxFloors ? 'max_floors' : 'max_height' })\n return Object.assign({}, op, { floor: limit })\n }\n if (!tpl.floorRange || !tpl.floorsFn) return op\n const current = floorsOfTemplate(tpl, op)\n const floors = tpl.floorsFn(op)\n const ceiling = floors.reduce((m, f) => Math.max(m, f.ceiling), 0) || 2.8\n const byHeight = Math.max(1, Math.floor(zone.maxHeight / ceiling + 1e-9))\n const limit = Math.max(tpl.floorRange[0], Math.min(zone.maxFloors, byHeight, tpl.floorRange[1]))\n if (current <= limit) return op\n adjustments.push({ field: 'floors', from: current, to: limit, reason: current > zone.maxFloors ? 'max_floors' : 'max_height' })\n return Object.assign({}, op, { floors: limit })\n}\n\n/** Raises lot setbacks to the zone minimums. */\nexport function clampLotToZone(cfg: LotConfig, zone: ZoneDef, adjustments: ZoneAdjustment[], partyWalls: string[] = []): void {\n const raise = (field: string, key: LotSetbackKey, min: number, reason: string) => {\n if (cfg[key] < min) {\n adjustments.push({ field, from: cfg[key], to: min, reason })\n cfg[key] = min\n }\n }\n raise('frontSetback', 'frontSetback', zone.setbacks.front, 'setback_front')\n if (!partyWalls.includes('left')) raise('marginLeft', 'marginLeft', zone.setbacks.side, 'setback_side')\n if (!partyWalls.includes('right')) raise('marginRight', 'marginRight', zone.setbacks.side, 'setback_side')\n raise('backyardDepth', 'backyardDepth', zone.setbacks.back, 'setback_back')\n}\n\nexport type { Plan }\n\n/** Lot zone types whose ground can be switched to a permeable one to meet the permeability rate. */\nconst ADJUSTABLE_ZONES = new Set(['garden', 'backyard', 'side_yard'])\n\n/**\n * Raises the permeable area of a lot to the zone's `permeableMin` by turning paved garden, yard\n * and side zones (largest first) into the first registered permeable ground. Reports each change.\n */\nexport function enforcePermeability(lot: Lot, zones: Room[], zone: ZoneDef, adjustments: ZoneAdjustment[]): void {\n const target = [...registries().PERMEABLE_GROUNDS][0]\n if (!target) return\n const [u0, v0, u1, v1] = lot.rect\n const area = (u1 - u0) * (v1 - v0)\n const areaOfZone = (z: Room) => z.parts.reduce((s, p) => s + (p[2] - p[0]) * (p[3] - p[1]), 0)\n let permeable = zones.filter((z) => z.ground != null && registries().PERMEABLE_GROUNDS.has(z.ground)).reduce((s, z) => s + areaOfZone(z), 0)\n if (permeable / area >= zone.permeableMin) return\n const candidates = zones.filter((z) => ADJUSTABLE_ZONES.has(z.type) && !(z.ground != null && registries().PERMEABLE_GROUNDS.has(z.ground))).sort((a, b) => areaOfZone(b) - areaOfZone(a))\n for (const z of candidates) {\n if (permeable / area >= zone.permeableMin) break\n adjustments.push({ field: 'ground:' + z.id, from: z.ground ?? '', to: target, reason: 'permeable_min' })\n z.ground = target\n permeable += areaOfZone(z)\n }\n}\n","import { CAR_CLEARANCE, DOOR_EDGE_CLEARANCE, MARGIN, PLAYER_RADIUS, TOL, WALL_THICKNESS, WINDOWLESS_ROOM_TYPES, WINDOW_EDGE_CLEARANCE } from './constants'\nimport { buildWalls, clamp, eq, exteriorEdge, inRect, normalizeRoom, openingDepth, openingZones, r2, sharedEdge } from './geometry'\nimport { STREAM } from './legacy-seeds'\nimport { createRng, pickWeighted } from './rng'\nimport { registries, resolveStyleId, styleOf } from './registry'\nimport { addExteriorDoorPaths } from './paths'\nimport { clampLotToZone, enforcePermeability } from './zoning'\nimport type { FloorDef, FloorplanOptions, GateCfg, Lot, LotBoundary, LotConfig, LotPath, Plan, PlanDoor, PlanGate, PlanWall, PlanWindow, Rect, Room, StyleDef, TemplateDef, WindowDef, ZoneAdjustment, ZoneDef } from './types'\n\nexport const floorsOf = (tpl: TemplateDef, op?: FloorplanOptions): FloorDef[] => (tpl.floorsFn ? tpl.floorsFn(op || {}) : (tpl.floors as FloorDef[]))\n\nexport function clampSize(tpl: TemplateDef, w: number | undefined, d: number | undefined, op?: FloorplanOptions) {\n const L = tpl.limitsFn ? tpl.limitsFn(op || {}) : tpl.limits\n const P0 = tpl.defaultsFn ? tpl.defaultsFn(op || {}) : tpl.defaults\n const ww = w == null ? P0.w : clamp(w, L.w[0], L.w[1])\n const dd = d == null ? P0.d : clamp(d, L.d[0], L.d[1])\n return { w: r2(ww), d: r2(dd) }\n}\n\nexport interface BuildContext {\n zone?: ZoneDef | null\n adjustments?: ZoneAdjustment[]\n}\n\nexport function buildPlan(tpl: TemplateDef, wIn: number | undefined, dIn: number | undefined, opIn?: FloorplanOptions, bc: BuildContext = {}): Plan {\n const op = opIn || {}\n const { w, d } = clampSize(tpl, wIn, dIn, op)\n const styleId = resolveStyleId(op.style || (typeof tpl.style === 'function' ? tpl.style(op) : tpl.style) || 'budget')\n const FLOOR_DEFS = floorsOf(tpl, op)\n const style = styleOf(styleId)\n const plan: Plan = {\n w, d, tpl, floorDefs: FLOOR_DEFS, style: styleId, floors: [], rooms: [], zones: [], doors: [], windows: [], walls: [], gates: [], paths: [], lot: null, openPairs: {}, reservations: [], options: op,\n playerRadius: op.playerRadius ?? PLAYER_RADIUS,\n carClearance: Object.assign({}, CAR_CLEARANCE, op.carClearance),\n }\n FLOOR_DEFS.forEach((A, floorIndex) => {\n const floorNumber = tpl.singleFloor ? op.floor || 3 : floorIndex + 1\n plan.floors.push({\n index: floorIndex,\n name: tpl.singleFloor ? 'floor_n' : A.label,\n number: tpl.singleFloor ? floorNumber : undefined,\n y0: tpl.singleFloor ? (floorNumber - 1) * A.ceiling : tpl.cumulativeCeilings ? FLOOR_DEFS.slice(0, floorIndex).reduce((t, q) => t + q.ceiling, 0) : floorIndex * A.ceiling,\n ceiling: A.ceiling,\n })\n plan.openPairs[floorIndex] = A.openPairs || []\n const list = A.rooms(w, d, op).map((c) => normalizeRoom(c, floorIndex))\n for (const c of list) {\n if (plan.rooms.some((x) => x.id === c.id)) throw new Error('Duplicate room: ' + c.id)\n plan.rooms.push(c)\n }\n const byId: Record<string, Room> = {}\n for (const c of list) byId[c.id] = c\n const floorDoors: PlanDoor[] = []\n ;(A.doors(w, d, op) || []).forEach((sp, i) => {\n const a = byId[sp.a]\n if (!a) throw new Error('Door references a missing room: ' + sp.a)\n let edge\n if (sp.edge) edge = sp.edge\n else if (sp.b === 'outside') edge = exteriorEdge(a, sp.side as string, w, d, sp.at)\n else {\n const b = byId[sp.b]\n if (!b) throw new Error('Door references a missing room: ' + sp.b)\n edge = sharedEdge(a, b, sp.at)\n }\n if (!edge) throw new Error('Door without a wall: ' + sp.a + ' / ' + sp.b)\n const width = sp.width\n const margin = width / 2 + (sp.clearance ?? tpl.clearance?.door ?? DOOR_EDGE_CLEARANCE)\n if (edge.a1 - edge.a0 < width + 0.24) throw new Error('Wall too short for the door: ' + sp.a + ' / ' + sp.b)\n const c = clamp(sp.at != null ? sp.at : (edge.a0 + edge.a1) / 2, edge.a0 + margin, edge.a1 - margin)\n const exterior = sp.b === 'outside'\n const leaf = exterior && sp.steel ? 0 : width > 1.1 ? width / 2 : width\n const u = edge.axis === 'u' ? c : edge.pos\n const v = edge.axis === 'u' ? edge.pos : c\n floorDoors.push({\n id: 'd' + floorIndex + '_' + i,\n floor: floorIndex,\n u: r2(u),\n v: r2(v),\n axis: edge.axis,\n pos: edge.pos,\n at: r2(c),\n width,\n a: sp.a,\n b: sp.b,\n opensTo: sp.opensTo || sp.a,\n exterior,\n side: sp.side || null,\n leaves: exterior && sp.steel ? 0 : width > 1.1 ? 2 : 1,\n model: sp.model || (sp.steel ? 'steel' : width > 1.1 ? 'double' : 'single'),\n type: sp.type || 'door',\n steps: sp.steps || 0,\n hinge: 'start',\n zones: openingZones(u, v, edge.axis, width, openingDepth(width, leaf)),\n })\n })\n plan.doors.push(...floorDoors)\n const floorWalls = (tpl.noWalls ? [] : buildWalls(list, floorDoors, A.openPairs || [], floorIndex)).map((p) => Object.assign(p, { h: p.h || A.ceiling }))\n const windowsOut = placeWindows({ list, byId, floorWalls, windowDefs: A.windows(w, d, op) || [], floorIndex, ceiling: A.ceiling, w, d, clearance: tpl.clearance?.window ?? WINDOW_EDGE_CLEARANCE })\n plan.windows.push(...windowsOut)\n plan.walls.push(...floorWalls)\n })\n if (tpl.config) plan.config = tpl.config(op, w, d)\n if (tpl.reservations) tpl.reservations(plan)\n buildLot(plan, tpl, w, d, op, style, styleId, bc)\n return plan\n}\n\ninterface WindowGroup {\n wall: PlanWall\n edge: { axis: 'u' | 'v'; pos: number }\n start: number\n end: number\n def: WindowDef\n entries: { def: WindowDef; centre: number; order: number }[]\n}\ninterface WindowParams {\n list: Room[]\n byId: Record<string, Room>\n floorWalls: PlanWall[]\n windowDefs: WindowDef[]\n floorIndex: number\n ceiling: number\n w: number\n d: number\n clearance: number\n}\n\n/**\n * Each window lands on a stretch of exterior wall (between corners, junctions and doors) and is spread over it: a single window is centred,\n * several get equal gaps, and none comes closer than `clearance` to a corner, a junction or a door. A room that needs light but got no window gets one.\n */\nfunction placeWindows(params: WindowParams): PlanWindow[] {\n const { list, byId, floorWalls, windowDefs, floorIndex, ceiling, w, d, clearance } = params\n const stretches = floorWalls.filter((p) => p.exterior && p.type === 'wall')\n const found: (PlanWindow & { _order?: number })[] = []\n const groups: WindowGroup[] = []\n let order = 0\n for (const def of windowDefs) {\n const room = byId[def.room]\n if (!room) throw new Error('Window references a missing room: ' + def.room)\n const edge = exteriorEdge(room, def.side, w, d, def.at)\n if (!edge) continue\n const centres = def.n ? Array.from({ length: def.n }, (_, i) => edge.a0 + ((edge.a1 - edge.a0) * (i + 1)) / (def.n! + 1)) : [def.at as number]\n for (const centre of centres) {\n const onEdge = stretches.filter((t) => t.axis === edge.axis && eq(edge.axis === 'u' ? t.v0 : t.u0, edge.pos) && t.sides.includes(def.room))\n const start = (t: PlanWall) => (edge.axis === 'u' ? t.u0 : t.v0)\n const end = (t: PlanWall) => (edge.axis === 'u' ? t.u1 : t.v1)\n const gap = (t: PlanWall) => Math.min(Math.abs(centre - start(t)), Math.abs(centre - end(t)))\n const target = onEdge.find((t) => centre >= start(t) - TOL && centre <= end(t) + TOL) || onEdge.slice().sort((x, y) => gap(x) - gap(y))[0]\n if (!target) continue\n let group = groups.find((x) => x.wall === target && x.def.room === def.room)\n if (!group) groups.push((group = { wall: target, edge, start: start(target), end: end(target), def, entries: [] }))\n group.entries.push({ def, centre, order: order++ })\n }\n }\n for (const g of groups) {\n const room = byId[g.def.room]\n const bath = room.type === 'bathroom'\n const length = g.end - g.start\n const its = g.entries\n .slice()\n .sort((x, y) => x.centre - y.centre)\n .map((x) => ({ def: x.def, order: x.order, width: bath ? Math.min(x.def.width, 0.6) : x.def.width }))\n const fits = (l: typeof its) => l.reduce((t, x) => t + x.width, 0) + (l.length + 1) * clearance <= length + TOL\n while (its.length && !fits(its)) {\n const k = its.reduce((m, x, i, arr) => (x.width > arr[m].width ? i : m), 0)\n if (its[k].width > 0.6 + TOL) its[k] = Object.assign({}, its[k], { width: Math.max(0.6, r2(its[k].width - 0.1)) })\n else its.pop()\n }\n if (!its.length) continue\n const space = (length - its.reduce((t, x) => t + x.width, 0)) / (its.length + 1)\n let pos = g.start + space\n for (const x of its) {\n const c = pos + x.width / 2\n pos += x.width + space\n const u = g.edge.axis === 'u' ? c : g.edge.pos\n const v = g.edge.axis === 'u' ? g.edge.pos : c\n let y0 = x.def.y0 || 1.0\n let y1 = x.def.y1 || 2.15\n if (bath) {\n y0 = Math.max(y0, 2.1)\n y1 = Math.min(Math.max(y1, y0 + 0.4), ceiling - 0.25)\n }\n found.push({ id: '', floor: floorIndex, u: r2(u), v: r2(v), axis: g.edge.axis, pos: g.edge.pos, at: r2(c), width: x.width, y0: r2(y0), y1: r2(y1), room: x.def.room, side: x.def.side, _order: x.order })\n }\n }\n for (const room of list) {\n if (WINDOWLESS_ROOM_TYPES.has(room.type) || found.some((j) => j.room === room.id)) continue\n let best: { length: number; window: PlanWindow & { _order?: number } } | null = null\n for (const t of stretches) {\n if (!t.sides.includes(room.id)) continue\n const i0 = t.axis === 'u' ? t.u0 : t.v0\n const i1 = t.axis === 'u' ? t.u1 : t.v1\n const length = i1 - i0\n const width = Math.min(room.type === 'bathroom' ? 0.6 : 1.2, length - 2 * clearance)\n if (width < 0.6 - TOL || (best && best.length >= length)) continue\n const side = t.axis === 'u' ? (t.sides[0] === 'outside' ? 'front' : 'back') : t.sides[0] === 'outside' ? 'left' : 'right'\n const c = (i0 + i1) / 2\n const pos = t.axis === 'u' ? t.v0 : t.u0\n const bath = room.type === 'bathroom'\n best = { length, window: { id: '', floor: floorIndex, u: r2(t.axis === 'u' ? c : pos), v: r2(t.axis === 'u' ? pos : c), axis: t.axis, pos, at: r2(c), width: r2(width), y0: bath ? 2.1 : 1.0, y1: bath ? Math.min(2.5, ceiling - 0.25) : 2.15, room: room.id, side, _order: 1e6 + found.length } }\n }\n if (best) found.push(best.window)\n }\n found.sort((x, y) => (x._order as number) - (y._order as number))\n found.forEach((j, i) => {\n delete j._order\n j.id = 'w' + floorIndex + '_' + i\n })\n return found\n}\n\n/** Facade and lot: zones, gates, paths and perimeter. */\nfunction buildLot(plan: Plan, tpl: TemplateDef, w: number, d: number, op: FloorplanOptions, style: StyleDef, styleId: string, bc: BuildContext) {\n const seed = op.seed == null ? 1 : op.seed\n const rFacade = createRng(seed, STREAM.facade)\n const facadeStyle = style.facade\n const palette = style.swatches\n const color = palette[Math.floor(rFacade() * palette.length)]\n const extra = tpl.facade || {}\n plan.facade = {\n style: styleId,\n color: { name: color[0], hex: color[1] },\n finish: pickWeighted(rFacade, facadeStyle.finish),\n grilles: rFacade() < facadeStyle.grilles,\n roof: pickWeighted(rFacade, facadeStyle.roof),\n balcony: !!extra.balcony,\n veranda: !!extra.veranda,\n steelDoor: !!extra.steelDoor,\n floors: plan.floorDefs.length,\n }\n if (tpl.facadeExtra) tpl.facadeExtra(plan.facade, rFacade, w, d, op)\n if (plan.floorDefs.length > 1 && plan.facade.roof === 'fiber_cement') plan.facade.roof = 'colonial'\n if (!tpl.lot) return\n const cfg: LotConfig = tpl.lot(w, d, style, op)\n if (bc.zone) clampLotToZone(cfg, bc.zone, bc.adjustments || [], tpl.partyWalls)\n const rLot = createRng(seed, STREAM.lot)\n const setback = cfg.frontSetback\n const marginL = cfg.marginLeft\n const marginR = cfg.marginRight\n const backDepth = cfg.backyardDepth\n const lot: Lot = {\n rect: [-marginL, -setback, w + marginR, d + backDepth],\n setback,\n sideYard: { left: marginL, right: marginR },\n backyard: backDepth,\n style: styleId,\n zones: [],\n perimeter: [],\n gates: [],\n paths: [],\n pool: !!cfg.pool,\n }\n const ZONES: Room[] = []\n const libs = Object.assign({ garden: 'garden', backyard: 'backyard', parking: 'parking', sideYard: 'side_yard' }, cfg.libraries || {})\n const addZone = (id: string, type: string, label: string, parts: Rect[], library?: string) =>\n ZONES.push(Object.assign(normalizeRoom({ id, type, label, rect: parts[0], parts: parts.slice(1), library, outdoor: true }, -1), { floor: -1, outdoor: true }))\n if (setback > 0) {\n let parts: Rect[] = [[-marginL, -setback, w + marginR, 0]]\n if (cfg.parking) {\n const garageU = (cfg.garage as GateCfg).u\n const vw = cfg.parking.width\n const x0 = Math.max(-marginL, garageU - vw / 2)\n const x1 = Math.min(w + marginR, garageU + vw / 2)\n parts = []\n if (x0 + marginL > 0.8) parts.push([-marginL, -setback, x0, 0])\n if (w + marginR - x1 > 0.8) parts.push([x1, -setback, w + marginR, 0])\n addZone('parking', 'parking', 'parking', [[x0, -setback, x1, 0]], libs.parking)\n if (!parts.length) parts = [[x1, -setback, w + marginR, 0]]\n }\n parts.sort((a, b) => b[2] - b[0] - (a[2] - a[0]))\n addZone('garden', 'garden', 'garden', parts, libs.garden)\n }\n const yard = cfg.yardZones\n if (backDepth > 0 && yard) {\n for (const q of yard) addZone(q.id, q.type, q.label || q.id, [[-marginL, d + q.v0, w + marginR, d + Math.min(backDepth, q.v1)]], q.library)\n } else if (backDepth > 0) addZone('backyard', 'backyard', 'backyard', [[-marginL, d, w + marginR, d + backDepth]], libs.backyard)\n for (const q of cfg.extraZones || []) addZone(q.id, q.type, q.label || q.id, q.parts, q.library)\n if (marginL > 0.5) addZone('side_left', 'side_yard', 'side_left', [[-marginL, 0, 0, d]], libs.sideYard)\n if (marginR > 0.5) addZone('side_right', 'side_yard', 'side_right', [[w, 0, w + marginR, d]], libs.sideYard)\n const gates: PlanGate[] = []\n const addGate = (type: string, model: string, u: number, v: number, width: number, side: string, toTarget?: string | null) => {\n const g: PlanGate = {\n id: 'g' + gates.length,\n type,\n model,\n u: r2(u),\n v: r2(v),\n axis: 'u',\n width,\n height: type === 'pedestrian' ? style.height : Math.min(style.height, 2.2),\n side,\n to: toTarget || null,\n material: 'iron',\n zones: openingZones(u, v, 'u', width, openingDepth(width, type === 'pedestrian' ? width : 0)),\n }\n gates.push(g)\n return g\n }\n if (cfg.pedestrian && setback > 0) addGate('pedestrian', 'pedestrian', cfg.pedestrian.u, -setback, 1.0, 'front', 'door')\n if (cfg.garage && setback > 0) addGate('garage', pickWeighted(rLot, style.gate.garage), cfg.garage.u, -setback, cfg.garage.width, 'front', cfg.garage.to)\n if (cfg.cargo) addGate('cargo', 'sliding', cfg.cargo.u, d + backDepth, cfg.cargo.width, 'back', 'stockroom')\n plan.gates = gates\n lot.gates = gates\n const paths: LotPath[] = []\n const target = (a: string, side: string) => plan.doors.find((p) => p.exterior && p.a === a && p.side === side)\n for (const g of gates) {\n if (g.type === 'pedestrian' && cfg.doorTarget) {\n const pt = target(cfg.doorTarget.a, cfg.doorTarget.side)\n if (!pt) continue\n const gateU = g.u\n const dx = pt.u\n const ym = -setback / 2\n const L = 1.0\n const h = L / 2\n const rs: Rect[] = []\n if (Math.abs(gateU - dx) < 0.05) rs.push([dx - h, -setback, dx + h, 0])\n else {\n rs.push([gateU - h, -setback, gateU + h, ym + h])\n rs.push([Math.min(gateU, dx) - h, ym - h, Math.max(gateU, dx) + h, ym + h])\n rs.push([dx - h, ym - h, dx + h, 0])\n }\n paths.push({ id: 'pedestrian_path', type: 'pedestrian', from: g.id, to: pt.id, width: L, rects: rs.map((r) => r.map(r2) as Rect), points: [[gateU, -setback], [gateU, ym], [dx, ym], [dx, 0]] })\n } else if (g.type === 'garage' && g.to === 'inner_garage') {\n const pt = plan.doors.find((p) => p.exterior && p.side === 'front' && Math.abs(p.u - g.u) < 0.6 && p.width >= 2.5)\n if (!pt) continue\n const hw = Math.max(g.width, pt.width) / 2\n paths.push({ id: 'garage_path', type: 'vehicle', from: g.id, to: pt.id, width: hw * 2, rects: [[g.u - hw, -setback, g.u + hw, 0].map(r2) as Rect], points: [[g.u, -setback], [g.u, 0]] })\n } else if (g.type === 'cargo') {\n const pt = target('stockroom', 'back')\n if (!pt) continue\n const hw = Math.max(g.width, pt.width) / 2\n paths.push({ id: 'cargo_path', type: 'vehicle', from: g.id, to: pt.id, width: hw * 2, rects: [[g.u - hw, d, g.u + hw, d + backDepth].map(r2) as Rect], points: [[g.u, d + backDepth], [g.u, d]] })\n }\n }\n if (tpl.paths) paths.push(...tpl.paths(plan, { gates, setback, marginLeft: marginL, marginRight: marginR, backyard: backDepth, w, d }))\n else addExteriorDoorPaths(plan, { gates, paths, zones: ZONES, setback, marginLeft: marginL, marginRight: marginR, backyard: backDepth, w, target: cfg.doorTarget })\n plan.paths = paths\n lot.paths = paths\n const boundary = (rule: { type: Record<string, number>; top: Record<string, number> }) => {\n const type = pickWeighted(rLot, rule.type)\n const top = type === 'railing' ? 'none' : pickWeighted(rLot, rule.top)\n const wallHeight = type === 'railing' ? 1.2 : type === 'fence' ? (style.fenceHeight ?? 2.0) : style.height\n return { type, material: type === 'wall' ? 'block' : type === 'fence' ? 'wire_mesh' : 'iron', height: wallHeight, top, totalHeight: r2(wallHeight + registries().WALL_TOP_HEIGHTS[top]), thickness: WALL_THICKNESS }\n }\n const A: Record<string, LotBoundary> = { front: boundary(style.front), left: boundary(style.sideYard), right: boundary(style.sideYard), back: boundary(style.back) }\n const seg = (side: string, u0: number, v0: number, u1: number, v1: number) => {\n if (Math.abs(u1 - u0) + Math.abs(v1 - v0) < 0.05) return\n lot.perimeter.push(Object.assign({ id: 'm' + lot.perimeter.length, side, u0: r2(u0), v0: r2(v0), u1: r2(u1), v1: r2(v1) }, A[side]))\n }\n const cutRun = (side: string, de: number, to: number, vfix: number, gs: PlanGate[]) => {\n let pieces: [number, number][] = [[de, to]]\n for (const g of gs) {\n const g0 = g.u - g.width / 2\n const g1 = g.u + g.width / 2\n const n: [number, number][] = []\n for (const [x, y] of pieces) {\n if (g1 <= x || g0 >= y) {\n n.push([x, y])\n continue\n }\n if (g0 > x) n.push([x, g0])\n if (g1 < y) n.push([g1, y])\n }\n pieces = n\n }\n for (const [x, y] of pieces) seg(side, x, vfix, y, vfix)\n }\n if (setback > 0)\n cutRun('front', -marginL, w + marginR, -setback, gates.filter((g) => g.side === 'front'))\n cutRun('back', -marginL, w + marginR, d + backDepth, gates.filter((g) => g.side === 'back'))\n const vi = setback > 0 ? -setback : 0\n if (marginL > 0.5) seg('left', -marginL, vi, -marginL, d + backDepth)\n else if (backDepth > 0) seg('left', 0, d, 0, d + backDepth)\n if (marginR > 0.5) seg('right', w + marginR, vi, w + marginR, d + backDepth)\n else if (backDepth > 0) seg('right', w, d, w, d + backDepth)\n for (const z of ZONES) z.ground = (cfg.grounds || {})[z.id] || (cfg.grounds || {})[z.type] || pickWeighted(rLot, style.grounds[z.type] || { concrete: 1 })\n if (bc.zone) enforcePermeability(lot, ZONES, bc.zone, bc.adjustments || [])\n plan.zones = ZONES\n lot.zones = ZONES\n plan.lot = lot\n}\n\nexport { inRect, MARGIN }\n","import { clamp } from './geometry'\nimport { STREAM } from './legacy-seeds'\nimport { registries, resolveStyleId } from './registry'\nimport { createRng } from './rng'\nimport type { Rng } from './rng'\nimport type { Hsl } from './types'\n\nexport const HIGH_SATURATION = 0.4\nexport const MIN_WALL_FLOOR_CONTRAST = 20\nexport const MIN_FABRIC_FLOOR_CONTRAST = 15\n\nconst SCHEMES = ['analogous', 'complementary', 'split_complementary', 'triad'] as const\nconst HARMONY_OFFSETS: Record<string, [number, number]> = { analogous: [-30, 30], complementary: [180, 165], split_complementary: [150, 210], triad: [120, 240] }\n\n/** Roles the contrast rules rely on. A palette recipe must produce them. */\nexport const ROLE_FABRIC_MAIN = 'fabric_main'\nexport const ROLE_FABRIC_ACCENT = 'fabric_accent'\nexport const ROLE_FLOOR_REFERENCE = 'floor_living'\n\n/** Tools handed to a style recipe. `jit` and `rng` draw from the style's seeded stream: draw order is part of the contract. */\nexport interface PaletteDraw {\n rng: Rng\n base: [string, number, number, number]\n H0: number\n H1: number\n H2: number\n jit(v: number, a: number): number\n hsl(h: number, s: number, l: number): Hsl\n}\nexport interface PaletteEarly {\n /** Accent mode: true saturates walls, false puts accents on objects. */\n wallMode: boolean\n /** Maximum wall saturation. */\n sMax: number\n /** Facade, wall, gate, roof, ceiling... in insertion order. */\n roles: Record<string, Hsl>\n /** General floor `[h, s, l]` for room types that do not define their own. */\n generalFloor: [number, number, number]\n}\nexport interface PaletteStyleDef {\n /** Legacy stream suffix; defaults to the style id. */\n seedKey?: string\n /** Facade colour table `[labelKey, h, s, l]`. */\n facadeColors: [string, number, number, number][]\n /** Draws up to the room colours (before the room loop). */\n early(d: PaletteDraw): PaletteEarly\n /** Draws the object roles (wood, fabrics, metal, ground colours) after the room loop. */\n late(d: PaletteDraw, e: PaletteEarly): Record<string, Hsl>\n}\n\nexport interface PaletteContext extends PaletteDraw {\n style: string\n sMax: number\n wallMode: boolean\n generalFloor: [number, number, number]\n}\n\nexport const hslToInt = (h: number, s: number, l: number): number => {\n h = ((h % 360) + 360) % 360\n s = clamp(s, 0, 1)\n l = clamp(l, 0, 1)\n const a = s * Math.min(l, 1 - l)\n const f = (n: number) => {\n const k = (n + h / 30) % 12\n return l - a * Math.max(-1, Math.min(k - 3, 9 - k, 1))\n }\n return (Math.round(f(0) * 255) << 16) | (Math.round(f(8) * 255) << 8) | Math.round(f(4) * 255)\n}\nexport const intToHsl = (n: number): Hsl => {\n const r = ((n >> 16) & 255) / 255\n const g = ((n >> 8) & 255) / 255\n const b = (n & 255) / 255\n const mx = Math.max(r, g, b)\n const mn = Math.min(r, g, b)\n const l = (mx + mn) / 2\n const d = mx - mn\n let h = 0\n let s = 0\n if (d > 1e-9) {\n s = d / (1 - Math.abs(2 * l - 1))\n h = mx === r ? (g - b) / d + (g < b ? 6 : 0) : mx === g ? (b - r) / d + 2 : (r - g) / d + 4\n h *= 60\n }\n return { h, s, l }\n}\n/** CIE L* lightness of a packed RGB colour. */\nexport const lstar = (n: number): number => {\n const linear = (c: number) => ((c /= 255) <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4))\n const Y = 0.2126 * linear((n >> 16) & 255) + 0.7152 * linear((n >> 8) & 255) + 0.0722 * linear(n & 255)\n return Y > 216 / 24389 ? 116 * Math.cbrt(Y) - 16 : (Y * 24389) / 27\n}\nexport const hexString = (n: number): string => '#' + (n >>> 0).toString(16).padStart(6, '0')\n\nexport interface PaletteOptions {\n seed?: number | string\n style?: string\n state?: string\n}\nexport type Palette = { meta: { seed: number | string; style: string; state: string; scheme: string; base: string; accentMode: 'wall' | 'object' } } & Record<string, number | object>\n\n/** Seeded colour-harmony palette: a facade base colour, a harmony scheme, role colours and contrast rules. */\nexport function palette(o?: PaletteOptions): Palette {\n const opt = o || {}\n let style = resolveStyleId(opt.style || 'budget')\n if (!registries().PALETTE_STYLES[style]) style = registries().PALETTE_STYLES.mid ? 'mid' : Object.keys(registries().PALETTE_STYLES)[0]\n const def = registries().PALETTE_STYLES[style]\n const state = opt.state || 'normal'\n const seed = opt.seed == null ? 1 : opt.seed\n const rng = createRng(seed, STREAM.palettePrefix + (def.seedKey ?? style))\n const table = def.facadeColors\n const base = table[Math.floor(rng() * table.length)]\n const scheme = SCHEMES[Math.floor(rng() * 4)]\n const offsets = HARMONY_OFFSETS[scheme]\n const jit = (v: number, a: number) => v + (rng() - 0.5) * a\n const hsl = (h: number, s: number, l: number): Hsl => ({ h: ((h % 360) + 360) % 360, s: clamp(s, 0, 1), l: clamp(l, 0, 1) })\n const H0 = base[1]\n const H1 = H0 + offsets[0]\n const H2 = H0 + offsets[1]\n const draw: PaletteDraw = { rng, base, H0, H1, H2, jit, hsl }\n const early = def.early(draw)\n const { wallMode, sMax } = early\n const R: Record<string, Hsl> = Object.assign({}, early.roles)\n const ctx: PaletteContext = Object.assign({ style, sMax, wallMode, generalFloor: early.generalFloor }, draw)\n for (const c of registries().ROOM_COLORS) {\n const [wh, wl] = c.wall(ctx)\n R['wall_' + c.type] = hsl(wh, c.neutral ? Math.min(0.16, sMax) : clamp(jit(sMax * 0.75, sMax * 0.5), 0.03, sMax), jit(wl, 0.03))\n const pi = c.floor || early.generalFloor\n R['floor_' + c.type] = hsl(pi[0], Math.min(pi[1], wallMode ? 0.18 : 0.3), jit(pi[2], 0.04))\n }\n Object.assign(R, def.late(draw, early))\n // state hook (e.g. dirt: desaturate and darken)\n registries().STATE_PLUGINS[state]?.adjustPalette?.(R)\n // anti-clash rules: floor never saturated if the wall is; minimum lightness separation\n const adjust = (color: Hsl, ref: Hsl, min: number, preferredDir?: number) => {\n for (let i = 0; i < 60; i++) {\n if (Math.abs(lstar(hslToInt(color.h, color.s, color.l)) - lstar(hslToInt(ref.h, ref.s, ref.l))) >= min) return\n const refL = lstar(hslToInt(ref.h, ref.s, ref.l))\n let dir = preferredDir || (refL > 50 ? -1 : 1)\n if ((dir < 0 && color.l <= 0.06) || (dir > 0 && color.l >= 0.94)) dir = -dir\n color.l = clamp(color.l + dir * 0.015, 0.04, 0.96)\n }\n }\n const types = registries().ROOM_COLORS.map((c) => c.type)\n for (const c of types) {\n const w = R['wall_' + c]\n const p = R['floor_' + c]\n if (w.s > 0.3) p.s = Math.min(p.s, 0.2)\n if (p.s > HIGH_SATURATION) p.s = HIGH_SATURATION - 0.05\n adjust(p, w, MIN_WALL_FLOOR_CONTRAST + 2, lstar(hslToInt(w.h, w.s, w.l)) > 50 ? -1 : 1)\n }\n const floorRef = R[ROLE_FLOOR_REFERENCE] || R['floor_' + types[0]]\n const fabric = R[ROLE_FABRIC_MAIN]\n adjust(fabric, floorRef, MIN_FABRIC_FLOOR_CONTRAST + 3)\n adjust(R[ROLE_FABRIC_ACCENT], floorRef, MIN_FABRIC_FLOOR_CONTRAST + 3)\n for (const c of types) {\n const p = R['floor_' + c]\n if (Math.abs(lstar(hslToInt(fabric.h, fabric.s, fabric.l)) - lstar(hslToInt(p.h, p.s, p.l))) < MIN_FABRIC_FLOOR_CONTRAST)\n adjust(p, fabric, MIN_FABRIC_FLOOR_CONTRAST + 2, lstar(hslToInt(fabric.h, fabric.s, fabric.l)) > 50 ? -1 : 1)\n }\n const out: Record<string, unknown> = { meta: { seed, style, state, scheme, base: base[0], accentMode: wallMode ? 'wall' : 'object' } }\n for (const k of Object.keys(R)) out[k] = hslToInt(R[k].h, R[k].s, R[k].l)\n // final contrast after rounding: fabric against every floor; search lightness for floor (then wall) satisfying both rules\n const num = (k: string) => out[k] as number\n const pairOk = (w: number, p: number) => Math.abs(lstar(w) - lstar(p)) >= MIN_WALL_FLOOR_CONTRAST + 1 && Math.abs(lstar(num(ROLE_FABRIC_MAIN)) - lstar(p)) >= MIN_FABRIC_FLOOR_CONTRAST + 1\n const search = (color: number, ok: (n: number) => boolean) => {\n const h = intToHsl(color)\n let bestValue: number | null = null\n let md = 9\n for (let l = 0.02; l <= 0.98; l += 0.005) {\n const n = hslToInt(h.h, h.s, l)\n if (ok(n) && Math.abs(l - h.l) < md) {\n md = Math.abs(l - h.l)\n bestValue = n\n }\n }\n return bestValue\n }\n for (const c of types) {\n if (pairOk(num('wall_' + c), num('floor_' + c))) continue\n const n = search(num('floor_' + c), (p) => pairOk(num('wall_' + c), p))\n if (n != null) {\n out['floor_' + c] = n\n continue\n }\n // no solution with the floor alone: move the wall\n const w = search(num('wall_' + c), (w2) => pairOk(w2, num('floor_' + c)))\n if (w != null) out['wall_' + c] = w\n }\n return out as Palette\n}\n","import { EPS, MARGIN, TOL } from './constants'\nimport { cardinal, clamp, eq, extent, inner, overlaps, r2 } from './geometry'\nimport { registries } from './registry'\nimport { isOpenSide, openingsOfFloor, windowsOfRoom, zonesOfFloor } from './queries'\nimport type { Plan, PlanOpening, PlanWindow, Rect, Room, Slot, SlotDef, Vec2 } from './types'\n\nconst SIDE_NORMAL: Record<string, Vec2> = { left: [1, 0], right: [-1, 0], front: [0, 1], back: [0, -1] }\nconst FIXED_FACING: Record<string, Vec2> = { 'u+': [1, 0], 'u-': [-1, 0], 'v+': [0, 1], 'v-': [0, -1] }\nconst SIDE_OPPOSITE: Record<string, string> = { front: 'back', back: 'front', left: 'right', right: 'left' }\nconst WINDOW_SIDE: Record<string, string> = { front: 'front', back: 'back', left: 'left', right: 'right' }\n\n/** Slot definitions of a room after `without`, `overrides`, `extras` and `any`/window expansion. */\nexport function slotDefsOf(plan: Plan, room: Room): SlotDef[] {\n const name = room.library || room.type\n const key = registries().LIBRARY_ALIAS[name] || name\n const library = room.slots ? room.slots : registries().LIBRARIES[key]\n if (!library) return []\n const R = inner(room.parts[0])\n let defs = typeof library === 'function' ? library({ w: R[2] - R[0], d: R[3] - R[1] }) : library.slice()\n defs = defs.map((x) => Object.assign({}, x))\n for (const id of room.without || []) defs = defs.filter((x) => x.id !== id)\n for (const [id, aj] of Object.entries(room.overrides || {})) {\n const i = defs.findIndex((x) => x.id === id)\n if (i < 0) continue\n if (aj === null) defs.splice(i, 1)\n else defs[i] = Object.assign(defs[i], aj)\n }\n defs.push(...(room.extras || []).map((x) => Object.assign({}, x)))\n const out: SlotDef[] = []\n for (const def of defs) {\n def.parent = def.on\n if (def.anchor === 'wall' && def.side === 'any') for (const l of ['left', 'right', 'front', 'back']) out.push(Object.assign({}, def, { id: def.id + '@' + l, side: l as SlotDef['side'], group: def.group || def.id }))\n else if (def.anchor === 'corner' && def.corner === 'any') for (const l of ['front-left', 'front-right', 'back-left', 'back-right']) out.push(Object.assign({}, def, { id: def.id + '@' + l, corner: l, group: def.group || def.id }))\n else if (def.anchor === 'window' && def.n == null) {\n const windowList = windowsOfRoom(plan, room)\n windowList.forEach((_j, i) => out.push(Object.assign({}, def, { id: def.id + '@w' + i, n: i, group: def.group || def.id })))\n } else out.push(def)\n }\n return out\n}\n\nexport function resolveSlots(plan: Plan): Slot[] {\n const all: Slot[] = []\n for (const room of plan.rooms.concat(plan.zones)) {\n const defs = slotDefsOf(plan, room)\n const byId: Record<string, Slot> = {}\n // stairs: a door on any storey applies\n const zones = room.type === 'stairs' ? plan.floors.flatMap((_, floorIndex) => zonesOfFloor(plan, floorIndex)) : zonesOfFloor(plan, room.floor)\n for (const def of defs) {\n const s = resolveSlot(plan, room, def, byId, zones)\n byId[def.id] = s\n all.push(s)\n }\n }\n return all\n}\n\n/** Fields `resolveSlot` adds once it knows where the slot sits. */\ntype SlotPlacementKey = 'x' | 'z' | 'ry' | 'w' | 'd' | 'frontU' | 'frontV' | 'aabb' | '_cell'\n\nexport function resolveSlot(plan: Plan, room: Room, def: SlotDef, byId: Record<string, Slot>, zones: Rect[]): Slot {\n const base: Omit<Slot, SlotPlacementKey> = {\n id: def.id,\n room: room.id,\n floor: room.floor,\n outdoor: room.outdoor,\n anchor: def.anchor,\n side: def.side || def.corner || null,\n cats: def.cats,\n slide: def.slide,\n required: !!def.required,\n chance: def.required ? 1 : def.chance == null ? 1 : def.chance,\n clearance: def.clearance == null ? 0.5 : def.clearance,\n front: def.facing || 'center',\n group: def.group || null,\n requires: def.requires || null,\n on: def.parent || null,\n target: def.target || null,\n valid: true,\n reason: null,\n }\n const invalid = (m: string): Slot => Object.assign(base, { valid: false, reason: m, x: 0, z: 0, ry: 0, w: 0, d: 0, frontU: 0, frontV: 1, aabb: [0, 0, 0, 0], _cell: null }) as Slot\n if (def.anchor === 'on' || def.anchor === 'inside') {\n const parent = def.parent ? byId[def.parent] : undefined\n if (!parent || !parent.valid) return invalid('invalid_parent')\n return Object.assign(base, { x: parent.x, z: parent.z, ry: parent.ry, w: parent.w, d: parent.d, frontU: parent.frontU, frontV: parent.frontV, aabb: parent.aabb, _cell: parent._cell }) as Slot\n }\n const size = def.size as Vec2\n const roomCenter = ((): Vec2 => {\n const R0 = inner(room.parts[0])\n return [(R0[0] + R0[2]) / 2, (R0[1] + R0[3]) / 2]\n })()\n const openings = openingsOfFloor(plan, room.floor)\n let point: Vec2 = [0, 0]\n const targetPoint = (rule: string): Vec2 => {\n if (rule === 'door') {\n let best: PlanOpening | null = null\n let bestDist = 1e9\n for (const ab of openings) {\n const dist = Math.hypot(ab.u - point[0], ab.v - point[1])\n if (dist < bestDist) {\n bestDist = dist\n best = ab\n }\n }\n return best ? [best.u, best.v] : roomCenter\n }\n if (rule === 'target') {\n const t = byId[def.target as string]\n return t && t.valid ? [t.x, t.z] : roomCenter\n }\n return roomCenter\n }\n const free = (rect: Rect) => !!def.floorFree || !zones.some((z) => overlaps(rect, z, room.type === 'stairs' ? -0.011 : EPS))\n const rule: string = def.facing || 'center'\n let R = inner(room.parts[Math.min(def.part || 0, room.parts.length - 1)])\n if (def.anchor === 'wall' || def.anchor === 'window') {\n let side = def.side as string\n let a: number | null = null\n let win: PlanWindow | null = null\n if (def.anchor === 'window') {\n const windowList = windowsOfRoom(plan, room)\n win = windowList[def.n as number]\n if (!win) return invalid('no_window')\n const found = win\n side = room.outdoor ? SIDE_OPPOSITE[win.side] : WINDOW_SIDE[win.side]\n const cand = room.parts\n .map(inner)\n .find(\n (r) =>\n (found.axis === 'u' ? found.u >= r[0] - TOL && found.u <= r[2] + TOL : found.v >= r[1] - TOL && found.v <= r[3] + TOL) &&\n ((side === 'left' && eq(r[0], found.pos + MARGIN)) || (side === 'right' && eq(r[2], found.pos - MARGIN)) || (side === 'front' && eq(r[1], found.pos + MARGIN)) || (side === 'back' && eq(r[3], found.pos - MARGIN))),\n )\n if (!cand) return invalid('window_outside_room')\n R = cand\n a = win.axis === 'u' ? win.u : win.v\n }\n const n = SIDE_NORMAL[side]\n if (!n) return invalid('invalid_side')\n const horizontal = side === 'front' || side === 'back'\n const a0 = horizontal ? R[0] : R[1]\n const a1 = horizontal ? R[2] : R[3]\n const len = a1 - a0\n const depth = size[1]\n if (depth > (horizontal ? R[3] - R[1] : R[2] - R[0]) + EPS) return invalid('larger_than_room')\n const hw = Math.min(size[0], len) / 2\n const cell = (ac: number): Rect =>\n side === 'left' ? [R[0], ac - hw, R[0] + depth, ac + hw] : side === 'right' ? [R[2] - depth, ac - hw, R[2], ac + hw] : side === 'front' ? [ac - hw, R[1], ac + hw, R[1] + depth] : [ac - hw, R[3] - depth, ac + hw, R[3]]\n const nominal = a != null ? a : a0 + hw + (def.pos == null ? 0.5 : def.pos) * Math.max(0, len - 2 * hw) + (def.shift || 0)\n const wp = side === 'left' ? R[0] - MARGIN : side === 'right' ? R[2] + MARGIN : side === 'front' ? R[1] - MARGIN : R[3] + MARGIN\n const pa = clamp(nominal, a0 + hw, a1 - hw)\n let found: number | null = null\n const steps = [0]\n if (def.anchor !== 'window') for (let k = 1; k <= 60; k++) steps.push(k, -k)\n for (const k of steps) {\n const ac = pa + k * 0.05\n if (ac - hw < a0 - EPS || ac + hw > a1 + EPS) continue\n if (free(cell(ac))) {\n found = ac\n break\n }\n }\n if (found == null) return invalid('blocked_by_door')\n const sp: Vec2 = horizontal ? [found, wp - n[1] * 0.1] : [wp - n[0] * 0.1, found]\n if (isOpenSide(plan, room, sp[0], sp[1])) return invalid('open_wall')\n const rect = cell(found)\n return Object.assign(base, { side, x: r2((rect[0] + rect[2]) / 2), z: r2((rect[1] + rect[3]) / 2), frontU: n[0], frontV: n[1], ry: r2(Math.atan2(n[0], n[1])), w: size[0], d: size[1], aabb: rect.map(r2) as Rect, _cell: { rect, f: n, enclosed: [side], R, size } }) as Slot\n }\n if (def.anchor === 'corner') {\n const [cornerV, cornerU] = (def.corner as string).split('-')\n const normalV = SIDE_NORMAL[cornerV]\n const normalU = SIDE_NORMAL[cornerU]\n if (!normalV || !normalU) return invalid('invalid_corner')\n const kx = cornerU === 'left' ? R[0] : R[2]\n const kz = cornerV === 'front' ? R[1] : R[3]\n point = [kx, kz]\n let f: Vec2\n if (FIXED_FACING[rule]) {\n f = FIXED_FACING[rule]\n if (!((f[0] === normalU[0] && f[1] === normalU[1]) || (f[0] === normalV[0] && f[1] === normalV[1]))) f = normalU\n } else {\n const t = targetPoint(rule)\n f = Math.abs(t[0] - kx) >= Math.abs(t[1] - kz) ? normalU : normalV\n }\n const [extentU, extentV] = extent(size, f)\n if (extentU > R[2] - R[0] + EPS || extentV > R[3] - R[1] + EPS) return invalid('larger_than_room')\n const rect: Rect = [cornerU === 'left' ? R[0] : R[2] - extentU, cornerV === 'front' ? R[1] : R[3] - extentV, cornerU === 'left' ? R[0] + extentU : R[2], cornerV === 'front' ? R[1] + extentV : R[3]]\n if (!free(rect)) return invalid('blocked_by_door')\n for (const sp of [[kx - normalU[0] * (MARGIN + 0.1), (rect[1] + rect[3]) / 2], [(rect[0] + rect[2]) / 2, kz - normalV[1] * (MARGIN + 0.1)]]) if (isOpenSide(plan, room, sp[0], sp[1])) return invalid('open_wall')\n return Object.assign(base, { x: r2((rect[0] + rect[2]) / 2), z: r2((rect[1] + rect[3]) / 2), frontU: f[0], frontV: f[1], ry: r2(Math.atan2(f[0], f[1])), w: size[0], d: size[1], aabb: rect.map(r2) as Rect, _cell: { rect, f, enclosed: [cornerU, cornerV], R, size } }) as Slot\n }\n if (def.anchor === 'center') {\n let cx = R[0] + (def.fx == null ? 0.5 : def.fx) * (R[2] - R[0]) + (def.dx || 0)\n let cz = R[1] + (def.fz == null ? 0.5 : def.fz) * (R[3] - R[1]) + (def.dz || 0)\n point = [cx, cz]\n let f: Vec2\n if (FIXED_FACING[rule]) f = FIXED_FACING[rule]\n else {\n const t = targetPoint(rule)\n const dx = t[0] - cx\n const dz = t[1] - cz\n f = Math.hypot(dx, dz) < 0.05 ? [0, 1] : cardinal(dx, dz)\n }\n const [extentU, extentV] = extent(size, f)\n if (extentU > R[2] - R[0] + EPS || extentV > R[3] - R[1] + EPS) return invalid('larger_than_room')\n cx = clamp(cx, R[0] + extentU / 2, R[2] - extentU / 2)\n cz = clamp(cz, R[1] + extentV / 2, R[3] - extentV / 2)\n const rect: Rect = [cx - extentU / 2, cz - extentV / 2, cx + extentU / 2, cz + extentV / 2]\n if (!free(rect)) return invalid('blocked_by_door')\n return Object.assign(base, { x: r2(cx), z: r2(cz), frontU: f[0], frontV: f[1], ry: r2(Math.atan2(f[0], f[1])), w: size[0], d: size[1], aabb: rect.map(r2) as Rect, _cell: { rect, f, enclosed: [] as string[], R, size } }) as Slot\n }\n return invalid('unknown_anchor')\n}\n","import { DOOR_CLEARANCE } from './constants'\nimport { createPlacementContext, placementKit, runPostProcess } from './context'\nimport { runResultExtensions } from './extensions'\nimport { fillRoom } from './fill'\nimport { overlaps, openingZones, r2 } from './geometry'\nimport { STREAM } from './legacy-seeds'\nimport { translate } from './locale'\nimport { buildPlan, floorsOf } from './plan'\nimport { hexString, palette } from './palette'\nimport { registries } from './registry'\nimport { createRng, hashString } from './rng'\nimport { resolveSlots } from './slots'\nimport { checkLot, clampOptionsToZone, resolveZone, useOf } from './zoning'\nimport type { FloorplanOptions, FloorplanResult, ItemColor, FloorplanResultFields, PlacedItem, Plan, Rect, ResultItem, ResultLot, Slot, SlotFields, TemplateDef, ZoneAdjustment } from './types'\nimport type { StateContext } from './types'\n\nexport function templateOf(t: string | TemplateDef): TemplateDef {\n if (typeof t === 'string') {\n if (!registries().TEMPLATES[t]) throw new Error('Unknown template: ' + t)\n return registries().TEMPLATES[t]\n }\n return t\n}\n\n/** A recorded slot: the resolved slot without its internal fields, with the category names only. */\nexport interface RecordedSlot extends Omit<SlotFields, '_cell' | 'cats'> {\n cats: string[]\n [extra: string]: unknown\n}\n\nconst cleanSlot = (s: Slot): RecordedSlot => {\n const o: Record<string, unknown> = {}\n for (const k of Object.keys(s)) if (k[0] !== '_') o[k] = s[k]\n o.cats = Object.keys(s.cats || {})\n return o as RecordedSlot // the slot's own fields, copied\n}\n\n/** Recorded slots (resolved positions) of every storey and of the lot. */\nexport function slots(template: string | TemplateDef, options?: FloorplanOptions): RecordedSlot[] {\n const tpl = templateOf(template)\n const o = options || {}\n const plan = buildPlan(tpl, o.w, o.d, o)\n const locale = o.locale || 'en'\n return resolveSlots(plan)\n .map(cleanSlot)\n .map((s) => (s.reason ? Object.assign(s, { reason: translate('reasons', s.reason, locale) }) : s))\n}\n\n/** Picks the house state: the requested one, else a seeded draw over the registered distribution, else `normal`. */\nexport function pickState(requested: string | undefined, seed: number | string): string {\n if (requested && registries().STATE_PLUGINS[requested]) return requested\n const dist = registries().stateDistribution.weights\n if (!dist) return 'normal'\n const x = createRng(seed, registries().stateDistribution.seedKey)()\n let acc = 0\n const keys = Object.keys(dist)\n for (const k of keys) {\n acc += dist[k]\n if (x < acc) return k\n }\n return keys[keys.length - 1]\n}\n\nfunction colorOf(m: PlacedItem, seed: number | string): number | string {\n const spec: ItemColor = m.colorSpec || registries().CATALOG[m.type]?.color || { role: 'wood' }\n if ('role' in spec) return spec.role\n if ('hex' in spec) return spec.hex\n return spec.pick[hashString(seed + '|' + (m._seedId ?? m.id)) % spec.pick.length]\n}\n\nfunction applyState(plan: Plan, items: PlacedItem[], ctx: ReturnType<typeof createPlacementContext>, seed: number | string, state: string): PlacedItem[] {\n const plugin = registries().STATE_PLUGINS[state]\n if (!plugin || state === 'normal') return []\n const c: StateContext = {\n plan,\n items,\n seed,\n state,\n rng: createRng(seed, plugin.seedKey ?? 'state:' + state),\n ctx,\n kit: placementKit,\n catalog: registries().CATALOG,\n wallTopHeights: registries().WALL_TOP_HEIGHTS,\n }\n return plugin.apply(c)\n}\n\nconst loc = (key: string | undefined, locale: string, ns: 'labels' | 'facadeColors' = 'labels', vars?: Record<string, string | number>) => (key ? translate(ns, key, locale, vars) : key)\n\n/** Generates a plan: building, lot, seeded item fill, decor, house state and palette. */\nexport function generate(template: string | TemplateDef, options?: FloorplanOptions): FloorplanResult {\n const tpl = templateOf(template)\n const o = options || {}\n const seed = o.seed == null ? 1 : o.seed\n const locale = o.locale || 'en'\n let op: FloorplanOptions = Object.assign({}, o, { seed })\n const zone = resolveZone(o.zone)\n const adjustments: ZoneAdjustment[] = []\n if (zone) op = clampOptionsToZone(tpl, op, zone, adjustments)\n const plan = buildPlan(tpl, op.w, op.d, op, { zone, adjustments })\n const all = resolveSlots(plan)\n const items: PlacedItem[] = []\n const missing: { room: string; slot: string }[] = []\n for (const room of plan.rooms.concat(plan.zones)) {\n const sl = all.filter((s) => s.room === room.id && s.floor === room.floor)\n const r = fillRoom(plan, room, sl, createRng(seed, STREAM.roomPrefix + (room.seedKey ?? registries().SEED_KEYS.rooms[room.id] ?? room.id)))\n items.push(...r.items)\n missing.push(...r.missing)\n }\n const ctx = runPostProcess(plan, items, seed)\n const state = pickState(o.state, seed)\n const stateItemsAll = applyState(plan, items, ctx, seed, state)\n const colors = palette({ seed, style: plan.style, state })\n const strip = (m: PlacedItem): ResultItem => {\n const x: Record<string, unknown> = {}\n for (const k of Object.keys(m)) if (k[0] !== '_' && k !== 'colorSpec') x[k] = m[k]\n return x as ResultItem // the item's own fields, copied\n }\n const L = plan.lot\n const lot: ResultLot | null = L\n ? {\n rect: L.rect.map(r2) as Rect,\n setback: r2(L.setback),\n backyard: r2(L.backyard),\n sideYard: L.sideYard,\n style: L.style,\n pool: L.pool,\n zones: plan.zones.map((z) => ({ id: z.id, type: z.type, label: z.label, name: loc(z.label, locale), parts: z.parts, ground: z.ground })),\n perimeter: L.perimeter.map((s) => Object.assign({ color: 'wall' }, s)),\n gates: plan.gates.map((g) => ({ id: g.id, type: g.type, model: g.model, u: g.u, v: g.v, axis: g.axis, width: g.width, height: g.height, side: g.side, to: g.to, material: g.material, open: !!g.open, color: 'gate' })),\n paths: plan.paths.map((c) => ({ id: c.id, type: c.type, from: c.from, to: c.to, width: c.width, rects: c.rects, points: c.points })),\n }\n : null\n const facade = Object.assign({}, plan.facade, {\n color: { name: loc(colors.meta.base, locale, 'facadeColors'), key: colors.meta.base, hex: hexString(colors.facade as number) },\n roles: { facade: 'facade', detail: 'facade_detail', roof: 'roof', wall: 'wall', gate: 'gate' },\n })\n const itemsOut = items.map((m) => {\n const out = strip(m)\n out.color = colorOf(m, seed)\n return out\n })\n const stateItemsOut = stateItemsAll.map((m) => {\n const out = strip(m)\n if (m.category) out.color = colorOf(m, seed)\n return out\n })\n const base: Omit<FloorplanResultFields, 'partyWalls'> = {\n template: tpl.id,\n name: translate('templates', tpl.id, locale),\n use: useOf(tpl),\n seed,\n style: plan.style,\n state,\n w: plan.w,\n d: plan.d,\n floors: plan.floors.map((f) => ({ index: f.index, label: f.name, name: f.number != null ? translate('labels', 'floor_n', locale, { n: f.number }) : loc(f.name, locale), number: f.number, y0: f.y0, ceiling: f.ceiling })),\n rooms: plan.rooms.map((c) => ({\n id: c.id,\n type: c.type,\n label: c.label,\n name: loc(c.label, locale),\n floor: c.floor,\n u0: c.parts[0][0],\n v0: c.parts[0][1],\n u1: c.parts[0][2],\n v1: c.parts[0][3],\n parts: c.parts,\n link: c.link,\n ceiling: c.ceiling || plan.floors[c.floor].ceiling,\n color: { wall: 'wall_' + c.type, floor: 'floor_' + c.type },\n })),\n walls: plan.walls,\n doors: plan.doors,\n windows: plan.windows,\n openPairs: ([] as [string, string][]).concat(...Object.values(plan.openPairs)),\n facade,\n lot,\n items: itemsOut,\n stateItems: stateItemsOut,\n colors,\n building: tpl.building ? tpl.building(plan.w, plan.d, op) : null,\n missing,\n }\n if (tpl.singleFloor) base.floorNumber = op.floor || 3\n const result: FloorplanResult = Object.assign(base, { partyWalls: tpl.partyWalls || [] })\n if (plan.config) result.config = plan.config\n runResultExtensions(plan, result, seed, op)\n if (zone) {\n const report = { zone: zone.id, adjustments, violations: checkLot(zone, lot, Object.assign({}, result, { rooms: plan.rooms })) }\n result.zoning = report\n }\n return result\n}\n\nconst isSolid = (m: Pick<PlacedItem, 'flat' | 'on' | 'decor' | 'mount'>) => !m.flat && !m.on && (!m.decor || m.mount === 'floor')\n\n/** Validates a result of `generate`; returns a list of messages (empty when valid). */\nexport function validate(result: FloorplanResult, options?: { locale?: string }): string[] {\n const locale = options?.locale || result.locale || 'en'\n const t = (key: string, vars: Record<string, string | number>) => translate('messages', key, locale, vars)\n const errors: string[] = []\n const solids = result.items.filter(isSolid)\n for (let i = 0; i < solids.length; i++)\n for (let j = i + 1; j < solids.length; j++)\n if (solids[i].floor === solids[j].floor && !solids[i].barricade && !solids[j].barricade && overlaps(solids[i].aabb, solids[j].aabb, 0.011)) errors.push(t('overlap', { a: solids[i].id, b: solids[j].id }))\n for (const m of solids) {\n if (m.barricade) continue\n for (const p of result.doors) if (p.floor === (m.outdoor ? 0 : m.floor) && p.zones.some((z) => overlaps(m.aabb, z, 0.011))) errors.push(t('door_blocked', { id: m.id }))\n if (result.lot) for (const g of result.lot.gates) if (m.outdoor && openingZones(g.u, g.v, 'u', g.width, DOOR_CLEARANCE).some((z) => overlaps(m.aabb, z, 0.011))) errors.push(t('gate_blocked', { id: m.id }))\n }\n for (const f of result.missing) errors.push(t('missing_required', { room: f.room, slot: f.slot }))\n if (result.zoning) for (const v of result.zoning.violations) errors.push(t('zone_violation', { zone: result.zoning.zone, rule: v.rule, actual: v.actual, limit: v.limit }))\n return errors\n}\n\n/** Size limits and default size of a template (they can depend on options such as `tier`). */\nexport function limitsOf(template: string | TemplateDef, options?: FloorplanOptions) {\n const tpl = templateOf(template)\n const op = options || {}\n return { limits: tpl.limitsFn ? tpl.limitsFn(op) : tpl.limits, defaults: tpl.defaultsFn ? tpl.defaultsFn(op) : tpl.defaults }\n}\n\nexport function listTemplates(locale = 'en') {\n return Object.values(registries().TEMPLATES).map((t) => {\n const a = floorsOf(t, {})\n return {\n id: t.id,\n name: translate('templates', t.id, locale),\n use: useOf(t),\n style: typeof t.style === 'function' ? t.style({}) : t.style,\n limits: t.limits,\n defaults: t.defaults,\n floors: a.length,\n floorRange: t.floorRange || null,\n lot: !!t.lot,\n options: t.options || {},\n }\n })\n}\n\n","import type { Vec3 } from './destruction'\n\n/**\n * The numbers of the shove a blast gives to a body that moves (a loose item, a piece of furniture, a person): all of them a game value, with a default that reads well in a room,\n * not a physical table. A host reads them once and lends them to the modules that move their own bodies (`ModuleHost.blastShove`).\n */\nexport interface BlastShoveOptions {\n /**\n * The share of the blast energy that reaches a body as motion: the speed at the centre is `sqrt(2 * energy * coupling / mass)`, before the falloff (default 0.02).\n */\n readonly coupling?: number\n /** Fastest a body is thrown, in m/s, at the centre of the blast (default 20). */\n readonly maxSpeed?: number\n /** How much of the push goes up: the direction is `(away, lift)` normalised from the horizontal outward direction (default 0.3). */\n readonly lift?: number\n /** Below this speed (m/s) nothing moves: a heavy thing far from a small blast stays where it is (default 0.3). */\n readonly minSpeed?: number\n /** Exponent of the falloff `(1 - distance / radius) ^ power`, the same as the damage of the destruction world (default 2). */\n readonly falloffPower?: number\n}\n\n/** The defaults of `BlastShoveOptions`. */\nexport const DEFAULT_BLAST_SHOVE: Readonly<Required<BlastShoveOptions>> = { coupling: 0.02, maxSpeed: 20, lift: 0.3, minSpeed: 0.3, falloffPower: 2 }\n\n/** A blast as the shove reads it: where, how much energy (J) and how far it reaches (m). `reach` (0..1) is the share that got through what stood in the way. */\nexport interface BlastSource {\n readonly point: Vec3\n readonly energy: number\n readonly radius: number\n readonly reach?: number\n /**\n * Kilograms of TNT equivalent of the charge. With it a body is pushed by the blast wave itself (`blast-impulse`), and the shove of loose items keeps this module's rule; without it the body\n * takes the charge from `energy` by `BlastImpulseOptions.tntPerJoule`.\n */\n readonly tnt?: number\n /** Inside this radius (metres) the blast is lethal: a body there that the blast reaches (not behind cover) goes down, wounded, wherever the wave pushed it. */\n readonly lethalRadius?: number\n}\n\n/** What a blast does to one body: how fast it leaves (m/s), the unit direction it leaves in, and how far from the centre it was. */\nexport interface BlastShove {\n readonly speed: number\n readonly direction: Vec3\n readonly distance: number\n /** The falloff applied, 0..1. */\n readonly falloff: number\n}\n\n/**\n * The shove a blast gives to a body of `mass` kg whose centre is at `position`: away from the centre, lifted a little, with the speed\n * `min(maxSpeed, sqrt(2 * energy * reach * coupling / mass)) * (1 - distance / radius) ^ 2`. Undefined when the body is outside the radius or the speed is under `minSpeed`.\n * The same rule moves the loose items and furniture of the test room and the people of the characters module, so a game that tunes the options tunes all of them.\n */\nexport function blastShove(blast: BlastSource, target: { readonly position: Vec3; readonly mass: number }, options: BlastShoveOptions = {}): BlastShove | undefined {\n const o = { ...DEFAULT_BLAST_SHOVE, ...options }\n const dx = target.position[0] - blast.point[0]\n const dy = target.position[1] - blast.point[1]\n const dz = target.position[2] - blast.point[2]\n const distance = Math.hypot(dx, dy, dz)\n if (!(blast.radius > 0) || distance > blast.radius) return undefined\n const falloff = (1 - distance / blast.radius) ** o.falloffPower\n const mass = Math.max(target.mass, 0.05)\n const speed = Math.min(o.maxSpeed, Math.sqrt((2 * blast.energy * (blast.reach ?? 1) * o.coupling) / mass)) * falloff\n if (!(speed >= o.minSpeed)) return undefined\n // straight above or below the centre there is no \"away\": the push goes up\n const direction: Vec3 = distance > 1e-4 ? [dx / distance, dy / distance + o.lift, dz / distance] : [0, 1, 0]\n const length = Math.hypot(direction[0], direction[1], direction[2])\n return { speed, direction: [direction[0] / length, direction[1] / length, direction[2] / length], distance, falloff }\n}\n","/**\n * The push a blast gives a standing body, from the physics of the blast wave and not from a game coupling: the impulse of the wave per square metre at a distance from a charge of\n * `tnt` kg of TNT equivalent (Kinney and Graham's fit of the side-on impulse, scaled by the cube root of the charge), reflected on the body, over the area the body shows the wave,\n * divided by its mass. A hand grenade at 3 m gives a person a few tenths of a metre per second; what floors that person is the fragments, not the wave. A big charge close throws.\n */\n\n/** The numbers of the body a blast wave pushes. All have a default for a standing adult. */\nexport interface BlastImpulseOptions {\n /** Square metres of the body the wave meets: about 1.75 m tall by 0.4 m wide (default 0.7). */\n readonly bodyArea?: number\n /** How much of the push goes up: the direction is `(away, lift)` normalised (default 0.15: the wave runs along the ground). */\n readonly lift?: number\n /** Below this speed (m/s) the body does not move (default 0.3). */\n readonly minSpeed?: number\n /**\n * Kilograms of TNT per joule of the blast `energy`, for a blast that does not say its charge (`BlastSource.tnt`). Default 0.24 / 200000: the arsenal's energy scale, where the M67 (180 g\n * of Composition B, 0.24 kg of TNT) is 200 kJ. It is a game equivalence for blasts without a charge, not a physical constant.\n */\n readonly tntPerJoule?: number\n}\n\nexport const DEFAULT_BLAST_IMPULSE: Readonly<Required<BlastImpulseOptions>> = { bodyArea: 0.7, lift: 0.15, minSpeed: 0.3, tntPerJoule: 0.24 / 200000 }\n\n/** Closest distance (m) the fit is read at: inside it the charge is in contact and the body is torn apart anyway. */\nconst NEAREST = 0.3\n\n/**\n * Side-on (incident) specific impulse of the wave, in Pa·s, at `distance` metres from `tnt` kg of TNT in free air: Kinney and Graham, \"Explosive Shocks in Air\" (1985),\n * `I/W^(1/3) = 0.067 sqrt(1 + (Z/0.23)^4) / (Z^2 (1 + (Z/1.55)^3)^(1/3))` bar·ms per kg^(1/3), with the scaled distance `Z = R / W^(1/3)`.\n */\nexport function sideOnImpulse(tnt: number, distance: number): number {\n if (!(tnt > 0)) return 0\n const w3 = Math.cbrt(tnt)\n const z = Math.max(distance, NEAREST) / w3\n const scaled = (0.067 * Math.sqrt(1 + (z / 0.23) ** 4)) / (z * z * Math.cbrt(1 + (z / 1.55) ** 3))\n return scaled * w3 * 100 // bar·ms to Pa·s\n}\n\n/**\n * The impulse per square metre a body facing the wave takes, Pa·s: the side-on impulse reflected. The reflection doubles a weak wave and grows up to about six times close to the charge,\n * where the wave is strong (the ratio of reflected to side-on impulse of the Kingery-Bulmash charts, fitted as `2 + 4 / (1 + Z^2)`).\n */\nexport function bodyImpulse(tnt: number, distance: number): number {\n if (!(tnt > 0)) return 0\n const z = Math.max(distance, NEAREST) / Math.cbrt(tnt)\n return sideOnImpulse(tnt, distance) * (2 + 4 / (1 + z * z))\n}\n\n/** The speed (m/s) a blast wave gives a free body of `mass` kg at `distance` metres from `tnt` kg of TNT, `reach` (0..1) of it getting through what stands in the way. */\nexport function blastBodySpeed(tnt: number, distance: number, mass: number, reach = 1, options: BlastImpulseOptions = {}): number {\n const area = options.bodyArea ?? DEFAULT_BLAST_IMPULSE.bodyArea\n return (bodyImpulse(tnt, distance) * area * Math.max(0, reach)) / Math.max(mass, 1)\n}\n","import { blastBodySpeed, DEFAULT_BLAST_IMPULSE } from './blast-impulse'\nimport type { BlastImpulseOptions } from './blast-impulse'\nimport type { BlastShoveOptions, BlastSource } from './blast-shove'\nimport type { Vec3 } from './destruction'\n\n/** From this speed (m/s) a blast takes a standing body off its feet. Below it the body is only pushed. */\nexport const KNOCK_DOWN_SPEED = 2.5\n/** The angle of a body lying where it fell (the same tilt a dead body takes). */\nexport const KNOCKED_DOWN_ANGLE = 1.35\n/** Seconds the body lies after it lands: this plus the landing speed times `STAND_UP_PER_SPEED`. */\nconst LIE_SECONDS = 1.6\n/** Seconds a body floored by its wounds (inside the lethal radius) lies before it gets up, when it is not dead. */\nconst WOUNDED_LIE_SECONDS = 6\n/** The share of the blast that has to get through for its fragments to reach a body: behind cover that stops half of it the fragments stop too. */\nexport const FRAGMENT_COVER = 0.5\n/** Seconds a body is stunned at the edge of the lethal radius (the ringing ears, the dizziness); it falls with the square of the way to the edge of the blast. */\nconst STUN_SECONDS = 4\nconst STAND_UP_PER_SPEED = 0.25\nconst FALL_SECONDS = 0.25\nconst RISE_SECONDS = 0.6\n/** m/s squared that slows a body sliding on the ground. */\nconst GROUND_FRICTION = 7\nconst GRAVITY = 9.81\n/** Height of the chest above the feet: where the blast takes the body. */\nexport const KNOCK_CHEST = 1.1\nconst CHEST = KNOCK_CHEST\n\n/** What a blast is doing to one body: its velocity (m/s), whether it is in the air, and how far down it is (0 on its feet, 1 lying). */\nexport interface Knock {\n velocity: [number, number, number]\n airborne: boolean\n /** 0..1 */\n lying: number\n /** Seconds left to lie on the ground after it stopped. */\n lieLeft: number\n /** Knocked off its feet by this blast. */\n down: boolean\n /** Floored by its wounds: inside the lethal radius and not behind cover. It lies longer and falls where it stood. */\n wounded?: boolean\n /** Seconds of stun the blast gave the body: dizziness and ringing ears. */\n stunSeconds?: number\n /** The horizontal unit direction away from the blast, even when the push is too weak to move the body: the way it falls. */\n away?: Vec3\n}\n\n/** The mass of a body in kg from its height (m) and its build (1 = average): 70 kg at 1.75 m. */\nexport const bodyMass = (height: number, build = 1): number => 70 * (height / 1.75) ** 2 * build\n\n/**\n * What a blast does to a body standing at `feet`, of `mass` kg. Undefined when the blast does not reach it or does nothing to it.\n *\n * The body is pushed by the blast wave (`blastBodySpeed`, from the charge `blast.tnt`, or from `energy` by `tntPerJoule`), taken at the chest and cut by `reach`, the share that got through\n * cover. It is floored when that push is `KNOCK_DOWN_SPEED` or more, or when it stands inside `lethalRadius` with the blast reaching it (the fragments and the overpressure fell it where it\n * stands). It is stunned for a while inside the radius. `options` are the shove numbers of the host's loose items; only their `minSpeed` applies to a body.\n */\nexport function knockOf(blast: BlastSource, feet: Vec3, mass: number, options?: BlastShoveOptions, impulse: BlastImpulseOptions = {}): Knock | undefined {\n const o = { ...DEFAULT_BLAST_IMPULSE, ...impulse }\n const chest: Vec3 = [feet[0], feet[1] + CHEST, feet[2]]\n const dx = chest[0] - blast.point[0]\n const dy = chest[1] - blast.point[1]\n const dz = chest[2] - blast.point[2]\n const distance = Math.hypot(dx, dy, dz)\n if (!(blast.radius > 0) || distance > blast.radius) return undefined\n const reach = Math.max(0, Math.min(1, blast.reach ?? 1))\n const tnt = blast.tnt ?? blast.energy * o.tntPerJoule\n let speed = blastBodySpeed(tnt, distance, mass, reach, o)\n const minSpeed = impulse.minSpeed ?? options?.minSpeed ?? o.minSpeed\n if (speed < minSpeed) speed = 0\n const struck = reach >= FRAGMENT_COVER\n const wounded = struck && blast.lethalRadius !== undefined && distance <= blast.lethalRadius\n const edge = 1 - distance / blast.radius\n const stunSeconds = struck ? STUN_SECONDS * edge * edge * reach : 0\n if (speed === 0 && !wounded && stunSeconds < 0.25) return undefined\n // straight above or below the centre there is no \"away\": the push goes up\n const horizontal = Math.hypot(dx, dz)\n const away: Vec3 = horizontal > 1e-4 ? [dx / horizontal, o.lift, dz / horizontal] : [0, 1, 0]\n const length = Math.hypot(away[0], away[1], away[2])\n const velocity: [number, number, number] = [(away[0] / length) * speed, (away[1] / length) * speed, (away[2] / length) * speed]\n return {\n velocity,\n airborne: velocity[1] > 0.5,\n lying: 0,\n lieLeft: wounded ? WOUNDED_LIE_SECONDS : 0,\n away: horizontal > 1e-4 ? [dx / horizontal, 0, dz / horizontal] : [0, 0, 0],\n down: speed >= KNOCK_DOWN_SPEED || wounded,\n ...(wounded ? { wounded } : {}),\n ...(stunSeconds >= 0.25 ? { stunSeconds } : {}),\n }\n}\n\n/**\n * Moves a body one step: it slides on the ground and slows, falls when it was knocked down, lies a while and gets up (a dead body stays down). Moves `position` in place; returns true when the\n * body is on its feet and still, and the knock can be dropped.\n */\nexport function stepKnock(knock: Knock, position: { x: number; y: number; z: number }, dt: number, groundAt: (x: number, z: number) => number, alive: boolean): boolean {\n const v = knock.velocity\n position.x += v[0] * dt\n position.z += v[2] * dt\n const ground = groundAt(position.x, position.z)\n if (knock.airborne || position.y > ground + 1e-4) {\n v[1] -= GRAVITY * dt\n position.y += v[1] * dt\n if (position.y <= ground) {\n position.y = ground\n v[1] = 0\n knock.airborne = false\n }\n } else position.y = ground\n const horizontal = Math.hypot(v[0], v[2])\n if (!knock.airborne && horizontal > 0) {\n const slowed = Math.max(0, horizontal - GROUND_FRICTION * dt)\n v[0] *= slowed / horizontal\n v[2] *= slowed / horizontal\n }\n const moving = horizontal > 0.05 || knock.airborne\n if (knock.down) {\n // a body floored where it stands (its wounds, not the push) still takes the time of a fall to reach the ground\n if (moving || knock.lying < 1) knock.lying = Math.min(1, knock.lying + dt / FALL_SECONDS)\n else if (alive) {\n knock.lieLeft = knock.lieLeft > 0 ? knock.lieLeft : LIE_SECONDS + Math.hypot(v[0], v[2]) * STAND_UP_PER_SPEED\n knock.lieLeft -= dt\n if (knock.lieLeft <= 0) knock.down = false\n }\n } else if (knock.lying > 0) knock.lying = Math.max(0, knock.lying - dt / RISE_SECONDS)\n return !moving && !knock.down && knock.lying === 0\n}\n","export interface CostOptions {\n /** Reads of `state()` and of `describe()` to time. Default 10 000. */\n reads?: number\n /** Ceiling, in milliseconds, for all the reads of one method. Default 50 (5 microseconds per read). */\n ceilingMs?: number\n /** Ceiling of heap growth, in bytes, over all the reads of one method (only where `process.memoryUsage` exists). Default 1 MiB. */\n allocationBytes?: number\n}\n\nconst DEFAULT_COST_READS = 10_000\nconst DEFAULT_COST_CEILING_MS = 50\nconst DEFAULT_COST_ALLOCATION_BYTES = 1024 * 1024\n\nconst heapUsedBytes = (): number | undefined => {\n const nodeProcess = (globalThis as { process?: { memoryUsage?: () => { heapUsed: number } } }).process\n return nodeProcess?.memoryUsage?.().heapUsed\n}\n\ntype CheckReadCostParams = { readonly name: string; readonly read: () => unknown; readonly options: CostOptions; readonly problems: string[] }\n\nexport const checkReadCost = ({ name, read, options, problems }: CheckReadCostParams): void => {\n const reads = options.reads ?? DEFAULT_COST_READS\n const ceilingMs = options.ceilingMs ?? DEFAULT_COST_CEILING_MS\n const allocationBytes = options.allocationBytes ?? DEFAULT_COST_ALLOCATION_BYTES\n if (read() !== read()) problems.push(`${name}() returns a new object on each read: cache it between changes (cost contract)`)\n // a first pass lets the engine compile and optimise the loop: that code and its feedback are heap too, and would read as the method allocating\n for (let i = 0; i < reads; i++) read()\n const heapBefore = heapUsedBytes()\n const started = performance.now()\n for (let i = 0; i < reads; i++) read()\n const elapsedMs = performance.now() - started\n const heapAfter = heapUsedBytes()\n if (elapsedMs > ceilingMs) problems.push(`${name}() took ${elapsedMs.toFixed(1)} ms for ${reads} reads, over the ${ceilingMs} ms ceiling (cost contract)`)\n if (heapBefore !== undefined && heapAfter !== undefined && heapAfter - heapBefore > allocationBytes)\n problems.push(`${name}() grew the heap by ${heapAfter - heapBefore} bytes over ${reads} reads, over the ${allocationBytes} byte ceiling (cost contract)`)\n}\n","import { checkReadCost } from './impact-cost'\nimport type { CostOptions } from './impact-cost'\nimport type { DamageType, DestructibleSpec, DestructionEvent, Hit, JointSpec, ObjectState, ToolKind, Vec3 } from './destruction'\n\n/**\n * What a game module implements for an object whose behaviour it owns (a vehicle with its own panel deformation, a creature, a machine). The\n * world (`DestructionWorld.register`) hosts it next to its own objects: raycast, shoot, explode, hit, disassemble, extinguish, update, state,\n * reset and `on` all route to it.\n *\n * Space: the impl receives hits in WORLD space and returns events in WORLD space (it owns its transform; the transform given to `register` or\n * `setTransform` is only used by the world for raycasts and blast range). Every event must carry `object === id` and name parts listed by\n * `describe()`.\n */\n/** World-space ray for `DestructibleImpl.surfaceRay`. */\nexport interface SurfaceRay {\n readonly origin: Vec3\n readonly direction: Vec3\n readonly maxDistance: number\n ignored?(part: string): boolean\n}\n\nexport interface SurfaceRayHit {\n readonly part: string\n readonly point: Vec3\n readonly normal: Vec3\n readonly distance: number\n /** Thickness the ray crosses in this part, metres. */\n readonly pathLen: number\n}\n\nexport interface DestructibleImpl {\n readonly id: string\n readonly name?: string\n /**\n * Parts, joints and structure in the impl's local space, for raycast, inspector and log.\n * COST CONTRACT (D8): called per frame by the renderer, so it is O(1), allocation-free and cached between changes: the same object comes\n * back until a hit, tool, fire or pose change alters it. `checkDestructible(impl, { cost: true })` measures it.\n */\n describe(): DestructibleSpec\n /** Apply one hit (see `IMPACT_CONTRACT` for the fields per type) and return the events it caused. */\n hit(hit: Hit): DestructionEvent[]\n /**\n * The real surface a ray meets, for an impl whose drawn shape is not its boxes (a car body): the boxes of `describe()` only say where to look, and a shot that crosses\n * them without touching the drawn surface goes on. `ignored` answers for the parts the round already went through. Null when the ray meets nothing.\n */\n surfaceRay?(ray: SurfaceRay): SurfaceRayHit | null\n /** Advance fire, melting, collapse and other timed behaviour. */\n update?(dt: number): DestructionEvent[]\n /**\n * COST CONTRACT (D8): the host reads it per part per frame, so it is O(1), allocation-free and cached between changes (see `describe()`).\n * The cached object is shared with every reader: treat it as read-only, copy before changing it.\n */\n state(): Readonly<ObjectState>\n reset?(): void\n /** The world took the object out (`DestructionWorld.remove`): the impl lets go of what it joined (shared queues, listeners). */\n dispose?(): void\n /** Same contract as `DestructionWorld.disassemble`: progress 0..1, or -1 when the tool cannot undo the joint. */\n disassemble?(jointId: string, tool: ToolKind, dt: number): number\n extinguish?(partId?: string): void\n /** Optional: an animation moved a part; `position` / `rotation` (Euler XYZ, radians) are object-local. Keep raycast and hit shapes in sync. */\n setPartPose?(partId: string, position: Vec3, rotation?: Vec3): void\n /** Plain JSON of the impl's own state, stored in `DestructionSnapshot.impls`. */\n serialize?(): unknown\n load?(data: unknown): void\n}\n\n/** The fields a weapon or hazard must put in a `Hit`, per damage type. THE impact contract. */\nexport interface ImpactContract {\n required: string[]\n optional: string[]\n note: string\n}\n\nexport const IMPACT_CONTRACT: Record<DamageType, ImpactContract> = {\n ballistic: { required: ['type', 'point', 'direction', 'energy', 'caliber'], optional: ['space', 'source'], note: 'bullets and pellets: joules and diameter in millimetres' },\n blunt: { required: ['type', 'point', 'energy'], optional: ['direction', 'radius', 'space', 'source'], note: 'contact radius in metres (default 3 cm)' },\n slash: { required: ['type', 'point', 'energy'], optional: ['direction', 'radius', 'space', 'source'], note: 'axes, knives, machetes' },\n explosive: { required: ['type', 'point', 'energy', 'radius'], optional: ['lethalRadius', 'space', 'source'], note: 'point is the centre of the blast, radius the range in metres' },\n fire: { required: ['type', 'point', 'temperature', 'radius'], optional: ['duration', 'space', 'source'], note: 'flame temperature in °C; duration in seconds (call every frame with `dt`)' },\n heat: { required: ['type', 'point', 'temperature', 'radius'], optional: ['duration', 'space', 'source'], note: 'heat without flame (cutting torch, hot plate)' },\n}\n\n/** Problems with a hit according to the impact contract (empty when it is valid). */\nexport const checkHit = (hit: Hit): string[] => {\n const c = IMPACT_CONTRACT[hit.type]\n if (!c) return [`unknown damage type \"${String(hit.type)}\"`]\n const out: string[] = []\n for (const f of c.required) {\n const v = (hit as unknown as Record<string, unknown>)[f]\n if (v === undefined || (Array.isArray(v) ? v.some((n) => !Number.isFinite(n)) : typeof v === 'number' && !Number.isFinite(v))) out.push(`${hit.type} hit needs \"${f}\"`)\n }\n return out\n}\n\nexport interface CheckOptions {\n /**\n * Ids of every material the impl may use (the contracts package does not know the materials of your world: pass the ids of\n * `world.materials`, or the built-in plus your own). When omitted, the material check is skipped.\n */\n materials?: Iterable<string>\n /** Opt-in cost measurement (D8): `true` for the defaults, or the limits to use. */\n cost?: boolean | CostOptions\n}\n\nconst finiteJson = (v: unknown, path: string, out: string[]) => {\n if (typeof v === 'number') {\n if (!Number.isFinite(v)) out.push(`${path} is not a finite number`)\n } else if (Array.isArray(v)) v.forEach((x, i) => finiteJson(x, `${path}[${i}]`, out))\n else if (v && typeof v === 'object') for (const [k, x] of Object.entries(v)) finiteJson(x, `${path}.${k}`, out)\n else if (typeof v === 'function' || typeof v === 'symbol' || typeof v === 'bigint') out.push(`${path} is not JSON`)\n}\n\n/**\n * Contract checker for the test room (it needs no world): `describe()` is valid, a 500 J ballistic hit at a part centre returns well-formed events of this impl, `state()`\n * matches `describe()`, hit points never go negative, `update(0.016)` returns an array and every event is JSON-serializable. It hits the impl\n * (and calls `reset()` afterwards when there is one). With `options.cost` it also times `state()` and `describe()` (the cost contract of D8).\n */\nexport const checkDestructible = (impl: DestructibleImpl, options: CheckOptions = {}): { ok: boolean; problems: string[] } => {\n const problems: string[] = []\n const known = options.materials ? new Set(options.materials) : null\n let spec: DestructibleSpec | undefined\n try {\n spec = impl.describe()\n } catch (e) {\n return { ok: false, problems: [`describe() threw: ${String(e)}`] }\n }\n if (!spec || !Array.isArray(spec.parts) || spec.parts.length === 0) return { ok: false, problems: ['describe() must return at least one part'] }\n const ids = new Set<string>()\n for (const p of spec.parts) {\n if (ids.has(p.id)) problems.push(`duplicate part id \"${p.id}\"`)\n ids.add(p.id)\n if (known && !known.has(p.material)) problems.push(`part \"${p.id}\" has unknown material \"${p.material}\"`)\n if (!p.shape || !['box', 'cylinder', 'sphere'].includes(p.shape.kind)) problems.push(`part \"${p.id}\" has no valid shape`)\n if (!Array.isArray(p.position) || p.position.length !== 3) problems.push(`part \"${p.id}\" has no position`)\n }\n const jointIds = new Set<string>()\n for (const j of (spec.joints ?? []) as JointSpec[]) {\n if (!ids.has(j.a) || !ids.has(j.b)) problems.push(`joint \"${j.id ?? `${j.a}~${j.b}`}\" references an unknown part`)\n const jid = j.id ?? `${j.a}~${j.b}`\n if (jointIds.has(jid)) problems.push(`duplicate joint id \"${jid}\"`)\n jointIds.add(jid)\n }\n const checkState = (label: string) => {\n let st: ObjectState\n try {\n st = impl.state()\n } catch (e) {\n problems.push(`state() threw ${label}: ${String(e)}`)\n return\n }\n const sids = st.parts.map((p) => p.id).sort().join(',')\n if (sids !== [...ids].sort().join(',')) problems.push(`state() part ids do not match describe() ${label}`)\n for (const p of st.parts) if (!(p.hp >= 0)) problems.push(`part \"${p.id}\" has negative or invalid hp ${label}`)\n }\n const checkEvents = (events: unknown, label: string) => {\n if (!Array.isArray(events)) {\n problems.push(`${label} must return an array`)\n return\n }\n const evs = events as DestructionEvent[]\n evs.forEach((e, i) => {\n if (e.object !== impl.id) problems.push(`${label} event ${i} (${e.type}) has object \"${String(e.object)}\", expected \"${impl.id}\"`)\n const part = (e as { part?: string }).part\n if (part !== undefined && !ids.has(part)) problems.push(`${label} event ${i} (${e.type}) names unknown part \"${part}\"`)\n })\n const bad: string[] = []\n finiteJson(evs, 'events', bad)\n problems.push(...bad.map((b) => `${label}: ${b}`))\n try {\n const s = JSON.stringify(evs)\n if (JSON.stringify(JSON.parse(s)) !== s) problems.push(`${label} events do not survive a JSON round trip`)\n } catch (e) {\n problems.push(`${label} events are not JSON-serializable: ${String(e)}`)\n }\n }\n checkState('before the hit')\n const target = spec.parts[0]\n try {\n const hit: Hit = { type: 'ballistic', point: [target.position[0], target.position[1], target.position[2]], direction: [0, 0, -1], energy: 500, caliber: 9 }\n checkEvents(impl.hit(hit), 'hit()')\n } catch (e) {\n problems.push(`hit() threw: ${String(e)}`)\n }\n checkState('after the hit')\n if (impl.update) {\n try {\n checkEvents(impl.update(0.016), 'update()')\n } catch (e) {\n problems.push(`update() threw: ${String(e)}`)\n }\n checkState('after update')\n }\n try {\n impl.reset?.()\n } catch (e) {\n problems.push(`reset() threw: ${String(e)}`)\n }\n if (options.cost) {\n const cost = options.cost === true ? {} : options.cost\n try {\n checkReadCost({ name: 'state', read: () => impl.state(), options: cost, problems })\n checkReadCost({ name: 'describe', read: () => impl.describe(), options: cost, problems })\n } catch (e) {\n problems.push(`cost measurement threw: ${String(e)}`)\n }\n }\n return { ok: problems.length === 0, problems }\n}\n","/** The slots of a body an item can cover (the item slot vocabulary: game-items imports it from here). */\nexport type BodySlot = 'head' | 'eyes' | 'torso' | 'arms' | 'hands' | 'legs' | 'feet' | 'over'\n\n/** The 11 segments of the detailed body model (the Arsenal ids). */\nexport type SegmentKind = 'head' | 'jaw' | 'neck' | 'torso' | 'pelvis' | 'upperArm' | 'forearm' | 'hand' | 'thigh' | 'shin' | 'foot'\n\n/** The 6 regions of the crowd model (the game regions 0..5). */\nexport type BodyRegion = 'head' | 'torso' | 'armL' | 'armR' | 'legL' | 'legR'\n\n/** Bits of the `missing` mask of a body. The instanced body shader reads them, so the values are part of the contract. */\nexport const MISSING_BITS = {\n head: 1,\n armL: 2,\n armR: 4,\n legL: 8,\n legR: 16,\n armLBroken: 32,\n armRBroken: 64,\n legLBroken: 128,\n legRBroken: 256,\n jaw: 512,\n} as const\n","import type { DestructibleSpec, PartSpec } from './destruction'\n\nexport interface CheckSpecOptions {\n /** Known material ids. When given, every part's material must be one of them. */\n materials?: Iterable<string>\n}\n\nexport interface SpecReport {\n /** False when there is at least one problem (warnings do not count). */\n ok: boolean\n problems: string[]\n /** Things that are legal but probably wrong, e.g. structural parts that cannot reach an anchored part. */\n warnings: string[]\n}\n\nconst STRUCTURE_ROLES = ['foundation', 'column', 'beam', 'slab', 'wall', 'partition', 'roof', 'stair', 'none']\nconst BEARS = [true, false, 'a_on_b', 'b_on_a']\n\nconst finite = (n: unknown): n is number => typeof n === 'number' && Number.isFinite(n)\nconst positive = (n: unknown): boolean => finite(n) && n > 0\nconst vec3 = (v: unknown): boolean => Array.isArray(v) && v.length === 3 && v.every(finite)\nconst nonNegative = (n: unknown): boolean => n === undefined || (finite(n) && n >= 0)\n\nconst FACES = ['both', '+', '-']\nconst BONDS = ['running', 'stack']\n\n/** Layers, reinforcement, units and breach: known materials, finite positive sizes. */\nconst checkStagedFields = (p: PartSpec | undefined, label: string, materials: Set<string> | null, problems: string[]): void => {\n const known = (m: unknown, what: string): void => {\n if (materials && !materials.has(m as string)) problems.push(`${label} ${what} has unknown material \"${String(m)}\"`)\n }\n ;(p?.layers ?? []).forEach((l, i) => {\n known(l?.material, `layer ${i}`)\n if (!positive(l?.thickness)) problems.push(`${label} layer ${i} thickness must be finite and positive`)\n if (!FACES.includes(l?.faces)) problems.push(`${label} layer ${i} has an invalid faces \"${String(l?.faces)}\"`)\n })\n const r = p?.reinforcement\n if (r) {\n known(r.material, 'reinforcement')\n if (!positive(r.spacing) || !positive(r.diameter)) problems.push(`${label} reinforcement spacing and diameter must be finite and positive`)\n if (r.residualCapacity !== undefined && !(finite(r.residualCapacity) && r.residualCapacity >= 0 && r.residualCapacity <= 1)) problems.push(`${label} reinforcement residualCapacity must be between 0 and 1`)\n }\n const u = p?.units\n if (u) {\n known(u.mortar, 'units mortar')\n if (!vec3(u.size) || !u.size.every(positive)) problems.push(`${label} units size must be three finite positive numbers`)\n if (!BONDS.includes(u.bond)) problems.push(`${label} units has an invalid bond \"${String(u.bond)}\"`)\n }\n if (p?.breach && p.breach.area !== undefined && !positive(p.breach.area)) problems.push(`${label} breach area must be finite and positive`)\n}\n\n/**\n * Static checks on a `DestructibleSpec` (no world needed), for items that give a `spec` instead of an `impl`: unique part ids, known materials\n * (when `options.materials` is given), joints that reference existing, different parts, finite positive sizes, non-negative mass / hp / capacity,\n * valid structure roles and `bears` directions. A structural part with no path of joints to an anchored part is a warning, not a problem: it\n * is allowed, it just falls.\n */\nexport const checkSpec = (spec: DestructibleSpec, options: CheckSpecOptions = {}): SpecReport => {\n const problems: string[] = []\n const warnings: string[] = []\n const materials = options.materials ? new Set(options.materials) : null\n const parts = Array.isArray(spec?.parts) ? spec.parts : []\n if (!Array.isArray(spec?.parts) || parts.length === 0) problems.push('the spec needs at least one part')\n const ids = new Set<string>()\n for (const p of parts) {\n const id = String(p?.id ?? '')\n const label = `part \"${id}\"`\n if (id === '') problems.push('a part has no id')\n else if (ids.has(id)) problems.push(`duplicate part id \"${id}\"`)\n ids.add(id)\n if (materials && !materials.has(p?.material)) problems.push(`${label} has unknown material \"${String(p?.material)}\"`)\n else if (typeof p?.material !== 'string' || p.material === '') problems.push(`${label} needs a material`)\n const s = p?.shape\n if (s?.kind === 'box') {\n if (!Array.isArray(s.size) || s.size.length !== 3 || !s.size.every(positive)) problems.push(`${label} box size must be three finite positive numbers`)\n } else if (s?.kind === 'cylinder') {\n if (!positive(s.radius) || !positive(s.height)) problems.push(`${label} cylinder radius and height must be finite and positive`)\n } else if (s?.kind === 'sphere') {\n if (!positive(s.radius)) problems.push(`${label} sphere radius must be finite and positive`)\n } else problems.push(`${label} has an unknown shape`)\n if (!vec3(p?.position)) problems.push(`${label} needs a finite position [x, y, z]`)\n if (p?.rotation !== undefined && !vec3(p.rotation)) problems.push(`${label} has an invalid rotation`)\n for (const f of ['mass', 'hp', 'thickness'] as const) if (!nonNegative(p?.[f])) problems.push(`${label} ${f} must be a finite number >= 0`)\n if (p?.fill !== undefined && !(finite(p.fill) && p.fill >= 0 && p.fill <= 1)) problems.push(`${label} fill must be between 0 and 1`)\n if (p?.structure) {\n if (!STRUCTURE_ROLES.includes(p.structure.role)) problems.push(`${label} has an invalid structure role \"${String(p.structure.role)}\"`)\n if (!nonNegative(p.structure.capacity)) problems.push(`${label} structure capacity must be a finite number >= 0`)\n }\n if (p?.contains && !nonNegative(p.contains.liters)) problems.push(`${label} contains.liters must be a finite number >= 0`)\n checkStagedFields(p, label, materials, problems)\n }\n\n const jointIds = new Set<string>()\n const edges: Array<[string, string]> = []\n for (const j of spec?.joints ?? []) {\n const id = j.id ?? `${j.a}~${j.b}`\n const label = `joint \"${id}\"`\n if (jointIds.has(id)) problems.push(`duplicate joint id \"${id}\"`)\n jointIds.add(id)\n if (!ids.has(j.a)) problems.push(`${label} references unknown part \"${String(j.a)}\"`)\n if (!ids.has(j.b)) problems.push(`${label} references unknown part \"${String(j.b)}\"`)\n if (j.a === j.b) problems.push(`${label} joins part \"${String(j.a)}\" to itself`)\n if (j.bears !== undefined && !BEARS.includes(j.bears)) problems.push(`${label} has an invalid bears \"${String(j.bears)}\"`)\n if (!nonNegative(j.strength)) problems.push(`${label} strength must be a finite number >= 0`)\n if (!nonNegative(j.seconds)) problems.push(`${label} seconds must be a finite number >= 0`)\n if (j.bears !== false && ids.has(j.a) && ids.has(j.b) && j.a !== j.b) edges.push([j.a, j.b])\n }\n\n // structural parts must reach an anchored part over the joints (only when the spec lists its joints: otherwise they are inferred later)\n const structural = parts.filter((p) => p?.structure && p.structure.role !== 'none')\n if (structural.length && spec.joints) {\n const anchored = parts.filter((p) => p.anchored || p.structure?.role === 'foundation').map((p) => p.id)\n const adj = new Map<string, string[]>()\n for (const [a, b] of edges) {\n adj.set(a, [...(adj.get(a) ?? []), b])\n adj.set(b, [...(adj.get(b) ?? []), a])\n }\n const seen = new Set(anchored)\n const queue = [...anchored]\n while (queue.length) {\n for (const n of adj.get(queue.pop()!) ?? []) {\n if (seen.has(n)) continue\n seen.add(n)\n queue.push(n)\n }\n }\n const lost = structural.filter((p) => !seen.has(p.id)).map((p) => p.id)\n if (lost.length) warnings.push(`structural part(s) ${lost.map((i) => `\"${i}\"`).join(', ')} cannot reach an anchored part, so they will fall`)\n }\n return { ok: problems.length === 0, problems, warnings }\n}\n","import type { BallisticExtras, Hit, HitIgnition, Vec3 } from './destruction'\n\n/**\n * A ballistic shot (one per pellet) as a weapon module produces it. Plain data: any damage model can consume it (`shotToHit` makes the `Hit`).\n */\nexport interface Shot {\n origin: Vec3\n /** Unit vector. */\n direction: Vec3\n /** Muzzle energy in joules. */\n energy: number\n /** Bullet diameter in millimetres. */\n caliber: number\n /** snake_case calibre id, e.g. `9x19`. */\n caliberId: string\n /** Muzzle speed in m/s. */\n speed: number\n /** Projectile mass in grams (one pellet for a shotgun load). */\n mass?: number\n /** Energy at a distance in metres, with the calibre's drag. */\n energyAt(distance: number): number\n pellet: number\n /** snake_case weapon id. */\n weapon: string\n source?: string\n /** Kind of the round that was loaded (`fmj`, `hp`, `ap`, `buck`, `slug`, `incendiary`, `tracer`...). */\n ammo?: string\n /** Millimetres of steel, concrete, brick and wood the round goes through at the muzzle (the ammo table of the weapons module). `shotToHit` scales it by the energy left. */\n penetration?: Readonly<Record<string, number>>\n incendiary?: boolean\n tracer?: boolean\n /** Chances that the round lights flammable vapour or fuel. */\n ignition?: HitIgnition\n}\n\n/**\n * The fields of the round that a damage model takes besides the geometry: the penetration by material scaled by the energy that is left at `distance`\n * (linear in the energy: half the energy goes through half as much), the incendiary and tracer flags and the ignition chances. Pass it as the sixth\n * argument of `DestructionWorld.shoot` or spread it in a `Hit`.\n */\nexport const shotExtras = (shot: Shot, distance = 0): BallisticExtras => {\n const out: { -readonly [K in keyof BallisticExtras]: BallisticExtras[K] } = {}\n if (shot.penetration) {\n const k = shot.energy > 0 ? Math.min(1, Math.max(0, shot.energyAt(distance) / shot.energy)) : 1\n const scaled: Record<string, number> = {}\n for (const key of Object.keys(shot.penetration)) scaled[key] = shot.penetration[key]! * k\n out.penetration = scaled\n }\n if (shot.incendiary) out.incendiary = true\n if (shot.tracer) out.tracer = true\n if (shot.ignition) out.ignition = { spark: shot.ignition.spark, flame: shot.ignition.flame }\n return out\n}\n\n/** One use of a non-firearm (melee swing, flame tick, heat tick, throw, tool tick, extinguisher tick). */\nexport type Use =\n | { kind: 'melee'; damage: 'blunt' | 'slash'; energy: number; radius: number; reach: number; origin: Vec3; direction: Vec3 }\n | { kind: 'flame'; temperature: number; radius: number; range: number; cone: boolean; duration: number; origin: Vec3; direction: Vec3 }\n | { kind: 'heat'; temperature: number; radius: number; range: number; duration: number; origin: Vec3; direction: Vec3 }\n | {\n kind: 'throw'\n energy: number\n radius: number\n fuse: number\n velocity: Vec3\n origin: Vec3\n fire?: { temperature: number; radius: number; seconds: number }\n /** Explosive id (`m67`, `molotov`, `pg7v`...): the host looks the numbers up in the arsenal. Absent on a plain thrown object. */\n explosive?: string\n /** What sets it off: `timer` after `fuse` seconds, `impact` on the first hit once armed. */\n trigger?: 'timer' | 'impact'\n /** Metres the projectile must fly before an impact sets it off; closer, it hits without exploding (rocket launchers). */\n armDistance?: number\n /** Radius in metres of the wounding area (`radius` is the lethal one). */\n injuryRadius?: number\n /** Seconds the blast stuns whoever is inside the injury radius (flashbang). */\n stunSeconds?: number\n /** Seconds the thrower held it after pulling the pin: `fuse` is what was left of the full fuse when it left the hand. */\n cooked?: number\n /** Went off in the thrower's hand (held past the fuse): no velocity, `fuse` is 0 and the blast is at `origin`. */\n inHand?: boolean\n }\n /** An explosive set down where the trigger is pulled (mine, C4, charge): it waits for its trigger instead of flying. */\n | {\n kind: 'place'\n explosive: string\n /** `wire`: something trips it; `remote`: the player fires it; `timer`: after `fuse` seconds. */\n triggers: readonly ('timer' | 'wire' | 'remote')[]\n energy: number\n /** Lethal radius in metres. */\n radius: number\n injuryRadius: number\n /** Cone the blast goes through, in front of `direction` (mine); absent for a blast in every direction. */\n cone?: { halfAngleDeg: number; length: number }\n /** The wire a `wire` charge stretches from where it is set down: metres out, degrees from its facing (counter-clockwise from above) and metres above it. */\n tripwire?: { length: number; angleDeg: number; height: number }\n fuse?: number\n origin: Vec3\n direction: Vec3\n }\n /** The blast behind a rocket launcher: dangerous inside `radius` metres, in the cone around `direction` (pointing away from the target). */\n | { kind: 'backblast'; radius: number; halfAngleDeg: number; origin: Vec3; direction: Vec3 }\n | { kind: 'tool'; tool: string; reach: number; duration: number; origin: Vec3; direction: Vec3 }\n | { kind: 'extinguish'; range: number; coolC: number; duration: number; origin: Vec3; direction: Vec3 }\n | { kind: 'hand'; reach: number; origin: Vec3; direction: Vec3 }\n\n/**\n * The `Hit` a ballistic shot makes at `point` (world space): the energy is what is left of the shot at that distance from its origin\n * (`shot.energyAt`), the direction and calibre come from the shot. `normal` (the surface normal at the point, when the caller knows it) does not\n * change the hit; it is accepted so that callers can pass what their raycast returned and so that a stricter implementation could use it.\n */\nexport const shotToHit = (shot: Shot, point: Vec3, normal?: Vec3): Hit => {\n void normal\n const dx = point[0] - shot.origin[0]\n const dy = point[1] - shot.origin[1]\n const dz = point[2] - shot.origin[2]\n const distance = Math.hypot(dx, dy, dz)\n return {\n type: 'ballistic',\n point: [point[0], point[1], point[2]],\n direction: [shot.direction[0], shot.direction[1], shot.direction[2]],\n energy: shot.energyAt(distance),\n caliber: shot.caliber,\n ...(shot.mass === undefined ? {} : { mass: shot.mass }),\n ...shotExtras(shot, distance),\n source: shot.source ?? shot.weapon,\n }\n}\n\n/**\n * The `Hit` a non-firearm `Use` makes at `point` (world space), or `null` for uses that do not damage by themselves.\n *\n * - `melee` -> `blunt` / `slash` with the swing's `energy`, contact `radius` and `direction`;\n * - `flame` -> `fire` and `heat` -> `heat`, with `temperature`, `duration` and a contact radius of at most 0.3 m (one ray of the cone);\n * - `throw` -> the blast (`explosive`, `energy`, `radius`, centred on `point`, the place it detonates). A thrown item with no blast energy but\n * a `fire` patch (a molotov) gives that patch as a `fire` hit (`temperature`, `radius`, `seconds` as `duration`). No energy and no fire -> `null`;\n * - `tool`, `extinguish` and `hand` -> `null` (tools work on joints, the extinguisher cools, the hand only grabs).\n *\n * `normal` does not change the hit (same as `shotToHit`).\n */\nexport const useToHit = (use: Use, point: Vec3, normal?: Vec3): Hit | null => {\n void normal\n const p: Vec3 = [point[0], point[1], point[2]]\n switch (use.kind) {\n case 'melee':\n return { type: use.damage, point: p, direction: [use.direction[0], use.direction[1], use.direction[2]], energy: use.energy, radius: use.radius }\n case 'flame':\n case 'heat':\n return {\n type: use.kind === 'flame' ? 'fire' : 'heat',\n point: p,\n direction: [use.direction[0], use.direction[1], use.direction[2]],\n temperature: use.temperature,\n radius: Math.min(use.radius, 0.3),\n duration: use.duration,\n }\n case 'throw':\n if (use.energy > 0) return { type: 'explosive', point: p, energy: use.energy, radius: use.radius }\n if (use.fire) return { type: 'fire', point: p, temperature: use.fire.temperature, radius: use.fire.radius, duration: use.fire.seconds }\n return null\n default:\n return null\n }\n}\n","import type { Hit } from './destruction'\n\n/**\n * How a container of flammable fluid (a fuel tank, a jerrycan, a gas bottle) is set alight by what hits it. A normal bullet that goes through only\n * makes a leak; the leak lights when something supplies a flame: a spark of a hard round on metal, an incendiary or tracer round, a fire nearby\n * or a blast. These are the numbers of the target side; the numbers of the round (core, jacket, incendiary, tracer) are in the weapons module\n * (`rules.ignition` of `@adatechnology/game-weapons`) and reach the target in `Hit.ignition`. Every number is a default to be changed per game.\n */\nexport interface IgnitionRules {\n /**\n * How much of the spark and of the flame of a round reaches the vapour, by how full the container is: points `[filled, factor]`, `filled` 0..1\n * (litres over capacity), `factor` 0..1, linear between points. A full container holds a mixture too rich to burn (the vapour has no air) and\n * mostly leaks; a nearly empty one holds the vapour/air mixture of a flammable range and lights the easiest; a dry one has little vapour left.\n * Default: 0.6 empty, 1 at 10 percent, 0.6 at 35, 0.3 at 65, 0.15 at 90 and 0.12 full.\n */\n fillCurve: ReadonlyArray<readonly [number, number]>\n /** 0..1: how much of the fill factor also weighs on the flame of an incendiary or tracer (1: as much as on a spark; 0: not at all). Default 0.5. */\n flameFillInfluence: number\n /** Chance of the flame of a round that is flagged `incendiary` or `tracer` but carries no `ignition` numbers (a host that passes only the flags). */\n flameDefaults: { incendiary: number; tracer: number }\n /**\n * What a spark needs to strike: a factor 0..1 by material id of the struck part. A material that is not listed but is metal takes\n * `sparkMetalDefault`; a part that is not metal never sparks. Default: steel and iron 1, aluminium 0.25.\n */\n sparkTarget: Readonly<Record<string, number>>\n sparkMetalDefault: number\n /**\n * Factor 0..1 on the spark by fluid (default 1): diesel has a flash point of 52 degrees C and more, so a spark that lights petrol vapour does\n * not light it (a flame does). Default: diesel 0.15.\n */\n sparkFluid: Readonly<Record<string, number>>\n /** A leaking container of flammable fluid within `radius` metres of a burning part or a burning fuel stain lights at `chancePerSecond`. */\n fireNear: { radius: number; chancePerSecond: number }\n}\n\n/** Defaults of `IgnitionRules`. */\nexport const DEFAULT_IGNITION_RULES: IgnitionRules = {\n fillCurve: [\n [0, 0.6],\n [0.1, 1],\n [0.35, 0.6],\n [0.65, 0.3],\n [0.9, 0.15],\n [1, 0.12],\n ],\n flameFillInfluence: 0.5,\n flameDefaults: { incendiary: 0.7, tracer: 0.2 },\n sparkTarget: { steel: 1, iron: 1, aluminium: 0.25 },\n sparkMetalDefault: 0.5,\n sparkFluid: { diesel: 0.15 },\n fireNear: { radius: 1.5, chancePerSecond: 0.5 },\n}\n\n/** Merges a partial `IgnitionRules` over the defaults (an object is merged one level deep). */\nexport const resolveIgnitionRules = (rules?: Partial<IgnitionRules>): IgnitionRules => ({\n ...DEFAULT_IGNITION_RULES,\n ...rules,\n flameDefaults: { ...DEFAULT_IGNITION_RULES.flameDefaults, ...rules?.flameDefaults },\n sparkTarget: { ...DEFAULT_IGNITION_RULES.sparkTarget, ...rules?.sparkTarget },\n sparkFluid: { ...DEFAULT_IGNITION_RULES.sparkFluid, ...rules?.sparkFluid },\n fireNear: { ...DEFAULT_IGNITION_RULES.fireNear, ...rules?.fireNear },\n})\n\n/** Linear interpolation of the fill curve at `fill` (0..1); outside the points it keeps the first or the last. */\nexport const fillFactor = (fill: number, curve: IgnitionRules['fillCurve'] = DEFAULT_IGNITION_RULES.fillCurve): number => {\n if (curve.length === 0) return 1\n const f = Math.min(1, Math.max(0, fill))\n if (f <= curve[0]![0]) return curve[0]![1]\n for (let i = 1; i < curve.length; i++) {\n const [x1, y1] = curve[i]!\n const [x0, y0] = curve[i - 1]!\n if (f <= x1) return x1 === x0 ? y1 : y0 + ((y1 - y0) * (f - x0)) / (x1 - x0)\n }\n return curve[curve.length - 1]![1]\n}\n\n/** The factor of what a spark strikes: 0 when the struck part is not metal. */\nexport const sparkTargetFactor = (materialId: string, metal: boolean, rules: IgnitionRules = DEFAULT_IGNITION_RULES): number =>\n !metal ? 0 : rules.sparkTarget[materialId] ?? rules.sparkMetalDefault\n\n/**\n * Chance that one round that went through the wall of a container lights the fluid that leaks: the spark (only on metal) and the flame (any\n * wall), each weighed by the fill of the container; the two are independent. 0 when the round carries nothing (`Hit.ignition` absent and not\n * flagged `incendiary` or `tracer`): a plain bullet on a plain wall only leaks.\n */\nexport const ignitionChance = (hit: Pick<Hit, 'incendiary' | 'tracer' | 'ignition'>, target: { sparkTarget: number; fill: number; fluid?: string }, rules: IgnitionRules = DEFAULT_IGNITION_RULES): number => {\n const k = fillFactor(target.fill, rules.fillCurve)\n const spark = (hit.ignition?.spark ?? 0) * target.sparkTarget * (target.fluid === undefined ? 1 : rules.sparkFluid[target.fluid] ?? 1) * k\n const flameBase = hit.ignition?.flame ?? Math.max(hit.incendiary ? rules.flameDefaults.incendiary : 0, hit.tracer ? rules.flameDefaults.tracer : 0)\n const flame = flameBase * (1 - rules.flameFillInfluence * (1 - k))\n return 1 - (1 - Math.min(1, Math.max(0, spark))) * (1 - Math.min(1, Math.max(0, flame)))\n}\n","/**\n * The seal of a closed container (a food tin, a drink can, a jar, a bottle with a cap): what opens it and whether a breach spoils what is inside.\n * Plain data and one pure check, shared by the item rules (`resolveUse` of game-items) and any host that lets the player open and eat (the test room).\n */\nexport interface SealSpec {\n /** Ids of the tools that open it (items or weapons: `can_opener`, `knife`); any one of them is enough. */\n readonly openWith?: readonly string[]\n /** It opens by hand (a pull tab, a ring pull, a screw cap): no tool needed. */\n readonly byHand?: boolean\n /** A hole through the container or a leak spoils what is inside: it can no longer be eaten or drunk. */\n readonly spoilsWhenBreached?: boolean\n}\n\n/** The state of one container: opened, holed through (a shot, a blade) or leaking. */\nexport interface SealState {\n readonly opened?: boolean\n readonly breached?: boolean\n readonly leaked?: boolean\n}\n\n/** Why a sealed container cannot be eaten or drunk now. */\nexport type SealBlock = 'sealed' | 'breached' | 'leaked'\n\n/** Whether it can be opened with the tools at hand, and with which one (undefined when it opens by hand). */\nexport const sealOpener = (seal: SealSpec, tools: Iterable<string>): { readonly ok: boolean; readonly tool?: string } => {\n if (seal.byHand || !seal.openWith || seal.openWith.length === 0) return { ok: true }\n const have = new Set(tools)\n const tool = seal.openWith.find((id) => have.has(id))\n return tool === undefined ? { ok: false } : { ok: true, tool }\n}\n\n/** What stops eating or drinking it now, or undefined when nothing does. A spoiled container (breached, leaked) is blocked even once open. */\nexport const sealBlock = (seal: SealSpec, state: SealState): SealBlock | undefined => {\n if (seal.spoilsWhenBreached && state.breached) return 'breached'\n if (seal.spoilsWhenBreached && state.leaked) return 'leaked'\n if (!state.opened) return 'sealed'\n return undefined\n}\n","/** How a hand turns something round in strokes (a screw cap, a tap handle, a knob): what `twistStroke` answers for one moment of the turning. */\nexport interface TwistStroke {\n /** Radians the wrist is turned from the middle of its stroke, positive the way the part turns. */\n readonly angle: number\n /** Radians the part has turned in all, from 0 to `strokes * reach`. */\n readonly turned: number\n /** How closed the fingers are, 0 open to 1 closed: closed on the part while it turns, open while the wrist turns back. */\n readonly grip: number\n /** 0..1, how far the hand rises off the part while the wrist turns back (1 is `TWIST_LIFT` metres). */\n readonly lift: number\n}\n\nexport interface TwistOptions {\n /** Strokes of the wrist. Default 3. */\n readonly strokes?: number\n /** Radians the part turns in one stroke (a wrist turns about a quarter round with its hold). Default 1.6. */\n readonly reach?: number\n}\n\n/** Metres a hand rises off the part between two strokes. */\nexport const TWIST_LIFT = 0.012\n/** Share of each stroke spent turning the part; the rest turns the wrist back open. */\nconst TURNING = 0.7\n\nconst smooth = (k: number): number => k * k * (3 - 2 * k)\n\n/**\n * The hand turning a part round at `share` (0..1) of the whole turning: in each stroke the wrist turns with the part, then lets go, rises a little and turns back.\n * Pure and the same for every host, so first and third person turn the same hand the same way.\n */\nexport const twistStroke = (share: number, options: TwistOptions = {}): TwistStroke => {\n const strokes = Math.max(1, Math.round(options.strokes ?? 3))\n const reach = options.reach ?? 1.6\n const along = Math.min(1, Math.max(0, share)) * strokes\n const index = Math.min(strokes - 1, Math.floor(along))\n const phase = along - index\n if (phase <= TURNING) {\n const k = smooth(phase / TURNING)\n return { angle: reach * (k - 0.5), turned: reach * (index + k), grip: 1, lift: 0 }\n }\n const k = (phase - TURNING) / (1 - TURNING)\n return { angle: reach * (0.5 - smooth(k)), turned: reach * (index + 1), grip: 0.35, lift: Math.sin(k * Math.PI) }\n}\n","import type { Vec3 } from './destruction'\n\n/** Pose of one part (or of the whole item) at a key: position offset in metres and Euler XYZ rotation in radians, both relative to the rest pose. */\nexport interface AnimationPose {\n position?: Vec3\n rotation?: Vec3\n}\n\nexport interface AnimationKey {\n /** Seconds from the start of the clip. */\n t: number\n /** Pose of the item's root. */\n position?: Vec3\n rotation?: Vec3\n /** Poses of named parts: the key is a destruction part id (a pistol `reload` moves `mag`; a car door `open` rotates `door_l`). */\n parts?: Record<string, AnimationPose>\n}\n\nexport interface AnimationEventSpec {\n /** Seconds from the start of the clip. */\n t: number\n /** snake_case type the host maps (`sound`, `eject_casing`, `door_latch`...). */\n type: string\n data?: Record<string, unknown>\n /**\n * Seconds of real time the event fires before `t`, not stretched with the clip: a recorded sound whose hit comes that long after its start\n * (the click of a magazine seating) starts early so the hit lands on `t`. The player passes the lead it could apply as `data.lead`.\n */\n lead?: number\n}\n\n/** A use animation a module brings with its item. Poses between keys are interpolated by the player (the test room does it linearly). */\nexport interface AnimationClipSpec {\n /** snake_case: `reload`, `open`, `drink`... Unique within the item. */\n id: string\n /** Seconds. */\n duration: number\n keys: AnimationKey[]\n events?: AnimationEventSpec[]\n}\n\n/** What an item exposes when it brings its own animations. */\nexport interface ItemAnimationContract {\n animations: AnimationClipSpec[]\n}\n\nconst finite3 = (v: unknown): boolean => Array.isArray(v) && v.length === 3 && v.every((n) => typeof n === 'number' && Number.isFinite(n))\n\n/**\n * Problems with a clip (empty when it is valid): a snake_case id, a positive finite duration, at least one key, key and event times inside\n * `[0, duration]` and not going backwards, finite vectors, every named part one of `partIds`, event types that are non-empty strings and\n * JSON-serializable event data.\n */\nexport const checkAnimation = (clip: AnimationClipSpec, partIds: Iterable<string>): { ok: boolean; problems: string[] } => {\n const problems: string[] = []\n const parts = new Set(partIds)\n const id = String(clip?.id ?? '')\n if (!/^[a-z][a-z0-9_]*$/.test(id)) problems.push(`clip id \"${id}\" must be snake_case`)\n const label = `clip \"${id}\"`\n if (!(typeof clip?.duration === 'number' && Number.isFinite(clip.duration) && clip.duration > 0)) problems.push(`${label} needs a positive finite duration`)\n const dur = typeof clip?.duration === 'number' && clip.duration > 0 ? clip.duration : Infinity\n if (!Array.isArray(clip?.keys) || clip.keys.length === 0) {\n problems.push(`${label} needs at least one key`)\n return { ok: false, problems }\n }\n let prev = -Infinity\n clip.keys.forEach((k, i) => {\n if (!(typeof k.t === 'number' && Number.isFinite(k.t)) || k.t < 0 || k.t > dur + 1e-9) problems.push(`${label} key ${i} has t=${String(k.t)} outside 0..${dur}`)\n else if (k.t < prev) problems.push(`${label} key ${i} goes back in time (${k.t} < ${prev})`)\n else prev = k.t\n for (const f of ['position', 'rotation'] as const) if (k[f] !== undefined && !finite3(k[f])) problems.push(`${label} key ${i} has an invalid ${f}`)\n for (const [pid, pose] of Object.entries(k.parts ?? {})) {\n if (!parts.has(pid)) problems.push(`${label} key ${i} moves unknown part \"${pid}\"`)\n for (const f of ['position', 'rotation'] as const) if (pose?.[f] !== undefined && !finite3(pose[f])) problems.push(`${label} key ${i} part \"${pid}\" has an invalid ${f}`)\n }\n })\n let prevEv = -Infinity\n ;(clip.events ?? []).forEach((e, i) => {\n if (!(typeof e.t === 'number' && Number.isFinite(e.t)) || e.t < 0 || e.t > dur + 1e-9) problems.push(`${label} event ${i} has t=${String(e.t)} outside 0..${dur}`)\n else if (e.t < prevEv) problems.push(`${label} event ${i} goes back in time`)\n else prevEv = e.t\n if (typeof e.type !== 'string' || e.type === '') problems.push(`${label} event ${i} needs a type`)\n try {\n JSON.stringify(e.data ?? {})\n } catch {\n problems.push(`${label} event ${i} data is not JSON`)\n }\n })\n return { ok: problems.length === 0, problems }\n}\n","import type { AnimationClipSpec, AnimationEventSpec, AnimationPose } from './animation'\nimport { checkAnimation } from './animation'\nimport type { HostEvent } from './module'\n\n/** Clips a tool can bring, one per move of its cycle. A tool brings the ones it has; a missing clip is simply not played. */\nexport const TOOL_CLIP = {\n DRAW: 'draw',\n SHOT: 'shot',\n MISFIRE: 'misfire',\n EMPTY: 'empty',\n CYCLE: 'cycle',\n RELOAD: 'reload',\n FEED: 'feed',\n FAULT: 'fault',\n CLEAR: 'clear',\n SAFETY_ON: 'safety_on',\n SAFETY_OFF: 'safety_off',\n MODE: 'mode',\n /** A throwable with the pin out, held until it is thrown. */\n COOK: 'cook',\n /** The stock folds, unfolds, slides in or out (variants `fold`, `unfold`, `collapse`, `extend`). */\n STOCK: 'stock',\n /** A light or a laser is switched (variants `on`, `off`). */\n TOGGLE: 'toggle',\n} as const\nexport type ToolClipId = (typeof TOOL_CLIP)[keyof typeof TOOL_CLIP]\n\n/** What a renderer does when a rule event arrives. `variant` picks `<clip>_<variant>` when the tool has it, else `<clip>`. */\nexport type ToolAnimationStep =\n | { readonly type: 'play'; readonly clip: ToolClipId; readonly variant?: string; readonly duration?: number; readonly repeat?: number }\n /** Move the clip that is playing to the marker (a clip event `stage` with `data.stage`) the rule just reached. */\n | { readonly type: 'sync'; readonly stage: string }\n /** The rule says the phase is over: the clip jumps to its end if it is still running. */\n | { readonly type: 'finish'; readonly clip: ToolClipId }\n\nconst stockVariant = (event: Extract<HostEvent, { type: 'stock' }>): string => {\n const isFolding = event.kind === undefined ? false : event.kind.includes('fold')\n if (event.state === 'collapsed') return isFolding ? 'fold' : 'collapse'\n return isFolding ? 'unfold' : 'extend'\n}\n\n/** The move a host event asks of the tool in hand, or null when it has no motion. */\nexport const toolAnimationStep = (event: HostEvent): ToolAnimationStep | null => {\n switch (event.type) {\n case 'tool':\n return { type: 'play', clip: TOOL_CLIP.DRAW, ...(event.duration === undefined ? {} : { duration: event.duration }) }\n case 'shot':\n return { type: 'play', clip: TOOL_CLIP.SHOT, repeat: Math.max(1, event.rounds ?? 1) }\n case 'misfire':\n return { type: 'play', clip: TOOL_CLIP.MISFIRE }\n case 'empty':\n return { type: 'play', clip: TOOL_CLIP.EMPTY }\n case 'mode':\n return { type: 'play', clip: TOOL_CLIP.MODE, variant: event.mode }\n case 'fault':\n return { type: 'play', clip: TOOL_CLIP.FAULT, variant: event.fault }\n case 'clear':\n if (event.phase === 'end') return { type: 'finish', clip: TOOL_CLIP.CLEAR }\n return { type: 'play', clip: TOOL_CLIP.CLEAR, variant: event.fault, ...(event.duration === undefined ? {} : { duration: event.duration }) }\n case 'safety':\n return { type: 'play', clip: event.on ? TOOL_CLIP.SAFETY_ON : TOOL_CLIP.SAFETY_OFF }\n case 'cycle':\n if (event.phase === 'end') return { type: 'finish', clip: TOOL_CLIP.CYCLE }\n return { type: 'play', clip: TOOL_CLIP.CYCLE, ...(event.duration === undefined ? {} : { duration: event.duration }) }\n case 'reload':\n if (event.phase === 'end') return { type: 'finish', clip: TOOL_CLIP.RELOAD }\n return { type: 'play', clip: TOOL_CLIP.RELOAD, ...(event.kind === undefined ? {} : { variant: event.kind }), ...(event.duration === undefined ? {} : { duration: event.duration }) }\n case 'stage':\n return { type: 'sync', stage: event.stage }\n case 'feed':\n return { type: 'play', clip: TOOL_CLIP.FEED }\n case 'cook':\n if (event.phase === 'start') return { type: 'play', clip: TOOL_CLIP.COOK, duration: event.fuse }\n return { type: 'finish', clip: TOOL_CLIP.COOK }\n case 'stock':\n return { type: 'play', clip: TOOL_CLIP.STOCK, variant: stockVariant(event), ...(event.duration === undefined ? {} : { duration: event.duration }) }\n case 'toggle':\n return { type: 'play', clip: TOOL_CLIP.TOGGLE, variant: event.on ? 'on' : 'off' }\n default:\n return null\n }\n}\n\n/** Where a renderer puts the poses: every part of the tool by id (the ids the clips move), and the whole tool. Poses are offsets from rest. */\nexport interface ToolRig {\n setPartPose(partId: string, pose: AnimationPose): void\n setRootPose?(pose: AnimationPose): void\n}\n\n/** Clips by id, with the variants as `<clip>_<variant>`. */\nexport type ToolClipSet = Readonly<Record<string, AnimationClipSpec>>\n\n/** A renderer's tool animator: feed it the host events and the frame time. */\nexport interface ToolAnimator {\n handle(event: HostEvent): void\n update(dt: number): void\n /** Ids of the clips playing now. */\n readonly playing: readonly string[]\n dispose(): void\n}\n\nexport const STAGE_EVENT = 'stage'\n\n/** The clip with its times (keys and events) scaled so that it lasts `duration` seconds. */\nexport const scaleClip = (clip: AnimationClipSpec, duration: number): AnimationClipSpec => {\n const factor = clip.duration > 0 ? duration / clip.duration : 1\n return {\n ...clip,\n duration,\n keys: clip.keys.map((key) => ({ ...key, t: key.t * factor })),\n ...(clip.events ? { events: clip.events.map((event) => ({ ...event, t: event.t * factor })) } : {}),\n }\n}\n\nconst ZERO: [number, number, number] = [0, 0, 0]\nconst mix = (from: readonly number[], to: readonly number[], fraction: number): [number, number, number] => [\n (from[0] ?? 0) + ((to[0] ?? 0) - (from[0] ?? 0)) * fraction,\n (from[1] ?? 0) + ((to[1] ?? 0) - (from[1] ?? 0)) * fraction,\n (from[2] ?? 0) + ((to[2] ?? 0) - (from[2] ?? 0)) * fraction,\n]\n\n/** Pose of the whole tool (`partId` undefined) or of one part at `time`, linear between keys; a key that does not name it means rest. */\nexport const sampleClip = (clip: AnimationClipSpec, partId: string | undefined, time: number): { position: [number, number, number]; rotation: [number, number, number] } => {\n const points = clip.keys.map((key) => {\n const pose = partId === undefined ? key : key.parts?.[partId]\n return { t: key.t, position: pose?.position ?? ZERO, rotation: pose?.rotation ?? ZERO }\n })\n const first = points[0]\n if (!first || first.t > 0) points.unshift({ t: 0, position: ZERO, rotation: ZERO })\n const last = points[points.length - 1]\n if (!last) return { position: ZERO, rotation: ZERO }\n if (time >= last.t) return { position: mix(last.position, last.position, 0), rotation: mix(last.rotation, last.rotation, 0) }\n const index = Math.max(0, points.findIndex((point, i) => time >= point.t && time < (points[i + 1]?.t ?? Infinity)))\n const from = points[index]\n const to = points[index + 1]\n if (!from || !to) return { position: ZERO, rotation: ZERO }\n const fraction = to.t > from.t ? (time - from.t) / (to.t - from.t) : 0\n return { position: mix(from.position, to.position, fraction), rotation: mix(from.rotation, to.rotation, fraction) }\n}\n\n/** Problems with a clip set (empty when valid): each key is the clip id (or `<clip>_<variant>`), every clip passes `checkAnimation`, and a `stage` event names its stage. */\nexport const checkToolClips = (clips: ToolClipSet, partIds: Iterable<string>): { ok: boolean; problems: string[] } => {\n const parts = [...partIds]\n const problems: string[] = []\n for (const [key, clip] of Object.entries(clips)) {\n if (clip.id !== key) problems.push(`clip \"${key}\" has the id \"${clip.id}\"`)\n if (!(clip.duration > 0)) problems.push(`clip \"${key}\" has no duration`)\n problems.push(...checkAnimation(clip, parts).problems)\n for (const event of clip.events ?? []) if (event.type === STAGE_EVENT && typeof event.data?.stage !== 'string') problems.push(`clip \"${key}\" has a stage event without data.stage`)\n }\n return { ok: problems.length === 0, problems }\n}\n\ninterface Instance {\n readonly name: string\n readonly clip: AnimationClipSpec\n time: number\n delay: number\n fired: number\n}\n\nexport interface ToolClipPlayerOptions {\n clips: ToolClipSet\n rig: ToolRig\n /** Called for each clip event as its time passes (`eject_casing`, `drop_magazine`, `stage`...). */\n onEvent?(event: AnimationEventSpec, clip: string): void\n /** Seconds between the rounds of a `repeat` (a burst): default 0.1. */\n repeatInterval?(): number\n}\n\n/** The default player of a tool's clips: runs the steps of `toolAnimationStep` against a rig, scaled to the duration the rule gives. */\nexport interface ToolClipPlayer {\n apply(step: ToolAnimationStep): void\n update(dt: number): void\n readonly playing: readonly string[]\n /** The clips being played with the time each has reached and the clip itself (scaled to the duration the rule gave), for a renderer that has to follow what the clip does now (the hands working a part). */\n readonly running: ReadonlyArray<{ readonly name: string; readonly time: number; readonly clip: AnimationClipSpec }>\n}\n\n/**\n * The clip with every event that has a `lead` moved that many seconds earlier, the lead it got in `data.lead`. A led event never goes before 0\n * nor before the event written ahead of it (a fast clip keeps its order: the lead shrinks). Run after `scaleClip`: the lead is real time, the\n * clip's stretch does not touch it.\n */\nexport const leadClipEvents = (clip: AnimationClipSpec): AnimationClipSpec => {\n const events = clip.events ?? []\n if (!events.some((event) => (event.lead ?? 0) > 0)) return clip\n let floor = 0\n const led = events.map((event) => {\n const lead = Math.max(0, Math.min(event.t - floor, event.lead ?? 0))\n const t = event.t - lead\n floor = Math.max(floor, t)\n if (event.lead === undefined) return event\n const moved: AnimationEventSpec = { ...event, t, data: lead > 0 ? { ...event.data, lead } : { ...event.data } }\n delete moved.lead\n return moved\n })\n return { ...clip, events: led }\n}\n\nexport const createToolClipPlayer = (options: ToolClipPlayerOptions): ToolClipPlayer => {\n const { clips, rig, onEvent } = options\n let instances: Instance[] = []\n\n const find = (clip: string, variant?: string): { name: string; clip: AnimationClipSpec } | undefined => {\n const name = variant !== undefined && clips[`${clip}_${variant}`] ? `${clip}_${variant}` : clip\n const found = clips[name]\n return found ? { name, clip: found } : undefined\n }\n\n const render = (instance: Instance): void => {\n const time = Math.min(instance.time, instance.clip.duration)\n const root = sampleClip(instance.clip, undefined, time)\n if (instance.clip.keys.some((key) => key.position || key.rotation)) rig.setRootPose?.(root)\n const touched = new Set(instance.clip.keys.flatMap((key) => Object.keys(key.parts ?? {})))\n for (const id of touched) rig.setPartPose(id, sampleClip(instance.clip, id, time))\n }\n\n const fireEvents = (instance: Instance, upTo: number): void => {\n const events = instance.clip.events ?? []\n while (instance.fired < events.length && (events[instance.fired]?.t ?? Infinity) <= upTo + 1e-9) {\n const event = events[instance.fired]\n instance.fired += 1\n if (event) onEvent?.(event, instance.name)\n }\n }\n\n return {\n apply(step) {\n if (step.type === 'sync') {\n for (const instance of instances) {\n const marker = (instance.clip.events ?? []).find((event) => event.type === STAGE_EVENT && event.data?.stage === step.stage)\n if (marker && instance.time < marker.t) instance.time = marker.t\n }\n return\n }\n if (step.type === 'finish') {\n for (const instance of instances) {\n if (instance.name !== step.clip && !instance.name.startsWith(`${step.clip}_`)) continue\n fireEvents(instance, instance.clip.duration)\n instance.time = instance.clip.duration\n }\n return\n }\n const found = find(step.clip, step.variant)\n if (!found) return\n const clip = leadClipEvents(step.duration && step.duration > 0 ? scaleClip(found.clip, step.duration) : found.clip)\n const interval = options.repeatInterval?.() ?? 0.1\n instances = instances.filter((existing) => existing.name !== found.name || existing.delay > 0)\n for (let round = 0; round < (step.repeat ?? 1); round++) {\n instances.push({ name: found.name, clip, time: 0, delay: round * interval, fired: 0 })\n }\n },\n update(dt) {\n for (const instance of instances) {\n const carried = instance.delay > 0 ? dt - instance.delay : dt\n if (instance.delay > 0) {\n instance.delay = Math.max(0, instance.delay - dt)\n if (instance.delay > 0) continue\n }\n instance.time += carried\n fireEvents(instance, instance.time)\n render(instance)\n }\n instances = instances.filter((instance) => instance.delay > 0 || instance.time < instance.clip.duration)\n },\n get playing() {\n return instances.map((instance) => instance.name)\n },\n get running() {\n return instances.filter((instance) => instance.delay <= 0).map((instance) => ({ name: instance.name, time: instance.time, clip: instance.clip }))\n },\n }\n}\n","export const FRAME_PHASES = ['input', 'fixedSimulate', 'lateSimulate', 'present', 'render', 'idle'] as const\nexport type FramePhase = (typeof FRAME_PHASES)[number]\n\n/**\n * Presentation work a system leaves for later frames, run in small units within a shared time budget.\n * Never simulation: nothing that consumes a seeded generator or decides an outcome may wait in a queue.\n */\nexport interface DeferredQueue {\n /** Stable name for stats and logs (see `DEFERRED_QUEUE_ID`). */\n readonly id: string\n /**\n * Units waiting. 0 means idle; the budget skips the queue without calling `run`. `frame` is the budget's frame counter: a queue may\n * report 0 for the rest of a frame (the crease queue does in the frame a panel was torn). Same value for repeated calls in one frame.\n */\n pending(frame?: number): number\n /**\n * Runs units in order until `clock() >= deadline`. Contract: when `pending() > 0` it runs **at least one** unit, even with a deadline\n * already past; it never runs a unit after it saw the deadline pass. Returns how many units it ran.\n */\n run(deadline: number, clock: () => number): number\n /** Runs everything now (synchronous step, clear, dispose). */\n flush(): void\n /**\n * Called by `budget.register`: from now on the owner stops draining on its own (no MessageChannel, no drain inside `update`).\n * Never called by a getter; a queue nobody registered keeps today's internal draining.\n */\n attach?(): void\n /** Called by the unregister function and by `budget.dispose`: the owner goes back to its internal draining. */\n detach?(): void\n}\n\n/** Where a module registers a deferred queue with the host's budget. */\nexport interface DeferredQueueOptions {\n /** Higher runs first. See DEFERRED_PRIORITY. */\n readonly priority: number\n /** `present` runs before the render (the work must show this frame); `idle` runs after it. Default `idle`. */\n readonly phase?: 'present' | 'idle'\n /** Starvation guard: the queue runs at least one unit every this many frames, even with the budget spent. Default 4. */\n readonly minEveryFrames?: number\n /** Milliseconds of every frame kept for this queue before the others share the rest (when it has work). Default 0. */\n readonly reserveMs?: number\n}\n\n/** The ids of the kit's queues: what `DeferredQueue.id` says and what `DEFERRED_PRIORITY` is keyed by. */\nexport const DEFERRED_QUEUE_ID = {\n DESTRUCTION_EVENTS: 'destruction.events',\n BREACH_PAINT: 'floorplan.breach-paint',\n AUDIO_VOICES: 'audio.voices',\n VEHICLE_CREASE: 'vehicles.crease',\n} as const\n\n/** Default priorities and reserves of the kit's queues; a host may override any of them. */\nexport const DEFERRED_PRIORITY = {\n [DEFERRED_QUEUE_ID.DESTRUCTION_EVENTS]: { priority: 300, phase: 'present' },\n [DEFERRED_QUEUE_ID.BREACH_PAINT]: { priority: 250, phase: 'present' },\n [DEFERRED_QUEUE_ID.AUDIO_VOICES]: { priority: 200, phase: 'idle', reserveMs: 1 },\n [DEFERRED_QUEUE_ID.VEHICLE_CREASE]: { priority: 100, phase: 'idle' },\n} as const satisfies Readonly<Record<string, DeferredQueueOptions>>\n\nexport interface DeferredQueueReport {\n readonly ok: boolean\n readonly problems: readonly string[]\n}\n\n/**\n * Checks the `DeferredQueue` contract. `fill` leaves the queue with at least two units waiting (the same call is made on a fresh queue).\n * It cannot prove the queue only carries presentation work: that is a rule of review.\n */\nexport function checkDeferredQueue(queue: DeferredQueue, fill: () => void): DeferredQueueReport {\n const problems: string[] = []\n fill()\n const waiting = queue.pending(1)\n if (waiting < 2) problems.push(`fill() must leave at least 2 units waiting (pending is ${waiting})`)\n if (queue.pending(1) !== waiting) problems.push('pending(frame) changed between two calls in the same frame')\n const ran = queue.run(0, () => 1)\n if (ran !== 1) problems.push(`run with a deadline already past must run exactly one unit (ran ${ran})`)\n if (waiting >= 2 && queue.pending(2) !== waiting - 1) problems.push(`one unit ran but pending went from ${waiting} to ${queue.pending(2)}`)\n try {\n queue.attach?.()\n queue.attach?.()\n queue.detach?.()\n queue.detach?.()\n } catch (error) {\n problems.push(`attach/detach must be idempotent: ${error instanceof Error ? error.message : String(error)}`)\n }\n queue.flush()\n if (queue.pending(3) !== 0) problems.push(`flush must leave nothing pending (pending is ${queue.pending(3)})`)\n if (queue.run(0, () => 1) !== 0) problems.push('run on an empty queue must run no unit')\n return { ok: problems.length === 0, problems }\n}\n","const WARNED_KEY = Symbol.for('@adatechnology/game-contracts.warned')\n\ntype WarnedHolder = { [WARNED_KEY]?: Set<string> }\n\nconst warnedKeys = (): Set<string> => {\n const holder = globalThis as WarnedHolder\n return (holder[WARNED_KEY] ??= new Set<string>())\n}\n\ndeclare const process: { readonly env: { readonly NODE_ENV?: string } }\n\n// The literal `process.env.NODE_ENV` is what bundlers replace; where there is no `process` the reference throws and counts as development.\nconst isProduction = (): boolean => {\n try {\n return process.env.NODE_ENV === 'production'\n } catch {\n return false\n }\n}\n\nconst isQuiet = (): boolean => (globalThis as { __GAME_KIT_QUIET__?: unknown }).__GAME_KIT_QUIET__ === true\n\n/**\n * Warns on the console the first time `key` is seen, and only outside production and when `globalThis.__GAME_KIT_QUIET__` is not `true`: for a silent fallback that keeps working (an adapter that made its own effects\n * world or audio engine because the host lent none). The seen keys live on `globalThis`, so several bundles of the kit on one page warn once together.\n */\nexport const warnOnce = (key: string, message: string): void => {\n if (isQuiet() || isProduction()) return\n const seen = warnedKeys()\n if (seen.has(key)) return\n seen.add(key)\n console.warn(`[game-kit] ${message}`)\n}\n\n/** Forgets what `warnOnce` has seen (tests that count warnings). */\nexport const resetWarnOnce = (): void => warnedKeys().clear()\n","import { warnOnce } from './warn'\n\ntype PlainObject = Record<string, unknown>\ntype Entry = { readonly id: string }\n\n/** Keys that would reach the prototype of the result when a patch comes from parsed JSON. */\nconst UNSAFE_KEYS: ReadonlySet<string> = new Set(['__proto__', 'constructor', 'prototype'])\n\nconst isPlainObject = (value: unknown): value is PlainObject =>\n typeof value === 'object' && value !== null && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype\n\n/** Recursively optional; arrays and functions are replaced as a whole, objects are merged. */\nexport type DeepPartial<TValue> = TValue extends (...args: never[]) => unknown\n ? TValue\n : TValue extends readonly unknown[]\n ? TValue\n : TValue extends object\n ? { [TKey in keyof TValue]?: DeepPartial<TValue[TKey]> }\n : TValue\n\n/** Merges `patch` over `base`: plain objects merge field by field, arrays, functions and primitives replace. `undefined` in the patch is ignored. */\nexport const deepMerge = <TBase extends object>(base: TBase, patch: object | undefined): TBase => {\n if (!patch) return base\n const result: PlainObject = { ...(base as PlainObject) }\n for (const [key, value] of Object.entries(patch)) {\n if (value === undefined || UNSAFE_KEYS.has(key)) continue\n const current = result[key]\n result[key] = isPlainObject(current) && isPlainObject(value) ? deepMerge(current, value) : value\n }\n return result as TBase\n}\n\n/** The shipped entries with the ones from `extra` added or, when the id exists, replaced. */\nexport const mergeById = <TEntry extends Entry>(shipped: readonly TEntry[], extra: readonly TEntry[] | undefined): Map<string, TEntry> => {\n const entries = new Map<string, TEntry>()\n for (const entry of [...shipped, ...(extra ?? [])]) entries.set(entry.id, entry)\n return entries\n}\n\n/** Applies `patch` by id; a patch for an id that does not exist is ignored (and warned about once, in development). */\nexport const applyPatches = <TEntry extends Entry>(entries: Map<string, TEntry>, patches: Readonly<Record<string, DeepPartial<TEntry> | Partial<TEntry>>> | undefined): void => {\n for (const [id, patch] of Object.entries(patches ?? {})) {\n const entry = entries.get(id)\n if (entry) entries.set(id, deepMerge(entry, patch))\n else warnOnce(`registry.patch.${id}`, `patch for \"${id}\" ignored: no entry has that id`)\n }\n}\n\n/** Takes the ids out; an id that does not exist is ignored (and warned about once, in development). */\nexport const removeIds = (entries: Map<string, unknown>, ids: readonly string[] | undefined): void => {\n for (const id of ids ?? []) {\n if (!entries.delete(id)) warnOnce(`registry.remove.${id}`, `remove of \"${id}\" ignored: no entry has that id`)\n }\n}\n","import type { Vec3 } from './destruction'\n\n/**\n * The bench of a module: controls, layers and counters it declares as data. The host keeps the values, draws them in a generic way and hands\n * every change back through `ModuleHost.bench`. Nothing here is specific to a kind of module.\n */\nexport type ControlValue = number | boolean | string\n\nexport interface ChoiceOption {\n readonly id: string\n readonly name: string\n /** Heading the host lists the option under (`optgroup`, a grouped row of buttons). Options of a group must sit next to each other. */\n readonly group?: string\n}\n\ninterface ControlBase {\n /** snake_case, unique across the module's controls, layers and metrics. */\n readonly id: string\n /** Display name, already translated for the locale the host asked for. */\n readonly name: string\n readonly hint?: string\n readonly hidden?: boolean\n /**\n * The change (or the press, for an action) takes a noticeable time, a third of a second or more: the host shows its loading indicator while it works, with this text, or the control's name for `true`.\n * Only the host's own controls panel does it; a change made through `TestRoom.bench().set / act` runs at once.\n */\n readonly slow?: boolean | string\n}\n\nexport interface NumberControl extends ControlBase {\n readonly kind: 'number'\n readonly min: number\n readonly max: number\n readonly step?: number\n readonly unit?: string\n readonly default: number\n}\n\nexport interface BooleanControl extends ControlBase {\n readonly kind: 'boolean'\n readonly default: boolean\n}\n\nexport interface ChoiceControl extends ControlBase {\n readonly kind: 'choice'\n readonly options: readonly ChoiceOption[]\n readonly default: string\n}\n\n/** A button: no value, only the press. */\nexport interface ActionControl extends ControlBase {\n readonly kind: 'action'\n}\n\nexport type ModuleControl = NumberControl | BooleanControl | ChoiceControl | ActionControl\n\n/** Something of the module the viewer turns on or off (smoke, flash, casings). */\nexport interface ModuleLayer {\n readonly id: string\n readonly name: string\n /** On unless `false`. */\n readonly default?: boolean\n}\n\n/** Pulled: the room calls read only when it samples (~4 Hz, or on TestRoom.metrics()). */\nexport interface ModuleMetric {\n readonly id: string\n readonly name: string\n readonly unit?: string\n /** Budget: the host shows a bar and warns past it. */\n readonly max?: number\n readonly digits?: number\n read(): number | string\n}\n\nexport type BenchChange =\n | { readonly kind: 'control'; readonly id: string; readonly value: ControlValue }\n | { readonly kind: 'layer'; readonly id: string; readonly on: boolean }\n | { readonly kind: 'action'; readonly id: string }\n\nexport interface ControlPatch {\n readonly hidden?: boolean\n readonly disabled?: boolean\n readonly options?: readonly ChoiceOption[]\n readonly value?: ControlValue\n}\n\n/** What the host lends a module that declares a bench: the current values and the changes. */\nexport interface ModuleBench {\n value(id: string): ControlValue | undefined\n layer(id: string): boolean\n /** Right after attach returns, the host sends one change per control (not actions) and per layer, in declaration order. */\n onChange(listener: (change: BenchChange) => void): () => void\n /** `value` sets without emitting (no echo loops); `options` falls back to the first option if the value is no longer offered. */\n patch(id: string, patch: ControlPatch): void\n /** Move the host camera (a near / middle / far choice). */\n look(eye: Vec3, target: Vec3): void\n /** Shows a sheet on the host's panel, or takes it down with `null`. A host without a sheet area ignores it. */\n sheet?(sheet: BenchSheet | null): void\n}\n\n/**\n * A card of text the module puts on the host's panel (the sheet of an effect, of a weapon): what it is, its numbers, its steps, its colours and,\n * optionally, a strip of segments over time. Names and texts are already translated for the host's locale.\n */\nexport interface BenchSheet {\n readonly kicker?: string\n readonly title: string\n readonly body?: string\n readonly facts?: readonly { readonly label: string; readonly value: string }[]\n readonly steps?: readonly { readonly at: string; readonly text: string }[]\n readonly swatches?: readonly { readonly color: string; readonly name: string }[]\n readonly note?: string\n /** A strip of named segments (seconds), with tick marks and a playhead that follows the module metric `metric`. */\n readonly timeline?: {\n readonly segments: readonly { readonly name: string; readonly start: number; readonly end: number; readonly color: string }[]\n readonly ticks: readonly number[]\n readonly metric: string\n }\n}\n\nexport interface BenchReport {\n readonly ok: boolean\n readonly problems: readonly string[]\n}\n\nexport interface BenchDeclaration {\n readonly controls?: readonly ModuleControl[]\n readonly layers?: readonly ModuleLayer[]\n readonly metrics?: readonly ModuleMetric[]\n}\n\nconst SNAKE_CASE = /^[a-z][a-z0-9_]*$/\nconst finite = (n: unknown): n is number => typeof n === 'number' && Number.isFinite(n)\n\nfunction checkControl(control: ModuleControl, problems: string[]): void {\n const label = `control \"${control.id}\"`\n if (control.kind === 'number') {\n if (!finite(control.min) || !finite(control.max) || control.min >= control.max) problems.push(`${label} needs min < max`)\n if (control.step !== undefined && !(finite(control.step) && control.step > 0)) problems.push(`${label} needs a step > 0`)\n if (!finite(control.default) || control.default < control.min || control.default > control.max) problems.push(`${label} default ${String(control.default)} is outside ${control.min}..${control.max}`)\n return\n }\n if (control.kind !== 'choice') return\n if (control.options.length === 0) {\n problems.push(`${label} needs at least one option`)\n return\n }\n const seen = new Set<string>()\n const groups = new Set<string>()\n let previousGroup: string | undefined\n for (const option of control.options) {\n if (seen.has(option.id)) problems.push(`${label} repeats option \"${option.id}\"`)\n seen.add(option.id)\n if (option.group !== undefined && (typeof option.group !== 'string' || option.group === '')) problems.push(`${label} option \"${option.id}\" has an empty group`)\n else if (option.group !== undefined && option.group !== previousGroup && groups.has(option.group)) problems.push(`${label} group \"${option.group}\" is split: its options must be next to each other`)\n if (typeof option.group === 'string' && option.group !== '') groups.add(option.group)\n previousGroup = option.group\n }\n if (!seen.has(control.default)) problems.push(`${label} default \"${control.default}\" is not among its options`)\n}\n\n/** snake_case ids unique across controls, layers and metrics; min < max; step > 0; default in range; options non-empty, unique, default among them, each group in one run; metric max > 0. */\nexport function checkBench(declared: BenchDeclaration): BenchReport {\n const problems: string[] = []\n const ids = new Set<string>()\n const claim = (kind: string, id: string): void => {\n if (!SNAKE_CASE.test(id)) problems.push(`${kind} id \"${id}\" must be snake_case`)\n if (ids.has(id)) problems.push(`duplicate id \"${id}\" across controls, layers and metrics`)\n ids.add(id)\n }\n for (const control of declared.controls ?? []) {\n claim('control', control.id)\n checkControl(control, problems)\n }\n for (const layer of declared.layers ?? []) claim('layer', layer.id)\n for (const metric of declared.metrics ?? []) {\n claim('metric', metric.id)\n if (metric.max !== undefined && !(finite(metric.max) && metric.max > 0)) problems.push(`metric \"${metric.id}\" needs a max > 0`)\n }\n return { ok: problems.length === 0, problems }\n}\n","/** The weather, light and ground as the world is right now. Written by whoever drives the weather, read by whoever reacts to it. */\nexport interface EnvironmentState {\n /** Rain in mm/h; 0 is dry. */\n readonly rain: number\n /** Wind in m/s along x and z, and its strength (the length of that vector). */\n readonly windX: number\n readonly windZ: number\n readonly windSpeed: number\n /** Strongest gust in m/s. */\n readonly gust: number\n /** Render fog far distance in metres. */\n readonly fogFar: number\n /** How far one can see for gameplay, in metres (not the render fog). */\n readonly visibility: number\n /** 0 is full daylight, 1 is the darkest night. */\n readonly nightFactor: number\n readonly temperatureC: number\n /** Wet ground, 0..1: rises with rain and dries after it stops. */\n readonly wetness: number\n}\n\nexport type EnvironmentKey = keyof EnvironmentState\n\n/** A calm dry day (the normal world, before anything went wrong). */\nexport const DEFAULT_ENVIRONMENT: EnvironmentState = {\n rain: 0,\n windX: 0,\n windZ: 0,\n windSpeed: 0,\n gust: 0,\n fogFar: 220,\n visibility: 220,\n nightFactor: 0,\n temperatureC: 20,\n wetness: 0,\n}\n\n/** The host's environment (`ModuleHost.environment`): a store the weather module writes to and the others read. */\nexport interface EnvironmentBus {\n get(): EnvironmentState\n /** Merges `patch` into the state; listeners hear it only when a value really changed. */\n set(patch: Partial<EnvironmentState>): void\n /** Hears every change with the keys that changed. Returns the unsubscribe function. */\n on(listener: (state: EnvironmentState, changed: readonly EnvironmentKey[]) => void): () => void\n}\n\n/** A plain store that implements the bus; the test room and tests use it, a game may bring its own. */\nexport function createEnvironmentBus(initial: Partial<EnvironmentState> = {}): EnvironmentBus {\n let state: EnvironmentState = { ...DEFAULT_ENVIRONMENT, ...initial }\n const listeners = new Set<(state: EnvironmentState, changed: readonly EnvironmentKey[]) => void>()\n return {\n get: () => state,\n set(patch) {\n const changed = (Object.keys(patch) as EnvironmentKey[]).filter((key) => patch[key] !== undefined && patch[key] !== state[key])\n if (changed.length === 0) return\n const next = { ...state } as { -readonly [Key in EnvironmentKey]: number }\n for (const key of changed) next[key] = patch[key] as number\n state = next\n for (const listener of [...listeners]) listener(state, changed)\n },\n on(listener) {\n listeners.add(listener)\n return () => void listeners.delete(listener)\n },\n }\n}\n","import { applyPatches, deepMerge, mergeById, removeIds } from './registry'\nimport type { DeepPartial } from './registry'\n\n/** One category (kind) of items. Defaults and required contracts are inherited from the `extends` chain. */\nexport interface CategoryDef<TDefaults extends object = Record<string, unknown>> {\n readonly id: string\n /** Parent category id; the child inherits its defaults and its required contracts. */\n readonly extends?: string\n /** Field values every entry of this kind starts with; objects merge down the chain, arrays replace. */\n readonly defaults?: DeepPartial<TDefaults>\n /** Contract ids (`ContractChecker.id`) every entry of this kind, or of a descendant, must satisfy. */\n readonly requires?: readonly string[]\n /** An abstract category only groups: entries cannot declare it directly, only its descendants. */\n readonly abstract?: boolean\n}\n\n/** Where a checker is being run: the entry's kind and the chain of categories root first. */\nexport interface ContractContext {\n readonly kind: string\n readonly chain: readonly string[]\n}\n\n/** A named contract: returns the problems of an entry, each a short phrase like `missing leftover.despawnSeconds`. Empty means it holds. */\nexport interface ContractChecker<TEntry> {\n readonly id: string\n check(entry: TEntry, ctx: ContractContext): string[]\n}\n\nexport interface CategoryOptions {\n /** Categories added to the shipped ones; the same id replaces. */\n readonly extra?: readonly CategoryDef[]\n /** Partial changes by id, applied after `extra`. */\n readonly patches?: Readonly<Record<string, DeepPartial<CategoryDef> | Partial<CategoryDef>>>\n /** Ids taken out of the tree (their children are then reported by `check()`). */\n readonly remove?: readonly string[]\n}\n\nexport interface CategoryRegistry {\n get(id: string): CategoryDef | undefined\n has(id: string): boolean\n ids(): string[]\n /** Root first, ending at `id`. Throws on an unknown id, an unknown parent or a cycle. */\n chain(id: string): string[]\n /** `defaults` merged along the chain, root first, so the closest category wins. */\n defaults(id: string): Record<string, unknown>\n /** Union of `requires` along the chain, order kept, without duplicates. */\n requires(id: string): string[]\n /** True when `id` is `ancestorId` or descends from it. */\n isA(id: string, ancestorId: string): boolean\n /** Problems in the tree itself: duplicate ids, unknown `extends`, cycles. */\n check(): string[]\n}\n\nexport interface CategorizedOptions {\n /** Field of the entry that names its category. Default `kind`. */\n readonly kindField?: string\n /** Known gaps by entry id: problems starting with one of these texts go to `allowed`, so the list can shrink over time. */\n readonly allow?: Readonly<Record<string, readonly string[]>>\n}\n\nexport interface CategorizedReport {\n readonly ok: boolean\n readonly problems: string[]\n readonly allowed: string[]\n}\n\nexport const defineCategories = (defs: readonly CategoryDef[], options: CategoryOptions = {}): CategoryRegistry => {\n const problems: string[] = []\n const duplicates = (list: readonly CategoryDef[]): void => {\n const ids = new Set<string>()\n for (const def of list) {\n if (ids.has(def.id)) problems.push(`duplicate category \"${def.id}\"`)\n ids.add(def.id)\n }\n }\n duplicates(defs)\n duplicates(options.extra ?? [])\n\n const entries = mergeById(defs, options.extra)\n applyPatches(entries, options.patches)\n removeIds(entries, options.remove)\n\n const chain = (id: string): string[] => {\n const path: string[] = []\n let current: string | undefined = id\n while (current !== undefined) {\n const def = entries.get(current)\n if (!def) throw new Error(path.length === 0 ? `unknown category \"${current}\"` : `category \"${path[0]}\" has unknown parent \"${current}\"`)\n if (path.includes(current)) throw new Error(`category cycle: ${[...path, current].reverse().join(' -> ')}`)\n path.push(current)\n current = def.extends\n }\n return path.reverse()\n }\n\n const registry: CategoryRegistry = {\n get: (id) => entries.get(id),\n has: (id) => entries.has(id),\n ids: () => [...entries.keys()],\n chain,\n defaults: (id) => chain(id).reduce<Record<string, unknown>>((acc, ancestor) => deepMerge(acc, entries.get(ancestor)?.defaults), {}),\n requires: (id) => {\n const out: string[] = []\n for (const ancestor of chain(id)) for (const contract of entries.get(ancestor)?.requires ?? []) if (!out.includes(contract)) out.push(contract)\n return out\n },\n isA: (id, ancestorId) => {\n try {\n return chain(id).includes(ancestorId)\n } catch {\n return false\n }\n },\n check: () => {\n const found = [...problems]\n for (const [id, def] of entries) {\n if (def.extends !== undefined && !entries.has(def.extends)) found.push(`category \"${id}\" extends unknown \"${def.extends}\"`)\n else {\n try {\n chain(id)\n } catch (error) {\n const message = (error as Error).message\n // The same cycle is found from each of its members; the dedupe keeps one line per distinct message.\n if (message.startsWith('category cycle') && !found.includes(message)) found.push(message)\n }\n }\n }\n return found\n },\n }\n return registry\n}\n\n/** The entry with the defaults of its category underneath: the entry wins, objects merge, arrays replace. */\nexport const resolveEntry = <TEntry extends object>(registry: CategoryRegistry, entry: TEntry, kindField = 'kind'): TEntry =>\n deepMerge(registry.defaults(String((entry as Record<string, unknown>)[kindField])) as TEntry, entry)\n\n/** Checks that each entry has a known, concrete kind and satisfies every contract its chain requires. */\nexport const checkCategorized = <TEntry extends { readonly id: string }>(\n entries: readonly TEntry[],\n registry: CategoryRegistry,\n checkers: readonly ContractChecker<TEntry>[],\n options: CategorizedOptions = {},\n): CategorizedReport => {\n const kindField = options.kindField ?? 'kind'\n const byId = new Map(checkers.map((checker) => [checker.id, checker]))\n const problems: string[] = [...registry.check()]\n const allowed: string[] = []\n\n for (const entry of entries) {\n const kind = String((entry as Record<string, unknown>)[kindField])\n if (!registry.has(kind)) {\n problems.push(`\"${entry.id}\" has unknown kind \"${kind}\"`)\n continue\n }\n if (registry.get(kind)?.abstract) {\n problems.push(`\"${entry.id}\" has abstract kind \"${kind}\"`)\n continue\n }\n let path: string[]\n try {\n path = registry.chain(kind)\n } catch (error) {\n problems.push(`\"${entry.id}\" (${kind}): ${(error as Error).message}`)\n continue\n }\n const resolved = resolveEntry(registry, entry, kindField)\n for (const contract of registry.requires(kind)) {\n const owner = path.find((ancestor) => registry.get(ancestor)?.requires?.includes(contract)) ?? kind\n const checker = byId.get(contract)\n if (!checker) {\n problems.push(`kind \"${kind}\" requires contract \"${contract}\" but no checker is registered`)\n continue\n }\n const prefix = `\"${entry.id}\" (${kind}): `\n for (const problem of checker.check(resolved, { kind, chain: path })) {\n const text = `${prefix}${problem}, required by ${owner}`\n if ((options.allow?.[entry.id] ?? []).some((start) => problem.startsWith(start))) allowed.push(text)\n else problems.push(text)\n }\n }\n }\n return { ok: problems.length === 0, problems: [...new Set(problems)], allowed }\n}\n","/**\n * Where a drawn object comes from. Every builder of the kit that draws a piece (a car of the fleet, a house or a wall, a piece of furniture, a person, an\n * animal, a plant, an item, a weapon) marks the root it returns, and every renderer that draws for the room (effects, debris, liquids, the room itself)\n * marks its own roots, so a host can tell a piece of the kit from something drawn on the spot. Duck-typed on three.js objects (`userData`, `parent`,\n * `children`), so the contracts stay free of three.js.\n */\nexport const KIT_ORIGIN_KEY = 'kitOrigin'\n\n/** What drew an object: the package and the kind of piece (`vehicle`, `structure`, `furniture`, `person`... or `effect`, `room` for what is not a piece). */\nexport interface KitOrigin {\n readonly owner: string\n readonly kind: string\n /** The catalogue id of the piece, when it has one. */\n readonly id?: string\n /** Drawn as a simple stand-in shape because the kit has no model of the piece yet (an item with no team model): a model still to make. */\n readonly standIn?: boolean\n}\n\ninterface Node {\n userData?: Record<string, unknown>\n parent?: Node | null\n children?: readonly Node[]\n name?: string\n visible?: boolean\n isMesh?: boolean\n isPoints?: boolean\n isLine?: boolean\n isSprite?: boolean\n}\n\n/** Marks `object` as drawn by `origin.owner` and returns it. */\nexport function markKitOrigin<T>(object: T, origin: KitOrigin): T {\n const node = object as unknown as Node\n node.userData = node.userData ?? {}\n node.userData[KIT_ORIGIN_KEY] = { ...origin }\n return object\n}\n\n/** The origin of the object or of its nearest marked ancestor; null when nothing up the tree is marked. */\nexport function kitOriginOf(object: unknown): KitOrigin | null {\n for (let node = object as Node | null | undefined; node; node = node.parent) {\n const origin = node.userData?.[KIT_ORIGIN_KEY] as KitOrigin | undefined\n if (origin && typeof origin.owner === 'string') return origin\n }\n return null\n}\n\n/** A drawn thing that no builder of the kit marked: what was drawn on the spot. */\nexport interface UnmarkedDrawing {\n /** The names of the object and its named ancestors, outermost first. */\n readonly path: string\n readonly object: unknown\n}\n\n/** Every visible mesh, line, point cloud or sprite under `root` with no marked ancestor (`root` itself not counted as one). */\nexport function unmarkedDrawings(root: unknown): UnmarkedDrawing[] {\n const out: UnmarkedDrawing[] = []\n const pathOf = (node: Node): string => {\n const names: string[] = []\n for (let n: Node | null | undefined = node; n && n !== root; n = n.parent) if (n.name) names.push(n.name)\n return names.reverse().join(' > ') || '(no name)'\n }\n const walk = (node: Node, marked: boolean): void => {\n if (node.visible === false) return\n const here = marked || (node !== root && Boolean((node.userData?.[KIT_ORIGIN_KEY] as KitOrigin | undefined)?.owner))\n if (!here && (node.isMesh || node.isPoints || node.isLine || node.isSprite)) out.push({ path: pathOf(node), object: node })\n for (const child of node.children ?? []) walk(child, here)\n }\n walk(root as Node, false)\n return out\n}\n","/** A floor rectangle in an object's own space, metres (x across, z along). */\nexport interface Footprint {\n readonly minX: number\n readonly maxX: number\n readonly minZ: number\n readonly maxZ: number\n}\n\n/** What `footprintBlocker` reads of an object: its world matrix (three.js `Object3D`, duck-typed so the contracts stay free of three.js). */\nexport interface FootprintObject {\n readonly matrixWorld: { readonly elements: ArrayLike<number> }\n readonly parent?: unknown\n updateWorldMatrix?(updateParents: boolean, updateChildren: boolean): void\n}\n\n/**\n * The `ModuleHost.addBlocker` function of a solid object standing on the floor: the walking player stays out of `footprint`, a rectangle in the object's own space,\n * so the object blocks turned with it and follows it when it moves. An object out of the scene (no parent) blocks nothing.\n */\nexport function footprintBlocker(object: FootprintObject | (() => FootprintObject | null | undefined), footprint: Footprint | (() => Footprint | null | undefined)): (x: number, z: number, radius: number) => boolean {\n return (x, z, radius) => {\n const o = typeof object === 'function' ? object() : object\n const fp = typeof footprint === 'function' ? footprint() : footprint\n if (!o || !fp || !o.parent) return false\n o.updateWorldMatrix?.(true, false)\n const e = o.matrixWorld.elements\n // the world point in the object's own floor axes: its x and z columns are at right angles, so a projection on each (over its squared length, for a scale) inverts the matrix\n const dx = x - (e[12] as number)\n const dz = z - (e[14] as number)\n const ax = (e[0] as number) ** 2 + (e[1] as number) ** 2 + (e[2] as number) ** 2\n const az = (e[8] as number) ** 2 + (e[9] as number) ** 2 + (e[10] as number) ** 2\n const lx = (dx * (e[0] as number) + dz * (e[2] as number)) / (ax || 1)\n const lz = (dx * (e[8] as number) + dz * (e[10] as number)) / (az || 1)\n return lx > fp.minX - radius && lx < fp.maxX + radius && lz > fp.minZ - radius && lz < fp.maxZ + radius\n }\n}\n","/**\n * The sounds of a body (footsteps, jumps, landings, blows, hurt), as ids every package agrees on: the rule that knows what the body did\n * (`game-player`, a host's own player) names the sound, and the bank that knows how it sounds (`game-audio`'s `BODY_FOLEY_BANK`) answers it.\n * A game swaps the sound of an id (a sample instead of the synthesis) without touching the rule.\n */\n\n/** What the feet touch, by how it sounds (not by what it is made of: a wooden floor and a plywood board both sound `wood`). */\nexport const SURFACE_IDS = ['concrete', 'asphalt', 'wood', 'tile', 'dirt', 'grass', 'gravel', 'sand', 'metal', 'water', 'glass', 'carpet'] as const\nexport type SurfaceId = (typeof SURFACE_IDS)[number]\n\n/** The surface a body stands on when nobody says (the test room's floor is a concrete slab). */\nexport const DEFAULT_SURFACE: SurfaceId = 'concrete'\n\n/** How the feet move: a run hits harder and shorter; a crouched step is the walk, quieter. */\nexport const GAIT_IDS = ['walk', 'run'] as const\nexport type GaitId = (typeof GAIT_IDS)[number]\n\n/** How hard a landing is: `light` for a jump on the spot or a step down (up to about 5 m/s), `heavy` for a drop of more than a metre and a half. */\nexport const LANDING_IDS = ['light', 'heavy'] as const\nexport type LandingId = (typeof LANDING_IDS)[number]\n\n/** The fall speed (m/s) from which a landing is `heavy`. */\nexport const HEAVY_LANDING_SPEED = 5.5\n\nexport type FootstepSoundId = `footstep_${SurfaceId}_${GaitId}`\nexport type LandSoundId = `land_${SurfaceId}_${LandingId}`\n\n/**\n * How a blow is struck, by the body part or the tool that does it. `blade` stabs or slashes, `blunt` is a club, a bat, a pipe or a hammer, `chop` an\n * axe or a machete driven down.\n */\nexport const BLOW_IDS = ['punch', 'kick', 'shove', 'blade', 'blunt', 'chop'] as const\nexport type BlowId = (typeof BLOW_IDS)[number]\n\n/** What the blow meets: a body (flesh and bone, the head apart), something else (the material answers with its own impact), or nothing. */\nexport type BlowTarget = 'body' | 'head' | 'object' | 'air'\n\n/** The sounds of the body that are not a footstep or a landing. */\nexport const BODY_SOUND_IDS = [\n 'jump',\n 'cloth_rustle',\n 'body_fall',\n 'fall_damage',\n 'player_hurt',\n 'player_breath_run',\n 'player_death',\n 'bite',\n 'grab',\n 'punch_swing',\n 'punch_hit_body',\n 'punch_hit_face',\n 'punch_hit_object',\n 'kick_swing',\n 'kick_hit',\n 'kick_hit_object',\n 'shove_two_hands',\n 'knife_swing',\n 'knife_stab',\n 'knife_slash',\n 'knife_hit_object',\n 'blunt_swing',\n 'blunt_hit',\n 'blunt_hit_object',\n 'axe_swing',\n 'axe_chop',\n 'axe_hit_object',\n] as const\nexport type BodySoundId = (typeof BODY_SOUND_IDS)[number]\n\n/** Every sound of a body: what a host plays for the player, a survivor or a zombie. */\nexport type BodyFoleyId = FootstepSoundId | LandSoundId | BodySoundId\n\nexport const footstepSoundId = (surface: SurfaceId, gait: GaitId): FootstepSoundId => `footstep_${surface}_${gait}`\nexport const landSoundId = (surface: SurfaceId, fallSpeed: number): LandSoundId => `land_${surface}_${fallSpeed >= HEAVY_LANDING_SPEED ? 'heavy' : 'light'}`\n\n/** Every footstep and landing id, in the order of the surfaces. */\nexport const FOOTSTEP_SOUND_IDS: readonly FootstepSoundId[] = SURFACE_IDS.flatMap((surface) => GAIT_IDS.map((gait) => footstepSoundId(surface, gait)))\nexport const LAND_SOUND_IDS: readonly LandSoundId[] = SURFACE_IDS.flatMap((surface) => LANDING_IDS.map((landing): LandSoundId => `land_${surface}_${landing}`))\nexport const BODY_FOLEY_IDS: readonly BodyFoleyId[] = [...FOOTSTEP_SOUND_IDS, ...LAND_SOUND_IDS, ...BODY_SOUND_IDS]\n\nconst SWING: Readonly<Record<BlowId, BodySoundId | null>> = {\n punch: 'punch_swing',\n kick: 'kick_swing',\n // two hands pushed out do not whistle: the shove is one sound, at the contact\n shove: null,\n blade: 'knife_swing',\n blunt: 'blunt_swing',\n chop: 'axe_swing',\n}\n\n/**\n * Seconds from the start of a swing's sound to its loudest point (the limb or the tool at full speed, just before the contact). A host that knows when the\n * blow lands starts the swing this long before; one that does not plays the swing now and the hit this long after.\n */\nexport const SWING_LEAD_SECONDS: Readonly<Record<BlowId, number>> = { punch: 0.07, kick: 0.09, shove: 0, blade: 0.05, blunt: 0.1, chop: 0.11 }\n\n/** The swing through the air, played as the blow starts (`null`: the blow has none). */\nexport const swingSoundId = (blow: BlowId): BodySoundId | null => SWING[blow]\n\nconst HIT: Readonly<Record<BlowId, Readonly<Record<Exclude<BlowTarget, 'air'>, BodySoundId>>>> = {\n punch: { body: 'punch_hit_body', head: 'punch_hit_face', object: 'punch_hit_object' },\n kick: { body: 'kick_hit', head: 'kick_hit', object: 'kick_hit_object' },\n shove: { body: 'shove_two_hands', head: 'shove_two_hands', object: 'shove_two_hands' },\n blade: { body: 'knife_stab', head: 'knife_stab', object: 'knife_hit_object' },\n blunt: { body: 'blunt_hit', head: 'blunt_hit', object: 'blunt_hit_object' },\n chop: { body: 'axe_chop', head: 'axe_chop', object: 'axe_hit_object' },\n}\n\n/**\n * The body's side of a blow that lands: the knuckles, the shoe, the blade or the club meeting what it hit. On an object the material's own impact\n * plays too (the wood, the metal); this is the part that says it was a punch and not a shot.\n */\nexport const hitSoundId = (blow: BlowId, target: Exclude<BlowTarget, 'air'>): BodySoundId => HIT[blow][target]\n\n/**\n * The surface a material sounds like underfoot, by the material ids of `game-destruction` and `game-terrain` (unknown ids: `fallback`). Data, so\n * a game with its own materials passes its own table to `surfaceOfMaterial`.\n */\nexport const MATERIAL_SURFACES: Readonly<Record<string, SurfaceId>> = {\n concrete: 'concrete',\n mortar: 'concrete',\n stone: 'concrete',\n brick: 'concrete',\n plaster: 'concrete',\n asphalt: 'asphalt',\n wood_soft: 'wood',\n wood_hard: 'wood',\n green_wood: 'wood',\n plywood: 'wood',\n mdf: 'wood',\n ceramic: 'tile',\n plastic: 'tile',\n soil: 'dirt',\n wax: 'dirt',\n flesh_fruit: 'dirt',\n turf: 'grass',\n foliage: 'grass',\n cactus: 'grass',\n gravel: 'gravel',\n sand: 'sand',\n steel: 'metal',\n cast_iron: 'metal',\n aluminium: 'metal',\n copper: 'metal',\n water: 'water',\n glass: 'glass',\n tempered_glass: 'glass',\n fabric: 'carpet',\n foam: 'carpet',\n leather: 'carpet',\n rubber: 'carpet',\n paper: 'carpet',\n}\n\nexport const isSurfaceId = (value: unknown): value is SurfaceId => typeof value === 'string' && (SURFACE_IDS as readonly string[]).includes(value)\n\n/** The surface of a material id; a surface id passes through. */\nexport function surfaceOfMaterial(material: string | undefined, table: Readonly<Record<string, SurfaceId>> = MATERIAL_SURFACES, fallback: SurfaceId = DEFAULT_SURFACE): SurfaceId {\n if (material === undefined) return fallback\n if (isSurfaceId(material)) return material\n return table[material] ?? fallback\n}\n","/**\n * @adatechnology/game-contracts: the contracts every game module (vehicles, furniture, plants, houses, weapons) depends on, and nothing else.\n * Types plus tiny pure checkers, no runtime dependencies. The default destruction world, the renderers and the test room are optional.\n */\nexport type {\n ChainDelay,\n Crack,\n DamageStage,\n DamageType,\n DebrisKind,\n Dent,\n DestructibleSpec,\n BlastOptions,\n BlastReport,\n ConfinementOptions,\n ExplosionChain,\n FragmentHitOptions,\n ShelterOptions,\n DestructionEvent,\n DestructionEventType,\n FluidKind,\n Fragment,\n FragmentMark,\n FractureStyle,\n BallisticExtras,\n Hit,\n HitIgnition,\n HitResult,\n Hole,\n JointKind,\n JointSpec,\n JointState,\n MaterialId,\n ObjectState,\n PartShape,\n PartSpec,\n PartBreach,\n PartState,\n PartStatus,\n PartUnits,\n Quat,\n RayHit,\n Reinforcement,\n TensionRebar,\n TunedMassDamper,\n WindExposure,\n WindState,\n PileSpec,\n SoilLayer,\n SoilProfile,\n SoilState,\n StructureRole,\n SurfaceLayer,\n ToolKind,\n Vec3,\n} from './destruction'\nexport type { BusyOptions, BusySink, BusyTask } from './busy'\nexport { blastShove, DEFAULT_BLAST_SHOVE } from './blast-shove'\nexport { bodyMass, FRAGMENT_COVER, KNOCK_CHEST, KNOCK_DOWN_SPEED, KNOCKED_DOWN_ANGLE, knockOf, stepKnock } from './blast-knock'\nexport { blastBodySpeed, bodyImpulse, DEFAULT_BLAST_IMPULSE, sideOnImpulse } from './blast-impulse'\nexport type { BlastImpulseOptions } from './blast-impulse'\nexport type { Knock } from './blast-knock'\nexport type { BlastShove, BlastShoveOptions, BlastSource } from './blast-shove'\nexport { IMPACT_CONTRACT, checkDestructible, checkHit } from './impact'\nexport type { CheckOptions, DestructibleImpl, ImpactContract, SurfaceRay, SurfaceRayHit } from './impact'\nexport type { CostOptions } from './impact-cost'\nexport { MISSING_BITS } from './body'\nexport type { BodyRegion, BodySlot, SegmentKind } from './body'\nexport { checkSpec } from './spec'\nexport type { CheckSpecOptions, SpecReport } from './spec'\nexport { shotToHit, shotExtras, useToHit } from './weapons'\nexport { DEFAULT_IGNITION_RULES, fillFactor, ignitionChance, resolveIgnitionRules, sparkTargetFactor } from './ignition'\nexport type { IgnitionRules } from './ignition'\nexport type { Shot, Use } from './weapons'\nexport type { ContainerSpec, ItemUseDef, LiquidId } from './fluids'\nexport { sealBlock, sealOpener } from './seal'\nexport type { SealBlock, SealSpec, SealState } from './seal'\nexport type { HandPose, HandTargetSource, HandTargets } from './hands'\nexport { TWIST_LIFT, twistStroke } from './twist'\nexport type { TwistOptions, TwistStroke } from './twist'\nexport type { EffectHandle, EffectRequest, EffectSink, Enclosure, EnclosureBox } from './effects'\nexport type { WarmUpProbes } from './warm-up'\nexport { checkAnimation } from './animation'\nexport type { AnimationClipSpec, AnimationEventSpec, AnimationKey, AnimationPose, ItemAnimationContract } from './animation'\nexport { STAGE_EVENT, TOOL_CLIP, checkToolClips, createToolClipPlayer, leadClipEvents, sampleClip, scaleClip, toolAnimationStep } from './tool-animation'\nexport type { ToolAnimationStep, ToolAnimator, ToolClipId, ToolClipPlayer, ToolClipPlayerOptions, ToolClipSet, ToolRig } from './tool-animation'\nexport { DEFERRED_PRIORITY, DEFERRED_QUEUE_ID, FRAME_PHASES, checkDeferredQueue } from './frame'\nexport type { DeferredQueue, DeferredQueueOptions, DeferredQueueReport, FramePhase } from './frame'\nexport type { FrameOptions, AreaPlacement, GroundLayout, GroundZone, HostEvent, HostGraphics, HostTool, HostToolAttachment, ModuleArea, ModuleHost, ModuleView, ModuleItemFluid, ModuleItemSeal, ModuleScenario, PlayerState, ItemSeat, ItemSounds, TestableItem, TestableModule, Thumbnail, ToolCommand, ToolCommandResult, HostReach } from './module'\nexport { applyPatches, deepMerge, mergeById, removeIds } from './registry'\nexport type { DeepPartial } from './registry'\nimport { resetWarnOnce as resetWarnOnceForTests } from './warn'\n\nexport { warnOnce } from './warn'\n/** @deprecated Import it from `@adatechnology/game-contracts/testing`. */\nexport const resetWarnOnce = resetWarnOnceForTests\nexport { checkBench } from './bench'\nexport type {\n ActionControl,\n BenchChange,\n BenchDeclaration,\n BenchReport,\n BenchSheet,\n BooleanControl,\n ChoiceControl,\n ChoiceOption,\n ControlPatch,\n ControlValue,\n ModuleBench,\n ModuleControl,\n ModuleLayer,\n ModuleMetric,\n NumberControl,\n} from './bench'\nexport type { AudioListener, AudioSink, LoopHandle, SoundHandle, SoundRequest } from './audio'\nexport { DEFAULT_ENVIRONMENT, createEnvironmentBus } from './environment'\nexport type { EnvironmentBus, EnvironmentKey, EnvironmentState } from './environment'\nexport { checkCategorized, defineCategories, resolveEntry } from './categories'\nexport type { CategorizedOptions, CategorizedReport, CategoryDef, CategoryOptions, CategoryRegistry, ContractChecker, ContractContext } from './categories'\nexport { KIT_ORIGIN_KEY, kitOriginOf, markKitOrigin, unmarkedDrawings } from './origin'\nexport type { KitOrigin, UnmarkedDrawing } from './origin'\nexport { footprintBlocker } from './footprint'\nexport type { Footprint, FootprintObject } from './footprint'\nexport {\n BLOW_IDS,\n BODY_FOLEY_IDS,\n BODY_SOUND_IDS,\n DEFAULT_SURFACE,\n FOOTSTEP_SOUND_IDS,\n GAIT_IDS,\n HEAVY_LANDING_SPEED,\n LANDING_IDS,\n LAND_SOUND_IDS,\n MATERIAL_SURFACES,\n SURFACE_IDS,\n SWING_LEAD_SECONDS,\n footstepSoundId,\n hitSoundId,\n isSurfaceId,\n landSoundId,\n surfaceOfMaterial,\n swingSoundId,\n} from './foley'\nexport type { BlowId, BlowTarget, BodyFoleyId, BodySoundId, FootstepSoundId, GaitId, LandSoundId, LandingId, SurfaceId } from './foley'\n","import { registerItems } from './registry'\n\n/** Ground cover types the lot builder can draw. Colours come from the palette roles of the same purpose. */\nexport function registerGroundItems(): void {\n const flat = { category: 'ground_cover', w: 1, d: 1, h: 0, decor: true, mount: 'ground', flat: true } as const\n registerItems([\n { type: 'lawn', ...flat, color: { role: 'lawn' } },\n { type: 'tile_floor', ...flat, color: { role: 'exterior_floor' } },\n { type: 'concrete', ...flat, color: { role: 'exterior_floor' } },\n { type: 'deck_floor', ...flat, color: { role: 'deck_floor' } },\n { type: 'dirt', ...flat, color: { role: 'dirt' } },\n ])\n}\n","import type { SlotDef, SlotKit } from './types'\n\n/** Builders for the slot definitions of a room library. */\nexport const slotKit: SlotKit = {\n wall: (id, side, pos, size, cats, o) => Object.assign({ id, anchor: 'wall', side, pos, size, cats }, o) as SlotDef,\n corner: (id, corner, size, cats, o) => Object.assign({ id, anchor: 'corner', corner, size, cats }, o) as SlotDef,\n center: (id, fx, fz, size, cats, o) => Object.assign({ id, anchor: 'center', fx, fz, size, cats }, o) as SlotDef,\n windowSlot: (id, size, cats, o) => Object.assign({ id, anchor: 'window', size, cats }, o) as SlotDef,\n on: (id, parent, cats, o) => Object.assign({ id, anchor: 'on', on: parent, cats }, o) as SlotDef,\n inside: (id, parent, cats, o) => Object.assign({ id, anchor: 'inside', on: parent, cats }, o) as SlotDef,\n}\n","{\n \"labels\": {\n \"floor_n\": \"Floor {n}\",\n \"parking\": \"Parking\",\n \"garden\": \"Garden\",\n \"backyard\": \"Backyard\",\n \"side_left\": \"Left side\",\n \"side_right\": \"Right side\"\n },\n \"reasons\": {\n \"invalid_parent\": \"invalid parent\",\n \"invalid_side\": \"invalid side\",\n \"blocked_by_door\": \"blocked by a door\",\n \"open_wall\": \"open wall\",\n \"invalid_corner\": \"invalid corner\",\n \"no_window\": \"no window\",\n \"window_outside_room\": \"window outside the room\",\n \"larger_than_room\": \"slot larger than the room\",\n \"unknown_anchor\": \"unknown anchor\"\n },\n \"messages\": {\n \"overlap\": \"Overlap: {a} and {b}\",\n \"door_blocked\": \"Door blocked by {id}\",\n \"gate_blocked\": \"Gate blocked by {id}\",\n \"missing_required\": \"Required item missing: {room}/{slot}\",\n \"zone_violation\": \"Zone {zone}: {rule} is {actual}, limit {limit}\"\n },\n \"ui\": {\n \"title\": \"Floor plan viewer\",\n \"template\": \"Template\",\n \"seed\": \"Seed\",\n \"random_seed\": \"Random\",\n \"state\": \"State\",\n \"style\": \"Style\",\n \"zone\": \"Zone\",\n \"no_zone\": \"No zone (unrestricted)\",\n \"floor\": \"Floor\",\n \"outside\": \"Whole lot\",\n \"language\": \"Language\",\n \"width\": \"Width (m)\",\n \"depth\": \"Depth (m)\",\n \"auto_size\": \"Template default size\",\n \"options\": \"Options\",\n \"opt_floors\": \"Floors\",\n \"opt_elevator\": \"Elevator\",\n \"opt_tier\": \"Tier\",\n \"yes\": \"Yes\",\n \"no\": \"No\",\n \"default\": \"Default\",\n \"show_labels\": \"Labels\",\n \"show_items\": \"Items\",\n \"show_state\": \"State items\",\n \"show_lot\": \"Lot\",\n \"show_grid\": \"Grid\",\n \"legend\": \"Legend\",\n \"summary\": \"Summary\",\n \"rooms\": \"Rooms\",\n \"items\": \"Items\",\n \"state_items\": \"State items\",\n \"missing\": \"Missing required items\",\n \"none\": \"None\",\n \"validation\": \"Validation\",\n \"valid\": \"Valid plan\",\n \"zoning\": \"Zoning\",\n \"adjustments\": \"Adjustments\",\n \"violations\": \"Violations\",\n \"compliant\": \"Compliant with the zone\",\n \"hover\": \"Hover an item for details\",\n \"meters\": \"m\",\n \"use_label\": \"Use\",\n \"unit_floor\": \"Unit floor\",\n \"legend_wall\": \"Wall\",\n \"legend_door\": \"Door\",\n \"legend_window\": \"Window\",\n \"legend_gate\": \"Gate\",\n \"legend_path\": \"Path\",\n \"legend_item\": \"Furniture\",\n \"legend_state\": \"State item (outlined)\",\n \"rule_use\": \"Use not allowed\",\n \"rule_floors\": \"Too many floors\",\n \"rule_height\": \"Too tall\",\n \"rule_setback_front\": \"Front setback too small\",\n \"rule_setback_side\": \"Side setback too small\",\n \"rule_setback_back\": \"Back setback too small\",\n \"rule_min_lot\": \"Lot too small\",\n \"rule_min_frontage\": \"Frontage too narrow\",\n \"rule_coverage\": \"Coverage too high\",\n \"rule_far\": \"Floor area ratio too high\",\n \"rule_permeable\": \"Permeable area too small\",\n \"reason_max_floors\": \"Zone floor limit\",\n \"reason_max_height\": \"Zone height limit\",\n \"reason_setback_front\": \"Zone front setback\",\n \"reason_setback_side\": \"Zone side setback\",\n \"reason_setback_back\": \"Zone back setback\",\n \"reason_permeable_min\": \"Zone permeable area\"\n }\n}\n","{\n \"labels\": {\n \"floor_n\": \"Andar {n}\",\n \"parking\": \"Vaga\",\n \"garden\": \"Jardim\",\n \"backyard\": \"Quintal\",\n \"side_left\": \"Lateral esquerda\",\n \"side_right\": \"Lateral direita\"\n },\n \"reasons\": {\n \"invalid_parent\": \"pai inválido\",\n \"invalid_side\": \"lado inválido\",\n \"blocked_by_door\": \"bloqueado por porta\",\n \"open_wall\": \"parede aberta\",\n \"invalid_corner\": \"canto inválido\",\n \"no_window\": \"sem janela\",\n \"window_outside_room\": \"janela fora do cômodo\",\n \"larger_than_room\": \"slot maior que o cômodo\",\n \"unknown_anchor\": \"âncora desconhecida\"\n },\n \"messages\": {\n \"overlap\": \"Sobreposição: {a} e {b}\",\n \"door_blocked\": \"Porta bloqueada por {id}\",\n \"gate_blocked\": \"Portão bloqueado por {id}\",\n \"missing_required\": \"Item obrigatório ausente: {room}/{slot}\",\n \"zone_violation\": \"Zona {zone}: {rule} é {actual}, limite {limit}\"\n },\n \"ui\": {\n \"title\": \"Visualizador de plantas\",\n \"template\": \"Modelo\",\n \"seed\": \"Semente\",\n \"random_seed\": \"Aleatória\",\n \"state\": \"Estado\",\n \"style\": \"Estilo\",\n \"zone\": \"Zona\",\n \"no_zone\": \"Sem zona (livre)\",\n \"floor\": \"Andar\",\n \"outside\": \"Lote inteiro\",\n \"language\": \"Idioma\",\n \"width\": \"Largura (m)\",\n \"depth\": \"Profundidade (m)\",\n \"auto_size\": \"Tamanho padrão do modelo\",\n \"options\": \"Opções\",\n \"opt_floors\": \"Andares\",\n \"opt_elevator\": \"Elevador\",\n \"opt_tier\": \"Padrão\",\n \"yes\": \"Sim\",\n \"no\": \"Não\",\n \"default\": \"Padrão\",\n \"show_labels\": \"Rótulos\",\n \"show_items\": \"Móveis\",\n \"show_state\": \"Itens de estado\",\n \"show_lot\": \"Lote\",\n \"show_grid\": \"Grade\",\n \"legend\": \"Legenda\",\n \"summary\": \"Resumo\",\n \"rooms\": \"Cômodos\",\n \"items\": \"Móveis\",\n \"state_items\": \"Itens de estado\",\n \"missing\": \"Itens obrigatórios ausentes\",\n \"none\": \"Nenhum\",\n \"validation\": \"Validação\",\n \"valid\": \"Planta válida\",\n \"zoning\": \"Zoneamento\",\n \"adjustments\": \"Ajustes\",\n \"violations\": \"Violações\",\n \"compliant\": \"Em conformidade com a zona\",\n \"hover\": \"Passe o mouse sobre um item para ver detalhes\",\n \"meters\": \"m\",\n \"use_label\": \"Uso\",\n \"unit_floor\": \"Andar da unidade\",\n \"legend_wall\": \"Parede\",\n \"legend_door\": \"Porta\",\n \"legend_window\": \"Janela\",\n \"legend_gate\": \"Portão\",\n \"legend_path\": \"Caminho\",\n \"legend_item\": \"Móvel\",\n \"legend_state\": \"Item de estado (contorno)\",\n \"rule_use\": \"Uso não permitido\",\n \"rule_floors\": \"Andares demais\",\n \"rule_height\": \"Altura excedida\",\n \"rule_setback_front\": \"Recuo frontal insuficiente\",\n \"rule_setback_side\": \"Recuo lateral insuficiente\",\n \"rule_setback_back\": \"Recuo de fundos insuficiente\",\n \"rule_min_lot\": \"Lote pequeno demais\",\n \"rule_min_frontage\": \"Testada estreita demais\",\n \"rule_coverage\": \"Taxa de ocupação excedida\",\n \"rule_far\": \"Coeficiente de aproveitamento excedido\",\n \"rule_permeable\": \"Área permeável insuficiente\",\n \"reason_max_floors\": \"Limite de andares da zona\",\n \"reason_max_height\": \"Limite de altura da zona\",\n \"reason_setback_front\": \"Recuo frontal da zona\",\n \"reason_setback_side\": \"Recuo lateral da zona\",\n \"reason_setback_back\": \"Recuo de fundos da zona\",\n \"reason_permeable_min\": \"Área permeável da zona\"\n }\n}\n","import { applyPatches, removeIds } from '@adatechnology/game-contracts'\nimport type { DeepPartial } from '@adatechnology/game-contracts'\n\nimport { CAR_CLEARANCE, DOOR_CLEARANCE, DOOR_EDGE_CLEARANCE, OVERHEAD_TOP, PLAYER_RADIUS, WALL_THICKNESS, WINDOW_EDGE_CLEARANCE } from './constants'\nimport { findsAnswer, findsFor } from './extensions'\nimport { generate, limitsOf, listTemplates, slots, validate } from './generate'\nimport { overlaps, openingZones } from './geometry'\nimport { registerGroundItems } from './ground-items'\nimport { listLocales, registerLocale, translate } from './locale'\nimport { HIGH_SATURATION, MIN_FABRIC_FLOOR_CONTRAST, MIN_WALL_FLOOR_CONTRAST, hexString, intToHsl, lstar, palette } from './palette'\nimport { blocksWindow, windowZone } from './queries'\nimport {\n createRegistries,\n getDefaultRegistries,\n listStates,\n registerDecorProfile,\n registerFindsProvider,\n registerGroundOverlay,\n registerItem,\n registerItems,\n registerLibrary,\n registerLibraryAlias,\n registerPass,\n registerPaletteStyle,\n registerResultExtension,\n registerRoomColors,\n registerSeedKeys,\n registerState,\n registerStyle,\n registerTemplate,\n registerViewerLayer,\n registerWallTop,\n setStateDistribution,\n withRegistries,\n} from './registry'\nimport type { Registries } from './registry'\nimport { createRng, hashString, mulberry32 } from './rng'\nimport { slotKit } from './slot-kit'\nimport type { FurnitureDef, TemplateDef } from './types'\nimport { checkLot, defineZone, getZone, listZones, registerPermeableGround } from './zoning'\n\nimport enLocale from './locales/en.json'\nimport ptBrLocale from './locales/pt-BR.json'\n\nexport const version = '0.1.0'\n\n/** Registers `packs` and applies `patch` / `remove` over the catalogs, by id. Items are keyed by `type`, templates by `id`. */\nexport type CreateFloorplanOptions = {\n /** Content packs, applied in order: a function `(engine) => void` or an object with `register(engine)`. */\n readonly packs?: readonly FloorplanPack[]\n readonly patch?: { readonly items?: Readonly<Record<string, DeepPartial<FurnitureDef>>>; readonly templates?: Readonly<Record<string, DeepPartial<TemplateDef>>> }\n readonly remove?: { readonly items?: readonly string[]; readonly templates?: readonly string[] }\n}\n\nexport type FloorplanPack = ((engine: FloorplanEngine) => void) | { readonly register: (engine: FloorplanEngine) => void }\n\ntype Keyed = { id: string }\n\nfunction editCatalog<TDef extends object>(catalog: Record<string, TDef>, patch: Readonly<Record<string, DeepPartial<TDef>>> | undefined, remove: readonly string[] | undefined): void {\n if (!patch && !remove) return\n const entries = new Map<string, TDef & Keyed>(Object.entries(catalog).map(([key, definition]) => [key, { ...definition, id: key }]))\n applyPatches(entries, patch as Readonly<Record<string, DeepPartial<TDef & Keyed>>> | undefined)\n removeIds(entries, remove)\n for (const key of Object.keys(catalog)) {\n const edited = entries.get(key)\n if (!edited) delete catalog[key]\n else if (patch && key in patch) {\n const hadId = 'id' in catalog[key]!\n const next: TDef & Partial<Keyed> = { ...edited }\n if (!hadId) delete next.id\n catalog[key] = next\n }\n }\n}\n\nfunction buildEngine(scope: Registries) {\n const scoped = <TFunction extends (...args: never[]) => unknown>(fn: TFunction): TFunction =>\n ((...args: never[]) => withRegistries(scope, () => fn(...args))) as TFunction\n return {\n version,\n generate: scoped(generate),\n slots: scoped(slots),\n validate: scoped(validate),\n palette: scoped(palette),\n limitsOf: scoped(limitsOf),\n listTemplates: scoped(listTemplates),\n listStates: scoped(listStates),\n // content registration\n registerItem: scoped(registerItem),\n registerItems: scoped(registerItems),\n registerLibrary: scoped(registerLibrary),\n registerLibraryAlias: scoped(registerLibraryAlias),\n registerTemplate: scoped(registerTemplate),\n registerStyle: scoped(registerStyle),\n registerPaletteStyle: scoped(registerPaletteStyle),\n registerRoomColors: scoped(registerRoomColors),\n registerDecorProfile: scoped(registerDecorProfile),\n registerPass: scoped(registerPass),\n registerGroundOverlay: scoped(registerGroundOverlay),\n registerWallTop: scoped(registerWallTop),\n registerSeedKeys: scoped(registerSeedKeys),\n registerState: scoped(registerState),\n setStateDistribution: scoped(setStateDistribution),\n registerLocale: scoped(registerLocale),\n registerResultExtension: scoped(registerResultExtension),\n registerFindsProvider: scoped(registerFindsProvider),\n findsFor: scoped(findsFor),\n findsAnswer: scoped(findsAnswer),\n registerViewerLayer: scoped(registerViewerLayer),\n viewerLayers: scope.VIEWER_LAYERS,\n blocksWindow: scoped(blocksWindow),\n // zoning\n defineZone: scoped(defineZone),\n getZone: scoped(getZone),\n listZones: scoped(listZones),\n checkLot: scoped(checkLot),\n registerPermeableGround: scoped(registerPermeableGround),\n // kits and data\n slotKit,\n translate: scoped(translate),\n listLocales: scoped(listLocales),\n templates: scope.TEMPLATES,\n catalog: scope.CATALOG,\n libraries: scope.LIBRARIES,\n styles: scope.STYLES,\n paletteStyles: scope.PALETTE_STYLES,\n createRng,\n mulberry32,\n hashString,\n overlaps,\n windowZone,\n openingZones,\n color: { lstar, hex: hexString, hsl: intToHsl, HIGH_SATURATION, MIN_WALL_FLOOR_CONTRAST, MIN_FABRIC_FLOOR_CONTRAST },\n constants: { WALL_THICKNESS, DOOR_CLEARANCE, PLAYER_RADIUS, DOOR_EDGE_CLEARANCE, WINDOW_EDGE_CLEARANCE, OVERHEAD_TOP, CAR_CLEARANCE },\n }\n}\n\nexport type FloorplanEngine = ReturnType<typeof buildEngine>\n\nfunction seedBase(scope: Registries): void {\n withRegistries(scope, () => {\n registerGroundItems()\n registerPermeableGround('lawn', 'dirt')\n registerLocale('en', enLocale)\n registerLocale('pt-BR', ptBrLocale)\n })\n}\n\n/** An engine of its own: registries, zones and locales are not shared with any other engine on the page. */\nexport function createFloorplan(options: CreateFloorplanOptions = {}): FloorplanEngine {\n const scope = createRegistries()\n seedBase(scope)\n const instance = buildEngine(scope)\n for (const pack of options.packs ?? []) (typeof pack === 'function' ? pack : pack.register)(instance)\n editCatalog(scope.CATALOG, options.patch?.items, options.remove?.items)\n editCatalog(scope.TEMPLATES, options.patch?.templates, options.remove?.templates)\n return instance\n}\n\nlet defaultEngine: FloorplanEngine | undefined\n\n/** The engine the global `engine` stands for, created on first use. Content packs of the old `register(engine)` calls fill this one. */\nexport function defaultFloorplan(): FloorplanEngine {\n if (defaultEngine) return defaultEngine\n seedBase(getDefaultRegistries())\n defaultEngine = buildEngine(getDefaultRegistries())\n return defaultEngine\n}\n","import type { RandomSource } from './types'\n\n/** The page's own seeded generator (mulberry32), so a silhouette drawn from the same seed has the same windows and colours. */\nexport function createSilhouetteRandom(seed: number): RandomSource {\n let state = seed\n return () => {\n state |= 0\n state = (state + 0x6d2b79f5) | 0\n let t = Math.imul(state ^ (state >>> 15), 1 | state)\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n","import type { RandomSource, Silhouette, SilhouettePart, SilhouetteWindow } from './types'\n\nconst ROOT = -1\nconst MAX_BOX_RADIUS = 0.15\nconst BOX_RADIUS_RATIO = 0.22\nconst PLAIN_BOX_RADIUS = 0.012\n\ntype Options = { parent?: number; ry?: number; rz?: number; emissive?: boolean }\n\n/** Rounded-box radius the team page gives a box; below 1.2 cm it is a plain box. */\nexport function boxRadius(width: number, height: number, depth: number): number {\n const radius = Math.min(Math.min(width, height, depth) * BOX_RADIUS_RATIO, MAX_BOX_RADIUS)\n return radius < PLAIN_BOX_RADIUS ? 0 : radius\n}\n\n/** Collects the parts of one silhouette; the generators call it the way the team page calls its own helpers. */\nexport function createSilhouetteBuilder(random: RandomSource) {\n const parts: SilhouettePart[] = []\n const windows: SilhouetteWindow[] = []\n const pick = <T>(list: readonly T[]): T => list[Math.floor(random() * list.length)] as T\n const group = (x: number, y: number, z: number, ry = 0, parent = ROOT): number => parts.push({ shape: 'group', parent, x, y, z, ry }) - 1\n const box = (x: number, y: number, z: number, width: number, height: number, depth: number, color: number, o: Options = {}): void => {\n parts.push({ shape: 'box', parent: o.parent ?? ROOT, x, y: y + height / 2, z, width, height, depth, color, emissive: o.emissive ?? false, ry: o.ry ?? 0, rz: o.rz ?? 0, radius: boxRadius(width, height, depth) })\n }\n const prism = (x: number, y: number, z: number, width: number, height: number, depth: number, color: number, parent = ROOT): void => {\n parts.push({ shape: 'prism', parent, x, y, z, width, height, depth, color, ry: 0 })\n }\n const cylinder = (x: number, y: number, z: number, radiusTop: number, radiusBottom: number, height: number, color: number, parent = ROOT, segments = 14): void => {\n parts.push({ shape: 'cylinder', parent, x, y: y + height / 2, z, radiusTop, radiusBottom, height, color, segments })\n }\n const line = (points: [number, number, number][], color: number, parent = ROOT): void => {\n parts.push({ shape: 'line', parent, points, color })\n }\n const sign = (text: string, x: number, y: number, z: number, width: number, height: number, ry: number, colors: { background: string; foreground: string }, parent = ROOT): void => {\n parts.push({ shape: 'sign', parent, x, y, z, width, height, ry, text, ...colors })\n }\n const fence = (x0: number, z0: number, x1: number, z1: number, height: number, color: number, parent = ROOT): void => {\n const length = Math.hypot(x1 - x0, z1 - z0)\n const count = Math.ceil(length / 3)\n for (let index = 0; index <= count; index++) {\n const t = index / count\n cylinder(x0 + (x1 - x0) * t, 0, z0 + (z1 - z0) * t, 0.05, 0.05, height, color, parent, 5)\n }\n for (const level of [height * 0.35, height * 0.65, height * 0.98]) line([[x0, level, z0], [x1, level, z1]], 0x8a8c8e, parent)\n }\n const finish = (footprint: Silhouette['footprint']): Silhouette => ({ parts, windows, footprint })\n return { random, pick, group, box, prism, cylinder, line, sign, fence, windows, finish }\n}\n\nexport type SilhouetteBuilder = ReturnType<typeof createSilhouetteBuilder>\n","import { createSilhouetteBuilder } from './builder'\nimport { createSilhouetteRandom } from './random'\nimport type { RandomSource, Silhouette } from './types'\n\nconst STOREY_HEIGHT = 3\nconst SHOP_AWNING_HEIGHT = 4.5\nconst WINDOW_COLUMN_WIDTH = 2.6\nconst SHOP_SIGNS = ['FARMÁCIA', 'MAGAZINE', 'LOTÉRICA', 'PADARIA', 'ÓTICA', 'CALÇADOS', 'BAR'] as const\nconst SIGN_COLORS = ['#ffd27a', '#e8dfcf', '#c4483b'] as const\nconst DEFAULT_LIT_CHANCE = 0.07\n\nexport type CityBuildingParams = {\n x: number\n z: number\n width: number\n depth: number\n height: number\n color: number\n /** Chance of a ground-floor shop on both long faces; omitted means none. */\n shopChance?: number\n /** Chance that a window is lit. */\n litChance?: number\n random?: RandomSource\n seed?: number\n}\n\n/** City building: block, roof slab, maybe a vent, maybe a shop front, and window instances on the four faces. */\nexport function createCityBuilding(p: CityBuildingParams): Silhouette {\n const random = p.random ?? createSilhouetteRandom(p.seed ?? 7)\n const b = createSilhouetteBuilder(random)\n const { x, z, width: w, depth: d, height: h } = p\n b.box(x, 0, z, w, h, d, p.color)\n b.box(x, h, z, w + 0.3, 0.35, d + 0.3, 0x2a2a2c)\n if (random() < 0.4) b.cylinder(x + (random() - 0.5) * (w - 3), h + 0.35, z + (random() - 0.5) * (d - 3), 0.8, 0.8, 1.4, 0x4b4540)\n const hasShop = p.shopChance !== undefined && p.shopChance > 0 && random() < p.shopChance\n if (hasShop) {\n for (const face of [1, -1]) {\n const zFace = z + face * (d / 2)\n b.box(x, SHOP_AWNING_HEIGHT, zFace + face * 0.8, w, 0.2, 1.6, 0x2a2a2c)\n b.box(x, 0, zFace + face * 0.03, w * 0.6, 3.5, 0.05, 0x4a4c4e)\n const text = b.pick(SHOP_SIGNS)\n b.sign(text, x, 5.3, zFace + face * 0.12, Math.min(w * 0.7, 8), 1, face > 0 ? 0 : Math.PI, { background: '#1a1a1c', foreground: b.pick(SIGN_COLORS) })\n }\n }\n addWindows(b, p, hasShop ? SHOP_AWNING_HEIGHT : 0)\n return b.finish({ x, z, width: w, depth: d, height: h + 0.35 })\n}\n\nfunction addWindows(b: ReturnType<typeof createSilhouetteBuilder>, p: CityBuildingParams, base: number): void {\n const { x, z, width: w, depth: d, height: h } = p\n const floors = Math.max(1, Math.floor((h - 1) / STOREY_HEIGHT))\n const faces: [number, number, number, number][] = [[0, d / 2 + 0.03, w, 0], [0, -d / 2 - 0.03, w, Math.PI], [w / 2 + 0.03, 0, d, Math.PI / 2], [-w / 2 - 0.03, 0, d, -Math.PI / 2]]\n for (const [ox, oz, faceWidth, ry] of faces) {\n const columns = Math.max(1, Math.floor(faceWidth / WINDOW_COLUMN_WIDTH))\n for (let floor = 0; floor < floors; floor++) {\n const y = base + 1.8 + floor * STOREY_HEIGHT\n for (let column = 0; column < columns; column++) {\n const u = (column - (columns - 1) / 2) * WINDOW_COLUMN_WIDTH\n b.windows.push({ x: ox ? x + ox : x + u, y, z: ox ? z + u : z + oz, ry, width: 1.2, height: 1.4, isLit: b.random() < (p.litChance || DEFAULT_LIT_CHANCE) })\n }\n }\n }\n}\n","import { createSilhouetteBuilder } from './builder'\nimport { createSilhouetteRandom } from './random'\nimport type { RandomSource, Silhouette } from './types'\n\nconst LIT_WINDOW = 0xffb45e\nconst DARK_WINDOW = 0x10151b\nconst DEFAULT_ROOF = 0x5a3a2a\n\ntype Seeded = { random?: RandomSource; seed?: number }\n\nconst randomOf = (o: Seeded): RandomSource => o.random ?? createSilhouetteRandom(o.seed ?? 7)\n\n/** Window colour: a lit one glows (emissive), a dark one is a plain dark pane. */\nconst pane = (isLit: boolean) => ({ color: isLit ? LIT_WINDOW : DARK_WINDOW, emissive: isLit })\n\nexport type TwoStoreyParams = Seeded & { x: number; z: number; width: number; depth: number; color: number; roofColor?: number; ry?: number }\n\n/** Two-storey house with a balcony slab, pitched roof and four windows. */\nexport function createTwoStoreyHouse(p: TwoStoreyParams): Silhouette {\n const b = createSilhouetteBuilder(randomOf(p))\n const { width: w, depth: d } = p\n const g = b.group(p.x, 0, p.z, p.ry)\n b.box(0, 0, 0, w, 6, d, p.color, { parent: g })\n b.prism(0, 6, 0, w + 0.4, 1.4, d + 0.4, p.roofColor ?? DEFAULT_ROOF, g)\n b.box(0, 3.1, d / 2 + 0.5, w * 0.6, 0.15, 1, 0x6a6a66, { parent: g })\n for (const floor of [0, 1]) {\n for (const side of [-1, 1]) {\n const { color, emissive } = pane(b.random() < 0.12)\n b.box(side * w * 0.26, 1.1 + floor * 3, d / 2 + 0.03, 1.1, 1.2, 0.04, color, { parent: g, emissive })\n }\n }\n b.box(0, 0, d / 2 + 0.02, 1, 2.1, 0.05, 0x2a1d14, { parent: g })\n return b.finish({ x: p.x, z: p.z, width: w, depth: d, height: 7.4 })\n}\n\nexport type SlabHouseParams = Seeded & { x: number; z: number; width: number; depth: number; floors: number; color: number }\n\n/** Reinforced-concrete slab house of one to three floors, with water tank, side stair and sometimes rebar starters. */\nexport function createSlabHouse(p: SlabHouseParams): Silhouette {\n const b = createSilhouetteBuilder(randomOf(p))\n const { width: w, depth: d, floors } = p\n const g = b.group(p.x, 0, p.z, 0)\n for (let floor = 0; floor < floors; floor++) {\n const isTop = floor === floors - 1\n b.box(0, floor * 2.9, 0, w, 2.9, d, isTop && b.random() < 0.5 ? 0x9a6a50 : p.color, { parent: g })\n const { color, emissive } = pane(b.random() < 0.1)\n b.box(0, floor * 2.9 + 1.1, d / 2 + 0.03, 1, 1, 0.04, color, { parent: g, emissive })\n }\n b.cylinder(w * 0.25, floors * 2.9, -d * 0.2, 0.55, 0.55, 0.9, 0x2a5aa0, g, 10)\n for (let level = 0; level < floors; level++) b.box(w / 2 + 0.4, level * 2.9, 0, 0.8, 0.18, 1.2, 0x7a7a74, { parent: g })\n if (b.random() < 0.6) for (let index = 0; index < 4; index++) b.box(-w * 0.3 + index * 0.4, floors * 2.9, 0, 0.02, 1, 0.02, 0x8a8a8a, { parent: g })\n return b.finish({ x: p.x, z: p.z, width: w, depth: d, height: floors * 2.9 + 1 })\n}\n\nexport type ColonialParams = Seeded & { x: number; z: number; width: number; color: number; hasDoor: boolean }\n\n/** Colonial terrace house: parapet, roof behind it and a row of doors or windows. */\nexport function createColonialHouse(p: ColonialParams): Silhouette {\n const b = createSilhouetteBuilder(randomOf(p))\n const { width: w } = p\n const g = b.group(p.x, 0, p.z, 0)\n b.box(0, 0, 0, w, 4.2, 10, p.color, { parent: g })\n b.box(0, 4.2, 4.6, w, 0.8, 0.25, p.color, { parent: g })\n b.prism(0, 4.2, -0.4, w, 1.4, 9.6, 0x7a4a32, g)\n const count = Math.max(1, Math.floor(w / 2.2))\n for (let index = 0; index < count; index++) {\n const u = (index - (count - 1) / 2) * 2.2\n const isDoor = index === 0 && p.hasDoor\n const lit = isDoor ? false : b.random() < 0.15\n const color = isDoor ? 0x3a2416 : lit ? LIT_WINDOW : 0x2a3a4a\n b.box(u, 1.0, 5.02, 0.9, 2.0, 0.05, color, { parent: g, emissive: lit })\n }\n return b.finish({ x: p.x, z: p.z, width: w, depth: 10, height: 6 })\n}\n\nexport type ChaletParams = Seeded & { x: number; z: number; color?: number; ry?: number }\n\n/** Wooden chalet on a stone base with a steep roof and a chimney. */\nexport function createChalet(p: ChaletParams): Silhouette {\n const b = createSilhouetteBuilder(randomOf(p))\n const g = b.group(p.x, 0, p.z, p.ry)\n b.box(0, 0, 0, 7, 0.8, 9, 0x5a5650, { parent: g })\n b.box(0, 0.8, 0, 7, 4.2, 9, p.color ?? 0x6b4a30, { parent: g })\n b.prism(0, 5, 0, 7.6, 4, 9.6, 0x2c2a28, g)\n b.box(2.2, 5, -1, 0.8, 4.2, 0.8, 0x5a5650, { parent: g })\n const { color, emissive } = pane(b.random() < 0.3)\n b.box(0, 1.6, 4.52, 1.3, 1.3, 0.04, color, { parent: g, emissive })\n b.box(0, 6.2, 4.6, 1, 1, 0.04, DARK_WINDOW, { parent: g })\n return b.finish({ x: p.x, z: p.z, width: 7.6, depth: 9.6, height: 9 })\n}\n\nexport type CompanyHouseParams = Seeded & { x: number; z: number; color?: number }\n\n/** Company-town house with a low front fence. */\nexport function createCompanyHouse(p: CompanyHouseParams): Silhouette {\n const b = createSilhouetteBuilder(randomOf(p))\n const g = b.group(p.x, 0, p.z, 0)\n b.box(0, 0, 0, 6, 3, 9, p.color ?? 0xd8d0c0, { parent: g })\n b.prism(0, 3, 0, 6.4, 1.6, 9.4, 0x8a4a32, g)\n b.box(0, 0, 4.52, 0.9, 2.1, 0.05, 0x3a2a1c, { parent: g })\n b.box(1.8, 1.1, 4.52, 1, 1, 0.04, DARK_WINDOW, { parent: g })\n b.fence(-3.2, 6.5, 3.2, 6.5, 0.9, 0xe0d8c8, g)\n return b.finish({ x: p.x, z: p.z, width: 6.4, depth: 13, height: 4.6 })\n}\n\nexport type StiltHouseParams = Seeded & { x: number; z: number; color?: number }\n\n/** House on stilts with a ramp-like entry platform. */\nexport function createStiltHouse(p: StiltHouseParams): Silhouette {\n const b = createSilhouetteBuilder(randomOf(p))\n const g = b.group(p.x, 0, p.z, 0)\n for (const a of [-2, 2]) for (const c of [-3, 3]) b.cylinder(a, -1.5, c, 0.12, 0.12, 3.1, 0x3a2a1c, g, 6)\n b.box(0, 1.5, 0, 5, 0.2, 7, 0x5a4630, { parent: g })\n b.box(0, 1.7, 0, 4.6, 2.6, 6.4, p.color ?? 0x6a5a46, { parent: g })\n b.prism(0, 4.3, 0, 5.2, 1.1, 7, 0x7a7a78, g)\n b.box(0, 1.5, 5, 1.2, 0.15, 4, 0x5a4630, { parent: g })\n return b.finish({ x: p.x, z: p.z, width: 5.2, depth: 9, height: 5.4 })\n}\n\nexport type FarmhouseParams = Seeded & { x: number; z: number }\n\n/** Farm house with a long covered porch on six posts. */\nexport function createFarmhouse(p: FarmhouseParams): Silhouette {\n const b = createSilhouetteBuilder(randomOf(p))\n const g = b.group(p.x, 0, p.z, 0)\n b.box(0, 0, 0, 15, 3.2, 11, 0xd8cfb8, { parent: g })\n b.prism(0, 3.2, 0, 17, 2.2, 13, 0x8a4a32, g)\n b.box(0, 0, 6.8, 15, 0.25, 2.6, 0x6a5a46, { parent: g })\n for (let index = 0; index < 6; index++) b.cylinder(-7 + index * 2.8, 0, 7.8, 0.1, 0.1, 3.2, 0x5a4630, g, 6)\n b.box(-3, 1.0, 5.52, 1.2, 1.2, 0.04, LIT_WINDOW, { parent: g, emissive: true })\n return b.finish({ x: p.x, z: p.z, width: 17, depth: 13, height: 5.4 })\n}\n\nexport type DetachedHouseParams = Seeded & { x: number; z: number; width: number; depth: number; color: number; roofColor?: number; ry?: number; isBoarded?: boolean }\n\n/** One-storey detached house; boarded windows get two crossed planks each. */\nexport function createDetachedHouse(p: DetachedHouseParams): Silhouette {\n const b = createSilhouetteBuilder(randomOf(p))\n const { width: w, depth: d } = p\n const g = b.group(p.x, 0, p.z, p.ry)\n b.box(0, 0, 0, w, 3, d, p.color, { parent: g })\n b.prism(0, 3, 0, w + 0.5, 1.6, d + 0.5, p.roofColor ?? DEFAULT_ROOF, g)\n b.box(0, 0, d / 2 + 0.02, 1, 2.1, 0.05, 0x2a1d14, { parent: g })\n for (const side of [-1, 1]) {\n const { color, emissive } = pane(b.random() < 0.15)\n b.box(side * w * 0.28, 1.1, d / 2 + 0.03, 1.1, 1.1, 0.04, color, { parent: g, emissive })\n if (p.isBoarded || b.random() < 0.3) for (const k of [-1, 1]) b.box(side * w * 0.28, 1.5 + k * 0.25, d / 2 + 0.08, 1.3, 0.14, 0.04, 0x6b4a2a, { parent: g, rz: k * 0.15 })\n }\n return b.finish({ x: p.x, z: p.z, width: w + 0.5, depth: d + 0.5, height: 4.6 })\n}\n"],"mappings":"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","names":["slots","r","cl","m","rimRect","process","ceiling","current","limit","palette","rule","found"]}