@vgai/engine 0.5.13 → 0.5.14

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 (192) hide show
  1. package/dist/adapter/adapter-module.d.ts +447 -0
  2. package/dist/adapter/adapter-module.d.ts.map +1 -0
  3. package/dist/adapter/adapter-module.js +308 -0
  4. package/dist/adapter/authoring.d.ts +357 -10
  5. package/dist/adapter/authoring.d.ts.map +1 -1
  6. package/dist/adapter/authoring.js +87 -1
  7. package/dist/adapter/constraint.d.ts +9 -3
  8. package/dist/adapter/constraint.d.ts.map +1 -1
  9. package/dist/adapter/finders/finder-result.d.ts +28 -0
  10. package/dist/adapter/finders/finder-result.d.ts.map +1 -0
  11. package/dist/adapter/finders/finder-result.js +10 -0
  12. package/dist/adapter/finders/index.d.ts +38 -0
  13. package/dist/adapter/finders/index.d.ts.map +1 -0
  14. package/dist/adapter/finders/index.js +41 -0
  15. package/dist/adapter/finders/prefabs-from-stories.d.ts +64 -0
  16. package/dist/adapter/finders/prefabs-from-stories.d.ts.map +1 -0
  17. package/dist/adapter/finders/prefabs-from-stories.js +92 -0
  18. package/dist/adapter/finders/scenes-from-entrypoint-selection.d.ts +67 -0
  19. package/dist/adapter/finders/scenes-from-entrypoint-selection.d.ts.map +1 -0
  20. package/dist/adapter/finders/scenes-from-entrypoint-selection.js +226 -0
  21. package/dist/adapter/first-party-systems.d.ts.map +1 -1
  22. package/dist/adapter/first-party-systems.js +29 -0
  23. package/dist/adapter/index.d.ts +7 -3
  24. package/dist/adapter/index.d.ts.map +1 -1
  25. package/dist/adapter/index.js +5 -2
  26. package/dist/adapter/ingest/contract-system-adapters.d.ts +24 -1
  27. package/dist/adapter/ingest/contract-system-adapters.d.ts.map +1 -1
  28. package/dist/adapter/ingest/contract-system-adapters.js +100 -34
  29. package/dist/adapter/ingest/game-contract.d.ts +188 -2
  30. package/dist/adapter/ingest/game-contract.d.ts.map +1 -1
  31. package/dist/adapter/ingest/game-contract.js +107 -0
  32. package/dist/adapter/ingest/mount-readiness.d.ts +84 -0
  33. package/dist/adapter/ingest/mount-readiness.d.ts.map +1 -0
  34. package/dist/adapter/ingest/mount-readiness.js +81 -0
  35. package/dist/adapter/ingest/scene-capture.d.ts +91 -2
  36. package/dist/adapter/ingest/scene-capture.d.ts.map +1 -1
  37. package/dist/adapter/ingest/scene-capture.js +110 -18
  38. package/dist/adapter/ingest/structural-ids.d.ts +11 -5
  39. package/dist/adapter/ingest/structural-ids.d.ts.map +1 -1
  40. package/dist/adapter/ingest/structural-ids.js +18 -9
  41. package/dist/adapter/ingest/upstream-pin.d.ts +4 -2
  42. package/dist/adapter/ingest/upstream-pin.d.ts.map +1 -1
  43. package/dist/adapter/ingest/upstream-pin.js +4 -2
  44. package/dist/adapter/ingest/visible-capture-window.d.ts +116 -0
  45. package/dist/adapter/ingest/visible-capture-window.d.ts.map +1 -0
  46. package/dist/adapter/ingest/visible-capture-window.js +141 -0
  47. package/dist/adapter/loop-gate-report.d.ts +3 -4
  48. package/dist/adapter/loop-gate-report.d.ts.map +1 -1
  49. package/dist/adapter/loop-gate-report.js +3 -4
  50. package/dist/adapter/root-adapter.d.ts +22 -2
  51. package/dist/adapter/root-adapter.d.ts.map +1 -1
  52. package/dist/adapter/setup-three-root-adapter.d.ts.map +1 -1
  53. package/dist/adapter/setup-three-root-adapter.js +15 -0
  54. package/dist/adapter/system-adapter.d.ts +161 -2
  55. package/dist/adapter/system-adapter.d.ts.map +1 -1
  56. package/dist/adapter/system-adapter.js +18 -1
  57. package/dist/animation/camera-ownership.d.ts +4 -2
  58. package/dist/animation/camera-ownership.d.ts.map +1 -1
  59. package/dist/animation/camera-ownership.js +58 -1
  60. package/dist/animation/runtime-inspection.d.ts +70 -0
  61. package/dist/animation/runtime-inspection.d.ts.map +1 -0
  62. package/dist/animation/runtime-inspection.js +25 -0
  63. package/dist/animation/xstate-animation-binding.d.ts +9 -1
  64. package/dist/animation/xstate-animation-binding.d.ts.map +1 -1
  65. package/dist/animation/xstate-animation-binding.js +48 -1
  66. package/dist/asset-formats/material.d.ts +1 -1
  67. package/dist/asset-formats/mesh.d.ts +1 -1
  68. package/dist/asset-formats/particles.d.ts +13 -0
  69. package/dist/asset-formats/particles.d.ts.map +1 -1
  70. package/dist/asset-formats/particles.js +28 -0
  71. package/dist/behavior/xstate-inspection.d.ts +24 -0
  72. package/dist/behavior/xstate-inspection.d.ts.map +1 -0
  73. package/dist/behavior/xstate-inspection.js +25 -0
  74. package/dist/core/game-loop.d.ts +7 -5
  75. package/dist/core/game-loop.d.ts.map +1 -1
  76. package/dist/core/game-loop.js +39 -18
  77. package/dist/core/types.d.ts +11 -12
  78. package/dist/core/types.d.ts.map +1 -1
  79. package/dist/data/data-asset.js +1 -1
  80. package/dist/dev/instruments.d.ts.map +1 -1
  81. package/dist/dev/instruments.js +5 -1
  82. package/dist/dev/render-debug-adapter.d.ts +19 -2
  83. package/dist/dev/render-debug-adapter.d.ts.map +1 -1
  84. package/dist/dev/render-debug-adapter.js +10 -0
  85. package/dist/ecs/user-data.d.ts +10 -2
  86. package/dist/ecs/user-data.d.ts.map +1 -1
  87. package/dist/ecs/user-data.js +6 -2
  88. package/dist/input/binding-identity.d.ts +10 -0
  89. package/dist/input/binding-identity.d.ts.map +1 -0
  90. package/dist/input/binding-identity.js +36 -0
  91. package/dist/input/input-manager.d.ts +18 -185
  92. package/dist/input/input-manager.d.ts.map +1 -1
  93. package/dist/input/input-manager.js +78 -68
  94. package/dist/manifest/load.d.ts +14 -0
  95. package/dist/manifest/load.d.ts.map +1 -1
  96. package/dist/manifest/load.js +6 -1
  97. package/dist/manifest/schema.d.ts +18 -0
  98. package/dist/manifest/schema.d.ts.map +1 -1
  99. package/dist/manifest/schema.js +64 -7
  100. package/dist/pixi/authoring.d.ts +27 -0
  101. package/dist/pixi/authoring.d.ts.map +1 -1
  102. package/dist/pixi/authoring.js +10 -3
  103. package/dist/pixi/index.d.ts +1 -1
  104. package/dist/pixi/index.d.ts.map +1 -1
  105. package/dist/pixi/index.js +1 -1
  106. package/dist/pixi/ingest.d.ts +8 -0
  107. package/dist/pixi/ingest.d.ts.map +1 -1
  108. package/dist/pixi/ingest.js +10 -1
  109. package/dist/pixi/render-pass-bracket.d.ts +56 -0
  110. package/dist/pixi/render-pass-bracket.d.ts.map +1 -0
  111. package/dist/pixi/render-pass-bracket.js +98 -0
  112. package/dist/pixi/scene-capture.d.ts +32 -1
  113. package/dist/pixi/scene-capture.d.ts.map +1 -1
  114. package/dist/pixi/scene-capture.js +21 -9
  115. package/dist/pixi/system-adapters.d.ts +29 -0
  116. package/dist/pixi/system-adapters.d.ts.map +1 -1
  117. package/dist/pixi/system-adapters.js +27 -0
  118. package/dist/render/particles-factory.d.ts +16 -2
  119. package/dist/render/particles-factory.d.ts.map +1 -1
  120. package/dist/render/particles-factory.js +88 -5
  121. package/dist/render/soft-particle-depth.d.ts +149 -0
  122. package/dist/render/soft-particle-depth.d.ts.map +1 -0
  123. package/dist/render/soft-particle-depth.js +305 -0
  124. package/dist/render/voxel-surface.d.ts +117 -0
  125. package/dist/render/voxel-surface.d.ts.map +1 -0
  126. package/dist/render/voxel-surface.js +263 -0
  127. package/dist/runtime/create-runtime.js +7 -0
  128. package/dist/runtime/debug-bridge.d.ts +15 -15
  129. package/dist/runtime/debug-bridge.d.ts.map +1 -1
  130. package/dist/runtime/debug-bridge.js +27 -26
  131. package/dist/runtime/game.d.ts.map +1 -1
  132. package/dist/runtime/game.js +1 -2
  133. package/dist/setup/setup-particles.d.ts.map +1 -1
  134. package/dist/setup/setup-particles.js +9 -0
  135. package/dist/world3d-react/r3f-adapter.d.ts.map +1 -1
  136. package/dist/world3d-react/r3f-adapter.js +42 -3
  137. package/dist/world3d-react/rapier-physics-bridge.d.ts.map +1 -1
  138. package/dist/world3d-react/rapier-physics-bridge.js +201 -11
  139. package/dist-config/config.js.map +1 -1
  140. package/package.json +4 -2
  141. package/schemas/engine-capabilities.json +12 -12
  142. package/schemas/vgai-project.schema.json +41 -2
  143. package/src/adapter/adapter-module.ts +607 -0
  144. package/src/adapter/authoring.ts +440 -10
  145. package/src/adapter/constraint.ts +10 -3
  146. package/src/adapter/finders/finder-result.ts +29 -0
  147. package/src/adapter/finders/index.ts +62 -0
  148. package/src/adapter/finders/prefabs-from-stories.ts +142 -0
  149. package/src/adapter/finders/scenes-from-entrypoint-selection.ts +304 -0
  150. package/src/adapter/first-party-systems.ts +30 -0
  151. package/src/adapter/index.ts +32 -1
  152. package/src/adapter/ingest/contract-system-adapters.ts +116 -32
  153. package/src/adapter/ingest/game-contract.ts +265 -2
  154. package/src/adapter/ingest/mount-readiness.ts +140 -0
  155. package/src/adapter/ingest/scene-capture.ts +199 -22
  156. package/src/adapter/ingest/structural-ids.ts +21 -9
  157. package/src/adapter/ingest/upstream-pin.ts +4 -2
  158. package/src/adapter/ingest/visible-capture-window.ts +213 -0
  159. package/src/adapter/loop-gate-report.ts +3 -4
  160. package/src/adapter/root-adapter.ts +22 -2
  161. package/src/adapter/setup-three-root-adapter.ts +16 -0
  162. package/src/adapter/system-adapter.ts +188 -2
  163. package/src/animation/camera-ownership.ts +68 -3
  164. package/src/animation/runtime-inspection.ts +104 -0
  165. package/src/animation/xstate-animation-binding.ts +53 -1
  166. package/src/asset-formats/particles.ts +31 -0
  167. package/src/behavior/xstate-inspection.ts +51 -0
  168. package/src/core/game-loop.ts +39 -17
  169. package/src/core/types.ts +11 -12
  170. package/src/data/data-asset.ts +1 -1
  171. package/src/dev/instruments.ts +5 -1
  172. package/src/dev/render-debug-adapter.ts +22 -2
  173. package/src/ecs/user-data.ts +10 -2
  174. package/src/input/binding-identity.ts +37 -0
  175. package/src/input/input-manager.ts +93 -68
  176. package/src/manifest/load.ts +23 -2
  177. package/src/manifest/schema.ts +76 -7
  178. package/src/pixi/authoring.ts +37 -5
  179. package/src/pixi/index.ts +2 -0
  180. package/src/pixi/ingest.ts +15 -2
  181. package/src/pixi/render-pass-bracket.ts +117 -0
  182. package/src/pixi/scene-capture.ts +63 -13
  183. package/src/pixi/system-adapters.ts +41 -0
  184. package/src/render/particles-factory.ts +89 -6
  185. package/src/render/soft-particle-depth.ts +336 -0
  186. package/src/render/voxel-surface.ts +358 -0
  187. package/src/runtime/create-runtime.ts +7 -0
  188. package/src/runtime/debug-bridge.ts +32 -31
  189. package/src/runtime/game.ts +1 -2
  190. package/src/setup/setup-particles.ts +9 -0
  191. package/src/world3d-react/r3f-adapter.tsx +48 -2
  192. package/src/world3d-react/rapier-physics-bridge.tsx +249 -11
@@ -1 +1 @@
1
- {"version":3,"file":"constraint.d.ts","sourceRoot":"","sources":["../../src/adapter/constraint.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAGpC,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,UAAU,GAAG,YAAY,GAAG,OAAO,CAAC;AAE7E,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,aAAa,GAAG,QAAQ,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;IACxD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,iEAAiE;IACjE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,oEAAoE;IACpE,QAAQ,CAAC,KAAK,EAAE,SAAS,KAAK,CAAC,QAAQ,EAAE,CAAC;IAC1C,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;IACrC,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,WAAW,IAAI,kBAAkB,CAAC;CACnC;AAED,wBAAgB,aAAa,CAC3B,MAAM,EAAE,KAAK,CAAC,QAAQ,GAAG,IAAI,GAAG,SAAS,GACxC,SAAS,cAAc,EAAE,CAU3B;AAED,iFAAiF;AACjF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI,CAGpF;AAED,4EAA4E;AAC5E,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAQ7E"}
1
+ {"version":3,"file":"constraint.d.ts","sourceRoot":"","sources":["../../src/adapter/constraint.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAGpC,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,UAAU,GAAG,YAAY,GAAG,OAAO,CAAC;AAE7E,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,aAAa,GAAG,QAAQ,GAAG,KAAK,GAAG,UAAU,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;IAC7E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,iEAAiE;IACjE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,CAAC;CACrC;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,oEAAoE;IACpE,QAAQ,CAAC,KAAK,EAAE,SAAS,KAAK,CAAC,QAAQ,EAAE,CAAC;IAC1C,kEAAkE;IAClE,QAAQ,CAAC,WAAW,EAAE,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;IAC5C,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;IACrC,wEAAwE;IACxE,QAAQ,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;CACxC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,WAAW,IAAI,kBAAkB,CAAC;CACnC;AAED,wBAAgB,aAAa,CAC3B,MAAM,EAAE,KAAK,CAAC,QAAQ,GAAG,IAAI,GAAG,SAAS,GACxC,SAAS,cAAc,EAAE,CAU3B;AAED,iFAAiF;AACjF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI,CAGpF;AAED,4EAA4E;AAC5E,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAQ7E"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * What every finder answers with.
3
+ *
4
+ * A finder is a PURE function over project source/files with explicit inputs
5
+ * and outputs — it never reads a filesystem, never fetches, and never consults
6
+ * ambient state. What it cannot answer it says so in {@link FinderResult.notes}
7
+ * rather than degrading silently: "has none" and "nobody could look" are
8
+ * different facts, and only the second is a defect.
9
+ */
10
+ import type { SceneEntry } from '../adapter-module';
11
+ export interface FinderResult {
12
+ /** Scene-table entries this finder produced, in discovery order. */
13
+ readonly entries: readonly SceneEntry[];
14
+ /**
15
+ * The entry this finder's own answer makes the default, when its answer
16
+ * settles it UNAMBIGUOUSLY (one candidate). A finder never picks between
17
+ * candidates — that is the adapter author's declaration to make, and an
18
+ * absent default stays the honest fact that none was declared.
19
+ */
20
+ readonly default?: string;
21
+ /**
22
+ * Loud, non-fatal diagnostics: a selection identifier that is not in the
23
+ * source, an entrypoint whose bytes could not be read. Every note names the
24
+ * file it is about. The host surfaces these; it never swallows them.
25
+ */
26
+ readonly notes: readonly string[];
27
+ }
28
+ //# sourceMappingURL=finder-result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finder-result.d.ts","sourceRoot":"","sources":["../../../src/adapter/finders/finder-result.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,WAAW,YAAY;IAC3B,oEAAoE;IACpE,QAAQ,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;IACxC;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * What every finder answers with.
3
+ *
4
+ * A finder is a PURE function over project source/files with explicit inputs
5
+ * and outputs — it never reads a filesystem, never fetches, and never consults
6
+ * ambient state. What it cannot answer it says so in {@link FinderResult.notes}
7
+ * rather than degrading silently: "has none" and "nobody could look" are
8
+ * different facts, and only the second is a defect.
9
+ */
10
+ export {};
@@ -0,0 +1,38 @@
1
+ /**
2
+ * THE FINDER NAMESPACE — host-owned discovery algorithms an adapter SELECTS.
3
+ *
4
+ * ARCHITECTURE-CORE §The editor protocol, "Zero inference": what zero
5
+ * inference forbids is the ENGINE running a finder nobody selected. A
6
+ * convention (`src/scenes/`, a story registration) is legitimate exactly when
7
+ * it is an adapter's declared finder parameter, and illegitimate as implicit
8
+ * engine behavior.
9
+ *
10
+ * That is enforced MECHANICALLY, not by policy: everything under this
11
+ * directory has exactly ONE sanctioned importer — the editor's adapter loader
12
+ * (`packages/editor/src/project-adapter.ts`) — and
13
+ * `packages/engine/test/finder-import-boundary.test.ts` fails by name when any
14
+ * other engine/editor file imports it. Do not add a second importer; make the
15
+ * loader answer instead.
16
+ *
17
+ * Dependency direction is one-way: finders import their parameter types from
18
+ * `../adapter-module`, and `adapter-module.ts` imports nothing from here. That
19
+ * is what keeps a game's `vgai.adapter.ts` free of finder implementations.
20
+ */
21
+ import type { FinderSelection } from '../adapter-module';
22
+ import type { FinderResult } from './finder-result';
23
+ import { type PrefabsFromStoriesInput } from './prefabs-from-stories';
24
+ import { type ScenesFromEntrypointSelectionInput } from './scenes-from-entrypoint-selection';
25
+ export type { FinderResult } from './finder-result';
26
+ export type { PrefabsFromStoriesInput, ProjectComponentRef, StoryRegistration, } from './prefabs-from-stories';
27
+ export { prefabsFromStories } from './prefabs-from-stories';
28
+ export type { EntrypointSource, ScenesFromEntrypointSelectionInput, } from './scenes-from-entrypoint-selection';
29
+ export { scenesFromEntrypointSelection } from './scenes-from-entrypoint-selection';
30
+ /** Everything any shipped finder can be handed, gathered once by the loader. */
31
+ export type FinderInput = ScenesFromEntrypointSelectionInput & PrefabsFromStoriesInput;
32
+ /**
33
+ * Run one adapter-declared selection. The switch is exhaustive over
34
+ * {@link FinderSelection}: a new finder that forgets a case fails to COMPILE
35
+ * here rather than silently contributing nothing.
36
+ */
37
+ export declare function runFinderSelection(selection: FinderSelection, input: FinderInput): FinderResult;
38
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapter/finders/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,KAAK,uBAAuB,EAAsB,MAAM,wBAAwB,CAAC;AAC1F,OAAO,EACL,KAAK,kCAAkC,EAExC,MAAM,oCAAoC,CAAC;AAE5C,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,YAAY,EACV,uBAAuB,EACvB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,YAAY,EACV,gBAAgB,EAChB,kCAAkC,GACnC,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,6BAA6B,EAAE,MAAM,oCAAoC,CAAC;AAEnF,gFAAgF;AAChF,MAAM,MAAM,WAAW,GAAG,kCAAkC,GAAG,uBAAuB,CAAC;AAEvF;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,eAAe,EAAE,KAAK,EAAE,WAAW,GAAG,YAAY,CAW/F"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * THE FINDER NAMESPACE — host-owned discovery algorithms an adapter SELECTS.
3
+ *
4
+ * ARCHITECTURE-CORE §The editor protocol, "Zero inference": what zero
5
+ * inference forbids is the ENGINE running a finder nobody selected. A
6
+ * convention (`src/scenes/`, a story registration) is legitimate exactly when
7
+ * it is an adapter's declared finder parameter, and illegitimate as implicit
8
+ * engine behavior.
9
+ *
10
+ * That is enforced MECHANICALLY, not by policy: everything under this
11
+ * directory has exactly ONE sanctioned importer — the editor's adapter loader
12
+ * (`packages/editor/src/project-adapter.ts`) — and
13
+ * `packages/engine/test/finder-import-boundary.test.ts` fails by name when any
14
+ * other engine/editor file imports it. Do not add a second importer; make the
15
+ * loader answer instead.
16
+ *
17
+ * Dependency direction is one-way: finders import their parameter types from
18
+ * `../adapter-module`, and `adapter-module.ts` imports nothing from here. That
19
+ * is what keeps a game's `vgai.adapter.ts` free of finder implementations.
20
+ */
21
+ import { prefabsFromStories } from './prefabs-from-stories';
22
+ import { scenesFromEntrypointSelection, } from './scenes-from-entrypoint-selection';
23
+ export { prefabsFromStories } from './prefabs-from-stories';
24
+ export { scenesFromEntrypointSelection } from './scenes-from-entrypoint-selection';
25
+ /**
26
+ * Run one adapter-declared selection. The switch is exhaustive over
27
+ * {@link FinderSelection}: a new finder that forgets a case fails to COMPILE
28
+ * here rather than silently contributing nothing.
29
+ */
30
+ export function runFinderSelection(selection, input) {
31
+ switch (selection.finder) {
32
+ case 'scenesFromEntrypointSelection':
33
+ return scenesFromEntrypointSelection(selection, input);
34
+ case 'prefabsFromStories':
35
+ return prefabsFromStories(selection, input);
36
+ default: {
37
+ const unreachable = selection;
38
+ throw new Error(`Unknown finder selection: ${JSON.stringify(unreachable)}`);
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,64 @@
1
+ /**
2
+ * FINDER — prefabs from colocated portable-CSF story registrations.
3
+ *
4
+ * ARCHITECTURE-CORE §Roots: "A prefab is an ordinary source component that a
5
+ * designer independently places, duplicates, or reuses, explicitly registered
6
+ * for Content by a colocated portable story whose `meta.component` names it."
7
+ * The registration is the load-bearing reference — delete the story and the
8
+ * declaration is gone — which is why source SHAPE alone never admits a prefab.
9
+ *
10
+ * EXTRACTION, not a new rule. The join implemented here is the one the editor
11
+ * already runs:
12
+ * - the match + same-source-directory tiebreak:
13
+ * `packages/editor/src/stories/story-registry.ts:162-186`
14
+ * (`componentPreviewStories`) and `:148-159` (`pickComponentPreviewStory`);
15
+ * - the default-story preference: `story-registry.ts:118-123`
16
+ * (`isDeclaredDefaultStory`);
17
+ * - the admission rule "a component with no story is not a Content entry at
18
+ * all": `packages/editor/src/components/AssetBrowser.tsx`, the
19
+ * `browserEntries` content scope (`if (!previewStory) return []`).
20
+ * `meta.component`'s identity NAME is read live by
21
+ * `packages/editor/src/stories/compose-project-stories.ts:130` /
22
+ * `:185` (`componentIdentityName`) — this finder consumes that answer rather
23
+ * than re-deriving it, so both sides of the join agree by construction.
24
+ *
25
+ * Pure over its inputs: the host hands in the registrations the story registry
26
+ * already produced and the component index it already has.
27
+ */
28
+ import type { PrefabsFromStoriesParams } from '../adapter-module';
29
+ import type { FinderResult } from './finder-result';
30
+ /** One composed portable-CSF story, as the host's story registry reports it. */
31
+ export interface StoryRegistration {
32
+ /** Project-relative path of the CSF module (`src/prefabs/HeroBox.stories.tsx`). */
33
+ readonly modulePath: string;
34
+ /** The composed story's stable id. */
35
+ readonly storyId: string;
36
+ /** Human label for the story. */
37
+ readonly label: string;
38
+ /**
39
+ * `meta.component`'s identity name. Absent ⇒ this story is joined to nothing
40
+ * and declares no prefab — an ordinary story document, not a defect.
41
+ */
42
+ readonly componentName?: string;
43
+ /** Whether the module declares this story as its component's default. */
44
+ readonly isDefault?: boolean;
45
+ }
46
+ /** One entry of the host's project component index. */
47
+ export interface ProjectComponentRef {
48
+ readonly name: string;
49
+ /** Project-relative source path of the component's own module. */
50
+ readonly path: string;
51
+ /** Region this component's surface belongs to, when the host knows it. */
52
+ readonly region?: string | null;
53
+ }
54
+ export interface PrefabsFromStoriesInput {
55
+ readonly stories: readonly StoryRegistration[];
56
+ /**
57
+ * The project's component index. Supplies each prefab's own source path and
58
+ * region; absent, entries still exist (the story IS the declaration) and
59
+ * simply carry no `source`.
60
+ */
61
+ readonly components?: readonly ProjectComponentRef[];
62
+ }
63
+ export declare function prefabsFromStories(_params: PrefabsFromStoriesParams, input: PrefabsFromStoriesInput): FinderResult;
64
+ //# sourceMappingURL=prefabs-from-stories.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prefabs-from-stories.d.ts","sourceRoot":"","sources":["../../../src/adapter/finders/prefabs-from-stories.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAc,MAAM,mBAAmB,CAAC;AAC9E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEpD,gFAAgF;AAChF,MAAM,WAAW,iBAAiB;IAChC,mFAAmF;IACnF,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,sCAAsC;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,iCAAiC;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,yEAAyE;IACzE,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,uDAAuD;AACvD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,0EAA0E;IAC1E,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,OAAO,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC/C;;;;OAIG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,mBAAmB,EAAE,CAAC;CACtD;AA6CD,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,wBAAwB,EACjC,KAAK,EAAE,uBAAuB,GAC7B,YAAY,CA4Bd"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * FINDER — prefabs from colocated portable-CSF story registrations.
3
+ *
4
+ * ARCHITECTURE-CORE §Roots: "A prefab is an ordinary source component that a
5
+ * designer independently places, duplicates, or reuses, explicitly registered
6
+ * for Content by a colocated portable story whose `meta.component` names it."
7
+ * The registration is the load-bearing reference — delete the story and the
8
+ * declaration is gone — which is why source SHAPE alone never admits a prefab.
9
+ *
10
+ * EXTRACTION, not a new rule. The join implemented here is the one the editor
11
+ * already runs:
12
+ * - the match + same-source-directory tiebreak:
13
+ * `packages/editor/src/stories/story-registry.ts:162-186`
14
+ * (`componentPreviewStories`) and `:148-159` (`pickComponentPreviewStory`);
15
+ * - the default-story preference: `story-registry.ts:118-123`
16
+ * (`isDeclaredDefaultStory`);
17
+ * - the admission rule "a component with no story is not a Content entry at
18
+ * all": `packages/editor/src/components/AssetBrowser.tsx`, the
19
+ * `browserEntries` content scope (`if (!previewStory) return []`).
20
+ * `meta.component`'s identity NAME is read live by
21
+ * `packages/editor/src/stories/compose-project-stories.ts:130` /
22
+ * `:185` (`componentIdentityName`) — this finder consumes that answer rather
23
+ * than re-deriving it, so both sides of the join agree by construction.
24
+ *
25
+ * Pure over its inputs: the host hands in the registrations the story registry
26
+ * already produced and the component index it already has.
27
+ */
28
+ /** Directory portion of a project-relative path — `story-registry.ts:126`'s `sourceDir`. */
29
+ function sourceDir(path) {
30
+ const normalized = path.replaceAll('\\', '/').replace(/^\.\//, '');
31
+ const slash = normalized.lastIndexOf('/');
32
+ return slash >= 0 ? normalized.slice(0, slash) : '';
33
+ }
34
+ /** Group the registrations by the component their meta NAMES. A story naming
35
+ * none is joined to nothing and declares no prefab. */
36
+ function storiesByComponent(stories) {
37
+ const byComponent = new Map();
38
+ for (const story of stories) {
39
+ const name = story.componentName;
40
+ if (name === undefined || name === '')
41
+ continue;
42
+ const bucket = byComponent.get(name);
43
+ if (bucket)
44
+ bucket.push(story);
45
+ else
46
+ byComponent.set(name, [story]);
47
+ }
48
+ return byComponent;
49
+ }
50
+ /**
51
+ * The story that speaks for a component: colocated beats distant
52
+ * (story-registry.ts:177-180 — two files can export a same-named component),
53
+ * and within that set the module's own declared default wins
54
+ * (story-registry.ts:118-123).
55
+ */
56
+ function chooseStory(stories, component) {
57
+ const sameDir = component
58
+ ? stories.filter((story) => sourceDir(story.modulePath) === sourceDir(component.path))
59
+ : [];
60
+ const pool = sameDir.length > 0 ? sameDir : stories;
61
+ return {
62
+ chosen: pool.find((story) => story.isDefault === true) ?? pool[0],
63
+ colocated: sameDir.length > 0,
64
+ };
65
+ }
66
+ export function prefabsFromStories(_params, input) {
67
+ const entries = [];
68
+ const notes = [];
69
+ for (const [componentName, stories] of storiesByComponent(input.stories)) {
70
+ const component = input.components?.find((candidate) => candidate.name === componentName);
71
+ const { chosen, colocated } = chooseStory(stories, component);
72
+ if (!chosen)
73
+ continue;
74
+ if (component && !colocated) {
75
+ notes.push(`prefabsFromStories: "${componentName}" is declared by ${chosen.modulePath}, which is not ` +
76
+ `colocated with ${component.path}. The join is by name; confirm it names this component.`);
77
+ }
78
+ entries.push({
79
+ id: componentName,
80
+ label: componentName,
81
+ kind: 'prefab',
82
+ region: component?.region ?? null,
83
+ authorable: true,
84
+ reach: { kind: 'story', storyId: chosen.storyId },
85
+ ...(component ? { source: { path: component.path, export: component.name } } : {}),
86
+ finder: 'prefabsFromStories',
87
+ });
88
+ }
89
+ // Prefabs are sibling documents, never the default scene — a finder that
90
+ // cannot settle a default says nothing rather than nominating one.
91
+ return { entries, notes };
92
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * FINDER — scenes from the entrypoint's active-scene selection.
3
+ *
4
+ * ARCHITECTURE-CORE §The editor protocol, "Zero inference": discovery may be a
5
+ * LIBRARY, and this is one. It only ever runs because an adapter SELECTED it
6
+ * (`{ finder: 'scenesFromEntrypointSelection', … }`); the engine never runs a
7
+ * finder nobody selected, which `packages/engine/test/finder-import-boundary.test.ts`
8
+ * enforces mechanically rather than by policy.
9
+ *
10
+ * Why the ENTRYPOINT and not a folder: it is a LOAD-BEARING source — a
11
+ * reference the game itself executes. The review test is "would the game break
12
+ * if this fact lied?", and here it would: change the entrypoint's selection
13
+ * table and the game changes with it. A `src/scenes/` convention can drift
14
+ * silently; this cannot.
15
+ *
16
+ * Two answers, and the difference is declared rather than sniffed:
17
+ * - the adapter names a `selection` identifier ⇒ read that module-level
18
+ * table and answer one entry per key, each reachable through it;
19
+ * - the adapter names none ⇒ the entrypoint mounts ONE composition, and the
20
+ * answer is the single-scene DEGENERATE table: the region's own
21
+ * composition, opened by mounting the region.
22
+ *
23
+ * ON `typescript`: this module parses the entrypoint's own TSX with the
24
+ * TypeScript compiler API — the same parser `packages/editor/src/ui-source/
25
+ * oid-transform.ts` and `packages/editor/src/asset-workflow/project-content.ts`
26
+ * already use for exactly this kind of question (vgai has `typescript`; it does
27
+ * NOT have @babel/*). It is a HOST-SIDE-ONLY dependency: finders are importable
28
+ * only by the adapter loader, `adapter-module.ts` imports nothing from this
29
+ * directory, and a game's `vgai.adapter.ts` therefore never pulls a parser into
30
+ * its own bundle.
31
+ */
32
+ import type { ScenesFromEntrypointSelectionParams } from '../adapter-module';
33
+ import type { FinderResult } from './finder-result';
34
+ /** One region's entrypoint, as the host reads it off the manifest + disk. */
35
+ export interface EntrypointSource {
36
+ /** The region (== manifest root) id. */
37
+ readonly regionId: string;
38
+ /** Project-relative path of the root's `entry` module. */
39
+ readonly path: string;
40
+ /** The module's bytes; `null` when they could not be read. */
41
+ readonly source: string | null;
42
+ /** The root's declared `dev` flag — a dev layer is the game's own dev GUI. */
43
+ readonly dev: boolean;
44
+ }
45
+ export interface ScenesFromEntrypointSelectionInput {
46
+ /**
47
+ * Every region the host mounts from an exported composition (a root with an
48
+ * `entry`), in manifest order.
49
+ */
50
+ readonly entrypoints: readonly EntrypointSource[];
51
+ /**
52
+ * Resolve one of the entrypoint's own import specifiers to a project-relative
53
+ * path. Supplied by the host because extension/index resolution is a
54
+ * filesystem question and this function is pure. Absent, or answering `null`,
55
+ * means the produced entry carries no `source` — an honest omission rather
56
+ * than a guessed path.
57
+ */
58
+ readonly resolveModule?: (specifier: string, fromPath: string) => string | null;
59
+ }
60
+ /**
61
+ * Answer the scene table this finder's selection describes.
62
+ *
63
+ * Pure: every input is passed in, nothing is read from disk, and an
64
+ * unanswerable question becomes a NOTE rather than a fabricated entry.
65
+ */
66
+ export declare function scenesFromEntrypointSelection(params: ScenesFromEntrypointSelectionParams, input: ScenesFromEntrypointSelectionInput): FinderResult;
67
+ //# sourceMappingURL=scenes-from-entrypoint-selection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scenes-from-entrypoint-selection.d.ts","sourceRoot":"","sources":["../../../src/adapter/finders/scenes-from-entrypoint-selection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAGH,OAAO,KAAK,EAGV,mCAAmC,EACpC,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEpD,6EAA6E;AAC7E,MAAM,WAAW,gBAAgB;IAC/B,wCAAwC;IACxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,8EAA8E;IAC9E,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,kCAAkC;IACjD;;;OAGG;IACH,QAAQ,CAAC,WAAW,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAClD;;;;;;OAMG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CACjF;AA2MD;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,mCAAmC,EAC3C,KAAK,EAAE,kCAAkC,GACxC,YAAY,CAwBd"}
@@ -0,0 +1,226 @@
1
+ /**
2
+ * FINDER — scenes from the entrypoint's active-scene selection.
3
+ *
4
+ * ARCHITECTURE-CORE §The editor protocol, "Zero inference": discovery may be a
5
+ * LIBRARY, and this is one. It only ever runs because an adapter SELECTED it
6
+ * (`{ finder: 'scenesFromEntrypointSelection', … }`); the engine never runs a
7
+ * finder nobody selected, which `packages/engine/test/finder-import-boundary.test.ts`
8
+ * enforces mechanically rather than by policy.
9
+ *
10
+ * Why the ENTRYPOINT and not a folder: it is a LOAD-BEARING source — a
11
+ * reference the game itself executes. The review test is "would the game break
12
+ * if this fact lied?", and here it would: change the entrypoint's selection
13
+ * table and the game changes with it. A `src/scenes/` convention can drift
14
+ * silently; this cannot.
15
+ *
16
+ * Two answers, and the difference is declared rather than sniffed:
17
+ * - the adapter names a `selection` identifier ⇒ read that module-level
18
+ * table and answer one entry per key, each reachable through it;
19
+ * - the adapter names none ⇒ the entrypoint mounts ONE composition, and the
20
+ * answer is the single-scene DEGENERATE table: the region's own
21
+ * composition, opened by mounting the region.
22
+ *
23
+ * ON `typescript`: this module parses the entrypoint's own TSX with the
24
+ * TypeScript compiler API — the same parser `packages/editor/src/ui-source/
25
+ * oid-transform.ts` and `packages/editor/src/asset-workflow/project-content.ts`
26
+ * already use for exactly this kind of question (vgai has `typescript`; it does
27
+ * NOT have @babel/*). It is a HOST-SIDE-ONLY dependency: finders are importable
28
+ * only by the adapter loader, `adapter-module.ts` imports nothing from this
29
+ * directory, and a game's `vgai.adapter.ts` therefore never pulls a parser into
30
+ * its own bundle.
31
+ */
32
+ import ts from 'typescript';
33
+ import { EXPORTED_COMPOSITION_REGIONS } from '../adapter-module';
34
+ /** Strip the directory and extension from a project-relative path. */
35
+ function basename(path) {
36
+ const file = path.replaceAll('\\', '/').split('/').pop() ?? path;
37
+ return file.replace(/\.[jt]sx?$/, '');
38
+ }
39
+ function parse(path, source) {
40
+ return ts.createSourceFile(path, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
41
+ }
42
+ /**
43
+ * The name the module's own default export carries — the game's own word for
44
+ * this composition, so the editor's tab reads `World`, not `world.tsx`.
45
+ * `undefined` when the default export is anonymous or absent.
46
+ */
47
+ function defaultExportName(sf) {
48
+ for (const statement of sf.statements) {
49
+ if (ts.isExportAssignment(statement) && !statement.isExportEquals) {
50
+ const expression = statement.expression;
51
+ if (ts.isIdentifier(expression))
52
+ return expression.text;
53
+ continue;
54
+ }
55
+ const modifiers = ts.canHaveModifiers(statement) ? ts.getModifiers(statement) : undefined;
56
+ const isDefault = modifiers?.some((m) => m.kind === ts.SyntaxKind.DefaultKeyword);
57
+ if (!isDefault)
58
+ continue;
59
+ if (ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement)) {
60
+ return statement.name?.text;
61
+ }
62
+ }
63
+ return undefined;
64
+ }
65
+ function recordClauseBindings(clause, specifier, bindings) {
66
+ if (clause.name)
67
+ bindings.set(clause.name.text, { specifier });
68
+ const named = clause.namedBindings;
69
+ if (!named || !ts.isNamedImports(named))
70
+ return;
71
+ for (const element of named.elements) {
72
+ bindings.set(element.name.text, {
73
+ specifier,
74
+ exported: (element.propertyName ?? element.name).text,
75
+ });
76
+ }
77
+ }
78
+ function importedBindings(sf) {
79
+ const bindings = new Map();
80
+ for (const statement of sf.statements) {
81
+ if (!ts.isImportDeclaration(statement) || !statement.importClause)
82
+ continue;
83
+ if (!ts.isStringLiteral(statement.moduleSpecifier))
84
+ continue;
85
+ recordClauseBindings(statement.importClause, statement.moduleSpecifier.text, bindings);
86
+ }
87
+ return bindings;
88
+ }
89
+ /** The module-level `const <name> = { … }` initializer, if there is one. */
90
+ function selectionTable(sf, name) {
91
+ for (const statement of sf.statements) {
92
+ if (!ts.isVariableStatement(statement))
93
+ continue;
94
+ for (const declaration of statement.declarationList.declarations) {
95
+ if (!ts.isIdentifier(declaration.name) || declaration.name.text !== name)
96
+ continue;
97
+ const initializer = declaration.initializer;
98
+ if (initializer && ts.isObjectLiteralExpression(initializer))
99
+ return initializer;
100
+ }
101
+ }
102
+ return undefined;
103
+ }
104
+ function propertyKey(property) {
105
+ const name = property.name;
106
+ if (!name)
107
+ return undefined;
108
+ if (ts.isIdentifier(name) || ts.isStringLiteral(name))
109
+ return name.text;
110
+ return undefined;
111
+ }
112
+ /** The identifier a selection entry's value names, if it names one at all. */
113
+ function propertyIdentifier(property) {
114
+ if (ts.isShorthandPropertyAssignment(property))
115
+ return property.name.text;
116
+ if (ts.isPropertyAssignment(property) && ts.isIdentifier(property.initializer)) {
117
+ return property.initializer.text;
118
+ }
119
+ return undefined;
120
+ }
121
+ function sourceFor(binding, fromPath, resolveModule) {
122
+ if (!binding || !resolveModule)
123
+ return undefined;
124
+ const path = resolveModule(binding.specifier, fromPath);
125
+ if (!path)
126
+ return undefined;
127
+ return binding.exported === undefined ? { path } : { path, export: binding.exported };
128
+ }
129
+ /**
130
+ * Which entrypoints this selection targets.
131
+ *
132
+ * The RULE form is every exported-composition region that is not a declared
133
+ * DEV layer. Reading `dev` is reading the manifest's own declaration — the dev
134
+ * GUI is edit-time chrome, not authorable game content — never a name
135
+ * heuristic. A named region with no matching entrypoint becomes a note, not a
136
+ * silent omission.
137
+ */
138
+ function targetedEntrypoints(params, entrypoints, notes) {
139
+ if (params.regions === EXPORTED_COMPOSITION_REGIONS) {
140
+ return entrypoints.filter((entrypoint) => !entrypoint.dev);
141
+ }
142
+ const found = [];
143
+ for (const regionId of params.regions) {
144
+ const match = entrypoints.find((entry) => entry.regionId === regionId);
145
+ if (match)
146
+ found.push(match);
147
+ else {
148
+ notes.push(`scenesFromEntrypointSelection: region "${regionId}" is selected but the project ` +
149
+ 'declares no root with that id and an entry.');
150
+ }
151
+ }
152
+ return found;
153
+ }
154
+ /** DEGENERATE: the entrypoint mounts one composition, and mounting the region
155
+ * IS opening it. Labelled by the module's own default export — the game's own
156
+ * word for this composition. */
157
+ function degenerateEntry(entrypoint, sf) {
158
+ return {
159
+ id: entrypoint.regionId,
160
+ label: defaultExportName(sf) ?? basename(entrypoint.path),
161
+ kind: 'scene',
162
+ region: entrypoint.regionId,
163
+ authorable: true,
164
+ reach: { kind: 'root-mount' },
165
+ source: { path: entrypoint.path },
166
+ finder: 'scenesFromEntrypointSelection',
167
+ };
168
+ }
169
+ /** One entry per key of the entrypoint's own selection table. */
170
+ function selectionEntries(entrypoint, sf, selection, resolveModule, notes) {
171
+ const table = selectionTable(sf, selection);
172
+ if (!table) {
173
+ notes.push(`scenesFromEntrypointSelection: ${entrypoint.path} declares no module-level ` +
174
+ `\`const ${selection} = { … }\` selection table. Nothing is assumed in its ` +
175
+ 'place — fix the adapter’s `selection` or the entrypoint.');
176
+ return [];
177
+ }
178
+ const bindings = importedBindings(sf);
179
+ const entries = [];
180
+ for (const property of table.properties) {
181
+ const key = propertyKey(property);
182
+ if (key === undefined) {
183
+ notes.push(`scenesFromEntrypointSelection: ${entrypoint.path}'s \`${selection}\` has an ` +
184
+ 'entry whose key is computed, so it cannot be named statically.');
185
+ continue;
186
+ }
187
+ const identifier = propertyIdentifier(property);
188
+ const source = sourceFor(identifier ? bindings.get(identifier) : undefined, entrypoint.path, resolveModule);
189
+ entries.push({
190
+ id: key,
191
+ label: identifier ?? key,
192
+ kind: 'scene',
193
+ region: entrypoint.regionId,
194
+ authorable: true,
195
+ reach: { kind: 'entrypoint-selection', selection, key },
196
+ ...(source ? { source } : {}),
197
+ finder: 'scenesFromEntrypointSelection',
198
+ });
199
+ }
200
+ return entries;
201
+ }
202
+ /**
203
+ * Answer the scene table this finder's selection describes.
204
+ *
205
+ * Pure: every input is passed in, nothing is read from disk, and an
206
+ * unanswerable question becomes a NOTE rather than a fabricated entry.
207
+ */
208
+ export function scenesFromEntrypointSelection(params, input) {
209
+ const notes = [];
210
+ const entries = [];
211
+ for (const entrypoint of targetedEntrypoints(params, input.entrypoints, notes)) {
212
+ if (entrypoint.source === null) {
213
+ notes.push(`scenesFromEntrypointSelection: could not read ${entrypoint.path} (region ` +
214
+ `"${entrypoint.regionId}"), so its scenes are unknown — not empty.`);
215
+ continue;
216
+ }
217
+ const sf = parse(entrypoint.path, entrypoint.source);
218
+ entries.push(...(params.selection === undefined
219
+ ? [degenerateEntry(entrypoint, sf)]
220
+ : selectionEntries(entrypoint, sf, params.selection, input.resolveModule, notes)));
221
+ }
222
+ // One candidate settles the default; two or more is a choice, and a choice
223
+ // belongs to the adapter author.
224
+ const only = entries.length === 1 ? entries[0] : undefined;
225
+ return only ? { entries, default: only.id, notes } : { entries, notes };
226
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"first-party-systems.d.ts","sourceRoot":"","sources":["../../src/adapter/first-party-systems.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,IAAI,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,KAAK,EACV,YAAY,EAIZ,iBAAiB,EAElB,MAAM,kBAAkB,CAAC;AAmC1B,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAI9D;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,SAAS,GAAG,YAAY,CAoIvE;AAED;;gEAEgE;AAChE,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,cAAc,GAAG,iBAAiB,CAS9E"}
1
+ {"version":3,"file":"first-party-systems.d.ts","sourceRoot":"","sources":["../../src/adapter/first-party-systems.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,IAAI,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,KAAK,EACV,YAAY,EAKZ,iBAAiB,EAElB,MAAM,kBAAkB,CAAC;AAmC1B,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAI9D;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,SAAS,GAAG,YAAY,CAiKvE;AAED;;gEAEgE;AAChE,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,cAAc,GAAG,iBAAiB,CAS9E"}
@@ -177,6 +177,35 @@ export function createAudioSystemAdapter(audio) {
177
177
  liveMeterHandles.add(handle);
178
178
  return handle;
179
179
  },
180
+ /** Native Web Audio tap used by the editor's gameplay recorder. It is a
181
+ * sink beside the speakers, never an insert, so recording cannot change
182
+ * what the player hears. */
183
+ acquireRecordingStream() {
184
+ const recordingContext = nativeAudioContext(audio);
185
+ if (!recordingContext ||
186
+ typeof recordingContext.createMediaStreamDestination !== 'function') {
187
+ return null;
188
+ }
189
+ const destination = recordingContext.createMediaStreamDestination();
190
+ audio.masterGain.connect(destination);
191
+ let disposed = false;
192
+ return {
193
+ stream: destination.stream,
194
+ dispose() {
195
+ if (disposed)
196
+ return;
197
+ disposed = true;
198
+ try {
199
+ audio.masterGain.disconnect(destination);
200
+ }
201
+ catch {
202
+ // The world/context may already have been torn down.
203
+ }
204
+ for (const track of destination.stream.getTracks())
205
+ track.stop();
206
+ },
207
+ };
208
+ },
180
209
  };
181
210
  meterHandlesByAdapter.set(adapter, liveMeterHandles);
182
211
  return adapter;