@adatechnology/game-floorplan 0.2.2 → 0.3.1

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.
@@ -30,11 +30,13 @@ var GameFloorplan = (() => {
30
30
  createCompanyHouse: () => createCompanyHouse,
31
31
  createDetachedHouse: () => createDetachedHouse,
32
32
  createFarmhouse: () => createFarmhouse,
33
+ createFloorplan: () => createFloorplan,
33
34
  createRng: () => createRng,
34
35
  createSilhouetteRandom: () => createSilhouetteRandom,
35
36
  createSlabHouse: () => createSlabHouse,
36
37
  createStiltHouse: () => createStiltHouse,
37
38
  createTwoStoreyHouse: () => createTwoStoreyHouse,
39
+ defaultFloorplan: () => defaultFloorplan,
38
40
  defineZone: () => defineZone,
39
41
  engine: () => engine,
40
42
  findsAnswer: () => findsAnswer,
@@ -79,137 +81,123 @@ var GameFloorplan = (() => {
79
81
  windowZone: () => windowZone
80
82
  });
81
83
 
82
- // src/constants.ts
83
- var WALL_THICKNESS = 0.15;
84
- var MARGIN = WALL_THICKNESS / 2;
85
- var EPS = 1e-6;
86
- var TOL = 1e-3;
87
- var DOOR_CLEARANCE = 0.9;
88
- var PLAYER_RADIUS = 0.24;
89
- var DOOR_EDGE_CLEARANCE = 0.12;
90
- var WINDOW_EDGE_CLEARANCE = 0.3;
91
- var OVERHEAD_TOP = 2.15;
92
- var WINDOWLESS_ROOM_TYPES = /* @__PURE__ */ new Set([
93
- "stockroom",
94
- "kitchen",
95
- "laundry",
96
- "bathroom",
97
- "void",
98
- "elevator",
99
- "stairs",
100
- "pantry",
101
- "closet",
102
- "corridor",
103
- "hall",
104
- "balcony",
105
- "terrace",
106
- "garage",
107
- "storage",
108
- "porch",
109
- "tent",
110
- "outhouse"
111
- ]);
112
- var CAR_CLEARANCE = { driver: 0.8, side: 0.6, end: 0.6 };
113
-
114
84
  // src/registry.ts
115
- var CATALOG = {};
116
- var LIBRARIES = {};
117
- var LIBRARY_ALIAS = {};
118
- var TEMPLATES = {};
119
- var STYLES = {};
120
- var STYLE_ALIAS = {};
121
- var PALETTE_STYLES = {};
122
- var ROOM_COLORS = [];
123
- var PASSES = [];
124
- var DECOR_PROFILES = {};
125
- var GROUND_OVERLAYS = [];
126
- var STATE_PLUGINS = { normal: { apply: () => [] } };
127
- var WALL_TOP_HEIGHTS = { none: 0 };
128
- var SEED_KEYS = { rooms: {}, items: {} };
129
- var stateDistribution = { weights: null, seedKey: "state" };
85
+ var createRegistries = () => ({
86
+ CATALOG: {},
87
+ LIBRARIES: {},
88
+ LIBRARY_ALIAS: {},
89
+ TEMPLATES: {},
90
+ STYLES: {},
91
+ STYLE_ALIAS: {},
92
+ PALETTE_STYLES: {},
93
+ ROOM_COLORS: [],
94
+ PASSES: [],
95
+ DECOR_PROFILES: {},
96
+ GROUND_OVERLAYS: [],
97
+ STATE_PLUGINS: { normal: { apply: () => [] } },
98
+ WALL_TOP_HEIGHTS: { none: 0 },
99
+ SEED_KEYS: { rooms: {}, items: {} },
100
+ stateDistribution: { weights: null, seedKey: "state" },
101
+ RESULT_EXTENSIONS: [],
102
+ FINDS_PROVIDERS: [],
103
+ VIEWER_LAYERS: [],
104
+ LOCALES: {},
105
+ ZONES: {},
106
+ PERMEABLE_GROUNDS: /* @__PURE__ */ new Set()
107
+ });
108
+ var defaultRegistries;
109
+ var activeRegistries;
110
+ var getDefaultRegistries = () => defaultRegistries ?? (defaultRegistries = createRegistries());
111
+ var registries = () => activeRegistries ?? getDefaultRegistries();
112
+ function withRegistries(scope, run) {
113
+ const previous = activeRegistries;
114
+ activeRegistries = scope;
115
+ try {
116
+ return run();
117
+ } finally {
118
+ activeRegistries = previous;
119
+ }
120
+ }
130
121
  function registerItem(def) {
131
122
  const h = def.h;
132
123
  const item = Object.assign({ front: "+z", window: h <= 0.95, low: h <= 0.5, flat: false, deck: false, rim: 0 }, def);
133
- CATALOG[def.type] = item;
124
+ registries().CATALOG[def.type] = item;
134
125
  return item;
135
126
  }
136
127
  function registerItems(list) {
137
128
  for (const d of list) registerItem(d);
138
129
  }
139
130
  function registerLibrary(id, library) {
140
- LIBRARIES[id] = library;
131
+ registries().LIBRARIES[id] = library;
141
132
  }
142
133
  function registerLibraryAlias(alias, id) {
143
- LIBRARY_ALIAS[alias] = id;
134
+ registries().LIBRARY_ALIAS[alias] = id;
144
135
  }
145
136
  function registerTemplate(t) {
146
- TEMPLATES[t.id] = t;
137
+ registries().TEMPLATES[t.id] = t;
147
138
  return t;
148
139
  }
149
140
  function registerStyle(style) {
150
- STYLES[style.id] = style;
151
- for (const a of style.aliases || []) STYLE_ALIAS[a] = style.id;
141
+ registries().STYLES[style.id] = style;
142
+ for (const a of style.aliases || []) registries().STYLE_ALIAS[a] = style.id;
152
143
  }
153
144
  function registerPaletteStyle(id, def) {
154
- PALETTE_STYLES[id] = def;
145
+ registries().PALETTE_STYLES[id] = def;
155
146
  }
156
147
  function registerRoomColors(list) {
157
148
  for (const d of list) {
158
- const i = ROOM_COLORS.findIndex((x) => x.type === d.type);
159
- if (i >= 0) ROOM_COLORS.splice(i, 1);
160
- ROOM_COLORS.push(d);
149
+ const i = registries().ROOM_COLORS.findIndex((x) => x.type === d.type);
150
+ if (i >= 0) registries().ROOM_COLORS.splice(i, 1);
151
+ registries().ROOM_COLORS.push(d);
161
152
  }
162
- ROOM_COLORS.sort((a, b) => a.order - b.order);
153
+ registries().ROOM_COLORS.sort((a, b) => a.order - b.order);
163
154
  }
164
155
  function registerDecorProfile(styleId, profile) {
165
- DECOR_PROFILES[styleId] = profile;
156
+ registries().DECOR_PROFILES[styleId] = profile;
166
157
  }
167
158
  function registerPass(name, run) {
168
- const i = PASSES.findIndex((p) => p.name === name);
169
- if (i >= 0) PASSES[i] = { name, run };
170
- else PASSES.push({ name, run });
159
+ const i = registries().PASSES.findIndex((p) => p.name === name);
160
+ if (i >= 0) registries().PASSES[i] = { name, run };
161
+ else registries().PASSES.push({ name, run });
171
162
  }
172
163
  function registerGroundOverlay(rule) {
173
- GROUND_OVERLAYS.push(rule);
164
+ registries().GROUND_OVERLAYS.push(rule);
174
165
  }
175
166
  function registerWallTop(id, height) {
176
- WALL_TOP_HEIGHTS[id] = height;
167
+ registries().WALL_TOP_HEIGHTS[id] = height;
177
168
  }
178
169
  function registerSeedKeys(keys) {
179
- Object.assign(SEED_KEYS.rooms, keys.rooms);
180
- Object.assign(SEED_KEYS.items, keys.items);
170
+ Object.assign(registries().SEED_KEYS.rooms, keys.rooms);
171
+ Object.assign(registries().SEED_KEYS.items, keys.items);
181
172
  }
182
173
  function registerState(name, plugin) {
183
- STATE_PLUGINS[name] = plugin;
174
+ registries().STATE_PLUGINS[name] = plugin;
184
175
  }
185
176
  function setStateDistribution(weights, seedKey = "state") {
186
- stateDistribution.weights = weights;
187
- stateDistribution.seedKey = seedKey;
177
+ registries().stateDistribution.weights = weights;
178
+ registries().stateDistribution.seedKey = seedKey;
188
179
  }
189
- var listStates = () => Object.keys(STATE_PLUGINS);
180
+ var listStates = () => Object.keys(registries().STATE_PLUGINS);
190
181
  function resolveStyleId(id) {
191
182
  const s = id ?? "";
192
- return STYLE_ALIAS[s] ?? s;
183
+ return registries().STYLE_ALIAS[s] ?? s;
193
184
  }
194
185
  function styleOf(id) {
195
- return STYLES[id] || STYLES.budget || Object.values(STYLES)[0];
186
+ return registries().STYLES[id] || registries().STYLES.budget || Object.values(registries().STYLES)[0];
196
187
  }
197
- var RESULT_EXTENSIONS = [];
198
- var FINDS_PROVIDERS = [];
199
188
  function registerResultExtension(name, run, options = {}) {
200
189
  const entry = { name, run, after: options.after || [], seedKey: options.seedKey ?? name };
201
- const i = RESULT_EXTENSIONS.findIndex((x) => x.name === name);
202
- if (i >= 0) RESULT_EXTENSIONS[i] = entry;
203
- else RESULT_EXTENSIONS.push(entry);
190
+ const i = registries().RESULT_EXTENSIONS.findIndex((x) => x.name === name);
191
+ if (i >= 0) registries().RESULT_EXTENSIONS[i] = entry;
192
+ else registries().RESULT_EXTENSIONS.push(entry);
204
193
  }
205
194
  function registerFindsProvider(provider) {
206
- FINDS_PROVIDERS.push(provider);
195
+ registries().FINDS_PROVIDERS.push(provider);
207
196
  }
208
- var VIEWER_LAYERS = [];
209
197
  function registerViewerLayer(layer) {
210
- const i = VIEWER_LAYERS.findIndex((x) => x.id === layer.id);
211
- if (i >= 0) VIEWER_LAYERS[i] = layer;
212
- else VIEWER_LAYERS.push(layer);
198
+ const i = registries().VIEWER_LAYERS.findIndex((x) => x.id === layer.id);
199
+ if (i >= 0) registries().VIEWER_LAYERS[i] = layer;
200
+ else registries().VIEWER_LAYERS.push(layer);
213
201
  }
214
202
 
215
203
  // src/rng.ts
@@ -289,7 +277,7 @@ var GameFloorplan = (() => {
289
277
  return ordered;
290
278
  }
291
279
  function runResultExtensions(plan, result, seed, options) {
292
- for (const extension of orderOf(RESULT_EXTENSIONS)) {
280
+ for (const extension of orderOf(registries().RESULT_EXTENSIONS)) {
293
281
  result[extension.name] = extension.run({ plan, result, seed, rng: createRng(seed, extension.seedKey), options });
294
282
  }
295
283
  }
@@ -300,13 +288,45 @@ var GameFloorplan = (() => {
300
288
  return answerOf(query);
301
289
  }
302
290
  function answerOf(query) {
303
- for (const provider of FINDS_PROVIDERS) {
291
+ for (const provider of registries().FINDS_PROVIDERS) {
304
292
  const stacks = provider.findsFor(query);
305
293
  if (stacks !== null) return stacks;
306
294
  }
307
295
  return null;
308
296
  }
309
297
 
298
+ // src/constants.ts
299
+ var WALL_THICKNESS = 0.15;
300
+ var MARGIN = WALL_THICKNESS / 2;
301
+ var EPS = 1e-6;
302
+ var TOL = 1e-3;
303
+ var DOOR_CLEARANCE = 0.9;
304
+ var PLAYER_RADIUS = 0.24;
305
+ var DOOR_EDGE_CLEARANCE = 0.12;
306
+ var WINDOW_EDGE_CLEARANCE = 0.3;
307
+ var OVERHEAD_TOP = 2.15;
308
+ var WINDOWLESS_ROOM_TYPES = /* @__PURE__ */ new Set([
309
+ "stockroom",
310
+ "kitchen",
311
+ "laundry",
312
+ "bathroom",
313
+ "void",
314
+ "elevator",
315
+ "stairs",
316
+ "pantry",
317
+ "closet",
318
+ "corridor",
319
+ "hall",
320
+ "balcony",
321
+ "terrace",
322
+ "garage",
323
+ "storage",
324
+ "porch",
325
+ "tent",
326
+ "outhouse"
327
+ ]);
328
+ var CAR_CLEARANCE = { driver: 0.8, side: 0.6, end: 0.6 };
329
+
310
330
  // src/geometry.ts
311
331
  var r2 = (x) => Math.round(x * 100) / 100;
312
332
  var clamp = (x, a, b) => Math.max(a, Math.min(b, x));
@@ -523,6 +543,7 @@ var GameFloorplan = (() => {
523
543
  var MAX_CANDIDATES = 80;
524
544
  function carCandidates(slot, item, car) {
525
545
  const front = [slot.frontU, slot.frontV];
546
+ if (!slot._cell) throw new Error("Slot without a cell: " + slot.id);
526
547
  const zone = slot._cell.R;
527
548
  const alongV = Math.abs(front[1]) === 1;
528
549
  const [extentU, extentV] = extent([item.w, item.d], front);
@@ -741,13 +762,14 @@ var GameFloorplan = (() => {
741
762
  const out = [];
742
763
  for (const [cat, weight] of Object.entries(cats)) {
743
764
  const exact = cat[0] === "=";
744
- const its = Object.values(CATALOG).filter((i) => !i.decor && (exact ? i.type === cat.slice(1) : !i.exactOnly && (i.category === cat || i.type === cat)));
765
+ const its = Object.values(registries().CATALOG).filter((i) => !i.decor && (exact ? i.type === cat.slice(1) : !i.exactOnly && (i.category === cat || i.type === cat)));
745
766
  for (const it of its) out.push({ it, weight: weight / its.length });
746
767
  }
747
768
  return out;
748
769
  }
749
770
  function itemRect(slot, it, shift) {
750
771
  const c = slot._cell;
772
+ if (!c) throw new Error("Slot without a cell: " + slot.id);
751
773
  const f = c.f;
752
774
  const [extentU, extentV] = extent([it.w, it.d], f);
753
775
  const R = c.R;
@@ -832,7 +854,7 @@ var GameFloorplan = (() => {
832
854
  low: it.low,
833
855
  aabb: r.map(r2),
834
856
  _r: r,
835
- _seedId: SEED_KEYS.items[id] ?? id
857
+ _seedId: registries().SEED_KEYS.items[id] ?? id
836
858
  };
837
859
  if (it.overhead) m.overhead = !overheadOff;
838
860
  if (it.category === "car") {
@@ -852,7 +874,7 @@ var GameFloorplan = (() => {
852
874
  if (!parent) return null;
853
875
  for (const { it } of cands) {
854
876
  if (it.w > parent.w + EPS || it.d > parent.d + EPS) continue;
855
- const f = [parent.frontU, parent.frontV];
877
+ const f = [parent.frontU ?? 0, parent.frontV ?? 1];
856
878
  const r = parent.aabb;
857
879
  const [extentU, extentV] = extent([it.w, it.d], f);
858
880
  const cu = (r[0] + r[2]) / 2 - f[0] * (parent.d / 2 - it.d / 2);
@@ -886,7 +908,7 @@ var GameFloorplan = (() => {
886
908
  if (!car && !relax && s.clearance > 0 && !it.low) {
887
909
  cl2 = clearRect(r3, f, s.clearance);
888
910
  if (!insideUnion(cl2, inners)) continue;
889
- if (items.some((m2) => !m2.low && !m2.flat && !m2.on && overlaps(cl2, m2._r))) continue;
911
+ if (items.some((m2) => !m2.low && !m2.flat && !m2.on && overlaps(cl2, m2._r ?? m2.aabb))) continue;
890
912
  }
891
913
  if (!it.low && reserves.some((q) => overlaps(r3, q))) continue;
892
914
  let rimRect2 = null;
@@ -909,7 +931,7 @@ var GameFloorplan = (() => {
909
931
  }
910
932
  return null;
911
933
  };
912
- const process = (u) => {
934
+ const process2 = (u) => {
913
935
  const pr = u.members[0].chance;
914
936
  const x = rng();
915
937
  const arr = u.members.slice();
@@ -945,7 +967,7 @@ var GameFloorplan = (() => {
945
967
  let i = pending.findIndex(ready);
946
968
  if (i < 0) i = 0;
947
969
  const u = pending.splice(i, 1)[0];
948
- process(u);
970
+ process2(u);
949
971
  for (const m of u.members) done.add(m.id);
950
972
  }
951
973
  return { items, missing };
@@ -983,9 +1005,9 @@ var GameFloorplan = (() => {
983
1005
  clearRect,
984
1006
  pickWeighted,
985
1007
  createRng,
986
- roomSeedKey: (room) => room.seedKey ?? SEED_KEYS.rooms[room.id] ?? room.id,
1008
+ roomSeedKey: (room) => room.seedKey ?? registries().SEED_KEYS.rooms[room.id] ?? room.id,
987
1009
  shuffle,
988
- facingRotation: (f, type) => rotationFor(f, CATALOG[type].front),
1010
+ facingRotation: (f, type) => rotationFor(f, registries().CATALOG[type].front),
989
1011
  cutIntervals,
990
1012
  blocksWindow
991
1013
  };
@@ -993,7 +1015,7 @@ var GameFloorplan = (() => {
993
1015
  const added = [];
994
1016
  const counters = {};
995
1017
  const make = (room, type, r, f, o) => {
996
- const it = CATALOG[type];
1018
+ const it = registries().CATALOG[type];
997
1019
  const n = counters[room.id + type] = (counters[room.id + type] || 0) + 1;
998
1020
  return Object.assign(
999
1021
  {
@@ -1039,9 +1061,9 @@ var GameFloorplan = (() => {
1039
1061
  const gridOf = (c) => gridCache[c.id] || (gridCache[c.id] = createGrid(plan, c, ignored));
1040
1062
  function placeOnFloor(room, type, rng2, optsIn) {
1041
1063
  const opts = Object.assign({}, optsIn || {});
1042
- const it0 = CATALOG[type];
1064
+ const it0 = registries().CATALOG[type];
1043
1065
  if (it0.flat) opts.flat = true;
1044
- const it = CATALOG[type];
1066
+ const it = registries().CATALOG[type];
1045
1067
  const inners = usableParts(room, 0);
1046
1068
  const solidList = solidsOfRoom(room);
1047
1069
  const zones = zonesOfFloor(plan, room.floor);
@@ -1074,7 +1096,7 @@ var GameFloorplan = (() => {
1074
1096
  if (!(opts.without && opts.without(r))) return r;
1075
1097
  continue;
1076
1098
  }
1077
- if (occupied.some((m) => !m.low && !m.flat && !m.on && !m.decor && m.clearance > 0 && overlaps(r, clearRect(m._r, [m.frontU, m.frontV], m.clearance)))) continue;
1099
+ if (occupied.some((m) => !m.low && !m.flat && !m.on && !m.decor && (m.clearance ?? 0) > 0 && overlaps(r, clearRect(m._r, [m.frontU ?? 0, m.frontV ?? 1], m.clearance ?? 0)))) continue;
1078
1100
  if (opts.without && opts.without(r)) continue;
1079
1101
  if (!reachable(opts.railing || gridOf(room), solidList.concat([r]), room.outdoor ? 0.16 : plan.playerRadius)) continue;
1080
1102
  return r;
@@ -1120,7 +1142,7 @@ var GameFloorplan = (() => {
1120
1142
  z.parts.forEach((p, i) => groundPiece(z, z.ground, p, 0, i));
1121
1143
  let k = 0;
1122
1144
  const clip = (r) => z.parts.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])]).filter((q) => q[2] - q[0] > 0.3 && q[3] - q[1] > 0.3).sort((a, b) => areaOf(b) - areaOf(a))[0];
1123
- for (const rule of GROUND_OVERLAYS) {
1145
+ for (const rule of registries().GROUND_OVERLAYS) {
1124
1146
  const triggers = items.filter((m) => m.room === z.id && m.category === rule.category);
1125
1147
  if (rule.merge) {
1126
1148
  if (triggers.length && z.ground !== rule.unlessGround) {
@@ -1140,19 +1162,20 @@ var GameFloorplan = (() => {
1140
1162
  function runPostProcess(plan, items, seed) {
1141
1163
  const ctx = createPlacementContext(plan, items);
1142
1164
  const rng = createRng(seed, STREAM.decor);
1143
- for (const pass of PASSES) pass.run({ plan, items, seed, rng, ctx, kit: placementKit, catalog: CATALOG, profiles: DECOR_PROFILES });
1165
+ for (const pass of registries().PASSES) pass.run({ plan, items, seed, rng, ctx, kit: placementKit, catalog: registries().CATALOG, profiles: registries().DECOR_PROFILES });
1144
1166
  groundCover(plan, items, ctx);
1145
1167
  return ctx;
1146
1168
  }
1147
1169
 
1148
1170
  // src/locale.ts
1149
- var locales = {};
1150
1171
  function registerLocale(code, table) {
1172
+ const { LOCALES: locales } = registries();
1151
1173
  const cur = locales[code] = locales[code] || {};
1152
1174
  for (const ns of Object.keys(table)) cur[ns] = Object.assign(cur[ns] || {}, table[ns]);
1153
1175
  }
1154
- var listLocales = () => Object.keys(locales);
1176
+ var listLocales = () => Object.keys(registries().LOCALES);
1155
1177
  function translate(ns, key, locale = "en", vars) {
1178
+ const { LOCALES: locales } = registries();
1156
1179
  const raw = locales[locale]?.[ns]?.[key] ?? locales.en?.[ns]?.[key] ?? key;
1157
1180
  return vars ? raw.replace(/\{(\w+)\}/g, (m, k) => k in vars ? String(vars[k]) : m) : raw;
1158
1181
  }
@@ -1281,22 +1304,20 @@ var GameFloorplan = (() => {
1281
1304
  }
1282
1305
 
1283
1306
  // src/zoning.ts
1284
- var ZONES = {};
1285
- var PERMEABLE_GROUNDS = /* @__PURE__ */ new Set();
1286
1307
  function defineZone(zone) {
1287
1308
  if (!zone || !zone.id) throw new Error("defineZone: id is required");
1288
- ZONES[zone.id] = zone;
1309
+ registries().ZONES[zone.id] = zone;
1289
1310
  return zone;
1290
1311
  }
1291
- var getZone = (id) => ZONES[id];
1292
- var listZones = () => Object.values(ZONES);
1312
+ var getZone = (id) => registries().ZONES[id];
1313
+ var listZones = () => Object.values(registries().ZONES);
1293
1314
  function registerPermeableGround(...types) {
1294
- for (const t of types) PERMEABLE_GROUNDS.add(t);
1315
+ for (const t of types) registries().PERMEABLE_GROUNDS.add(t);
1295
1316
  }
1296
1317
  function resolveZone(z) {
1297
1318
  if (!z) return null;
1298
1319
  if (typeof z === "string") {
1299
- const found = ZONES[z];
1320
+ const found = registries().ZONES[z];
1300
1321
  if (!found) throw new Error("Unknown zone: " + z);
1301
1322
  return found;
1302
1323
  }
@@ -1342,7 +1363,7 @@ var GameFloorplan = (() => {
1342
1363
  const far = m.built / area;
1343
1364
  if (far > zone.maxFar + 1e-9) out.push({ rule: "far", actual: r2(far), limit: zone.maxFar });
1344
1365
  let permeable = 0;
1345
- for (const z of lot.zones) if (PERMEABLE_GROUNDS.has(z.ground)) for (const p of z.parts) permeable += (p[2] - p[0]) * (p[3] - p[1]);
1366
+ 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]);
1346
1367
  const permeability = permeable / area;
1347
1368
  if (permeability < zone.permeableMin - 1e-9) out.push({ rule: "permeable", actual: r2(permeability), limit: zone.permeableMin });
1348
1369
  return out;
@@ -1380,17 +1401,17 @@ var GameFloorplan = (() => {
1380
1401
  }
1381
1402
  var ADJUSTABLE_ZONES = /* @__PURE__ */ new Set(["garden", "backyard", "side_yard"]);
1382
1403
  function enforcePermeability(lot, zones, zone, adjustments) {
1383
- const target = [...PERMEABLE_GROUNDS][0];
1404
+ const target = [...registries().PERMEABLE_GROUNDS][0];
1384
1405
  if (!target) return;
1385
1406
  const [u0, v0, u1, v1] = lot.rect;
1386
1407
  const area = (u1 - u0) * (v1 - v0);
1387
1408
  const areaOfZone = (z) => z.parts.reduce((s, p) => s + (p[2] - p[0]) * (p[3] - p[1]), 0);
1388
- let permeable = zones.filter((z) => PERMEABLE_GROUNDS.has(z.ground)).reduce((s, z) => s + areaOfZone(z), 0);
1409
+ let permeable = zones.filter((z) => z.ground != null && registries().PERMEABLE_GROUNDS.has(z.ground)).reduce((s, z) => s + areaOfZone(z), 0);
1389
1410
  if (permeable / area >= zone.permeableMin) return;
1390
- const candidates = zones.filter((z) => ADJUSTABLE_ZONES.has(z.type) && !PERMEABLE_GROUNDS.has(z.ground)).sort((a, b) => areaOfZone(b) - areaOfZone(a));
1411
+ 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));
1391
1412
  for (const z of candidates) {
1392
1413
  if (permeable / area >= zone.permeableMin) break;
1393
- adjustments.push({ field: "ground:" + z.id, from: z.ground, to: target, reason: "permeable_min" });
1414
+ adjustments.push({ field: "ground:" + z.id, from: z.ground ?? "", to: target, reason: "permeable_min" });
1394
1415
  z.ground = target;
1395
1416
  permeable += areaOfZone(z);
1396
1417
  }
@@ -1620,9 +1641,9 @@ var GameFloorplan = (() => {
1620
1641
  paths: [],
1621
1642
  pool: !!cfg.pool
1622
1643
  };
1623
- const ZONES2 = [];
1644
+ const ZONES = [];
1624
1645
  const libs = Object.assign({ garden: "garden", backyard: "backyard", parking: "parking", sideYard: "side_yard" }, cfg.libraries || {});
1625
- const addZone = (id, type, label, parts, library) => ZONES2.push(Object.assign(normalizeRoom({ id, type, label, rect: parts[0], parts: parts.slice(1), library, outdoor: true }, -1), { floor: -1, outdoor: true }));
1646
+ const addZone = (id, type, label, parts, library) => ZONES.push(Object.assign(normalizeRoom({ id, type, label, rect: parts[0], parts: parts.slice(1), library, outdoor: true }, -1), { floor: -1, outdoor: true }));
1626
1647
  if (setback > 0) {
1627
1648
  let parts = [[-marginL, -setback, w + marginR, 0]];
1628
1649
  if (cfg.parking) {
@@ -1659,9 +1680,9 @@ var GameFloorplan = (() => {
1659
1680
  height: type === "pedestrian" ? style.height : Math.min(style.height, 2.2),
1660
1681
  side,
1661
1682
  to: toTarget || null,
1662
- material: "iron"
1683
+ material: "iron",
1684
+ zones: openingZones(u, v, "u", width, openingDepth(width, type === "pedestrian" ? width : 0))
1663
1685
  };
1664
- g.zones = openingZones(u, v, "u", width, openingDepth(width, type === "pedestrian" ? width : 0));
1665
1686
  gates.push(g);
1666
1687
  return g;
1667
1688
  };
@@ -1702,14 +1723,14 @@ var GameFloorplan = (() => {
1702
1723
  }
1703
1724
  }
1704
1725
  if (tpl.paths) paths.push(...tpl.paths(plan, { gates, setback, marginLeft: marginL, marginRight: marginR, backyard: backDepth, w, d }));
1705
- else addExteriorDoorPaths(plan, { gates, paths, zones: ZONES2, setback, marginLeft: marginL, marginRight: marginR, backyard: backDepth, w, target: cfg.doorTarget });
1726
+ else addExteriorDoorPaths(plan, { gates, paths, zones: ZONES, setback, marginLeft: marginL, marginRight: marginR, backyard: backDepth, w, target: cfg.doorTarget });
1706
1727
  plan.paths = paths;
1707
1728
  lot.paths = paths;
1708
1729
  const boundary = (rule) => {
1709
1730
  const type = pickWeighted(rLot, rule.type);
1710
1731
  const top = type === "railing" ? "none" : pickWeighted(rLot, rule.top);
1711
1732
  const wallHeight = type === "railing" ? 1.2 : type === "fence" ? style.fenceHeight ?? 2 : style.height;
1712
- return { type, material: type === "wall" ? "block" : type === "fence" ? "wire_mesh" : "iron", height: wallHeight, top, totalHeight: r2(wallHeight + WALL_TOP_HEIGHTS[top]), thickness: WALL_THICKNESS };
1733
+ 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 };
1713
1734
  };
1714
1735
  const A = { front: boundary(style.front), left: boundary(style.sideYard), right: boundary(style.sideYard), back: boundary(style.back) };
1715
1736
  const seg = (side, u0, v0, u1, v1) => {
@@ -1742,10 +1763,10 @@ var GameFloorplan = (() => {
1742
1763
  else if (backDepth > 0) seg("left", 0, d, 0, d + backDepth);
1743
1764
  if (marginR > 0.5) seg("right", w + marginR, vi, w + marginR, d + backDepth);
1744
1765
  else if (backDepth > 0) seg("right", w, d, w, d + backDepth);
1745
- for (const z of ZONES2) z.ground = (cfg.grounds || {})[z.id] || (cfg.grounds || {})[z.type] || pickWeighted(rLot, style.grounds[z.type] || { concrete: 1 });
1746
- if (bc.zone) enforcePermeability(lot, ZONES2, bc.zone, bc.adjustments || []);
1747
- plan.zones = ZONES2;
1748
- lot.zones = ZONES2;
1766
+ for (const z of ZONES) z.ground = (cfg.grounds || {})[z.id] || (cfg.grounds || {})[z.type] || pickWeighted(rLot, style.grounds[z.type] || { concrete: 1 });
1767
+ if (bc.zone) enforcePermeability(lot, ZONES, bc.zone, bc.adjustments || []);
1768
+ plan.zones = ZONES;
1769
+ lot.zones = ZONES;
1749
1770
  plan.lot = lot;
1750
1771
  }
1751
1772
 
@@ -1795,8 +1816,8 @@ var GameFloorplan = (() => {
1795
1816
  function palette(o) {
1796
1817
  const opt = o || {};
1797
1818
  let style = resolveStyleId(opt.style || "budget");
1798
- if (!PALETTE_STYLES[style]) style = PALETTE_STYLES.mid ? "mid" : Object.keys(PALETTE_STYLES)[0];
1799
- const def = PALETTE_STYLES[style];
1819
+ if (!registries().PALETTE_STYLES[style]) style = registries().PALETTE_STYLES.mid ? "mid" : Object.keys(registries().PALETTE_STYLES)[0];
1820
+ const def = registries().PALETTE_STYLES[style];
1800
1821
  const state = opt.state || "normal";
1801
1822
  const seed = opt.seed == null ? 1 : opt.seed;
1802
1823
  const rng = createRng(seed, STREAM.palettePrefix + (def.seedKey ?? style));
@@ -1814,14 +1835,14 @@ var GameFloorplan = (() => {
1814
1835
  const { wallMode, sMax } = early;
1815
1836
  const R = Object.assign({}, early.roles);
1816
1837
  const ctx = Object.assign({ style, sMax, wallMode, generalFloor: early.generalFloor }, draw);
1817
- for (const c of ROOM_COLORS) {
1838
+ for (const c of registries().ROOM_COLORS) {
1818
1839
  const [wh, wl] = c.wall(ctx);
1819
1840
  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));
1820
1841
  const pi = c.floor || early.generalFloor;
1821
1842
  R["floor_" + c.type] = hsl(pi[0], Math.min(pi[1], wallMode ? 0.18 : 0.3), jit(pi[2], 0.04));
1822
1843
  }
1823
1844
  Object.assign(R, def.late(draw, early));
1824
- STATE_PLUGINS[state]?.adjustPalette?.(R);
1845
+ registries().STATE_PLUGINS[state]?.adjustPalette?.(R);
1825
1846
  const adjust = (color, ref, min, preferredDir) => {
1826
1847
  for (let i = 0; i < 60; i++) {
1827
1848
  if (Math.abs(lstar(hslToInt(color.h, color.s, color.l)) - lstar(hslToInt(ref.h, ref.s, ref.l))) >= min) return;
@@ -1831,7 +1852,7 @@ var GameFloorplan = (() => {
1831
1852
  color.l = clamp(color.l + dir * 0.015, 0.04, 0.96);
1832
1853
  }
1833
1854
  };
1834
- const types = ROOM_COLORS.map((c) => c.type);
1855
+ const types = registries().ROOM_COLORS.map((c) => c.type);
1835
1856
  for (const c of types) {
1836
1857
  const w = R["wall_" + c];
1837
1858
  const p = R["floor_" + c];
@@ -1885,8 +1906,8 @@ var GameFloorplan = (() => {
1885
1906
  var WINDOW_SIDE = { front: "front", back: "back", left: "left", right: "right" };
1886
1907
  function slotDefsOf(plan, room) {
1887
1908
  const name = room.library || room.type;
1888
- const key = LIBRARY_ALIAS[name] || name;
1889
- const library = room.slots ? room.slots : LIBRARIES[key];
1909
+ const key = registries().LIBRARY_ALIAS[name] || name;
1910
+ const library = room.slots ? room.slots : registries().LIBRARIES[key];
1890
1911
  if (!library) return [];
1891
1912
  const R = inner(room.parts[0]);
1892
1913
  let defs = typeof library === "function" ? library({ w: R[2] - R[0], d: R[3] - R[1] }) : library.slice();
@@ -1948,7 +1969,7 @@ var GameFloorplan = (() => {
1948
1969
  };
1949
1970
  const invalid = (m) => 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 });
1950
1971
  if (def.anchor === "on" || def.anchor === "inside") {
1951
- const parent = byId[def.parent];
1972
+ const parent = def.parent ? byId[def.parent] : void 0;
1952
1973
  if (!parent || !parent.valid) return invalid("invalid_parent");
1953
1974
  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 });
1954
1975
  }
@@ -1989,9 +2010,10 @@ var GameFloorplan = (() => {
1989
2010
  const windowList = windowsOfRoom(plan, room);
1990
2011
  win = windowList[def.n];
1991
2012
  if (!win) return invalid("no_window");
2013
+ const found2 = win;
1992
2014
  side = room.outdoor ? SIDE_OPPOSITE[win.side] : WINDOW_SIDE[win.side];
1993
2015
  const cand = room.parts.map(inner).find(
1994
- (r) => (win.axis === "u" ? win.u >= r[0] - TOL && win.u <= r[2] + TOL : win.v >= r[1] - TOL && win.v <= r[3] + TOL) && (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))
2016
+ (r) => (found2.axis === "u" ? found2.u >= r[0] - TOL && found2.u <= r[2] + TOL : found2.v >= r[1] - TOL && found2.v <= r[3] + TOL) && (side === "left" && eq(r[0], found2.pos + MARGIN) || side === "right" && eq(r[2], found2.pos - MARGIN) || side === "front" && eq(r[1], found2.pos + MARGIN) || side === "back" && eq(r[3], found2.pos - MARGIN))
1995
2017
  );
1996
2018
  if (!cand) return invalid("window_outside_room");
1997
2019
  R = cand;
@@ -2076,8 +2098,8 @@ var GameFloorplan = (() => {
2076
2098
  // src/generate.ts
2077
2099
  function templateOf(t) {
2078
2100
  if (typeof t === "string") {
2079
- if (!TEMPLATES[t]) throw new Error("Unknown template: " + t);
2080
- return TEMPLATES[t];
2101
+ if (!registries().TEMPLATES[t]) throw new Error("Unknown template: " + t);
2102
+ return registries().TEMPLATES[t];
2081
2103
  }
2082
2104
  return t;
2083
2105
  }
@@ -2095,10 +2117,10 @@ var GameFloorplan = (() => {
2095
2117
  return resolveSlots(plan).map(cleanSlot).map((s) => s.reason ? Object.assign(s, { reason: translate("reasons", s.reason, locale) }) : s);
2096
2118
  }
2097
2119
  function pickState(requested, seed) {
2098
- if (requested && STATE_PLUGINS[requested]) return requested;
2099
- const dist = stateDistribution.weights;
2120
+ if (requested && registries().STATE_PLUGINS[requested]) return requested;
2121
+ const dist = registries().stateDistribution.weights;
2100
2122
  if (!dist) return "normal";
2101
- const x = createRng(seed, stateDistribution.seedKey)();
2123
+ const x = createRng(seed, registries().stateDistribution.seedKey)();
2102
2124
  let acc = 0;
2103
2125
  const keys = Object.keys(dist);
2104
2126
  for (const k of keys) {
@@ -2108,13 +2130,13 @@ var GameFloorplan = (() => {
2108
2130
  return keys[keys.length - 1];
2109
2131
  }
2110
2132
  function colorOf(m, seed) {
2111
- const spec = m.colorSpec || CATALOG[m.type]?.color || { role: "wood" };
2133
+ const spec = m.colorSpec || registries().CATALOG[m.type]?.color || { role: "wood" };
2112
2134
  if ("role" in spec) return spec.role;
2113
2135
  if ("hex" in spec) return spec.hex;
2114
2136
  return spec.pick[hashString(seed + "|" + (m._seedId ?? m.id)) % spec.pick.length];
2115
2137
  }
2116
2138
  function applyState(plan, items, ctx, seed, state) {
2117
- const plugin = STATE_PLUGINS[state];
2139
+ const plugin = registries().STATE_PLUGINS[state];
2118
2140
  if (!plugin || state === "normal") return [];
2119
2141
  const c = {
2120
2142
  plan,
@@ -2124,8 +2146,8 @@ var GameFloorplan = (() => {
2124
2146
  rng: createRng(seed, plugin.seedKey ?? "state:" + state),
2125
2147
  ctx,
2126
2148
  kit: placementKit,
2127
- catalog: CATALOG,
2128
- wallTopHeights: WALL_TOP_HEIGHTS
2149
+ catalog: registries().CATALOG,
2150
+ wallTopHeights: registries().WALL_TOP_HEIGHTS
2129
2151
  };
2130
2152
  return plugin.apply(c);
2131
2153
  }
@@ -2145,7 +2167,7 @@ var GameFloorplan = (() => {
2145
2167
  const missing = [];
2146
2168
  for (const room of plan.rooms.concat(plan.zones)) {
2147
2169
  const sl = all.filter((s) => s.room === room.id && s.floor === room.floor);
2148
- const r = fillRoom(plan, room, sl, createRng(seed, STREAM.roomPrefix + (room.seedKey ?? SEED_KEYS.rooms[room.id] ?? room.id)));
2170
+ const r = fillRoom(plan, room, sl, createRng(seed, STREAM.roomPrefix + (room.seedKey ?? registries().SEED_KEYS.rooms[room.id] ?? room.id)));
2149
2171
  items.push(...r.items);
2150
2172
  missing.push(...r.missing);
2151
2173
  }
@@ -2185,7 +2207,7 @@ var GameFloorplan = (() => {
2185
2207
  if (m.category) out.color = colorOf(m, seed);
2186
2208
  return out;
2187
2209
  });
2188
- const result = {
2210
+ const base = {
2189
2211
  template: tpl.id,
2190
2212
  name: translate("templates", tpl.id, locale),
2191
2213
  use: useOf(tpl),
@@ -2222,8 +2244,8 @@ var GameFloorplan = (() => {
2222
2244
  building: tpl.building ? tpl.building(plan.w, plan.d, op) : null,
2223
2245
  missing
2224
2246
  };
2225
- if (tpl.singleFloor) result.floorNumber = op.floor || 3;
2226
- result.partyWalls = tpl.partyWalls || [];
2247
+ if (tpl.singleFloor) base.floorNumber = op.floor || 3;
2248
+ const result = Object.assign(base, { partyWalls: tpl.partyWalls || [] });
2227
2249
  if (plan.config) result.config = plan.config;
2228
2250
  runResultExtensions(plan, result, seed, op);
2229
2251
  if (zone) {
@@ -2258,7 +2280,7 @@ var GameFloorplan = (() => {
2258
2280
  return { limits: tpl.limitsFn ? tpl.limitsFn(op) : tpl.limits, defaults: tpl.defaultsFn ? tpl.defaultsFn(op) : tpl.defaults };
2259
2281
  }
2260
2282
  function listTemplates(locale = "en") {
2261
- return Object.values(TEMPLATES).map((t) => {
2283
+ return Object.values(registries().TEMPLATES).map((t) => {
2262
2284
  const a = floorsOf(t, {});
2263
2285
  return {
2264
2286
  id: t.id,
@@ -2275,6 +2297,101 @@ var GameFloorplan = (() => {
2275
2297
  });
2276
2298
  }
2277
2299
 
2300
+ // ../game-contracts/dist/index.js
2301
+ var DEFAULT_COST_ALLOCATION_BYTES = 1024 * 1024;
2302
+ var DEFERRED_QUEUE_ID = {
2303
+ DESTRUCTION_EVENTS: "destruction.events",
2304
+ BREACH_PAINT: "floorplan.breach-paint",
2305
+ AUDIO_VOICES: "audio.voices",
2306
+ VEHICLE_CREASE: "vehicles.crease"
2307
+ };
2308
+ var DEFERRED_PRIORITY = {
2309
+ [DEFERRED_QUEUE_ID.DESTRUCTION_EVENTS]: { priority: 300, phase: "present" },
2310
+ [DEFERRED_QUEUE_ID.BREACH_PAINT]: { priority: 250, phase: "present" },
2311
+ [DEFERRED_QUEUE_ID.AUDIO_VOICES]: { priority: 200, phase: "idle", reserveMs: 1 },
2312
+ [DEFERRED_QUEUE_ID.VEHICLE_CREASE]: { priority: 100, phase: "idle" }
2313
+ };
2314
+ var WARNED_KEY = /* @__PURE__ */ Symbol.for("@adatechnology/game-contracts.warned");
2315
+ var warnedKeys = () => {
2316
+ const holder = globalThis;
2317
+ return holder[WARNED_KEY] ?? (holder[WARNED_KEY] = /* @__PURE__ */ new Set());
2318
+ };
2319
+ var isProduction = () => {
2320
+ try {
2321
+ return process.env.NODE_ENV === "production";
2322
+ } catch {
2323
+ return false;
2324
+ }
2325
+ };
2326
+ var isQuiet = () => globalThis.__GAME_KIT_QUIET__ === true;
2327
+ var warnOnce = (key, message) => {
2328
+ if (isQuiet() || isProduction()) return;
2329
+ const seen = warnedKeys();
2330
+ if (seen.has(key)) return;
2331
+ seen.add(key);
2332
+ console.warn(`[game-kit] ${message}`);
2333
+ };
2334
+ var UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
2335
+ var isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
2336
+ var deepMerge = (base, patch) => {
2337
+ if (!patch) return base;
2338
+ const result = { ...base };
2339
+ for (const [key, value] of Object.entries(patch)) {
2340
+ if (value === void 0 || UNSAFE_KEYS.has(key)) continue;
2341
+ const current = result[key];
2342
+ result[key] = isPlainObject(current) && isPlainObject(value) ? deepMerge(current, value) : value;
2343
+ }
2344
+ return result;
2345
+ };
2346
+ var applyPatches = (entries, patches) => {
2347
+ for (const [id, patch] of Object.entries(patches ?? {})) {
2348
+ const entry = entries.get(id);
2349
+ if (entry) entries.set(id, deepMerge(entry, patch));
2350
+ else warnOnce(`registry.patch.${id}`, `patch for "${id}" ignored: no entry has that id`);
2351
+ }
2352
+ };
2353
+ var removeIds = (entries, ids) => {
2354
+ for (const id of ids ?? []) {
2355
+ if (!entries.delete(id)) warnOnce(`registry.remove.${id}`, `remove of "${id}" ignored: no entry has that id`);
2356
+ }
2357
+ };
2358
+ var SURFACE_IDS = ["concrete", "asphalt", "wood", "tile", "dirt", "grass", "gravel", "sand", "metal", "water", "glass", "carpet"];
2359
+ var GAIT_IDS = ["walk", "run"];
2360
+ var LANDING_IDS = ["light", "heavy"];
2361
+ var BODY_SOUND_IDS = [
2362
+ "jump",
2363
+ "cloth_rustle",
2364
+ "body_fall",
2365
+ "fall_damage",
2366
+ "player_hurt",
2367
+ "player_breath_run",
2368
+ "player_death",
2369
+ "bite",
2370
+ "grab",
2371
+ "punch_swing",
2372
+ "punch_hit_body",
2373
+ "punch_hit_face",
2374
+ "punch_hit_object",
2375
+ "kick_swing",
2376
+ "kick_hit",
2377
+ "kick_hit_object",
2378
+ "shove_two_hands",
2379
+ "knife_swing",
2380
+ "knife_stab",
2381
+ "knife_slash",
2382
+ "knife_hit_object",
2383
+ "blunt_swing",
2384
+ "blunt_hit",
2385
+ "blunt_hit_object",
2386
+ "axe_swing",
2387
+ "axe_chop",
2388
+ "axe_hit_object"
2389
+ ];
2390
+ var footstepSoundId = (surface, gait) => `footstep_${surface}_${gait}`;
2391
+ var FOOTSTEP_SOUND_IDS = SURFACE_IDS.flatMap((surface) => GAIT_IDS.map((gait) => footstepSoundId(surface, gait)));
2392
+ var LAND_SOUND_IDS = SURFACE_IDS.flatMap((surface) => LANDING_IDS.map((landing) => `land_${surface}_${landing}`));
2393
+ var BODY_FOLEY_IDS = [...FOOTSTEP_SOUND_IDS, ...LAND_SOUND_IDS, ...BODY_SOUND_IDS];
2394
+
2278
2395
  // src/ground-items.ts
2279
2396
  function registerGroundItems() {
2280
2397
  const flat = { category: "ground_cover", w: 1, d: 1, h: 0, decor: true, mount: "ground", flat: true };
@@ -2495,6 +2612,109 @@ var GameFloorplan = (() => {
2495
2612
  }
2496
2613
  };
2497
2614
 
2615
+ // src/instance.ts
2616
+ var version = "0.1.0";
2617
+ function editCatalog(catalog, patch, remove) {
2618
+ if (!patch && !remove) return;
2619
+ const entries = new Map(Object.entries(catalog).map(([key, definition]) => [key, { ...definition, id: key }]));
2620
+ applyPatches(entries, patch);
2621
+ removeIds(entries, remove);
2622
+ for (const key of Object.keys(catalog)) {
2623
+ const edited = entries.get(key);
2624
+ if (!edited) delete catalog[key];
2625
+ else if (patch && key in patch) {
2626
+ const hadId = "id" in catalog[key];
2627
+ const next = { ...edited };
2628
+ if (!hadId) delete next.id;
2629
+ catalog[key] = next;
2630
+ }
2631
+ }
2632
+ }
2633
+ function buildEngine(scope) {
2634
+ const scoped = (fn) => ((...args) => withRegistries(scope, () => fn(...args)));
2635
+ return {
2636
+ version,
2637
+ generate: scoped(generate),
2638
+ slots: scoped(slots),
2639
+ validate: scoped(validate),
2640
+ palette: scoped(palette),
2641
+ limitsOf: scoped(limitsOf),
2642
+ listTemplates: scoped(listTemplates),
2643
+ listStates: scoped(listStates),
2644
+ // content registration
2645
+ registerItem: scoped(registerItem),
2646
+ registerItems: scoped(registerItems),
2647
+ registerLibrary: scoped(registerLibrary),
2648
+ registerLibraryAlias: scoped(registerLibraryAlias),
2649
+ registerTemplate: scoped(registerTemplate),
2650
+ registerStyle: scoped(registerStyle),
2651
+ registerPaletteStyle: scoped(registerPaletteStyle),
2652
+ registerRoomColors: scoped(registerRoomColors),
2653
+ registerDecorProfile: scoped(registerDecorProfile),
2654
+ registerPass: scoped(registerPass),
2655
+ registerGroundOverlay: scoped(registerGroundOverlay),
2656
+ registerWallTop: scoped(registerWallTop),
2657
+ registerSeedKeys: scoped(registerSeedKeys),
2658
+ registerState: scoped(registerState),
2659
+ setStateDistribution: scoped(setStateDistribution),
2660
+ registerLocale: scoped(registerLocale),
2661
+ registerResultExtension: scoped(registerResultExtension),
2662
+ registerFindsProvider: scoped(registerFindsProvider),
2663
+ findsFor: scoped(findsFor),
2664
+ findsAnswer: scoped(findsAnswer),
2665
+ registerViewerLayer: scoped(registerViewerLayer),
2666
+ viewerLayers: scope.VIEWER_LAYERS,
2667
+ blocksWindow: scoped(blocksWindow),
2668
+ // zoning
2669
+ defineZone: scoped(defineZone),
2670
+ getZone: scoped(getZone),
2671
+ listZones: scoped(listZones),
2672
+ checkLot: scoped(checkLot),
2673
+ registerPermeableGround: scoped(registerPermeableGround),
2674
+ // kits and data
2675
+ slotKit,
2676
+ translate: scoped(translate),
2677
+ listLocales: scoped(listLocales),
2678
+ templates: scope.TEMPLATES,
2679
+ catalog: scope.CATALOG,
2680
+ libraries: scope.LIBRARIES,
2681
+ styles: scope.STYLES,
2682
+ paletteStyles: scope.PALETTE_STYLES,
2683
+ createRng,
2684
+ mulberry32,
2685
+ hashString,
2686
+ overlaps,
2687
+ windowZone,
2688
+ openingZones,
2689
+ color: { lstar, hex: hexString, hsl: intToHsl, HIGH_SATURATION, MIN_WALL_FLOOR_CONTRAST, MIN_FABRIC_FLOOR_CONTRAST },
2690
+ constants: { WALL_THICKNESS, DOOR_CLEARANCE, PLAYER_RADIUS, DOOR_EDGE_CLEARANCE, WINDOW_EDGE_CLEARANCE, OVERHEAD_TOP, CAR_CLEARANCE }
2691
+ };
2692
+ }
2693
+ function seedBase(scope) {
2694
+ withRegistries(scope, () => {
2695
+ registerGroundItems();
2696
+ registerPermeableGround("lawn", "dirt");
2697
+ registerLocale("en", en_default);
2698
+ registerLocale("pt-BR", pt_BR_default);
2699
+ });
2700
+ }
2701
+ function createFloorplan(options = {}) {
2702
+ const scope = createRegistries();
2703
+ seedBase(scope);
2704
+ const instance = buildEngine(scope);
2705
+ for (const pack of options.packs ?? []) (typeof pack === "function" ? pack : pack.register)(instance);
2706
+ editCatalog(scope.CATALOG, options.patch?.items, options.remove?.items);
2707
+ editCatalog(scope.TEMPLATES, options.patch?.templates, options.remove?.templates);
2708
+ return instance;
2709
+ }
2710
+ var defaultEngine;
2711
+ function defaultFloorplan() {
2712
+ if (defaultEngine) return defaultEngine;
2713
+ seedBase(getDefaultRegistries());
2714
+ defaultEngine = buildEngine(getDefaultRegistries());
2715
+ return defaultEngine;
2716
+ }
2717
+
2498
2718
  // src/silhouettes/random.ts
2499
2719
  function createSilhouetteRandom(seed) {
2500
2720
  let state = seed;
@@ -2704,68 +2924,7 @@ var GameFloorplan = (() => {
2704
2924
  }
2705
2925
 
2706
2926
  // src/index.ts
2707
- registerGroundItems();
2708
- registerPermeableGround("lawn", "dirt");
2709
- registerLocale("en", en_default);
2710
- registerLocale("pt-BR", pt_BR_default);
2711
- var version = "0.1.0";
2712
- var engine = {
2713
- version,
2714
- generate,
2715
- slots,
2716
- validate,
2717
- palette,
2718
- limitsOf,
2719
- listTemplates,
2720
- listStates,
2721
- // content registration
2722
- registerItem,
2723
- registerItems,
2724
- registerLibrary,
2725
- registerLibraryAlias,
2726
- registerTemplate,
2727
- registerStyle,
2728
- registerPaletteStyle,
2729
- registerRoomColors,
2730
- registerDecorProfile,
2731
- registerPass,
2732
- registerGroundOverlay,
2733
- registerWallTop,
2734
- registerSeedKeys,
2735
- registerState,
2736
- setStateDistribution,
2737
- registerLocale,
2738
- registerResultExtension,
2739
- registerFindsProvider,
2740
- findsFor,
2741
- findsAnswer,
2742
- registerViewerLayer,
2743
- viewerLayers: VIEWER_LAYERS,
2744
- blocksWindow,
2745
- // zoning
2746
- defineZone,
2747
- getZone,
2748
- listZones,
2749
- checkLot,
2750
- registerPermeableGround,
2751
- // kits and data
2752
- slotKit,
2753
- translate,
2754
- listLocales,
2755
- templates: TEMPLATES,
2756
- catalog: CATALOG,
2757
- libraries: LIBRARIES,
2758
- styles: STYLES,
2759
- paletteStyles: PALETTE_STYLES,
2760
- createRng,
2761
- mulberry32,
2762
- hashString,
2763
- overlaps,
2764
- windowZone,
2765
- openingZones,
2766
- color: { lstar, hex: hexString, hsl: intToHsl, HIGH_SATURATION, MIN_WALL_FLOOR_CONTRAST, MIN_FABRIC_FLOOR_CONTRAST },
2767
- constants: { WALL_THICKNESS, DOOR_CLEARANCE, PLAYER_RADIUS, DOOR_EDGE_CLEARANCE, WINDOW_EDGE_CLEARANCE, OVERHEAD_TOP, CAR_CLEARANCE }
2768
- };
2927
+ var engine = defaultFloorplan();
2769
2928
  return __toCommonJS(index_exports);
2770
2929
  })();
2771
2930
  //# sourceMappingURL=index.global.js.map