@vgai/engine 0.5.22 → 0.5.24

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 (303) hide show
  1. package/README.md +6 -3
  2. package/dist/adapter/adapter-module.d.ts.map +1 -1
  3. package/dist/adapter/adapter-module.js +2 -4
  4. package/dist/adapter/adapter-surface.d.ts +1 -1
  5. package/dist/adapter/adapter-surface.js +1 -1
  6. package/dist/adapter/authoring.d.ts +19 -21
  7. package/dist/adapter/authoring.d.ts.map +1 -1
  8. package/dist/adapter/authoring.js +2 -2
  9. package/dist/adapter/binding.d.ts +341 -0
  10. package/dist/adapter/binding.d.ts.map +1 -0
  11. package/dist/adapter/binding.js +148 -0
  12. package/dist/adapter/colyseus-networking-adapter.d.ts.map +1 -1
  13. package/dist/adapter/colyseus-networking-adapter.js +23 -4
  14. package/dist/adapter/entrypoint-selection-readers.d.ts +24 -0
  15. package/dist/adapter/entrypoint-selection-readers.d.ts.map +1 -0
  16. package/dist/adapter/entrypoint-selection-readers.js +63 -0
  17. package/dist/adapter/entrypoint-selection-source.d.ts.map +1 -1
  18. package/dist/adapter/entrypoint-selection-source.js +1 -44
  19. package/dist/adapter/finders/scenes-from-entrypoint-selection.d.ts.map +1 -1
  20. package/dist/adapter/finders/scenes-from-entrypoint-selection.js +1 -52
  21. package/dist/adapter/host-context.d.ts +46 -15
  22. package/dist/adapter/host-context.d.ts.map +1 -1
  23. package/dist/adapter/host-context.js +2 -9
  24. package/dist/adapter/index.d.ts +11 -12
  25. package/dist/adapter/index.d.ts.map +1 -1
  26. package/dist/adapter/index.js +9 -10
  27. package/dist/adapter/ingest/game-contract-seams.d.ts +5 -0
  28. package/dist/adapter/ingest/game-contract-seams.d.ts.map +1 -1
  29. package/dist/adapter/ingest/game-contract-seams.js +1 -0
  30. package/dist/adapter/ingest/game-contract.d.ts +22 -3
  31. package/dist/adapter/ingest/game-contract.d.ts.map +1 -1
  32. package/dist/adapter/ingest/game-contract.js +0 -3
  33. package/dist/adapter/ingest/scene-capture.d.ts +19 -23
  34. package/dist/adapter/ingest/scene-capture.d.ts.map +1 -1
  35. package/dist/adapter/ingest/scene-capture.js +143 -17
  36. package/dist/adapter/ingest/visible-capture-window.d.ts +34 -0
  37. package/dist/adapter/ingest/visible-capture-window.d.ts.map +1 -1
  38. package/dist/adapter/native-debug-module.d.ts +40 -5
  39. package/dist/adapter/native-debug-module.d.ts.map +1 -1
  40. package/dist/adapter/native-debug-module.js +36 -9
  41. package/dist/adapter/rapier-physics-adapter.d.ts +31 -1
  42. package/dist/adapter/rapier-physics-adapter.d.ts.map +1 -1
  43. package/dist/adapter/rapier-physics-adapter.js +50 -36
  44. package/dist/adapter/renderer-config.d.ts +2 -2
  45. package/dist/adapter/renderer-config.js +2 -2
  46. package/dist/adapter/root-adapter.d.ts +7 -7
  47. package/dist/adapter/root-adapter.js +4 -4
  48. package/dist/adapter/system-adapter.d.ts +45 -7
  49. package/dist/adapter/system-adapter.d.ts.map +1 -1
  50. package/dist/adapter/system-seam-contract.d.ts +3 -3
  51. package/dist/adapter/system-seam-contract.js +3 -3
  52. package/dist/adapter/system-slot.d.ts +168 -0
  53. package/dist/adapter/system-slot.d.ts.map +1 -0
  54. package/dist/adapter/system-slot.js +229 -0
  55. package/dist/adapter/transform.d.ts +11 -1
  56. package/dist/adapter/transform.d.ts.map +1 -1
  57. package/dist/ai/navigation.d.ts +17 -1
  58. package/dist/ai/navigation.d.ts.map +1 -1
  59. package/dist/ai/navigation.js +26 -5
  60. package/dist/animation/anim-graph-types.d.ts +11 -3
  61. package/dist/animation/anim-graph-types.d.ts.map +1 -1
  62. package/dist/animation/theatre-clock-binding.d.ts +4 -4
  63. package/dist/animation/theatre-clock-binding.js +4 -4
  64. package/dist/animation/xstate-animation-binding.d.ts.map +1 -1
  65. package/dist/animation/xstate-animation-binding.js +2 -2
  66. package/dist/animation/xstate-animation-meta.d.ts +13 -0
  67. package/dist/animation/xstate-animation-meta.d.ts.map +1 -1
  68. package/dist/animation/xstate-animation-meta.js +14 -0
  69. package/dist/asset-formats/index.d.ts +4 -7
  70. package/dist/asset-formats/index.d.ts.map +1 -1
  71. package/dist/asset-formats/index.js +4 -7
  72. package/dist/asset-formats/render-env.d.ts +5 -8
  73. package/dist/asset-formats/render-env.d.ts.map +1 -1
  74. package/dist/asset-formats/render-env.js +3 -6
  75. package/dist/asset-parse-error.d.ts +2 -5
  76. package/dist/asset-parse-error.d.ts.map +1 -1
  77. package/dist/asset-parse-error.js +2 -5
  78. package/dist/audio/bus-mixer.d.ts +101 -0
  79. package/dist/audio/bus-mixer.d.ts.map +1 -0
  80. package/dist/audio/bus-mixer.js +115 -0
  81. package/dist/core/frame-pacing.d.ts +1 -1
  82. package/dist/core/frame-pacing.js +2 -2
  83. package/dist/core/game-loop.d.ts +1 -3
  84. package/dist/core/game-loop.d.ts.map +1 -1
  85. package/dist/core/game-loop.js +1 -3
  86. package/dist/core/seeded-random.d.ts +1 -1
  87. package/dist/core/sim-clock.d.ts +5 -6
  88. package/dist/core/sim-clock.d.ts.map +1 -1
  89. package/dist/core/sim-clock.js +4 -5
  90. package/dist/core/types.d.ts +1 -3
  91. package/dist/core/types.d.ts.map +1 -1
  92. package/dist/defaults.d.ts +6 -14
  93. package/dist/defaults.d.ts.map +1 -1
  94. package/dist/defaults.js +6 -14
  95. package/dist/dev/register-render-vitals.d.ts +1 -4
  96. package/dist/dev/register-render-vitals.d.ts.map +1 -1
  97. package/dist/dev/register-render-vitals.js +1 -4
  98. package/dist/dev/render-debug-adapter.d.ts +2 -3
  99. package/dist/dev/render-debug-adapter.d.ts.map +1 -1
  100. package/dist/dev/render-debug-adapter.js +2 -3
  101. package/dist/dev/render-vitals.d.ts +3 -3
  102. package/dist/dev/render-vitals.js +3 -3
  103. package/dist/dev/webgl-frame-capture.d.ts +1 -1
  104. package/dist/dev/webgl-frame-capture.js +1 -1
  105. package/dist/index.d.ts +2 -5
  106. package/dist/index.d.ts.map +1 -1
  107. package/dist/index.js +2 -4
  108. package/dist/input/host-pointer.d.ts +122 -0
  109. package/dist/input/host-pointer.d.ts.map +1 -0
  110. package/dist/input/host-pointer.js +160 -0
  111. package/dist/input/input-manager.d.ts +18 -5
  112. package/dist/input/input-manager.d.ts.map +1 -1
  113. package/dist/input/input-manager.js +33 -13
  114. package/dist/input/rebind-controller.d.ts.map +1 -1
  115. package/dist/input/rebind-controller.js +6 -8
  116. package/dist/input/schema.d.ts.map +1 -1
  117. package/dist/input/schema.js +56 -28
  118. package/dist/manifest/filename.d.ts.map +1 -1
  119. package/dist/manifest/filename.js +8 -12
  120. package/dist/manifest/load.d.ts +10 -10
  121. package/dist/manifest/load.d.ts.map +1 -1
  122. package/dist/manifest/load.js +9 -6
  123. package/dist/manifest/schema.d.ts +17 -21
  124. package/dist/manifest/schema.d.ts.map +1 -1
  125. package/dist/manifest/schema.js +45 -35
  126. package/dist/physics/collider-dimensions.d.ts +8 -12
  127. package/dist/physics/collider-dimensions.d.ts.map +1 -1
  128. package/dist/physics/collider-dimensions.js +8 -12
  129. package/dist/pixi/scene-capture.d.ts +11 -13
  130. package/dist/pixi/scene-capture.d.ts.map +1 -1
  131. package/dist/react/world-state.d.ts +1 -1
  132. package/dist/react/world-state.d.ts.map +1 -1
  133. package/dist/render/light-camera-factory.d.ts +5 -7
  134. package/dist/render/light-camera-factory.d.ts.map +1 -1
  135. package/dist/render/light-camera-factory.js +8 -11
  136. package/dist/render/material-factory.js +1 -1
  137. package/dist/render/render-batch-system.d.ts.map +1 -1
  138. package/dist/render/render-features.d.ts +17 -6
  139. package/dist/render/render-features.d.ts.map +1 -1
  140. package/dist/render/render-features.js +0 -28
  141. package/dist/runtime/create-runtime.d.ts +34 -25
  142. package/dist/runtime/create-runtime.d.ts.map +1 -1
  143. package/dist/runtime/create-runtime.js +218 -93
  144. package/dist/runtime/debug-bridge.d.ts +12 -0
  145. package/dist/runtime/debug-bridge.d.ts.map +1 -1
  146. package/dist/runtime/debug-bridge.js +4 -0
  147. package/dist/runtime/debug-registry.d.ts +95 -8
  148. package/dist/runtime/debug-registry.d.ts.map +1 -1
  149. package/dist/runtime/debug-registry.js +24 -3
  150. package/dist/runtime/dev-build.d.ts +2 -2
  151. package/dist/runtime/dev-build.js +2 -2
  152. package/dist/runtime/game-input-seams.d.ts +2 -2
  153. package/dist/runtime/game-input-seams.d.ts.map +1 -1
  154. package/dist/runtime/game.d.ts +102 -41
  155. package/dist/runtime/game.d.ts.map +1 -1
  156. package/dist/runtime/game.js +80 -54
  157. package/dist/runtime/mount-game.d.ts +0 -16
  158. package/dist/runtime/mount-game.d.ts.map +1 -1
  159. package/dist/runtime/mount-game.js +8 -39
  160. package/dist/runtime/mount-manifest.d.ts +22 -14
  161. package/dist/runtime/mount-manifest.d.ts.map +1 -1
  162. package/dist/runtime/mount-manifest.js +18 -18
  163. package/dist/runtime/playtest.d.ts +22 -0
  164. package/dist/runtime/playtest.d.ts.map +1 -0
  165. package/dist/runtime/playtest.js +12 -0
  166. package/dist/runtime/run-ticks-settled.d.ts +34 -0
  167. package/dist/runtime/run-ticks-settled.d.ts.map +1 -0
  168. package/dist/runtime/run-ticks-settled.js +59 -0
  169. package/dist/runtime/state-bridge.d.ts +2 -3
  170. package/dist/runtime/state-bridge.d.ts.map +1 -1
  171. package/dist/runtime/state-bridge.js +1 -0
  172. package/dist/setup/setup-audio.d.ts +12 -0
  173. package/dist/setup/setup-audio.d.ts.map +1 -1
  174. package/dist/setup/setup-audio.js +9 -10
  175. package/dist/setup/setup-renderer.d.ts +2 -25
  176. package/dist/setup/setup-renderer.d.ts.map +1 -1
  177. package/dist/setup/setup-renderer.js +2 -31
  178. package/dist/world3d-react/r3f-root-factory.d.ts +7 -7
  179. package/dist/world3d-react/r3f-root-factory.js +7 -7
  180. package/dist/world3d-react/rapier-physics-bridge.d.ts +9 -8
  181. package/dist/world3d-react/rapier-physics-bridge.d.ts.map +1 -1
  182. package/dist/world3d-react/rapier-physics-bridge.js +100 -48
  183. package/package.json +1 -1
  184. package/schemas/engine-capabilities.json +16 -14
  185. package/schemas/vgai-project.schema.json +35 -26
  186. package/src/adapter/adapter-module.ts +2 -4
  187. package/src/adapter/adapter-surface.ts +1 -1
  188. package/src/adapter/authoring.ts +19 -21
  189. package/src/adapter/binding.ts +468 -0
  190. package/src/adapter/colyseus-networking-adapter.ts +20 -5
  191. package/src/adapter/entrypoint-selection-readers.ts +66 -0
  192. package/src/adapter/entrypoint-selection-source.ts +1 -40
  193. package/src/adapter/finders/scenes-from-entrypoint-selection.ts +1 -48
  194. package/src/adapter/host-context.ts +45 -15
  195. package/src/adapter/index.ts +23 -11
  196. package/src/adapter/ingest/game-contract-seams.ts +1 -0
  197. package/src/adapter/ingest/game-contract.ts +22 -3
  198. package/src/adapter/ingest/scene-capture.ts +190 -39
  199. package/src/adapter/ingest/visible-capture-window.ts +35 -0
  200. package/src/adapter/native-debug-module.ts +66 -9
  201. package/src/adapter/rapier-physics-adapter.ts +76 -20
  202. package/src/adapter/renderer-config.ts +2 -2
  203. package/src/adapter/root-adapter.ts +7 -7
  204. package/src/adapter/system-adapter.ts +43 -8
  205. package/src/adapter/system-seam-contract.ts +3 -3
  206. package/src/adapter/system-slot.ts +291 -0
  207. package/src/adapter/transform.ts +18 -1
  208. package/src/ai/navigation.ts +30 -3
  209. package/src/animation/anim-graph-types.ts +11 -3
  210. package/src/animation/theatre-clock-binding.ts +4 -4
  211. package/src/animation/xstate-animation-binding.ts +2 -2
  212. package/src/animation/xstate-animation-meta.ts +16 -0
  213. package/src/asset-formats/index.ts +4 -7
  214. package/src/asset-formats/render-env.ts +3 -6
  215. package/src/asset-parse-error.ts +2 -5
  216. package/src/audio/bus-mixer.ts +161 -0
  217. package/src/core/frame-pacing.ts +2 -2
  218. package/src/core/game-loop.ts +1 -3
  219. package/src/core/seeded-random.ts +1 -1
  220. package/src/core/sim-clock.ts +5 -6
  221. package/src/core/types.ts +1 -3
  222. package/src/defaults.ts +6 -14
  223. package/src/dev/register-render-vitals.ts +1 -4
  224. package/src/dev/render-debug-adapter.ts +2 -3
  225. package/src/dev/render-vitals.ts +3 -3
  226. package/src/dev/webgl-frame-capture.ts +1 -1
  227. package/src/index.ts +2 -5
  228. package/src/input/host-pointer.ts +230 -0
  229. package/src/input/input-manager.ts +34 -13
  230. package/src/input/input-types.ts +1 -1
  231. package/src/input/rebind-controller.ts +6 -8
  232. package/src/input/schema.ts +216 -188
  233. package/src/manifest/filename.ts +8 -12
  234. package/src/manifest/load.ts +17 -13
  235. package/src/manifest/schema.ts +55 -47
  236. package/src/physics/collider-dimensions.ts +8 -12
  237. package/src/pixi/scene-capture.ts +12 -15
  238. package/src/react/world-state.tsx +1 -1
  239. package/src/render/light-camera-factory.ts +8 -11
  240. package/src/render/material-factory.ts +1 -1
  241. package/src/render/render-batch-system.ts +14 -6
  242. package/src/render/render-features.ts +17 -35
  243. package/src/runtime/create-runtime.ts +270 -108
  244. package/src/runtime/debug-bridge.ts +16 -0
  245. package/src/runtime/debug-registry.ts +121 -8
  246. package/src/runtime/dev-build.ts +2 -2
  247. package/src/runtime/game-input-seams.ts +2 -2
  248. package/src/runtime/game.ts +180 -80
  249. package/src/runtime/mount-game.ts +8 -56
  250. package/src/runtime/mount-manifest.ts +43 -34
  251. package/src/runtime/playtest.ts +22 -0
  252. package/src/runtime/run-ticks-settled.ts +72 -0
  253. package/src/runtime/state-bridge.ts +3 -3
  254. package/src/setup/setup-audio.ts +21 -11
  255. package/src/setup/setup-renderer.ts +2 -61
  256. package/src/world3d-react/r3f-root-factory.tsx +7 -7
  257. package/src/world3d-react/rapier-physics-bridge.tsx +107 -50
  258. package/dist/adapter/setup-three-root-adapter.d.ts +0 -86
  259. package/dist/adapter/setup-three-root-adapter.d.ts.map +0 -1
  260. package/dist/adapter/setup-three-root-adapter.js +0 -908
  261. package/dist/animation/clip-map.d.ts +0 -12
  262. package/dist/animation/clip-map.d.ts.map +0 -1
  263. package/dist/animation/clip-map.js +0 -31
  264. package/dist/asset-registry.d.ts +0 -38
  265. package/dist/asset-registry.d.ts.map +0 -1
  266. package/dist/asset-registry.js +0 -66
  267. package/dist/canvas-react/engine-bridge.d.ts +0 -45
  268. package/dist/canvas-react/engine-bridge.d.ts.map +0 -1
  269. package/dist/canvas-react/engine-bridge.js +0 -45
  270. package/dist/canvas-react/pixi-react-adapter.d.ts +0 -77
  271. package/dist/canvas-react/pixi-react-adapter.d.ts.map +0 -1
  272. package/dist/canvas-react/pixi-react-adapter.js +0 -294
  273. package/dist/canvas-react/world-context.d.ts +0 -98
  274. package/dist/canvas-react/world-context.d.ts.map +0 -1
  275. package/dist/canvas-react/world-context.js +0 -173
  276. package/dist/dev/debug-draw.d.ts +0 -24
  277. package/dist/dev/debug-draw.d.ts.map +0 -1
  278. package/dist/dev/debug-draw.js +0 -73
  279. package/dist/render/auto-batcher.d.ts +0 -34
  280. package/dist/render/auto-batcher.d.ts.map +0 -1
  281. package/dist/render/auto-batcher.js +0 -140
  282. package/dist/render/lod.d.ts +0 -13
  283. package/dist/render/lod.d.ts.map +0 -1
  284. package/dist/render/lod.js +0 -16
  285. package/dist/runtime/types.d.ts +0 -303
  286. package/dist/runtime/types.d.ts.map +0 -1
  287. package/dist/runtime/types.js +0 -1
  288. package/dist/world3d-react/engine-bridge.d.ts +0 -47
  289. package/dist/world3d-react/engine-bridge.d.ts.map +0 -1
  290. package/dist/world3d-react/engine-bridge.js +0 -73
  291. package/dist/world3d-react/r3f-adapter.d.ts +0 -58
  292. package/dist/world3d-react/r3f-adapter.d.ts.map +0 -1
  293. package/dist/world3d-react/r3f-adapter.js +0 -634
  294. package/dist/world3d-react/world-context.d.ts +0 -182
  295. package/dist/world3d-react/world-context.d.ts.map +0 -1
  296. package/dist/world3d-react/world-context.js +0 -235
  297. package/src/adapter/setup-three-root-adapter.ts +0 -1032
  298. package/src/animation/clip-map.ts +0 -34
  299. package/src/asset-registry.ts +0 -89
  300. package/src/dev/debug-draw.ts +0 -80
  301. package/src/render/auto-batcher.ts +0 -168
  302. package/src/render/lod.ts +0 -17
  303. package/src/runtime/types.ts +0 -328
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@vgai/engine",
3
3
  "author": "Volter AI, Inc.",
4
4
  "license": "Apache-2.0",
5
- "version": "0.5.22",
5
+ "version": "0.5.24",
6
6
  "description": "Readable TypeScript game engine and universal host for Three.js, PixiJS, and React games.",
7
7
  "keywords": [
8
8
  "game-engine",
@@ -2,7 +2,7 @@
2
2
  "$comment": "Curated by human/agent review, NOT auto-generated (unlike engine-api.json beside it). Every claim was verified against code — see each entry's `evidence`. Staleness is machine-checked at two granularities: `schemaDirHash` (sha256 over packages/engine/src/asset-formats/) and per-entry `evidenceHashes` (sha256 of each cited evidence FILE — catches drift in files outside the schema dir, which is where most entries' evidence lives; T5.5/§7.2).",
3
3
  "_readme": "Read this before authoring scene JSON or engine code, to avoid the negatives below. Refresh flow after a schema-dir OR evidence-file change: `npx tsx scripts/capabilities-hash.ts --check` (fails naming the stale entry) -> re-review affected entries against current code -> `--write` to record fresh hashes. The pre-commit hook runs --check automatically. Each entry's `evidenceHashes` maps the repo-relative file path parsed off the front of each `evidence[]` citation (before any `:line-range` suffix) to a sha256 of that file's current content.",
4
4
  "schemaDirPath": "packages/engine/src/asset-formats/",
5
- "schemaDirHash": "4b984af5ddc2d4e756db14576a3a267f2d25e0b26490bfb953e614edc635625e",
5
+ "schemaDirHash": "cc141166e16e49380581a0a80f014057b3cf31030df741ce41480a1e8dc8d3f6",
6
6
  "reviewedAt": "2026-07-01",
7
7
  "entries": [
8
8
  {
@@ -11,11 +11,11 @@
11
11
  "status": "unsupported",
12
12
  "claim": "No Continuous Collision Detection (CCD). Fast/small dynamic bodies can tunnel through thin colliders in one step.",
13
13
  "evidence": [
14
- "packages/engine/src/adapter/setup-three-root-adapter.ts (the Rapier home: world init + step; no ccd flag is ever set)"
14
+ "packages/engine/src/world3d-react/rapier-physics-bridge.tsx (the engine's one physics-facing module: observation/debug bridge only — it constructs no world, no bodies, and sets no ccd flag)"
15
15
  ],
16
- "notes": "Grepped packages/engine/src for ccd/CCD/setCcdEnabled: zero matches. The engine constructs no rigid bodies itselfgames build their own descs via ctx.RAPIER and nothing engine-side ever enables ccd. Workaround: keep dynamic-body per-step travel small relative to the thinnest collider, or add intermediate colliders; a game may also call setCcdEnabled on its own bodies directly.",
16
+ "notes": "Grepped packages/engine/src for ccd/CCD/setCcdEnabled: zero matches. The engine constructs no Rapier world or rigid bodies at all physics lives in the game's own tree via @react-three/rapier (<Physics>/<RigidBody>), so CCD is a game choice: @react-three/rapier's `ccd` prop (or setCcdEnabled on a body ref) enables it per body with no engine involvement.",
17
17
  "evidenceHashes": {
18
- "packages/engine/src/adapter/setup-three-root-adapter.ts": "14cef0975f38ecceb25b607ef62232c1002bdd172a3456571f50aa9e39263c0c"
18
+ "packages/engine/src/world3d-react/rapier-physics-bridge.tsx": "03e8b28f7c60884a6fc9f00f488e6e157bc34287670c6cf723ee5e28e7924ce7"
19
19
  }
20
20
  },
21
21
  {
@@ -35,15 +35,17 @@
35
35
  "id": "input-value-model",
36
36
  "area": "input",
37
37
  "status": "supported-with-caveats",
38
- "claim": "F1 (spec §12) added a typed action-value model (digital/scalar/vector2/pointerDelta/pointerPosition, default digital) with real deadzone/combine rules and a valueType-mismatch throw. F2 ('Complete Device Backends') un-rejects mouse_move/gamepad_axis_pair, giving both real readers (mouse_move -> pointerDelta/vector2 off the real mouse-delta accumulator; gamepad_axis_pair -> vector2 off a coupled xAxis/yAxis stick, deadzone-rescaled like gamepad_axis), and adds touch_button/touch_stick (digital/vector2) via setTouchButton/setTouchStick. Real window focus (blur/focus) and pointer-lock state are tracked (requestPointerLock / exitPointerLock) and flush held REAL-device input on loss (#144: virtual/scheduled machine input gates on enabled only and survives blur); gamepad device identity (id/mapping) is exposed via getGamepadInfo/ActionValueSource.gamepadId. F4 adds getLastActiveDevice() + an optional getPrompt device param. Device-poll getters (isDeviceKeyPressed / isDeviceMouseButtonPressed / getDeviceMouseDelta / getDeviceMousePosition / hasDeviceGamepad / isDeviceGamepadButtonPressed / getDeviceGamepadAxis) read the same keysDown/mouseButtons/gamepads stores without inventing implicit actions, and return inert at READ time when inputActive is false. getDeviceGamepadAxis is deliberately RAW — no deadzone: the engine's own stick deadzone is on the action path (gamepad_axis / gamepad_axis_pair, where a game declares and can override it), and a device-door caller that wants a stick applies its own engine's processor (unity-compat reproduces Unity's StickDeadzone at 0.125/0.925). Caveat: pointerPosition still has no real-device backend (test_pointer_position injection only); scalar isn't fed by mouse_move (no axis-select field).",
38
+ "claim": "F1 (spec §12) added a typed action-value model (digital/scalar/vector2/pointerDelta/pointerPosition, default digital) with real deadzone/combine rules and a valueType-mismatch throw. F2 ('Complete Device Backends') un-rejects mouse_move/gamepad_axis_pair, giving both real readers (mouse_move -> pointerDelta/vector2 off the real mouse-delta accumulator; gamepad_axis_pair -> vector2 off a coupled xAxis/yAxis stick, deadzone-rescaled like gamepad_axis), and adds touch_button/touch_stick (digital/vector2) via setTouchButton/setTouchStick. Real window focus (blur/focus) and pointer-lock state are tracked (requestPointerLock / exitPointerLock) and flush held REAL-device input on loss (#144: virtual/scheduled machine input gates on enabled only and survives blur); gamepad device identity (id/mapping) is exposed via getGamepadInfo/ActionValueSource.gamepadId. F4 adds getLastActiveDevice() + an optional getPrompt device param. Device-poll getters (isDeviceKeyPressed / isDeviceMouseButtonPressed / getDeviceMouseDelta / getDeviceMousePosition / hasDeviceGamepad / isDeviceGamepadButtonPressed / getDeviceGamepadAxis) read the same keysDown/mouseButtons/gamepads stores without inventing implicit actions, and return inert at READ time when inputActive is false. getDeviceGamepadAxis is deliberately RAW — no deadzone: the engine's own stick deadzone is on the action path (gamepad_axis / gamepad_axis_pair, where a game declares and can override it), and a device-door caller that wants a stick applies its own engine's processor (unity-compat reproduces Unity's StickDeadzone at 0.125/0.925). The DOM edge those touch setters were written for now ships beside the manager as `input/host-pointer.ts` (`createHostPointer`): the host pointer stream resolved against a render surface, mapped into the game's own design space, with DENSE finger indices and a bounded queue, gated on the manager's own `isInputActive()` (published for exactly that, so a caller never recomposes `isEnabled() && isFocused()` into a looser gate). Caveat on that half: it reports fingers and does not press anything — the control layer (which rect owns which finger, how a knob becomes a stick vector) is the UI's, and no first-party game ships one. Caveat: pointerPosition still has no real-device backend (test_pointer_position injection only); scalar isn't fed by mouse_move (no axis-select field).",
39
39
  "evidence": [
40
40
  "packages/engine/src/input/input-types.ts:2-40 (InputBinding union incl. mouse_move/gamepad_axis_pair/touch_button/touch_stick/test_*)",
41
- "packages/engine/src/input/input-manager.ts (digital/gating/typed getters/device-poll/inject*/setTouch*/getGamepadInfo/F4 getLastActiveDevice+getPrompt/requestPointerLock/exitPointerLock)"
41
+ "packages/engine/src/input/input-manager.ts (digital/gating/typed getters/device-poll/inject*/setTouch*/getGamepadInfo/F4 getLastActiveDevice+getPrompt/requestPointerLock/exitPointerLock)",
42
+ "packages/engine/src/input/host-pointer.ts (createHostPointer: surface/design-space mapping, dense finger indices, isInputActive gate)"
42
43
  ],
43
44
  "notes": "gamepad disconnect/reconnect needs no special-cased code: poll() re-reads navigator.getGamepads() and every read skips a null slot, so a disconnected gamepad's actions go neutral with a correct isJustReleased edge for free — see input-device-backends-f2.test.ts.",
44
45
  "evidenceHashes": {
45
- "packages/engine/src/input/input-types.ts": "62d9005609a72b55a8214c869d1b27825b1a17b9389f3f3f5d0b04725331b382",
46
- "packages/engine/src/input/input-manager.ts": "928a1cde1c7245cfd8afc47794ddf28db8d1368bf7f88e602bb645f79f92ba61"
46
+ "packages/engine/src/input/input-types.ts": "b21ab448fc16d4881c900c57076ca1269241e1b23f8746fb8daa09c628f00f2b",
47
+ "packages/engine/src/input/input-manager.ts": "3cc14b5d3c5097bddfefbf1d620fc1ba8b0fb1d106191d9c640d94723330e888",
48
+ "packages/engine/src/input/host-pointer.ts": "aa012e3ddbcc236240e394614fb9e470e9ea18952faa848ffc1fa6597a2bdda9"
47
49
  }
48
50
  },
49
51
  {
@@ -57,8 +59,8 @@
57
59
  ],
58
60
  "notes": "This is a compatibility integration, not the canonical animation model: project-owned native controllers may drive AnimationMixer directly. When XState is deliberately used, parallel regions use distinct layer names; the binding filters native clip tracks, uses AnimationUtils.makeClipAdditive, can register with ctx.systems, and publishes format-neutral native runtime inspection until disposal.",
59
61
  "evidenceHashes": {
60
- "packages/engine/src/animation/xstate-animation-meta.ts": "80376ac74819803616c4b396244a971cb9a6b2859c33409d032363bfeb3db44f",
61
- "packages/engine/src/animation/xstate-animation-binding.ts": "8ec400c5abe1550a72adca3dfe30e57c42239fdd1eb986b8e05ec973ea3f3d7b"
62
+ "packages/engine/src/animation/xstate-animation-meta.ts": "d976f58b0bbd8b8159209083075c8860e02a59dd2475e55d9551794b06334035",
63
+ "packages/engine/src/animation/xstate-animation-binding.ts": "984db5596e51a2ea4e20e419f94fbb3af47c1abbadfaf80431bcd2ba4577032c"
62
64
  }
63
65
  },
64
66
  {
@@ -73,7 +75,7 @@
73
75
  "notes": "Limits: ARCHITECTURE-CORE.md. Any editor capability a mount does not reach stands warned per capability until it works.",
74
76
  "evidenceHashes": {
75
77
  "vendor/games/verify-unaltered.mjs": "257a362030a10f4d72a3280815069fbd83f436e1619391635b6f8df2ddd6c339",
76
- "packages/engine/src/manifest/schema.ts": "ce385bc9181b82f9d5044da6a41a025a5cb8ba1fc7156263665080c9fdf2b11c"
78
+ "packages/engine/src/manifest/schema.ts": "1f191ca4d77de85bc9ec4dbe4e5cc83c571dab017ff070ac0d5ee344ebec6fa2"
77
79
  }
78
80
  },
79
81
  {
@@ -83,12 +85,12 @@
83
85
  "claim": "Unmodified native-React DOM games run via the manifest `ingest-react` identity: vendored byte-for-byte (vendor/games/, zero-diff CI), mounted through the react world stack under the host React 19 (deduped). NO authoring in v1 (the editor never writes JSX back into an unmodified game, D-N4).",
84
86
  "evidence": [
85
87
  "vendor/games/verify-unaltered.mjs (vendored-bytes gate: zero UNRECORDED diff — byte-identical files, plus any recorded per-file patch that must reverse-apply to the pinned upstream)",
86
- "packages/editor/src/adapter-resolver.ts"
88
+ "packages/editor/src/roots/react-root.ts"
87
89
  ],
88
90
  "notes": "Scope is native-DOM React ONLY (D-N1): R3F/@pixi/react games are canvas games and ride the three.js/pixi seams instead. Generality limit: ONE proven game (react-rpg — menu-to-dungeon e2e under React 19; both game-2 candidates rejected on evidence, R-N7). Game deps must be host-installed root deps (D-N6). Open R-N6: vendored react games' raw window listeners bypass the play-mode input gate.",
89
91
  "evidenceHashes": {
90
92
  "vendor/games/verify-unaltered.mjs": "257a362030a10f4d72a3280815069fbd83f436e1619391635b6f8df2ddd6c339",
91
- "packages/editor/src/adapter-resolver.ts": "63e4204afceb4395f395d5a4df48a5148de75da597a4407ee74ccf233c5d2fa6"
93
+ "packages/editor/src/roots/react-root.ts": "68c54cd5426b4480f40e48f11e1445e85697796c280d4f88addbdcd21981cfbd"
92
94
  }
93
95
  },
94
96
  {
@@ -104,7 +106,7 @@
104
106
  "notes": "This file exists for negatives engine-api.json can't express (e.g. 'parses but does nothing'). For the full positive surface, read engine-api.json/.md — regenerated by `npm run generate-engine-manifest`, can't drift.",
105
107
  "evidenceHashes": {
106
108
  "packages/engine/schemas/engine-api.json": "cdfd395fab88575a13c74451051e6c86f8b07980152120f00caa62098ecf7917",
107
- "packages/engine/src/animation/xstate-animation-binding.ts": "8ec400c5abe1550a72adca3dfe30e57c42239fdd1eb986b8e05ec973ea3f3d7b",
109
+ "packages/engine/src/animation/xstate-animation-binding.ts": "984db5596e51a2ea4e20e419f94fbb3af47c1abbadfaf80431bcd2ba4577032c",
108
110
  "packages/engine/src/animation/blend-node.ts": "9e1d2018acf138bb984fd0d2c7ff1045ef00689e613abf531453af0a1ba06b2e"
109
111
  }
110
112
  }
@@ -35,6 +35,7 @@
35
35
  "required": [
36
36
  "version"
37
37
  ],
38
+ "additionalProperties": false,
38
39
  "description": "Engine version pin"
39
40
  },
40
41
  "roots": {
@@ -138,24 +139,6 @@
138
139
  "captureTimeoutMs": {
139
140
  "description": "How long the host waits for this game's first captured frame before the mount FAILS by name. A game that needs a long boot (streamed world assets, a menu the player must clear) raises it; the default is 10s.",
140
141
  "type": "number"
141
- },
142
- "world": {
143
- "description": "The component this root's WORLD is, in the game's own source — a three root whose scene is a React/R3F component tree names it here. Two readers, and they mount different things: the editor mounts THIS component alone as the root's design-time document (a still scene — its frameloop runs ONE bounded settle at mount, so physics-owned bodies rest at their authored spawn, and is then frozen forever; nothing moves in Edit), while `entry` above stays what PLAY mounts (the whole game, its own composition, its own HUD and loop). Declaring it is what lets a scene be a scene in Edit rather than the running game's mount surfaces. A game whose world is not a component omits it and keeps mounting through `entry` in both modes.",
144
- "type": "object",
145
- "properties": {
146
- "entry": {
147
- "type": "string",
148
- "description": "Project-relative path to the game's OWN module exporting that component"
149
- },
150
- "export": {
151
- "description": "Named export to read from that module; omit when the module default-exports it",
152
- "type": "string"
153
- }
154
- },
155
- "required": [
156
- "entry"
157
- ],
158
- "additionalProperties": false
159
142
  }
160
143
  },
161
144
  "additionalProperties": false,
@@ -181,6 +164,24 @@
181
164
  "type": "string"
182
165
  }
183
166
  },
167
+ "world": {
168
+ "description": "The component this root's WORLD is, in the game's own source. Two readers, and they mount different things: the EDITOR mounts THIS component alone as the root's design-time document, while `entry` above stays what PLAY mounts (the whole game — its own composition, its own HUD, its own loop). It sits on the ROOT rather than inside any one adapter because the split it names is not about ingest: a game whose runtime entry is a SHELL over the thing an author actually edits has this shape whether the source is vendored or first-party. Two shipped cases, one field: an ingested game whose `entry` mounts game+HUD+loop while the named export is the world alone; and a translated Unity/Godot port, whose `entry` is a scene HOST that mounts the scene the built player starts on (`EditorBuildSettings` index 0 — routinely a menu with no 3D content at all) while the named export opens the scene an author edits. That is Unity's own split: build settings say where the PLAYER starts; the Scene view opens a scene, and Unity keeps that fact somewhere else entirely. A game whose world is not a separate component omits this and keeps mounting through `entry` in both modes.",
169
+ "type": "object",
170
+ "properties": {
171
+ "entry": {
172
+ "type": "string",
173
+ "description": "Project-relative path to the game's OWN module exporting that component"
174
+ },
175
+ "export": {
176
+ "description": "Named export to read from that module; omit when the module default-exports it",
177
+ "type": "string"
178
+ }
179
+ },
180
+ "required": [
181
+ "entry"
182
+ ],
183
+ "additionalProperties": false
184
+ },
184
185
  "zOrder": {
185
186
  "default": 0,
186
187
  "description": "Canvas stacking order; ties broken by array order",
@@ -256,12 +257,15 @@
256
257
  "id",
257
258
  "label",
258
259
  "roots"
259
- ]
260
+ ],
261
+ "additionalProperties": false
260
262
  }
261
263
  }
262
- }
264
+ },
265
+ "additionalProperties": false
263
266
  }
264
- }
267
+ },
268
+ "additionalProperties": false
265
269
  },
266
270
  "server": {
267
271
  "description": "Multiplayer server config (Colyseus), if this game registers a room",
@@ -305,7 +309,8 @@
305
309
  },
306
310
  "required": [
307
311
  "room"
308
- ]
312
+ ],
313
+ "additionalProperties": false
309
314
  },
310
315
  "resolution": {
311
316
  "description": "Canvas resolution",
@@ -323,7 +328,8 @@
323
328
  "required": [
324
329
  "width",
325
330
  "height"
326
- ]
331
+ ],
332
+ "additionalProperties": false
327
333
  },
328
334
  "rendering": {
329
335
  "description": "Construction-time renderer properties, which no world can declare after the fact. Everything a world CAN declare (tone mapping, output colour space, clear colour, shadow filter) lives on the world's own renderer config instead.",
@@ -350,7 +356,8 @@
350
356
  },
351
357
  "required": [
352
358
  "allowInProduction"
353
- ]
359
+ ],
360
+ "additionalProperties": false
354
361
  },
355
362
  "determinism": {
356
363
  "description": "Seeded-RNG determinism contract (D15) — governs whether ctx.random is boot-seeded from a reproducible seed and whether the gameplay-rng-ban scan / dev-mode Math.random phase trap are active for this project.",
@@ -369,7 +376,8 @@
369
376
  },
370
377
  "required": [
371
378
  "seededRandom"
372
- ]
379
+ ],
380
+ "additionalProperties": false
373
381
  },
374
382
  "budget": {
375
383
  "description": "Performance budget (W3d, F11 perf regression gates) asserted by `vgai perf --assert-budget`: a seeded, fixed-step headless run samples the engine profiler and fails (nonzero exit) when any metric here is exceeded. Only headlessly-measurable metrics are budgetable; real GPU frame time is not (SwiftShader).",
@@ -403,7 +411,8 @@
403
411
  "exclusiveMinimum": 0,
404
412
  "maximum": 9007199254740991
405
413
  }
406
- }
414
+ },
415
+ "additionalProperties": false
407
416
  },
408
417
  "learn": {
409
418
  "description": "Optional learner-facing metadata (FT-5) — set on shipped example projects so the gallery/wizard/Learn-catalog registries can be generated from the manifest itself",
@@ -325,10 +325,8 @@ const AdapterRegionOverlaySchema = z
325
325
  * the full REPLACEMENT, and its entries carry `include`/`mounts` themselves.
326
326
  * Two homes for one fact is how a declaration goes stale in one of them.
327
327
  *
328
- * MEASURED BASIS (PR #2281, verified twice): the region binding was
329
- * replace-only, so no `nativeAdapter()` project could declare a single include
330
- * without restating every region — which is what blocked the source-text R3F
331
- * floor's retirement across the five shipped 3D projects.
328
+ * MEASURED BASIS: a replace-only region binding means no `nativeAdapter()`
329
+ * project can declare a single include without restating every region.
332
330
  */
333
331
  const RegionIncludesSchema = z
334
332
  .record(z.string().min(1), AdapterRegionOverlaySchema)
@@ -18,7 +18,7 @@ export type AdapterSurface = 'three' | 'canvas' | 'dom';
18
18
  * site, not silently contribute nothing or silently default to an existing
19
19
  * kind). Lives here — colocated with the kind vocabulary itself, not in a
20
20
  * generic util module — so the three call sites that need it
21
- * (`runtime/create-runtime.ts`'s mount loop, `editor/adapter-resolver.ts`'s
21
+ * (`runtime/create-runtime.ts`'s mount loop, `editor/binding-resolver.ts`'s
22
22
  * `resolveAllRoots`, `editor/play-mode.ts`'s `installMultiRootAuthoring`)
23
23
  * import it from the same leaf module that defines `AdapterSurface`, keeping the
24
24
  * type and its guard from drifting apart. The `never` parameter is the
@@ -2,8 +2,8 @@
2
2
  * AuthoringAdapter — the editor's authoring contract. The editor talks to THIS,
3
3
  * keyed by opaque string node ids, instead of to a concrete document format.
4
4
  *
5
- * `.vscn` / `SceneEntity` is the private model of ONE implementer
6
- * (`VgaiSceneAuthoringAdapter`); an ingested game's adapter implements the same
5
+ * An implementer's document model is its own private business; an ingested
6
+ * game's adapter implements the same
7
7
  * providers directly over its live `Object3D` tree. The editor sees only the
8
8
  * interface and the advertised `capabilities` — it never branches on which
9
9
  * implementer it is talking to.
@@ -29,8 +29,7 @@ import type { Transform } from './transform';
29
29
  * Deliberately SMALL: a capability flag earns its place only when the shell
30
30
  * actually branches on it. Structural affordances (create/delete/reparent) are
31
31
  * gated by `structure` PROVIDER PRESENCE instead — the flag and the provider
32
- * cannot disagree that way. (WO-2 deleted `material`/`create`/`delete`/
33
- * `reparent`/`layout`, which no shell code ever read.)
32
+ * cannot disagree that way.
34
33
  */
35
34
  export interface AuthoringCapabilities {
36
35
  transform: boolean;
@@ -89,7 +88,7 @@ export type EditorNodeRole =
89
88
  | 'entity'
90
89
  | 'boundary';
91
90
 
92
- /** A node in the authoring hierarchy — format-neutral (not a `SceneEntity`). */
91
+ /** A node in the authoring hierarchy — format-neutral. */
93
92
  export interface EditorNode {
94
93
  /** STABLE id — survives reload (see ingest structural-path ids). */
95
94
  id: string;
@@ -202,9 +201,9 @@ export interface SelectionProvider {
202
201
  }
203
202
 
204
203
  /** Adapter-owned result of semantic selection resolution: the raw native/render
205
- * hit mapped to the node the author actually means. (The former
206
- * `inspectorId`/`transformId`/`boundaryId` aliases were never read by the
207
- * shell deleted in WO-2.) */
204
+ * hit mapped to the node the author actually means. ONE id, deliberately:
205
+ * separate inspector/transform/boundary aliases would have to agree, and
206
+ * nothing in the shell can enforce that. */
208
207
  export interface SelectionResolution {
209
208
  /** Hierarchy selection and Inspector subject. */
210
209
  id: string;
@@ -316,7 +315,7 @@ export interface TransformObservation {
316
315
  }
317
316
 
318
317
  export interface InspectorProvider {
319
- /** Schema-driven — NOT fixed to `SceneEntity`. */
318
+ /** Schema-driven — fixed to no document format. */
320
319
  properties(id: string): PropertyDescriptor[];
321
320
  get(id: string, path: string): unknown;
322
321
  /**
@@ -620,24 +619,24 @@ export interface PersistenceProvider {
620
619
  * subsequent persistence clears it. Auto-saving source adapters use this to
621
620
  * report a rolled-back source write without inventing a dirty document. */
622
621
  lastError?(): string | null;
623
- /** Save to the adapter's OWN source of truth (.vscn / overlay file / …). */
622
+ /** Save to the adapter's OWN source of truth (its source file, its own
623
+ * data, …) — whatever that adapter defines it to be. */
624
624
  save(): Promise<void>;
625
625
  /**
626
626
  * Human/agent-readable destination this provider persists to — e.g.
627
- * `"scenes/main.vscn.json"`, `"live-only (not saved)"`, or `"ephemeral
627
+ * `"src/world.tsx"`, `"live-only (not saved)"`, or `"ephemeral
628
628
  * (discarded on stop)"`. Drives the save-status UI and makes routing
629
629
  * inspectable (design §2). Implementers whose destination can change during
630
- * the session (e.g. the first-party provider tracks the loaded `.vscn` path)
630
+ * the session (a provider that tracks the currently focused document, say)
631
631
  * should expose this as a live getter rather than a value captured once.
632
632
  */
633
633
  readonly destination: string;
634
634
  /**
635
635
  * The reload contract (design §5): apply an external change to this
636
636
  * provider's persisted artifact into the RUNNING session (e.g. a file-watcher
637
- * update to the `.vscn` or the overlay). Absent ⇒ the host must remount to
638
- * pick up external changes (the honest floor). Implemented (T3.2 slice 3) by
639
- * the first-party provider (`applyExternalUpdate`) and the ingest overlay
640
- * provider (`applyOverlay`); absent (correctly) on the ephemeral provider.
637
+ * update to the artifact). Absent ⇒ the host must remount to
638
+ * pick up external changes the honest floor, and correctly what the
639
+ * ephemeral provider reports.
641
640
  *
642
641
  * `rawContent`, when the host has it (the file-watcher SSE payload carries the
643
642
  * artifact's exact bytes), is an OPTIONAL second parameter enabling own-echo
@@ -823,7 +822,7 @@ export interface ColorSampleProvider {
823
822
  }
824
823
 
825
824
  /**
826
- * WO-IDX1 — where a node's live object CAME FROM in the game's own truth.
825
+ * Where a node's live object CAME FROM in the game's own truth.
827
826
  *
828
827
  * `display` is the string the editor shows verbatim. The unanchored shape
829
828
  * carries a `reason` rather than a blank, because "we don't know" and "a
@@ -1172,10 +1171,9 @@ export interface AuthoringAdapter {
1172
1171
  * Observe transform GESTURES on this adapter's nodes — the one seam the
1173
1172
  * animation sequencer needs to record a drag as keyframes and to refresh its
1174
1173
  * design baselines. Deliberately narrow (one event shape, one consumer, no
1175
- * general event bus): before it existed, the sequencer could only observe
1176
- * the first-party store's own `.vscn` transform path, so a live or
1177
- * source-backed world's gestures were invisible to it. Absent ⇒ this
1178
- * adapter reports no gestures.
1174
+ * general event bus): without it the sequencer can only observe the store's
1175
+ * own transform path, so a live or source-backed world's gestures are
1176
+ * invisible to it. Absent ⇒ this adapter reports no gestures.
1179
1177
  */
1180
1178
  observeTransforms?(listener: (event: TransformObservation) => void): () => void;
1181
1179
  }