@forgeax/engine-app 0.1.2

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 (354) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +418 -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__/app-rebuild.test.d.ts +2 -0
  7. package/dist/__tests__/app-rebuild.test.d.ts.map +1 -0
  8. package/dist/__tests__/asset-registry-types.test-d.d.ts +2 -0
  9. package/dist/__tests__/asset-registry-types.test-d.d.ts.map +1 -0
  10. package/dist/__tests__/assets-runtime-assembly.integration.test.d.ts +2 -0
  11. package/dist/__tests__/assets-runtime-assembly.integration.test.d.ts.map +1 -0
  12. package/dist/__tests__/callback-deletion.unit.test.d.ts +2 -0
  13. package/dist/__tests__/callback-deletion.unit.test.d.ts.map +1 -0
  14. package/dist/__tests__/callback-inference.test-d.d.ts +2 -0
  15. package/dist/__tests__/callback-inference.test-d.d.ts.map +1 -0
  16. package/dist/__tests__/component-introspection.unit.test.d.ts +2 -0
  17. package/dist/__tests__/component-introspection.unit.test.d.ts.map +1 -0
  18. package/dist/__tests__/consumer-migration.unit.test.d.ts +2 -0
  19. package/dist/__tests__/consumer-migration.unit.test.d.ts.map +1 -0
  20. package/dist/__tests__/create-app-features.test.d.ts +2 -0
  21. package/dist/__tests__/create-app-features.test.d.ts.map +1 -0
  22. package/dist/__tests__/create-app-listener-sync.test.d.ts +2 -0
  23. package/dist/__tests__/create-app-listener-sync.test.d.ts.map +1 -0
  24. package/dist/__tests__/create-app-lock-provider.test.d.ts +2 -0
  25. package/dist/__tests__/create-app-lock-provider.test.d.ts.map +1 -0
  26. package/dist/__tests__/create-app-plugin.test.d.ts +2 -0
  27. package/dist/__tests__/create-app-plugin.test.d.ts.map +1 -0
  28. package/dist/__tests__/create-app-stop.test.d.ts +2 -0
  29. package/dist/__tests__/create-app-stop.test.d.ts.map +1 -0
  30. package/dist/__tests__/create-app-time.unit.test.d.ts +2 -0
  31. package/dist/__tests__/create-app-time.unit.test.d.ts.map +1 -0
  32. package/dist/__tests__/create-app.test-d.d.ts +2 -0
  33. package/dist/__tests__/create-app.test-d.d.ts.map +1 -0
  34. package/dist/__tests__/create-app.test.d.ts +2 -0
  35. package/dist/__tests__/create-app.test.d.ts.map +1 -0
  36. package/dist/__tests__/create-renderer-error.integration.test.d.ts +2 -0
  37. package/dist/__tests__/create-renderer-error.integration.test.d.ts.map +1 -0
  38. package/dist/__tests__/create-renderer-lifecycle.integration.test.d.ts +2 -0
  39. package/dist/__tests__/create-renderer-lifecycle.integration.test.d.ts.map +1 -0
  40. package/dist/__tests__/docs-gate-green.unit.test.d.ts +2 -0
  41. package/dist/__tests__/docs-gate-green.unit.test.d.ts.map +1 -0
  42. package/dist/__tests__/draw-source-headless-full-chain.test.d.ts +2 -0
  43. package/dist/__tests__/draw-source-headless-full-chain.test.d.ts.map +1 -0
  44. package/dist/__tests__/draw-source-injected-world-update-visibility.test.d.ts +2 -0
  45. package/dist/__tests__/draw-source-injected-world-update-visibility.test.d.ts.map +1 -0
  46. package/dist/__tests__/draw-source-single-world-regression.test.d.ts +2 -0
  47. package/dist/__tests__/draw-source-single-world-regression.test.d.ts.map +1 -0
  48. package/dist/__tests__/ecs-import.unit.test.d.ts +2 -0
  49. package/dist/__tests__/ecs-import.unit.test.d.ts.map +1 -0
  50. package/dist/__tests__/engine-worker-bootstrap-channel.unit.test.d.ts +2 -0
  51. package/dist/__tests__/engine-worker-bootstrap-channel.unit.test.d.ts.map +1 -0
  52. package/dist/__tests__/engine-worker-world-swap.unit.test.d.ts +2 -0
  53. package/dist/__tests__/engine-worker-world-swap.unit.test.d.ts.map +1 -0
  54. package/dist/__tests__/errors-pointer-lock-failed.test.d.ts +2 -0
  55. package/dist/__tests__/errors-pointer-lock-failed.test.d.ts.map +1 -0
  56. package/dist/__tests__/execution-bootstrap-isolation.unit.test.d.ts +2 -0
  57. package/dist/__tests__/execution-bootstrap-isolation.unit.test.d.ts.map +1 -0
  58. package/dist/__tests__/execution-error-detail.test-d.d.ts +2 -0
  59. package/dist/__tests__/execution-error-detail.test-d.d.ts.map +1 -0
  60. package/dist/__tests__/execution-error-detail.unit.test.d.ts +2 -0
  61. package/dist/__tests__/execution-error-detail.unit.test.d.ts.map +1 -0
  62. package/dist/__tests__/execution-frame-order.unit.test.d.ts +2 -0
  63. package/dist/__tests__/execution-frame-order.unit.test.d.ts.map +1 -0
  64. package/dist/__tests__/execution-frame-protocol.unit.test.d.ts +2 -0
  65. package/dist/__tests__/execution-frame-protocol.unit.test.d.ts.map +1 -0
  66. package/dist/__tests__/execution-input-sample.contract.test.d.ts +2 -0
  67. package/dist/__tests__/execution-input-sample.contract.test.d.ts.map +1 -0
  68. package/dist/__tests__/execution-measurement.unit.test.d.ts +2 -0
  69. package/dist/__tests__/execution-measurement.unit.test.d.ts.map +1 -0
  70. package/dist/__tests__/execution-public-api.test-d.d.ts +2 -0
  71. package/dist/__tests__/execution-public-api.test-d.d.ts.map +1 -0
  72. package/dist/__tests__/execution-public-api.unit.test.d.ts +2 -0
  73. package/dist/__tests__/execution-public-api.unit.test.d.ts.map +1 -0
  74. package/dist/__tests__/execution-rebuild.contract.test.d.ts +2 -0
  75. package/dist/__tests__/execution-rebuild.contract.test.d.ts.map +1 -0
  76. package/dist/__tests__/execution-report.contract.test.d.ts +2 -0
  77. package/dist/__tests__/execution-report.contract.test.d.ts.map +1 -0
  78. package/dist/__tests__/execution-report.types.test-d.d.ts +2 -0
  79. package/dist/__tests__/execution-report.types.test-d.d.ts.map +1 -0
  80. package/dist/__tests__/execution-schema-freshness.unit.test.d.ts +2 -0
  81. package/dist/__tests__/execution-schema-freshness.unit.test.d.ts.map +1 -0
  82. package/dist/__tests__/execution-selector.unit.test.d.ts +2 -0
  83. package/dist/__tests__/execution-selector.unit.test.d.ts.map +1 -0
  84. package/dist/__tests__/execution-shared-kernel.unit.test.d.ts +2 -0
  85. package/dist/__tests__/execution-shared-kernel.unit.test.d.ts.map +1 -0
  86. package/dist/__tests__/execution-world-health-owner.test-d.d.ts +2 -0
  87. package/dist/__tests__/execution-world-health-owner.test-d.d.ts.map +1 -0
  88. package/dist/__tests__/fallback-camera.unit.test.d.ts +2 -0
  89. package/dist/__tests__/fallback-camera.unit.test.d.ts.map +1 -0
  90. package/dist/__tests__/frame-loop-time-elapsed.test.d.ts +2 -0
  91. package/dist/__tests__/frame-loop-time-elapsed.test.d.ts.map +1 -0
  92. package/dist/__tests__/frame-loop-time.unit.test.d.ts +2 -0
  93. package/dist/__tests__/frame-loop-time.unit.test.d.ts.map +1 -0
  94. package/dist/__tests__/frame-loop-world-array.test.d.ts +2 -0
  95. package/dist/__tests__/frame-loop-world-array.test.d.ts.map +1 -0
  96. package/dist/__tests__/kernel-worker-runtime.unit.test.d.ts +2 -0
  97. package/dist/__tests__/kernel-worker-runtime.unit.test.d.ts.map +1 -0
  98. package/dist/__tests__/migration-surface-inventory.unit.test.d.ts +2 -0
  99. package/dist/__tests__/migration-surface-inventory.unit.test.d.ts.map +1 -0
  100. package/dist/__tests__/plugin-policy.integration.test.d.ts +2 -0
  101. package/dist/__tests__/plugin-policy.integration.test.d.ts.map +1 -0
  102. package/dist/__tests__/plugin-profiles.unit.test.d.ts +2 -0
  103. package/dist/__tests__/plugin-profiles.unit.test.d.ts.map +1 -0
  104. package/dist/__tests__/profiler-default-off.test.d.ts +2 -0
  105. package/dist/__tests__/profiler-default-off.test.d.ts.map +1 -0
  106. package/dist/__tests__/profiler-frame-token.test.d.ts +2 -0
  107. package/dist/__tests__/profiler-frame-token.test.d.ts.map +1 -0
  108. package/dist/__tests__/profiler-phase-catalog.test.d.ts +2 -0
  109. package/dist/__tests__/profiler-phase-catalog.test.d.ts.map +1 -0
  110. package/dist/__tests__/profiler-phase-integration.test.d.ts +2 -0
  111. package/dist/__tests__/profiler-phase-integration.test.d.ts.map +1 -0
  112. package/dist/__tests__/profiler-remote-bridge.test.d.ts +2 -0
  113. package/dist/__tests__/profiler-remote-bridge.test.d.ts.map +1 -0
  114. package/dist/__tests__/remote-integration.test.d.ts +2 -0
  115. package/dist/__tests__/remote-integration.test.d.ts.map +1 -0
  116. package/dist/__tests__/remote-serve-flag.test.d.ts +2 -0
  117. package/dist/__tests__/remote-serve-flag.test.d.ts.map +1 -0
  118. package/dist/__tests__/rhi-capture-capability.test-d.d.ts +2 -0
  119. package/dist/__tests__/rhi-capture-capability.test-d.d.ts.map +1 -0
  120. package/dist/__tests__/rhi-capture-host.integration.test.d.ts +2 -0
  121. package/dist/__tests__/rhi-capture-host.integration.test.d.ts.map +1 -0
  122. package/dist/__tests__/rhi-capture.browser.test.d.ts +2 -0
  123. package/dist/__tests__/rhi-capture.browser.test.d.ts.map +1 -0
  124. package/dist/__tests__/surface-handoff.test.d.ts +2 -0
  125. package/dist/__tests__/surface-handoff.test.d.ts.map +1 -0
  126. package/dist/__tests__/types-m2.test-d.d.ts +2 -0
  127. package/dist/__tests__/types-m2.test-d.d.ts.map +1 -0
  128. package/dist/__tests__/visibility-remote.integration.test.d.ts +2 -0
  129. package/dist/__tests__/visibility-remote.integration.test.d.ts.map +1 -0
  130. package/dist/__tests__/worker-execution-stop.test.d.ts +2 -0
  131. package/dist/__tests__/worker-execution-stop.test.d.ts.map +1 -0
  132. package/dist/animation-asset-lookup.d.ts +8 -0
  133. package/dist/animation-asset-lookup.d.ts.map +1 -0
  134. package/dist/assets-runtime-assembly.d.ts +19 -0
  135. package/dist/assets-runtime-assembly.d.ts.map +1 -0
  136. package/dist/canvas-policy.d.ts +4 -0
  137. package/dist/canvas-policy.d.ts.map +1 -0
  138. package/dist/create-app.d.ts +57 -0
  139. package/dist/create-app.d.ts.map +1 -0
  140. package/dist/engine-worker-runtime.mjs +884 -0
  141. package/dist/engine-worker-runtime.mjs.map +1 -0
  142. package/dist/errors.d.ts +263 -0
  143. package/dist/errors.d.ts.map +1 -0
  144. package/dist/execution/attached-world-swap.d.ts +21 -0
  145. package/dist/execution/attached-world-swap.d.ts.map +1 -0
  146. package/dist/execution/bootstrap-entry.d.ts +30 -0
  147. package/dist/execution/bootstrap-entry.d.ts.map +1 -0
  148. package/dist/execution/capabilities.d.ts +5 -0
  149. package/dist/execution/capabilities.d.ts.map +1 -0
  150. package/dist/execution/control.d.ts +14 -0
  151. package/dist/execution/control.d.ts.map +1 -0
  152. package/dist/execution/engine-worker-runtime.d.ts +2 -0
  153. package/dist/execution/engine-worker-runtime.d.ts.map +1 -0
  154. package/dist/execution/engine-worker.d.ts +23 -0
  155. package/dist/execution/engine-worker.d.ts.map +1 -0
  156. package/dist/execution/host-controller.d.ts +16 -0
  157. package/dist/execution/host-controller.d.ts.map +1 -0
  158. package/dist/execution/index.d.ts +10 -0
  159. package/dist/execution/index.d.ts.map +1 -0
  160. package/dist/execution/kernel-pool.d.ts +14 -0
  161. package/dist/execution/kernel-pool.d.ts.map +1 -0
  162. package/dist/execution/kernel-worker-runtime.d.ts +2 -0
  163. package/dist/execution/kernel-worker-runtime.d.ts.map +1 -0
  164. package/dist/execution/measurement.d.ts +7 -0
  165. package/dist/execution/measurement.d.ts.map +1 -0
  166. package/dist/execution/protocol.d.ts +84 -0
  167. package/dist/execution/protocol.d.ts.map +1 -0
  168. package/dist/execution/report.d.ts +5 -0
  169. package/dist/execution/report.d.ts.map +1 -0
  170. package/dist/execution/schema.d.ts +4 -0
  171. package/dist/execution/schema.d.ts.map +1 -0
  172. package/dist/execution/selector.d.ts +10 -0
  173. package/dist/execution/selector.d.ts.map +1 -0
  174. package/dist/execution/types.d.ts +107 -0
  175. package/dist/execution/types.d.ts.map +1 -0
  176. package/dist/fallback-camera.d.ts +8 -0
  177. package/dist/fallback-camera.d.ts.map +1 -0
  178. package/dist/game-context.d.ts +98 -0
  179. package/dist/game-context.d.ts.map +1 -0
  180. package/dist/index.d.ts +24 -0
  181. package/dist/index.d.ts.map +1 -0
  182. package/dist/index.mjs +3985 -0
  183. package/dist/index.mjs.map +1 -0
  184. package/dist/input-map-plugin.d.ts +5 -0
  185. package/dist/input-map-plugin.d.ts.map +1 -0
  186. package/dist/input-plugin.d.ts +4 -0
  187. package/dist/input-plugin.d.ts.map +1 -0
  188. package/dist/internal/assembled-engine-profile.d.ts +5 -0
  189. package/dist/internal/assembled-engine-profile.d.ts.map +1 -0
  190. package/dist/internal/assets-world-plugin.d.ts +21 -0
  191. package/dist/internal/assets-world-plugin.d.ts.map +1 -0
  192. package/dist/internal/browser-remote-bridge.d.ts +25 -0
  193. package/dist/internal/browser-remote-bridge.d.ts.map +1 -0
  194. package/dist/internal/browser-rhi-debug-runtime.d.ts +18 -0
  195. package/dist/internal/browser-rhi-debug-runtime.d.ts.map +1 -0
  196. package/dist/internal/component-introspection.d.ts +24 -0
  197. package/dist/internal/component-introspection.d.ts.map +1 -0
  198. package/dist/internal/ecs-import.d.ts +6 -0
  199. package/dist/internal/ecs-import.d.ts.map +1 -0
  200. package/dist/internal/engine-profile-common.d.ts +9 -0
  201. package/dist/internal/engine-profile-common.d.ts.map +1 -0
  202. package/dist/internal/error-fanout.d.ts +66 -0
  203. package/dist/internal/error-fanout.d.ts.map +1 -0
  204. package/dist/internal/frame-loop.d.ts +35 -0
  205. package/dist/internal/frame-loop.d.ts.map +1 -0
  206. package/dist/internal/input-attach.d.ts +44 -0
  207. package/dist/internal/input-attach.d.ts.map +1 -0
  208. package/dist/internal/main-engine-profile.d.ts +15 -0
  209. package/dist/internal/main-engine-profile.d.ts.map +1 -0
  210. package/dist/internal/remote-serve-flag.d.ts +23 -0
  211. package/dist/internal/remote-serve-flag.d.ts.map +1 -0
  212. package/dist/internal/remote-server-plugin.d.ts +8 -0
  213. package/dist/internal/remote-server-plugin.d.ts.map +1 -0
  214. package/dist/internal/rhi-capture.d.ts +19 -0
  215. package/dist/internal/rhi-capture.d.ts.map +1 -0
  216. package/dist/internal/rhi-debug-flag.d.ts +18 -0
  217. package/dist/internal/rhi-debug-flag.d.ts.map +1 -0
  218. package/dist/internal/worker-engine-profile.d.ts +13 -0
  219. package/dist/internal/worker-engine-profile.d.ts.map +1 -0
  220. package/dist/kernel-worker-runtime.mjs +69 -0
  221. package/dist/kernel-worker-runtime.mjs.map +1 -0
  222. package/dist/load-game-errors.d.ts +131 -0
  223. package/dist/load-game-errors.d.ts.map +1 -0
  224. package/dist/load-game.d.ts +34 -0
  225. package/dist/load-game.d.ts.map +1 -0
  226. package/dist/plugin-factories.d.ts +3 -0
  227. package/dist/plugin-factories.d.ts.map +1 -0
  228. package/dist/tool-preview/bootstrap.d.ts +113 -0
  229. package/dist/tool-preview/bootstrap.d.ts.map +1 -0
  230. package/dist/tool-preview/evidence.d.ts +20 -0
  231. package/dist/tool-preview/evidence.d.ts.map +1 -0
  232. package/dist/tool-preview/framing.d.ts +13 -0
  233. package/dist/tool-preview/framing.d.ts.map +1 -0
  234. package/dist/tool-preview/recipe.d.ts +54 -0
  235. package/dist/tool-preview/recipe.d.ts.map +1 -0
  236. package/dist/types.d.ts +444 -0
  237. package/dist/types.d.ts.map +1 -0
  238. package/package.json +86 -0
  239. package/schema/execution-report.schema.json +168 -0
  240. package/src/__tests__/animation-asset-lookup.unit.test.ts +20 -0
  241. package/src/__tests__/app-rebuild.test.ts +31 -0
  242. package/src/__tests__/asset-registry-types.test-d.ts +16 -0
  243. package/src/__tests__/assets-runtime-assembly.integration.test.ts +68 -0
  244. package/src/__tests__/callback-deletion.unit.test.ts +14 -0
  245. package/src/__tests__/callback-inference.test-d.ts +32 -0
  246. package/src/__tests__/component-introspection.unit.test.ts +56 -0
  247. package/src/__tests__/consumer-migration.unit.test.ts +21 -0
  248. package/src/__tests__/create-app-features.test.ts +40 -0
  249. package/src/__tests__/create-app-listener-sync.test.ts +377 -0
  250. package/src/__tests__/create-app-lock-provider.test.ts +212 -0
  251. package/src/__tests__/create-app-plugin.test.ts +217 -0
  252. package/src/__tests__/create-app-stop.test.ts +617 -0
  253. package/src/__tests__/create-app-time.unit.test.ts +26 -0
  254. package/src/__tests__/create-app.test-d.ts +82 -0
  255. package/src/__tests__/create-app.test.ts +346 -0
  256. package/src/__tests__/create-renderer-error.integration.test.ts +24 -0
  257. package/src/__tests__/create-renderer-lifecycle.integration.test.ts +19 -0
  258. package/src/__tests__/docs-gate-green.unit.test.ts +61 -0
  259. package/src/__tests__/draw-source-headless-full-chain.test.ts +226 -0
  260. package/src/__tests__/draw-source-injected-world-update-visibility.test.ts +182 -0
  261. package/src/__tests__/draw-source-single-world-regression.test.ts +185 -0
  262. package/src/__tests__/ecs-import.unit.test.ts +40 -0
  263. package/src/__tests__/engine-worker-bootstrap-channel.unit.test.ts +74 -0
  264. package/src/__tests__/engine-worker-world-swap.unit.test.ts +76 -0
  265. package/src/__tests__/errors-pointer-lock-failed.test.ts +268 -0
  266. package/src/__tests__/execution-bootstrap-isolation.unit.test.ts +80 -0
  267. package/src/__tests__/execution-error-detail.test-d.ts +13 -0
  268. package/src/__tests__/execution-error-detail.unit.test.ts +35 -0
  269. package/src/__tests__/execution-frame-order.unit.test.ts +38 -0
  270. package/src/__tests__/execution-frame-protocol.unit.test.ts +61 -0
  271. package/src/__tests__/execution-input-sample.contract.test.ts +23 -0
  272. package/src/__tests__/execution-measurement.unit.test.ts +20 -0
  273. package/src/__tests__/execution-public-api.test-d.ts +10 -0
  274. package/src/__tests__/execution-public-api.unit.test.ts +9 -0
  275. package/src/__tests__/execution-rebuild.contract.test.ts +36 -0
  276. package/src/__tests__/execution-report.contract.test.ts +50 -0
  277. package/src/__tests__/execution-report.types.test-d.ts +16 -0
  278. package/src/__tests__/execution-schema-freshness.unit.test.ts +20 -0
  279. package/src/__tests__/execution-selector.unit.test.ts +72 -0
  280. package/src/__tests__/execution-shared-kernel.unit.test.ts +180 -0
  281. package/src/__tests__/execution-world-health-owner.test-d.ts +9 -0
  282. package/src/__tests__/fallback-camera.unit.test.ts +32 -0
  283. package/src/__tests__/frame-loop-time-elapsed.test.ts +115 -0
  284. package/src/__tests__/frame-loop-time.unit.test.ts +61 -0
  285. package/src/__tests__/frame-loop-world-array.test.ts +441 -0
  286. package/src/__tests__/kernel-worker-runtime.unit.test.ts +50 -0
  287. package/src/__tests__/migration-surface-inventory.unit.test.ts +13 -0
  288. package/src/__tests__/plugin-policy.integration.test.ts +15 -0
  289. package/src/__tests__/plugin-profiles.unit.test.ts +190 -0
  290. package/src/__tests__/profiler-default-off.test.ts +53 -0
  291. package/src/__tests__/profiler-frame-token.test.ts +248 -0
  292. package/src/__tests__/profiler-phase-catalog.test.ts +30 -0
  293. package/src/__tests__/profiler-phase-integration.test.ts +129 -0
  294. package/src/__tests__/profiler-remote-bridge.test.ts +31 -0
  295. package/src/__tests__/remote-integration.test.ts +224 -0
  296. package/src/__tests__/remote-serve-flag.test.ts +24 -0
  297. package/src/__tests__/rhi-capture-capability.test-d.ts +22 -0
  298. package/src/__tests__/rhi-capture-host.integration.test.ts +157 -0
  299. package/src/__tests__/rhi-capture.browser.test.ts +51 -0
  300. package/src/__tests__/surface-handoff.test.ts +92 -0
  301. package/src/__tests__/types-m2.test-d.ts +81 -0
  302. package/src/__tests__/visibility-remote.integration.test.ts +119 -0
  303. package/src/__tests__/worker-execution-stop.test.ts +116 -0
  304. package/src/animation-asset-lookup.ts +13 -0
  305. package/src/assets-runtime-assembly.ts +70 -0
  306. package/src/canvas-policy.ts +16 -0
  307. package/src/create-app.ts +1351 -0
  308. package/src/errors.ts +454 -0
  309. package/src/execution/attached-world-swap.ts +67 -0
  310. package/src/execution/bootstrap-entry.ts +122 -0
  311. package/src/execution/capabilities.ts +102 -0
  312. package/src/execution/control.ts +52 -0
  313. package/src/execution/engine-worker-runtime.ts +400 -0
  314. package/src/execution/engine-worker.ts +161 -0
  315. package/src/execution/host-controller.ts +454 -0
  316. package/src/execution/index.ts +43 -0
  317. package/src/execution/kernel-pool.ts +236 -0
  318. package/src/execution/kernel-worker-runtime.ts +103 -0
  319. package/src/execution/measurement.ts +39 -0
  320. package/src/execution/protocol.ts +131 -0
  321. package/src/execution/report.ts +66 -0
  322. package/src/execution/schema.ts +168 -0
  323. package/src/execution/selector.ts +98 -0
  324. package/src/execution/types.ts +146 -0
  325. package/src/fallback-camera.ts +20 -0
  326. package/src/game-context.ts +126 -0
  327. package/src/index.ts +176 -0
  328. package/src/input-map-plugin.ts +21 -0
  329. package/src/input-plugin.ts +26 -0
  330. package/src/internal/assembled-engine-profile.ts +22 -0
  331. package/src/internal/assets-world-plugin.ts +79 -0
  332. package/src/internal/browser-remote-bridge.ts +267 -0
  333. package/src/internal/browser-rhi-debug-runtime.ts +67 -0
  334. package/src/internal/component-introspection.ts +116 -0
  335. package/src/internal/ecs-import.ts +41 -0
  336. package/src/internal/engine-profile-common.ts +10 -0
  337. package/src/internal/error-fanout.ts +129 -0
  338. package/src/internal/frame-loop.ts +525 -0
  339. package/src/internal/input-attach.ts +104 -0
  340. package/src/internal/main-engine-profile.ts +80 -0
  341. package/src/internal/remote-serve-flag.ts +50 -0
  342. package/src/internal/remote-server-plugin.ts +16 -0
  343. package/src/internal/rhi-capture.ts +211 -0
  344. package/src/internal/rhi-debug-flag.ts +40 -0
  345. package/src/internal/worker-engine-profile.ts +47 -0
  346. package/src/load-game-errors.ts +211 -0
  347. package/src/load-game.ts +115 -0
  348. package/src/plugin-factories.ts +2 -0
  349. package/src/tool-preview/bootstrap.ts +848 -0
  350. package/src/tool-preview/evidence.ts +59 -0
  351. package/src/tool-preview/framing.ts +52 -0
  352. package/src/tool-preview/recipe.ts +137 -0
  353. package/src/types.ts +505 -0
  354. package/src/vite-env.d.ts +12 -0
@@ -0,0 +1,161 @@
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 { validateExecutionBootstrapData } from './bootstrap-entry';
4
+ import type {
5
+ EngineToHostMessage,
6
+ ExecutionFaultMessage,
7
+ ExecutionInitMessage,
8
+ ExecutionReadyMessage,
9
+ HostToEngineMessage,
10
+ } from './protocol';
11
+
12
+ export interface EngineWorkerSession {
13
+ readonly worker: Worker;
14
+ readonly ready: ExecutionReadyMessage;
15
+ post(message: HostToEngineMessage, transfer?: Transferable[]): void;
16
+ listen(listener: (message: EngineToHostMessage) => void): () => void;
17
+ dispose(): void;
18
+ }
19
+
20
+ export interface StartEngineWorkerOptions {
21
+ readonly canvas: HTMLCanvasElement;
22
+ readonly bootstrapUrl: string;
23
+ readonly bootstrapData?: import('./types').ExecutionBootstrapValue;
24
+ readonly bootstrapPort?: MessagePort;
25
+ readonly shaderManifestUrl?: string;
26
+ readonly time?: import('@forgeax/engine-ecs').TimePolicy;
27
+ readonly timeoutMs: number;
28
+ readonly tier: import('./types').ExecutionTier;
29
+ readonly workerFactory?: () => Worker;
30
+ }
31
+
32
+ function deadlineError(timeoutMs: number): AppErrorType {
33
+ return new AppError({
34
+ code: 'app-execution-deadline-exceeded',
35
+ expected: APP_EXPECTED['app-execution-deadline-exceeded'],
36
+ hint: APP_ERROR_HINTS['app-execution-deadline-exceeded'],
37
+ detail: { phase: 'handshake', timeoutMs },
38
+ });
39
+ }
40
+
41
+ function startupFault(message: ExecutionFaultMessage, moduleUrl: string): AppErrorType {
42
+ return new AppError({
43
+ code: 'app-execution-bootstrap-failed',
44
+ expected: APP_EXPECTED['app-execution-bootstrap-failed'],
45
+ hint: APP_ERROR_HINTS['app-execution-bootstrap-failed'],
46
+ detail: { phase: 'bootstrap', moduleUrl, cause: message.detail },
47
+ });
48
+ }
49
+
50
+ export async function startEngineWorker(
51
+ options: StartEngineWorkerOptions,
52
+ ): Promise<Result<EngineWorkerSession, AppErrorType>> {
53
+ const validData = validateExecutionBootstrapData(options.bootstrapData, options.bootstrapUrl);
54
+ if (!validData.ok) return validData;
55
+ const worker =
56
+ options.workerFactory?.() ??
57
+ new Worker(new URL('./engine-worker-runtime.mjs', import.meta.url), {
58
+ type: 'module',
59
+ name: 'forgeax-engine',
60
+ });
61
+ const listeners = new Set<(message: EngineToHostMessage) => void>();
62
+ let settled = false;
63
+ let resolveReady: (result: Result<ExecutionReadyMessage, AppErrorType>) => void = () => {};
64
+ const readyPromise = new Promise<Result<ExecutionReadyMessage, AppErrorType>>((resolve) => {
65
+ resolveReady = resolve;
66
+ });
67
+ const timeout = setTimeout(() => {
68
+ if (settled) return;
69
+ settled = true;
70
+ worker.terminate();
71
+ resolveReady(err(deadlineError(options.timeoutMs)));
72
+ }, options.timeoutMs);
73
+ worker.onmessage = (event: MessageEvent<EngineToHostMessage>) => {
74
+ const message = event.data;
75
+ if (!settled && message.kind === 'ready') {
76
+ settled = true;
77
+ clearTimeout(timeout);
78
+ resolveReady(ok(message));
79
+ } else if (!settled && message.kind === 'fault') {
80
+ settled = true;
81
+ clearTimeout(timeout);
82
+ worker.terminate();
83
+ resolveReady(err(startupFault(message, options.bootstrapUrl)));
84
+ }
85
+ for (const listener of listeners) listener(message);
86
+ };
87
+ worker.onerror = (event) => {
88
+ if (settled) {
89
+ const crash: ExecutionFaultMessage = {
90
+ kind: 'fault',
91
+ worldIdentity: null,
92
+ source: 'runtime',
93
+ code: 'worker-crashed',
94
+ expected: 'Engine Worker remains alive while the App is running',
95
+ hint: 'inspect the Worker error and create a new App; transferred canvas ownership is terminal',
96
+ detail: { message: event.message },
97
+ partialWrite: false,
98
+ retryable: false,
99
+ };
100
+ for (const listener of listeners) listener(crash);
101
+ return;
102
+ }
103
+ settled = true;
104
+ clearTimeout(timeout);
105
+ worker.terminate();
106
+ resolveReady(
107
+ err(
108
+ startupFault(
109
+ {
110
+ kind: 'fault',
111
+ worldIdentity: null,
112
+ source: 'bootstrap',
113
+ code: 'worker-error',
114
+ expected: 'Engine Worker module loads',
115
+ hint: 'inspect the Worker module graph',
116
+ detail: { message: event.message },
117
+ partialWrite: false,
118
+ retryable: false,
119
+ },
120
+ options.bootstrapUrl,
121
+ ),
122
+ ),
123
+ );
124
+ };
125
+
126
+ const offscreen = options.canvas.transferControlToOffscreen();
127
+ const init: ExecutionInitMessage = {
128
+ kind: 'init',
129
+ canvas: offscreen,
130
+ bootstrapUrl: options.bootstrapUrl,
131
+ ...(options.bootstrapData === undefined ? {} : { bootstrapData: options.bootstrapData }),
132
+ ...(options.bootstrapPort === undefined ? {} : { bootstrapPort: options.bootstrapPort }),
133
+ ...(options.shaderManifestUrl !== undefined
134
+ ? { shaderManifestUrl: options.shaderManifestUrl }
135
+ : {}),
136
+ ...(options.time !== undefined ? { time: options.time } : {}),
137
+ tier: options.tier,
138
+ };
139
+ worker.postMessage(init, [
140
+ offscreen,
141
+ ...(options.bootstrapPort === undefined ? [] : [options.bootstrapPort]),
142
+ ]);
143
+ const ready = await readyPromise;
144
+ if (!ready.ok) return ready;
145
+ return ok({
146
+ worker,
147
+ ready: ready.value,
148
+ post(message, transfer = []): void {
149
+ worker.postMessage(message, transfer);
150
+ },
151
+ listen(listener): () => void {
152
+ listeners.add(listener);
153
+ return () => listeners.delete(listener);
154
+ },
155
+ dispose(): void {
156
+ worker.postMessage({ kind: 'dispose' } satisfies HostToEngineMessage);
157
+ worker.terminate();
158
+ listeners.clear();
159
+ },
160
+ });
161
+ }
@@ -0,0 +1,454 @@
1
+ import { createHostAudioConsumer } from '@forgeax/engine-audio-webaudio';
2
+ import { attachBrowserInputBackend, type InputBackend } from '@forgeax/engine-input';
3
+ import { err, ok, type Result } from '@forgeax/engine-types';
4
+ import { APP_ERROR_HINTS, APP_EXPECTED, AppError, type AppError as AppErrorType } from '../errors';
5
+ import { ErrorFanoutRegistry } from '../internal/error-fanout';
6
+ import type { BundlerOptions, CanvasDrawingBufferSize } from '../types';
7
+ import {
8
+ APP_PHASE_CATALOG,
9
+ type AppDispatchError,
10
+ type CreateAppOptions,
11
+ type ExecutionApp,
12
+ } from '../types';
13
+ import { cloneExecutionReport } from './control';
14
+ import { type EngineWorkerSession, startEngineWorker } from './engine-worker';
15
+ import { createMeasurementSeries } from './measurement';
16
+ import {
17
+ type EngineToHostMessage,
18
+ type ExecutionFaultMessage,
19
+ FrameCreditLedger,
20
+ } from './protocol';
21
+ import { createExecutionReport, executionAudioReport } from './report';
22
+ import type {
23
+ ExecutionCapabilities,
24
+ ExecutionControl,
25
+ ExecutionReport,
26
+ ExecutionSelection,
27
+ } from './types';
28
+
29
+ export interface CreateWorkerExecutionAppOptions {
30
+ readonly canvas: HTMLCanvasElement;
31
+ readonly appOptions: CreateAppOptions;
32
+ /** Host-owned resize policy applied before each frame sent to the worker. */
33
+ readonly syncCanvas?: () => CanvasDrawingBufferSize;
34
+ readonly bundler?: BundlerOptions;
35
+ readonly capabilities: ExecutionCapabilities;
36
+ readonly selection: ExecutionSelection;
37
+ }
38
+
39
+ function lifecycleError(code: 'app-not-started' | 'app-already-running'): AppErrorType {
40
+ return new AppError({
41
+ code,
42
+ expected: APP_EXPECTED[code],
43
+ hint: APP_ERROR_HINTS[code],
44
+ detail: {},
45
+ });
46
+ }
47
+
48
+ function runtimeError(message: ExecutionFaultMessage): AppErrorType {
49
+ if (message.code === 'shared-kernel-failed' && message.worldIdentity !== null) {
50
+ return new AppError({
51
+ code: 'app-execution-kernel-failed',
52
+ expected: APP_EXPECTED['app-execution-kernel-failed'],
53
+ hint: APP_ERROR_HINTS['app-execution-kernel-failed'],
54
+ detail: {
55
+ kernelName: (message.detail as { kernelName?: string })?.kernelName ?? 'unknown',
56
+ worldIdentity: message.worldIdentity,
57
+ cause: message.detail,
58
+ partialWrite: true,
59
+ retryable: false,
60
+ },
61
+ });
62
+ }
63
+ return new AppError({
64
+ code: 'app-system-update-failed',
65
+ expected: APP_EXPECTED['app-system-update-failed'],
66
+ hint: APP_ERROR_HINTS['app-system-update-failed'],
67
+ detail: { cause: message.detail },
68
+ });
69
+ }
70
+
71
+ export async function createWorkerExecutionApp(
72
+ options: CreateWorkerExecutionAppOptions,
73
+ ): Promise<Result<ExecutionApp, AppErrorType>> {
74
+ const executionOptions = options.appOptions.execution;
75
+ if (executionOptions === undefined) throw new Error('execution options are required');
76
+ const syncCanvas = options.syncCanvas;
77
+ const bootstrapUrl = new URL(executionOptions.bootstrap, globalThis.location?.href).href;
78
+ const startupTimeoutMs = executionOptions.startupTimeoutMs ?? 10_000;
79
+ const frameTimeoutMs = executionOptions.frameTimeoutMs ?? 2_000;
80
+ const started = await startEngineWorker({
81
+ canvas: options.canvas,
82
+ bootstrapUrl,
83
+ ...(executionOptions.bootstrapData === undefined
84
+ ? {}
85
+ : { bootstrapData: executionOptions.bootstrapData }),
86
+ ...(executionOptions.bootstrapPort === undefined
87
+ ? {}
88
+ : { bootstrapPort: executionOptions.bootstrapPort }),
89
+ ...(options.bundler?.shaderManifestUrl !== undefined
90
+ ? { shaderManifestUrl: options.bundler.shaderManifestUrl }
91
+ : {}),
92
+ ...(options.appOptions.time !== undefined ? { time: options.appOptions.time } : {}),
93
+ timeoutMs: startupTimeoutMs,
94
+ tier: options.selection.actualTier,
95
+ });
96
+ if (!started.ok) return started;
97
+
98
+ const session: EngineWorkerSession = started.value;
99
+ const profiler = options.appOptions.profiler;
100
+ const phaseCatalogRegistration = profiler?.registerPhaseCatalog('app', APP_PHASE_CATALOG);
101
+ let releasePhaseCatalog =
102
+ phaseCatalogRegistration?.ok === true ? phaseCatalogRegistration.value : undefined;
103
+ const fanout = new ErrorFanoutRegistry(
104
+ options.appOptions.silenceUnhandledErrors === undefined
105
+ ? {}
106
+ : { silenceUnhandledErrors: options.appOptions.silenceUnhandledErrors },
107
+ );
108
+ const inputHandle =
109
+ options.appOptions.input === undefined
110
+ ? attachBrowserInputBackend(options.canvas, {
111
+ ...(options.appOptions.uiRoot !== undefined ? { uiRoot: options.appOptions.uiRoot } : {}),
112
+ ...(options.appOptions.pointerLockAllowed !== undefined
113
+ ? { pointerLockAllowed: options.appOptions.pointerLockAllowed }
114
+ : {}),
115
+ ...(options.appOptions.virtualJoysticks !== undefined
116
+ ? { virtualJoysticks: options.appOptions.virtualJoysticks }
117
+ : {}),
118
+ ...(options.appOptions.lockProvider !== undefined
119
+ ? { lockProvider: options.appOptions.lockProvider }
120
+ : {}),
121
+ onLockError: (detail) =>
122
+ fanout.fire(
123
+ new AppError({
124
+ code: 'app-pointer-lock-failed',
125
+ expected: APP_EXPECTED['app-pointer-lock-failed'],
126
+ hint: APP_ERROR_HINTS['app-pointer-lock-failed'],
127
+ detail,
128
+ }),
129
+ ),
130
+ })
131
+ : undefined;
132
+ const input: InputBackend = options.appOptions.input ??
133
+ inputHandle?.backend ?? {
134
+ sample: () => ({
135
+ downKeys: new Set(),
136
+ upKeys: new Set(),
137
+ buttons: [false, false, false],
138
+ movementX: 0,
139
+ movementY: 0,
140
+ wheelDelta: 0,
141
+ focused: true,
142
+ pointerLocked: false,
143
+ }),
144
+ detach: () => {},
145
+ };
146
+
147
+ let report: ExecutionReport = {
148
+ ...createExecutionReport(
149
+ executionOptions.tier ?? 'auto',
150
+ options.capabilities,
151
+ options.selection,
152
+ ),
153
+ engine: { realm: 'worker', health: 'idle' },
154
+ world: {
155
+ identity: session.ready.worldIdentity,
156
+ health: 'healthy',
157
+ partialWrite: false,
158
+ retryable: true,
159
+ },
160
+ };
161
+ let state: 'idle' | 'running' | 'paused' | 'stopped' | 'faulted' = 'idle';
162
+ let ledger = new FrameCreditLedger(session.ready.worldIdentity);
163
+ let rafId = 0;
164
+ let lastTimestamp = 0;
165
+ let frameDeadline: ReturnType<typeof setTimeout> | undefined;
166
+ let lastError: AppDispatchError | undefined;
167
+ let rebuildResolve: ((result: Result<ExecutionReport, AppErrorType>) => void) | undefined;
168
+ let rebuildInFlight: Promise<Result<ExecutionReport, AppErrorType>> | undefined;
169
+ const hostFrameMeasurements = createMeasurementSeries();
170
+ const engineMeasurements = createMeasurementSeries();
171
+ const kernelMeasurements = createMeasurementSeries();
172
+ const audioMeasurements = createMeasurementSeries();
173
+ let audio = createHostAudioConsumer();
174
+ let frameSentAt = 0;
175
+ let profilerCaptureId: string | undefined;
176
+ let profilerFrameId = 0;
177
+ let frameProfile = profiler?.activeSession();
178
+ let profileFrameOpen = false;
179
+ let hostFrameOpen = false;
180
+
181
+ const setEngineHealth = (health: ExecutionReport['engine']['health']): void => {
182
+ report = { ...report, engine: { ...report.engine, health } };
183
+ };
184
+
185
+ const finishProfile = (): void => {
186
+ if (hostFrameOpen) frameProfile?.endPhase();
187
+ if (profileFrameOpen) frameProfile?.endFrame();
188
+ frameProfile = undefined;
189
+ profileFrameOpen = false;
190
+ hostFrameOpen = false;
191
+ try {
192
+ profiler?.activeSession()?.finish();
193
+ } catch {}
194
+ releasePhaseCatalog?.();
195
+ releasePhaseCatalog = undefined;
196
+ };
197
+
198
+ const terminalFault = (message: ExecutionFaultMessage): void => {
199
+ if (frameDeadline !== undefined) {
200
+ clearTimeout(frameDeadline);
201
+ frameDeadline = undefined;
202
+ }
203
+ const error = runtimeError(message);
204
+ lastError = error;
205
+ state = message.partialWrite ? 'faulted' : 'stopped';
206
+ report = {
207
+ ...report,
208
+ engine: { ...report.engine, health: 'faulted' },
209
+ world: {
210
+ identity: message.worldIdentity,
211
+ health: message.partialWrite ? 'poisoned' : report.world.health,
212
+ partialWrite: message.partialWrite,
213
+ retryable: message.retryable,
214
+ },
215
+ kernelDispatch: {
216
+ ...report.kernelDispatch,
217
+ reason: message.partialWrite ? 'poisoned' : report.kernelDispatch.reason,
218
+ },
219
+ fault: {
220
+ source: message.source,
221
+ code: message.code,
222
+ expected: message.expected,
223
+ hint: message.hint,
224
+ detail: message.detail,
225
+ partialWrite: message.partialWrite,
226
+ retryable: message.retryable,
227
+ },
228
+ };
229
+ fanout.fire(error);
230
+ if (!message.partialWrite) {
231
+ audio.dispose();
232
+ session.dispose();
233
+ }
234
+ finishProfile();
235
+ };
236
+
237
+ const scheduleFrame = (): void => {
238
+ rafId = requestAnimationFrame((timestamp) => {
239
+ if (state !== 'running') return;
240
+ const deltaSeconds =
241
+ lastTimestamp === 0 ? 0 : Math.max(0, (timestamp - lastTimestamp) / 1_000);
242
+ lastTimestamp = timestamp;
243
+ const canvasSize =
244
+ syncCanvas?.() ??
245
+ ({
246
+ width: options.canvas.width,
247
+ height: options.canvas.height,
248
+ } satisfies CanvasDrawingBufferSize);
249
+ const frame = ledger.issue(deltaSeconds, () => input.sample(), canvasSize);
250
+ if (frame === undefined) return;
251
+ frameProfile = profiler?.activeSession();
252
+ if (frameProfile !== undefined && profilerCaptureId !== frameProfile.captureId) {
253
+ profilerCaptureId = frameProfile.captureId;
254
+ profilerFrameId = 0;
255
+ }
256
+ profileFrameOpen = frameProfile?.beginFrame(++profilerFrameId).ok ?? false;
257
+ hostFrameOpen = profileFrameOpen
258
+ ? (frameProfile?.beginPhase('app', 'host-frame').ok ?? false)
259
+ : false;
260
+ session.post(frame);
261
+ frameSentAt = performance.now();
262
+ frameDeadline = setTimeout(() => {
263
+ if (state !== 'running') return;
264
+ terminalFault({
265
+ kind: 'fault',
266
+ worldIdentity: report.world.identity,
267
+ source: 'runtime',
268
+ code: 'app-execution-deadline-exceeded',
269
+ expected: APP_EXPECTED['app-execution-deadline-exceeded'],
270
+ hint: APP_ERROR_HINTS['app-execution-deadline-exceeded'],
271
+ detail: { phase: 'frame', timeoutMs: frameTimeoutMs },
272
+ partialWrite: false,
273
+ retryable: false,
274
+ });
275
+ }, frameTimeoutMs);
276
+ });
277
+ };
278
+
279
+ session.listen((message: EngineToHostMessage) => {
280
+ if (message.kind === 'frame-complete') {
281
+ if (ledger.complete(message) !== 'accepted') return;
282
+ if (frameDeadline !== undefined) clearTimeout(frameDeadline);
283
+ if (hostFrameOpen) frameProfile?.endPhase();
284
+ if (profileFrameOpen) {
285
+ frameProfile?.recordSkip({
286
+ source: 'app',
287
+ phase: 'engine-update',
288
+ reason: `worker-report:${message.engineUpdateMs.toFixed(3)}ms`,
289
+ });
290
+ frameProfile?.recordSkip({
291
+ source: 'app',
292
+ phase: 'kernel-wait',
293
+ reason: `worker-report:${message.kernelWaitMs.toFixed(3)}ms`,
294
+ });
295
+ }
296
+ const audioStarted = performance.now();
297
+ const audioProfileOpen = profileFrameOpen
298
+ ? (frameProfile?.beginPhase('app', 'host-audio').ok ?? false)
299
+ : false;
300
+ for (const intent of message.audioIntents ?? []) audio.consume(intent);
301
+ if (audioProfileOpen) frameProfile?.endPhase();
302
+ const audioMs = performance.now() - audioStarted;
303
+ report = {
304
+ ...report,
305
+ performance: {
306
+ ...report.performance,
307
+ hostFrameMs: hostFrameMeasurements.add(performance.now() - frameSentAt),
308
+ engineUpdateMs: engineMeasurements.add(message.engineUpdateMs),
309
+ kernelWaitMs: kernelMeasurements.add(message.kernelWaitMs),
310
+ hostAudioMs: audioMeasurements.add(audioMs),
311
+ },
312
+ };
313
+ if (message.kernelDispatch !== undefined) {
314
+ report = { ...report, kernelDispatch: message.kernelDispatch };
315
+ }
316
+ if (profileFrameOpen) frameProfile?.endFrame();
317
+ frameProfile = undefined;
318
+ profileFrameOpen = false;
319
+ hostFrameOpen = false;
320
+ if (state === 'running') scheduleFrame();
321
+ } else if (message.kind === 'fault') {
322
+ terminalFault(message);
323
+ } else if (message.kind === 'rebuilt') {
324
+ audio.dispose();
325
+ audio = createHostAudioConsumer();
326
+ ledger = new FrameCreditLedger(message.worldIdentity);
327
+ hostFrameMeasurements.clear();
328
+ engineMeasurements.clear();
329
+ kernelMeasurements.clear();
330
+ audioMeasurements.clear();
331
+ state = 'idle';
332
+ report = {
333
+ ...report,
334
+ engine: { ...report.engine, health: 'idle' },
335
+ world: {
336
+ identity: message.worldIdentity,
337
+ health: 'healthy',
338
+ partialWrite: false,
339
+ retryable: true,
340
+ },
341
+ kernelDispatch: {
342
+ eligible: false,
343
+ usedShared: false,
344
+ reason: 'no-eligible-kernel',
345
+ dispatched: 0,
346
+ completed: 0,
347
+ },
348
+ fault: null,
349
+ performance: {
350
+ hostFrameMs: null,
351
+ engineUpdateMs: null,
352
+ kernelWaitMs: null,
353
+ hostAudioMs: null,
354
+ },
355
+ };
356
+ rebuildResolve?.(ok(cloneExecutionReport(report)));
357
+ rebuildResolve = undefined;
358
+ rebuildInFlight = undefined;
359
+ } else if (message.kind === 'host-control') {
360
+ if (message.command === 'set-pointer-lock-allowed') {
361
+ input.setPointerLockAllowed?.(message.allowed);
362
+ }
363
+ }
364
+ });
365
+
366
+ const execution: ExecutionControl = {
367
+ report: () =>
368
+ cloneExecutionReport({
369
+ ...report,
370
+ audio: executionAudioReport(audio.state()),
371
+ }),
372
+ rebuild: () => {
373
+ if (rebuildInFlight !== undefined) return rebuildInFlight;
374
+ if (state !== 'faulted' || report.world.identity === null) {
375
+ return Promise.resolve(
376
+ err(
377
+ new AppError({
378
+ code: 'app-execution-rebuild-failed',
379
+ expected: APP_EXPECTED['app-execution-rebuild-failed'],
380
+ hint: APP_ERROR_HINTS['app-execution-rebuild-failed'],
381
+ detail: {
382
+ worldIdentity: report.world.identity,
383
+ cause: new Error('World is not in a rebuildable poisoned state.'),
384
+ },
385
+ }),
386
+ ),
387
+ );
388
+ }
389
+ rebuildInFlight = new Promise((resolve) => {
390
+ rebuildResolve = resolve;
391
+ session.post({ kind: 'rebuild', worldIdentity: report.world.identity as string });
392
+ setTimeout(() => {
393
+ if (rebuildResolve !== resolve) return;
394
+ rebuildResolve = undefined;
395
+ rebuildInFlight = undefined;
396
+ resolve(
397
+ err(
398
+ new AppError({
399
+ code: 'app-execution-deadline-exceeded',
400
+ expected: APP_EXPECTED['app-execution-deadline-exceeded'],
401
+ hint: APP_ERROR_HINTS['app-execution-deadline-exceeded'],
402
+ detail: { phase: 'handshake', timeoutMs: startupTimeoutMs },
403
+ }),
404
+ ),
405
+ );
406
+ }, startupTimeoutMs);
407
+ });
408
+ return rebuildInFlight;
409
+ },
410
+ };
411
+
412
+ const app: ExecutionApp = {
413
+ execution,
414
+ input,
415
+ start: () => {
416
+ if (state === 'running') return err(lifecycleError('app-already-running'));
417
+ if (state === 'stopped' || state === 'faulted') return err(lifecycleError('app-not-started'));
418
+ state = 'running';
419
+ setEngineHealth('running');
420
+ lastTimestamp = 0;
421
+ scheduleFrame();
422
+ return ok(undefined);
423
+ },
424
+ stop: () => {
425
+ if (state !== 'running' && state !== 'paused') return err(lifecycleError('app-not-started'));
426
+ if (state === 'running') cancelAnimationFrame(rafId);
427
+ state = 'stopped';
428
+ inputHandle?.();
429
+ audio.dispose();
430
+ session.dispose();
431
+ setEngineHealth('stopped');
432
+ finishProfile();
433
+ return ok(undefined);
434
+ },
435
+ pause: () => {
436
+ if (state !== 'running') return err(lifecycleError('app-not-started'));
437
+ state = 'paused';
438
+ cancelAnimationFrame(rafId);
439
+ return ok(undefined);
440
+ },
441
+ resume: () => {
442
+ if (state !== 'paused') return err(lifecycleError('app-not-started'));
443
+ state = 'running';
444
+ lastTimestamp = 0;
445
+ scheduleFrame();
446
+ return ok(undefined);
447
+ },
448
+ onError: (listener) => fanout.add(listener),
449
+ get lastError() {
450
+ return lastError;
451
+ },
452
+ };
453
+ return ok(app);
454
+ }
@@ -0,0 +1,43 @@
1
+ export type {
2
+ ExecutionBootstrapEntry,
3
+ ExecutionBootstrapHost,
4
+ PreparedExecutionBootstrap,
5
+ } from './bootstrap-entry';
6
+ export {
7
+ executionBootstrapHostPlugin,
8
+ loadBootstrapEntry,
9
+ prepareBootstrapEntry,
10
+ validateExecutionBootstrapData,
11
+ } from './bootstrap-entry';
12
+ export {
13
+ missingExecutionCapabilities,
14
+ probeExecutionCapabilities,
15
+ unavailableExecutionCapabilities,
16
+ } from './capabilities';
17
+ export { cloneExecutionReport } from './control';
18
+ export { createExecutionReport } from './report';
19
+ export { EXECUTION_REPORT_SCHEMA_VERSION, isExecutionReport } from './schema';
20
+ export { type ExecutionSelectionInput, selectExecutionTier } from './selector';
21
+ export type {
22
+ ExecutionBootstrapValue,
23
+ ExecutionCapabilities,
24
+ ExecutionCapabilityFact,
25
+ ExecutionCapabilityName,
26
+ ExecutionControl,
27
+ ExecutionEngineHealth,
28
+ ExecutionFault,
29
+ ExecutionMeasurement,
30
+ ExecutionOptions,
31
+ ExecutionReport,
32
+ ExecutionRequestedTier,
33
+ ExecutionSelection,
34
+ ExecutionSelectionReason,
35
+ ExecutionTier,
36
+ ExecutionWorldHealth,
37
+ KernelDispatchReason,
38
+ } from './types';
39
+ export {
40
+ EXECUTION_CAPABILITY_NAMES,
41
+ EXECUTION_REQUESTED_TIERS,
42
+ EXECUTION_TIERS,
43
+ } from './types';