@vgai/engine 0.5.11 → 0.5.13

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 (152) hide show
  1. package/README.md +6 -5
  2. package/dist/adapter/authoring.d.ts +51 -28
  3. package/dist/adapter/authoring.d.ts.map +1 -1
  4. package/dist/adapter/body-marks.d.ts +59 -0
  5. package/dist/adapter/body-marks.d.ts.map +1 -0
  6. package/dist/adapter/body-marks.js +62 -0
  7. package/dist/adapter/constraint.d.ts +41 -0
  8. package/dist/adapter/constraint.d.ts.map +1 -0
  9. package/dist/adapter/constraint.js +27 -0
  10. package/dist/adapter/hierarchy-marks.d.ts +138 -0
  11. package/dist/adapter/hierarchy-marks.d.ts.map +1 -0
  12. package/dist/adapter/hierarchy-marks.js +148 -0
  13. package/dist/adapter/index.d.ts +1 -1
  14. package/dist/adapter/index.d.ts.map +1 -1
  15. package/dist/adapter/ingest/contract-system-adapters.d.ts +64 -0
  16. package/dist/adapter/ingest/contract-system-adapters.d.ts.map +1 -0
  17. package/dist/adapter/ingest/contract-system-adapters.js +134 -0
  18. package/dist/adapter/ingest/game-contract.d.ts +87 -9
  19. package/dist/adapter/ingest/game-contract.d.ts.map +1 -1
  20. package/dist/adapter/ingest/game-contract.js +7 -6
  21. package/dist/adapter/ingest/scene-capture.d.ts +31 -4
  22. package/dist/adapter/ingest/scene-capture.d.ts.map +1 -1
  23. package/dist/adapter/ingest/scene-capture.js +29 -7
  24. package/dist/adapter/ingest/structural-ids.d.ts +1 -1
  25. package/dist/adapter/ingest/structural-ids.js +2 -2
  26. package/dist/adapter/reflection-probe.d.ts +53 -0
  27. package/dist/adapter/reflection-probe.d.ts.map +1 -0
  28. package/dist/adapter/reflection-probe.js +18 -0
  29. package/dist/asset-formats/index.d.ts +4 -10
  30. package/dist/asset-formats/index.d.ts.map +1 -1
  31. package/dist/asset-formats/index.js +3 -8
  32. package/dist/asset-formats/material.d.ts +0 -66
  33. package/dist/asset-formats/material.d.ts.map +1 -1
  34. package/dist/asset-formats/material.js +0 -8
  35. package/dist/asset-formats/mesh.d.ts +1 -2
  36. package/dist/asset-formats/mesh.d.ts.map +1 -1
  37. package/dist/asset-formats/mesh.js +3 -13
  38. package/dist/asset-formats/render-env.d.ts +2 -2
  39. package/dist/asset-parse-error.d.ts +4 -5
  40. package/dist/asset-parse-error.d.ts.map +1 -1
  41. package/dist/asset-parse-error.js +4 -5
  42. package/dist/config.d.ts +7 -0
  43. package/dist/config.d.ts.map +1 -1
  44. package/dist/config.js +7 -0
  45. package/dist/data/curve.d.ts +116 -0
  46. package/dist/data/curve.d.ts.map +1 -0
  47. package/dist/data/curve.js +230 -0
  48. package/dist/data/vite-plugin-data.d.ts +2 -2
  49. package/dist/data/vite-plugin-data.d.ts.map +1 -1
  50. package/dist/data/vite-plugin-data.js +24 -15
  51. package/dist/dev/performance-profiler.d.ts +1 -0
  52. package/dist/dev/performance-profiler.d.ts.map +1 -1
  53. package/dist/dev/performance-profiler.js +25 -2
  54. package/dist/ecs/user-data.d.ts +49 -1
  55. package/dist/ecs/user-data.d.ts.map +1 -1
  56. package/dist/ecs/user-data.js +34 -0
  57. package/dist/index.d.ts +2 -3
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +2 -3
  60. package/dist/manifest/index.d.ts +3 -3
  61. package/dist/manifest/index.d.ts.map +1 -1
  62. package/dist/manifest/index.js +2 -2
  63. package/dist/manifest/load.d.ts +15 -67
  64. package/dist/manifest/load.d.ts.map +1 -1
  65. package/dist/manifest/load.js +11 -103
  66. package/dist/manifest/schema.d.ts +18 -103
  67. package/dist/manifest/schema.d.ts.map +1 -1
  68. package/dist/manifest/schema.js +59 -179
  69. package/dist/pixi/index.d.ts +2 -3
  70. package/dist/pixi/index.d.ts.map +1 -1
  71. package/dist/pixi/index.js +2 -3
  72. package/dist/pixi/ingest.d.ts +7 -75
  73. package/dist/pixi/ingest.d.ts.map +1 -1
  74. package/dist/pixi/ingest.js +6 -14
  75. package/dist/pixi/scene-capture.d.ts +2 -2
  76. package/dist/pixi/scene-capture.js +2 -2
  77. package/dist/react/use-data.d.ts +10 -5
  78. package/dist/react/use-data.d.ts.map +1 -1
  79. package/dist/react/use-data.js +15 -15
  80. package/dist/render/viewport-shading.d.ts +1 -1
  81. package/dist/render/viewport-shading.d.ts.map +1 -1
  82. package/dist/render/viewport-shading.js +14 -0
  83. package/dist/runtime/create-runtime.d.ts +12 -0
  84. package/dist/runtime/create-runtime.d.ts.map +1 -1
  85. package/dist/runtime/create-runtime.js +7 -2
  86. package/dist/runtime/mount-game.d.ts +1 -1
  87. package/dist/runtime/mount-game.d.ts.map +1 -1
  88. package/dist/runtime/mount-manifest.d.ts.map +1 -1
  89. package/dist/runtime/mount-manifest.js +5 -1
  90. package/dist/world3d-react/r3f-adapter.d.ts.map +1 -1
  91. package/dist/world3d-react/r3f-adapter.js +69 -39
  92. package/dist/world3d-react/renderer-config.d.ts +15 -0
  93. package/dist/world3d-react/renderer-config.d.ts.map +1 -1
  94. package/dist/world3d-react/renderer-config.js +15 -0
  95. package/dist/world3d-react/world-context.d.ts +2 -1
  96. package/dist/world3d-react/world-context.d.ts.map +1 -1
  97. package/dist-config/config.js +140 -20
  98. package/dist-config/config.js.map +4 -4
  99. package/package.json +1 -1
  100. package/schemas/engine-capabilities.json +10 -10
  101. package/schemas/vgai-project.schema.json +21 -76
  102. package/src/adapter/authoring.ts +54 -31
  103. package/src/adapter/body-marks.ts +69 -0
  104. package/src/adapter/constraint.ts +71 -0
  105. package/src/adapter/hierarchy-marks.ts +155 -0
  106. package/src/adapter/index.ts +2 -3
  107. package/src/adapter/ingest/contract-system-adapters.ts +174 -0
  108. package/src/adapter/ingest/game-contract.ts +98 -9
  109. package/src/adapter/ingest/scene-capture.ts +61 -11
  110. package/src/adapter/ingest/structural-ids.ts +2 -2
  111. package/src/adapter/reflection-probe.ts +75 -0
  112. package/src/asset-formats/index.ts +4 -10
  113. package/src/asset-formats/material.ts +0 -11
  114. package/src/asset-formats/mesh.ts +3 -16
  115. package/src/asset-parse-error.ts +4 -5
  116. package/src/config.ts +13 -0
  117. package/src/data/curve.ts +263 -0
  118. package/src/data/vite-plugin-data.ts +48 -14
  119. package/src/dev/performance-profiler.ts +21 -2
  120. package/src/ecs/user-data.ts +50 -0
  121. package/src/index.ts +2 -3
  122. package/src/manifest/index.ts +3 -15
  123. package/src/manifest/load.ts +27 -143
  124. package/src/manifest/schema.ts +65 -223
  125. package/src/pixi/index.ts +2 -15
  126. package/src/pixi/ingest.ts +13 -87
  127. package/src/pixi/scene-capture.ts +2 -2
  128. package/src/react/use-data.ts +15 -20
  129. package/src/render/viewport-shading.ts +16 -1
  130. package/src/runtime/create-runtime.ts +30 -5
  131. package/src/runtime/mount-game.ts +1 -1
  132. package/src/runtime/mount-manifest.ts +5 -1
  133. package/src/world3d-react/r3f-adapter.tsx +73 -39
  134. package/src/world3d-react/renderer-config.ts +31 -0
  135. package/src/world3d-react/world-context.ts +2 -1
  136. package/dist/asset-formats/instances.d.ts +0 -17
  137. package/dist/asset-formats/instances.d.ts.map +0 -1
  138. package/dist/asset-formats/instances.js +0 -31
  139. package/dist/asset-formats/parse.d.ts +0 -20
  140. package/dist/asset-formats/parse.d.ts.map +0 -1
  141. package/dist/asset-formats/parse.js +0 -34
  142. package/dist/pixi/ingest-iframe.d.ts +0 -82
  143. package/dist/pixi/ingest-iframe.d.ts.map +0 -1
  144. package/dist/pixi/ingest-iframe.js +0 -166
  145. package/dist/render/instance-mesh.d.ts +0 -5
  146. package/dist/render/instance-mesh.d.ts.map +0 -1
  147. package/dist/render/instance-mesh.js +0 -19
  148. package/schemas/mat.schema.json +0 -255
  149. package/src/asset-formats/instances.ts +0 -38
  150. package/src/asset-formats/parse.ts +0 -39
  151. package/src/pixi/ingest-iframe.ts +0 -255
  152. package/src/render/instance-mesh.ts +0 -25
@@ -0,0 +1,148 @@
1
+ /**
2
+ * The hierarchy-presentation convention: how a game tells the editor which
3
+ * parts of its LIVE scene graph are one component instance, and which parts are
4
+ * implementation rather than content.
5
+ *
6
+ * ## Why marks and not a second tree
7
+ *
8
+ * The live tree IS the display surface. A hierarchy derived from source would
9
+ * be a mirror layer — a second model of the world that drifts from the one on
10
+ * screen — so the boundaries a reader needs have to live ON the nodes. That is
11
+ * what these marks are, and it is the whole mechanism: a component WRAPS its
12
+ * functionality and MARKS its root; the editor supports the convention
13
+ * generically and never learns which library, importer or lane produced the
14
+ * node.
15
+ *
16
+ * ## STRUCTURE IS THE TREE'S JOB. MARKS ONLY CLASSIFY.
17
+ *
18
+ * There is deliberately no mark that says "show this row somewhere else". A
19
+ * group owns its children by CONTAINING them; a prefab owns its parts by
20
+ * CONTAINING them. If an object reads as belonging under something it is not
21
+ * parented to, the tree is wrong and the tree is what to fix — because the
22
+ * panel is not the only reader. `getWorldPosition`, raycasting, disposal,
23
+ * `traverse`, every physics or gameplay walk and every person reading the
24
+ * source all follow real parenthood, and a presentation-only "logical parent"
25
+ * would be true for exactly one of them.
26
+ *
27
+ * The usual reason a world gets this wrong is that three's parent chain is a
28
+ * TRANSFORM chain: `matrixWorld` is unconditionally `parent × local`, so an
29
+ * object that must not inherit its owner's pose — a physics-driven body writing
30
+ * a world transform every step, a world-space trail or decal, a follow camera
31
+ * that must escape its target's rotation — gets mounted at the scene root, and
32
+ * ownership is lost as a side effect. **That trade is not necessary.** Set
33
+ * `object.matrixWorldAutoUpdate = false` (three r144+) and the parent's
34
+ * propagation skips it: the object stays parented where it belongs and its
35
+ * `matrixWorld` becomes yours to write. Keep it parented, own the matrix, and
36
+ * the hierarchy needs no help.
37
+ *
38
+ * These two marks then have exactly one job left, which is CLASSIFICATION:
39
+ * which of the objects that really are here is the game, and which is the
40
+ * machinery underneath it.
41
+ *
42
+ * ## What the hierarchy is FOR
43
+ *
44
+ * It shows YOUR GAME: the structure you authored, plus the objects your game
45
+ * makes while it runs. Nothing else. Three consequences, and every rule below
46
+ * follows from them:
47
+ *
48
+ * - **A spawned object is content.** A bullet you fired, a wave of enemies, a
49
+ * prop pulled out of a pool and parented into the level — these are rows.
50
+ * They exist, you can select them, and they are usually the exact things you
51
+ * opened the panel to look at. An object your game frees stops being a row,
52
+ * because it stopped existing.
53
+ * - **An implementation artifact is not.** The bones behind a rig, the batched
54
+ * renderer behind a particle system, the instanced-mesh pools behind a tile
55
+ * field, the `target` object three needs in order to aim a directional
56
+ * light: machinery a library or a helper builds so one thing you DID author
57
+ * can work. It belongs UNDER that thing, folded, not beside it.
58
+ * - **"Not in the source file" is the wrong test for either.** Half of a
59
+ * running world is not in the source file — that is what running means.
60
+ * Folding spawned gameplay because a document does not name it is the same
61
+ * defect as listing bones, in the more damaging direction: the rows it loses
62
+ * are the ones you were looking for.
63
+ *
64
+ * ## The two marks
65
+ *
66
+ * - {@link markComponentRoot} — "this subtree is one instance of `<name>`."
67
+ * The editor renders it as ONE row, closed, expandable on demand. Put it on
68
+ * the EARLIEST point the node exists: the constructor that makes it, or the
69
+ * ref callback that receives it. A component whose root is a plain `<mesh>`
70
+ * marks that mesh.
71
+ * - {@link markBuiltInternal} — "this is IMPLEMENTATION, not content." It is
72
+ * **subtree-scoped**: marking the root of a built subtree marks everything
73
+ * under it, so a 60-bone rig costs one call and folding is transitive. The
74
+ * editor hides these rows and offers them behind the same "Reveal Internals"
75
+ * action a source-backed instance's internals already use — revealed rows
76
+ * are read-only, because there is no authored source for a rename or a
77
+ * reparent to write to.
78
+ *
79
+ * An instance therefore reads as the parent of everything meaningful beneath
80
+ * it: content nested inside an implementation node is listed under the instance
81
+ * rather than lost with it (the editor's `hierarchy-component-marks.ts` calls
82
+ * that promotion), so marking a rig does not hide the mesh skinned to it.
83
+ *
84
+ * ## Mark it where the subtree is ATTACHED, by whoever attaches it
85
+ *
86
+ * A mark belongs at the attach seam: the code that puts an implementation
87
+ * subtree into the world marks it in the same breath, because that code is the
88
+ * only thing that knows the subtree is implementation. Not a later sweep of the
89
+ * tree — "everything present at time T that the source did not name" is the
90
+ * wrong predicate twice over. It arrives too early for anything attached
91
+ * asynchronously (a model clone landing after its bytes resolve, a node gated
92
+ * on an audio decode) and too late in principle for anything attached
93
+ * afterwards (every spawn) — and were it re-run to catch those, it would
94
+ * classify each spawned object as implementation, which is the second bullet
95
+ * above inverted. Attach-seam marking has neither failure: it fires once, at
96
+ * the moment the answer is known, and an unmarked node is content by default.
97
+ *
98
+ * The subtree scope is what keeps this cheap — one call per attached root, not
99
+ * one per node, so a rig or a pool costs one line at the one place that builds
100
+ * it.
101
+ *
102
+ * ## What is NOT built-internal
103
+ *
104
+ * A node your game means as content — even one a class rather than JSX
105
+ * constructs — is content. `vgaiBuiltInternal` is not "the editor cannot write
106
+ * this"; that question is `TransformProvider.editability`'s, answered per
107
+ * channel with a sentence. This mark answers "is this implementation", and
108
+ * getting it wrong hides real content.
109
+ *
110
+ * Both keys live in the typed `userData` registry (`../ecs/user-data.ts`) so
111
+ * their literal strings are spelled exactly once; this module is the only
112
+ * reader/writer, which is why the helpers below exist at all rather than
113
+ * `setUserData` calls scattered through emitters and prefabs.
114
+ */
115
+ import { getUserData, setUserData } from '../ecs/user-data';
116
+ /**
117
+ * Declare `node` the root of one component instance, displayed under `name`.
118
+ *
119
+ * `name` is the COMPONENT's name (`'Coin'`, `'HeroBox'`), not the instance's —
120
+ * the instance is already named by `node.name`, and the editor prints both.
121
+ */
122
+ export function markComponentRoot(node, name) {
123
+ setUserData(node, 'vgaiComponentRoot', name);
124
+ }
125
+ /** The component name `node` is the root of, or `undefined` for an ordinary node. */
126
+ export function componentRootName(node) {
127
+ const name = getUserData(node, 'vgaiComponentRoot');
128
+ return typeof name === 'string' && name ? name : undefined;
129
+ }
130
+ /** Whether `node` is a marked component-instance root. */
131
+ export function isComponentRoot(node) {
132
+ return componentRootName(node) !== undefined;
133
+ }
134
+ /**
135
+ * Declare `node` (and everything under it) IMPLEMENTATION of whatever node it
136
+ * sits under, rather than content of its own. Call it on the ROOT of the built
137
+ * subtree only, at the seam that attaches it — see this module's header for why
138
+ * the seam and not a sweep.
139
+ */
140
+ export function markBuiltInternal(node) {
141
+ setUserData(node, 'vgaiBuiltInternal', true);
142
+ }
143
+ /** Whether `node` itself carries the implementation mark. Ancestry is the
144
+ * CALLER's walk — see this module's header for why the mark is subtree-scoped
145
+ * but not restamped onto descendants. */
146
+ export function isBuiltInternal(node) {
147
+ return getUserData(node, 'vgaiBuiltInternal') === true;
148
+ }
@@ -23,7 +23,7 @@
23
23
  * `@engine/adapter/first-party-systems` createNavigationAdapter
24
24
  */
25
25
  export type { AdapterSurface } from './adapter-surface';
26
- export type { AssetDropContext, AssetDropProvider, AssetSubjectProvider, AuthoringAdapter, AuthoringAssetSubject, AuthoringCapabilities, AuthoringProvenance, BoxEditProvider, BoxEditReferencePoint, ColorSampleProvider, CreationSiteProvider, DOMRectLike, EditorNode, EditorNodeRole, FileMapProvider, HierarchyProvider, InspectorProvider, NodeCreationSite, PersistenceProvider, PickProvider, PropertyDescriptor, RectProvider, RootGroup, RootGroupsProvider, SelectionProvider, SelectionResolution, StoriesProvider, StoryRef, StructureProvider, TextProvider, TransformChannel, TransformEditability, TransformObservation, TransformProvider, } from './authoring';
26
+ export type { AssetDropContext, AssetDropProvider, AssetSubjectProvider, AuthoringAdapter, AuthoringAssetSubject, AuthoringCapabilities, AuthoringProvenance, BoxEditProvider, BoxEditReferencePoint, ColorSampleProvider, CreationSiteProvider, DOMRectLike, EditorNode, EditorNodeRole, HierarchyProvider, InspectorProvider, NodeCreationSite, PersistenceProvider, PickProvider, PropertyDescriptor, RectProvider, RelatedSubjectLink, RelatedSubjectsProvider, SelectionProvider, SelectionResolution, StoriesProvider, StoryRef, StructureProvider, TextProvider, TransformChannel, TransformEditability, TransformObservation, TransformProvider, } from './authoring';
27
27
  export type { ColyseusNetworkingConfig } from './colyseus-networking-adapter';
28
28
  export type { CanvasHostContext, DomHostContext, HostContextBase, HostContextFor, HostSurface, ThreeHostContext, } from './host-context';
29
29
  export type { MountedPixiRoot, MountedReactRoot, MountedRoot, MountedRootBase, MountedThreeRoot, RootAdapter, RootStateObserver, SurfaceAdapter, SurfaceAdapterFor, } from './root-adapter';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapter/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,YAAY,EACV,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,EACrB,mBAAmB,EACnB,eAAe,EACf,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,WAAW,EACX,UAAU,EACV,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,SAAS,EACT,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,EACf,QAAQ,EACR,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAC9E,YAAY,EACV,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,cAAc,EACd,WAAW,EACX,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,WAAW,EACX,eAAe,EACf,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EACjB,cAAc,EACd,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAC9F,YAAY,EACV,YAAY,EACZ,eAAe,EACf,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,QAAQ,EACR,eAAe,EACf,eAAe,EACf,OAAO,EACP,iBAAiB,EACjB,QAAQ,EACR,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,QAAQ,EACR,cAAc,EACd,WAAW,GACZ,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapter/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,YAAY,EACV,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,EACrB,mBAAmB,EACnB,eAAe,EACf,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,WAAW,EACX,UAAU,EACV,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,kBAAkB,EAClB,uBAAuB,EACvB,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,EACf,QAAQ,EACR,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAC9E,YAAY,EACV,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,cAAc,EACd,WAAW,EACX,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,WAAW,EACX,eAAe,EACf,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EACjB,cAAc,EACd,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAC9F,YAAY,EACV,YAAY,EACZ,eAAe,EACf,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,QAAQ,EACR,eAAe,EACf,eAAe,EACf,OAAO,EACP,iBAAiB,EACjB,QAAQ,EACR,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,QAAQ,EACR,cAAc,EACd,WAAW,GACZ,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Projects a game's declared {@link VgaiGameSystemAdapters}
3
+ * (`window.vgaiGame.systems.systemAdapters`) onto the host's ordinary
4
+ * {@link SystemAdapters} bag — the ingest-realm counterpart of a first-party
5
+ * world's `ctx.registerSystemAdapter`, and the sibling of
6
+ * `contract-debug-adapter.ts` (which owns the `debug` slot).
7
+ *
8
+ * ## Why a projection with a verdict per slot
9
+ *
10
+ * The ingestion bar (docs/BRINGING-AN-EXISTING-GAME.md §The ingestion
11
+ * checklist) admits exactly two terminal states per slot: IMPLEMENTED or
12
+ * IMPLEMENTED-EMPTY. `SystemAdapters` alone cannot express the second — an
13
+ * omitted key means "unsupported", which is the same shape as "nobody looked".
14
+ * So this returns THREE lists, and the caller hands the non-`bound` ones to the
15
+ * coverage report, where a positively-answered absence prints as terminal and an
16
+ * unanswered slot prints as a work order.
17
+ *
18
+ * ## Why the shape check
19
+ *
20
+ * A slot that declares `{}` would otherwise register as "implemented" and light
21
+ * up an editor panel over an object with no methods. Each slot therefore names
22
+ * the members its interface makes REQUIRED, and a declaration missing any of
23
+ * them is `malformed` — reported by name, never silently bound and never
24
+ * silently dropped. This is the same honesty the anti-shim rule asks of the
25
+ * other direction: a wrong "present" claim is as much a defect as a wrong
26
+ * "empty" one.
27
+ *
28
+ * Nothing here calls a declared method. Presence and shape only.
29
+ */
30
+ import type { SystemAdapters } from '../system-adapter';
31
+ import type { VgaiGameSystemAdapters, VgaiGameSystems } from './game-contract';
32
+ /** The slots a game may declare through the contract (`debug` is projected from
33
+ * `commands`/`state` instead — see {@link VgaiGameSystemAdapters}). */
34
+ export type ContractSystemSlot = keyof VgaiGameSystemAdapters;
35
+ /** Fixed slot order, so two reports of the same mount are diffable line for
36
+ * line (the same rule the coverage report's row order follows). */
37
+ export declare const CONTRACT_SYSTEM_SLOTS: readonly ContractSystemSlot[];
38
+ /** One slot the game positively answered as having nothing behind it. */
39
+ export interface ContractSystemEmptySlot {
40
+ readonly slot: ContractSystemSlot;
41
+ /** The game's own source-level evidence, verbatim. */
42
+ readonly evidence: string;
43
+ }
44
+ /** One slot whose declaration could not be honoured, and why. */
45
+ export interface ContractSystemMalformedSlot {
46
+ readonly slot: ContractSystemSlot;
47
+ readonly reason: string;
48
+ }
49
+ export interface ContractSystemAdapterProjection {
50
+ /** Real adapters, ready to spread onto a `MountedRoot`'s `systems`. */
51
+ readonly bound: Partial<Pick<SystemAdapters, ContractSystemSlot>>;
52
+ /** Slots answered IMPLEMENTED-EMPTY, with the evidence. */
53
+ readonly empty: readonly ContractSystemEmptySlot[];
54
+ /** Slots declared but unusable — bound to nothing, reported by name. */
55
+ readonly malformed: readonly ContractSystemMalformedSlot[];
56
+ }
57
+ /**
58
+ * Read the declared slots and sort each into exactly one verdict. A game that
59
+ * declared no `systemAdapters` at all projects to three empty lists — which is
60
+ * the "nobody answered" case, and is deliberately NOT the same as declaring
61
+ * every slot empty.
62
+ */
63
+ export declare function projectContractSystemAdapters(systems: VgaiGameSystems | undefined | null): ContractSystemAdapterProjection;
64
+ //# sourceMappingURL=contract-system-adapters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract-system-adapters.d.ts","sourceRoot":"","sources":["../../../src/adapter/ingest/contract-system-adapters.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAE,sBAAsB,EAAuB,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEpG;wEACwE;AACxE,MAAM,MAAM,kBAAkB,GAAG,MAAM,sBAAsB,CAAC;AA8B9D;oEACoE;AACpE,eAAO,MAAM,qBAAqB,EAAE,SAAS,kBAAkB,EAM9D,CAAC;AAEF,yEAAyE;AACzE,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAClC,sDAAsD;IACtD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,iEAAiE;AACjE,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,+BAA+B;IAC9C,uEAAuE;IACvE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC,CAAC;IAClE,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,EAAE,SAAS,uBAAuB,EAAE,CAAC;IACnD,wEAAwE;IACxE,QAAQ,CAAC,SAAS,EAAE,SAAS,2BAA2B,EAAE,CAAC;CAC5D;AAsBD;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,eAAe,GAAG,SAAS,GAAG,IAAI,GAC1C,+BAA+B,CAgDjC"}
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Projects a game's declared {@link VgaiGameSystemAdapters}
3
+ * (`window.vgaiGame.systems.systemAdapters`) onto the host's ordinary
4
+ * {@link SystemAdapters} bag — the ingest-realm counterpart of a first-party
5
+ * world's `ctx.registerSystemAdapter`, and the sibling of
6
+ * `contract-debug-adapter.ts` (which owns the `debug` slot).
7
+ *
8
+ * ## Why a projection with a verdict per slot
9
+ *
10
+ * The ingestion bar (docs/BRINGING-AN-EXISTING-GAME.md §The ingestion
11
+ * checklist) admits exactly two terminal states per slot: IMPLEMENTED or
12
+ * IMPLEMENTED-EMPTY. `SystemAdapters` alone cannot express the second — an
13
+ * omitted key means "unsupported", which is the same shape as "nobody looked".
14
+ * So this returns THREE lists, and the caller hands the non-`bound` ones to the
15
+ * coverage report, where a positively-answered absence prints as terminal and an
16
+ * unanswered slot prints as a work order.
17
+ *
18
+ * ## Why the shape check
19
+ *
20
+ * A slot that declares `{}` would otherwise register as "implemented" and light
21
+ * up an editor panel over an object with no methods. Each slot therefore names
22
+ * the members its interface makes REQUIRED, and a declaration missing any of
23
+ * them is `malformed` — reported by name, never silently bound and never
24
+ * silently dropped. This is the same honesty the anti-shim rule asks of the
25
+ * other direction: a wrong "present" claim is as much a defect as a wrong
26
+ * "empty" one.
27
+ *
28
+ * Nothing here calls a declared method. Presence and shape only.
29
+ */
30
+ /**
31
+ * The members each slot's interface makes NON-optional. A declaration missing
32
+ * one of these cannot honour the interface, whatever else it carries.
33
+ *
34
+ * This table is the single place the required surface is spelled; it is checked
35
+ * against the interfaces by the compiler at the point of use below (each list
36
+ * is typed as keys of its own adapter), so it cannot drift into naming a member
37
+ * that does not exist.
38
+ */
39
+ const REQUIRED_MEMBERS = {
40
+ physics: ['ownerOf', 'freeze', 'commit', 'unfreeze'],
41
+ networking: [
42
+ 'peers',
43
+ 'networkId',
44
+ 'authority',
45
+ 'editable',
46
+ 'getConnectionState',
47
+ 'getRoomInfo',
48
+ 'getReplicationStats',
49
+ 'subscribe',
50
+ ],
51
+ navigation: ['hasNavMesh', 'findPath', 'debugMesh'],
52
+ audio: ['setMuted', 'isMuted'],
53
+ renderDebug: ['captureFrame'],
54
+ };
55
+ /** Fixed slot order, so two reports of the same mount are diffable line for
56
+ * line (the same rule the coverage report's row order follows). */
57
+ export const CONTRACT_SYSTEM_SLOTS = [
58
+ 'physics',
59
+ 'networking',
60
+ 'navigation',
61
+ 'audio',
62
+ 'renderDebug',
63
+ ];
64
+ const EMPTY_PROJECTION = {
65
+ bound: {},
66
+ empty: [],
67
+ malformed: [],
68
+ };
69
+ function isEmptyRecord(value) {
70
+ return value.present === false;
71
+ }
72
+ function missingMembers(slot, value) {
73
+ const missing = [];
74
+ for (const member of REQUIRED_MEMBERS[slot]) {
75
+ if (typeof value[member] !== 'function') {
76
+ missing.push(member);
77
+ }
78
+ }
79
+ return missing;
80
+ }
81
+ /**
82
+ * Read the declared slots and sort each into exactly one verdict. A game that
83
+ * declared no `systemAdapters` at all projects to three empty lists — which is
84
+ * the "nobody answered" case, and is deliberately NOT the same as declaring
85
+ * every slot empty.
86
+ */
87
+ export function projectContractSystemAdapters(systems) {
88
+ const declared = systems?.systemAdapters;
89
+ if (!declared)
90
+ return EMPTY_PROJECTION;
91
+ const bound = {};
92
+ const empty = [];
93
+ const malformed = [];
94
+ for (const slot of CONTRACT_SYSTEM_SLOTS) {
95
+ const value = declared[slot];
96
+ if (value === undefined || value === null)
97
+ continue;
98
+ if (typeof value !== 'object') {
99
+ malformed.push({
100
+ slot,
101
+ reason: `declared as ${typeof value}; expected an adapter object or { present: false, evidence }`,
102
+ });
103
+ continue;
104
+ }
105
+ if (isEmptyRecord(value)) {
106
+ const evidence = value.evidence;
107
+ if (typeof evidence !== 'string' || evidence.trim() === '') {
108
+ // An empty claim with no evidence is exactly the "wrong empty claim"
109
+ // the bar calls a defect — it asserts an absence nobody can re-check.
110
+ malformed.push({
111
+ slot,
112
+ reason: 'declared `present: false` with no `evidence` string to back the absence',
113
+ });
114
+ continue;
115
+ }
116
+ empty.push({ slot, evidence });
117
+ continue;
118
+ }
119
+ const missing = missingMembers(slot, value);
120
+ if (missing.length > 0) {
121
+ malformed.push({
122
+ slot,
123
+ reason: `declared an adapter missing required member(s): ${missing.join(', ')}`,
124
+ });
125
+ continue;
126
+ }
127
+ bound[slot] = value;
128
+ }
129
+ return {
130
+ bound: bound,
131
+ empty,
132
+ malformed,
133
+ };
134
+ }
@@ -15,8 +15,10 @@
15
15
  * endpoint by endpoint: capture infers what it can (the scene), the game
16
16
  * declares what inference can't reach (its DOM root, its session lifecycle).
17
17
  *
18
- * Origin (root), F17+F21 (lifecycle), WO-SYS1 (systems).
18
+ * Origin (root), F17+F21 (lifecycle), WO-SYS1 (systems), WO-SYS2
19
+ * (`systems.systemAdapters`).
19
20
  */
21
+ import type { AudioAdapter, NavigationAdapter, NetworkingAdapter, PhysicsAdapter, RenderDebugAdapter } from '../system-adapter';
20
22
  /**
21
23
  * Session lifecycle endpoints. Declaring `start` means "I support cold
22
24
  * mount": when the host sets `window.__vgaiMountCold` before the game's entry
@@ -62,6 +64,27 @@ export interface VgaiGameStateProvider {
62
64
  tier?: 'observable' | 'assisted';
63
65
  read(): unknown;
64
66
  }
67
+ /**
68
+ * One top-level semantic hierarchy group from the game's OWN model. `count`
69
+ * is recomputed by the game when the host reads the hierarchy; it is not
70
+ * inferred from render objects. The editor presents these rows beside the
71
+ * captured render tree, so a system-driven game can say what its content is
72
+ * without pretending its scene graph is authored truth.
73
+ */
74
+ export interface VgaiGameHierarchyGroup {
75
+ id: string;
76
+ label: string;
77
+ count: number;
78
+ }
79
+ /**
80
+ * Synchronous read plus an optional game-owned invalidation signal. The
81
+ * editor never polls or guesses when a game's model changed; a dynamic game
82
+ * subscribes its ordinary authoring hierarchy to the same truth it reads.
83
+ */
84
+ export interface VgaiGameHierarchyProvider {
85
+ (): VgaiGameHierarchyGroup[];
86
+ subscribe?(listener: () => void): () => void;
87
+ }
65
88
  /**
66
89
  * The game's SYSTEM surface: what its content actually IS, as opposed to how
67
90
  * it renders. An ingested game's content is not always its scene graph — in a
@@ -69,9 +92,10 @@ export interface VgaiGameStateProvider {
69
92
  * is reached through the game's own verbs, which `root`/`lifecycle` could not
70
93
  * express.
71
94
  *
72
- * Both members are read by exactly one consumer,
73
- * `adapter/ingest/contract-debug-adapter.ts`, which projects them onto the
74
- * host's ordinary `DebugAdapter` (`adapter/system-adapter.ts`) so
95
+ * Every member is read by a concrete consumer: commands/state are projected
96
+ * by `adapter/ingest/contract-debug-adapter.ts` onto the host's ordinary
97
+ * `DebugAdapter` (`adapter/system-adapter.ts`), while `hierarchy` is projected
98
+ * by the editor onto the ordinary `AuthoringAdapter.hierarchy` surface. Thus
75
99
  * `game.commands()`/`game.state()` reach an ingested game through the same
76
100
  * bridge first-party content uses, with no second vocabulary for agents to
77
101
  * learn. That is deliberate scope: this
@@ -84,6 +108,60 @@ export interface VgaiGameSystems {
84
108
  commands?: VgaiGameCommand[];
85
109
  /** State reads, enumerated by `game.providers()` and read by `game.state(...)`. */
86
110
  state?: VgaiGameStateProvider[];
111
+ /** Semantic hierarchy groups from the game's own model, recomputed on read. */
112
+ hierarchy?: VgaiGameHierarchyProvider;
113
+ /**
114
+ * The game's own {@link SystemAdapters} slots — the ingest-realm equivalent
115
+ * of a first-party world's `ctx.registerSystemAdapter`. Read and projected by
116
+ * `contract-system-adapters.ts` onto the mounted root's `systems` bag, so an
117
+ * ingested game's physics/audio/navigation/networking reach the editor's
118
+ * ordinary panels through the SAME registry a native world publishes to.
119
+ */
120
+ systemAdapters?: VgaiGameSystemAdapters;
121
+ }
122
+ /**
123
+ * A slot's IMPLEMENTED-EMPTY answer: "this game genuinely has no X", carried
124
+ * with the source-level evidence that establishes it.
125
+ *
126
+ * This exists because `SystemAdapters` is capability-by-PRESENCE, and presence
127
+ * has only two values while the ingestion bar (docs/BRINGING-AN-EXISTING-GAME.md
128
+ * §The ingestion checklist) has three inputs: bound, positively-absent, and
129
+ * not-yet-answered. Omitting a slot cannot tell the last two apart — an editor
130
+ * reading a bare absence cannot know whether anyone ever looked. Declaring this
131
+ * record says someone looked, says what they found, and turns a work-order row
132
+ * into a terminal one.
133
+ *
134
+ * It is deliberately NOT an adapter whose methods return zeros: a
135
+ * `getConnectionState()` of `'disconnected'` on a game with no transport at all
136
+ * is a fabrication (it implies a connection that could exist), which the
137
+ * anti-shim rule forbids. The absence is stated, never simulated.
138
+ */
139
+ export interface VgaiGameSystemEmpty {
140
+ /** Always `false` — the discriminant that separates this from an adapter. */
141
+ present: false;
142
+ /**
143
+ * Why the slot is empty, in SOURCE terms: what was searched and what was
144
+ * found. "no netcode anywhere in `src/`" is a finished answer; "not
145
+ * implemented yet" is not one, and a reviewer reading this field is meant to
146
+ * be able to re-run the search.
147
+ */
148
+ evidence: string;
149
+ }
150
+ /**
151
+ * The declarable `SystemAdapters` slots, each either a real implementation or a
152
+ * positively-answered {@link VgaiGameSystemEmpty}.
153
+ *
154
+ * `debug` is deliberately NOT here: it is already the projection of
155
+ * `commands`/`state` above (`contract-debug-adapter.ts`), and a second door onto
156
+ * the same slot would let a game declare two different debug planes with no rule
157
+ * for which wins.
158
+ */
159
+ export interface VgaiGameSystemAdapters {
160
+ physics?: PhysicsAdapter | VgaiGameSystemEmpty;
161
+ networking?: NetworkingAdapter | VgaiGameSystemEmpty;
162
+ navigation?: NavigationAdapter | VgaiGameSystemEmpty;
163
+ audio?: AudioAdapter | VgaiGameSystemEmpty;
164
+ renderDebug?: RenderDebugAdapter | VgaiGameSystemEmpty;
87
165
  }
88
166
  export interface VgaiGameContract {
89
167
  /** Bump only on breaking shape changes; additive endpoints keep version 1. */
@@ -108,11 +186,11 @@ export interface VgaiGameContract {
108
186
  * forward-compatibility hinge: a future v2 game on a v1 host is ignored
109
187
  * (pre-contract fallbacks apply) rather than half-interpreted.
110
188
  *
111
- * `scope` is the REALM to read from, and defaults to this module's own `window`
112
- * — correct for a same-realm mount, where the game's modules and the host share
113
- * one global. An iframe-hosted game declares on ITS realm's window, so the host
114
- * passes `iframe.contentWindow`: the contract is a property of the realm the
115
- * game runs in, never of the realm that happens to be asking.
189
+ * `scope` is the REALM to read from, and defaults to this module's own
190
+ * `window` the realm every ingest mount runs the game's modules in, where the
191
+ * game and the host share one global. It is a parameter at all because the
192
+ * contract is a property of the realm the game runs in, never of the realm that
193
+ * happens to be asking.
116
194
  */
117
195
  export declare function readGameContract(scope?: Window | null | undefined): VgaiGameContract | null;
118
196
  //# sourceMappingURL=game-contract.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"game-contract.d.ts","sourceRoot":"","sources":["../../../src/adapter/ingest/game-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH;;;;;;;;;GASG;AACH,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,IAAI,IAAI,CAAC;IACf,KAAK,CAAC,IAAI,IAAI,CAAC;IACf,MAAM,CAAC,IAAI,IAAI,CAAC;CACjB;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+EAA+E;IAC/E,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACrD;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IACjC,IAAI,IAAI,OAAO,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,eAAe;IAC9B,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,eAAe,EAAE,CAAC;IAC7B,mFAAmF;IACnF,KAAK,CAAC,EAAE,qBAAqB,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,gBAAgB;IAC/B,8EAA8E;IAC9E,eAAe,EAAE,CAAC,CAAC;IACnB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B;;;;OAIG;IACH,OAAO,CAAC,EAAE,eAAe,CAAC;CAC3B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,GAAE,MAAM,GAAG,IAAI,GAAG,SAAyD,GAC/E,gBAAgB,GAAG,IAAI,CAKzB"}
1
+ {"version":3,"file":"game-contract.d.ts","sourceRoot":"","sources":["../../../src/adapter/ingest/game-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EACnB,MAAM,mBAAmB,CAAC;AAE3B;;;;;;;;;GASG;AACH,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,IAAI,IAAI,CAAC;IACf,KAAK,CAAC,IAAI,IAAI,CAAC;IACf,MAAM,CAAC,IAAI,IAAI,CAAC;CACjB;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+EAA+E;IAC/E,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACrD;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IACjC,IAAI,IAAI,OAAO,CAAC;CACjB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,MAAM,WAAW,yBAAyB;IACxC,IAAI,sBAAsB,EAAE,CAAC;IAC7B,SAAS,CAAC,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;CAC9C;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,eAAe;IAC9B,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,eAAe,EAAE,CAAC;IAC7B,mFAAmF;IACnF,KAAK,CAAC,EAAE,qBAAqB,EAAE,CAAC;IAChC,+EAA+E;IAC/E,SAAS,CAAC,EAAE,yBAAyB,CAAC;IACtC;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,sBAAsB,CAAC;CACzC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,mBAAmB;IAClC,6EAA6E;IAC7E,OAAO,EAAE,KAAK,CAAC;IACf;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,sBAAsB;IACrC,OAAO,CAAC,EAAE,cAAc,GAAG,mBAAmB,CAAC;IAC/C,UAAU,CAAC,EAAE,iBAAiB,GAAG,mBAAmB,CAAC;IACrD,UAAU,CAAC,EAAE,iBAAiB,GAAG,mBAAmB,CAAC;IACrD,KAAK,CAAC,EAAE,YAAY,GAAG,mBAAmB,CAAC;IAC3C,WAAW,CAAC,EAAE,kBAAkB,GAAG,mBAAmB,CAAC;CACxD;AAED,MAAM,WAAW,gBAAgB;IAC/B,8EAA8E;IAC9E,eAAe,EAAE,CAAC,CAAC;IACnB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B;;;;OAIG;IACH,OAAO,CAAC,EAAE,eAAe,CAAC;CAC3B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,GAAE,MAAM,GAAG,IAAI,GAAG,SAAyD,GAC/E,gBAAgB,GAAG,IAAI,CAKzB"}
@@ -15,18 +15,19 @@
15
15
  * endpoint by endpoint: capture infers what it can (the scene), the game
16
16
  * declares what inference can't reach (its DOM root, its session lifecycle).
17
17
  *
18
- * Origin (root), F17+F21 (lifecycle), WO-SYS1 (systems).
18
+ * Origin (root), F17+F21 (lifecycle), WO-SYS1 (systems), WO-SYS2
19
+ * (`systems.systemAdapters`).
19
20
  */
20
21
  /**
21
22
  * Read the declared contract, if any. The `contractVersion` gate is the
22
23
  * forward-compatibility hinge: a future v2 game on a v1 host is ignored
23
24
  * (pre-contract fallbacks apply) rather than half-interpreted.
24
25
  *
25
- * `scope` is the REALM to read from, and defaults to this module's own `window`
26
- * — correct for a same-realm mount, where the game's modules and the host share
27
- * one global. An iframe-hosted game declares on ITS realm's window, so the host
28
- * passes `iframe.contentWindow`: the contract is a property of the realm the
29
- * game runs in, never of the realm that happens to be asking.
26
+ * `scope` is the REALM to read from, and defaults to this module's own
27
+ * `window` the realm every ingest mount runs the game's modules in, where the
28
+ * game and the host share one global. It is a parameter at all because the
29
+ * contract is a property of the realm the game runs in, never of the realm that
30
+ * happens to be asking.
30
31
  */
31
32
  export function readGameContract(scope = typeof window === 'undefined' ? null : window) {
32
33
  const declared = scope
@@ -67,11 +67,11 @@ export interface SceneCaptureOptions {
67
67
  * each with its own offscreen renderer and its own little light rig) is a
68
68
  * candidate to be captured AS THE GAME.
69
69
  *
70
- * That is what made `cov-mismatched-three` — the spec for "a game bundling
71
- * its own three is DETECTED and degrades to embed-only, never silently"
70
+ * That is what made the "a game bundling its own three is DETECTED, never
71
+ * silently mistaken for a capture" spec
72
72
  * pass or fail on timing alone: whether a thumbnail happened to bake inside
73
- * the game's 2.5s capture window. When it did, the editor adopted its own
74
- * preview scene as the game and `captureFailed` never fired.
73
+ * the game's capture window. When it did, the editor adopted its own
74
+ * preview scene as the game and the mount reported success.
75
75
  *
76
76
  * Identity, not shape, is the discriminator: a host renderer and a game
77
77
  * renderer are the same class, both built after install, both drawing real
@@ -80,10 +80,37 @@ export interface SceneCaptureOptions {
80
80
  */
81
81
  isHostRenderer?: (renderer: unknown) => boolean;
82
82
  }
83
+ /**
84
+ * Brackets ONE `render()` call the captured renderer makes.
85
+ *
86
+ * The trap already stands between an ingested game and its own
87
+ * `WebGLRenderer.render`, which is the only place a host can see the game's
88
+ * render pass begin and end — the game owns its loop, so nothing else in the
89
+ * editor gets a `finally` around it. That is exactly the bracket
90
+ * `dev/render-debug-adapter.ts`'s `beforeRender`/`afterRender` need, so the
91
+ * first-party `RenderDebugAdapter` works for an ingested game with no per-game
92
+ * shimming and no second capture mechanism.
93
+ *
94
+ * Neither hook may throw: they run inside the game's own render call, so an
95
+ * exception here would break the game's frame. The trap calls them in a
96
+ * `try`/`finally` for `after`, but a throwing `before` is the hook author's bug.
97
+ */
98
+ export interface RenderPassHooks {
99
+ before(): void;
100
+ after(): void;
101
+ }
83
102
  /** Handle returned by {@link installSceneCapture}. */
84
103
  export interface SceneCaptureHandle {
85
104
  /** The captured runtime, or null until the game renders its first frame. */
86
105
  readonly captured: CapturedRuntime | null;
106
+ /**
107
+ * Install (or clear, with `null`) hooks bracketing every `render()` the
108
+ * CAPTURED renderer makes. Set AFTER capture, because the consumer
109
+ * (`RenderDebugAdapter`) is built from the captured scene and context. Only
110
+ * the captured renderer's renders are bracketed — the editor's own viewport
111
+ * renders come through the same trap and are not the game's frame.
112
+ */
113
+ setRenderPassHooks(hooks: RenderPassHooks | null): void;
87
114
  /** Resolve once a scene+camera is captured (rejects on timeout). */
88
115
  waitForCapture(timeoutMs?: number): Promise<CapturedRuntime>;
89
116
  /** Total `render()` calls observed through the trap (a liveness signal). */
@@ -1 +1 @@
1
- {"version":3,"file":"scene-capture.d.ts","sourceRoot":"","sources":["../../../src/adapter/ingest/scene-capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAEpC,iFAAiF;AACjF,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;IACnB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC;IACrB,QAAQ,EAAE,KAAK,CAAC,aAAa,CAAC;CAC/B;AAED,+CAA+C;AAC/C,MAAM,WAAW,mBAAmB;IAClC;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,OAAO,CAAC;CACjD;AAED,sDAAsD;AACtD,MAAM,WAAW,kBAAkB;IACjC,4EAA4E;IAC5E,QAAQ,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;IAC1C,oEAAoE;IACpE,cAAc,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAC7D,4EAA4E;IAC5E,YAAY,IAAI,MAAM,CAAC;IACvB;gFAC4E;IAC5E,gBAAgB,CAAC,QAAQ,EAAE,KAAK,CAAC,aAAa,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC;IACjF;;;;;;;;OAQG;IACH,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,yEAAyE;IACzE,SAAS,IAAI,IAAI,CAAC;CACnB;AAsBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CACjC,cAAc,EAAE,OAAO,EACvB,kBAAkB,CAAC,EAAE,OAAO,EAC5B,IAAI,CAAC,EAAE,mBAAmB,GACzB,kBAAkB,CA8MpB"}
1
+ {"version":3,"file":"scene-capture.d.ts","sourceRoot":"","sources":["../../../src/adapter/ingest/scene-capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAEpC,iFAAiF;AACjF,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;IACnB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC;IACrB,QAAQ,EAAE,KAAK,CAAC,aAAa,CAAC;CAC/B;AAED,+CAA+C;AAC/C,MAAM,WAAW,mBAAmB;IAClC;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,OAAO,CAAC;CACjD;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,eAAe;IAC9B,MAAM,IAAI,IAAI,CAAC;IACf,KAAK,IAAI,IAAI,CAAC;CACf;AAED,sDAAsD;AACtD,MAAM,WAAW,kBAAkB;IACjC,4EAA4E;IAC5E,QAAQ,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;IAC1C;;;;;;OAMG;IACH,kBAAkB,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,GAAG,IAAI,CAAC;IACxD,oEAAoE;IACpE,cAAc,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAC7D,4EAA4E;IAC5E,YAAY,IAAI,MAAM,CAAC;IACvB;gFAC4E;IAC5E,gBAAgB,CAAC,QAAQ,EAAE,KAAK,CAAC,aAAa,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC;IACjF;;;;;;;;OAQG;IACH,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,yEAAyE;IACzE,SAAS,IAAI,IAAI,CAAC;CACnB;AAsBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CACjC,cAAc,EAAE,OAAO,EACvB,kBAAkB,CAAC,EAAE,OAAO,EAC5B,IAAI,CAAC,EAAE,mBAAmB,GACzB,kBAAkB,CAoOpB"}