@vgai/engine 0.5.4 → 0.5.6

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 (448) hide show
  1. package/dist/adapter/adapter-surface.d.ts +30 -0
  2. package/dist/adapter/adapter-surface.d.ts.map +1 -0
  3. package/dist/adapter/adapter-surface.js +18 -0
  4. package/dist/adapter/authoring.d.ts +597 -0
  5. package/dist/adapter/authoring.d.ts.map +1 -0
  6. package/dist/adapter/authoring.js +22 -0
  7. package/dist/adapter/colyseus-networking-adapter.d.ts +77 -0
  8. package/dist/adapter/colyseus-networking-adapter.d.ts.map +1 -0
  9. package/dist/adapter/colyseus-networking-adapter.js +76 -0
  10. package/dist/adapter/first-party-systems.d.ts +23 -0
  11. package/dist/adapter/first-party-systems.d.ts.map +1 -0
  12. package/dist/adapter/first-party-systems.js +196 -0
  13. package/dist/adapter/host-context.d.ts +194 -0
  14. package/dist/adapter/host-context.d.ts.map +1 -0
  15. package/dist/adapter/host-context.js +80 -0
  16. package/dist/adapter/index.d.ts +33 -0
  17. package/dist/adapter/index.d.ts.map +1 -0
  18. package/dist/adapter/index.js +25 -0
  19. package/dist/adapter/ingest/game-contract.d.ts +53 -0
  20. package/dist/adapter/ingest/game-contract.d.ts.map +1 -0
  21. package/dist/adapter/ingest/game-contract.js +30 -0
  22. package/dist/adapter/ingest/scene-capture.d.ts +121 -0
  23. package/dist/adapter/ingest/scene-capture.d.ts.map +1 -0
  24. package/dist/adapter/ingest/scene-capture.js +270 -0
  25. package/dist/adapter/ingest/structural-ids.d.ts +64 -0
  26. package/dist/adapter/ingest/structural-ids.d.ts.map +1 -0
  27. package/dist/adapter/ingest/structural-ids.js +110 -0
  28. package/dist/adapter/ingest/upstream-pin.d.ts +44 -0
  29. package/dist/adapter/ingest/upstream-pin.d.ts.map +1 -0
  30. package/dist/adapter/ingest/upstream-pin.js +47 -0
  31. package/dist/adapter/loop-gate-report.d.ts +34 -0
  32. package/dist/adapter/loop-gate-report.d.ts.map +1 -0
  33. package/dist/adapter/loop-gate-report.js +37 -0
  34. package/dist/adapter/rapier-physics-adapter.d.ts +69 -0
  35. package/dist/adapter/rapier-physics-adapter.d.ts.map +1 -0
  36. package/dist/adapter/rapier-physics-adapter.js +135 -0
  37. package/dist/adapter/root-adapter.d.ts +195 -0
  38. package/dist/adapter/root-adapter.d.ts.map +1 -0
  39. package/dist/adapter/root-adapter.js +25 -0
  40. package/dist/adapter/setup-three-root-adapter.d.ts +87 -0
  41. package/dist/adapter/setup-three-root-adapter.d.ts.map +1 -0
  42. package/dist/adapter/setup-three-root-adapter.js +791 -0
  43. package/dist/adapter/system-adapter.d.ts +453 -0
  44. package/dist/adapter/system-adapter.d.ts.map +1 -0
  45. package/dist/adapter/system-adapter.js +13 -0
  46. package/dist/adapter/transform.d.ts +18 -0
  47. package/dist/adapter/transform.d.ts.map +1 -0
  48. package/dist/adapter/transform.js +1 -0
  49. package/dist/ai/navigation.d.ts +78 -0
  50. package/dist/ai/navigation.d.ts.map +1 -0
  51. package/dist/ai/navigation.js +152 -0
  52. package/dist/animation/anim-graph-types.d.ts +25 -0
  53. package/dist/animation/anim-graph-types.d.ts.map +1 -0
  54. package/dist/animation/anim-graph-types.js +1 -0
  55. package/dist/animation/animation-clock.d.ts +213 -0
  56. package/dist/animation/animation-clock.d.ts.map +1 -0
  57. package/dist/animation/animation-clock.js +301 -0
  58. package/dist/animation/blend-node.d.ts +22 -0
  59. package/dist/animation/blend-node.d.ts.map +1 -0
  60. package/dist/animation/blend-node.js +97 -0
  61. package/dist/animation/camera-ownership.d.ts +249 -0
  62. package/dist/animation/camera-ownership.d.ts.map +1 -0
  63. package/dist/animation/camera-ownership.js +169 -0
  64. package/dist/animation/cinematic-cues.d.ts +200 -0
  65. package/dist/animation/cinematic-cues.d.ts.map +1 -0
  66. package/dist/animation/cinematic-cues.js +213 -0
  67. package/dist/animation/clip-map.d.ts +12 -0
  68. package/dist/animation/clip-map.d.ts.map +1 -0
  69. package/dist/animation/clip-map.js +31 -0
  70. package/dist/animation/cubic-spline-interpolant.d.ts +54 -0
  71. package/dist/animation/cubic-spline-interpolant.d.ts.map +1 -0
  72. package/dist/animation/cubic-spline-interpolant.js +111 -0
  73. package/dist/animation/theatre-clock-binding.d.ts +89 -0
  74. package/dist/animation/theatre-clock-binding.d.ts.map +1 -0
  75. package/dist/animation/theatre-clock-binding.js +29 -0
  76. package/dist/animation/theatre-director.d.ts +277 -0
  77. package/dist/animation/theatre-director.d.ts.map +1 -0
  78. package/dist/animation/theatre-director.js +248 -0
  79. package/dist/animation/theatre-object-binding.d.ts +305 -0
  80. package/dist/animation/theatre-object-binding.d.ts.map +1 -0
  81. package/dist/animation/theatre-object-binding.js +351 -0
  82. package/dist/animation/xstate-animation-binding.d.ts +119 -0
  83. package/dist/animation/xstate-animation-binding.d.ts.map +1 -0
  84. package/dist/animation/xstate-animation-binding.js +349 -0
  85. package/dist/animation/xstate-animation-meta.d.ts +266 -0
  86. package/dist/animation/xstate-animation-meta.d.ts.map +1 -0
  87. package/dist/animation/xstate-animation-meta.js +252 -0
  88. package/dist/asset-formats/camera.d.ts +15 -0
  89. package/dist/asset-formats/camera.d.ts.map +1 -0
  90. package/dist/asset-formats/camera.js +15 -0
  91. package/dist/asset-formats/collider.d.ts +21 -0
  92. package/dist/asset-formats/collider.d.ts.map +1 -0
  93. package/dist/asset-formats/collider.js +53 -0
  94. package/dist/asset-formats/index.d.ts +46 -0
  95. package/dist/asset-formats/index.d.ts.map +1 -0
  96. package/dist/asset-formats/index.js +36 -0
  97. package/dist/asset-formats/instances.d.ts +17 -0
  98. package/dist/asset-formats/instances.d.ts.map +1 -0
  99. package/dist/asset-formats/instances.js +31 -0
  100. package/dist/asset-formats/light.d.ts +21 -0
  101. package/dist/asset-formats/light.d.ts.map +1 -0
  102. package/dist/asset-formats/light.js +35 -0
  103. package/dist/asset-formats/material.d.ts +129 -0
  104. package/dist/asset-formats/material.d.ts.map +1 -0
  105. package/dist/asset-formats/material.js +88 -0
  106. package/dist/asset-formats/mesh.d.ts +22 -0
  107. package/dist/asset-formats/mesh.d.ts.map +1 -0
  108. package/dist/asset-formats/mesh.js +64 -0
  109. package/dist/asset-formats/parse.d.ts +20 -0
  110. package/dist/asset-formats/parse.d.ts.map +1 -0
  111. package/dist/asset-formats/parse.js +34 -0
  112. package/dist/asset-formats/particles.d.ts +1390 -0
  113. package/dist/asset-formats/particles.d.ts.map +1 -0
  114. package/dist/asset-formats/particles.js +319 -0
  115. package/dist/asset-formats/render-env.d.ts +387 -0
  116. package/dist/asset-formats/render-env.d.ts.map +1 -0
  117. package/dist/asset-formats/render-env.js +300 -0
  118. package/dist/asset-formats/tuples.d.ts +12 -0
  119. package/dist/asset-formats/tuples.d.ts.map +1 -0
  120. package/dist/asset-formats/tuples.js +14 -0
  121. package/dist/asset-loaders.d.ts +97 -0
  122. package/dist/asset-loaders.d.ts.map +1 -0
  123. package/dist/asset-loaders.js +209 -0
  124. package/dist/asset-parse-error.d.ts +24 -0
  125. package/dist/asset-parse-error.d.ts.map +1 -0
  126. package/dist/asset-parse-error.js +29 -0
  127. package/dist/asset-registry.d.ts +38 -0
  128. package/dist/asset-registry.d.ts.map +1 -0
  129. package/dist/asset-registry.js +66 -0
  130. package/dist/assets.d.ts +26 -0
  131. package/dist/assets.d.ts.map +1 -0
  132. package/dist/assets.js +55 -0
  133. package/dist/audio/wav-encode.d.ts +38 -0
  134. package/dist/audio/wav-encode.d.ts.map +1 -0
  135. package/dist/audio/wav-encode.js +97 -0
  136. package/dist/canvas-react/engine-bridge.d.ts +45 -0
  137. package/dist/canvas-react/engine-bridge.d.ts.map +1 -0
  138. package/dist/canvas-react/engine-bridge.js +45 -0
  139. package/dist/canvas-react/index.d.ts +42 -0
  140. package/dist/canvas-react/index.d.ts.map +1 -0
  141. package/dist/canvas-react/index.js +41 -0
  142. package/dist/canvas-react/pixi-primitive.d.ts +85 -0
  143. package/dist/canvas-react/pixi-primitive.d.ts.map +1 -0
  144. package/dist/canvas-react/pixi-primitive.js +181 -0
  145. package/dist/canvas-react/pixi-react-adapter.d.ts +71 -0
  146. package/dist/canvas-react/pixi-react-adapter.d.ts.map +1 -0
  147. package/dist/canvas-react/pixi-react-adapter.js +229 -0
  148. package/dist/canvas-react/pixi-react-root-factory.d.ts +56 -0
  149. package/dist/canvas-react/pixi-react-root-factory.d.ts.map +1 -0
  150. package/dist/canvas-react/pixi-react-root-factory.js +73 -0
  151. package/dist/canvas-react/world-context.d.ts +88 -0
  152. package/dist/canvas-react/world-context.d.ts.map +1 -0
  153. package/dist/canvas-react/world-context.js +212 -0
  154. package/dist/config.d.ts +9 -0
  155. package/dist/config.d.ts.map +1 -0
  156. package/dist/config.js +8 -0
  157. package/dist/core/frame-pacing.d.ts +90 -0
  158. package/dist/core/frame-pacing.d.ts.map +1 -0
  159. package/dist/core/frame-pacing.js +89 -0
  160. package/dist/core/game-loop.d.ts +62 -0
  161. package/dist/core/game-loop.d.ts.map +1 -0
  162. package/dist/core/game-loop.js +189 -0
  163. package/dist/core/seeded-random.d.ts +69 -0
  164. package/dist/core/seeded-random.d.ts.map +1 -0
  165. package/dist/core/seeded-random.js +121 -0
  166. package/dist/core/sim-clock.d.ts +199 -0
  167. package/dist/core/sim-clock.d.ts.map +1 -0
  168. package/dist/core/sim-clock.js +291 -0
  169. package/dist/core/system-runner.d.ts +96 -0
  170. package/dist/core/system-runner.d.ts.map +1 -0
  171. package/dist/core/system-runner.js +253 -0
  172. package/dist/core/types.d.ts +111 -0
  173. package/dist/core/types.d.ts.map +1 -0
  174. package/dist/core/types.js +25 -0
  175. package/dist/data/data-asset.d.ts +101 -0
  176. package/dist/data/data-asset.d.ts.map +1 -0
  177. package/dist/data/data-asset.js +122 -0
  178. package/dist/data/data-check-core.d.ts +109 -0
  179. package/dist/data/data-check-core.d.ts.map +1 -0
  180. package/dist/data/data-check-core.js +177 -0
  181. package/dist/data/data-ref.d.ts +79 -0
  182. package/dist/data/data-ref.d.ts.map +1 -0
  183. package/dist/data/data-ref.js +130 -0
  184. package/dist/data/vite-plugin-data.d.ts +79 -0
  185. package/dist/data/vite-plugin-data.d.ts.map +1 -0
  186. package/dist/data/vite-plugin-data.js +217 -0
  187. package/dist/defaults.d.ts +233 -0
  188. package/dist/defaults.d.ts.map +1 -0
  189. package/dist/defaults.js +137 -0
  190. package/dist/dev/chrome-trace.d.ts +45 -0
  191. package/dist/dev/chrome-trace.d.ts.map +1 -0
  192. package/dist/dev/chrome-trace.js +114 -0
  193. package/dist/dev/console-bridge.d.ts +22 -0
  194. package/dist/dev/console-bridge.d.ts.map +1 -0
  195. package/dist/dev/console-bridge.js +71 -0
  196. package/dist/dev/debug-draw.d.ts +24 -0
  197. package/dist/dev/debug-draw.d.ts.map +1 -0
  198. package/dist/dev/debug-draw.js +73 -0
  199. package/dist/dev/instruments.d.ts +133 -0
  200. package/dist/dev/instruments.d.ts.map +1 -0
  201. package/dist/dev/instruments.js +231 -0
  202. package/dist/dev/logger.d.ts +30 -0
  203. package/dist/dev/logger.d.ts.map +1 -0
  204. package/dist/dev/logger.js +90 -0
  205. package/dist/dev/performance-profiler.d.ts +111 -0
  206. package/dist/dev/performance-profiler.d.ts.map +1 -0
  207. package/dist/dev/performance-profiler.js +215 -0
  208. package/dist/dev/render-debug-adapter.d.ts +57 -0
  209. package/dist/dev/render-debug-adapter.d.ts.map +1 -0
  210. package/dist/dev/render-debug-adapter.js +141 -0
  211. package/dist/dev/render-memory.d.ts +53 -0
  212. package/dist/dev/render-memory.d.ts.map +1 -0
  213. package/dist/dev/render-memory.js +190 -0
  214. package/dist/dev/webgl-frame-capture.d.ts +134 -0
  215. package/dist/dev/webgl-frame-capture.d.ts.map +1 -0
  216. package/dist/dev/webgl-frame-capture.js +270 -0
  217. package/dist/dev/webgl-gpu-timer.d.ts +8 -0
  218. package/dist/dev/webgl-gpu-timer.d.ts.map +1 -0
  219. package/dist/dev/webgl-gpu-timer.js +52 -0
  220. package/dist/ecs/scene-index.d.ts +179 -0
  221. package/dist/ecs/scene-index.d.ts.map +1 -0
  222. package/dist/ecs/scene-index.js +331 -0
  223. package/dist/ecs/scene-query.d.ts +6 -0
  224. package/dist/ecs/scene-query.d.ts.map +1 -0
  225. package/dist/ecs/scene-query.js +40 -0
  226. package/dist/ecs/user-data.d.ts +193 -0
  227. package/dist/ecs/user-data.d.ts.map +1 -0
  228. package/dist/ecs/user-data.js +145 -0
  229. package/dist/index.d.ts +35 -0
  230. package/dist/index.d.ts.map +1 -0
  231. package/dist/index.js +29 -0
  232. package/dist/input/input-manager.d.ts +944 -0
  233. package/dist/input/input-manager.d.ts.map +1 -0
  234. package/dist/input/input-manager.js +2209 -0
  235. package/dist/input/input-types.d.ts +174 -0
  236. package/dist/input/input-types.d.ts.map +1 -0
  237. package/dist/input/input-types.js +1 -0
  238. package/dist/input/prompt-labels.d.ts +21 -0
  239. package/dist/input/prompt-labels.d.ts.map +1 -0
  240. package/dist/input/prompt-labels.js +121 -0
  241. package/dist/input/rebind-controller.d.ts +59 -0
  242. package/dist/input/rebind-controller.d.ts.map +1 -0
  243. package/dist/input/rebind-controller.js +85 -0
  244. package/dist/input/schema.d.ts +16 -0
  245. package/dist/input/schema.d.ts.map +1 -0
  246. package/dist/input/schema.js +228 -0
  247. package/dist/loader.d.ts +76 -0
  248. package/dist/loader.d.ts.map +1 -0
  249. package/dist/loader.js +114 -0
  250. package/dist/manifest/editor-port.d.ts +53 -0
  251. package/dist/manifest/editor-port.d.ts.map +1 -0
  252. package/dist/manifest/editor-port.js +67 -0
  253. package/dist/manifest/filename.d.ts +14 -0
  254. package/dist/manifest/filename.d.ts.map +1 -0
  255. package/dist/manifest/filename.js +43 -0
  256. package/dist/manifest/index.d.ts +6 -0
  257. package/dist/manifest/index.d.ts.map +1 -0
  258. package/dist/manifest/index.js +9 -0
  259. package/dist/manifest/load-file.d.ts +7 -0
  260. package/dist/manifest/load-file.d.ts.map +1 -0
  261. package/dist/manifest/load-file.js +23 -0
  262. package/dist/manifest/load.d.ts +161 -0
  263. package/dist/manifest/load.d.ts.map +1 -0
  264. package/dist/manifest/load.js +269 -0
  265. package/dist/manifest/locate.d.ts +24 -0
  266. package/dist/manifest/locate.d.ts.map +1 -0
  267. package/dist/manifest/locate.js +48 -0
  268. package/dist/manifest/schema.d.ts +293 -0
  269. package/dist/manifest/schema.d.ts.map +1 -0
  270. package/dist/manifest/schema.js +633 -0
  271. package/dist/physics/collider-dimensions.d.ts +63 -0
  272. package/dist/physics/collider-dimensions.d.ts.map +1 -0
  273. package/dist/physics/collider-dimensions.js +98 -0
  274. package/dist/physics/collision-system.d.ts +41 -0
  275. package/dist/physics/collision-system.d.ts.map +1 -0
  276. package/dist/physics/collision-system.js +64 -0
  277. package/dist/physics/physics-registry.d.ts +45 -0
  278. package/dist/physics/physics-registry.d.ts.map +1 -0
  279. package/dist/physics/physics-registry.js +65 -0
  280. package/dist/physics/transform-writer.d.ts +16 -0
  281. package/dist/physics/transform-writer.d.ts.map +1 -0
  282. package/dist/physics/transform-writer.js +38 -0
  283. package/dist/pixi/authoring.d.ts +93 -0
  284. package/dist/pixi/authoring.d.ts.map +1 -0
  285. package/dist/pixi/authoring.js +207 -0
  286. package/dist/pixi/index.d.ts +16 -0
  287. package/dist/pixi/index.d.ts.map +1 -0
  288. package/dist/pixi/index.js +15 -0
  289. package/dist/pixi/ingest-iframe.d.ts +82 -0
  290. package/dist/pixi/ingest-iframe.d.ts.map +1 -0
  291. package/dist/pixi/ingest-iframe.js +166 -0
  292. package/dist/pixi/ingest.d.ts +97 -0
  293. package/dist/pixi/ingest.d.ts.map +1 -0
  294. package/dist/pixi/ingest.js +40 -0
  295. package/dist/pixi/physics-registry.d.ts +24 -0
  296. package/dist/pixi/physics-registry.d.ts.map +1 -0
  297. package/dist/pixi/physics-registry.js +38 -0
  298. package/dist/pixi/scene-capture.d.ts +43 -0
  299. package/dist/pixi/scene-capture.d.ts.map +1 -0
  300. package/dist/pixi/scene-capture.js +92 -0
  301. package/dist/pixi/system-adapters.d.ts +16 -0
  302. package/dist/pixi/system-adapters.d.ts.map +1 -0
  303. package/dist/pixi/system-adapters.js +37 -0
  304. package/dist/react/unmanaged-root-detector.d.ts +18 -0
  305. package/dist/react/unmanaged-root-detector.d.ts.map +1 -0
  306. package/dist/react/unmanaged-root-detector.js +70 -0
  307. package/dist/react/use-data.d.ts +60 -0
  308. package/dist/react/use-data.d.ts.map +1 -0
  309. package/dist/react/use-data.js +101 -0
  310. package/dist/react/use-selection.d.ts +54 -0
  311. package/dist/react/use-selection.d.ts.map +1 -0
  312. package/dist/react/use-selection.js +71 -0
  313. package/dist/react/world-state.d.ts +154 -0
  314. package/dist/react/world-state.d.ts.map +1 -0
  315. package/dist/react/world-state.js +220 -0
  316. package/dist/render/auto-batcher.d.ts +34 -0
  317. package/dist/render/auto-batcher.d.ts.map +1 -0
  318. package/dist/render/auto-batcher.js +140 -0
  319. package/dist/render/instance-mesh.d.ts +5 -0
  320. package/dist/render/instance-mesh.d.ts.map +1 -0
  321. package/dist/render/instance-mesh.js +19 -0
  322. package/dist/render/light-camera-factory.d.ts +24 -0
  323. package/dist/render/light-camera-factory.d.ts.map +1 -0
  324. package/dist/render/light-camera-factory.js +71 -0
  325. package/dist/render/lod.d.ts +13 -0
  326. package/dist/render/lod.d.ts.map +1 -0
  327. package/dist/render/lod.js +16 -0
  328. package/dist/render/material-factory.d.ts +15 -0
  329. package/dist/render/material-factory.d.ts.map +1 -0
  330. package/dist/render/material-factory.js +186 -0
  331. package/dist/render/mesh-shadow.d.ts +11 -0
  332. package/dist/render/mesh-shadow.d.ts.map +1 -0
  333. package/dist/render/mesh-shadow.js +19 -0
  334. package/dist/render/particles-factory.d.ts +99 -0
  335. package/dist/render/particles-factory.d.ts.map +1 -0
  336. package/dist/render/particles-factory.js +361 -0
  337. package/dist/render/render-batch-system.d.ts +33 -0
  338. package/dist/render/render-batch-system.d.ts.map +1 -0
  339. package/dist/render/render-batch-system.js +223 -0
  340. package/dist/render/render-features.d.ts +47 -0
  341. package/dist/render/render-features.d.ts.map +1 -0
  342. package/dist/render/render-features.js +105 -0
  343. package/dist/render/render-settings.d.ts +35 -0
  344. package/dist/render/render-settings.d.ts.map +1 -0
  345. package/dist/render/render-settings.js +51 -0
  346. package/dist/render/spark-renderer-lifecycle.d.ts +18 -0
  347. package/dist/render/spark-renderer-lifecycle.d.ts.map +1 -0
  348. package/dist/render/spark-renderer-lifecycle.js +57 -0
  349. package/dist/render/viewport-shading.d.ts +17 -0
  350. package/dist/render/viewport-shading.d.ts.map +1 -0
  351. package/dist/render/viewport-shading.js +87 -0
  352. package/dist/runtime/create-runtime.d.ts +259 -0
  353. package/dist/runtime/create-runtime.d.ts.map +1 -0
  354. package/dist/runtime/create-runtime.js +666 -0
  355. package/dist/runtime/debug-bridge.d.ts +288 -0
  356. package/dist/runtime/debug-bridge.d.ts.map +1 -0
  357. package/dist/runtime/debug-bridge.js +277 -0
  358. package/dist/runtime/debug-registry.d.ts +287 -0
  359. package/dist/runtime/debug-registry.d.ts.map +1 -0
  360. package/dist/runtime/debug-registry.js +528 -0
  361. package/dist/runtime/dev-layers.d.ts +34 -0
  362. package/dist/runtime/dev-layers.d.ts.map +1 -0
  363. package/dist/runtime/dev-layers.js +40 -0
  364. package/dist/runtime/frame-selector-cache.d.ts +41 -0
  365. package/dist/runtime/frame-selector-cache.d.ts.map +1 -0
  366. package/dist/runtime/frame-selector-cache.js +65 -0
  367. package/dist/runtime/game.d.ts +576 -0
  368. package/dist/runtime/game.d.ts.map +1 -0
  369. package/dist/runtime/game.js +1003 -0
  370. package/dist/runtime/gameplay-rng-trap.d.ts +47 -0
  371. package/dist/runtime/gameplay-rng-trap.d.ts.map +1 -0
  372. package/dist/runtime/gameplay-rng-trap.js +95 -0
  373. package/dist/runtime/input-router.d.ts +78 -0
  374. package/dist/runtime/input-router.d.ts.map +1 -0
  375. package/dist/runtime/input-router.js +171 -0
  376. package/dist/runtime/mount-game.d.ts +126 -0
  377. package/dist/runtime/mount-game.d.ts.map +1 -0
  378. package/dist/runtime/mount-game.js +159 -0
  379. package/dist/runtime/mount-manifest.d.ts +174 -0
  380. package/dist/runtime/mount-manifest.d.ts.map +1 -0
  381. package/dist/runtime/mount-manifest.js +304 -0
  382. package/dist/runtime/presentation.d.ts +85 -0
  383. package/dist/runtime/presentation.d.ts.map +1 -0
  384. package/dist/runtime/presentation.js +92 -0
  385. package/dist/runtime/render-audio-control.d.ts +126 -0
  386. package/dist/runtime/render-audio-control.d.ts.map +1 -0
  387. package/dist/runtime/render-audio-control.js +116 -0
  388. package/dist/runtime/render-control.d.ts +347 -0
  389. package/dist/runtime/render-control.d.ts.map +1 -0
  390. package/dist/runtime/render-control.js +317 -0
  391. package/dist/runtime/render-seed.d.ts +56 -0
  392. package/dist/runtime/render-seed.d.ts.map +1 -0
  393. package/dist/runtime/render-seed.js +73 -0
  394. package/dist/runtime/state-bridge.d.ts +60 -0
  395. package/dist/runtime/state-bridge.d.ts.map +1 -0
  396. package/dist/runtime/state-bridge.js +62 -0
  397. package/dist/runtime/types.d.ts +285 -0
  398. package/dist/runtime/types.d.ts.map +1 -0
  399. package/dist/runtime/types.js +1 -0
  400. package/dist/runtime/unexported-game-trap.d.ts +36 -0
  401. package/dist/runtime/unexported-game-trap.d.ts.map +1 -0
  402. package/dist/runtime/unexported-game-trap.js +80 -0
  403. package/dist/setup/setup-audio.d.ts +20 -0
  404. package/dist/setup/setup-audio.d.ts.map +1 -0
  405. package/dist/setup/setup-audio.js +41 -0
  406. package/dist/setup/setup-particles.d.ts +17 -0
  407. package/dist/setup/setup-particles.d.ts.map +1 -0
  408. package/dist/setup/setup-particles.js +16 -0
  409. package/dist/setup/setup-physics.d.ts +25 -0
  410. package/dist/setup/setup-physics.d.ts.map +1 -0
  411. package/dist/setup/setup-physics.js +51 -0
  412. package/dist/setup/setup-renderer.d.ts +82 -0
  413. package/dist/setup/setup-renderer.d.ts.map +1 -0
  414. package/dist/setup/setup-renderer.js +381 -0
  415. package/dist/world3d-react/engine-bridge.d.ts +47 -0
  416. package/dist/world3d-react/engine-bridge.d.ts.map +1 -0
  417. package/dist/world3d-react/engine-bridge.js +48 -0
  418. package/dist/world3d-react/index.d.ts +47 -0
  419. package/dist/world3d-react/index.d.ts.map +1 -0
  420. package/dist/world3d-react/index.js +46 -0
  421. package/dist/world3d-react/r3f-adapter.d.ts +51 -0
  422. package/dist/world3d-react/r3f-adapter.d.ts.map +1 -0
  423. package/dist/world3d-react/r3f-adapter.js +368 -0
  424. package/dist/world3d-react/r3f-root-factory.d.ts +62 -0
  425. package/dist/world3d-react/r3f-root-factory.d.ts.map +1 -0
  426. package/dist/world3d-react/r3f-root-factory.js +79 -0
  427. package/dist/world3d-react/rapier-physics-bridge.d.ts +76 -0
  428. package/dist/world3d-react/rapier-physics-bridge.d.ts.map +1 -0
  429. package/dist/world3d-react/rapier-physics-bridge.js +120 -0
  430. package/dist/world3d-react/renderer-config.d.ts +58 -0
  431. package/dist/world3d-react/renderer-config.d.ts.map +1 -0
  432. package/dist/world3d-react/renderer-config.js +96 -0
  433. package/dist/world3d-react/world-context.d.ts +123 -0
  434. package/dist/world3d-react/world-context.d.ts.map +1 -0
  435. package/dist/world3d-react/world-context.js +204 -0
  436. package/dist-config/config.js +303 -0
  437. package/dist-config/config.js.map +7 -0
  438. package/package.json +14 -3
  439. package/src/adapter/rapier-physics-adapter.ts +77 -34
  440. package/src/config.ts +8 -0
  441. package/src/core/frame-pacing.ts +26 -0
  442. package/src/core/game-loop.ts +4 -3
  443. package/src/dev/instruments.ts +302 -0
  444. package/src/runtime/mount-game.ts +6 -0
  445. package/src/runtime/unexported-game-trap.ts +82 -0
  446. package/src/setup/setup-renderer.ts +2 -0
  447. package/src/world3d-react/index.ts +9 -0
  448. package/src/world3d-react/rapier-physics-bridge.tsx +137 -0
@@ -0,0 +1,302 @@
1
+ /**
2
+ * THE UNIVERSAL INSTRUMENTS — time scale, pause/frame-step, collider draw and
3
+ * frame time, furnished by the ENGINE for every game before it has written a
4
+ * line.
5
+ *
6
+ * These are physics of the medium, not genre ontology. Time runs; it can run
7
+ * slower or stop; a frame can be stepped; colliders can be drawn; frames take
8
+ * time. None of that is a decision any particular game makes, so none of it
9
+ * belongs in a game's own declarations — and none of it belongs on the game's
10
+ * own dev panel either, which shows ONLY what the game itself declared
11
+ * (`stat()`, `cheat()`). They publish as DOORS: an agent drives them through
12
+ * `game.state()`/`game.command()`, and a human drives the same controls from
13
+ * the editor chrome that already owns them — pause and frame-step on the
14
+ * transport, frame time on the stats overlay, colliders in the play-adopted
15
+ * Scene viewport.
16
+ *
17
+ * WHAT IS NOT HERE, and why: a FREE CAMERA. The editor already ships one
18
+ * (owner, 2026-08-10): play adoption swaps the live game scene into the editor
19
+ * viewport (`enterPlayScene`), so the Scene view during play IS a free orbit
20
+ * camera over the running game — no game-side camera override needed, and the
21
+ * game's own camera writes never fight it because the game keeps rendering
22
+ * through its own canvas untouched. Per the non-redundancy rule that governs
23
+ * this list, a control the editor's own chrome furnishes gets no instrument;
24
+ * agents reach that camera through the editor half of `vgai eval`, not the
25
+ * game registry.
26
+ *
27
+ * ── THE DOOR ────────────────────────────────────────────────────────────────
28
+ * This module is IMPLEMENTATION ONLY. It publishes nothing itself: the dev-menu
29
+ * capability's own registry adopts this list (`installDevMenuInstruments`) and
30
+ * publishes each instrument through the SAME door every declaration in that
31
+ * capability uses — one provider per reading (`instrument.timescale`), one
32
+ * command per action (`instrument.timescale.set`), plus the `dev-menu` index
33
+ * provider. That is deliberate and load-bearing: the registry IS the product,
34
+ * so every reader of an instrument reaches the SAME registration.
35
+ *
36
+ * ── DEGRADING ───────────────────────────────────────────────────────────────
37
+ * An instrument whose subject this game does not have (no physics adapter ⇒ no
38
+ * colliders) READS `null` — honest emptiness rather than a fabricated value.
39
+ * Its ACTION, invoked anyway, THROWS and names what is missing. Silence is the
40
+ * one thing forbidden: an agent that calls `instrument.colliders.toggle` and
41
+ * gets `undefined` back learns nothing.
42
+ *
43
+ * ── RESOURCE OWNERSHIP, STATED ONCE ─────────────────────────────────────────
44
+ * {@link createDevInstruments} owns everything it allocates: the frame-time
45
+ * ring buffer and its ONE `game.onRenderStep` subscription. SHARER: the
46
+ * dev-menu capability's `DevMenuBridge`, which creates one set per mounted
47
+ * game. TEARDOWN: the returned {@link DevInstrumentSet.dispose} — the ONE path
48
+ * that ends it. Nothing else here holds a resource; the time-scale, pause and
49
+ * collider instruments only drive state that `Game` already owns.
50
+ */
51
+
52
+ import { z } from 'zod';
53
+ import { clampTimeScale, TIME_SCALE_RANGE } from '../core/frame-pacing';
54
+ import type { Game } from '../runtime/game';
55
+
56
+ /** What shape an instrument's reading is, and what drives it. Data, not
57
+ * layout: a reader learns how to interpret and actuate an instrument without
58
+ * having to recognise it by name. */
59
+ export type DevInstrumentControl =
60
+ /** A value only. */
61
+ | { readonly kind: 'reading' }
62
+ /** On/off, driven by the named action. */
63
+ | { readonly kind: 'toggle'; readonly action: string }
64
+ /** A continuous value, driven by the named action (one numeric argument). */
65
+ | {
66
+ readonly kind: 'scale';
67
+ readonly action: string;
68
+ readonly min: number;
69
+ readonly max: number;
70
+ readonly step: number;
71
+ }
72
+ /** A {@link FrameTimeReading} — a window of samples, not a scalar. */
73
+ | { readonly kind: 'plot' };
74
+
75
+ /** One instrument verb. Every action declares an args tuple — `z.tuple([])`
76
+ * for a verb that takes none — so the debug registry REJECTS an unexpected
77
+ * argument at the door instead of passing it through to a handler that
78
+ * ignores it. */
79
+ export interface DevInstrumentAction {
80
+ /** Second half of the command name: `instrument.<id>.<this>`. */
81
+ readonly id: string;
82
+ readonly label: string;
83
+ readonly hint: string;
84
+ readonly args: z.ZodTuple;
85
+ run(values: readonly unknown[]): unknown;
86
+ }
87
+
88
+ export interface DevInstrument {
89
+ /** Second half of the provider name: `instrument.<this>`. */
90
+ readonly id: string;
91
+ readonly label: string;
92
+ readonly hint: string;
93
+ /** Trailing unit for a scalar reading (`x`, `ms`). */
94
+ readonly unit?: string;
95
+ readonly control: DevInstrumentControl;
96
+ readonly actions: readonly DevInstrumentAction[];
97
+ /** This instant's value, or `null` when this game has no such subject. */
98
+ read(): unknown;
99
+ }
100
+
101
+ export interface DevInstrumentSet {
102
+ readonly instruments: readonly DevInstrument[];
103
+ /** See the ownership note above — the ONE teardown path. */
104
+ dispose(): void;
105
+ }
106
+
107
+ /**
108
+ * How many display frames the frame-time reading keeps. ~1 second at 60 Hz —
109
+ * long enough that a hitch is still in the window when you look, short enough
110
+ * that the mean tracks what the game is doing NOW.
111
+ */
112
+ export const FRAME_TIME_WINDOW = 60;
113
+
114
+ /** What `instrument.frame-time` reads. `null`s (rather than zeros) before the
115
+ * first sampled frame: a stopped game has no frame time, and `0 ms / 0 fps`
116
+ * would read as a measurement. */
117
+ export interface FrameTimeReading {
118
+ /** Mean wall-clock milliseconds per display frame over the window. */
119
+ readonly ms: number | null;
120
+ /** Frames per second implied by {@link ms}. */
121
+ readonly fps: number | null;
122
+ /** The worst single frame in the window — the hitch the mean hides. */
123
+ readonly worstMs: number | null;
124
+ /** Oldest first, for the plot. */
125
+ readonly samples: readonly number[];
126
+ }
127
+
128
+ /** Pure: the whole frame-time reading from a window of samples. */
129
+ export function summarizeFrameTimes(samples: readonly number[]): FrameTimeReading {
130
+ if (samples.length === 0) return { ms: null, fps: null, worstMs: null, samples: [] };
131
+ let total = 0;
132
+ let worst = 0;
133
+ for (const sample of samples) {
134
+ total += sample;
135
+ if (sample > worst) worst = sample;
136
+ }
137
+ const ms = total / samples.length;
138
+ return {
139
+ ms: round(ms, 2),
140
+ fps: ms > 0 ? round(1000 / ms, 1) : null,
141
+ worstMs: round(worst, 2),
142
+ samples: samples.map((sample) => round(sample, 2)),
143
+ };
144
+ }
145
+
146
+ function round(value: number, places: number): number {
147
+ const factor = 10 ** places;
148
+ return Math.round(value * factor) / factor;
149
+ }
150
+
151
+ const NO_COLLIDERS =
152
+ 'No physics adapter on this game implements setDebugDrawEnabled, so nothing can draw its ' +
153
+ 'colliders. A first-party three root with Rapier physics registers one; a game with no ' +
154
+ 'physics has no colliders to draw.';
155
+
156
+ const NO_ARGS = z.tuple([]);
157
+
158
+ /**
159
+ * Build this game's universal instrument set. One call per mounted game; the
160
+ * caller owns the returned {@link DevInstrumentSet.dispose}.
161
+ */
162
+ export function createDevInstruments(game: Game): DevInstrumentSet {
163
+ // --- Frame time: one subscription, one ring buffer ------------------------
164
+ const samples: number[] = [];
165
+ let previousFrameAt = now();
166
+ const stopSampling = game.onRenderStep(() => {
167
+ const at = now();
168
+ samples.push(at - previousFrameAt);
169
+ previousFrameAt = at;
170
+ if (samples.length > FRAME_TIME_WINDOW) samples.shift();
171
+ });
172
+
173
+ // --- Collider draw: the adapter has a setter and no getter, so the ON/OFF
174
+ // state is ours to remember. It is only ever written through the one action
175
+ // below, which is also the only thing that calls the adapter.
176
+ let collidersDrawn = false;
177
+ const colliderDraw = () => {
178
+ const adapter = game.systemAdapters.physics;
179
+ return adapter?.setDebugDrawEnabled ? adapter : null;
180
+ };
181
+
182
+ const instruments: readonly DevInstrument[] = [
183
+ {
184
+ id: 'timescale',
185
+ label: 'Time scale',
186
+ hint: 'Sim speed multiplier. 1 is real time, 0 freezes the simulation while the game keeps drawing.',
187
+ unit: 'x',
188
+ control: {
189
+ kind: 'scale',
190
+ action: 'set',
191
+ min: TIME_SCALE_RANGE.min,
192
+ max: TIME_SCALE_RANGE.max,
193
+ step: 0.05,
194
+ },
195
+ actions: [
196
+ {
197
+ id: 'set',
198
+ label: 'Set',
199
+ hint: `Set the sim speed multiplier (${TIME_SCALE_RANGE.min}–${TIME_SCALE_RANGE.max}).`,
200
+ args: z.tuple([z.number()]),
201
+ run: (values) => {
202
+ // The LOOP clamps and warns; asking for the clamp here too would
203
+ // be a second opinion about the same range. It reads back the
204
+ // value that actually took effect, never the one requested.
205
+ game.loop.timeScale = clampTimeScale(values[0] as number);
206
+ return game.loop.timeScale;
207
+ },
208
+ },
209
+ ],
210
+ read: () => game.loop.timeScale,
211
+ },
212
+ {
213
+ id: 'paused',
214
+ label: 'Paused',
215
+ hint: 'Freeze the simulation. The game keeps drawing, so you can look at a frozen frame.',
216
+ control: { kind: 'toggle', action: 'toggle' },
217
+ actions: [
218
+ {
219
+ id: 'toggle',
220
+ label: 'Toggle',
221
+ hint: 'Pause or resume the simulation.',
222
+ args: NO_ARGS,
223
+ run: () => {
224
+ if (game.play.paused) game.play.resume();
225
+ else game.play.pause();
226
+ return game.play.paused;
227
+ },
228
+ },
229
+ {
230
+ id: 'step',
231
+ label: 'Step',
232
+ hint: 'Advance exactly one fixed substep. Pauses first if the game is running.',
233
+ args: NO_ARGS,
234
+ run: () => {
235
+ // Frame advance implies pause — `Game.play.step()` is a
236
+ // deliberate whole-call no-op while running, and a button that
237
+ // silently does nothing is the failure this instrument exists to
238
+ // avoid.
239
+ if (!game.play.paused) game.play.pause();
240
+ game.play.step();
241
+ return game.play.paused;
242
+ },
243
+ },
244
+ ],
245
+ read: () => game.play.paused,
246
+ },
247
+ {
248
+ id: 'colliders',
249
+ label: 'Colliders drawn',
250
+ hint: "Draw the physics colliders over the world, through the game's own physics adapter.",
251
+ control: { kind: 'toggle', action: 'toggle' },
252
+ actions: [
253
+ {
254
+ id: 'toggle',
255
+ label: 'Toggle',
256
+ hint: 'Turn collider wireframes on or off.',
257
+ args: NO_ARGS,
258
+ run: () => {
259
+ const adapter = colliderDraw();
260
+ if (!adapter) throw new Error(NO_COLLIDERS);
261
+ collidersDrawn = !collidersDrawn;
262
+ adapter.setDebugDrawEnabled?.(collidersDrawn);
263
+ return collidersDrawn;
264
+ },
265
+ },
266
+ ],
267
+ read: () => (colliderDraw() === null ? null : collidersDrawn),
268
+ },
269
+ {
270
+ id: 'frame-time',
271
+ label: 'Frame time',
272
+ hint: 'Wall-clock milliseconds per display frame, newest last. The window is where a hitch shows; the mean hides it.',
273
+ unit: 'ms',
274
+ control: { kind: 'plot' },
275
+ actions: [
276
+ {
277
+ id: 'clear',
278
+ label: 'Clear',
279
+ hint: 'Forget the sampled window and start measuring again.',
280
+ args: NO_ARGS,
281
+ run: () => {
282
+ samples.length = 0;
283
+ return null;
284
+ },
285
+ },
286
+ ],
287
+ read: () => summarizeFrameTimes(samples),
288
+ },
289
+ ];
290
+
291
+ return {
292
+ instruments,
293
+ dispose() {
294
+ stopSampling();
295
+ samples.length = 0;
296
+ },
297
+ };
298
+ }
299
+
300
+ function now(): number {
301
+ return typeof performance === 'undefined' ? Date.now() : performance.now();
302
+ }
@@ -22,6 +22,7 @@ import type { ResolvedAdapterRoot } from '../manifest/load';
22
22
  import type { GameSession } from './create-runtime';
23
23
  import { type MountEntry, mountManifestRoots, resolveManifest } from './mount-manifest';
24
24
  import type { GameSetupFn } from './types';
25
+ import { assertExportedOrInEditor } from './unexported-game-trap';
25
26
 
26
27
  // ---------------------------------------------------------------------------
27
28
  // The host contract (design/26 §5 D1's `ManifestHost`)
@@ -232,6 +233,11 @@ export async function mountGameFromManifest(
232
233
  host: ManifestHost,
233
234
  opts: MountGameOptions = {},
234
235
  ): Promise<GameSession> {
236
+ // Owner invariant: an unexported game never mounts outside the editor. The
237
+ // editor mounts through its own resolver, so every caller of THIS function
238
+ // is a standalone page — and on a dev server, that page refuses to boot
239
+ // (see unexported-game-trap.ts for why this is a trap and not a rule).
240
+ assertExportedOrInEditor();
235
241
  const manifest = resolveManifest(manifestInput);
236
242
  const entries: Record<string, MountEntry> = { ...opts.entries };
237
243
 
@@ -0,0 +1,82 @@
1
+ /**
2
+ * THE UNEXPORTED-GAME TRAP: a dev-served standalone game page REFUSES to boot.
3
+ *
4
+ * Owner decision (2026-08-09): until a game is EXPORTED, it is never played
5
+ * outside the editor. The editor is the one authoring, viewing and
6
+ * verification surface; the standalone page exists to serve the exported
7
+ * artifact, not to be a second door during development.
8
+ *
9
+ * Why this is a trap in CODE and not a rule in prose: the rule already
10
+ * existed, and it drifted. When an editor session broke mid-task, an agent
11
+ * "temporarily" switched to `npm run game`, the fallback fed its whole
12
+ * feedback loop (pixels for screenshots), nothing broken ever pushed it back,
13
+ * and hours of verification ran outside the editor without anyone deciding
14
+ * that. A workaround whose cost lands outside the loop that chose it is
15
+ * sticky; the only fix that holds is for the workaround PATH ITSELF to fail
16
+ * immediately, loudly, and with the way back in its hands. That is this file.
17
+ *
18
+ * The boundary is DEV-SERVED vs EXPORTED, decided by the bundler: a Vite dev
19
+ * server strips nothing, so `import.meta.env.DEV` is true; a production build
20
+ * (`vite build` — what `vgai deploy` runs) compiles it false and this module
21
+ * costs an exported game nothing. Headless contexts (unit tests, playtest's
22
+ * node leg) have no real browser page and never trip it — the check requires
23
+ * a document whose `defaultView` is the window, which no test stub wires up.
24
+ *
25
+ * There is deliberately NO opt-out flag, env var, or query param. An escape
26
+ * hatch an agent can reach for is the workaround again, one hop later.
27
+ */
28
+
29
+ /** What the refusal says — one place, so the page and the thrown Error agree. */
30
+ const REFUSAL = [
31
+ 'UNEXPORTED GAME, OUTSIDE THE EDITOR — refusing to mount.',
32
+ '',
33
+ 'This game has not been exported. Until it is, the ONLY way to run, see,',
34
+ 'or drive it is the editor:',
35
+ '',
36
+ ' vgai edit . open (or reuse) the editor for this project',
37
+ ' vgai play enter play mode from the terminal',
38
+ " vgai eval '<js>' drive and read the running game",
39
+ '',
40
+ 'The standalone page serves EXPORTED builds only (`vgai deploy`, or the',
41
+ 'production build it runs). Do not script around this page — no headless',
42
+ 'browsers, bots, or screenshots against the dev server. Every agent',
43
+ 'workflow goes through the editor session.',
44
+ ].join('\n');
45
+
46
+ /** True only on a real, dev-served browser page — the one context the trap is for. */
47
+ function isDevServedBrowserPage(): boolean {
48
+ if (typeof window === 'undefined' || typeof document === 'undefined') return false;
49
+ // Test stubs install a bare `document` object; only a real page has the
50
+ // document↔window linkage.
51
+ if (document.defaultView !== window) return false;
52
+ return Boolean(import.meta.env?.DEV);
53
+ }
54
+
55
+ /**
56
+ * Throws (and paints a full-screen refusal, so a human at the tab sees it as
57
+ * immediately as a harness watching the console does) when an unexported game
58
+ * is being mounted on a dev-served page. Called by `mountGameFromManifest`
59
+ * before any root is resolved; exported builds and headless tests pass
60
+ * through untouched.
61
+ */
62
+ export function assertExportedOrInEditor(): void {
63
+ if (!isDevServedBrowserPage()) return;
64
+
65
+ const screen = document.createElement('pre');
66
+ screen.textContent = REFUSAL;
67
+ screen.style.cssText = [
68
+ 'position:fixed',
69
+ 'inset:0',
70
+ 'z-index:2147483647',
71
+ 'margin:0',
72
+ 'padding:48px',
73
+ 'background:#1A0E0E',
74
+ 'color:#FF9B8A',
75
+ 'font:600 15px/1.7 ui-monospace,SFMono-Regular,Menlo,monospace',
76
+ 'white-space:pre-wrap',
77
+ ].join(';');
78
+ document.body.appendChild(screen);
79
+ document.title = 'UNEXPORTED — use the editor';
80
+
81
+ throw new Error(`mountGameFromManifest: ${REFUSAL}`);
82
+ }
@@ -1,3 +1,5 @@
1
+ /// <reference path="../types-n8ao.d.ts" />
2
+
1
3
  import { N8AOPostPass } from 'n8ao';
2
4
  import {
3
5
  BloomEffect,
@@ -29,6 +29,15 @@
29
29
  * to use instead.
30
30
  * - `EngineBridge` / `EngineBridgeValue` — the context contract, exported
31
31
  * for advanced adopters building their own bridge.
32
+ *
33
+ * Deliberately NOT re-exported here: `<RapierPhysicsBridge>`
34
+ * (`@engine/world3d-react/rapier-physics-bridge`), which registers an R3F
35
+ * world's `@react-three/rapier` physics as the game's
36
+ * `SystemAdapters.physics` — so the dev menu's colliders instrument and the
37
+ * editor's transform coordination can see it. It imports
38
+ * `@react-three/rapier`, and only a world that already depends on that library
39
+ * should pull it into its graph; a deep import keeps this barrel's peer
40
+ * contract to `react`/`@react-three/fiber`/`three` alone.
32
41
  */
33
42
 
34
43
  export { EngineBridge, type EngineBridgeValue, useGameContext } from './engine-bridge';
@@ -0,0 +1,137 @@
1
+ /**
2
+ * `<RapierPhysicsBridge>` — the one line that makes an R3F world's
3
+ * `@react-three/rapier` physics VISIBLE to the engine's editor/dev seams.
4
+ *
5
+ * WHY IT EXISTS. `SystemAdapters.physics` is what the editor's transform
6
+ * coordination (`freeze → apply → unfreeze`) and the dev menu's universal
7
+ * "Colliders drawn" instrument (`@engine/dev/instruments`) read. The
8
+ * first-party imperative three root registers one from
9
+ * `../adapter/setup-three-root-adapter.ts`; an R3F world builds no first-party
10
+ * Rapier runtime at all (see `R3FGameContext`'s doc comment) — it does physics
11
+ * with `@react-three/rapier` INSIDE the fiber tree, where nothing engine-side
12
+ * can see it. Result, before this: the colliders instrument read `null` (an
13
+ * em-dash) and its toggle threw "no physics adapter" in every shipped example
14
+ * and every scaffolded game.
15
+ *
16
+ * NOT A WRAPPER. This registers an adapter and gets out of the way: the world
17
+ * still writes `<Physics>` itself, with the library's own props, and every
18
+ * `<RigidBody>`/collider call stays `@react-three/rapier`'s own API. The one
19
+ * thing it cannot do for you is flip the library's debug rendering, because
20
+ * `@react-three/rapier@2` exposes that ONLY as the `debug` boolean PROP on
21
+ * `<Physics>` (its `<Debug>` component is internal and unexported). A prop is
22
+ * the parent's to own, so the world holds the state and this bridge hands the
23
+ * setter to the instrument — which is why `onDebugChange` is required:
24
+ *
25
+ * ```tsx
26
+ * const [physicsDebug, setPhysicsDebug] = useState(false);
27
+ * // …
28
+ * <Physics debug={physicsDebug}>
29
+ * <RapierPhysicsBridge onDebugChange={setPhysicsDebug} />
30
+ * …
31
+ * </Physics>
32
+ * ```
33
+ *
34
+ * Nothing draws colliders here: the wireframes are the library's own
35
+ * `world.debugRender()` output, rendered by its own component.
36
+ *
37
+ * ANTI-SHIM. `debugDraw()` and `contactPoints()` are OMITTED, not stubbed —
38
+ * the library owns its debug line segments inside the tree and hands out no
39
+ * handle to them, so claiming the capability would be a fabrication. Absence
40
+ * is how a `SystemAdapters` member says "not supported".
41
+ *
42
+ * ── RESOURCE OWNERSHIP, STATED ONCE ─────────────────────────────────────────
43
+ * OWNER: this component owns exactly ONE `SystemAdapters.physics` registration,
44
+ * on the R3F root it is mounted in. It allocates nothing else — no timers, no
45
+ * subscriptions, no per-frame work (see the phase note below), and no Rapier
46
+ * objects: the bodies it edits belong to `<Physics>`.
47
+ * SHARERS: every reader of `game.systemAdapters.physics` — the dev menu's
48
+ * colliders instrument, the editor's transform coordination. They read; they
49
+ * never dispose.
50
+ * TEARDOWN: the effect's cleanup, and nothing else — it clears the SAME key it
51
+ * set (`registerSystemAdapter('physics', undefined)`, which
52
+ * `Game.computeSystemAdapters` skips), so a play stop/start, a hot restart, or
53
+ * a world that unmounts `<Physics>` leaves no stale adapter behind. Two
54
+ * bridges in one root would fight over that one key; mount exactly one.
55
+ *
56
+ * PHASE ORDERING: none to respect — this component registers pull-only
57
+ * callbacks and runs no per-frame work. Every method it exposes is invoked
58
+ * BETWEEN frames, by an editor gesture or a dev-menu command, never from a
59
+ * phase.
60
+ */
61
+
62
+ import { type RapierRigidBody, useRapier } from '@react-three/rapier';
63
+ import { useEffect } from 'react';
64
+ import type * as THREE from 'three';
65
+ import {
66
+ createRapierBodyEditing,
67
+ type RapierEditableBody,
68
+ } from '../adapter/rapier-physics-adapter';
69
+ import type { PhysicsAdapter } from '../adapter/system-adapter';
70
+ import { useGameContext } from './engine-bridge';
71
+
72
+ export interface RapierPhysicsBridgeProps {
73
+ /**
74
+ * Set the `debug` prop of the SAME `<Physics>` this bridge is mounted in.
75
+ * The dev menu's "Colliders drawn" toggle calls it; the world's own state is
76
+ * what `<Physics debug={…}>` reads, so the library's debug rendering is the
77
+ * only thing that ever draws a collider.
78
+ */
79
+ readonly onDebugChange: (debug: boolean) => void;
80
+ }
81
+
82
+ /**
83
+ * Register this R3F world's `@react-three/rapier` physics as the game's
84
+ * `SystemAdapters.physics`. Mount it once, INSIDE `<Physics>` (it reads
85
+ * `useRapier()`). Renders nothing.
86
+ */
87
+ export function RapierPhysicsBridge({ onDebugChange }: RapierPhysicsBridgeProps): null {
88
+ const ctx = useGameContext();
89
+ const { rigidBodyStates } = useRapier();
90
+ const registerSystemAdapter = ctx.registerSystemAdapter;
91
+
92
+ useEffect(() => {
93
+ if (!registerSystemAdapter) return;
94
+
95
+ /**
96
+ * node id → the Rapier body driving it, in two hops the library and the
97
+ * engine each already own:
98
+ *
99
+ * 1. id → `Object3D`, through the live scene index — `userData.entityId`
100
+ * is this stack's identity convention (the editor's R3F authoring
101
+ * adapter stamps it; `../adapter/setup-three-root-adapter.ts` resolves
102
+ * the same way for the imperative root).
103
+ * 2. `Object3D` → body, through `rigidBodyStates` — the library's OWN
104
+ * body↔object map, carried on the `RapierContext` `useRapier()`
105
+ * returns. Walking ANCESTORS matters: `<RigidBody>` owns a subtree, so
106
+ * the selected mesh is usually a descendant of the object the state
107
+ * names.
108
+ *
109
+ * Both maps are live, so this is computed per call rather than cached —
110
+ * calls arrive at gesture rate (a gizmo drag start/end, a dev command),
111
+ * never per frame. `ctx.sceneIndex` is read AT CALL TIME, never captured:
112
+ * the R3F root backfills it once fiber resolves the scene, which can land
113
+ * after this component's first effect (`world-context.ts`'s
114
+ * `setSceneCamera`), so a destructured copy would be permanently absent.
115
+ */
116
+ const bodyFor = (nodeId: string): RapierEditableBody | undefined => {
117
+ const object = ctx.sceneIndex?.byEntityId(nodeId);
118
+ if (!object) return undefined;
119
+ const byObject = new Map<THREE.Object3D, RapierRigidBody>();
120
+ for (const state of rigidBodyStates.values()) byObject.set(state.object, state.rigidBody);
121
+ for (let node: THREE.Object3D | null = object; node; node = node.parent) {
122
+ const body = byObject.get(node);
123
+ if (body) return body;
124
+ }
125
+ return undefined;
126
+ };
127
+
128
+ const adapter: PhysicsAdapter = {
129
+ ...createRapierBodyEditing(bodyFor),
130
+ setDebugDrawEnabled: (enabled) => onDebugChange(enabled),
131
+ };
132
+ registerSystemAdapter('physics', adapter);
133
+ return () => registerSystemAdapter('physics', undefined);
134
+ }, [ctx, registerSystemAdapter, rigidBodyStates, onDebugChange]);
135
+
136
+ return null;
137
+ }