@vgai/engine 0.5.7 → 0.5.8

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.
@@ -0,0 +1,14 @@
1
+ /**
2
+ * A non-enumerable slot carried by the game object itself.
3
+ *
4
+ * Packaged editor play can legitimately involve two copies of `@vgai/engine`:
5
+ * the editor bundle creates the Game, while the project's Vite graph creates
6
+ * its root adapter. Module-local WeakMaps cannot cross that boundary. A
7
+ * registry-backed symbol can, while keeping the internal value off the public
8
+ * string-keyed Game surface.
9
+ */
10
+ export declare function createGameScopedSlot<T>(name: string): {
11
+ set(owner: object, value: T): void;
12
+ get(owner: object): T | null;
13
+ };
14
+ //# sourceMappingURL=game-scoped-slot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"game-scoped-slot.d.ts","sourceRoot":"","sources":["../../src/core/game-scoped-slot.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG;IACrD,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IACnC,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC;CAC9B,CAeA"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * A non-enumerable slot carried by the game object itself.
3
+ *
4
+ * Packaged editor play can legitimately involve two copies of `@vgai/engine`:
5
+ * the editor bundle creates the Game, while the project's Vite graph creates
6
+ * its root adapter. Module-local WeakMaps cannot cross that boundary. A
7
+ * registry-backed symbol can, while keeping the internal value off the public
8
+ * string-keyed Game surface.
9
+ */
10
+ export function createGameScopedSlot(name) {
11
+ const key = Symbol.for(`@vgai/engine/game-scoped/${name}`);
12
+ return {
13
+ set(owner, value) {
14
+ Object.defineProperty(owner, key, {
15
+ configurable: true,
16
+ enumerable: false,
17
+ value,
18
+ });
19
+ },
20
+ get(owner) {
21
+ return owner[key] ?? null;
22
+ },
23
+ };
24
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"seeded-random.d.ts","sourceRoot":"","sources":["../../src/core/seeded-random.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAIH,0EAA0E;AAC1E,eAAO,MAAM,eAAe,aAAa,CAAC;AAE1C;;;;;;gFAMgF;AAChF,eAAO,MAAM,0BAA0B,aAAa,CAAC;AAErD;;;;;;;;;GASG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,MAAM,CAAC;IACX,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,MAAM,CAAC;IACnC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAsBD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,YAAY,CAgDpE;AAeD;yEACyE;AACzE,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAE9E;AAED;;;2DAG2D;AAC3D,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAElE"}
1
+ {"version":3,"file":"seeded-random.d.ts","sourceRoot":"","sources":["../../src/core/seeded-random.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAKH,0EAA0E;AAC1E,eAAO,MAAM,eAAe,aAAa,CAAC;AAE1C;;;;;;gFAMgF;AAChF,eAAO,MAAM,0BAA0B,aAAa,CAAC;AAErD;;;;;;;;;GASG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,MAAM,CAAC;IACX,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,MAAM,CAAC;IACnC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAsBD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,YAAY,CAgDpE;AAeD;yEACyE;AACzE,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAE9E;AAED;;;2DAG2D;AAC3D,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAElE"}
@@ -26,6 +26,7 @@
26
26
  * stay orthogonal; only the generator function itself is shared).
27
27
  */
28
28
  import { createMulberry32 } from '../runtime/render-seed';
29
+ import { createGameScopedSlot } from './game-scoped-slot';
29
30
  /** The name `ctx.random()` (called with no `.stream(...)`) draws from. */
30
31
  export const GAMEPLAY_STREAM = 'gameplay';
31
32
  /** The fixed fallback seed a `SeededRandom` boots with when no explicit seed
@@ -98,7 +99,7 @@ export function createSeededRandom(initialSeed) {
98
99
  }
99
100
  // ---------------------------------------------------------------------------
100
101
  // Game-scoped registry — mirrors `runtime/debug-registry.ts`'s
101
- // `registerDebugRegistry`/`getDebugRegistry` WeakMap pattern exactly, but
102
+ // `registerDebugRegistry`/`getDebugRegistry` game-slot pattern exactly, but
102
103
  // keyed on a bare `object` (not `Game`) so this module never needs to import
103
104
  // `runtime/game.ts` even as a type — `core/` stays independent of `runtime/`
104
105
  // except for the one explicit, documented `render-seed.ts` reuse above.
@@ -106,7 +107,7 @@ export function createSeededRandom(initialSeed) {
106
107
  // (the `GameInternal` shell) as the key, exactly like it does for
107
108
  // `registerDebugRegistry(gameInternal, debugRegistry)`.
108
109
  // ---------------------------------------------------------------------------
109
- const registryByOwner = new WeakMap();
110
+ const registryByOwner = createGameScopedSlot('seeded-random');
110
111
  /** Called once by `createGame`, right after both the seeded-random surface
111
112
  * and the Game shell object exist — mirrors `registerDebugRegistry`. */
112
113
  export function registerSeededRandom(owner, random) {
@@ -1 +1 @@
1
- {"version":3,"file":"sim-clock.d.ts","sourceRoot":"","sources":["../../src/core/sim-clock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiHG;AAEH,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAEpC,sFAAsF;AACtF,MAAM,WAAW,cAAc;IAC7B,4DAA4D;IAC5D,MAAM,IAAI,IAAI,CAAC;CAChB;AAED,iDAAiD;AACjD,MAAM,WAAW,kBAAkB;IACjC,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAC3C;AAED,qEAAqE;AACrE,MAAM,WAAW,QAAQ;IACvB,wEAAwE;IACxE,GAAG,IAAI,MAAM,CAAC;IACd,2EAA2E;IAC3E,OAAO,IAAI,MAAM,CAAC;IAClB;;;;;OAKG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE;;;OAGG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,IAAI,EAAE,IAAI,CAAC,EAAE,kBAAkB,GAAG,cAAc,CAAC;IAClF;;;;;OAKG;IACH,YAAY,CAAC,GAAG,EAAE,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,cAAc,CAAC;CACpE;AAED;;;;;GAKG;AACH,MAAM,WAAW,gBAAiB,SAAQ,QAAQ;IAChD;;;;;OAKG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;;;OAKG;IACH,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC,QAAQ,KAAK,IAAI,CAAC;CACjD;AAyBD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,gBAAgB,CAiJzE;AAWD,mFAAmF;AACnF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAE7E;AAED;;;;;;;;+EAQ+E;AAC/E,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAElE"}
1
+ {"version":3,"file":"sim-clock.d.ts","sourceRoot":"","sources":["../../src/core/sim-clock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiHG;AAEH,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAGpC,sFAAsF;AACtF,MAAM,WAAW,cAAc;IAC7B,4DAA4D;IAC5D,MAAM,IAAI,IAAI,CAAC;CAChB;AAED,iDAAiD;AACjD,MAAM,WAAW,kBAAkB;IACjC,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAC3C;AAED,qEAAqE;AACrE,MAAM,WAAW,QAAQ;IACvB,wEAAwE;IACxE,GAAG,IAAI,MAAM,CAAC;IACd,2EAA2E;IAC3E,OAAO,IAAI,MAAM,CAAC;IAClB;;;;;OAKG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE;;;OAGG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,IAAI,EAAE,IAAI,CAAC,EAAE,kBAAkB,GAAG,cAAc,CAAC;IAClF;;;;;OAKG;IACH,YAAY,CAAC,GAAG,EAAE,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,cAAc,CAAC;CACpE;AAED;;;;;GAKG;AACH,MAAM,WAAW,gBAAiB,SAAQ,QAAQ;IAChD;;;;;OAKG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;;;OAKG;IACH,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC,QAAQ,KAAK,IAAI,CAAC;CACjD;AAyBD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,gBAAgB,CAiJzE;AAWD,mFAAmF;AACnF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAE7E;AAED;;;;;;;;+EAQ+E;AAC/E,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAElE"}
@@ -112,6 +112,7 @@
112
112
  * - **No wall clock.** This module reads no system timer and creates no
113
113
  * host timeout; every time value comes from the runtime's own accumulator.
114
114
  */
115
+ import { createGameScopedSlot } from './game-scoped-slot';
115
116
  const NOOP_HANDLE = { cancel() { } };
116
117
  /** `fetch`-shaped abort rejection: a `DOMException` named `AbortError`. */
117
118
  function abortError(message) {
@@ -268,11 +269,11 @@ export function createSimClock(options) {
268
269
  }
269
270
  // ---------------------------------------------------------------------------
270
271
  // Game-scoped registry — mirrors `core/seeded-random.ts`'s
271
- // `registerSeededRandom`/`getSeededRandom` WeakMap pattern exactly, keyed on a
272
+ // `registerSeededRandom`/`getSeededRandom` slot pattern exactly, keyed on a
272
273
  // bare `object` (not `Game`) so `core/` never imports `runtime/`. `createGame`
273
274
  // is the one real registrant, passing the `GameInternal` shell as the key.
274
275
  // ---------------------------------------------------------------------------
275
- const clockByOwner = new WeakMap();
276
+ const clockByOwner = createGameScopedSlot('sim-clock');
276
277
  /** Called once by `createGame`, right after the clock and the Game shell exist. */
277
278
  export function registerSimClock(owner, clock) {
278
279
  clockByOwner.set(owner, clock);
@@ -4,8 +4,8 @@
4
4
  * SAME registry via {@link DebugRegistry.forRoot}, so a name a game registers is
5
5
  * visible (and name-collision-checked) across every world, not just the one that
6
6
  * registered it. `createGame` (`runtime/game.ts`) constructs the registry
7
- * alongside the state bridge and files it in the `Game -> DebugRegistry` WeakMap
8
- * this module owns; later consumers (the react `useDebugProvider`/
7
+ * alongside the state bridge and files it in a non-enumerable game-scoped slot;
8
+ * later consumers (the react `useDebugProvider`/
9
9
  * `useDebugCommand` hooks, editor panels) reach it via {@link getDebugRegistry}
10
10
  * rather than threading it through every call site.
11
11
  *
@@ -1 +1 @@
1
- {"version":3,"file":"debug-registry.d.ts","sourceRoot":"","sources":["../../src/runtime/debug-registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"debug-registry.d.ts","sourceRoot":"","sources":["../../src/runtime/debug-registry.ts"],"names":[],"mappings":"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"}
@@ -4,8 +4,8 @@
4
4
  * SAME registry via {@link DebugRegistry.forRoot}, so a name a game registers is
5
5
  * visible (and name-collision-checked) across every world, not just the one that
6
6
  * registered it. `createGame` (`runtime/game.ts`) constructs the registry
7
- * alongside the state bridge and files it in the `Game -> DebugRegistry` WeakMap
8
- * this module owns; later consumers (the react `useDebugProvider`/
7
+ * alongside the state bridge and files it in a non-enumerable game-scoped slot;
8
+ * later consumers (the react `useDebugProvider`/
9
9
  * `useDebugCommand` hooks, editor panels) reach it via {@link getDebugRegistry}
10
10
  * rather than threading it through every call site.
11
11
  *
@@ -20,6 +20,7 @@
20
20
  * by convention, so collision messages stay meaningful in practice.
21
21
  */
22
22
  import { z } from 'zod';
23
+ import { createGameScopedSlot } from '../core/game-scoped-slot';
23
24
  /** Engine-local error for the debug seam — mirrors the `code` + `data` shape
24
25
  * `packages/vgai-sdk/src/errors.ts` uses (no import: the engine does not
25
26
  * depend on `@vgai/sdk`). `code` is always machine-readable; nothing reading
@@ -514,7 +515,7 @@ export function createDebugRegistry(opts) {
514
515
  },
515
516
  };
516
517
  }
517
- const registryByGame = new WeakMap();
518
+ const registryByGame = createGameScopedSlot('debug-registry');
518
519
  /** Called once by `createGame`, right after both the registry and the Game
519
520
  * shell object exist, to file the association {@link getDebugRegistry} reads. */
520
521
  export function registerDebugRegistry(game, registry) {
@@ -297,7 +297,7 @@ export function createGame(opts) {
297
297
  // same `advanced` guard as the two bumps above, so a paused/frozen frame
298
298
  // fires no timers). Every world's `ctx.clock` is THIS instance, reached the
299
299
  // same way `ctx.random`/`ctx.debug` reach their game-scoped singletons —
300
- // `getSimClock(host.game)` over the WeakMap filed below.
300
+ // `getSimClock(host.game)` over the game-scoped slot filed below.
301
301
  //
302
302
  // The disposer is supplied HERE rather than inside the clock because
303
303
  // `core/sim-clock.ts` deliberately knows nothing about Rapier or shared
@@ -979,7 +979,7 @@ export function createGame(opts) {
979
979
  debugRegistry.strip();
980
980
  },
981
981
  };
982
- // Filed AFTER the shell exists (the WeakMap keys on the Game object
982
+ // Filed AFTER the shell exists (the slot lives on the Game object
983
983
  // itself) so `getDebugRegistry(game)` — the react hooks' and any later
984
984
  // consumer's reach-in — works from the moment `createGame` returns.
985
985
  registerDebugRegistry(gameInternal, debugRegistry);
@@ -1 +1 @@
1
- {"version":3,"file":"gameplay-rng-trap.d.ts","sourceRoot":"","sources":["../../src/runtime/gameplay-rng-trap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,WAAW,eAAe;IAC9B,8EAA8E;IAC9E,MAAM,IAAI,IAAI,CAAC;IACf;;;0CAGsC;IACtC,OAAO,IAAI,IAAI,CAAC;CACjB;AAcD;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,GAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAG1B,GACA,eAAe,CA6CjB;AAaD,MAAM,WAAW,sBAAsB;IACrC,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAID;+BAC+B;AAC/B,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,sBAAsB,GAC9B,IAAI,CAEN;AAED;4CAC4C;AAC5C,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,sBAAsB,GAAG,IAAI,CAEtF"}
1
+ {"version":3,"file":"gameplay-rng-trap.d.ts","sourceRoot":"","sources":["../../src/runtime/gameplay-rng-trap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,MAAM,WAAW,eAAe;IAC9B,8EAA8E;IAC9E,MAAM,IAAI,IAAI,CAAC;IACf;;;0CAGsC;IACtC,OAAO,IAAI,IAAI,CAAC;CACjB;AAcD;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,GAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAG1B,GACA,eAAe,CA6CjB;AAaD,MAAM,WAAW,sBAAsB;IACrC,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAID;+BAC+B;AAC/B,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,sBAAsB,GAC9B,IAAI,CAEN;AAED;4CAC4C;AAC5C,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,sBAAsB,GAAG,IAAI,CAEtF"}
@@ -19,6 +19,7 @@
19
19
  * Never throws: a cosmetic third-party draw is legal, just outside the
20
20
  * contract (the design doc is explicit about this — "warn, never throw").
21
21
  */
22
+ import { createGameScopedSlot } from '../core/game-scoped-slot';
22
23
  /** Pull a single representative "call site" line out of a captured stack —
23
24
  * the warn-once dedupe key. `stack[0]` is the `Error:` header line,
24
25
  * `stack[1]` is this trap's OWN wrapper frame — the caller's frame is the
@@ -82,7 +83,7 @@ export function createGameplayRngTrap(warn = (message) => {
82
83
  },
83
84
  };
84
85
  }
85
- const controlByOwner = new WeakMap();
86
+ const controlByOwner = createGameScopedSlot('gameplay-rng-trap');
86
87
  /** Called once by `createGame`, alongside `registerSeededRandom`/
87
88
  * `registerDebugRegistry`. */
88
89
  export function registerGameplayRngTrapControl(owner, control) {
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@vgai/engine",
3
3
  "author": "Volter AI, Inc.",
4
4
  "license": "Apache-2.0",
5
- "version": "0.5.7",
5
+ "version": "0.5.8",
6
6
  "description": "Readable TypeScript game engine and universal host for Three.js, PixiJS, and React games.",
7
7
  "keywords": [
8
8
  "game-engine",
@@ -0,0 +1,28 @@
1
+ /**
2
+ * A non-enumerable slot carried by the game object itself.
3
+ *
4
+ * Packaged editor play can legitimately involve two copies of `@vgai/engine`:
5
+ * the editor bundle creates the Game, while the project's Vite graph creates
6
+ * its root adapter. Module-local WeakMaps cannot cross that boundary. A
7
+ * registry-backed symbol can, while keeping the internal value off the public
8
+ * string-keyed Game surface.
9
+ */
10
+ export function createGameScopedSlot<T>(name: string): {
11
+ set(owner: object, value: T): void;
12
+ get(owner: object): T | null;
13
+ } {
14
+ const key = Symbol.for(`@vgai/engine/game-scoped/${name}`);
15
+
16
+ return {
17
+ set(owner, value) {
18
+ Object.defineProperty(owner, key, {
19
+ configurable: true,
20
+ enumerable: false,
21
+ value,
22
+ });
23
+ },
24
+ get(owner) {
25
+ return (owner as { [key: symbol]: T | undefined })[key] ?? null;
26
+ },
27
+ };
28
+ }
@@ -27,6 +27,7 @@
27
27
  */
28
28
 
29
29
  import { createMulberry32 } from '../runtime/render-seed';
30
+ import { createGameScopedSlot } from './game-scoped-slot';
30
31
 
31
32
  /** The name `ctx.random()` (called with no `.stream(...)`) draws from. */
32
33
  export const GAMEPLAY_STREAM = 'gameplay';
@@ -135,7 +136,7 @@ export function createSeededRandom(initialSeed: number): SeededRandom {
135
136
 
136
137
  // ---------------------------------------------------------------------------
137
138
  // Game-scoped registry — mirrors `runtime/debug-registry.ts`'s
138
- // `registerDebugRegistry`/`getDebugRegistry` WeakMap pattern exactly, but
139
+ // `registerDebugRegistry`/`getDebugRegistry` game-slot pattern exactly, but
139
140
  // keyed on a bare `object` (not `Game`) so this module never needs to import
140
141
  // `runtime/game.ts` even as a type — `core/` stays independent of `runtime/`
141
142
  // except for the one explicit, documented `render-seed.ts` reuse above.
@@ -144,7 +145,7 @@ export function createSeededRandom(initialSeed: number): SeededRandom {
144
145
  // `registerDebugRegistry(gameInternal, debugRegistry)`.
145
146
  // ---------------------------------------------------------------------------
146
147
 
147
- const registryByOwner = new WeakMap<object, SeededRandom>();
148
+ const registryByOwner = createGameScopedSlot<SeededRandom>('seeded-random');
148
149
 
149
150
  /** Called once by `createGame`, right after both the seeded-random surface
150
151
  * and the Game shell object exist — mirrors `registerDebugRegistry`. */
@@ -114,6 +114,7 @@
114
114
  */
115
115
 
116
116
  import type * as THREE from 'three';
117
+ import { createGameScopedSlot } from './game-scoped-slot';
117
118
 
118
119
  /** Cancel handle returned by {@link SimClock.after}/{@link SimClock.disposeAfter}. */
119
120
  export interface SimTimerHandle {
@@ -362,12 +363,12 @@ export function createSimClock(options: SimClockOptions): SimClockInternal {
362
363
 
363
364
  // ---------------------------------------------------------------------------
364
365
  // Game-scoped registry — mirrors `core/seeded-random.ts`'s
365
- // `registerSeededRandom`/`getSeededRandom` WeakMap pattern exactly, keyed on a
366
+ // `registerSeededRandom`/`getSeededRandom` slot pattern exactly, keyed on a
366
367
  // bare `object` (not `Game`) so `core/` never imports `runtime/`. `createGame`
367
368
  // is the one real registrant, passing the `GameInternal` shell as the key.
368
369
  // ---------------------------------------------------------------------------
369
370
 
370
- const clockByOwner = new WeakMap<object, SimClockInternal>();
371
+ const clockByOwner = createGameScopedSlot<SimClockInternal>('sim-clock');
371
372
 
372
373
  /** Called once by `createGame`, right after the clock and the Game shell exist. */
373
374
  export function registerSimClock(owner: object, clock: SimClockInternal): void {
@@ -4,8 +4,8 @@
4
4
  * SAME registry via {@link DebugRegistry.forRoot}, so a name a game registers is
5
5
  * visible (and name-collision-checked) across every world, not just the one that
6
6
  * registered it. `createGame` (`runtime/game.ts`) constructs the registry
7
- * alongside the state bridge and files it in the `Game -> DebugRegistry` WeakMap
8
- * this module owns; later consumers (the react `useDebugProvider`/
7
+ * alongside the state bridge and files it in a non-enumerable game-scoped slot;
8
+ * later consumers (the react `useDebugProvider`/
9
9
  * `useDebugCommand` hooks, editor panels) reach it via {@link getDebugRegistry}
10
10
  * rather than threading it through every call site.
11
11
  *
@@ -22,6 +22,7 @@
22
22
 
23
23
  import { z } from 'zod';
24
24
  import type { DebugAdapter, DebugCommandInfo, TickStampedEvent } from '../adapter/system-adapter';
25
+ import { createGameScopedSlot } from '../core/game-scoped-slot';
25
26
  import type { GameLoopLiveness } from '../core/types';
26
27
  import type { Game } from './game';
27
28
  import type { DebugCommandArgs, DebugCtxSurface, DebugRoomHandle } from './types';
@@ -865,7 +866,7 @@ export function createDebugRegistry(opts: {
865
866
  };
866
867
  }
867
868
 
868
- const registryByGame = new WeakMap<Game, DebugRegistry>();
869
+ const registryByGame = createGameScopedSlot<DebugRegistry>('debug-registry');
869
870
 
870
871
  /** Called once by `createGame`, right after both the registry and the Game
871
872
  * shell object exist, to file the association {@link getDebugRegistry} reads. */
@@ -862,7 +862,7 @@ export function createGame(opts: {
862
862
  // same `advanced` guard as the two bumps above, so a paused/frozen frame
863
863
  // fires no timers). Every world's `ctx.clock` is THIS instance, reached the
864
864
  // same way `ctx.random`/`ctx.debug` reach their game-scoped singletons —
865
- // `getSimClock(host.game)` over the WeakMap filed below.
865
+ // `getSimClock(host.game)` over the game-scoped slot filed below.
866
866
  //
867
867
  // The disposer is supplied HERE rather than inside the clock because
868
868
  // `core/sim-clock.ts` deliberately knows nothing about Rapier or shared
@@ -1568,7 +1568,7 @@ export function createGame(opts: {
1568
1568
  },
1569
1569
  };
1570
1570
 
1571
- // Filed AFTER the shell exists (the WeakMap keys on the Game object
1571
+ // Filed AFTER the shell exists (the slot lives on the Game object
1572
1572
  // itself) so `getDebugRegistry(game)` — the react hooks' and any later
1573
1573
  // consumer's reach-in — works from the moment `createGame` returns.
1574
1574
  registerDebugRegistry(gameInternal, debugRegistry);
@@ -20,6 +20,8 @@
20
20
  * contract (the design doc is explicit about this — "warn, never throw").
21
21
  */
22
22
 
23
+ import { createGameScopedSlot } from '../core/game-scoped-slot';
24
+
23
25
  export interface GameplayRngTrap {
24
26
  /** Wrap `Math.random` for the duration of one frame — call at frame start. */
25
27
  enable(): void;
@@ -100,7 +102,7 @@ export function createGameplayRngTrap(
100
102
  }
101
103
 
102
104
  // ---------------------------------------------------------------------------
103
- // Game-scoped registry — same WeakMap-on-owner-object pattern as
105
+ // Game-scoped registry — same slot-on-owner-object pattern as
104
106
  // `core/seeded-random.ts`'s `registerSeededRandom`/`getSeededRandom` (and
105
107
  // `debug-registry.ts`'s `registerDebugRegistry`/`getDebugRegistry`): the
106
108
  // trap's enable/disable calls live inside `game.ts`'s `runFrameImpl`, gated
@@ -115,7 +117,7 @@ export interface GameplayRngTrapControl {
115
117
  readonly enabled: boolean;
116
118
  }
117
119
 
118
- const controlByOwner = new WeakMap<object, GameplayRngTrapControl>();
120
+ const controlByOwner = createGameScopedSlot<GameplayRngTrapControl>('gameplay-rng-trap');
119
121
 
120
122
  /** Called once by `createGame`, alongside `registerSeededRandom`/
121
123
  * `registerDebugRegistry`. */