@forgeax/engine-app 0.0.0-dev.8d955ade1c79

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 (348) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +424 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/__tests__/animation-asset-lookup.unit.test.d.ts +2 -0
  5. package/dist/__tests__/animation-asset-lookup.unit.test.d.ts.map +1 -0
  6. package/dist/__tests__/callback-deletion.unit.test.d.ts +2 -0
  7. package/dist/__tests__/callback-deletion.unit.test.d.ts.map +1 -0
  8. package/dist/__tests__/callback-inference.test-d.d.ts +2 -0
  9. package/dist/__tests__/callback-inference.test-d.d.ts.map +1 -0
  10. package/dist/__tests__/component-introspection.unit.test.d.ts +2 -0
  11. package/dist/__tests__/component-introspection.unit.test.d.ts.map +1 -0
  12. package/dist/__tests__/consumer-migration.unit.test.d.ts +2 -0
  13. package/dist/__tests__/consumer-migration.unit.test.d.ts.map +1 -0
  14. package/dist/__tests__/create-app-error-retention.integration.test.d.ts +2 -0
  15. package/dist/__tests__/create-app-error-retention.integration.test.d.ts.map +1 -0
  16. package/dist/__tests__/create-app-features.test.d.ts +2 -0
  17. package/dist/__tests__/create-app-features.test.d.ts.map +1 -0
  18. package/dist/__tests__/create-app-listener-sync.test.d.ts +2 -0
  19. package/dist/__tests__/create-app-listener-sync.test.d.ts.map +1 -0
  20. package/dist/__tests__/create-app-lock-provider.test.d.ts +2 -0
  21. package/dist/__tests__/create-app-lock-provider.test.d.ts.map +1 -0
  22. package/dist/__tests__/create-app-physics-plugin-failure.integration.test.d.ts +2 -0
  23. package/dist/__tests__/create-app-physics-plugin-failure.integration.test.d.ts.map +1 -0
  24. package/dist/__tests__/create-app-plugin.test.d.ts +2 -0
  25. package/dist/__tests__/create-app-plugin.test.d.ts.map +1 -0
  26. package/dist/__tests__/create-app-stop.test.d.ts +2 -0
  27. package/dist/__tests__/create-app-stop.test.d.ts.map +1 -0
  28. package/dist/__tests__/create-app-time.unit.test.d.ts +2 -0
  29. package/dist/__tests__/create-app-time.unit.test.d.ts.map +1 -0
  30. package/dist/__tests__/create-app.test-d.d.ts +2 -0
  31. package/dist/__tests__/create-app.test-d.d.ts.map +1 -0
  32. package/dist/__tests__/create-app.test.d.ts +2 -0
  33. package/dist/__tests__/create-app.test.d.ts.map +1 -0
  34. package/dist/__tests__/create-renderer-error.integration.test.d.ts +2 -0
  35. package/dist/__tests__/create-renderer-error.integration.test.d.ts.map +1 -0
  36. package/dist/__tests__/create-renderer-lifecycle.integration.test.d.ts +2 -0
  37. package/dist/__tests__/create-renderer-lifecycle.integration.test.d.ts.map +1 -0
  38. package/dist/__tests__/docs-gate-green.unit.test.d.ts +2 -0
  39. package/dist/__tests__/docs-gate-green.unit.test.d.ts.map +1 -0
  40. package/dist/__tests__/draw-source-injected-world-update-visibility.test.d.ts +2 -0
  41. package/dist/__tests__/draw-source-injected-world-update-visibility.test.d.ts.map +1 -0
  42. package/dist/__tests__/draw-source-single-world-regression.test.d.ts +2 -0
  43. package/dist/__tests__/draw-source-single-world-regression.test.d.ts.map +1 -0
  44. package/dist/__tests__/engine-worker-bootstrap-channel.unit.test.d.ts +2 -0
  45. package/dist/__tests__/engine-worker-bootstrap-channel.unit.test.d.ts.map +1 -0
  46. package/dist/__tests__/engine-worker-world-swap.unit.test.d.ts +2 -0
  47. package/dist/__tests__/engine-worker-world-swap.unit.test.d.ts.map +1 -0
  48. package/dist/__tests__/errors-pointer-lock-failed.test.d.ts +2 -0
  49. package/dist/__tests__/errors-pointer-lock-failed.test.d.ts.map +1 -0
  50. package/dist/__tests__/execution-bootstrap-isolation.unit.test.d.ts +2 -0
  51. package/dist/__tests__/execution-bootstrap-isolation.unit.test.d.ts.map +1 -0
  52. package/dist/__tests__/execution-error-detail.test-d.d.ts +2 -0
  53. package/dist/__tests__/execution-error-detail.test-d.d.ts.map +1 -0
  54. package/dist/__tests__/execution-error-detail.unit.test.d.ts +2 -0
  55. package/dist/__tests__/execution-error-detail.unit.test.d.ts.map +1 -0
  56. package/dist/__tests__/execution-frame-order.unit.test.d.ts +2 -0
  57. package/dist/__tests__/execution-frame-order.unit.test.d.ts.map +1 -0
  58. package/dist/__tests__/execution-frame-protocol.unit.test.d.ts +2 -0
  59. package/dist/__tests__/execution-frame-protocol.unit.test.d.ts.map +1 -0
  60. package/dist/__tests__/execution-input-sample.contract.test.d.ts +2 -0
  61. package/dist/__tests__/execution-input-sample.contract.test.d.ts.map +1 -0
  62. package/dist/__tests__/execution-measurement.unit.test.d.ts +2 -0
  63. package/dist/__tests__/execution-measurement.unit.test.d.ts.map +1 -0
  64. package/dist/__tests__/execution-public-api.test-d.d.ts +2 -0
  65. package/dist/__tests__/execution-public-api.test-d.d.ts.map +1 -0
  66. package/dist/__tests__/execution-public-api.unit.test.d.ts +2 -0
  67. package/dist/__tests__/execution-public-api.unit.test.d.ts.map +1 -0
  68. package/dist/__tests__/execution-rebuild.contract.test.d.ts +2 -0
  69. package/dist/__tests__/execution-rebuild.contract.test.d.ts.map +1 -0
  70. package/dist/__tests__/execution-report.contract.test.d.ts +2 -0
  71. package/dist/__tests__/execution-report.contract.test.d.ts.map +1 -0
  72. package/dist/__tests__/execution-report.types.test-d.d.ts +2 -0
  73. package/dist/__tests__/execution-report.types.test-d.d.ts.map +1 -0
  74. package/dist/__tests__/execution-schema-freshness.unit.test.d.ts +2 -0
  75. package/dist/__tests__/execution-schema-freshness.unit.test.d.ts.map +1 -0
  76. package/dist/__tests__/execution-selector.unit.test.d.ts +2 -0
  77. package/dist/__tests__/execution-selector.unit.test.d.ts.map +1 -0
  78. package/dist/__tests__/execution-shared-kernel.unit.test.d.ts +2 -0
  79. package/dist/__tests__/execution-shared-kernel.unit.test.d.ts.map +1 -0
  80. package/dist/__tests__/fallback-camera.unit.test.d.ts +2 -0
  81. package/dist/__tests__/fallback-camera.unit.test.d.ts.map +1 -0
  82. package/dist/__tests__/frame-loop-time-elapsed.test.d.ts +2 -0
  83. package/dist/__tests__/frame-loop-time-elapsed.test.d.ts.map +1 -0
  84. package/dist/__tests__/frame-loop-time.unit.test.d.ts +2 -0
  85. package/dist/__tests__/frame-loop-time.unit.test.d.ts.map +1 -0
  86. package/dist/__tests__/frame-loop-world-array.test.d.ts +2 -0
  87. package/dist/__tests__/frame-loop-world-array.test.d.ts.map +1 -0
  88. package/dist/__tests__/kernel-worker-runtime.unit.test.d.ts +2 -0
  89. package/dist/__tests__/kernel-worker-runtime.unit.test.d.ts.map +1 -0
  90. package/dist/__tests__/migration-surface-inventory.unit.test.d.ts +2 -0
  91. package/dist/__tests__/migration-surface-inventory.unit.test.d.ts.map +1 -0
  92. package/dist/__tests__/plugin-policy.integration.test.d.ts +2 -0
  93. package/dist/__tests__/plugin-policy.integration.test.d.ts.map +1 -0
  94. package/dist/__tests__/plugin-profiles.unit.test.d.ts +2 -0
  95. package/dist/__tests__/plugin-profiles.unit.test.d.ts.map +1 -0
  96. package/dist/__tests__/profiler-default-off.test.d.ts +2 -0
  97. package/dist/__tests__/profiler-default-off.test.d.ts.map +1 -0
  98. package/dist/__tests__/profiler-frame-token.test.d.ts +2 -0
  99. package/dist/__tests__/profiler-frame-token.test.d.ts.map +1 -0
  100. package/dist/__tests__/profiler-phase-catalog.test.d.ts +2 -0
  101. package/dist/__tests__/profiler-phase-catalog.test.d.ts.map +1 -0
  102. package/dist/__tests__/profiler-phase-integration.test.d.ts +2 -0
  103. package/dist/__tests__/profiler-phase-integration.test.d.ts.map +1 -0
  104. package/dist/__tests__/profiler-remote-bridge.test.d.ts +2 -0
  105. package/dist/__tests__/profiler-remote-bridge.test.d.ts.map +1 -0
  106. package/dist/__tests__/remote-integration.test.d.ts +2 -0
  107. package/dist/__tests__/remote-integration.test.d.ts.map +1 -0
  108. package/dist/__tests__/rhi-capture-capability.test-d.d.ts +2 -0
  109. package/dist/__tests__/rhi-capture-capability.test-d.d.ts.map +1 -0
  110. package/dist/__tests__/rhi-capture-host.integration.test.d.ts +2 -0
  111. package/dist/__tests__/rhi-capture-host.integration.test.d.ts.map +1 -0
  112. package/dist/__tests__/rhi-capture.browser.test.d.ts +2 -0
  113. package/dist/__tests__/rhi-capture.browser.test.d.ts.map +1 -0
  114. package/dist/__tests__/surface-handoff.test.d.ts +2 -0
  115. package/dist/__tests__/surface-handoff.test.d.ts.map +1 -0
  116. package/dist/__tests__/types-m2.test-d.d.ts +2 -0
  117. package/dist/__tests__/types-m2.test-d.d.ts.map +1 -0
  118. package/dist/__tests__/visibility-remote.integration.test.d.ts +2 -0
  119. package/dist/__tests__/visibility-remote.integration.test.d.ts.map +1 -0
  120. package/dist/__tests__/worker-execution-stop.test.d.ts +2 -0
  121. package/dist/__tests__/worker-execution-stop.test.d.ts.map +1 -0
  122. package/dist/animation-asset-lookup.d.ts +7 -0
  123. package/dist/animation-asset-lookup.d.ts.map +1 -0
  124. package/dist/browser-frame-signal.d.ts +17 -0
  125. package/dist/browser-frame-signal.d.ts.map +1 -0
  126. package/dist/canvas-policy.d.ts +4 -0
  127. package/dist/canvas-policy.d.ts.map +1 -0
  128. package/dist/create-app.d.ts +78 -0
  129. package/dist/create-app.d.ts.map +1 -0
  130. package/dist/engine-worker-runtime.mjs +827 -0
  131. package/dist/engine-worker-runtime.mjs.map +1 -0
  132. package/dist/errors.d.ts +254 -0
  133. package/dist/errors.d.ts.map +1 -0
  134. package/dist/execution/attached-world-swap.d.ts +10 -0
  135. package/dist/execution/attached-world-swap.d.ts.map +1 -0
  136. package/dist/execution/bootstrap-entry.d.ts +30 -0
  137. package/dist/execution/bootstrap-entry.d.ts.map +1 -0
  138. package/dist/execution/bootstrap-url.d.ts +5 -0
  139. package/dist/execution/bootstrap-url.d.ts.map +1 -0
  140. package/dist/execution/capabilities.d.ts +5 -0
  141. package/dist/execution/capabilities.d.ts.map +1 -0
  142. package/dist/execution/control.d.ts +12 -0
  143. package/dist/execution/control.d.ts.map +1 -0
  144. package/dist/execution/engine-worker-runtime.d.ts +2 -0
  145. package/dist/execution/engine-worker-runtime.d.ts.map +1 -0
  146. package/dist/execution/engine-worker.d.ts +24 -0
  147. package/dist/execution/engine-worker.d.ts.map +1 -0
  148. package/dist/execution/host-controller.d.ts +16 -0
  149. package/dist/execution/host-controller.d.ts.map +1 -0
  150. package/dist/execution/index.d.ts +10 -0
  151. package/dist/execution/index.d.ts.map +1 -0
  152. package/dist/execution/kernel-pool.d.ts +14 -0
  153. package/dist/execution/kernel-pool.d.ts.map +1 -0
  154. package/dist/execution/kernel-worker-runtime.d.ts +2 -0
  155. package/dist/execution/kernel-worker-runtime.d.ts.map +1 -0
  156. package/dist/execution/measurement.d.ts +7 -0
  157. package/dist/execution/measurement.d.ts.map +1 -0
  158. package/dist/execution/protocol.d.ts +87 -0
  159. package/dist/execution/protocol.d.ts.map +1 -0
  160. package/dist/execution/report.d.ts +5 -0
  161. package/dist/execution/report.d.ts.map +1 -0
  162. package/dist/execution/schema.d.ts +4 -0
  163. package/dist/execution/schema.d.ts.map +1 -0
  164. package/dist/execution/selector.d.ts +10 -0
  165. package/dist/execution/selector.d.ts.map +1 -0
  166. package/dist/execution/types.d.ts +123 -0
  167. package/dist/execution/types.d.ts.map +1 -0
  168. package/dist/fallback-camera.d.ts +8 -0
  169. package/dist/fallback-camera.d.ts.map +1 -0
  170. package/dist/game-context.d.ts +98 -0
  171. package/dist/game-context.d.ts.map +1 -0
  172. package/dist/index.d.ts +27 -0
  173. package/dist/index.d.ts.map +1 -0
  174. package/dist/index.mjs +3980 -0
  175. package/dist/index.mjs.map +1 -0
  176. package/dist/input-map-plugin.d.ts +5 -0
  177. package/dist/input-map-plugin.d.ts.map +1 -0
  178. package/dist/input-plugin.d.ts +4 -0
  179. package/dist/input-plugin.d.ts.map +1 -0
  180. package/dist/internal/assembled-engine-profile.d.ts +5 -0
  181. package/dist/internal/assembled-engine-profile.d.ts.map +1 -0
  182. package/dist/internal/assets-world-plugin.d.ts +7 -0
  183. package/dist/internal/assets-world-plugin.d.ts.map +1 -0
  184. package/dist/internal/browser-remote-bridge.d.ts +24 -0
  185. package/dist/internal/browser-remote-bridge.d.ts.map +1 -0
  186. package/dist/internal/browser-rhi-debug-runtime.d.ts +18 -0
  187. package/dist/internal/browser-rhi-debug-runtime.d.ts.map +1 -0
  188. package/dist/internal/component-introspection.d.ts +24 -0
  189. package/dist/internal/component-introspection.d.ts.map +1 -0
  190. package/dist/internal/debug-draw.d.ts +9 -0
  191. package/dist/internal/debug-draw.d.ts.map +1 -0
  192. package/dist/internal/ecs-import.d.ts +6 -0
  193. package/dist/internal/ecs-import.d.ts.map +1 -0
  194. package/dist/internal/engine-profile-common.d.ts +9 -0
  195. package/dist/internal/engine-profile-common.d.ts.map +1 -0
  196. package/dist/internal/error-fanout.d.ts +66 -0
  197. package/dist/internal/error-fanout.d.ts.map +1 -0
  198. package/dist/internal/frame-loop.d.ts +38 -0
  199. package/dist/internal/frame-loop.d.ts.map +1 -0
  200. package/dist/internal/input-attach.d.ts +44 -0
  201. package/dist/internal/input-attach.d.ts.map +1 -0
  202. package/dist/internal/main-engine-profile.d.ts +19 -0
  203. package/dist/internal/main-engine-profile.d.ts.map +1 -0
  204. package/dist/internal/remote-serve-flag.d.ts +19 -0
  205. package/dist/internal/remote-serve-flag.d.ts.map +1 -0
  206. package/dist/internal/remote-server-plugin.d.ts +8 -0
  207. package/dist/internal/remote-server-plugin.d.ts.map +1 -0
  208. package/dist/internal/rhi-capture.d.ts +19 -0
  209. package/dist/internal/rhi-capture.d.ts.map +1 -0
  210. package/dist/internal/rhi-debug-flag.d.ts +18 -0
  211. package/dist/internal/rhi-debug-flag.d.ts.map +1 -0
  212. package/dist/internal/worker-engine-profile.d.ts +15 -0
  213. package/dist/internal/worker-engine-profile.d.ts.map +1 -0
  214. package/dist/kernel-worker-runtime.mjs +69 -0
  215. package/dist/kernel-worker-runtime.mjs.map +1 -0
  216. package/dist/load-game-errors.d.ts +131 -0
  217. package/dist/load-game-errors.d.ts.map +1 -0
  218. package/dist/load-game.d.ts +34 -0
  219. package/dist/load-game.d.ts.map +1 -0
  220. package/dist/plugin-factories.d.ts +3 -0
  221. package/dist/plugin-factories.d.ts.map +1 -0
  222. package/dist/renderer-plugin.d.ts +25 -0
  223. package/dist/renderer-plugin.d.ts.map +1 -0
  224. package/dist/tool-preview/bootstrap.d.ts +113 -0
  225. package/dist/tool-preview/bootstrap.d.ts.map +1 -0
  226. package/dist/tool-preview/evidence.d.ts +20 -0
  227. package/dist/tool-preview/evidence.d.ts.map +1 -0
  228. package/dist/tool-preview/framing.d.ts +13 -0
  229. package/dist/tool-preview/framing.d.ts.map +1 -0
  230. package/dist/tool-preview/recipe.d.ts +54 -0
  231. package/dist/tool-preview/recipe.d.ts.map +1 -0
  232. package/dist/types.d.ts +404 -0
  233. package/dist/types.d.ts.map +1 -0
  234. package/package.json +85 -0
  235. package/schema/execution-report.schema.json +168 -0
  236. package/src/__tests__/animation-asset-lookup.unit.test.ts +20 -0
  237. package/src/__tests__/callback-deletion.unit.test.ts +14 -0
  238. package/src/__tests__/callback-inference.test-d.ts +36 -0
  239. package/src/__tests__/component-introspection.unit.test.ts +56 -0
  240. package/src/__tests__/consumer-migration.unit.test.ts +34 -0
  241. package/src/__tests__/create-app-error-retention.integration.test.ts +125 -0
  242. package/src/__tests__/create-app-features.test.ts +51 -0
  243. package/src/__tests__/create-app-listener-sync.test.ts +381 -0
  244. package/src/__tests__/create-app-lock-provider.test.ts +212 -0
  245. package/src/__tests__/create-app-physics-plugin-failure.integration.test.ts +142 -0
  246. package/src/__tests__/create-app-plugin.test.ts +217 -0
  247. package/src/__tests__/create-app-stop.test.ts +609 -0
  248. package/src/__tests__/create-app-time.unit.test.ts +26 -0
  249. package/src/__tests__/create-app.test-d.ts +83 -0
  250. package/src/__tests__/create-app.test.ts +287 -0
  251. package/src/__tests__/create-renderer-error.integration.test.ts +25 -0
  252. package/src/__tests__/create-renderer-lifecycle.integration.test.ts +24 -0
  253. package/src/__tests__/docs-gate-green.unit.test.ts +61 -0
  254. package/src/__tests__/draw-source-injected-world-update-visibility.test.ts +176 -0
  255. package/src/__tests__/draw-source-single-world-regression.test.ts +184 -0
  256. package/src/__tests__/engine-worker-bootstrap-channel.unit.test.ts +82 -0
  257. package/src/__tests__/engine-worker-world-swap.unit.test.ts +69 -0
  258. package/src/__tests__/errors-pointer-lock-failed.test.ts +265 -0
  259. package/src/__tests__/execution-bootstrap-isolation.unit.test.ts +79 -0
  260. package/src/__tests__/execution-error-detail.test-d.ts +13 -0
  261. package/src/__tests__/execution-error-detail.unit.test.ts +35 -0
  262. package/src/__tests__/execution-frame-order.unit.test.ts +38 -0
  263. package/src/__tests__/execution-frame-protocol.unit.test.ts +60 -0
  264. package/src/__tests__/execution-input-sample.contract.test.ts +23 -0
  265. package/src/__tests__/execution-measurement.unit.test.ts +20 -0
  266. package/src/__tests__/execution-public-api.test-d.ts +14 -0
  267. package/src/__tests__/execution-public-api.unit.test.ts +9 -0
  268. package/src/__tests__/execution-rebuild.contract.test.ts +36 -0
  269. package/src/__tests__/execution-report.contract.test.ts +50 -0
  270. package/src/__tests__/execution-report.types.test-d.ts +16 -0
  271. package/src/__tests__/execution-schema-freshness.unit.test.ts +20 -0
  272. package/src/__tests__/execution-selector.unit.test.ts +72 -0
  273. package/src/__tests__/execution-shared-kernel.unit.test.ts +180 -0
  274. package/src/__tests__/fallback-camera.unit.test.ts +32 -0
  275. package/src/__tests__/frame-loop-time-elapsed.test.ts +115 -0
  276. package/src/__tests__/frame-loop-time.unit.test.ts +61 -0
  277. package/src/__tests__/frame-loop-world-array.test.ts +450 -0
  278. package/src/__tests__/kernel-worker-runtime.unit.test.ts +50 -0
  279. package/src/__tests__/migration-surface-inventory.unit.test.ts +13 -0
  280. package/src/__tests__/plugin-policy.integration.test.ts +15 -0
  281. package/src/__tests__/plugin-profiles.unit.test.ts +190 -0
  282. package/src/__tests__/profiler-default-off.test.ts +53 -0
  283. package/src/__tests__/profiler-frame-token.test.ts +235 -0
  284. package/src/__tests__/profiler-phase-catalog.test.ts +30 -0
  285. package/src/__tests__/profiler-phase-integration.test.ts +117 -0
  286. package/src/__tests__/profiler-remote-bridge.test.ts +31 -0
  287. package/src/__tests__/remote-integration.test.ts +224 -0
  288. package/src/__tests__/rhi-capture-capability.test-d.ts +22 -0
  289. package/src/__tests__/rhi-capture-host.integration.test.ts +157 -0
  290. package/src/__tests__/rhi-capture.browser.test.ts +51 -0
  291. package/src/__tests__/surface-handoff.test.ts +89 -0
  292. package/src/__tests__/types-m2.test-d.ts +81 -0
  293. package/src/__tests__/visibility-remote.integration.test.ts +116 -0
  294. package/src/__tests__/worker-execution-stop.test.ts +173 -0
  295. package/src/animation-asset-lookup.ts +13 -0
  296. package/src/browser-frame-signal.ts +44 -0
  297. package/src/canvas-policy.ts +16 -0
  298. package/src/create-app.ts +1264 -0
  299. package/src/errors.ts +442 -0
  300. package/src/execution/attached-world-swap.ts +33 -0
  301. package/src/execution/bootstrap-entry.ts +122 -0
  302. package/src/execution/bootstrap-url.ts +25 -0
  303. package/src/execution/capabilities.ts +102 -0
  304. package/src/execution/control.ts +48 -0
  305. package/src/execution/engine-worker-runtime.ts +383 -0
  306. package/src/execution/engine-worker.ts +163 -0
  307. package/src/execution/host-controller.ts +460 -0
  308. package/src/execution/index.ts +44 -0
  309. package/src/execution/kernel-pool.ts +236 -0
  310. package/src/execution/kernel-worker-runtime.ts +103 -0
  311. package/src/execution/measurement.ts +39 -0
  312. package/src/execution/protocol.ts +134 -0
  313. package/src/execution/report.ts +66 -0
  314. package/src/execution/schema.ts +168 -0
  315. package/src/execution/selector.ts +98 -0
  316. package/src/execution/types.ts +163 -0
  317. package/src/fallback-camera.ts +20 -0
  318. package/src/game-context.ts +126 -0
  319. package/src/index.ts +190 -0
  320. package/src/input-map-plugin.ts +21 -0
  321. package/src/input-plugin.ts +26 -0
  322. package/src/internal/assembled-engine-profile.ts +14 -0
  323. package/src/internal/assets-world-plugin.ts +33 -0
  324. package/src/internal/browser-remote-bridge.ts +269 -0
  325. package/src/internal/browser-rhi-debug-runtime.ts +67 -0
  326. package/src/internal/component-introspection.ts +116 -0
  327. package/src/internal/debug-draw.ts +38 -0
  328. package/src/internal/ecs-import.ts +41 -0
  329. package/src/internal/engine-profile-common.ts +9 -0
  330. package/src/internal/error-fanout.ts +129 -0
  331. package/src/internal/frame-loop.ts +539 -0
  332. package/src/internal/input-attach.ts +104 -0
  333. package/src/internal/main-engine-profile.ts +84 -0
  334. package/src/internal/remote-serve-flag.ts +41 -0
  335. package/src/internal/remote-server-plugin.ts +16 -0
  336. package/src/internal/rhi-capture.ts +211 -0
  337. package/src/internal/rhi-debug-flag.ts +40 -0
  338. package/src/internal/worker-engine-profile.ts +47 -0
  339. package/src/load-game-errors.ts +211 -0
  340. package/src/load-game.ts +115 -0
  341. package/src/plugin-factories.ts +2 -0
  342. package/src/renderer-plugin.ts +96 -0
  343. package/src/tool-preview/bootstrap.ts +835 -0
  344. package/src/tool-preview/evidence.ts +59 -0
  345. package/src/tool-preview/framing.ts +52 -0
  346. package/src/tool-preview/recipe.ts +137 -0
  347. package/src/types.ts +450 -0
  348. package/src/vite-env.d.ts +10 -0
@@ -0,0 +1,168 @@
1
+ import {
2
+ EXECUTION_CAPABILITY_NAMES,
3
+ EXECUTION_REQUESTED_TIERS,
4
+ EXECUTION_TIERS,
5
+ type ExecutionReport,
6
+ } from './types';
7
+
8
+ export const EXECUTION_REPORT_SCHEMA_VERSION = 1 as const;
9
+
10
+ function isRecord(value: unknown): value is Record<string, unknown> {
11
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
12
+ }
13
+
14
+ function hasExactKeys(value: Record<string, unknown>, keys: readonly string[]): boolean {
15
+ const actual = Object.keys(value);
16
+ return actual.length === keys.length && keys.every((key) => key in value);
17
+ }
18
+
19
+ function isMeasurement(value: unknown): boolean {
20
+ if (!isRecord(value) || !hasExactKeys(value, ['samples', 'p50', 'p95', 'p99', 'jitter'])) {
21
+ return false;
22
+ }
23
+ return (
24
+ Number.isInteger(value.samples) &&
25
+ (value.samples as number) > 0 &&
26
+ ['p50', 'p95', 'p99', 'jitter'].every(
27
+ (key) => typeof value[key] === 'number' && Number.isFinite(value[key]) && value[key] >= 0,
28
+ )
29
+ );
30
+ }
31
+
32
+ export function isExecutionReport(value: unknown): value is ExecutionReport {
33
+ if (!isRecord(value)) return false;
34
+ if (
35
+ !hasExactKeys(value, [
36
+ 'schemaVersion',
37
+ 'requestedTier',
38
+ 'actualTier',
39
+ 'selectionReason',
40
+ 'sharedEvidencePassed',
41
+ 'capabilities',
42
+ 'engine',
43
+ 'world',
44
+ 'kernelDispatch',
45
+ 'performance',
46
+ 'audio',
47
+ 'fault',
48
+ ])
49
+ ) {
50
+ return false;
51
+ }
52
+ const report = value as unknown as Partial<ExecutionReport>;
53
+ if (report.schemaVersion !== EXECUTION_REPORT_SCHEMA_VERSION) return false;
54
+ if (!EXECUTION_REQUESTED_TIERS.includes(report.requestedTier as never)) return false;
55
+ if (report.actualTier !== null && !EXECUTION_TIERS.includes(report.actualTier as never)) {
56
+ return false;
57
+ }
58
+ if (typeof report.sharedEvidencePassed !== 'boolean' || report.capabilities === undefined) {
59
+ return false;
60
+ }
61
+ if (
62
+ !EXECUTION_CAPABILITY_NAMES.every((name) => {
63
+ const fact = report.capabilities?.[name];
64
+ return typeof fact?.available === 'boolean' && typeof fact.reason === 'string';
65
+ })
66
+ )
67
+ return false;
68
+ const engine = report.engine;
69
+ const world = report.world;
70
+ const dispatch = report.kernelDispatch;
71
+ const performance = report.performance;
72
+ const audio = report.audio;
73
+ if (!isRecord(engine) || !hasExactKeys(engine, ['realm', 'health'])) return false;
74
+ if (!['host', 'worker'].includes(engine.realm as string)) return false;
75
+ if (!['idle', 'starting', 'running', 'stopped', 'faulted'].includes(engine.health as string)) {
76
+ return false;
77
+ }
78
+ if (
79
+ !isRecord(world) ||
80
+ !hasExactKeys(world, ['identity', 'health', 'partialWrite', 'retryable'])
81
+ ) {
82
+ return false;
83
+ }
84
+ if (world.identity !== null && typeof world.identity !== 'string') return false;
85
+ if (!['healthy', 'poisoned'].includes(world.health as string)) return false;
86
+ if (typeof world.partialWrite !== 'boolean' || typeof world.retryable !== 'boolean') return false;
87
+ if (
88
+ !isRecord(dispatch) ||
89
+ !hasExactKeys(dispatch, ['eligible', 'usedShared', 'reason', 'dispatched', 'completed'])
90
+ ) {
91
+ return false;
92
+ }
93
+ if (typeof dispatch.eligible !== 'boolean' || typeof dispatch.usedShared !== 'boolean')
94
+ return false;
95
+ if (
96
+ ![
97
+ 'no-eligible-kernel',
98
+ 'zero-work',
99
+ 'small-span',
100
+ 'forced-inline',
101
+ 'shared',
102
+ 'poisoned',
103
+ ].includes(dispatch.reason as string)
104
+ )
105
+ return false;
106
+ if (!Number.isInteger(dispatch.dispatched) || !Number.isInteger(dispatch.completed)) return false;
107
+ if (
108
+ !isRecord(performance) ||
109
+ !hasExactKeys(performance, ['hostFrameMs', 'engineUpdateMs', 'kernelWaitMs', 'hostAudioMs'])
110
+ )
111
+ return false;
112
+ for (const key of ['hostFrameMs', 'engineUpdateMs', 'kernelWaitMs', 'hostAudioMs'] as const) {
113
+ const measurement = performance[key];
114
+ if (measurement !== null && !isMeasurement(measurement)) return false;
115
+ }
116
+ if (
117
+ !isRecord(audio) ||
118
+ !hasExactKeys(audio, ['owner', 'contextState', 'activeSourceCount', 'lastError'])
119
+ )
120
+ return false;
121
+ if (audio.owner !== 'host') return false;
122
+ if (!['running', 'suspended', 'closed'].includes(audio.contextState as string)) return false;
123
+ if (!Number.isInteger(audio.activeSourceCount) || (audio.activeSourceCount as number) < 0)
124
+ return false;
125
+ if (audio.lastError !== null) {
126
+ if (!isRecord(audio.lastError)) return false;
127
+ if (!hasExactKeys(audio.lastError, ['code', 'expected', 'hint', 'detail'])) return false;
128
+ if (
129
+ typeof audio.lastError.code !== 'string' ||
130
+ typeof audio.lastError.expected !== 'string' ||
131
+ typeof audio.lastError.hint !== 'string'
132
+ )
133
+ return false;
134
+ }
135
+ if (report.fault !== null) {
136
+ if (!isRecord(report.fault)) return false;
137
+ if (
138
+ !hasExactKeys(report.fault, [
139
+ 'source',
140
+ 'code',
141
+ 'expected',
142
+ 'hint',
143
+ 'detail',
144
+ 'partialWrite',
145
+ 'retryable',
146
+ ])
147
+ )
148
+ return false;
149
+ if (
150
+ !['bootstrap', 'handshake', 'runtime', 'kernel', 'world', 'rebuild'].includes(
151
+ report.fault.source as string,
152
+ )
153
+ )
154
+ return false;
155
+ if (
156
+ typeof report.fault.code !== 'string' ||
157
+ typeof report.fault.expected !== 'string' ||
158
+ typeof report.fault.hint !== 'string'
159
+ )
160
+ return false;
161
+ if (
162
+ typeof report.fault.partialWrite !== 'boolean' ||
163
+ typeof report.fault.retryable !== 'boolean'
164
+ )
165
+ return false;
166
+ }
167
+ return true;
168
+ }
@@ -0,0 +1,98 @@
1
+ import { err, ok, type Result } from '@forgeax/engine-types';
2
+ import { APP_ERROR_HINTS, APP_EXPECTED, AppError, type AppError as AppErrorType } from '../errors';
3
+ import { missingExecutionCapabilities } from './capabilities';
4
+ import type {
5
+ ExecutionCapabilities,
6
+ ExecutionCapabilityName,
7
+ ExecutionRequestedTier,
8
+ ExecutionSelection,
9
+ ExecutionTier,
10
+ } from './types';
11
+
12
+ const ENGINE_WORKER_CAPABILITIES = [
13
+ 'worker',
14
+ 'offscreenCanvas',
15
+ 'workerWebGpu',
16
+ ] as const satisfies readonly ExecutionCapabilityName[];
17
+ const SHARED_CAPABILITIES = [
18
+ ...ENGINE_WORKER_CAPABILITIES,
19
+ 'crossOriginIsolated',
20
+ 'sharedArrayBuffer',
21
+ 'atomicsWait',
22
+ ] as const satisfies readonly ExecutionCapabilityName[];
23
+
24
+ export interface ExecutionSelectionInput {
25
+ readonly requestedTier: ExecutionRequestedTier;
26
+ readonly capabilities: ExecutionCapabilities;
27
+ readonly sharedEvidencePassed: boolean;
28
+ }
29
+
30
+ function requiredCapabilities(tier: ExecutionTier): readonly ExecutionCapabilityName[] {
31
+ if (tier === 'main-serial') return [];
32
+ if (tier === 'engine-worker') return ENGINE_WORKER_CAPABILITIES;
33
+ return SHARED_CAPABILITIES;
34
+ }
35
+
36
+ function missingFor(
37
+ tier: ExecutionTier,
38
+ capabilities: ExecutionCapabilities,
39
+ ): readonly ExecutionCapabilityName[] {
40
+ return missingExecutionCapabilities(capabilities, requiredCapabilities(tier));
41
+ }
42
+
43
+ export function selectExecutionTier(
44
+ input: ExecutionSelectionInput,
45
+ ): Result<ExecutionSelection, AppErrorType> {
46
+ if (input.requestedTier !== 'auto') {
47
+ const missing = missingFor(input.requestedTier, input.capabilities);
48
+ if (missing.length > 0 || (input.requestedTier === 'shared' && !input.sharedEvidencePassed)) {
49
+ return err(
50
+ new AppError({
51
+ code: 'app-execution-tier-unavailable',
52
+ expected: APP_EXPECTED['app-execution-tier-unavailable'],
53
+ hint: APP_ERROR_HINTS['app-execution-tier-unavailable'],
54
+ detail: {
55
+ requestedTier: input.requestedTier,
56
+ missingCapabilities: missing,
57
+ sharedEvidencePassed: input.sharedEvidencePassed,
58
+ },
59
+ }),
60
+ );
61
+ }
62
+ return ok({
63
+ requestedTier: input.requestedTier,
64
+ actualTier: input.requestedTier,
65
+ selectionReason: 'explicit-request',
66
+ missingCapabilities: [],
67
+ sharedEvidencePassed: input.sharedEvidencePassed,
68
+ });
69
+ }
70
+
71
+ const sharedMissing = missingFor('shared', input.capabilities);
72
+ if (sharedMissing.length === 0 && input.sharedEvidencePassed) {
73
+ return ok({
74
+ requestedTier: 'auto',
75
+ actualTier: 'shared',
76
+ selectionReason: 'auto-shared',
77
+ missingCapabilities: [],
78
+ sharedEvidencePassed: true,
79
+ });
80
+ }
81
+ const workerMissing = missingFor('engine-worker', input.capabilities);
82
+ if (workerMissing.length === 0) {
83
+ return ok({
84
+ requestedTier: 'auto',
85
+ actualTier: 'engine-worker',
86
+ selectionReason: 'auto-engine-worker',
87
+ missingCapabilities: sharedMissing,
88
+ sharedEvidencePassed: input.sharedEvidencePassed,
89
+ });
90
+ }
91
+ return ok({
92
+ requestedTier: 'auto',
93
+ actualTier: 'main-serial',
94
+ selectionReason: 'auto-main-serial',
95
+ missingCapabilities: workerMissing,
96
+ sharedEvidencePassed: input.sharedEvidencePassed,
97
+ });
98
+ }
@@ -0,0 +1,163 @@
1
+ import type { WorldExecutionHealth } from '@forgeax/engine-ecs/shared';
2
+ import type { Result, RuntimeAssetBinding } from '@forgeax/engine-types';
3
+ import type { AppError } from '../errors';
4
+
5
+ export const EXECUTION_TIERS = ['main-serial', 'engine-worker', 'shared'] as const;
6
+ export type ExecutionTier = (typeof EXECUTION_TIERS)[number];
7
+
8
+ export const EXECUTION_REQUESTED_TIERS = ['auto', ...EXECUTION_TIERS] as const;
9
+ export type ExecutionRequestedTier = (typeof EXECUTION_REQUESTED_TIERS)[number];
10
+
11
+ export const EXECUTION_CAPABILITY_NAMES = [
12
+ 'worker',
13
+ 'offscreenCanvas',
14
+ 'workerAnimationFrame',
15
+ 'workerWebGpu',
16
+ 'crossOriginIsolated',
17
+ 'sharedArrayBuffer',
18
+ 'atomicsWait',
19
+ ] as const;
20
+ export type ExecutionCapabilityName = (typeof EXECUTION_CAPABILITY_NAMES)[number];
21
+
22
+ export interface ExecutionCapabilityFact {
23
+ readonly available: boolean;
24
+ readonly reason: string;
25
+ }
26
+
27
+ export type ExecutionCapabilities = Readonly<
28
+ Record<ExecutionCapabilityName, ExecutionCapabilityFact>
29
+ >;
30
+
31
+ export type ExecutionSelectionReason =
32
+ | 'explicit-request'
33
+ | 'auto-shared'
34
+ | 'auto-engine-worker'
35
+ | 'auto-main-serial';
36
+
37
+ export interface ExecutionSelection {
38
+ readonly requestedTier: ExecutionRequestedTier;
39
+ readonly actualTier: ExecutionTier;
40
+ readonly selectionReason: ExecutionSelectionReason;
41
+ readonly missingCapabilities: readonly ExecutionCapabilityName[];
42
+ readonly sharedEvidencePassed: boolean;
43
+ }
44
+
45
+ export type ExecutionEngineHealth = 'idle' | 'starting' | 'running' | 'stopped' | 'faulted';
46
+ export type ExecutionWorldHealth = WorldExecutionHealth;
47
+
48
+ export type KernelDispatchReason =
49
+ | 'no-eligible-kernel'
50
+ | 'zero-work'
51
+ | 'small-span'
52
+ | 'forced-inline'
53
+ | 'shared'
54
+ | 'poisoned';
55
+
56
+ export interface ExecutionMeasurement {
57
+ readonly samples: number;
58
+ readonly p50: number;
59
+ readonly p95: number;
60
+ readonly p99: number;
61
+ readonly jitter: number;
62
+ }
63
+
64
+ export interface ExecutionFault {
65
+ readonly source: 'bootstrap' | 'handshake' | 'runtime' | 'kernel' | 'world' | 'rebuild';
66
+ readonly code: string;
67
+ readonly expected: string;
68
+ readonly hint: string;
69
+ readonly detail: unknown;
70
+ readonly partialWrite: boolean;
71
+ readonly retryable: boolean;
72
+ }
73
+
74
+ export interface ExecutionAudioReport {
75
+ readonly owner: 'host';
76
+ readonly contextState: 'running' | 'suspended' | 'closed';
77
+ readonly activeSourceCount: number;
78
+ readonly lastError: {
79
+ readonly code: string;
80
+ readonly expected: string;
81
+ readonly hint: string;
82
+ readonly detail: unknown;
83
+ } | null;
84
+ }
85
+
86
+ /**
87
+ * Serializable asset-catalog configuration copied into the selected Engine
88
+ * realm. The URL is resolved by that realm, so a Worker never closes over a
89
+ * Host-side CatalogSource or Registry instance.
90
+ */
91
+ export interface ExecutionAssetCatalog {
92
+ readonly url: string;
93
+ readonly expectedScope?: Pick<RuntimeAssetBinding, 'scopeId' | 'generation'>;
94
+ }
95
+
96
+ export interface ExecutionReport {
97
+ readonly schemaVersion: 1;
98
+ readonly requestedTier: ExecutionRequestedTier;
99
+ readonly actualTier: ExecutionTier | null;
100
+ readonly selectionReason: ExecutionSelectionReason | null;
101
+ readonly sharedEvidencePassed: boolean;
102
+ readonly capabilities: ExecutionCapabilities;
103
+ readonly engine: {
104
+ readonly realm: 'host' | 'worker';
105
+ readonly health: ExecutionEngineHealth;
106
+ };
107
+ readonly world: {
108
+ readonly identity: string | null;
109
+ readonly health: ExecutionWorldHealth;
110
+ readonly partialWrite: boolean;
111
+ readonly retryable: boolean;
112
+ };
113
+ readonly kernelDispatch: {
114
+ readonly eligible: boolean;
115
+ readonly usedShared: boolean;
116
+ readonly reason: KernelDispatchReason;
117
+ readonly dispatched: number;
118
+ readonly completed: number;
119
+ };
120
+ readonly performance: {
121
+ readonly hostFrameMs: ExecutionMeasurement | null;
122
+ readonly engineUpdateMs: ExecutionMeasurement | null;
123
+ readonly kernelWaitMs: ExecutionMeasurement | null;
124
+ readonly hostAudioMs: ExecutionMeasurement | null;
125
+ };
126
+ readonly audio: ExecutionAudioReport;
127
+ readonly fault: ExecutionFault | null;
128
+ }
129
+
130
+ export interface ExecutionOptions {
131
+ readonly tier?: ExecutionRequestedTier;
132
+ /** Absolute or import.meta.url-relative URL of an ExecutionBootstrapEntry module. */
133
+ readonly bootstrap: string | URL;
134
+ /** Structured-cloneable input supplied identically to main and Worker realms. */
135
+ readonly bootstrapData?: ExecutionBootstrapValue;
136
+ /**
137
+ * Realm side of an optional typed host/game channel. The engine transfers it
138
+ * to a Worker when needed and otherwise preserves the same port contract.
139
+ */
140
+ readonly bootstrapPort?: MessagePort;
141
+ /**
142
+ * Serializable CatalogSource configuration constructed inside the selected
143
+ * execution realm. This is the asset delivery seam for Worker execution;
144
+ * `CreateAppOptions.assetCatalog` remains realm-bound and is rejected when
145
+ * execution is requested.
146
+ */
147
+ readonly assetCatalog?: ExecutionAssetCatalog;
148
+ readonly startupTimeoutMs?: number;
149
+ readonly frameTimeoutMs?: number;
150
+ }
151
+
152
+ export type ExecutionBootstrapValue =
153
+ | null
154
+ | boolean
155
+ | number
156
+ | string
157
+ | readonly ExecutionBootstrapValue[]
158
+ | { readonly [key: string]: ExecutionBootstrapValue };
159
+
160
+ export interface ExecutionControl {
161
+ report(): ExecutionReport;
162
+ rebuild(): Promise<Result<ExecutionReport, AppError>>;
163
+ }
@@ -0,0 +1,20 @@
1
+ import type { World } from '@forgeax/engine-ecs';
2
+ import { Camera, perspective } from '@forgeax/engine-render';
3
+ import { Transform } from '@forgeax/engine-scene';
4
+
5
+ /**
6
+ * Ensure the neutral camera used only by hosts that have no game bootstrap.
7
+ * An authored scene camera wins; a resolved game owns its camera policy and
8
+ * must not call this helper.
9
+ */
10
+ export function ensureFallbackCamera(
11
+ world: World,
12
+ aspect = 1,
13
+ ): ReturnType<World['spawn']> | undefined {
14
+ const cameras = world.query({ with: [Camera] }).unwrap();
15
+ if (!cameras[Symbol.iterator]().next().done) return undefined;
16
+ return world.spawn(
17
+ { component: Transform, data: { pos: [0, 0.6, 5] } },
18
+ { component: Camera, data: perspective({ fov: Math.PI / 3, aspect, far: 1000 }) },
19
+ );
20
+ }
@@ -0,0 +1,126 @@
1
+ // @forgeax/engine-app -- Host service for asset-resident game plugins.
2
+ //
3
+ // App, Preview, and Devkit provide one realm-local GameHost service. Project
4
+ // code default-exports a native Cordis plugin that injects this service and
5
+ // owns all non-ECS teardown through Fiber effects.
6
+
7
+ import type { AssetRegistry } from '@forgeax/engine-assets-runtime';
8
+ import type { EntityHandle } from '@forgeax/engine-ecs';
9
+ import type { Plugin } from '@forgeax/engine-plugin';
10
+ import type { Renderer } from '@forgeax/engine-render';
11
+ import type { SceneAsset } from '@forgeax/engine-types';
12
+
13
+ import type { App } from './types';
14
+
15
+ /** JSON-shaped data a game may intentionally project through a host bridge. */
16
+ export type GameProjectionValue =
17
+ | null
18
+ | boolean
19
+ | number
20
+ | string
21
+ | GameProjectionValue[]
22
+ | { [key: string]: GameProjectionValue };
23
+
24
+ /** Lightweight, host-agnostic argument schema for a game-owned action. */
25
+ export interface GameActionArgsSchema {
26
+ readonly type?: 'string' | 'number' | 'boolean' | 'object' | 'array';
27
+ readonly properties?: Record<string, GameActionArgsSchema>;
28
+ readonly required?: string[];
29
+ readonly enum?: GameProjectionValue[];
30
+ readonly items?: GameActionArgsSchema;
31
+ readonly nullable?: boolean;
32
+ readonly description?: string;
33
+ }
34
+
35
+ /**
36
+ * A Play-only capability owned by game code. The host may discover and invoke it,
37
+ * but never supplies its gameplay semantics or reaches into the game World.
38
+ */
39
+ export interface GameActionDef {
40
+ readonly id: string;
41
+ readonly title: string;
42
+ readonly description?: string;
43
+ readonly argsSchema?: GameActionArgsSchema;
44
+ /** Return an optional JSON-shaped result for inspection clients. */
45
+ readonly run: (
46
+ args: GameProjectionValue,
47
+ ) => GameProjectionValue | void | Promise<GameProjectionValue | void>;
48
+ }
49
+
50
+ /** A named, serializable Play-only read projection owned by game code. */
51
+ export interface GameReadDef {
52
+ readonly id: string;
53
+ readonly title: string;
54
+ readonly description?: string;
55
+ readonly read: () => GameProjectionValue | Promise<GameProjectionValue>;
56
+ }
57
+
58
+ /**
59
+ * Host-provided registration sink for one Play run. Games receive this only while
60
+ * bootstrapping the fresh transient world; registrations are discarded when the run is disposed.
61
+ */
62
+ export interface GameProjectionRegistrar {
63
+ registerAction(def: GameActionDef): () => void;
64
+ registerRead(def: GameReadDef): () => void;
65
+ }
66
+
67
+ /** Realm-local Host capability injected into an asset-resident game plugin. */
68
+ export interface GameHost {
69
+ /** Presentation canvas owned by this Host realm. */
70
+ readonly canvas: HTMLCanvasElement;
71
+ /** The WebGPU Renderer (optional — some hosts may not expose it). */
72
+ readonly renderer?: Renderer;
73
+ /** The AssetRegistry owned by the Renderer. */
74
+ readonly assets: AssetRegistry;
75
+ /** The App handle for lifecycle introspection. */
76
+ readonly app: App;
77
+ /** Synthetic root entity of the host-instantiated defaultScene. Carries the
78
+ * SceneInstance component. Absent when the game has no defaultScene. */
79
+ readonly defaultSceneRoot?: EntityHandle;
80
+ /** The loaded SceneAsset payload for the defaultScene. Contains the
81
+ * author-side entity list with Name components. Absent when the game has
82
+ * no defaultScene. */
83
+ readonly defaultScene?: SceneAsset;
84
+ /**
85
+ * Controlled UI container for this run. Games must mount their DOM UI here
86
+ * (`(ctx.uiRoot ?? document.body).appendChild(el)`) instead of appending
87
+ * directly to `document.body`. In the embedded editor viewport the host
88
+ * removes this whole container when the run is disposed. Absent means game
89
+ * code falls back to `document.body`.
90
+ */
91
+ readonly uiRoot?: HTMLElement;
92
+ /**
93
+ * M2 D-3: command-set pointer-lock gate. The game template calls this
94
+ * when the view mode changes (e.g. `setPointerLockAllowed(mode === 'fps')`
95
+ * to allow lock in FPS, disallow in top-down). The host wires this to
96
+ * App.input.setPointerLockAllowed?.() which delegates to the input backend.
97
+ * Absent → the host does not support pointer-lock gating (e.g. a host
98
+ * that only runs top-down games).
99
+ */
100
+ readonly setPointerLockAllowed?: (allowed: boolean) => void;
101
+ /**
102
+ * Optional Play-only projection seam. A game registers its own action and read
103
+ * capabilities here; the host may only discover/invoke/read those closures. It
104
+ * is deliberately absent outside a host that can clear registrations on disposal.
105
+ */
106
+ readonly gameProjection?: GameProjectionRegistrar;
107
+ }
108
+
109
+ /**
110
+ * Provide the Host boundary to a native Cordis game plugin.
111
+ */
112
+ export function gameHostPlugin(host: GameHost): Plugin {
113
+ return {
114
+ name: 'game-host',
115
+ provide: 'gameHost',
116
+ apply(ctx) {
117
+ ctx.provide('gameHost', host);
118
+ },
119
+ };
120
+ }
121
+
122
+ declare module '@forgeax/engine-plugin' {
123
+ interface EngineContextServices {
124
+ gameHost?: GameHost;
125
+ }
126
+ }