@volter/editor-game 0.5.65

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 (302) hide show
  1. package/LICENSE +661 -0
  2. package/NOTICE +23 -0
  3. package/contributions/asset-budget-asset.menu.ts +26 -0
  4. package/contributions/asset-budget.action.ts +18 -0
  5. package/contributions/asset-budget.document.tsx +21 -0
  6. package/contributions/asset-budget.menu.ts +22 -0
  7. package/contributions/audio-unlock.service.ts +17 -0
  8. package/contributions/audio.utility.tsx +15 -0
  9. package/contributions/autoplay.service.ts +48 -0
  10. package/contributions/bridge.command.ts +172 -0
  11. package/contributions/build-profiles.document.tsx +21 -0
  12. package/contributions/build-progress.status.tsx +45 -0
  13. package/contributions/build.action.ts +26 -0
  14. package/contributions/build.command.ts +27 -0
  15. package/contributions/build.header.tsx +37 -0
  16. package/contributions/build.menu.ts +31 -0
  17. package/contributions/build.service.ts +31 -0
  18. package/contributions/connection.status.tsx +43 -0
  19. package/contributions/coverage.service.ts +118 -0
  20. package/contributions/edit-mode-audio.service.ts +23 -0
  21. package/contributions/edit-mode-networking.service.ts +30 -0
  22. package/contributions/game-document.service.ts +25 -0
  23. package/contributions/game-eval.command.ts +210 -0
  24. package/contributions/game.layout.ts +19 -0
  25. package/contributions/gameplay.command.ts +255 -0
  26. package/contributions/generation.service.ts +96 -0
  27. package/contributions/generations.status.tsx +53 -0
  28. package/contributions/ingest.service.ts +80 -0
  29. package/contributions/instances.command.ts +75 -0
  30. package/contributions/navmesh.menu.ts +39 -0
  31. package/contributions/navmesh.service.ts +19 -0
  32. package/contributions/network.utility.tsx +17 -0
  33. package/contributions/play.command.ts +355 -0
  34. package/contributions/profiler.action.ts +16 -0
  35. package/contributions/profiler.menu.ts +22 -0
  36. package/contributions/profiler.utility.tsx +17 -0
  37. package/contributions/react/component-board.service.ts +21 -0
  38. package/contributions/react/design-time-mount.service.ts +60 -0
  39. package/contributions/react/pasteboard.action.ts +41 -0
  40. package/contributions/react/react-inspector.service.ts +85 -0
  41. package/contributions/react/story-documents.service.ts +44 -0
  42. package/contributions/scene-document.service.ts +32 -0
  43. package/contributions/state-watch.action.ts +17 -0
  44. package/contributions/state-watch.menu.ts +23 -0
  45. package/contributions/state-watch.utility.tsx +20 -0
  46. package/contributions/team-playtest.service.ts +124 -0
  47. package/contributions/three/camera-runtime.inspector.tsx +34 -0
  48. package/contributions/three/component-board.service.ts +24 -0
  49. package/contributions/three/component-verbs.command.ts +110 -0
  50. package/contributions/three/component-verbs.service.ts +92 -0
  51. package/contributions/three/constraints.inspector.tsx +34 -0
  52. package/contributions/three/model-asset-sections.service.ts +26 -0
  53. package/contributions/three/reflection-probe-capture.inspector.tsx +32 -0
  54. package/contributions/three/story-documents.service.ts +31 -0
  55. package/contributions/three/three-authoring.service.ts +66 -0
  56. package/contributions/transport.header.tsx +19 -0
  57. package/contributions/xstate-behavior.action.ts +42 -0
  58. package/contributions/xstate-behavior.document.tsx +73 -0
  59. package/contributions/xstate-behavior.inspector.tsx +28 -0
  60. package/contributions/xstate-behavior.menu.ts +23 -0
  61. package/package.json +144 -0
  62. package/src/asset-budget/AssetBudgetPanel.tsx +1172 -0
  63. package/src/asset-budget/asset-budget-model.ts +799 -0
  64. package/src/asset-budget/basis-encoder.ts +165 -0
  65. package/src/asset-budget/gltf-io.ts +154 -0
  66. package/src/asset-budget/gltf-optimize.ts +384 -0
  67. package/src/asset-budget/image-dims.ts +78 -0
  68. package/src/asset-budget/optimize-apply.ts +221 -0
  69. package/src/audio/AudioDebuggerPanel.tsx +457 -0
  70. package/src/audio/audio-debugger-model.ts +87 -0
  71. package/src/bridge/call.ts +60 -0
  72. package/src/bridge/dispatch.ts +459 -0
  73. package/src/bridge/live-frames.ts +25 -0
  74. package/src/bridge/screenshot.ts +316 -0
  75. package/src/build/BuildProfilesPanel.tsx +476 -0
  76. package/src/build/build-session.ts +247 -0
  77. package/src/build/format-bytes.ts +14 -0
  78. package/src/command-results.ts +36 -0
  79. package/src/coverage/live-authoring-surface.ts +30 -0
  80. package/src/coverage/live-project-verbs.ts +162 -0
  81. package/src/coverage/native-system-coverage.ts +143 -0
  82. package/src/coverage/root-coverage.ts +79 -0
  83. package/src/coverage/session-coverage.ts +193 -0
  84. package/src/design-system-stories/ApplicationChrome.stories.tsx +100 -0
  85. package/src/design-system-stories/InspectorNarrowBodies.stories.tsx +406 -0
  86. package/src/edit-mode/edit-mode-audio.ts +56 -0
  87. package/src/edit-mode/edit-mode-networking.ts +112 -0
  88. package/src/game-document/DevicePresetPicker.tsx +84 -0
  89. package/src/game-document/GameCaptureFrameButton.tsx +45 -0
  90. package/src/game-document/GameDocument.tsx +215 -0
  91. package/src/game-document/GamePanel.tsx +662 -0
  92. package/src/game-document/InstanceInspectorPicker.tsx +183 -0
  93. package/src/game-document/crowd-debug.ts +183 -0
  94. package/src/game-document/device-preview.ts +336 -0
  95. package/src/game-document/game-view-store.ts +107 -0
  96. package/src/game-document/physics-debug.ts +187 -0
  97. package/src/generation/GenerationActivity.tsx +421 -0
  98. package/src/generation/GenerationGallery.css +231 -0
  99. package/src/generation/generation-documents.tsx +338 -0
  100. package/src/generation/generation-jobs.ts +128 -0
  101. package/src/generation/generation-presentation.ts +257 -0
  102. package/src/host/adapter-reach.ts +445 -0
  103. package/src/host/adapter-runtime-bindings.ts +303 -0
  104. package/src/host/after-paint.ts +112 -0
  105. package/src/host/api/configurations.ts +66 -0
  106. package/src/host/authoring/babylon-authoring-adapter.ts +703 -0
  107. package/src/host/authoring/canvas-runtime-recognition.ts +50 -0
  108. package/src/host/authoring/contract-hierarchy-authoring.ts +144 -0
  109. package/src/host/authoring/contract-scenes-stories.ts +204 -0
  110. package/src/host/authoring/creation-site-related.ts +55 -0
  111. package/src/host/authoring/ephemeral-persistence.ts +29 -0
  112. package/src/host/authoring/gesture-persist.ts +84 -0
  113. package/src/host/authoring/ingest-data-writer.ts +232 -0
  114. package/src/host/authoring/ingest-source-persistence.ts +826 -0
  115. package/src/host/authoring/mount-isolated-pixi-screen.ts +250 -0
  116. package/src/host/authoring/mounted-authoring.ts +41 -0
  117. package/src/host/authoring/owned-pixi-ticker-listeners.ts +96 -0
  118. package/src/host/authoring/phaser-live-authoring-adapter.ts +265 -0
  119. package/src/host/authoring/pixi-authoring-adapter.ts +1554 -0
  120. package/src/host/authoring/pixi-creation-site-write-target.ts +60 -0
  121. package/src/host/authoring/pixi-isolation-assets.ts +25 -0
  122. package/src/host/authoring/pixi-live-write-target.ts +979 -0
  123. package/src/host/authoring/pixi-source-identity.ts +141 -0
  124. package/src/host/authoring/pixi-still-presentation.ts +71 -0
  125. package/src/host/authoring/pixi-structure-history.ts +237 -0
  126. package/src/host/authoring/pixi-transform-channels.ts +205 -0
  127. package/src/host/authoring/selection-remount-handoff.ts +23 -0
  128. package/src/host/authoring/source-persistence-backend.ts +373 -0
  129. package/src/host/authoring/source-refresh-revisions.ts +81 -0
  130. package/src/host/authoring/struct-write-pipe.ts +143 -0
  131. package/src/host/auto-frame-window.ts +89 -0
  132. package/src/host/binding-resolver.ts +393 -0
  133. package/src/host/browser-transpile.ts +631 -0
  134. package/src/host/canvas-entry-runtime.ts +95 -0
  135. package/src/host/components/CameraAuthoringOverlay.tsx +216 -0
  136. package/src/host/components/HeaderTelemetry.tsx +341 -0
  137. package/src/host/components/PixiIsolationSceneContent.tsx +280 -0
  138. package/src/host/components/ResolutionPicker.tsx +89 -0
  139. package/src/host/components/ThreeIsolationSceneContent.tsx +180 -0
  140. package/src/host/components/frame-debugger-model.ts +579 -0
  141. package/src/host/components/header-telemetry-model.ts +74 -0
  142. package/src/host/components/scene-document.tsx +447 -0
  143. package/src/host/components/utility-view-state.ts +87 -0
  144. package/src/host/components/world-root-stage-binding.tsx +133 -0
  145. package/src/host/components/world-root-stage.ts +1046 -0
  146. package/src/host/coverage/authoring-read-probe.ts +583 -0
  147. package/src/host/coverage/capability-coverage.ts +1587 -0
  148. package/src/host/coverage/coverage-accounting.ts +261 -0
  149. package/src/host/coverage/game-contract-seam-evidence.ts +82 -0
  150. package/src/host/coverage/project-verb-coverage.ts +148 -0
  151. package/src/host/coverage/system-adapter-coverage.ts +373 -0
  152. package/src/host/design-system-stories/StoryLayout.tsx +104 -0
  153. package/src/host/design-system-stories/fixtures/authoring.ts +247 -0
  154. package/src/host/design-system-stories/fixtures/editor-runtime.tsx +115 -0
  155. package/src/host/document-preview-three.ts +110 -0
  156. package/src/host/entry-adjudication.ts +89 -0
  157. package/src/host/game-location-guard.ts +150 -0
  158. package/src/host/game-module-access.ts +196 -0
  159. package/src/host/game-realm-page.ts +358 -0
  160. package/src/host/game-realm-reclaim.ts +55 -0
  161. package/src/host/game-realm-storage.ts +104 -0
  162. package/src/host/gameplay-export.ts +288 -0
  163. package/src/host/gameplay-recording.ts +717 -0
  164. package/src/host/gated-globals.ts +1511 -0
  165. package/src/host/history/json-history-resource.ts +254 -0
  166. package/src/host/ingest/registry.ts +261 -0
  167. package/src/host/instance-extract-actions.ts +120 -0
  168. package/src/host/instance-fork-actions.ts +120 -0
  169. package/src/host/play-control-hook.ts +26 -0
  170. package/src/host/playwright-shim.ts +479 -0
  171. package/src/host/projection/dom.ts +295 -0
  172. package/src/host/projection/pixi.ts +288 -0
  173. package/src/host/r3f-entry-runtime.ts +77 -0
  174. package/src/host/react-mount-runtime.ts +162 -0
  175. package/src/host/realm-services.ts +148 -0
  176. package/src/host/recording-preview.ts +106 -0
  177. package/src/host/roots/module-root.ts +203 -0
  178. package/src/host/roots/react-root.ts +181 -0
  179. package/src/host/same-realm-loop-gate.ts +544 -0
  180. package/src/host/scene-view-drawability.ts +69 -0
  181. package/src/host/sdk/tools.ts +31 -0
  182. package/src/host/served-bundle-runtime-modules.ts +331 -0
  183. package/src/host/server-log-bridge.ts +60 -0
  184. package/src/host/staged-projects.ts +24 -0
  185. package/src/host/stories/mounted-story-viewport-source.ts +64 -0
  186. package/src/host/stories/story-arg-descriptors.ts +50 -0
  187. package/src/host/stories/story-media-presence.ts +152 -0
  188. package/src/host/surface-content.ts +87 -0
  189. package/src/host/take-named-export.ts +23 -0
  190. package/src/host/three-ingest-runtime.ts +76 -0
  191. package/src/host/types-fastnoise-lite.d.ts +7 -0
  192. package/src/host/types-mikktspace.d.ts +20 -0
  193. package/src/host/types-troika-three-text.d.ts +7 -0
  194. package/src/host/use-active-performance-source.ts +53 -0
  195. package/src/host/viewport-pose-memory.ts +48 -0
  196. package/src/host/viewport-root-presentation.ts +40 -0
  197. package/src/ingest/active-ingest.ts +251 -0
  198. package/src/ingest/active-scene-navigation.ts +43 -0
  199. package/src/ingest/authoring/ingest-dom-surface-authoring.ts +191 -0
  200. package/src/ingest/authoring/ingest-root-adapter.ts +897 -0
  201. package/src/ingest/capture-wait-report.ts +122 -0
  202. package/src/ingest/deferred-ingest-play.ts +216 -0
  203. package/src/ingest/deferred-ingest-session.ts +23 -0
  204. package/src/ingest/discovery-public-ingest.ts +242 -0
  205. package/src/ingest/dom-stub-mark.ts +7 -0
  206. package/src/ingest/entry-load.ts +56 -0
  207. package/src/ingest/game-contract-realm.ts +34 -0
  208. package/src/ingest/game-pointer-lock.ts +89 -0
  209. package/src/ingest/held-scene-repaint.ts +73 -0
  210. package/src/ingest/host-surface-box.ts +174 -0
  211. package/src/ingest/ingest-boot-viewport.ts +54 -0
  212. package/src/ingest/ingest-canvas-scene-document.tsx +177 -0
  213. package/src/ingest/ingest-canvas-scene.ts +50 -0
  214. package/src/ingest/ingest-evidence-hook.ts +131 -0
  215. package/src/ingest/ingest-frame-snapshot.ts +183 -0
  216. package/src/ingest/ingest-play-commands.ts +134 -0
  217. package/src/ingest/ingest-play-control.ts +299 -0
  218. package/src/ingest/ingest-render-debug.ts +320 -0
  219. package/src/ingest/ingest-siblings.ts +487 -0
  220. package/src/ingest/ingest-status.ts +62 -0
  221. package/src/ingest/live-ingest-facet.ts +46 -0
  222. package/src/ingest/module-mode.ts +229 -0
  223. package/src/ingest/mount-canvas-ingest-root.ts +899 -0
  224. package/src/ingest/mount-coverage.ts +296 -0
  225. package/src/ingest/mount-dom-ingest-root.ts +282 -0
  226. package/src/ingest/mount-ingest-root.ts +744 -0
  227. package/src/ingest/mount-three-ingest-root.ts +366 -0
  228. package/src/ingest/resolve-canvas.ts +47 -0
  229. package/src/ingest/resolve-three.ts +123 -0
  230. package/src/ingest/served-bundle.ts +109 -0
  231. package/src/ingest/served-html-boot.ts +292 -0
  232. package/src/ingest/surface-canvas.ts +84 -0
  233. package/src/ingest/surface-dom.ts +84 -0
  234. package/src/ingest/surface-three.ts +128 -0
  235. package/src/ingest/types.ts +76 -0
  236. package/src/ingest/unmount-ingest-root.ts +224 -0
  237. package/src/navmesh/navmesh-actions.ts +27 -0
  238. package/src/navmesh/navmesh-handler.ts +237 -0
  239. package/src/navmesh/navmesh-workflow-store.ts +78 -0
  240. package/src/network/NetworkInspectorPanel.tsx +644 -0
  241. package/src/network/network-inspector-model.ts +225 -0
  242. package/src/play/play-boot-stall.ts +118 -0
  243. package/src/play/play-log-events.ts +26 -0
  244. package/src/play/play-mode.ts +2553 -0
  245. package/src/play/play-recording.ts +335 -0
  246. package/src/play/react-play-live-authoring.ts +165 -0
  247. package/src/play-bar/PlayBar.tsx +488 -0
  248. package/src/play-bar/PlayerCountPicker.tsx +100 -0
  249. package/src/profiler/FrameDebuggerPanel.tsx +458 -0
  250. package/src/profiler/PerformancePanel.tsx +1068 -0
  251. package/src/profiler/ProfilerPanel.tsx +53 -0
  252. package/src/profiler/frame-debugger-store.ts +97 -0
  253. package/src/profiler/main-thread-busy.ts +90 -0
  254. package/src/react/design-time-react-mount.ts +782 -0
  255. package/src/react/dom-authoring-adapter.ts +764 -0
  256. package/src/react/pasteboard-materialize.ts +154 -0
  257. package/src/react/react-inspector-section.tsx +2496 -0
  258. package/src/react/react-world-authoring-adapter.ts +3795 -0
  259. package/src/react/story-documents/story-args-section.ts +19 -0
  260. package/src/react/story-documents/story-documents.tsx +1380 -0
  261. package/src/react/story-paint-bounds.ts +94 -0
  262. package/src/react/ui-board-document.tsx +101 -0
  263. package/src/react/ui-board-title.ts +9 -0
  264. package/src/react/ui-component-board.ts +72 -0
  265. package/src/services/audio-pose-guard.ts +81 -0
  266. package/src/services/game-audio-unlock.ts +48 -0
  267. package/src/state-watch/StateWatchPanel.tsx +535 -0
  268. package/src/three/authoring/camera-runtime-inspector-section.tsx +135 -0
  269. package/src/three/authoring/constraint-inspector-section.tsx +189 -0
  270. package/src/three/authoring/design-time-renderer.ts +189 -0
  271. package/src/three/authoring/model-asset-inspector-section.css +41 -0
  272. package/src/three/authoring/model-asset-inspector-section.tsx +869 -0
  273. package/src/three/authoring/oid-source-persistence.ts +557 -0
  274. package/src/three/authoring/r3f-design-session.ts +1174 -0
  275. package/src/three/authoring/r3f-source-authoring-adapter.ts +5949 -0
  276. package/src/three/authoring/reflection-probe-inspector-section.tsx +76 -0
  277. package/src/three/authoring/spatial-audio-handles.ts +215 -0
  278. package/src/three/authoring/spatial-collider-handles.ts +229 -0
  279. package/src/three/authoring/spatial-joint-handles.ts +114 -0
  280. package/src/three/authoring/spatial-light-handles.ts +178 -0
  281. package/src/three/authoring/spatial-lod-handles.ts +93 -0
  282. package/src/three/authoring/spatial-particle-handles.ts +368 -0
  283. package/src/three/authoring/three-authoring-adapter.ts +1953 -0
  284. package/src/three/authoring/three-scene-identity.ts +19 -0
  285. package/src/three/authoring/three-spatial-handles.ts +161 -0
  286. package/src/three/authoring/typed-three-inspector.ts +528 -0
  287. package/src/three/component-verbs/extract-menu.ts +71 -0
  288. package/src/three/component-verbs/fork-menu.ts +78 -0
  289. package/src/three/component-verbs/internals-menu.ts +91 -0
  290. package/src/three/story-documents/three-story-documents.tsx +607 -0
  291. package/src/three/three-board/ThreeBoardDocument.tsx +888 -0
  292. package/src/three/three-board/board-framing.ts +412 -0
  293. package/src/three/three-board/board-layout.ts +401 -0
  294. package/src/three/three-board/board-scene.ts +901 -0
  295. package/src/three/three-board/three-component-board.ts +62 -0
  296. package/src/xstate/XStateBehaviorSection.tsx +130 -0
  297. package/src/xstate/XStateMachineInspector.tsx +566 -0
  298. package/src/xstate/character-animation-machine.fixture.ts +74 -0
  299. package/src/xstate/live-behaviors.ts +106 -0
  300. package/src/xstate/use-live-actor-state.ts +44 -0
  301. package/src/xstate/xstate-graph.ts +235 -0
  302. package/src/xstate/xstate-layout.ts +76 -0
@@ -0,0 +1,393 @@
1
+ /**
2
+ * ONE manifest root → the surface-tagged adapter that mounts it, plus the
3
+ * DECLARATION the host completes into a `RootBinding` at registration.
4
+ *
5
+ * A game is a native program plus a declaration of itself; the editor is a
6
+ * universal client of that declaration. This module is where the declaration
7
+ * is READ: the manifest root, the project's parsed `vgai.adapter.ts`, and the
8
+ * entry module's own static surface, resolved against ONE realm
9
+ * (`realm-services.ts` — dev or packaged).
10
+ *
11
+ * ## What used to be here, and is not any more
12
+ *
13
+ * The realm question — where a root's entry module is loaded FROM — was
14
+ * answered independently inside the three,
15
+ * canvas and dom resolvers, three copies that had already drifted apart in
16
+ * their error messages and branch order. It is `RealmServices.loadEntryModule`
17
+ * now, asked once per root. Entry adjudication ("what does this three module
18
+ * MEAN?") likewise had two copies calling two DIFFERENT engine doors, one of
19
+ * which crashed the packaged runtime; it is `entry-adjudication.ts` now. The
20
+ * `{ module }` guards live in `roots/module-root.ts`, the two DOM identities in
21
+ * `roots/react-root.ts`, and the ingest descriptors — whose served-bundle
22
+ * choice is per-PROJECT, not per-realm — in `ingest/resolve-{three,canvas}.ts`.
23
+ *
24
+ * ## Why the return is a `{ surface, adapter }` PAIR
25
+ *
26
+ * Every identity produces an adapter for a DIFFERENT render surface, each with
27
+ * its own host-context parameter. A single `Promise<RootAdapter>` channel can
28
+ * only be ONE of them, so callers used to re-assert the real kind with
29
+ * `as unknown as` — kind ERASURE: information the manifest already carried,
30
+ * thrown away here and guessed back there. Widening to a bare union does NOT
31
+ * fix it — a union of function types intersects its parameters, so
32
+ * `.mount(host)` becomes uncallable at every call site. Carrying the surface
33
+ * alongside makes the result a discriminated union, so `switch (r.surface)`
34
+ * narrows `r.adapter` to a single signature.
35
+ */
36
+
37
+ import {
38
+ beginProjectMountEpoch,
39
+ type EntrypointSelectionOverride,
40
+ } from '@volter/editor-sdk/session/project-module-url';
41
+ import {
42
+ nativeDebugBindingFromEntryModule,
43
+ nativeSystemsBindingFromEntryModule,
44
+ } from '@volter/game-runtime/adapter/native-debug-module';
45
+ import type { RootMountSpec } from '@volter/game-runtime/runtime/create-runtime';
46
+ import type { MountEntry } from '@volter/game-runtime/runtime/mount-manifest';
47
+ import type { SurfaceAdapter } from '@volter/editor-project/adapter';
48
+ import type { AdapterDefinition } from '@volter/editor-project/adapter/adapter-module';
49
+ import { assertNever } from '@volter/editor-project/adapter/adapter-surface';
50
+ import type { RootDeclaration } from '@volter/editor-project/adapter/binding';
51
+ import { declaredRoots } from '@volter/editor-project/adapter/manifest-interpreter';
52
+ import type { ResolvedAdapterRoot, ResolvedGameManifest } from '@volter/editor-project/manifest/load';
53
+ import { adjudicateThreeEntry } from './entry-adjudication';
54
+ import { projectAdapterDefinition } from '@volter/editor-core/project-adapter';
55
+ import { activeRealmServices, type RealmServices } from './realm-services';
56
+ import { resolveModuleAdapter } from './roots/module-root';
57
+ import { resolveDomAdapter, resolveIngestReactAdapter } from './roots/react-root';
58
+
59
+ /**
60
+ * What a root's binding is BEFORE anything mounts.
61
+ *
62
+ * `RootBinding` itself cannot exist yet: its `substrate.mounted` is the handle
63
+ * the adapter's `mount` returns, and mounting is the HOST's job, one layer
64
+ * further out. So resolution produces the adapter to mount and the declaration
65
+ * half; `create-runtime.ts`'s `register<Surface>Root` calls
66
+ * `createRootBinding` with both plus `mounted` at registration.
67
+ */
68
+ export interface ResolvedRootBinding {
69
+ readonly adapter: SurfaceAdapter;
70
+ /** Absent only for a captured ingest, which never becomes a `RootAdapter`. */
71
+ readonly declaration: RootDeclaration;
72
+ }
73
+
74
+ /** Optional per-root context for {@link resolveRootBinding}. */
75
+ export interface ResolveRootBindingOptions {
76
+ /**
77
+ * Serve this world's entry with its swap-slot const rewritten to `key`.
78
+ * Host-owned remount — the file on disk is untouched. Dev-only; the browser
79
+ * realms refuse it by name.
80
+ */
81
+ readonly selectionOverride?: EntrypointSelectionOverride | undefined;
82
+ }
83
+
84
+ /**
85
+ * Resolve one manifest root against one realm.
86
+ *
87
+ * `adapterDef` is an INPUT, never something this function goes and fetches:
88
+ * `vgai.adapter.ts` loading stays in `project-adapter.ts`, and the binding is
89
+ * the hand-off's shape rather than a second loader.
90
+ */
91
+ export async function resolveRootBinding(
92
+ root: ResolvedAdapterRoot,
93
+ realm: RealmServices,
94
+ adapterDef: AdapterDefinition | null,
95
+ opts?: ResolveRootBindingOptions,
96
+ ): Promise<ResolvedRootBinding> {
97
+ const { adapter, module } = await resolveSurfaceAdapter(root, realm, opts);
98
+ return { adapter, declaration: declare(root, adapterDef, module) };
99
+ }
100
+
101
+ /** The declaration half: the manifest root, the parsed definition, the entry
102
+ * namespace with its reach stated, and the entry's two static declared
103
+ * bindings harvested from that same namespace. */
104
+ function declare(
105
+ root: ResolvedAdapterRoot,
106
+ definition: AdapterDefinition | null,
107
+ module: Record<string, unknown>,
108
+ ): RootDeclaration {
109
+ const debug = nativeDebugBindingFromEntryModule(root.id, module);
110
+ const systems = nativeSystemsBindingFromEntryModule(root.id, module, root.surface);
111
+ return {
112
+ root,
113
+ definition,
114
+ entry: { reach: 'full', module },
115
+ ...(debug ? { entryDebug: debug } : {}),
116
+ ...(systems ? { entrySystems: systems } : {}),
117
+ };
118
+ }
119
+
120
+ /**
121
+ * The per-identity dispatch. Each branch's tag is the identity's own surface,
122
+ * not a guess: `load.ts` derives a builtin identity FROM the declared surface
123
+ * and an ingest identity likewise, so identity and surface agree by
124
+ * construction. `{ module }` is the one identity that does not fix a surface,
125
+ * and it dispatches on `root.surface` itself.
126
+ */
127
+ async function resolveSurfaceAdapter(
128
+ root: ResolvedAdapterRoot,
129
+ realm: RealmServices,
130
+ opts?: ResolveRootBindingOptions,
131
+ ): Promise<{ adapter: SurfaceAdapter; module: Record<string, unknown> }> {
132
+ const { adapter } = root;
133
+ switch (adapter.identity) {
134
+ case 'three':
135
+ return resolveThreeRoot(root, realm, opts);
136
+ case 'canvas':
137
+ return resolveCanvasRoot(root, realm, opts);
138
+ case 'dom': {
139
+ let module: Record<string, unknown> = {};
140
+ const built = await resolveDomAdapter(root, realm, (m) => {
141
+ module = m;
142
+ });
143
+ return { adapter: { surface: 'dom', adapter: built }, module };
144
+ }
145
+ case 'module': {
146
+ const { resolved, module } = await resolveModuleAdapter(root, realm.projectRoot, realm.epoch);
147
+ return { adapter: resolved, module };
148
+ }
149
+ case 'ingest-react': {
150
+ const { adapter: built, module } = await resolveIngestReactAdapter(root, realm);
151
+ return { adapter: { surface: 'dom', adapter: built }, module };
152
+ }
153
+ case 'ingest-pixi':
154
+ case 'ingest-three':
155
+ return rejectCapturedIngestAsRootAdapter(root);
156
+ default: {
157
+ const exhaustive: never = adapter;
158
+ throw new Error(
159
+ `resolveRootBinding: unhandled adapter identity ${JSON.stringify(exhaustive)}`,
160
+ );
161
+ }
162
+ }
163
+ }
164
+
165
+ /** A three root: `entry` is the only way one is authored, and what that module
166
+ * MEANS is `entry-adjudication.ts`'s single answer. */
167
+ async function resolveThreeRoot(
168
+ root: ResolvedAdapterRoot,
169
+ realm: RealmServices,
170
+ opts?: ResolveRootBindingOptions,
171
+ ): Promise<{ adapter: SurfaceAdapter; module: Record<string, unknown> }> {
172
+ if (root.entry === undefined) {
173
+ // Unreachable in practice: `load.ts` requires `entry` for every three root
174
+ // at manifest-load time.
175
+ throw new Error(
176
+ `resolveRootBinding: world "${root.id}" is a three root with no \`entry\` — this should ` +
177
+ 'have been rejected by manifest validation. A three root is authored as a TSX/R3F world ' +
178
+ 'module.',
179
+ );
180
+ }
181
+ const module = await realm.loadEntryModule(root.entry, root.id, 'three', opts?.selectionOverride);
182
+ const built = await adjudicateThreeEntry(module, root.id, { entryPath: root.entry });
183
+ if (!built) {
184
+ throw new Error(
185
+ `Project script at ${root.entry} neither exports \`adapter\` nor default-exports a ` +
186
+ 'React world component — every explicit first-party entry module satisfies one of the ' +
187
+ 'two (`export default function World() { … }`, or an `adapter` export for full control).',
188
+ );
189
+ }
190
+ return { adapter: { surface: 'three', adapter: built }, module };
191
+ }
192
+
193
+ /**
194
+ * A canvas root is source-as-truth exactly like a three root: its `entry` is a
195
+ * TSX world file, and what that file EXPORTS is adjudicated in ONE place —
196
+ * `resolveCanvasEntryAdapter` (`@volter/game-runtime/canvas-react`, reached through the
197
+ * realm so the packaged runtime takes it from the PROJECT's graph), the same
198
+ * function the standalone mount path uses. Keeping the adjudication there
199
+ * rather than here is what stops the editor and the standalone build from
200
+ * disagreeing about what a world file means.
201
+ */
202
+ async function resolveCanvasRoot(
203
+ root: ResolvedAdapterRoot,
204
+ realm: RealmServices,
205
+ opts?: ResolveRootBindingOptions,
206
+ ): Promise<{ adapter: SurfaceAdapter; module: Record<string, unknown> }> {
207
+ if (root.entry === undefined) {
208
+ throw new Error(
209
+ `resolveRootBinding: world "${root.id}" is a canvas root with no \`entry\` — this should ` +
210
+ 'have been rejected by manifest validation. A canvas root is authored as a TSX world ' +
211
+ 'module; point `entry` at it.',
212
+ );
213
+ }
214
+ const module = await realm.loadEntryModule(
215
+ root.entry,
216
+ root.id,
217
+ 'canvas',
218
+ opts?.selectionOverride,
219
+ );
220
+ const built = await realm.pixiRuntime(module, root.id);
221
+ if (!built) {
222
+ throw new Error(
223
+ `Project script at ${root.entry} (canvas root "${root.id}") must default-export a React ` +
224
+ 'component (`export default function World() { … }`) — or export an `adapter` for full ' +
225
+ 'control.',
226
+ );
227
+ }
228
+ return { adapter: { surface: 'canvas', adapter: built }, module };
229
+ }
230
+
231
+ /**
232
+ * Captured Three/Canvas ingests are not `RootAdapter`s. The foreign game owns
233
+ * the renderer, canvas, loop and capture lifecycle, while a normal
234
+ * `RootAdapter.mount(host)` receives a host-owned renderer/surface. Returning
235
+ * an adapter whose `mount()` only throws would fabricate mountability.
236
+ */
237
+ function rejectCapturedIngestAsRootAdapter(root: ResolvedAdapterRoot): never {
238
+ const resolver =
239
+ root.adapter.identity === 'ingest-pixi'
240
+ ? 'resolveIngest2DDescriptor + mountCanvasIngestRootFromManifest'
241
+ : 'resolveIngestDescriptor + mountThreeIngestRootFromManifest';
242
+ throw new Error(
243
+ `resolveRootBinding: world "${root.id}" (${root.adapter.identity}) is a captured foreign ` +
244
+ `runtime, not a host-mounted RootAdapter; dispatch it through ${resolver}`,
245
+ );
246
+ }
247
+
248
+ // ---------------------------------------------------------------------------
249
+ // Composition
250
+ // ---------------------------------------------------------------------------
251
+
252
+ /** Editor-only context for resolving a whole manifest composition. */
253
+ export interface ResolveAllRootEntriesOptions {
254
+ /**
255
+ * Remount the named region's entrypoint at this swap-slot key. Only that
256
+ * world's entry URL carries the override; siblings share `?vgai-mount=`
257
+ * alone so the module graph stays one instance.
258
+ */
259
+ readonly selectionOverride?:
260
+ | (EntrypointSelectionOverride & { readonly regionId: string })
261
+ | undefined;
262
+ }
263
+
264
+ interface ResolvedComposition {
265
+ readonly roots: { world: ResolvedAdapterRoot; resolved: ResolvedRootBinding }[];
266
+ readonly mountId: string;
267
+ }
268
+
269
+ /**
270
+ * Resolve every declared root in manifest order, against ONE realm and ONE
271
+ * mount epoch.
272
+ *
273
+ * The epoch opens HERE — once, before any root imports its entry — so every
274
+ * root of this composition resolves shared project modules to the same urls.
275
+ * It is the only place that call belongs: it is the single point every
276
+ * multi-root resolve funnels through, and moving it into the per-root
277
+ * resolvers would give each root its own generation, which is the defect.
278
+ *
279
+ * The COMPOSITION level is likewise where the project's two ambient inputs are
280
+ * fetched — the realm's services and the parsed `vgai.adapter.ts` — because
281
+ * both are properties of the open project rather than of any one root, and
282
+ * asking once per composition is what keeps every root of a game bound to the
283
+ * same declaration. `resolveRootBinding` itself still fetches neither: it is
284
+ * handed both, which is the rule that stops it becoming a second loader.
285
+ */
286
+ async function resolveComposition(
287
+ manifest: ResolvedGameManifest,
288
+ projectRoot: string,
289
+ opts?: ResolveAllRootEntriesOptions,
290
+ ): Promise<ResolvedComposition> {
291
+ const epoch = beginProjectMountEpoch();
292
+ const realm = await activeRealmServices(projectRoot, epoch);
293
+ const adapterDef = await projectAdapterDefinition();
294
+
295
+ const out: { world: ResolvedAdapterRoot; resolved: ResolvedRootBinding }[] = [];
296
+ for (const world of declaredRoots(manifest)) {
297
+ const override = opts?.selectionOverride;
298
+ const resolved = await resolveRootBinding(world, realm, adapterDef, {
299
+ ...(override && world.id === override.regionId
300
+ ? { selectionOverride: { selection: override.selection, key: override.key } }
301
+ : {}),
302
+ });
303
+ out.push({ world, resolved });
304
+ }
305
+ // Stringified because that is the form the id travels in everywhere else:
306
+ // the entry url's `?vgai-mount=` value, and therefore the key
307
+ // `gated-globals.ts` reads back off a module url.
308
+ return { roots: out, mountId: String(epoch) };
309
+ }
310
+
311
+ /** Every host-mounted root as a `RootMountSpec[]` — the shape
312
+ * `createGameRuntime({ roots })` takes directly. */
313
+ export async function resolveAllRoots(
314
+ manifest: ResolvedGameManifest,
315
+ projectRoot: string,
316
+ ): Promise<RootMountSpec[]> {
317
+ const { roots } = await resolveComposition(manifest, projectRoot);
318
+
319
+ const specs: RootMountSpec[] = [];
320
+ for (const { world, resolved } of roots) {
321
+ const base = {
322
+ id: world.id,
323
+ zOrder: world.zOrder,
324
+ pausable: world.pausable,
325
+ declaration: resolved.declaration,
326
+ };
327
+ const r = resolved.adapter;
328
+ switch (r.surface) {
329
+ case 'canvas':
330
+ specs.push({ ...base, kind: 'canvas', adapter: r.adapter });
331
+ break;
332
+ case 'dom':
333
+ specs.push({ ...base, kind: 'dom', adapter: r.adapter });
334
+ break;
335
+ case 'three':
336
+ specs.push({ ...base, kind: 'three', adapter: r.adapter });
337
+ break;
338
+ default:
339
+ assertNever(r, 'resolveAllRoots');
340
+ }
341
+ }
342
+ return specs;
343
+ }
344
+
345
+ /**
346
+ * `resolveAllRoots`'s composer-path sibling: the same loop, returning
347
+ * `mountManifestRoots`'s own `entries` shape (`{ kind, adapter }` per world id)
348
+ * instead of a hand-built `RootMountSpec[]` — so `zOrder`/`pausable` and the
349
+ * per-kind spec ASSEMBLY come from `mount-manifest.ts`'s `buildRootMountSpec`,
350
+ * the one authoritative place that translation lives, rather than being
351
+ * duplicated here AND at the `mountManifestRoots` call site.
352
+ *
353
+ * It also returns this composition's `mountId` — the identity the whole
354
+ * isolation layer is keyed by. It is minted here (one epoch per composition),
355
+ * rides every project module url as `?vgai-mount=`, and is what
356
+ * `gated-globals.ts` resolves a realm and an input gate under.
357
+ *
358
+ * It does NOT return the entry modules' harvested `debug`/`systems` bindings.
359
+ * Those ride each root's own declaration into its binding, and
360
+ * `installAdapterRuntimeBindings` reads them off `game.roots` there — one
361
+ * carrier for one fact, instead of a second array the caller had to thread
362
+ * from here to the install site by hand.
363
+ */
364
+ export async function resolveAllRootEntries(
365
+ manifest: ResolvedGameManifest,
366
+ projectRoot: string,
367
+ opts?: ResolveAllRootEntriesOptions,
368
+ ): Promise<{
369
+ entries: Record<string, MountEntry>;
370
+ mountId: string;
371
+ }> {
372
+ const { roots, mountId } = await resolveComposition(manifest, projectRoot, opts);
373
+
374
+ const entries: Record<string, MountEntry> = {};
375
+ for (const { world, resolved } of roots) {
376
+ const { root: _root, ...declaration } = resolved.declaration;
377
+ const r = resolved.adapter;
378
+ switch (r.surface) {
379
+ case 'canvas':
380
+ entries[world.id] = { kind: 'canvas', adapter: r.adapter, declaration };
381
+ break;
382
+ case 'dom':
383
+ entries[world.id] = { kind: 'dom', adapter: r.adapter, declaration };
384
+ break;
385
+ case 'three':
386
+ entries[world.id] = { kind: 'three', adapter: r.adapter, declaration };
387
+ break;
388
+ default:
389
+ assertNever(r, 'resolveAllRootEntries');
390
+ }
391
+ }
392
+ return { entries, mountId };
393
+ }