@volter/project 0.0.0-stage → 0.5.203

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.
Files changed (53) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +6 -0
  3. package/README.md +18 -3
  4. package/package.json +64 -4
  5. package/schemas/engine-api.json +57 -0
  6. package/schemas/engine-api.md +22 -0
  7. package/schemas/volter-project.schema.json +468 -0
  8. package/schemas/volter-settings.schema.json +149 -0
  9. package/src/adapter/adapter-module.ts +997 -0
  10. package/src/adapter/adapter-surface.ts +34 -0
  11. package/src/adapter/authoring-seam-contract.ts +224 -0
  12. package/src/adapter/authoring.ts +1336 -0
  13. package/src/adapter/binding.ts +445 -0
  14. package/src/adapter/debug-registry-ref.ts +19 -0
  15. package/src/adapter/editor-looks.ts +519 -0
  16. package/src/adapter/finders/finder-result.ts +29 -0
  17. package/src/adapter/finders/registry.ts +116 -0
  18. package/src/adapter/frame-capture.ts +80 -0
  19. package/src/adapter/host-context.ts +114 -0
  20. package/src/adapter/index.ts +209 -0
  21. package/src/adapter/ingest/contract-system-slots.ts +28 -0
  22. package/src/adapter/ingest/game-contract-seams.ts +86 -0
  23. package/src/adapter/ingest/game-contract.ts +506 -0
  24. package/src/adapter/ingest/mount-readiness.ts +140 -0
  25. package/src/adapter/loop-gate-report.ts +53 -0
  26. package/src/adapter/manifest-interpreter.ts +64 -0
  27. package/src/adapter/native-entry-surface.ts +100 -0
  28. package/src/adapter/physics-adapter-2d.ts +30 -0
  29. package/src/adapter/render-audio.ts +20 -0
  30. package/src/adapter/render-memory.ts +34 -0
  31. package/src/adapter/renderer-config.ts +84 -0
  32. package/src/adapter/root-adapter.ts +243 -0
  33. package/src/adapter/root-seam-contract.ts +61 -0
  34. package/src/adapter/root-stacking.ts +67 -0
  35. package/src/adapter/seam-evidence.ts +336 -0
  36. package/src/adapter/system-adapter.ts +865 -0
  37. package/src/adapter/system-seam-contract.ts +138 -0
  38. package/src/adapter/system-slot.ts +301 -0
  39. package/src/adapter/transform.ts +35 -0
  40. package/src/adapter/workspace-arrangement.ts +92 -0
  41. package/src/core/system-phase.ts +52 -0
  42. package/src/inspection.ts +281 -0
  43. package/src/manifest/configuration-kinds.ts +241 -0
  44. package/src/manifest/editor-port.ts +69 -0
  45. package/src/manifest/filename.ts +45 -0
  46. package/src/manifest/kind-modules.ts +58 -0
  47. package/src/manifest/load-file.ts +33 -0
  48. package/src/manifest/load.ts +380 -0
  49. package/src/manifest/locate.ts +55 -0
  50. package/src/manifest/runtime-environment.ts +48 -0
  51. package/src/manifest/schema.ts +690 -0
  52. package/src/settings/keys.ts +152 -0
  53. package/src/settings/schema.ts +151 -0
@@ -0,0 +1,445 @@
1
+ /**
2
+ * THE ROOT BINDING — a game's declaration of itself, bound, as ONE host-side
3
+ * value.
4
+ *
5
+ * A game is a native program plus a declaration of itself; the editor is a
6
+ * universal client of that declaration; the host must not know what it is
7
+ * hosting. Today that declaration arrives at the host as a scatter — a
8
+ * `RootInstance`, a `MountedRoot`, an `AuthoringAdapter` provider bag, a
9
+ * `SystemAdapters` slot map, a `ResolvedAdapterRoot`, a parsed
10
+ * `AdapterDefinition` — and every consumer re-assembles its own subset by
11
+ * hand. `RootBinding` is that same material REGROUPED under one name, by the
12
+ * FIVE protocol families a host actually talks in.
13
+ *
14
+ * ## This file declares the vocabulary AND performs the regrouping
15
+ *
16
+ * {@link createRootBinding} is the one place the five families are assembled,
17
+ * and it is a pure re-address of values it is HANDED — it loads nothing,
18
+ * fetches nothing, and constructs no provider. The editor's
19
+ * `binding-resolver.ts` (`resolveRootBinding(root, realm, adapterDef)`) is what
20
+ * gathers those values per realm and calls this; `RootInstance.binding`
21
+ * (`runtime/game.ts`) is where the result lives for the life of the mount.
22
+ * Keeping the assembly here rather than in the resolver is what makes the
23
+ * reference-equality rule below checkable in ONE function instead of once per
24
+ * realm.
25
+ *
26
+ * ## The one rule that makes this a regrouping and not an abstraction
27
+ *
28
+ * **Every member is a REFERENCE to the thing that already exists — never a
29
+ * facade, never a copy, never a wrapper.** `substrate.mounted` IS the
30
+ * `MountedRoot` the adapter returned. `observation.debugRegistry` IS the ONE
31
+ * game-scoped registry every root of that game shares (this binding neither
32
+ * owns it nor tears it down). And the providers that are read AND written
33
+ * through — `selection`, `transforms`, `inspector`, `instances`,
34
+ * `spatialHandles`, `boxEdit`, `text` — appear in BOTH
35
+ * {@link ProjectionBinding} and {@link TruthBinding} as literally the same
36
+ * object, so `binding.projection.selection === binding.truth.selection`. A
37
+ * facade at either address would make the two views disagree the first time
38
+ * anything stateful moved through one of them; reference equality is what
39
+ * makes "regrouping" a checkable claim instead of a promise.
40
+ */
41
+
42
+ import type { ResolvedAdapterRoot } from '../manifest/load';
43
+ import type { AdapterDefinition } from './adapter-module';
44
+ import type {
45
+ AssetDropProvider,
46
+ AssetSubjectProvider,
47
+ AuthoringCapabilities,
48
+ AuthoringProvenance,
49
+ BoxEditProvider,
50
+ ColorSampleProvider,
51
+ ComponentInstancesProvider,
52
+ HierarchyProvider,
53
+ InspectorProvider,
54
+ PersistenceProvider,
55
+ PickProvider,
56
+ RectProvider,
57
+ RelatedSubjectsProvider,
58
+ SelectionProvider,
59
+ SpatialHandlesProvider,
60
+ StoriesProvider,
61
+ StructureProvider,
62
+ TextProvider,
63
+ TransformProvider,
64
+ TruthProvider,
65
+ } from './authoring';
66
+ import type { DebugRegistryRef } from './debug-registry-ref';
67
+ import type { NativeDebugBinding, NativeSystemsBinding } from './native-entry-surface';
68
+ import type { MountedRoot, RootStateObserver, SurfaceAdapter } from './root-adapter';
69
+ import type { SystemAdapters } from './system-adapter';
70
+
71
+ /**
72
+ * THE PROTOCOL VOCABULARY — the five families a host talks to a root in, and
73
+ * the ONLY place they are enumerated.
74
+ *
75
+ * This union is the single enumeration on purpose: `RootBinding`'s keys are
76
+ * pinned to it by {@link RootBindingKeysAreExactlyTheProtocolFamilies} below,
77
+ * so a sixth family cannot be added at one address and forgotten at the
78
+ * other, and no second list of these names may exist anywhere in the repo
79
+ * (`adapter-binding-protocol-families.test.ts` is the tripwire).
80
+ */
81
+ export type ProtocolFamily = 'substrate' | 'projection' | 'truth' | 'observation' | 'project';
82
+
83
+ /**
84
+ * WHAT MOUNTED, AND HOW IT RUNS.
85
+ *
86
+ * The adapter that produced the mount, the mount itself, and the two
87
+ * lifecycle facts that are properties of the ROOT rather than of the mounted
88
+ * handle (`pausable` is the manifest's per-world play/pause semantics;
89
+ * `loop` is the declared loop model the loop gate reports against). Every
90
+ * other lifecycle member — `update`, `fixedUpdate`, `setPaused`, `step`,
91
+ * `resize`, `dispose`, `disposeComplete`, `drivesOwnLoop` — is reached
92
+ * through `mounted`, unrepeated, because repeating them here would be the
93
+ * facade this binding exists not to be.
94
+ */
95
+ export interface SubstrateBinding {
96
+ /** The surface-tagged adapter the resolver produced for this root. */
97
+ readonly adapter: SurfaceAdapter;
98
+ /** The handle the adapter's `mount` returned — the same object, not a view. */
99
+ readonly mounted: MountedRoot;
100
+ /** Per-world play/pause semantics (D10's per-world default is `true`). */
101
+ readonly pausable: boolean;
102
+ /** The declared loop model: host-ticked, or the game owns its own rAF. */
103
+ readonly loop: ResolvedAdapterRoot['loop'];
104
+ }
105
+
106
+ /**
107
+ * READ VIEWS of the provider set — what the editor's panels ASK this root.
108
+ *
109
+ * `capabilities` and `hierarchy` are required because an `AuthoringAdapter`
110
+ * cannot exist without them; every other member is optional and absent means
111
+ * "this root does not support that", never a fabricated empty.
112
+ *
113
+ * The seven members marked STRADDLER also appear on {@link TruthBinding}, as
114
+ * the same object (see this module's header).
115
+ */
116
+ export interface ProjectionBinding {
117
+ readonly capabilities: AuthoringCapabilities;
118
+ readonly hierarchy: HierarchyProvider;
119
+ readonly provenance?: AuthoringProvenance | undefined;
120
+ /** STRADDLER. */
121
+ readonly selection?: SelectionProvider | undefined;
122
+ /** STRADDLER. */
123
+ readonly transforms?: TransformProvider | undefined;
124
+ /** STRADDLER. */
125
+ readonly inspector?: InspectorProvider | undefined;
126
+ /** STRADDLER. */
127
+ readonly instances?: ComponentInstancesProvider | undefined;
128
+ /** STRADDLER. */
129
+ readonly spatialHandles?: SpatialHandlesProvider | undefined;
130
+ /** STRADDLER. */
131
+ readonly boxEdit?: BoxEditProvider | undefined;
132
+ /** STRADDLER. */
133
+ readonly text?: TextProvider | undefined;
134
+ readonly assetSubject?: AssetSubjectProvider | undefined;
135
+ readonly related?: RelatedSubjectsProvider | undefined;
136
+ readonly rects?: RectProvider | undefined;
137
+ readonly pickable?: PickProvider | undefined;
138
+ readonly stories?: StoriesProvider | undefined;
139
+ readonly colorSample?: ColorSampleProvider | undefined;
140
+ }
141
+
142
+ /**
143
+ * WRITE VIEWS of the provider set — what an authored edit goes THROUGH.
144
+ *
145
+ * The write-only members (`structure`, `persistence`, `truth`, `assetDrop`)
146
+ * plus the seven straddlers, which are the same objects the projection holds.
147
+ */
148
+ export interface TruthBinding {
149
+ readonly structure?: StructureProvider | undefined;
150
+ readonly persistence?: PersistenceProvider | undefined;
151
+ /** Projection subject → source/data anchor and write lane, resolved together. */
152
+ readonly truth?: TruthProvider | undefined;
153
+ readonly assetDrop?: AssetDropProvider | undefined;
154
+ /** STRADDLER. */
155
+ readonly selection?: SelectionProvider | undefined;
156
+ /** STRADDLER. */
157
+ readonly transforms?: TransformProvider | undefined;
158
+ /** STRADDLER. */
159
+ readonly inspector?: InspectorProvider | undefined;
160
+ /** STRADDLER. */
161
+ readonly instances?: ComponentInstancesProvider | undefined;
162
+ /** STRADDLER. */
163
+ readonly spatialHandles?: SpatialHandlesProvider | undefined;
164
+ /** STRADDLER. */
165
+ readonly boxEdit?: BoxEditProvider | undefined;
166
+ /** STRADDLER. */
167
+ readonly text?: TextProvider | undefined;
168
+ }
169
+
170
+ /**
171
+ * WHAT THIS ROOT LETS ANYONE WATCH — references only.
172
+ *
173
+ * `debugRegistry` is the ONE registry the whole Game shares. This binding
174
+ * holds a reference to it and nothing more: it never creates it, never
175
+ * disposes it, and per-root teardown must not end it (a game-scoped resource
176
+ * destroyed by a root-scoped teardown is a bug this repo has already paid
177
+ * for once).
178
+ *
179
+ * `entryDebug`/`entrySystems` are the entry module's own statically declared
180
+ * bindings, harvested at resolve time and INSTALLED post-mount by
181
+ * `adapter-runtime-bindings` — they ride here rather than being re-read from
182
+ * the module a second time.
183
+ */
184
+ export interface ObservationBinding {
185
+ /** The root's system-adapter slots (physics/networking/navigation/audio/debug). */
186
+ readonly systems?: SystemAdapters | undefined;
187
+ /** Reference to the game-scoped registry. Never owned, never disposed here. */
188
+ readonly debugRegistry: DebugRegistryRef | null;
189
+ /** The ingested-world observation contract, when the adapter has one. */
190
+ readonly observe?: RootStateObserver | undefined;
191
+ /** Change notification → UI refresh. */
192
+ readonly subscribe?: ((listener: () => void) => () => void) | undefined;
193
+ /** The entry module's `debug` export, already validated. */
194
+ readonly entryDebug?: NativeDebugBinding | undefined;
195
+ /** The entry module's `systems` export, already validated. */
196
+ readonly entrySystems?: NativeSystemsBinding | undefined;
197
+ }
198
+
199
+ /**
200
+ * The entry module's static surface, WITH the realm's reach stated.
201
+ *
202
+ * The host holds the entry module's WHOLE namespace: a project module is
203
+ * served by the session's own dev server, so there is nothing between the
204
+ * module and the host. `reach` is stated rather than assumed because the
205
+ * shape once had a second member, and a consumer that reaches for an export
206
+ * must be able to see in the TYPE whether it can be there.
207
+ */
208
+ export interface EntryStaticSurface {
209
+ readonly reach: 'full';
210
+ /** The entry module's own namespace object. */
211
+ readonly module: Record<string, unknown>;
212
+ }
213
+
214
+ /**
215
+ * WHAT THE PROJECT DECLARED — the manifest root, the parsed `editor/volter.adapter.ts`
216
+ * definition, and the entry's static surface.
217
+ *
218
+ * `editor/volter.adapter.ts` LOADING stays where it is (`project-adapter.ts`); its
219
+ * parsed result is an INPUT to `resolveRootBinding`, not something this
220
+ * binding goes and fetches. That is deliberate: the binding is the hand-off's
221
+ * shape, never a second loader.
222
+ */
223
+ export interface ProjectBinding {
224
+ /** The manifest's own resolved root record. */
225
+ readonly root: ResolvedAdapterRoot;
226
+ /**
227
+ * The project's parsed `editor/volter.adapter.ts`, or `null` when it declares none.
228
+ *
229
+ * `project-adapter.ts` is still the only thing that LOADS it; the editor's
230
+ * `resolveComposition` asks that owner once per composition — waiting on the
231
+ * load in flight rather than reading past it — and hands the answer to
232
+ * `resolveRootBinding`, so every root of one game carries the same
233
+ * declaration. `null` is therefore a fact about the PROJECT: it shipped no
234
+ * declaration file and runs on the declared native default. Which table
235
+ * stood in (project, registry, or native) is a separate question, answered
236
+ * by `ProjectAdapterFacet.source`.
237
+ */
238
+ readonly definition: AdapterDefinition | null;
239
+ /** The entry module's static surface, realm-honest about its reach. */
240
+ readonly entry: EntryStaticSurface;
241
+ }
242
+
243
+ /**
244
+ * One root's whole declaration, bound.
245
+ *
246
+ * The keys ARE {@link ProtocolFamily} — pinned below, so the vocabulary and
247
+ * the value can never drift apart.
248
+ */
249
+ export interface RootBinding {
250
+ readonly substrate: SubstrateBinding;
251
+ /**
252
+ * Present only when this root's mount exposes an `AuthoringAdapter`.
253
+ *
254
+ * A `ProjectionBinding` cannot be fabricated — `capabilities`/`hierarchy`
255
+ * are required — so a mount with no authoring gets no projection. It gets
256
+ * the other four families, which are constructible from the declaration and
257
+ * the mount alone, because withholding those too would answer "what root is
258
+ * this, what did the project declare, what can be watched" with silence for
259
+ * a question the mount's authoring has nothing to do with.
260
+ *
261
+ * Absent is a REAL state, not a rare one: the editor supplies live authoring
262
+ * for native TSX roots itself (`play-mode.ts`'s per-root live adapters,
263
+ * composed into one `CompositeAuthoringAdapter`) rather than through the
264
+ * mount, so today every first-party three/canvas/dom root lands here. Moving
265
+ * that projection into the mount is its own program item; until it does, the
266
+ * absence is the honest report of where authoring lives.
267
+ */
268
+ readonly projection?: ProjectionBinding | undefined;
269
+ /** Present exactly when {@link projection} is — same authoring adapter, same
270
+ * condition; see there. */
271
+ readonly truth?: TruthBinding | undefined;
272
+ readonly observation: ObservationBinding;
273
+ readonly project: ProjectBinding;
274
+ }
275
+
276
+ /**
277
+ * Compile-time pin: `keyof RootBinding` and `ProtocolFamily` are the same set
278
+ * of names, in both directions. Adding a family to one address and not the
279
+ * other is a type error HERE, at the vocabulary, rather than a silent
280
+ * asymmetry every consumer inherits.
281
+ */
282
+ type MutuallyAssignable<A, B> = [A] extends [B] ? ([B] extends [A] ? true : false) : false;
283
+ type AssertTrue<T extends true> = T;
284
+ export type RootBindingKeysAreExactlyTheProtocolFamilies = AssertTrue<
285
+ MutuallyAssignable<keyof RootBinding, ProtocolFamily>
286
+ >;
287
+
288
+ /**
289
+ * Everything {@link createRootBinding} needs, and nothing it could go and get
290
+ * for itself.
291
+ *
292
+ * Each member is a value some OTHER owner already produced: the resolver
293
+ * mounted the adapter, the manifest loader resolved the root, `project-adapter`
294
+ * parsed the definition, the realm loaded the entry namespace, `createGame`
295
+ * owns the debug registry. This shape exists so that list is stated once, at
296
+ * the seam, instead of being re-derived per realm.
297
+ */
298
+ export interface RootBindingParts extends RootDeclaration {
299
+ readonly adapter: SurfaceAdapter;
300
+ readonly mounted: MountedRoot;
301
+ readonly pausable: boolean;
302
+ /** The GAME-scoped registry, borrowed. Never created or disposed here. */
303
+ readonly debugRegistry: DebugRegistryRef | null;
304
+ }
305
+
306
+ /**
307
+ * The DECLARATION half — everything a resolver knows BEFORE anything mounts.
308
+ *
309
+ * This is the half that travels: `binding-resolver.ts` produces one per root
310
+ * while it is resolving adapters, hands it to the host on the root's mount
311
+ * spec, and the host completes the binding at REGISTRATION — the first moment
312
+ * `mounted` exists at all. Splitting it here is what keeps the resolver from
313
+ * having to be present at mount time, and the host from having to know how an
314
+ * entry module was loaded.
315
+ */
316
+ export interface RootDeclaration {
317
+ /** The manifest's own resolved root record. `loop` rides on it. */
318
+ readonly root: ResolvedAdapterRoot;
319
+ /** The project's parsed `editor/volter.adapter.ts`, or `null` when it declares none —
320
+ * see {@link ProjectBinding.definition} for the current wiring truth. */
321
+ readonly definition: AdapterDefinition | null;
322
+ /** The entry module's static surface, realm-honest about its reach. */
323
+ readonly entry: EntryStaticSurface;
324
+ /** The entry module's validated `debug` export, harvested at resolve. */
325
+ readonly entryDebug?: NativeDebugBinding | undefined;
326
+ /** The entry module's validated `systems` export, harvested at resolve. */
327
+ readonly entrySystems?: NativeSystemsBinding | undefined;
328
+ }
329
+
330
+ /**
331
+ * REGROUP the parts into the five families. No loading, no defaulting, no
332
+ * fabrication: every member of the result is one of `parts`' own values or one
333
+ * of `parts.mounted.authoring`'s own provider objects, read straight off it.
334
+ *
335
+ * The straddlers are read ONCE into locals and written to both bindings, which
336
+ * is what makes `binding.projection.selection === binding.truth.selection` true
337
+ * by construction rather than by care —
338
+ * `adapter-binding-protocol-families.test.ts` asserts it over a value this
339
+ * function built.
340
+ *
341
+ * `subscribe` is the one exception to "the same reference", and deliberately:
342
+ * it is a METHOD on its adapter (`three-authoring-adapter` reads `this.store`
343
+ * inside it), so a bare property read would hand the caller a function whose
344
+ * `this` is the observation binding. It is bound to the authoring adapter that
345
+ * owns it — the same function over the same receiver, with nothing interposed.
346
+ * It is not a straddler and carries no equality claim.
347
+ *
348
+ * An absent `mounted.authoring` costs this root its `projection` and `truth`
349
+ * and NOTHING ELSE. There is no such thing as an empty `ProjectionBinding` —
350
+ * `capabilities`/`hierarchy` are required — so those two families are simply
351
+ * not there, which is the honest report. The other three are built from the
352
+ * declaration and the mount, neither of which the authoring adapter has
353
+ * anything to do with; refusing them as well would answer "which root is
354
+ * this, what did the project declare, what can be watched" with silence, and
355
+ * that is what made `binding` unreadable for every native TSX root the editor
356
+ * plays (the editor supplies their authoring itself — see
357
+ * {@link RootBinding.projection}).
358
+ */
359
+ export function createRootBinding(parts: RootBindingParts): RootBinding {
360
+ const authoring = parts.mounted.authoring;
361
+
362
+ // Read each straddler ONCE — the two bindings below then hold these exact
363
+ // objects, not two reads of the same key.
364
+ const { selection, transforms, inspector, instances, spatialHandles, boxEdit, text } =
365
+ authoring ?? {};
366
+
367
+ return {
368
+ substrate: {
369
+ adapter: parts.adapter,
370
+ mounted: parts.mounted,
371
+ pausable: parts.pausable,
372
+ loop: parts.root.loop,
373
+ },
374
+ ...(authoring === undefined
375
+ ? {}
376
+ : projectionAndTruth(authoring, {
377
+ selection,
378
+ transforms,
379
+ inspector,
380
+ instances,
381
+ spatialHandles,
382
+ boxEdit,
383
+ text,
384
+ })),
385
+ observation: {
386
+ systems: parts.mounted.systems,
387
+ debugRegistry: parts.debugRegistry,
388
+ observe: parts.mounted.observe,
389
+ subscribe: authoring?.subscribe?.bind(authoring),
390
+ entryDebug: parts.entryDebug,
391
+ entrySystems: parts.entrySystems,
392
+ },
393
+ project: {
394
+ root: parts.root,
395
+ definition: parts.definition,
396
+ entry: parts.entry,
397
+ },
398
+ };
399
+ }
400
+
401
+ /** The two authoring-dependent families, built together from the ONE adapter
402
+ * and the straddlers already read off it — so the reference-equality rule is
403
+ * still decided in a single place. */
404
+ function projectionAndTruth(
405
+ authoring: NonNullable<MountedRoot['authoring']>,
406
+ straddlers: Pick<
407
+ ProjectionBinding,
408
+ 'selection' | 'transforms' | 'inspector' | 'instances' | 'spatialHandles' | 'boxEdit' | 'text'
409
+ >,
410
+ ): { projection: ProjectionBinding; truth: TruthBinding } {
411
+ const { selection, transforms, inspector, instances, spatialHandles, boxEdit, text } = straddlers;
412
+ return {
413
+ projection: {
414
+ capabilities: authoring.capabilities,
415
+ hierarchy: authoring.hierarchy,
416
+ provenance: authoring.provenance,
417
+ selection,
418
+ transforms,
419
+ inspector,
420
+ instances,
421
+ spatialHandles,
422
+ boxEdit,
423
+ text,
424
+ assetSubject: authoring.assetSubject,
425
+ related: authoring.related,
426
+ rects: authoring.rects,
427
+ pickable: authoring.pickable,
428
+ stories: authoring.stories,
429
+ colorSample: authoring.colorSample,
430
+ },
431
+ truth: {
432
+ structure: authoring.structure,
433
+ persistence: authoring.persistence,
434
+ truth: authoring.truth,
435
+ assetDrop: authoring.assetDrop,
436
+ selection,
437
+ transforms,
438
+ inspector,
439
+ instances,
440
+ spatialHandles,
441
+ boxEdit,
442
+ text,
443
+ },
444
+ };
445
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The game-scoped debug registry AS THE SEAM SEES IT — a reference a binding
3
+ * carries, and the one member the seam reads off it.
4
+ *
5
+ * The contract does not restate `@volter/editor-game/runtime/debug-registry`'s
6
+ * `DebugRegistry`: that interface names the game runtime's own vocabulary
7
+ * (`DebugCtxSurface`, `Game`, the input doors, the run-ticks target), and
8
+ * moving it here would put the game host's debugger inside the project
9
+ * contract. Nothing across this seam calls the registry — the binding holds
10
+ * the reference so the host can hand it back to whoever created it — so the
11
+ * structural shape is the adapter it seeds, and `DebugRegistry` satisfies it.
12
+ */
13
+
14
+ import type { DebugAdapter } from './system-adapter';
15
+
16
+ export interface DebugRegistryRef {
17
+ /** The `SystemAdapters.debug` implementer this registry seeds. */
18
+ readonly adapter: DebugAdapter;
19
+ }