@vgai/engine 0.5.21 → 0.5.23

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 (339) 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.d.ts +0 -3
  28. package/dist/adapter/ingest/game-contract.d.ts.map +1 -1
  29. package/dist/adapter/ingest/game-contract.js +0 -3
  30. package/dist/adapter/ingest/scene-capture.d.ts +19 -23
  31. package/dist/adapter/ingest/scene-capture.d.ts.map +1 -1
  32. package/dist/adapter/ingest/scene-capture.js +143 -17
  33. package/dist/adapter/ingest/visible-capture-window.d.ts +34 -0
  34. package/dist/adapter/ingest/visible-capture-window.d.ts.map +1 -1
  35. package/dist/adapter/manifest-interpreter.d.ts +59 -0
  36. package/dist/adapter/manifest-interpreter.d.ts.map +1 -0
  37. package/dist/adapter/manifest-interpreter.js +50 -0
  38. package/dist/adapter/native-debug-module.d.ts +71 -3
  39. package/dist/adapter/native-debug-module.d.ts.map +1 -1
  40. package/dist/adapter/native-debug-module.js +146 -10
  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 +3 -3
  45. package/dist/adapter/renderer-config.js +3 -3
  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/canvas-react/index.d.ts +5 -12
  82. package/dist/canvas-react/index.d.ts.map +1 -1
  83. package/dist/canvas-react/index.js +5 -12
  84. package/dist/canvas-react/pixi-react-root-factory.d.ts +34 -21
  85. package/dist/canvas-react/pixi-react-root-factory.d.ts.map +1 -1
  86. package/dist/canvas-react/pixi-react-root-factory.js +274 -36
  87. package/dist/core/countdown-timer.d.ts +118 -0
  88. package/dist/core/countdown-timer.d.ts.map +1 -0
  89. package/dist/core/countdown-timer.js +137 -0
  90. package/dist/core/deferred-commands.d.ts +127 -0
  91. package/dist/core/deferred-commands.d.ts.map +1 -0
  92. package/dist/core/deferred-commands.js +132 -0
  93. package/dist/core/frame-pacing.d.ts +1 -1
  94. package/dist/core/frame-pacing.js +2 -2
  95. package/dist/core/game-loop.d.ts +1 -3
  96. package/dist/core/game-loop.d.ts.map +1 -1
  97. package/dist/core/game-loop.js +1 -3
  98. package/dist/core/seeded-random.d.ts +1 -1
  99. package/dist/core/sim-clock.d.ts +19 -8
  100. package/dist/core/sim-clock.d.ts.map +1 -1
  101. package/dist/core/sim-clock.js +18 -7
  102. package/dist/core/types.d.ts +1 -3
  103. package/dist/core/types.d.ts.map +1 -1
  104. package/dist/defaults.d.ts +6 -14
  105. package/dist/defaults.d.ts.map +1 -1
  106. package/dist/defaults.js +6 -14
  107. package/dist/dev/instruments.d.ts +38 -11
  108. package/dist/dev/instruments.d.ts.map +1 -1
  109. package/dist/dev/instruments.js +81 -11
  110. package/dist/dev/register-render-vitals.d.ts +1 -4
  111. package/dist/dev/register-render-vitals.d.ts.map +1 -1
  112. package/dist/dev/register-render-vitals.js +1 -4
  113. package/dist/dev/render-debug-adapter.d.ts +2 -3
  114. package/dist/dev/render-debug-adapter.d.ts.map +1 -1
  115. package/dist/dev/render-debug-adapter.js +2 -3
  116. package/dist/dev/render-vitals.d.ts +3 -3
  117. package/dist/dev/render-vitals.js +3 -3
  118. package/dist/dev/webgl-frame-capture.d.ts +1 -1
  119. package/dist/dev/webgl-frame-capture.js +1 -1
  120. package/dist/index.d.ts +2 -5
  121. package/dist/index.d.ts.map +1 -1
  122. package/dist/index.js +2 -4
  123. package/dist/input/host-pointer.d.ts +122 -0
  124. package/dist/input/host-pointer.d.ts.map +1 -0
  125. package/dist/input/host-pointer.js +160 -0
  126. package/dist/input/input-manager.d.ts +33 -5
  127. package/dist/input/input-manager.d.ts.map +1 -1
  128. package/dist/input/input-manager.js +48 -13
  129. package/dist/input/rebind-controller.d.ts.map +1 -1
  130. package/dist/input/rebind-controller.js +6 -8
  131. package/dist/input/schema.d.ts.map +1 -1
  132. package/dist/input/schema.js +56 -28
  133. package/dist/manifest/filename.d.ts.map +1 -1
  134. package/dist/manifest/filename.js +8 -12
  135. package/dist/manifest/load.d.ts +10 -10
  136. package/dist/manifest/load.d.ts.map +1 -1
  137. package/dist/manifest/load.js +9 -6
  138. package/dist/manifest/schema.d.ts +17 -21
  139. package/dist/manifest/schema.d.ts.map +1 -1
  140. package/dist/manifest/schema.js +45 -35
  141. package/dist/physics/collider-dimensions.d.ts +8 -12
  142. package/dist/physics/collider-dimensions.d.ts.map +1 -1
  143. package/dist/physics/collider-dimensions.js +8 -12
  144. package/dist/pixi/scene-capture.d.ts +11 -13
  145. package/dist/pixi/scene-capture.d.ts.map +1 -1
  146. package/dist/react/world-state.d.ts +1 -1
  147. package/dist/react/world-state.d.ts.map +1 -1
  148. package/dist/render/directional-shadow-fit.d.ts +88 -0
  149. package/dist/render/directional-shadow-fit.d.ts.map +1 -0
  150. package/dist/render/directional-shadow-fit.js +133 -0
  151. package/dist/render/environment-capture.d.ts +68 -0
  152. package/dist/render/environment-capture.d.ts.map +1 -0
  153. package/dist/render/environment-capture.js +90 -0
  154. package/dist/render/ibl-override-material.d.ts +97 -0
  155. package/dist/render/ibl-override-material.d.ts.map +1 -0
  156. package/dist/render/ibl-override-material.js +114 -0
  157. package/dist/render/light-camera-factory.d.ts +5 -7
  158. package/dist/render/light-camera-factory.d.ts.map +1 -1
  159. package/dist/render/light-camera-factory.js +8 -11
  160. package/dist/render/material-factory.js +1 -1
  161. package/dist/render/render-batch-system.d.ts.map +1 -1
  162. package/dist/render/render-features.d.ts +17 -6
  163. package/dist/render/render-features.d.ts.map +1 -1
  164. package/dist/render/render-features.js +0 -28
  165. package/dist/runtime/create-runtime.d.ts +34 -25
  166. package/dist/runtime/create-runtime.d.ts.map +1 -1
  167. package/dist/runtime/create-runtime.js +218 -93
  168. package/dist/runtime/debug-registry.d.ts +77 -8
  169. package/dist/runtime/debug-registry.d.ts.map +1 -1
  170. package/dist/runtime/debug-registry.js +3 -3
  171. package/dist/runtime/dev-build.d.ts +2 -2
  172. package/dist/runtime/dev-build.js +2 -2
  173. package/dist/runtime/game-input-seams.d.ts +51 -0
  174. package/dist/runtime/game-input-seams.d.ts.map +1 -0
  175. package/dist/runtime/game-input-seams.js +86 -0
  176. package/dist/runtime/game.d.ts +104 -40
  177. package/dist/runtime/game.d.ts.map +1 -1
  178. package/dist/runtime/game.js +119 -61
  179. package/dist/runtime/mount-game.d.ts +0 -16
  180. package/dist/runtime/mount-game.d.ts.map +1 -1
  181. package/dist/runtime/mount-game.js +26 -41
  182. package/dist/runtime/mount-manifest.d.ts +22 -14
  183. package/dist/runtime/mount-manifest.d.ts.map +1 -1
  184. package/dist/runtime/mount-manifest.js +22 -20
  185. package/dist/runtime/playtest.d.ts +22 -0
  186. package/dist/runtime/playtest.d.ts.map +1 -0
  187. package/dist/runtime/playtest.js +12 -0
  188. package/dist/runtime/state-bridge.d.ts +2 -3
  189. package/dist/runtime/state-bridge.d.ts.map +1 -1
  190. package/dist/runtime/state-bridge.js +1 -0
  191. package/dist/setup/setup-audio.d.ts +12 -0
  192. package/dist/setup/setup-audio.d.ts.map +1 -1
  193. package/dist/setup/setup-audio.js +9 -10
  194. package/dist/setup/setup-renderer.d.ts +2 -25
  195. package/dist/setup/setup-renderer.d.ts.map +1 -1
  196. package/dist/setup/setup-renderer.js +2 -31
  197. package/dist/world3d-react/index.d.ts +15 -25
  198. package/dist/world3d-react/index.d.ts.map +1 -1
  199. package/dist/world3d-react/index.js +15 -25
  200. package/dist/world3d-react/r3f-root-factory.d.ts +28 -34
  201. package/dist/world3d-react/r3f-root-factory.d.ts.map +1 -1
  202. package/dist/world3d-react/r3f-root-factory.js +403 -57
  203. package/dist/world3d-react/rapier-physics-bridge.d.ts +30 -17
  204. package/dist/world3d-react/rapier-physics-bridge.d.ts.map +1 -1
  205. package/dist/world3d-react/rapier-physics-bridge.js +143 -58
  206. package/package.json +1 -1
  207. package/schemas/engine-capabilities.json +16 -14
  208. package/schemas/vgai-project.schema.json +35 -26
  209. package/src/adapter/adapter-module.ts +2 -4
  210. package/src/adapter/adapter-surface.ts +1 -1
  211. package/src/adapter/authoring.ts +19 -21
  212. package/src/adapter/binding.ts +468 -0
  213. package/src/adapter/colyseus-networking-adapter.ts +20 -5
  214. package/src/adapter/entrypoint-selection-readers.ts +66 -0
  215. package/src/adapter/entrypoint-selection-source.ts +1 -40
  216. package/src/adapter/finders/scenes-from-entrypoint-selection.ts +1 -48
  217. package/src/adapter/host-context.ts +45 -15
  218. package/src/adapter/index.ts +23 -11
  219. package/src/adapter/ingest/game-contract.ts +0 -3
  220. package/src/adapter/ingest/scene-capture.ts +190 -39
  221. package/src/adapter/ingest/visible-capture-window.ts +35 -0
  222. package/src/adapter/manifest-interpreter.ts +64 -0
  223. package/src/adapter/native-debug-module.ts +248 -15
  224. package/src/adapter/rapier-physics-adapter.ts +76 -20
  225. package/src/adapter/renderer-config.ts +3 -3
  226. package/src/adapter/root-adapter.ts +7 -7
  227. package/src/adapter/system-adapter.ts +43 -8
  228. package/src/adapter/system-seam-contract.ts +3 -3
  229. package/src/adapter/system-slot.ts +291 -0
  230. package/src/adapter/transform.ts +18 -1
  231. package/src/ai/navigation.ts +30 -3
  232. package/src/animation/anim-graph-types.ts +11 -3
  233. package/src/animation/theatre-clock-binding.ts +4 -4
  234. package/src/animation/xstate-animation-binding.ts +2 -2
  235. package/src/animation/xstate-animation-meta.ts +16 -0
  236. package/src/asset-formats/index.ts +4 -7
  237. package/src/asset-formats/render-env.ts +3 -6
  238. package/src/asset-parse-error.ts +2 -5
  239. package/src/audio/bus-mixer.ts +161 -0
  240. package/src/canvas-react/index.ts +5 -21
  241. package/src/canvas-react/pixi-react-root-factory.tsx +301 -39
  242. package/src/core/countdown-timer.ts +188 -0
  243. package/src/core/deferred-commands.ts +174 -0
  244. package/src/core/frame-pacing.ts +2 -2
  245. package/src/core/game-loop.ts +1 -3
  246. package/src/core/seeded-random.ts +1 -1
  247. package/src/core/sim-clock.ts +19 -8
  248. package/src/core/types.ts +1 -3
  249. package/src/defaults.ts +6 -14
  250. package/src/dev/instruments.ts +108 -11
  251. package/src/dev/register-render-vitals.ts +1 -4
  252. package/src/dev/render-debug-adapter.ts +2 -3
  253. package/src/dev/render-vitals.ts +3 -3
  254. package/src/dev/webgl-frame-capture.ts +1 -1
  255. package/src/index.ts +2 -5
  256. package/src/input/host-pointer.ts +230 -0
  257. package/src/input/input-manager.ts +49 -13
  258. package/src/input/input-types.ts +1 -1
  259. package/src/input/rebind-controller.ts +6 -8
  260. package/src/input/schema.ts +216 -188
  261. package/src/manifest/filename.ts +8 -12
  262. package/src/manifest/load.ts +17 -13
  263. package/src/manifest/schema.ts +55 -47
  264. package/src/physics/collider-dimensions.ts +8 -12
  265. package/src/pixi/scene-capture.ts +12 -15
  266. package/src/react/world-state.tsx +1 -1
  267. package/src/render/directional-shadow-fit.ts +156 -0
  268. package/src/render/environment-capture.ts +102 -0
  269. package/src/render/ibl-override-material.ts +170 -0
  270. package/src/render/light-camera-factory.ts +8 -11
  271. package/src/render/material-factory.ts +1 -1
  272. package/src/render/render-batch-system.ts +14 -6
  273. package/src/render/render-features.ts +17 -35
  274. package/src/runtime/create-runtime.ts +270 -108
  275. package/src/runtime/debug-registry.ts +84 -8
  276. package/src/runtime/dev-build.ts +2 -2
  277. package/src/runtime/game-input-seams.ts +108 -0
  278. package/src/runtime/game.ts +231 -85
  279. package/src/runtime/mount-game.ts +31 -57
  280. package/src/runtime/mount-manifest.ts +47 -36
  281. package/src/runtime/playtest.ts +22 -0
  282. package/src/runtime/state-bridge.ts +3 -3
  283. package/src/setup/setup-audio.ts +21 -11
  284. package/src/setup/setup-renderer.ts +2 -61
  285. package/src/world3d-react/index.ts +15 -31
  286. package/src/world3d-react/r3f-root-factory.tsx +451 -60
  287. package/src/world3d-react/rapier-physics-bridge.tsx +154 -58
  288. package/dist/adapter/setup-three-root-adapter.d.ts +0 -86
  289. package/dist/adapter/setup-three-root-adapter.d.ts.map +0 -1
  290. package/dist/adapter/setup-three-root-adapter.js +0 -908
  291. package/dist/animation/clip-map.d.ts +0 -12
  292. package/dist/animation/clip-map.d.ts.map +0 -1
  293. package/dist/animation/clip-map.js +0 -31
  294. package/dist/asset-registry.d.ts +0 -38
  295. package/dist/asset-registry.d.ts.map +0 -1
  296. package/dist/asset-registry.js +0 -66
  297. package/dist/canvas-react/engine-bridge.d.ts +0 -45
  298. package/dist/canvas-react/engine-bridge.d.ts.map +0 -1
  299. package/dist/canvas-react/engine-bridge.js +0 -45
  300. package/dist/canvas-react/pixi-react-adapter.d.ts +0 -77
  301. package/dist/canvas-react/pixi-react-adapter.d.ts.map +0 -1
  302. package/dist/canvas-react/pixi-react-adapter.js +0 -294
  303. package/dist/canvas-react/world-context.d.ts +0 -98
  304. package/dist/canvas-react/world-context.d.ts.map +0 -1
  305. package/dist/canvas-react/world-context.js +0 -173
  306. package/dist/dev/debug-draw.d.ts +0 -24
  307. package/dist/dev/debug-draw.d.ts.map +0 -1
  308. package/dist/dev/debug-draw.js +0 -73
  309. package/dist/render/auto-batcher.d.ts +0 -34
  310. package/dist/render/auto-batcher.d.ts.map +0 -1
  311. package/dist/render/auto-batcher.js +0 -140
  312. package/dist/render/lod.d.ts +0 -13
  313. package/dist/render/lod.d.ts.map +0 -1
  314. package/dist/render/lod.js +0 -16
  315. package/dist/runtime/types.d.ts +0 -303
  316. package/dist/runtime/types.d.ts.map +0 -1
  317. package/dist/runtime/types.js +0 -1
  318. package/dist/world3d-react/engine-bridge.d.ts +0 -47
  319. package/dist/world3d-react/engine-bridge.d.ts.map +0 -1
  320. package/dist/world3d-react/engine-bridge.js +0 -73
  321. package/dist/world3d-react/r3f-adapter.d.ts +0 -58
  322. package/dist/world3d-react/r3f-adapter.d.ts.map +0 -1
  323. package/dist/world3d-react/r3f-adapter.js +0 -634
  324. package/dist/world3d-react/world-context.d.ts +0 -182
  325. package/dist/world3d-react/world-context.d.ts.map +0 -1
  326. package/dist/world3d-react/world-context.js +0 -235
  327. package/src/adapter/setup-three-root-adapter.ts +0 -1032
  328. package/src/animation/clip-map.ts +0 -34
  329. package/src/asset-registry.ts +0 -89
  330. package/src/canvas-react/engine-bridge.ts +0 -59
  331. package/src/canvas-react/pixi-react-adapter.tsx +0 -356
  332. package/src/canvas-react/world-context.ts +0 -253
  333. package/src/dev/debug-draw.ts +0 -80
  334. package/src/render/auto-batcher.ts +0 -168
  335. package/src/render/lod.ts +0 -17
  336. package/src/runtime/types.ts +0 -328
  337. package/src/world3d-react/engine-bridge.ts +0 -86
  338. package/src/world3d-react/r3f-adapter.tsx +0 -717
  339. package/src/world3d-react/world-context.ts +0 -358
@@ -43,8 +43,8 @@
43
43
  * OWNER: the caller of {@link createRenderVitals}, which allocates one state
44
44
  * object and one `profiler.subscribe` registration. SHARER: none — the state
45
45
  * is private to that call. TEARDOWN: the returned `dispose()`, the ONE path
46
- * that ends the subscription (`setup-three-root-adapter.ts` calls it from
47
- * `disposeGame`).
46
+ * that ends the subscription (`world3d-react/r3f-root-factory.tsx` calls it
47
+ * from the mounted root's own `dispose()`).
48
48
  */
49
49
 
50
50
  import type { PerformanceFrame, PerformanceProfiler } from './performance-profiler';
@@ -52,7 +52,7 @@ import type { PerformanceFrame, PerformanceProfiler } from './performance-profil
52
52
  /**
53
53
  * The profiler phase name the three adapter brackets its CPU render
54
54
  * submission with — spelled HERE and nowhere else, so the producer
55
- * (`setup-three-root-adapter.ts`) and the consumer ({@link foldProfilerFrame})
55
+ * (`world3d-react/r3f-root-factory.tsx`) and the consumer ({@link foldProfilerFrame})
56
56
  * cannot drift apart. Dotted, so it reads as a decomposition of the enclosing
57
57
  * `render` phase rather than a ninth peer of `SystemPhase`.
58
58
  */
@@ -4,7 +4,7 @@
4
4
  * WHY FIRST-PARTY, NOT spectorjs (recorded per the "use libraries directly, no
5
5
  * wrappers" rule): the capture seam we need is the WebGL2 context this engine
6
6
  * ALREADY owns end-to-end (`renderer.getContext()` in
7
- * `setup-three-root-adapter.ts`). spectorjs is absent from node_modules, and its
7
+ * `world3d-react/r3f-root-factory.tsx`). spectorjs is absent from node_modules, and its
8
8
  * actual value is a bundled inspector UI we would discard — adopting it imports
9
9
  * ~2MB of library to keep ~10% of it, and it wraps the context with its own
10
10
  * global patching model rather than the instance-shadow-and-restore discipline
package/src/index.ts CHANGED
@@ -10,21 +10,19 @@
10
10
  * remain the primary way to reach engine internals — reach for a subpath
11
11
  * first. This barrel exists only so the package's bare-name entry point is
12
12
  * HONEST (resolves to something real and useful) instead of dangling; it
13
- * covers just the handful of symbols a game/consumer needs to author a
14
- * first-party `setup()` and mount it, plus the scene/manifest file
13
+ * covers just the handful of symbols a consumer needs to mount a game
14
+ * from its manifest, plus the manifest file
15
15
  * entry points. Keep it small when extending it — prefer a new subpath
16
16
  * export over growing this file into a firehose.
17
17
  *
18
18
  * Groups (import order below is alphabetical-by-specifier, per the repo's
19
19
  * biome `organizeImports` rule, not by group — see this list instead):
20
- * - game setup contract: `GameContext`/`GameCleanup`/`GameSetupFn`, `fromSetup`
21
20
  * - surface vocabulary: `AdapterSurface`
22
21
  * - manifest-driven mount: `mountManifestRoots` + its option/result types
23
22
  * - game manifest (vgai.project.json) entry point: `loadGameManifest`
24
23
  */
25
24
 
26
25
  export type { AdapterSurface } from './adapter/adapter-surface';
27
- export { fromSetup } from './adapter/setup-three-root-adapter';
28
26
  export { AssetParseError } from './asset-parse-error';
29
27
  export type {
30
28
  AdapterRoot,
@@ -42,4 +40,3 @@ export type {
42
40
  MountManifestOptions,
43
41
  } from './runtime/mount-manifest';
44
42
  export { mountManifestRoots } from './runtime/mount-manifest';
45
- export type { GameCleanup, GameContext, GameSetupFn } from './runtime/types';
@@ -0,0 +1,230 @@
1
+ /**
2
+ * The host POINTER stream, in the game's own coordinate space — the DOM edge
3
+ * `InputManager`'s touch backends (`setTouchButton` / `setTouchStick`) and any
4
+ * pointer-position read need, and which the manager itself deliberately does
5
+ * not own.
6
+ *
7
+ * `InputManager` listens on `window` for keyboard, mouse and focus, in CLIENT
8
+ * pixels, because an action map is surface-agnostic. A pointer is not: a tap is
9
+ * only meaningful relative to the surface it landed on, and a game's own
10
+ * coordinate space is usually NOT that surface's CSS pixels — a fixed design
11
+ * resolution presented by uniformly scaling and letterboxing is the common
12
+ * case, and a hit-test against a UI rect authored in design pixels has to
13
+ * happen in one space with the pointer. That mapping needs a surface and a
14
+ * design size the manager has no way to know, so it lives here, beside it.
15
+ *
16
+ * What this owns, and nothing more:
17
+ *
18
+ * - **Position** — the last pointer position over the surface, mapped into the
19
+ * design space. `setPosition` is the headless door (a harness or a game
20
+ * command driving the game with no DOM), the same shape as
21
+ * `InputManager.addMouseDelta`: inject through the accumulator the reader
22
+ * already reads, never a synthetic `pointermove`.
23
+ * - **Touches** — a per-frame queue of {@link HostPointerTouch} records with
24
+ * DENSE finger indices, drained by the game's own frame. `pointerId` is the
25
+ * browser's opaque, monotonically growing handle; a touch API that reports
26
+ * "finger 0 and finger 1" wants the lowest free slot, reused the moment a
27
+ * finger lifts, which is what {@link HostPointerTouch.index} is.
28
+ * - **Cursor** — the CSS cursor applied to the surface, because the surface is
29
+ * resolved here and nowhere else.
30
+ *
31
+ * **Gating.** Every listener returns early unless
32
+ * `InputManager.isInputActive()` — the SAME predicate the manager's own
33
+ * `keydown`/`mousemove` listeners pass, so play-mode isolation and window
34
+ * blur suppress pointer position and touches exactly as they suppress a key.
35
+ * The predicate is read from the manager rather than recomposed here
36
+ * (`isEnabled() && isFocused()` written out a second time is how a looser gate
37
+ * drifts in: a blurred or typing tab kept updating a pointer position under
38
+ * exactly that duplication). Text-entry focus is deliberately NOT part of it,
39
+ * matching `onMouseMove` rather than `onKeyDown` — moving a finger is not
40
+ * typing.
41
+ *
42
+ * **Ownership.** Owns its four pointer listeners on the resolved owner, the
43
+ * touch queue and the finger-index table. Shares the `InputManager`, which is
44
+ * the game's and is never mutated here — this reports; what a control DOES
45
+ * with a finger (which rect owns it, whether that becomes a `setTouchButton`)
46
+ * belongs to the UI that draws the control. Teardown is {@link
47
+ * HostPointer.dispose}, and only that: `InputManager.dispose` does not reach
48
+ * these listeners.
49
+ *
50
+ * Headless (no `window`): construction succeeds and binds nothing. Position is
51
+ * whatever {@link HostPointer.setPosition} last wrote, and the touch queue
52
+ * stays empty.
53
+ */
54
+
55
+ import type { InputManager } from './input-manager';
56
+ import type { Vector2 } from './input-types';
57
+
58
+ /**
59
+ * Cap on the undrained touch queue. A game that drains every frame cannot
60
+ * reach it — this is the bound for one that never drains at all (a project
61
+ * that reads no touches, on a device that has them), so the queue is a RING:
62
+ * the newest records win and the oldest are dropped.
63
+ */
64
+ const TOUCH_QUEUE_MAX = 256;
65
+
66
+ /** One finger edge the host pointer stream produced. */
67
+ export interface HostPointerTouch {
68
+ /**
69
+ * `'start'` when the finger went down on the surface, `'move'` while it
70
+ * drags, `'end'` when it lifted or the browser cancelled it. A cancel is an
71
+ * end: the finger is gone either way, and a control that treats them
72
+ * differently is holding a button nothing will ever release.
73
+ */
74
+ readonly phase: 'start' | 'move' | 'end';
75
+ /**
76
+ * DENSE finger index — the lowest slot free when this finger went down, and
77
+ * free again the moment it lifts. NOT the browser's `pointerId`, which never
78
+ * reuses a value and is therefore useless as "which finger is this".
79
+ */
80
+ readonly index: number;
81
+ /** Position in the design space (see {@link HostPointerOptions.designSize}). */
82
+ readonly position: Vector2;
83
+ }
84
+
85
+ /** What {@link createHostPointer} needs. */
86
+ export interface HostPointerOptions {
87
+ /** The game's own manager — read for its gate, never written. */
88
+ readonly input: InputManager;
89
+ /**
90
+ * The render surface pointer positions are relative to.
91
+ *
92
+ * A GETTER rather than an element because a renderer usually mints its
93
+ * canvas after the game's services exist. Absent (or returning `null`) falls
94
+ * back to the event's own target element, and listening falls back to
95
+ * `window` — which is what makes a finger that starts on the canvas and
96
+ * drags over a DOM overlay keep reporting.
97
+ */
98
+ readonly surface?: (() => HTMLElement | null) | undefined;
99
+ /**
100
+ * The game's own logical resolution, if it has one. Surface CSS pixels are
101
+ * mapped into it, so a pointer and a UI rect authored at this size share one
102
+ * space regardless of how the host scaled and letterboxed the surface.
103
+ *
104
+ * Absent: positions are reported in the surface's own CSS pixels, and the
105
+ * position before any event is `{x: 0, y: 0}`. Present: the position before
106
+ * any event is the CENTRE of the design space — a pointer that has never
107
+ * moved is better described as the middle of the view than as a corner it
108
+ * was never at.
109
+ */
110
+ readonly designSize?: Vector2 | undefined;
111
+ }
112
+
113
+ /** The host pointer stream bound to one surface. One per mounted game. */
114
+ export interface HostPointer {
115
+ /** The last pointer position, in the design space. */
116
+ getPosition(): Vector2;
117
+ /** Headless / harness door onto {@link getPosition}'s value. */
118
+ setPosition(position: Vector2): void;
119
+ /**
120
+ * Drain the touch records queued since the last call. Returns them in
121
+ * arrival order and empties the queue, so a frame that drains sees each
122
+ * finger edge exactly once.
123
+ */
124
+ takeTouches(): readonly HostPointerTouch[];
125
+ /**
126
+ * Set the CSS `cursor` applied to the surface. Applied on the next pointer
127
+ * move over it, which is also when the surface is known.
128
+ */
129
+ setCursor(cursor: string): void;
130
+ /** Remove the listeners this owns. */
131
+ dispose(): void;
132
+ }
133
+
134
+ export function createHostPointer(options: HostPointerOptions): HostPointer {
135
+ const { input, surface: surfaceOf, designSize } = options;
136
+ let position: Vector2 = designSize
137
+ ? { x: designSize.x / 2, y: designSize.y / 2 }
138
+ : { x: 0, y: 0 };
139
+ let cursor = 'default';
140
+
141
+ const touches: HostPointerTouch[] = [];
142
+ /** Browser `pointerId` -> dense finger index, for fingers currently down. */
143
+ const fingerOfPointer = new Map<number, number>();
144
+ const freeFinger = (): number => {
145
+ const taken = new Set(fingerOfPointer.values());
146
+ let index = 0;
147
+ while (taken.has(index)) index += 1;
148
+ return index;
149
+ };
150
+ const queue = (touch: HostPointerTouch): void => {
151
+ touches.push(touch);
152
+ if (touches.length > TOUCH_QUEUE_MAX) touches.shift();
153
+ };
154
+
155
+ const queueTouch = (event: PointerEvent, point: Vector2): void => {
156
+ if (event.type === 'pointerdown') {
157
+ const index = freeFinger();
158
+ fingerOfPointer.set(event.pointerId, index);
159
+ queue({ phase: 'start', index, position: point });
160
+ return;
161
+ }
162
+ // A move or a release from a pointer that never went down on this surface
163
+ // is not one of our fingers.
164
+ const index = fingerOfPointer.get(event.pointerId);
165
+ if (index === undefined) return;
166
+ if (event.type === 'pointerup' || event.type === 'pointercancel') {
167
+ fingerOfPointer.delete(event.pointerId);
168
+ queue({ phase: 'end', index, position: point });
169
+ return;
170
+ }
171
+ queue({ phase: 'move', index, position: point });
172
+ };
173
+
174
+ /** A client-space event as a point in the design space, via the surface rect
175
+ * the host actually presented it at. */
176
+ const toDesignSpace = (event: PointerEvent, rect: DOMRect): Vector2 => {
177
+ const x = event.clientX - rect.left;
178
+ const y = event.clientY - rect.top;
179
+ if (!designSize) return { x, y };
180
+ return { x: (x * designSize.x) / rect.width, y: (y * designSize.y) / rect.height };
181
+ };
182
+
183
+ const onPointer = (event: PointerEvent): void => {
184
+ // The manager's own gate, read from the manager. See this module's header
185
+ // for why it is not recomposed here.
186
+ if (!input.isInputActive()) return;
187
+ const surface = surfaceOf?.() ?? (event.target instanceof HTMLElement ? event.target : null);
188
+ if (surface === null) return;
189
+ const rect = surface.getBoundingClientRect();
190
+ if (rect.width <= 0 || rect.height <= 0) return;
191
+ const point = toDesignSpace(event, rect);
192
+
193
+ if (event.type === 'pointermove') {
194
+ // Every pointer type moves the position — a stylus and a dragging finger
195
+ // are as much "where the pointer is" as a mouse. Only the TOUCH queue is
196
+ // touch-only.
197
+ position = point;
198
+ surface.style.cursor = cursor;
199
+ }
200
+ // A mouse or a pen is not a finger. A control that answered them here would
201
+ // steal the clicks of a player who cannot see it.
202
+ if (event.pointerType === 'touch') queueTouch(event, point);
203
+ };
204
+
205
+ const KINDS = ['pointerdown', 'pointermove', 'pointerup', 'pointercancel'] as const;
206
+ const owner: EventTarget | null =
207
+ typeof window === 'undefined' ? null : (surfaceOf?.() ?? window);
208
+ if (owner !== null) {
209
+ for (const kind of KINDS) owner.addEventListener(kind, onPointer as EventListener);
210
+ }
211
+
212
+ return {
213
+ getPosition(): Vector2 {
214
+ return position;
215
+ },
216
+ setPosition(next): void {
217
+ position = { x: next.x, y: next.y };
218
+ },
219
+ takeTouches(): readonly HostPointerTouch[] {
220
+ return touches.splice(0, touches.length);
221
+ },
222
+ setCursor(next): void {
223
+ cursor = next;
224
+ },
225
+ dispose(): void {
226
+ if (owner === null) return;
227
+ for (const kind of KINDS) owner.removeEventListener(kind, onPointer as EventListener);
228
+ },
229
+ };
230
+ }
@@ -184,10 +184,16 @@ const INPUT_TRACE_CAP = 2000;
184
184
  * controls. `setTouchButton(sourceId, pressed)` feeds a digital action
185
185
  * (edge-tracked like `mouse_button`); `setTouchStick(sourceId, value)`
186
186
  * feeds a vector2 action (deadzone-rescaled like a gamepad stick). These
187
- * are the injectable entry points a real on-screen touch UI's own
188
- * touchstart/touchmove/touchend handlers would callthat DOM wiring is
189
- * a thin adapter at the edge (browser-verified separately, e.g. F4/e2e);
190
- * the mapping logic here is unit-tested headlessly with no DOM.
187
+ * are the injectable entry points an on-screen touch UI calls, and they
188
+ * are the UPPER half of the touch story. The LOWER half the DOM
189
+ * pointer stream itself, as dense finger indices mapped into the game's
190
+ * own design space and gated on `isInputActive()` is
191
+ * `input/host-pointer.ts` (`createHostPointer`), beside this file; a
192
+ * control drains its `takeTouches()` and calls the setters above.
193
+ * What is deliberately still NOT here is the control layer in between:
194
+ * which rect owns which finger, and how a knob's offset becomes a stick
195
+ * vector, is the shape of the UI drawing the control, so it belongs to
196
+ * that UI and there is no first-party one to generalize from yet.
191
197
  * - Focus gating — `blur`/`focus` on `window` (guarded, real DOM only) now
192
198
  * drop input the same way `setEnabled(false)` does (flushing held
193
199
  * key/mouse/touch-button state) without touching the `enabled` flag the
@@ -428,7 +434,7 @@ export class InputManager {
428
434
  // caller never tells `poll()` which tick it's servicing (every existing
429
435
  // bare/headless caller — tests, a mount with no `Game` shell behind it —
430
436
  // keeps this exact pre-existing behavior, zero regression). The REAL
431
- // per-world wiring (`setup-three-root-adapter.ts`) instead passes the
437
+ // per-world wiring (`world3d-react/r3f-root-factory.tsx`) instead passes the
432
438
  // shared `Game`-level tick counter into every `poll(tick)` call — this is
433
439
  // deliberate: an InputManager-local counter drifts from the actual game
434
440
  // tick for a paused/frozen world (its `poll()` isn't called every game
@@ -461,7 +467,7 @@ export class InputManager {
461
467
  * action}`) emitted whenever a scheduled entry is discarded because its
462
468
  * target tick's input phase never ran. Wired by whoever constructs this
463
469
  * `InputManager` with access to a `DebugRegistry`
464
- * (`setup-three-root-adapter.ts`, the same seed spot as
470
+ * (`world3d-react/r3f-root-factory.tsx`, the same seed spot as
465
471
  * `setVirtualInputTarget`/`setInputActionsSource`) — `null` (the
466
472
  * default) for a bare/headless `InputManager`, in which case a drop
467
473
  * stays silent (matching pre-D15/T-D15.5 behavior). */
@@ -787,8 +793,8 @@ export class InputManager {
787
793
  }
788
794
  }
789
795
 
790
- /** The names of all registered actions (r3f `world-context` enumerates these
791
- * for its input-binding projection). */
796
+ /** The names of all registered actions (the `game.input.actions` debug seam
797
+ * enumerates these — `runtime/game-input-seams.ts`). */
792
798
  actionNames(): string[] {
793
799
  return [...this.actions.keys()];
794
800
  }
@@ -797,7 +803,7 @@ export class InputManager {
797
803
  * Poll gamepads and virtual look stick (call at start of frame).
798
804
  *
799
805
  * `tick` (D15/T-D15.3/.5) — the GAME tick this call services. Pass the
800
- * live, shared `Game` tick counter here (`setup-three-root-adapter.ts` does,
806
+ * live, shared `Game` tick counter here (`world3d-react/r3f-root-factory.tsx` does,
801
807
  * via `DebugRegistry.getGameTick()`) so `scheduleActionAtTick`'s numbering
802
808
  * never drifts from the actual game tick — the bug an earlier revision of
803
809
  * this feature had: an InputManager-LOCAL counter, incremented once per
@@ -1691,6 +1697,22 @@ export class InputManager {
1691
1697
  return this.focused;
1692
1698
  }
1693
1699
 
1700
+ /**
1701
+ * The gate every REAL-DEVICE listener here passes: {@link isEnabled} AND
1702
+ * {@link isFocused}. Public because the DOM edge this class deliberately
1703
+ * does not own — `host-pointer.ts`, the pointer stream behind the touch
1704
+ * backends — must pass the SAME gate, and a caller writing
1705
+ * `isEnabled() && isFocused()` out for itself is how a looser one drifts in
1706
+ * (a pointer adapter that checked only `isEnabled` kept updating position
1707
+ * for a blurred tab). Read it; do not recompose it.
1708
+ *
1709
+ * Machine input (`setVirtualAction` and the tick-scheduled actuations) is
1710
+ * deliberately NOT this gate — see `machineInputActive`.
1711
+ */
1712
+ isInputActive(): boolean {
1713
+ return this.inputActive;
1714
+ }
1715
+
1694
1716
  /** Whether the pointer is currently locked to {@link requestPointerLock}'s
1695
1717
  * element (F2, spec §12 "pointer lock") — tracked via the real
1696
1718
  * `pointerlockchange` event. */
@@ -1797,6 +1819,21 @@ export class InputManager {
1797
1819
  return this.gamepadButtonsJustUp.has(`${index}:${button}`);
1798
1820
  }
1799
1821
 
1822
+ /**
1823
+ * The RAW `Gamepad.axes[axis]` of the first connected pad, gated on `inputActive`.
1824
+ *
1825
+ * Deliberately un-deadzoned, and it must stay that way. The engine's own stick deadzone lives on
1826
+ * the ACTION path (`gamepad_axis` / `gamepad_axis_pair`, default
1827
+ * `GAMEPAD_AXIS_DEFAULT_DEADZONE`), where a game declares it and can override it per binding.
1828
+ * This door exists for a caller that must apply a DIFFERENT rule — every foreign-engine compat
1829
+ * lane does: Unity's `Gamepad.leftStick` carries a `StickDeadzone` processor with its own
1830
+ * 0.125/0.925 (`unity-compat/input-system-device.ts` reproduces it), and Godot's `get_axis`
1831
+ * has its own. Baking one engine's constants in here would silently give every other lane the
1832
+ * wrong feel under its own API name.
1833
+ *
1834
+ * So: a caller that wants "a stick" wants a deadzone and must say WHOSE. A caller that wants
1835
+ * the hardware number calls this.
1836
+ */
1800
1837
  getDeviceGamepadAxis(axis: number): number {
1801
1838
  if (!this.inputActive) return 0;
1802
1839
  const index = this.firstConnectedGamepadIndex();
@@ -2152,12 +2189,11 @@ export class InputManager {
2152
2189
  }
2153
2190
 
2154
2191
  // ==========================================================================
2155
- // Task 1.4 — action-level virtual input for a synthetic player. Promoted from
2156
- // hollowstone's proven `VirtualInput` (`bot/virtual-input.ts`): a bot drives
2192
+ // Action-level virtual input for a synthetic player: a bot drives
2157
2193
  // NAMED ACTIONS (not raw devices), and its contributions join action
2158
2194
  // resolution at exactly the same points binding contributions do (see
2159
2195
  // isPressed/isJustPressed and collectScalarContributions/
2160
- // collectVector2Contributions above). #144 split the gates: virtual input
2196
+ // collectVector2Contributions above). The gates are split: virtual input
2161
2197
  // passes `machineInputActive` (the editor's `enabled` flag only), while
2162
2198
  // human input keeps the full `inputActive` (enabled AND focused) gate — a
2163
2199
  // synthetic player must keep playing the shared editor tab while the
@@ -2365,7 +2401,7 @@ export class InputManager {
2365
2401
  * `'input.schedule.dropped'` (`{tick, action}`) whenever it discards a
2366
2402
  * scheduled entry for a tick whose input phase never ran. Called once by
2367
2403
  * whoever constructs this `InputManager` with a `DebugRegistry` behind it
2368
- * (`setup-three-root-adapter.ts`), the same seed spot as
2404
+ * (`world3d-react/r3f-root-factory.tsx`), the same seed spot as
2369
2405
  * `setVirtualInputTarget`/`setInputActionsSource` — never called directly
2370
2406
  * by gameplay code. */
2371
2407
  setDebugEmit(fn: ((event: string, detail?: unknown) => void) | null): void {
@@ -128,7 +128,7 @@ export interface InputMapFile {
128
128
  // types. See input-manager.ts's class doc comment for the full design note;
129
129
  // these are the plain data shapes shared between `InputManager`'s rebinding
130
130
  // API, the framework-free `RebindController` (rebind-controller.ts), and any
131
- // UI (e.g. the template's `RebindPanel.tsx`) that surfaces them.
131
+ // UI that surfaces them.
132
132
  // =============================================================================
133
133
 
134
134
  /**
@@ -1,11 +1,9 @@
1
- // F3 (spec §12 "Add Rebinding and Prompts") — a framework-free rebinding
2
- // STATE MACHINE over an `InputManager`. Deliberately has no dependency on
3
- // React (or any UI library): "listen for the next input, surface a conflict,
4
- // let the caller decide" is the same flow whether the caller is the
5
- // template's `RebindPanel.tsx` (ordinary React, see that file) or any other
6
- // UI/CLI. Keeping the logic here means it's unit-testable with no DOM/JSX at
7
- // all, and the React component becomes a thin, mechanically-verifiable
8
- // wrapper (see the template component's own doc comment).
1
+ // A framework-free rebinding STATE MACHINE over an `InputManager`.
2
+ // Deliberately has no dependency on React (or any UI library): "listen for the
3
+ // next input, surface a conflict, let the caller decide" is the same flow
4
+ // whether the caller is a React panel or a CLI. Keeping the logic here makes
5
+ // it unit-testable with no DOM/JSX at all, and leaves any UI a thin,
6
+ // mechanically-verifiable wrapper.
9
7
  //
10
8
  // Flow: `listen(actionName)` -> caller captures the next raw input event
11
9
  // itself (a keydown, a gamepad poll, a touch tap — capture is inherently