@downdraft/engine 0.0.0 → 0.1.1

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 (908) hide show
  1. package/README.md +33 -0
  2. package/app/src/index.ts +10 -0
  3. package/app/src/renderer/bootstrap.ts +271 -0
  4. package/app/src/renderer/downdraft-base.css +93 -0
  5. package/app/src/renderer/feature-log.ts +200 -0
  6. package/app/src/renderer/game-module.ts +923 -0
  7. package/app/src/renderer/hooks.ts +88 -0
  8. package/app/src/renderer/hot-reload.ts +178 -0
  9. package/app/src/renderer/import-cache.ts +88 -0
  10. package/app/src/renderer/index.ts +206 -0
  11. package/app/src/renderer/mcp-harness.ts +144 -0
  12. package/app/src/renderer/save-store-factory.ts +239 -0
  13. package/app/src/renderer/sim-bridge.ts +183 -0
  14. package/app/src/renderer/standard-automation-tools.ts +771 -0
  15. package/app/src/shared/feature-log.ts +71 -0
  16. package/app/src/shared/gpu-info.ts +82 -0
  17. package/app/src/shared/import-cache-store.ts +142 -0
  18. package/app/src/shared/index.ts +6 -0
  19. package/app/src/shared/mcp-discovery.ts +47 -0
  20. package/app/src/shared/mcp-proxy.ts +82 -0
  21. package/app/src/shared/types.ts +324 -0
  22. package/asset-bake/src/bake-audio.ts +119 -0
  23. package/asset-bake/src/bake-gltf.ts +172 -0
  24. package/asset-bake/src/bake.ts +78 -0
  25. package/asset-bake/src/cache.ts +188 -0
  26. package/asset-bake/src/config.ts +186 -0
  27. package/asset-bake/src/index.ts +36 -0
  28. package/core/src/animation/animation-event.ts +41 -0
  29. package/core/src/animation/bone-mask.ts +122 -0
  30. package/core/src/animation/clip.ts +252 -0
  31. package/core/src/animation/index.ts +22 -0
  32. package/core/src/animation/mixamo.ts +113 -0
  33. package/core/src/animation/morph-target.ts +69 -0
  34. package/core/src/animation/player.ts +697 -0
  35. package/core/src/animation/retarget.ts +158 -0
  36. package/core/src/animation/skeleton-animator.ts +1399 -0
  37. package/core/src/animation/skeleton.ts +214 -0
  38. package/core/src/animation/state-machine.ts +280 -0
  39. package/core/src/assets/blob-store.ts +66 -0
  40. package/core/src/assets/cache.ts +186 -0
  41. package/core/src/assets/cubemap-converter.ts +155 -0
  42. package/core/src/assets/environment-manager.ts +121 -0
  43. package/core/src/assets/import-cache.ts +65 -0
  44. package/core/src/assets/import-settings.ts +72 -0
  45. package/core/src/assets/importer.ts +108 -0
  46. package/core/src/assets/index.ts +74 -0
  47. package/core/src/assets/irradiance-generator.ts +198 -0
  48. package/core/src/assets/loader-audio.ts +86 -0
  49. package/core/src/assets/loader-cubemap.ts +211 -0
  50. package/core/src/assets/loader-dds.ts +236 -0
  51. package/core/src/assets/loader-hdr.ts +474 -0
  52. package/core/src/assets/loader-mesh.ts +143 -0
  53. package/core/src/assets/loader-shader.ts +73 -0
  54. package/core/src/assets/loader-texture.ts +349 -0
  55. package/core/src/assets/lod.ts +198 -0
  56. package/core/src/assets/manager.ts +480 -0
  57. package/core/src/assets/manifest.ts +81 -0
  58. package/core/src/assets/material-bridge.ts +186 -0
  59. package/core/src/assets/model-importer.ts +72 -0
  60. package/core/src/assets/model-normalizer.ts +248 -0
  61. package/core/src/assets/model-to-gpu.ts +70 -0
  62. package/core/src/assets/model-to-mesh.ts +237 -0
  63. package/core/src/assets/prefilter-generator.ts +250 -0
  64. package/core/src/audio/engine.ts +177 -0
  65. package/core/src/audio/interface.ts +130 -0
  66. package/core/src/audio/listener.ts +32 -0
  67. package/core/src/audio/mixer.ts +141 -0
  68. package/core/src/audio/registry.ts +52 -0
  69. package/core/src/audio/sab.ts +87 -0
  70. package/core/src/audio/source.ts +89 -0
  71. package/core/src/change-detection/atomics.ts +1 -0
  72. package/core/src/change-detection/tracker.ts +47 -0
  73. package/core/src/debug-draw/lines.ts +64 -0
  74. package/core/src/debug-draw/points.ts +17 -0
  75. package/core/src/debug-draw/queue.ts +124 -0
  76. package/core/src/debug-draw/text.ts +25 -0
  77. package/core/src/ecs/archetype.ts +323 -0
  78. package/core/src/ecs/component.ts +188 -0
  79. package/core/src/ecs/entity.ts +25 -0
  80. package/core/src/ecs/events.ts +93 -0
  81. package/core/src/ecs/hierarchy.ts +124 -0
  82. package/core/src/ecs/hmr-swap-registry.ts +22 -0
  83. package/core/src/ecs/index.ts +25 -0
  84. package/core/src/ecs/query.ts +141 -0
  85. package/core/src/ecs/resource.ts +8 -0
  86. package/core/src/ecs/schedule.ts +181 -0
  87. package/core/src/ecs/system-params.ts +99 -0
  88. package/core/src/ecs/system.ts +42 -0
  89. package/core/src/ecs/world.ts +348 -0
  90. package/core/src/index.ts +352 -0
  91. package/core/src/input/context.ts +73 -0
  92. package/core/src/input/dom-handler.ts +380 -0
  93. package/core/src/input/local-player-manager.ts +218 -0
  94. package/core/src/input/mapping.ts +40 -0
  95. package/core/src/input/multi-sab-bridge.ts +276 -0
  96. package/core/src/input/multi-state.ts +54 -0
  97. package/core/src/input/sab-bridge.ts +71 -0
  98. package/core/src/input/state.ts +132 -0
  99. package/core/src/input/ui-router.ts +87 -0
  100. package/core/src/library/host.ts +317 -0
  101. package/core/src/library/index.ts +16 -0
  102. package/core/src/library/library.ts +292 -0
  103. package/core/src/material/compiler.ts +80 -0
  104. package/core/src/material/graph-bridge.ts +172 -0
  105. package/core/src/material/index.ts +9 -0
  106. package/core/src/material/library.ts +442 -0
  107. package/core/src/material/material.ts +156 -0
  108. package/core/src/material/variants.ts +61 -0
  109. package/core/src/math/mat4.ts +202 -0
  110. package/core/src/math/perlin-noise-2d.ts +77 -0
  111. package/core/src/math/perlin-noise-3d.ts +110 -0
  112. package/core/src/math/quat.ts +33 -0
  113. package/core/src/math/rng.ts +29 -0
  114. package/core/src/math/trig.ts +47 -0
  115. package/core/src/math/value-noise.ts +67 -0
  116. package/core/src/mesh/builder.ts +177 -0
  117. package/core/src/mesh/csg.ts +312 -0
  118. package/core/src/mesh/greased-line.ts +145 -0
  119. package/core/src/mesh/mesh.ts +17 -0
  120. package/core/src/mesh/parametric.ts +501 -0
  121. package/core/src/mesh/skinning.ts +67 -0
  122. package/core/src/mesh/vertex-layout.ts +91 -0
  123. package/core/src/module/cross-thread.ts +163 -0
  124. package/core/src/module/diagnostics.ts +123 -0
  125. package/core/src/module/host.ts +451 -0
  126. package/core/src/module/index.ts +22 -0
  127. package/core/src/module/module.ts +109 -0
  128. package/core/src/module/registry.ts +94 -0
  129. package/core/src/module/renderer-module.ts +247 -0
  130. package/core/src/module/ts-loader.ts +26 -0
  131. package/core/src/particles/compute-pass.ts +378 -0
  132. package/core/src/particles/emitter.ts +156 -0
  133. package/core/src/particles/index.ts +11 -0
  134. package/core/src/particles/particle-data.ts +47 -0
  135. package/core/src/particles/render-pass.ts +365 -0
  136. package/core/src/particles/simulator.ts +264 -0
  137. package/core/src/particles/system.ts +193 -0
  138. package/core/src/physics/body.ts +59 -0
  139. package/core/src/physics/ccd-heuristic.ts +55 -0
  140. package/core/src/physics/character.ts +282 -0
  141. package/core/src/physics/collider.ts +55 -0
  142. package/core/src/physics/collision-system.ts +91 -0
  143. package/core/src/physics/events.ts +133 -0
  144. package/core/src/physics/index.ts +34 -0
  145. package/core/src/physics/interface.ts +473 -0
  146. package/core/src/physics/interpolation-buffer.ts +192 -0
  147. package/core/src/physics/lifecycle.ts +87 -0
  148. package/core/src/physics/load-shedder.ts +164 -0
  149. package/core/src/physics/physics-accumulator.ts +101 -0
  150. package/core/src/physics/physics-system.ts +240 -0
  151. package/core/src/physics/ragdoll-presets.ts +272 -0
  152. package/core/src/physics/ragdoll-system.ts +220 -0
  153. package/core/src/physics/ragdoll.ts +182 -0
  154. package/core/src/physics/raycast.ts +143 -0
  155. package/core/src/physics/realm-manager.ts +499 -0
  156. package/core/src/physics/realm-worker-pool.ts +191 -0
  157. package/core/src/physics/realm-worker.ts +102 -0
  158. package/core/src/physics/realm.ts +189 -0
  159. package/core/src/physics/registry.ts +52 -0
  160. package/core/src/physics/safety.ts +247 -0
  161. package/core/src/physics/snapshot-manager.ts +141 -0
  162. package/core/src/physics/worker-protocol.ts +30 -0
  163. package/core/src/platform/bun-preload.ts +169 -0
  164. package/core/src/platform/css-stub.ts +4 -0
  165. package/core/src/platform/glob-polyfill.ts +124 -0
  166. package/core/src/platform/hidpi.ts +57 -0
  167. package/core/src/platform/render-surface.ts +77 -0
  168. package/core/src/platform/rpc.ts +98 -0
  169. package/core/src/platform/runtime.ts +132 -0
  170. package/core/src/plugin/context.ts +364 -0
  171. package/core/src/plugin/diagnostics.ts +61 -0
  172. package/core/src/plugin/discovery.ts +186 -0
  173. package/core/src/plugin/extension-loaders.ts +172 -0
  174. package/core/src/plugin/host.ts +659 -0
  175. package/core/src/plugin/index.ts +106 -0
  176. package/core/src/plugin/loader-asset.ts +124 -0
  177. package/core/src/plugin/loader-quickjs.ts +84 -0
  178. package/core/src/plugin/loader-wasm.ts +411 -0
  179. package/core/src/plugin/loader-worker.ts +261 -0
  180. package/core/src/plugin/manifest.ts +653 -0
  181. package/core/src/plugin/material-registry.ts +65 -0
  182. package/core/src/plugin/mcp-tools.ts +165 -0
  183. package/core/src/plugin/permissions.ts +175 -0
  184. package/core/src/plugin/quickjs-bridge.ts +294 -0
  185. package/core/src/plugin/registry.ts +107 -0
  186. package/core/src/plugin/sandbox-shim.ts +86 -0
  187. package/core/src/plugin/sandbox-worker.ts +215 -0
  188. package/core/src/plugin/wasm-abi.ts +152 -0
  189. package/core/src/plugin/wasm-worker.ts +229 -0
  190. package/core/src/plugin/workshop.ts +169 -0
  191. package/core/src/profiling/event-loop.ts +180 -0
  192. package/core/src/profiling/index.ts +69 -0
  193. package/core/src/profiling/iops/idb-patch.ts +242 -0
  194. package/core/src/profiling/iops/opfs-patch.ts +276 -0
  195. package/core/src/profiling/profiling-sab.ts +839 -0
  196. package/core/src/profiling/task-latency.ts +134 -0
  197. package/core/src/profiling/thread-metrics.ts +126 -0
  198. package/core/src/profiling/trace-event-writer.ts +205 -0
  199. package/core/src/profiling/warnings.ts +423 -0
  200. package/core/src/profiling/worker-prelude.ts +376 -0
  201. package/core/src/render/bind-group.ts +38 -0
  202. package/core/src/render/bindless/bindless-struct.ts +42 -0
  203. package/core/src/render/bindless/bindless.wgsl.ts +167 -0
  204. package/core/src/render/bindless/frame-bindings.ts +176 -0
  205. package/core/src/render/bindless/index.ts +10 -0
  206. package/core/src/render/bindless/material-manager.ts +257 -0
  207. package/core/src/render/bindless/texture-registry.ts +609 -0
  208. package/core/src/render/buffer.ts +82 -0
  209. package/core/src/render/camera-2d.ts +217 -0
  210. package/core/src/render/camera-controller.ts +440 -0
  211. package/core/src/render/camera.ts +409 -0
  212. package/core/src/render/canvas-resize-watcher.ts +46 -0
  213. package/core/src/render/compute-kernel.ts +172 -0
  214. package/core/src/render/constants.ts +2 -0
  215. package/core/src/render/device.ts +111 -0
  216. package/core/src/render/frame-graph.ts +768 -0
  217. package/core/src/render/frustum.ts +185 -0
  218. package/core/src/render/fullscreen-vs.ts +25 -0
  219. package/core/src/render/g-buffer.ts +186 -0
  220. package/core/src/render/game-renderer.ts +1452 -0
  221. package/core/src/render/gpu-driven/cull-pass.ts +394 -0
  222. package/core/src/render/gpu-driven/hzb.ts +215 -0
  223. package/core/src/render/gpu-driven/index.ts +7 -0
  224. package/core/src/render/gpu-driven/indirect-draw-pass.ts +324 -0
  225. package/core/src/render/gpu-driven/instance-buffer.ts +178 -0
  226. package/core/src/render/gpu-driven/mesh-table.ts +175 -0
  227. package/core/src/render/gpu-driven/passes/hzb-build-pass.ts +47 -0
  228. package/core/src/render/gpu-utils.ts +96 -0
  229. package/core/src/render/hdr.ts +88 -0
  230. package/core/src/render/hot-reload.ts +295 -0
  231. package/core/src/render/ibl-bind-group.ts +266 -0
  232. package/core/src/render/ibl.ts +180 -0
  233. package/core/src/render/index.ts +163 -0
  234. package/core/src/render/input-manager.ts +259 -0
  235. package/core/src/render/lighting/area-light.ts +196 -0
  236. package/core/src/render/lighting/cluster-grid.ts +288 -0
  237. package/core/src/render/lighting/cluster-types.ts +193 -0
  238. package/core/src/render/lighting/ies-parser.ts +162 -0
  239. package/core/src/render/lighting.ts +454 -0
  240. package/core/src/render/material-types/depth.wgsl +44 -0
  241. package/core/src/render/material-types/line.wgsl +50 -0
  242. package/core/src/render/material-types/matcap.wgsl +51 -0
  243. package/core/src/render/material-types/normal.wgsl +41 -0
  244. package/core/src/render/material-types/physical.wgsl +152 -0
  245. package/core/src/render/material-types/sprite.wgsl +46 -0
  246. package/core/src/render/material-types/sss.wgsl +79 -0
  247. package/core/src/render/material-types/toon.wgsl +79 -0
  248. package/core/src/render/passes/README.md +121 -0
  249. package/core/src/render/passes/atmosphere.ts +152 -0
  250. package/core/src/render/passes/cluster-lighting-pass.ts +476 -0
  251. package/core/src/render/passes/csm.ts +408 -0
  252. package/core/src/render/passes/cubemap-capture.ts +114 -0
  253. package/core/src/render/passes/debug-viz.ts +278 -0
  254. package/core/src/render/passes/debug.ts +538 -0
  255. package/core/src/render/passes/decal-mesh.ts +111 -0
  256. package/core/src/render/passes/decal-pass.ts +377 -0
  257. package/core/src/render/passes/deferred-lighting.ts +434 -0
  258. package/core/src/render/passes/depth-prepass.ts +163 -0
  259. package/core/src/render/passes/dome-360.ts +83 -0
  260. package/core/src/render/passes/fluid-render.ts +137 -0
  261. package/core/src/render/passes/gi-types.ts +118 -0
  262. package/core/src/render/passes/graph-compute.ts +300 -0
  263. package/core/src/render/passes/greased-line-pass.ts +232 -0
  264. package/core/src/render/passes/morph-target.ts +40 -0
  265. package/core/src/render/passes/opaque.ts +1028 -0
  266. package/core/src/render/passes/point-light-shadow.ts +266 -0
  267. package/core/src/render/passes/procedural-texture.ts +185 -0
  268. package/core/src/render/passes/reflection-probe.ts +140 -0
  269. package/core/src/render/passes/rsm-pass.ts +248 -0
  270. package/core/src/render/passes/sdf-text.ts +155 -0
  271. package/core/src/render/passes/shadow-map.ts +163 -0
  272. package/core/src/render/passes/shadow.ts +220 -0
  273. package/core/src/render/passes/skinning-vs.ts +121 -0
  274. package/core/src/render/passes/skinning.ts +326 -0
  275. package/core/src/render/passes/sky-dome.ts +404 -0
  276. package/core/src/render/passes/skybox.ts +162 -0
  277. package/core/src/render/passes/spot-light-shadow.ts +273 -0
  278. package/core/src/render/passes/terrain.ts +326 -0
  279. package/core/src/render/passes/transparent.ts +353 -0
  280. package/core/src/render/passes/underwater-fog.ts +185 -0
  281. package/core/src/render/passes/video-texture.ts +79 -0
  282. package/core/src/render/passes/volumetric-pass.ts +312 -0
  283. package/core/src/render/passes/volumetric-types.ts +171 -0
  284. package/core/src/render/passes/water.ts +753 -0
  285. package/core/src/render/pbr.ts +296 -0
  286. package/core/src/render/pipeline.ts +52 -0
  287. package/core/src/render/render-pass.ts +30 -0
  288. package/core/src/render/renderer-input-bus.ts +220 -0
  289. package/core/src/render/renderer-module-host.ts +623 -0
  290. package/core/src/render/resource-tracker.ts +67 -0
  291. package/core/src/render/sab-canvas-overlay.ts +122 -0
  292. package/core/src/render/shader-validator.ts +200 -0
  293. package/core/src/render/shaders/debug/debug-line.wgsl +27 -0
  294. package/core/src/render/shaders/debug/debug-point.wgsl +30 -0
  295. package/core/src/render/shaders/debug/debug-text.wgsl +42 -0
  296. package/core/src/render/shaders/debug-viz/aabb.wgsl +20 -0
  297. package/core/src/render/shaders/debug-viz/depth.wgsl +29 -0
  298. package/core/src/render/shaders/debug-viz/lod.wgsl +38 -0
  299. package/core/src/render/shaders/debug-viz/normals.wgsl +30 -0
  300. package/core/src/render/shaders/debug-viz/overdraw.wgsl +21 -0
  301. package/core/src/render/shaders/debug-viz/tangents.wgsl +29 -0
  302. package/core/src/render/shaders/debug-viz/wireframe.wgsl +33 -0
  303. package/core/src/render/shaders/shadow-chunks.ts +135 -0
  304. package/core/src/render/skybox.ts +146 -0
  305. package/core/src/render/splitscreen.ts +85 -0
  306. package/core/src/render/surface.ts +78 -0
  307. package/core/src/render/tonemap.ts +180 -0
  308. package/core/src/render/tracked-render-pass.ts +158 -0
  309. package/core/src/render/viewport.ts +109 -0
  310. package/core/src/render/wgsl-hmr.ts +70 -0
  311. package/core/src/sab/core-input-channel.ts +23 -0
  312. package/core/src/sab/define.ts +239 -0
  313. package/core/src/sab/errors.ts +76 -0
  314. package/core/src/sab/game-input.ts +343 -0
  315. package/core/src/sab/gamepad-devices.ts +259 -0
  316. package/core/src/sab/grid-buffer.ts +117 -0
  317. package/core/src/sab/input.ts +55 -0
  318. package/core/src/sab/layout.ts +219 -0
  319. package/core/src/sab/multi-input-channel.ts +50 -0
  320. package/core/src/sab/record-buffer.ts +155 -0
  321. package/core/src/sab/sab-polyfill.ts +56 -0
  322. package/core/src/sab/sim-channel.ts +453 -0
  323. package/core/src/sab/slot-buffer.ts +190 -0
  324. package/core/src/sab/types.ts +158 -0
  325. package/core/src/safety/bounds.ts +76 -0
  326. package/core/src/safety/json.ts +80 -0
  327. package/core/src/safety/path.ts +167 -0
  328. package/core/src/save/binary-format.ts +117 -0
  329. package/core/src/save/game-save-system.ts +161 -0
  330. package/core/src/save/grid-save-system.ts +158 -0
  331. package/core/src/save/migrate.ts +44 -0
  332. package/core/src/save/migration-registry.ts +94 -0
  333. package/core/src/save/persist-types.ts +208 -0
  334. package/core/src/save/schema.ts +46 -0
  335. package/core/src/save/serializer.ts +180 -0
  336. package/core/src/scene/builder.ts +65 -0
  337. package/core/src/scene/camera.ts +142 -0
  338. package/core/src/scene/checkpoint.ts +109 -0
  339. package/core/src/scene/game-loop.ts +198 -0
  340. package/core/src/scene/index.ts +24 -0
  341. package/core/src/scene/layer.ts +6 -0
  342. package/core/src/scene/prefab.ts +145 -0
  343. package/core/src/scene/scene-manager.ts +157 -0
  344. package/core/src/scene/scene.ts +192 -0
  345. package/core/src/scene/sky.ts +256 -0
  346. package/core/src/scene/spatial-grid.ts +176 -0
  347. package/core/src/scene/streaming.ts +304 -0
  348. package/core/src/scene/vegetation.ts +163 -0
  349. package/core/src/scene/world.ts +89 -0
  350. package/core/src/scripting/binding.ts +129 -0
  351. package/core/src/scripting/hot-reload.ts +144 -0
  352. package/core/src/scripting/script.ts +99 -0
  353. package/core/src/sim/hot-reload-pipeline.ts +49 -0
  354. package/core/src/sim/sim-state-helper.ts +47 -0
  355. package/core/src/sim/transient-state-registry.ts +77 -0
  356. package/core/src/sim/types.ts +113 -0
  357. package/core/src/sim/worker-loop.ts +222 -0
  358. package/core/src/stores/game-store.ts +158 -0
  359. package/core/src/stores/hot-reload-store.ts +44 -0
  360. package/core/src/telemetry/collector.ts +410 -0
  361. package/core/src/telemetry/gc-controller.ts +453 -0
  362. package/core/src/telemetry/gc-profiler.ts +126 -0
  363. package/core/src/telemetry/gc-tracker.ts +69 -0
  364. package/core/src/telemetry/gpu-profiler.ts +703 -0
  365. package/core/src/telemetry/gpu-resource-tracker.ts +285 -0
  366. package/core/src/telemetry/gpu-timer-pool.ts +234 -0
  367. package/core/src/telemetry/gpu-timer.ts +123 -0
  368. package/core/src/telemetry/gpu-timestamp-gate.ts +21 -0
  369. package/core/src/telemetry/reporter.ts +62 -0
  370. package/core/src/types/engine-types.ts +129 -0
  371. package/core/src/ui-font-scale.ts +112 -0
  372. package/core/src/util/broad-phase-grid.ts +82 -0
  373. package/core/src/util/feature-log.ts +220 -0
  374. package/core/src/util/index.ts +17 -0
  375. package/core/src/util/logger.ts +604 -0
  376. package/core/src/webgpu-destroy-augmentation.d.ts +25 -0
  377. package/core/src/worker/base-worker-host.ts +183 -0
  378. package/core/src/worker/buffer-sync.ts +550 -0
  379. package/core/src/worker/crash-recovery.ts +201 -0
  380. package/core/src/worker/entity-sim-worker-host.ts +190 -0
  381. package/core/src/worker/instrumented-worker-host.ts +171 -0
  382. package/core/src/worker/rpc.ts +253 -0
  383. package/core/src/worker/sim-worker-base.ts +913 -0
  384. package/core/src/worker/sim-worker-host.ts +358 -0
  385. package/core/src/worker/task-pool.ts +256 -0
  386. package/core/src/worker/task-worker.ts +83 -0
  387. package/libraries/asset-browser/src/index.ts +11 -0
  388. package/libraries/asset-browser/src/software-thumbnails.ts +949 -0
  389. package/libraries/audio-kira/README.md +17 -0
  390. package/libraries/audio-kira/native/Cargo.toml +14 -0
  391. package/libraries/audio-kira/native/src/engine.rs +27 -0
  392. package/libraries/audio-kira/native/src/lib.rs +185 -0
  393. package/libraries/audio-kira/native/src/mixer.rs +11 -0
  394. package/libraries/audio-kira/native/src/source.rs +80 -0
  395. package/libraries/audio-kira/src/backend.ts +469 -0
  396. package/libraries/audio-kira/src/index.ts +8 -0
  397. package/libraries/audio-kira/src/library.ts +82 -0
  398. package/libraries/blitz-ui/native/Cargo.toml +33 -0
  399. package/libraries/blitz-ui/native/assets/DejaVuSans.woff2 +0 -0
  400. package/libraries/blitz-ui/native/src/bridge.rs +100 -0
  401. package/libraries/blitz-ui/native/src/fonts.rs +20 -0
  402. package/libraries/blitz-ui/native/src/input.rs +80 -0
  403. package/libraries/blitz-ui/native/src/lib.rs +96 -0
  404. package/libraries/blitz-ui/native/src/shell.rs +301 -0
  405. package/libraries/blitz-ui/native-osr/Cargo.toml +24 -0
  406. package/libraries/blitz-ui/native-osr/src/events.rs +237 -0
  407. package/libraries/blitz-ui/native-osr/src/lib.rs +846 -0
  408. package/libraries/blitz-ui/native-osr/src/mutate.rs +385 -0
  409. package/libraries/blitz-ui/native-osr/src/resources.rs +45 -0
  410. package/libraries/blitz-ui/native-osr-spike.ts +70 -0
  411. package/libraries/blitz-ui/src/index.ts +15 -0
  412. package/libraries/blitz-ui/src/native-module.ts +221 -0
  413. package/libraries/blitz-ui/src/native-osr-ffi.ts +423 -0
  414. package/libraries/blitz-ui/src/router.ts +101 -0
  415. package/libraries/blitz-ui/src/shaders/ui-blit.wgsl.ts +35 -0
  416. package/libraries/blitz-ui/src/ui-blit-pass.ts +116 -0
  417. package/libraries/character/README.md +25 -0
  418. package/libraries/character/src/character-animator.ts +374 -0
  419. package/libraries/character/src/index.ts +24 -0
  420. package/libraries/character/src/loader.ts +375 -0
  421. package/libraries/character/src/locomotion.ts +124 -0
  422. package/libraries/character/src/preview.ts +287 -0
  423. package/libraries/devtools/README.md +51 -0
  424. package/libraries/devtools/native/Cargo.toml +12 -0
  425. package/libraries/devtools/native/src/lib.rs +1646 -0
  426. package/libraries/devtools/native/src/panels/console.rs +338 -0
  427. package/libraries/devtools/native/src/panels/dom_tree.rs +47 -0
  428. package/libraries/devtools/native/src/panels/generic.rs +317 -0
  429. package/libraries/devtools/native/src/panels/gpu.rs +107 -0
  430. package/libraries/devtools/native/src/panels/input.rs +88 -0
  431. package/libraries/devtools/native/src/panels/mod.rs +154 -0
  432. package/libraries/devtools/native/src/panels/perf_metrics.rs +91 -0
  433. package/libraries/devtools/native/src/panels/perf_recorder.rs +158 -0
  434. package/libraries/devtools/native/src/panels/scene.rs +72 -0
  435. package/libraries/devtools/native/src/state.rs +394 -0
  436. package/libraries/devtools/src/cdp-bridge.ts +349 -0
  437. package/libraries/devtools/src/collectors.ts +346 -0
  438. package/libraries/devtools/src/egui-ffi.ts +804 -0
  439. package/libraries/devtools/src/egui-renderer.ts +407 -0
  440. package/libraries/devtools/src/host.ts +363 -0
  441. package/libraries/devtools/src/index.ts +40 -0
  442. package/libraries/devtools/src/mirror.ts +794 -0
  443. package/libraries/devtools/src/native-providers.ts +744 -0
  444. package/libraries/devtools/src/verify.ts +167 -0
  445. package/libraries/devtools/src/web/browser.ts +102 -0
  446. package/libraries/devtools/src/web/host.ts +212 -0
  447. package/libraries/devtools/src/web/mirror.ts +430 -0
  448. package/libraries/devtools/src/web/server.ts +198 -0
  449. package/libraries/entities/README.md +17 -0
  450. package/libraries/entities/src/index.ts +4 -0
  451. package/libraries/entities/src/library.ts +64 -0
  452. package/libraries/entities/src/model-renderer.ts +1345 -0
  453. package/libraries/entities/src/shaders/model.wgsl +375 -0
  454. package/libraries/gamepad/src/feed-input.ts +83 -0
  455. package/libraries/gamepad/src/filters.ts +49 -0
  456. package/libraries/gamepad/src/glyphs.ts +93 -0
  457. package/libraries/gamepad/src/hub.ts +206 -0
  458. package/libraries/gamepad/src/index.ts +22 -0
  459. package/libraries/gamepad/src/library.ts +68 -0
  460. package/libraries/gamepad/src/source-sab.ts +70 -0
  461. package/libraries/gamepad/src/sysfs-enrich.ts +138 -0
  462. package/libraries/gaussian-splats/README.md +25 -0
  463. package/libraries/gaussian-splats/src/gpu-sort.ts +595 -0
  464. package/libraries/gaussian-splats/src/index.ts +31 -0
  465. package/libraries/gaussian-splats/src/library.ts +60 -0
  466. package/libraries/gaussian-splats/src/parser.ts +382 -0
  467. package/libraries/gaussian-splats/src/renderer.ts +427 -0
  468. package/libraries/gaussian-splats/src/sh-eval.ts +211 -0
  469. package/libraries/gaussian-splats/src/sorter.ts +110 -0
  470. package/libraries/gaussian-splats/src/tile-raster.ts +473 -0
  471. package/libraries/gpu-kernels/README.md +154 -0
  472. package/libraries/gpu-kernels/src/index.ts +11 -0
  473. package/libraries/gpu-kernels/src/kernel.ts +696 -0
  474. package/libraries/gpu-kernels/src/transpile.ts +958 -0
  475. package/libraries/html-ui-kit/src/behaviors.ts +250 -0
  476. package/libraries/html-ui-kit/src/components.ts +309 -0
  477. package/libraries/html-ui-kit/src/index.ts +30 -0
  478. package/libraries/html-ui-kit/src/nav/nav-controller.ts +238 -0
  479. package/libraries/html-ui-kit/src/nav/nav-input.ts +145 -0
  480. package/libraries/html-ui-kit/src/nav/osk.ts +153 -0
  481. package/libraries/html-ui-kit/src/nav/router.ts +167 -0
  482. package/libraries/html-ui-kit/src/nav/vcursor.ts +203 -0
  483. package/libraries/html-ui-kit/src/ten-foot.ts +182 -0
  484. package/libraries/html-ui-kit/src/theme.ts +238 -0
  485. package/libraries/lighting/README.md +20 -0
  486. package/libraries/lighting/src/index.ts +5 -0
  487. package/libraries/lighting/src/library.ts +66 -0
  488. package/libraries/lighting/src/light-system.ts +452 -0
  489. package/libraries/lighting/src/lighting-system.ts +68 -0
  490. package/libraries/lighting/src/shaders/light-debug.wgsl +30 -0
  491. package/libraries/marching-cubes/README.md +25 -0
  492. package/libraries/marching-cubes/src/chunked-field.ts +177 -0
  493. package/libraries/marching-cubes/src/deformation.ts +63 -0
  494. package/libraries/marching-cubes/src/generator.ts +407 -0
  495. package/libraries/marching-cubes/src/index.ts +32 -0
  496. package/libraries/marching-cubes/src/library.ts +80 -0
  497. package/libraries/marching-cubes/src/lod.ts +122 -0
  498. package/libraries/marching-cubes/src/marching-tetrahedra.ts +252 -0
  499. package/libraries/marching-cubes/src/sab.ts +45 -0
  500. package/libraries/marching-cubes/src/streaming-config.ts +48 -0
  501. package/libraries/marching-cubes/src/streaming-manager.ts +686 -0
  502. package/libraries/marching-cubes/src/tables.ts +323 -0
  503. package/libraries/marching-cubes/src/types.ts +18 -0
  504. package/libraries/models/README.md +25 -0
  505. package/libraries/models/src/bake-node-transforms.ts +171 -0
  506. package/libraries/models/src/codecs/basisu-codec.ts +180 -0
  507. package/libraries/models/src/codecs/draco-codec.ts +372 -0
  508. package/libraries/models/src/codecs/draco3dgltf.d.ts +40 -0
  509. package/libraries/models/src/codecs/index.ts +22 -0
  510. package/libraries/models/src/codecs/meshopt-codec.ts +91 -0
  511. package/libraries/models/src/codecs/registry.ts +221 -0
  512. package/libraries/models/src/dae.ts +753 -0
  513. package/libraries/models/src/default-part-selection.ts +56 -0
  514. package/libraries/models/src/dxf.ts +200 -0
  515. package/libraries/models/src/fbx/index.ts +457 -0
  516. package/libraries/models/src/fbx/interpreter/animation.ts +431 -0
  517. package/libraries/models/src/fbx/interpreter/blend-shapes.ts +323 -0
  518. package/libraries/models/src/fbx/interpreter/connections.ts +166 -0
  519. package/libraries/models/src/fbx/interpreter/diagnostics.ts +65 -0
  520. package/libraries/models/src/fbx/interpreter/geometry.ts +535 -0
  521. package/libraries/models/src/fbx/interpreter/global-settings.ts +92 -0
  522. package/libraries/models/src/fbx/interpreter/materials.ts +265 -0
  523. package/libraries/models/src/fbx/interpreter/nodes.ts +197 -0
  524. package/libraries/models/src/fbx/interpreter/skeleton.ts +476 -0
  525. package/libraries/models/src/fbx/parsers/binary-parser.ts +244 -0
  526. package/libraries/models/src/fbx/types.ts +119 -0
  527. package/libraries/models/src/gltf-extensions.ts +196 -0
  528. package/libraries/models/src/gltf.ts +935 -0
  529. package/libraries/models/src/index.ts +87 -0
  530. package/libraries/models/src/library.ts +75 -0
  531. package/libraries/models/src/loader.ts +265 -0
  532. package/libraries/models/src/material-adapter.ts +108 -0
  533. package/libraries/models/src/mini-xml.ts +174 -0
  534. package/libraries/models/src/normalize.ts +216 -0
  535. package/libraries/models/src/obj.ts +264 -0
  536. package/libraries/models/src/off.ts +95 -0
  537. package/libraries/models/src/ply.ts +348 -0
  538. package/libraries/models/src/pose-sampler.ts +219 -0
  539. package/libraries/models/src/sidecar/blender-extras.ts +37 -0
  540. package/libraries/models/src/sidecar/ddmeta.ts +114 -0
  541. package/libraries/models/src/sidecar/godot-import.ts +86 -0
  542. package/libraries/models/src/sidecar/resolver.ts +145 -0
  543. package/libraries/models/src/sidecar/types.ts +11 -0
  544. package/libraries/models/src/sidecar/unity-meta.ts +61 -0
  545. package/libraries/models/src/skeleton-synthesis.ts +132 -0
  546. package/libraries/models/src/stl.ts +149 -0
  547. package/libraries/models/src/threeds.ts +363 -0
  548. package/libraries/models/src/threemf.ts +201 -0
  549. package/libraries/models/src/types.ts +188 -0
  550. package/libraries/models/src/vtk.ts +218 -0
  551. package/libraries/models/test-fixtures/fbx/LICENSE-notice.txt +24 -0
  552. package/libraries/models/test-fixtures/fbx/README.md +46 -0
  553. package/libraries/models/test-fixtures/fbx/m01_cube_phong.fbx +0 -0
  554. package/libraries/models/test-fixtures/fbx/m02_geo_ngons.fbx +0 -0
  555. package/libraries/models/test-fixtures/fbx/m03_normals.fbx +0 -0
  556. package/libraries/models/test-fixtures/fbx/m04_material_properties.fbx +0 -0
  557. package/libraries/models/test-fixtures/fbx/m05_external_diffuse.png +0 -0
  558. package/libraries/models/test-fixtures/fbx/m05_textures.fbx +0 -0
  559. package/libraries/models/test-fixtures/fbx/m06_uv_transform.fbx +0 -0
  560. package/libraries/models/test-fixtures/fbx/m07_multimaterial.fbx +0 -0
  561. package/libraries/models/test-fixtures/fbx/m08_transforms.fbx +0 -0
  562. package/libraries/models/test-fixtures/fbx/m09_skinning.fbx +0 -0
  563. package/libraries/models/test-fixtures/fbx/m10_morph.fbx +0 -0
  564. package/libraries/models/test-fixtures/fbx/m11_node_anim.fbx +0 -0
  565. package/libraries/models/test-fixtures/fbx/m12_skeletal_anim.fbx +0 -0
  566. package/libraries/models/test-fixtures/fbx/m13_morph_anim.fbx +0 -0
  567. package/libraries/models/test-fixtures/fbx/m14_multiclip.fbx +0 -0
  568. package/libraries/models/test-fixtures/fbx/m15_camera_lights.fbx +0 -0
  569. package/libraries/models/test-fixtures/fbx/m16_axis_yup.fbx +0 -0
  570. package/libraries/models/test-fixtures/fbx/m16_axis_zup.fbx +0 -0
  571. package/libraries/models/test-fixtures/fbx/m16_units_254.fbx +0 -0
  572. package/libraries/navmesh/README.md +23 -0
  573. package/libraries/navmesh/src/crowd-system.ts +240 -0
  574. package/libraries/navmesh/src/debug-viz.ts +74 -0
  575. package/libraries/navmesh/src/index.ts +15 -0
  576. package/libraries/navmesh/src/library.ts +64 -0
  577. package/libraries/navmesh/src/navmesh-generator.ts +407 -0
  578. package/libraries/navmesh/src/navmesh.ts +159 -0
  579. package/libraries/navmesh/src/pathfinder.ts +252 -0
  580. package/libraries/navmesh/src/types.ts +63 -0
  581. package/libraries/networking/README.md +25 -0
  582. package/libraries/networking/src/authority.ts +121 -0
  583. package/libraries/networking/src/connection.ts +139 -0
  584. package/libraries/networking/src/discovery.ts +373 -0
  585. package/libraries/networking/src/enhanced-replication.ts +355 -0
  586. package/libraries/networking/src/epic-adapter.ts +129 -0
  587. package/libraries/networking/src/index.ts +45 -0
  588. package/libraries/networking/src/library.ts +69 -0
  589. package/libraries/networking/src/lobby.ts +108 -0
  590. package/libraries/networking/src/platform-adapter.ts +163 -0
  591. package/libraries/networking/src/rcs-adapter.ts +127 -0
  592. package/libraries/networking/src/remote-input.ts +188 -0
  593. package/libraries/networking/src/replication.ts +327 -0
  594. package/libraries/networking/src/rpc.ts +188 -0
  595. package/libraries/networking/src/session.ts +173 -0
  596. package/libraries/networking/src/transport.ts +201 -0
  597. package/libraries/networking/src/webrtc.ts +323 -0
  598. package/libraries/pathfinding-2d/README.md +15 -0
  599. package/libraries/pathfinding-2d/src/astar-grid.ts +312 -0
  600. package/libraries/pathfinding-2d/src/index.ts +11 -0
  601. package/libraries/persistence/README.md +25 -0
  602. package/libraries/persistence/src/autosave-manager.ts +112 -0
  603. package/libraries/persistence/src/binary-record-store.ts +244 -0
  604. package/libraries/persistence/src/browser.ts +51 -0
  605. package/libraries/persistence/src/file-save-store.ts +553 -0
  606. package/libraries/persistence/src/hash-utils.ts +59 -0
  607. package/libraries/persistence/src/index.ts +57 -0
  608. package/libraries/persistence/src/library.ts +74 -0
  609. package/libraries/persistence/src/mock-opfs.ts +141 -0
  610. package/libraries/persistence/src/node-fs-directory-handle.ts +161 -0
  611. package/libraries/persistence/src/opfs-save-store.ts +745 -0
  612. package/libraries/persistence/src/save-worker-proxy.ts +127 -0
  613. package/libraries/persistence/src/save-worker.ts +99 -0
  614. package/libraries/persistence/src/xxh3-ts.d.ts +10 -0
  615. package/libraries/physics-native/README.md +21 -0
  616. package/libraries/physics-native/native/Cargo.toml +11 -0
  617. package/libraries/physics-native/native/src/body.rs +403 -0
  618. package/libraries/physics-native/native/src/character.rs +226 -0
  619. package/libraries/physics-native/native/src/collider.rs +299 -0
  620. package/libraries/physics-native/native/src/joint.rs +81 -0
  621. package/libraries/physics-native/native/src/lib.rs +830 -0
  622. package/libraries/physics-native/native/src/query.rs +261 -0
  623. package/libraries/physics-native/native/src/realm.rs +33 -0
  624. package/libraries/physics-native/native/src/step.rs +54 -0
  625. package/libraries/physics-native/native/src/world.rs +148 -0
  626. package/libraries/physics-native/src/backend.ts +1046 -0
  627. package/libraries/physics-native/src/broadphase.ts +101 -0
  628. package/libraries/physics-native/src/ffi-spike-worker.ts +71 -0
  629. package/libraries/physics-native/src/index.ts +11 -0
  630. package/libraries/physics-native/src/library.ts +79 -0
  631. package/libraries/physics-native/src/narrowphase-shapes.ts +420 -0
  632. package/libraries/physics-native/src/narrowphase.ts +123 -0
  633. package/libraries/physics-native/src/solver.ts +141 -0
  634. package/libraries/physics-native/src/types.ts +76 -0
  635. package/libraries/physics-rapier/README.md +21 -0
  636. package/libraries/physics-rapier/bench/ffi-bench.ts +79 -0
  637. package/libraries/physics-rapier/bench/wasm-baseline.ts +90 -0
  638. package/libraries/physics-rapier/src/api.ts +452 -0
  639. package/libraries/physics-rapier/src/auto-backend.ts +59 -0
  640. package/libraries/physics-rapier/src/backend.ts +1207 -0
  641. package/libraries/physics-rapier/src/bulk-ops.ts +68 -0
  642. package/libraries/physics-rapier/src/ffi-backend.ts +21 -0
  643. package/libraries/physics-rapier/src/ffi-lib.ts +597 -0
  644. package/libraries/physics-rapier/src/index.ts +12 -0
  645. package/libraries/physics-rapier/src/library.ts +107 -0
  646. package/libraries/physics-rapier/src/rapier-backend.ts +1052 -0
  647. package/libraries/physics-rapier/src/realm-worker-script.ts +237 -0
  648. package/libraries/postfx/README.md +17 -0
  649. package/libraries/postfx/src/index.ts +19 -0
  650. package/libraries/postfx/src/library.ts +337 -0
  651. package/libraries/postfx/src/post-process-stack.ts +1752 -0
  652. package/libraries/postfx/src/shaders/post-process/afterimage.wgsl +14 -0
  653. package/libraries/postfx/src/shaders/post-process/ascii.wgsl +24 -0
  654. package/libraries/postfx/src/shaders/post-process/blit.wgsl +12 -0
  655. package/libraries/postfx/src/shaders/post-process/bloom-blur.wgsl +21 -0
  656. package/libraries/postfx/src/shaders/post-process/bloom-bright.wgsl +15 -0
  657. package/libraries/postfx/src/shaders/post-process/bloom-composite.wgsl +14 -0
  658. package/libraries/postfx/src/shaders/post-process/bloom-downsample.wgsl +60 -0
  659. package/libraries/postfx/src/shaders/post-process/bloom-soft.wgsl +46 -0
  660. package/libraries/postfx/src/shaders/post-process/bloom-upsample.wgsl +51 -0
  661. package/libraries/postfx/src/shaders/post-process/channel-mixer.wgsl +36 -0
  662. package/libraries/postfx/src/shaders/post-process/chromatic-aberration.wgsl +37 -0
  663. package/libraries/postfx/src/shaders/post-process/dithering.wgsl +64 -0
  664. package/libraries/postfx/src/shaders/post-process/dof.wgsl +131 -0
  665. package/libraries/postfx/src/shaders/post-process/edges.wgsl +45 -0
  666. package/libraries/postfx/src/shaders/post-process/fullscreen-vs.wgsl +15 -0
  667. package/libraries/postfx/src/shaders/post-process/fxaa.wgsl +102 -0
  668. package/libraries/postfx/src/shaders/post-process/gaussian-blur.wgsl +37 -0
  669. package/libraries/postfx/src/shaders/post-process/glow-blur.wgsl +33 -0
  670. package/libraries/postfx/src/shaders/post-process/glow-composite.wgsl +25 -0
  671. package/libraries/postfx/src/shaders/post-process/grain.wgsl +37 -0
  672. package/libraries/postfx/src/shaders/post-process/halftone.wgsl +80 -0
  673. package/libraries/postfx/src/shaders/post-process/highlight-blur.wgsl +33 -0
  674. package/libraries/postfx/src/shaders/post-process/highlight-composite.wgsl +32 -0
  675. package/libraries/postfx/src/shaders/post-process/lens-distortion.wgsl +43 -0
  676. package/libraries/postfx/src/shaders/post-process/lens-flare.wgsl +68 -0
  677. package/libraries/postfx/src/shaders/post-process/lut.wgsl +30 -0
  678. package/libraries/postfx/src/shaders/post-process/motion-blur.wgsl +55 -0
  679. package/libraries/postfx/src/shaders/post-process/occluder-chunk.wgsl +28 -0
  680. package/libraries/postfx/src/shaders/post-process/outline.wgsl +51 -0
  681. package/libraries/postfx/src/shaders/post-process/pixelation.wgsl +47 -0
  682. package/libraries/postfx/src/shaders/post-process/sharpen.wgsl +32 -0
  683. package/libraries/postfx/src/shaders/post-process/sobel.wgsl +26 -0
  684. package/libraries/postfx/src/shaders/post-process/split-tone.wgsl +36 -0
  685. package/libraries/postfx/src/shaders/post-process/ssao-blur.wgsl +38 -0
  686. package/libraries/postfx/src/shaders/post-process/ssao-composite.wgsl +25 -0
  687. package/libraries/postfx/src/shaders/post-process/ssao.wgsl +147 -0
  688. package/libraries/postfx/src/shaders/post-process/ssr.wgsl +155 -0
  689. package/libraries/postfx/src/shaders/post-process/taa.wgsl +98 -0
  690. package/libraries/postfx/src/shaders/post-process/tonemap.wgsl +40 -0
  691. package/libraries/postfx/src/shaders/post-process/watercolor.wgsl +82 -0
  692. package/libraries/postfx/src/shaders/post-process/white-balance.wgsl +41 -0
  693. package/libraries/recast/README.md +21 -0
  694. package/libraries/recast/src/backend.ts +150 -0
  695. package/libraries/recast/src/crowd-system.ts +352 -0
  696. package/libraries/recast/src/index.ts +12 -0
  697. package/libraries/recast/src/library.ts +91 -0
  698. package/libraries/recast/src/types.ts +86 -0
  699. package/libraries/sand/README.md +25 -0
  700. package/libraries/sand/src/cell.ts +43 -0
  701. package/libraries/sand/src/fields.ts +29 -0
  702. package/libraries/sand/src/fluid-grid.ts +261 -0
  703. package/libraries/sand/src/grid-dims.ts +74 -0
  704. package/libraries/sand/src/grid-sim-buffer.ts +271 -0
  705. package/libraries/sand/src/index.ts +81 -0
  706. package/libraries/sand/src/library.ts +92 -0
  707. package/libraries/sand/src/materials.ts +492 -0
  708. package/libraries/sand/src/palette.ts +93 -0
  709. package/libraries/sand/src/particles.ts +185 -0
  710. package/libraries/sand/src/render/sand-grid-pass.ts +430 -0
  711. package/libraries/sand/src/rng.ts +51 -0
  712. package/libraries/sand/src/rules/builtin-rules.ts +132 -0
  713. package/libraries/sand/src/rules/rule-compiler.ts +162 -0
  714. package/libraries/sand/src/rules/rule-engine.ts +231 -0
  715. package/libraries/sand/src/rules/rule-types.ts +87 -0
  716. package/libraries/sand/src/sand-step-pool.ts +484 -0
  717. package/libraries/sand/src/sand-step-worker.ts +97 -0
  718. package/libraries/sand/src/sand-world.ts +3227 -0
  719. package/libraries/stickman/README.md +25 -0
  720. package/libraries/stickman/src/index.ts +25 -0
  721. package/libraries/stickman/src/library.ts +61 -0
  722. package/libraries/stickman/src/proportions.ts +45 -0
  723. package/libraries/stickman/src/shader.ts +117 -0
  724. package/libraries/stickman/src/skeleton.ts +197 -0
  725. package/libraries/stickman/src/stickman-pass.ts +255 -0
  726. package/libraries/stickman/src/thick-line.ts +123 -0
  727. package/libraries/surface-nets/README.md +25 -0
  728. package/libraries/surface-nets/src/chunked-field.ts +14 -0
  729. package/libraries/surface-nets/src/deformation.ts +45 -0
  730. package/libraries/surface-nets/src/index.ts +36 -0
  731. package/libraries/surface-nets/src/library.ts +59 -0
  732. package/libraries/surface-nets/src/lod.ts +7 -0
  733. package/libraries/surface-nets/src/sab.ts +4 -0
  734. package/libraries/surface-nets/src/streaming-config.ts +5 -0
  735. package/libraries/surface-nets/src/streaming-manager.ts +15 -0
  736. package/libraries/surface-nets/src/surface-nets.ts +334 -0
  737. package/libraries/surface-nets/src/types.ts +23 -0
  738. package/libraries/water/README.md +25 -0
  739. package/libraries/water/src/buoyancy.ts +103 -0
  740. package/libraries/water/src/index.ts +43 -0
  741. package/libraries/water/src/library.ts +85 -0
  742. package/libraries/water/src/shore-damping.ts +93 -0
  743. package/libraries/water/src/water-buffer.ts +89 -0
  744. package/libraries/water/src/water-chunks.ts +13 -0
  745. package/libraries/water/src/water-physics.ts +376 -0
  746. package/libraries/water/src/water-renderer.ts +809 -0
  747. package/libraries/water/src/water-sab.ts +161 -0
  748. package/libraries/water/src/wave-sources.ts +84 -0
  749. package/libraries/weather/README.md +20 -0
  750. package/libraries/weather/src/index.ts +9 -0
  751. package/libraries/weather/src/library.ts +72 -0
  752. package/libraries/weather/src/types.ts +64 -0
  753. package/libraries/weather/src/weather-blend.ts +112 -0
  754. package/libraries/weather/src/weather-system.ts +271 -0
  755. package/libraries/weatherfx/README.md +24 -0
  756. package/libraries/weatherfx/src/cloud-provider.ts +31 -0
  757. package/libraries/weatherfx/src/cloud-system.ts +372 -0
  758. package/libraries/weatherfx/src/index.ts +9 -0
  759. package/libraries/weatherfx/src/library.ts +58 -0
  760. package/libraries/weatherfx/src/particle-system.ts +434 -0
  761. package/libraries/weatherfx/src/shaders/cloud.wgsl +111 -0
  762. package/libraries/weatherfx/src/shaders/particle-compute.wgsl +187 -0
  763. package/libraries/weatherfx/src/shaders/particle-render.wgsl +95 -0
  764. package/lint-plugin.mjs +41 -0
  765. package/mcp/src/client.ts +703 -0
  766. package/mcp/src/engine-context.ts +186 -0
  767. package/mcp/src/http-transport.ts +471 -0
  768. package/mcp/src/index.ts +13 -0
  769. package/mcp/src/prompts/add-entity.ts +42 -0
  770. package/mcp/src/prompts/create-scene.ts +44 -0
  771. package/mcp/src/prompts/debug-frame.ts +39 -0
  772. package/mcp/src/prompts/index.ts +12 -0
  773. package/mcp/src/resources/asset-list.ts +32 -0
  774. package/mcp/src/resources/checkpoint-list.ts +33 -0
  775. package/mcp/src/resources/entity-state.ts +55 -0
  776. package/mcp/src/resources/gpu-info.ts +103 -0
  777. package/mcp/src/resources/index.ts +57 -0
  778. package/mcp/src/resources/performance.ts +37 -0
  779. package/mcp/src/resources/scene-tree.ts +43 -0
  780. package/mcp/src/server.ts +375 -0
  781. package/mcp/src/tools/animation.ts +118 -0
  782. package/mcp/src/tools/asset.ts +161 -0
  783. package/mcp/src/tools/audio.ts +96 -0
  784. package/mcp/src/tools/build.ts +143 -0
  785. package/mcp/src/tools/camera.ts +167 -0
  786. package/mcp/src/tools/checkpoint.ts +100 -0
  787. package/mcp/src/tools/component.ts +199 -0
  788. package/mcp/src/tools/debug.ts +300 -0
  789. package/mcp/src/tools/entity.ts +361 -0
  790. package/mcp/src/tools/inspect.ts +210 -0
  791. package/mcp/src/tools/lighting.ts +263 -0
  792. package/mcp/src/tools/material.ts +243 -0
  793. package/mcp/src/tools/mesh.ts +239 -0
  794. package/mcp/src/tools/physics.ts +266 -0
  795. package/mcp/src/tools/scene.ts +153 -0
  796. package/mcp/src/tools/script.ts +122 -0
  797. package/mcp/src/types.ts +92 -0
  798. package/mcp/src/undo-redo.ts +77 -0
  799. package/modules/camera-controls/README.md +20 -0
  800. package/modules/camera-controls/src/index.ts +161 -0
  801. package/modules/controller-ui/src/index.ts +164 -0
  802. package/modules/devtools/README.md +25 -0
  803. package/modules/devtools/src/api.ts +461 -0
  804. package/modules/devtools/src/asset-utils.ts +105 -0
  805. package/modules/devtools/src/bind-debug-store.ts +48 -0
  806. package/modules/devtools/src/data-bridge.ts +286 -0
  807. package/modules/devtools/src/debug-overlay.ts +238 -0
  808. package/modules/devtools/src/debug-raycast.ts +328 -0
  809. package/modules/devtools/src/debug-store.ts +92 -0
  810. package/modules/devtools/src/debug-view-descriptors.ts +59 -0
  811. package/modules/devtools/src/doctor-panel.ts +182 -0
  812. package/modules/devtools/src/gizmo-module.ts +136 -0
  813. package/modules/devtools/src/graph-model.ts +509 -0
  814. package/modules/devtools/src/grid-renderer.ts +157 -0
  815. package/modules/devtools/src/height-ruler-renderer.ts +216 -0
  816. package/modules/devtools/src/index.ts +81 -0
  817. package/modules/devtools/src/init.ts +261 -0
  818. package/modules/devtools/src/label-overlay.ts +154 -0
  819. package/modules/devtools/src/material-stats-panel.ts +188 -0
  820. package/modules/devtools/src/profiling-bridge.ts +377 -0
  821. package/modules/devtools/src/profiling-hooks.ts +98 -0
  822. package/modules/devtools/src/renderer-adapter.ts +76 -0
  823. package/modules/devtools/src/scene-inspector.ts +637 -0
  824. package/modules/devtools/src/scene-store.ts +320 -0
  825. package/modules/devtools/src/scene-sync.ts +116 -0
  826. package/modules/devtools/src/shaders/transform-gizmo.wgsl +38 -0
  827. package/modules/devtools/src/sim-stats-panel.ts +272 -0
  828. package/modules/devtools/src/sim-stats-provider.ts +105 -0
  829. package/modules/devtools/src/skeleton-renderer.ts +351 -0
  830. package/modules/devtools/src/transform-gizmo.ts +928 -0
  831. package/modules/devtools/src/types.ts +290 -0
  832. package/modules/devtools/src/worker-expose.ts +67 -0
  833. package/modules/devtools/src/worker-sync.ts +137 -0
  834. package/modules/editor/src/commands/component.ts +156 -0
  835. package/modules/editor/src/commands/entity.ts +287 -0
  836. package/modules/editor/src/commands/hierarchy.ts +83 -0
  837. package/modules/editor/src/commands/index.ts +61 -0
  838. package/modules/editor/src/commands/prefab.ts +163 -0
  839. package/modules/editor/src/commands/registry.ts +331 -0
  840. package/modules/editor/src/commands/scene-io.ts +211 -0
  841. package/modules/editor/src/commands/selection.ts +73 -0
  842. package/modules/editor/src/commands/transform.ts +91 -0
  843. package/modules/editor/src/ddscene.ts +267 -0
  844. package/modules/editor/src/document.ts +123 -0
  845. package/modules/editor/src/editor-context.ts +172 -0
  846. package/modules/editor/src/index.ts +41 -0
  847. package/modules/editor/src/mcp.ts +103 -0
  848. package/modules/editor/src/module.ts +148 -0
  849. package/modules/editor/src/selection.ts +70 -0
  850. package/modules/editor/src/shell.ts +456 -0
  851. package/modules/editor/src/viewport.ts +199 -0
  852. package/modules/html-ui/src/composite.ts +135 -0
  853. package/modules/html-ui/src/create-html-ui.ts +188 -0
  854. package/modules/html-ui/src/doc-backend.ts +343 -0
  855. package/modules/html-ui/src/host.ts +646 -0
  856. package/modules/html-ui/src/index.ts +13 -0
  857. package/modules/html-ui/src/jsx-dev-runtime.ts +12 -0
  858. package/modules/html-ui/src/jsx-runtime.ts +126 -0
  859. package/modules/html-ui/src/protocol.ts +88 -0
  860. package/modules/html-ui/src/ui-worker.ts +16 -0
  861. package/modules/mcp/README.md +18 -0
  862. package/modules/mcp/src/index.ts +27 -0
  863. package/modules/movement-2d/README.md +19 -0
  864. package/modules/movement-2d/src/grid-character.ts +455 -0
  865. package/modules/movement-2d/src/index.ts +45 -0
  866. package/modules/movement-3d/README.md +21 -0
  867. package/modules/movement-3d/src/character-motor.ts +230 -0
  868. package/modules/movement-3d/src/index.ts +46 -0
  869. package/modules/native-osr/src/index.ts +22 -0
  870. package/modules/native-osr/src/input-router.ts +401 -0
  871. package/modules/native-osr/src/native-osr-manager.ts +247 -0
  872. package/modules/native-osr/src/native-texture-source.ts +86 -0
  873. package/modules/native-osr/src/types.ts +112 -0
  874. package/modules/native-osr/src/world-space-ui-pass.ts +351 -0
  875. package/modules/sailing/README.md +18 -0
  876. package/modules/sailing/src/index.ts +51 -0
  877. package/modules/terrain/README.md +18 -0
  878. package/modules/terrain/src/index.ts +78 -0
  879. package/modules/vitals/README.md +17 -0
  880. package/modules/vitals/src/index.ts +43 -0
  881. package/modules/vitals/src/vitals.ts +265 -0
  882. package/modules/xr/README.md +25 -0
  883. package/modules/xr/src/camera-rig.ts +146 -0
  884. package/modules/xr/src/debug.ts +59 -0
  885. package/modules/xr/src/frame-loop.ts +197 -0
  886. package/modules/xr/src/index.ts +16 -0
  887. package/modules/xr/src/input.ts +208 -0
  888. package/modules/xr/src/layer.ts +140 -0
  889. package/modules/xr/src/session.ts +156 -0
  890. package/modules/xr/src/sim-module.ts +23 -0
  891. package/modules/xr/src/types.ts +32 -0
  892. package/modules/xr/src/webxr.d.ts +182 -0
  893. package/modules/xr/src/xr-module.ts +179 -0
  894. package/package.json +232 -3
  895. package/shader-graph/src/chunks.ts +349 -0
  896. package/shader-graph/src/compiler.ts +732 -0
  897. package/shader-graph/src/compute-compiler.ts +453 -0
  898. package/shader-graph/src/compute-graph.ts +112 -0
  899. package/shader-graph/src/compute-profiles.ts +54 -0
  900. package/shader-graph/src/graph.ts +52 -0
  901. package/shader-graph/src/index.ts +53 -0
  902. package/shader-graph/src/profiles.ts +407 -0
  903. package/shader-graph/src/validator.ts +48 -0
  904. package/shader-graph/src/wgsl-binding-validator.ts +143 -0
  905. package/shader-graph/src/wgsl-struct-validator.ts +245 -0
  906. package/shader-graph/src/wgsl-struct.ts +397 -0
  907. package/test/src/index.ts +7 -0
  908. package/test/src/vision-test.ts +369 -0
@@ -0,0 +1,923 @@
1
+ // ============================================================================
2
+ // GameModule — declarative game definition + startGame() entry point
3
+ //
4
+ // A `GameModule` is a declarative description of a game's renderer-side
5
+ // bootstrap: the renderer factory, sim worker factory, UI mount, event
6
+ // routing, save config, devtools, and game-specific hooks. `startGame()`
7
+ // consumes a module and orchestrates the full bootstrap sequence, collapsing
8
+ // the ~700-line per-game `main.tsx` into a ~100-line module declaration.
9
+ //
10
+ // Design goals:
11
+ // - Declarative: games declare *what* they need, not *how* to wire it.
12
+ // - Progressive: every field is optional except `renderer` and `sim`.
13
+ // Simple games get a 10-line module; complex games add hooks.
14
+ // - Typed: the `GameContext` passed to hooks carries typed references
15
+ // (renderer, simWorker, SABs, saveStore, bridge) — no module-scope `let`.
16
+ // - Escape hatches: `onInit` / `onReady` / `onDispose` hooks let games
17
+ // run bespoke logic at well-defined points in the sequence.
18
+ //
19
+ // `startGame()` wraps `bootstrapGame()` — games that need full control can
20
+ // still call `bootstrapGame()` directly.
21
+ // ============================================================================
22
+
23
+ import {
24
+ ENGINE_VERSION,
25
+ LibraryHostImpl,
26
+ PluginHost,
27
+ WorkerPluginLoader,
28
+ isDevMode,
29
+ type GameRendererLike,
30
+ type ISaveStore,
31
+ type LibraryEntry,
32
+ type LibraryHost,
33
+ type PluginHostOptions,
34
+ type PluginManifest,
35
+ type PluginPermission,
36
+ type PluginSource,
37
+ type RenderSurface,
38
+ type SaveMeta,
39
+ type SaveState
40
+ } from "@downdraft/engine";
41
+ import { createLogger } from "@downdraft/engine/util/logger";
42
+ import { bootstrapGame, type BootstrapDevToolsOptions } from "./bootstrap";
43
+ import { downdraft, getSurface } from "./index";
44
+ import { createSaveStore, isOpfsAvailable, type SaveStoreMode } from "./save-store-factory";
45
+
46
+ const log = createLogger("info");
47
+
48
+ // ── Types ──
49
+
50
+ /**
51
+ * The sim worker abstraction. Games provide a factory that creates a sim
52
+ * worker; `startGame()` calls `start()`, captures SABs, wires event routing,
53
+ * and exposes the worker via `GameContext.sim`.
54
+ *
55
+ * This is intentionally minimal — games implement this interface on top of
56
+ * their own sim worker class (e.g. a game's `SimWebWorker`).
57
+ *
58
+ * Games that have a richer sim worker interface can pass their concrete type
59
+ * as the generic parameter `T` to `GameModule<T>` — `GameContext.sim` will
60
+ * then be typed as `T` (no casting needed).
61
+ */
62
+ export interface GameSimWorker {
63
+ /** Start the sim worker. Config is opaque to the framework (game-specific).
64
+ * Not called for renderer-owned workers (see `module.simFromRenderer`). */
65
+ start(config: unknown): Promise<void>;
66
+ /**
67
+ * `SimWorkerHost`-style event subscription — the callback receives
68
+ * `{ kind, data }` messages and the return value is an unsubscribe
69
+ * function. Preferred over `onEvent` when both exist.
70
+ *
71
+ * NOTE: `onEvent(cb)` is intentionally NOT declared on this interface —
72
+ * `SimWorkerHost`/`BaseWorkerHost` subclasses carry a *protected*
73
+ * `onEvent(kind, data)` dispatcher, and a class with a protected member
74
+ * can't satisfy an interface that declares the same name. Event wiring
75
+ * probes `subscribeEvents` first, then a public `onEvent` at runtime, so
76
+ * plain GameSimWorker implementations (e.g. falling-sand's worker host)
77
+ * still work.
78
+ */
79
+ subscribeEvents?(cb: (msg: { kind: string; data: unknown }) => void): () => void;
80
+ getSimBuffer(): SharedArrayBuffer;
81
+ getInputBuffer(): SharedArrayBuffer;
82
+ /** Optional additional SABs the game wants exposed via GameContext. */
83
+ getExtraBuffers?(): Record<string, SharedArrayBuffer>;
84
+ addPlayer?(playerId: number, name: string): Promise<void> | void;
85
+ save?(slotName: string, opts?: unknown): Promise<{ stateJson: string; success: boolean; meta?: Partial<SaveMeta> } | null>;
86
+ load?(slotName: string, stateJson?: string): Promise<boolean>;
87
+ initSaveStore?(opts: unknown): Promise<void>;
88
+ restoreFromState?(stateJson: string): Promise<void>;
89
+ hotReload?(config: unknown, preserveState: boolean): Promise<void>;
90
+ getDevToolsProxy?(): unknown;
91
+ }
92
+
93
+ /** Optional seed passed to the sim worker factory. */
94
+ export interface SimWorkerSeed {
95
+ /** SABs allocated by EngineLibrary descriptors (keyed by channel name). */
96
+ libraryBuffers?: Record<string, SharedArrayBuffer>;
97
+ }
98
+
99
+ /** Factory that creates a sim worker. Receives a seed with library-allocated
100
+ * SABs (if any libraries declared). Games can pass these to their sim worker
101
+ * constructor to avoid double-allocating SABs. */
102
+ export type SimWorkerFactory<T extends GameSimWorker = GameSimWorker> = (seed?: SimWorkerSeed) => T;
103
+
104
+ /** Factory that creates the renderer from the render surface. The return
105
+ * type narrows `GameContext.renderer` — inferred from the factory. */
106
+ export type RendererFactory<R extends GameRendererLike = GameRendererLike> = (surface: RenderSurface) => R;
107
+
108
+ /**
109
+ * Renderer-side save source — an alternative to the sim worker for providing
110
+ * serializable game state. Renderer-only games (no sim worker) declare a
111
+ * `saveSource` in their `GameModule` so the autosave wiring can call it
112
+ * instead of `sim.save()`.
113
+ *
114
+ * Sim-worker games do NOT need this — the sim worker's optional `save()`
115
+ * method is used directly. A game that declares both `sim` and `saveSource`
116
+ * is a configuration error; `saveSource` takes priority.
117
+ */
118
+ export interface GameSaveSource {
119
+ /** Serialize current state and return it as a JSON string. `meta` carries
120
+ * real SaveMeta for the renderer-side store write when available. */
121
+ save(slotName: string): Promise<{ stateJson: string; success: boolean; meta?: Partial<SaveMeta> } | null>;
122
+ /** Optional: load a previously saved state. If omitted, the save store's
123
+ * own load path is used (OPFS / host bridge). */
124
+ load?(slotName: string): Promise<string | null>;
125
+ }
126
+
127
+ /**
128
+ * Declarative event handler map. Each key is a sim→renderer message `kind`;
129
+ * each value is a handler that receives the message data and the game context.
130
+ *
131
+ * This replaces the manual `switch (msg.kind)` block in main.tsx. Unknown
132
+ * message kinds are logged as warnings in dev mode.
133
+ */
134
+ export type SimEventMap<C extends GameContext = GameContext> = Record<string, (data: any, ctx: C) => void>;
135
+
136
+ /** Save configuration. If omitted, no autosave is wired. */
137
+ export interface GameSaveConfig {
138
+ /** Save mode. Default: "host" when a native host save store is installed
139
+ * (disk, stable), "auto" in browser. Games should pin an explicit mode
140
+ * rather than relying on "auto" — see createSaveStore for resolution. */
141
+ mode?: SaveStoreMode;
142
+ /** Engine version string for save slots. */
143
+ engineVersion: string;
144
+ /** Max save generations to keep. Default: 3. */
145
+ maxGenerations?: number;
146
+ /** Autosave interval in ms. Default: 3000. */
147
+ intervalMs?: number;
148
+ /** Slot name for autosave. Default: "autosave". */
149
+ slotName?: string;
150
+ /**
151
+ * Name of the save-state component that carries the game's data blob
152
+ * (the key under `SaveState.components`, e.g. "sandbox"). Declared
153
+ * explicitly so `ctx.load` forwards the right component to the sim —
154
+ * without it, load falls back to guessing "the first component whose
155
+ * data is an object", which silently picks the wrong blob when a save
156
+ * has multiple object-valued components.
157
+ */
158
+ componentName?: string;
159
+ }
160
+
161
+ /**
162
+ * Serialize the restore payload for a SaveState components map.
163
+ * `explicit` (GameSaveConfig.componentName) selects a single component's
164
+ * `data`. Otherwise: a single-component save unwraps to its `data` (the raw
165
+ * payload restores expect), while a multi-component save forwards the whole
166
+ * map — the worker's extractRestoreData passes component-map input through
167
+ * to the game's restore, which selects the sections it owns. Picking the
168
+ * first component would silently drop the rest of the world.
169
+ */
170
+ export function serializeRestorePayload(
171
+ components: Record<string, { data?: unknown } | null | undefined>,
172
+ explicit: string | undefined,
173
+ ): string | undefined {
174
+ if (explicit) {
175
+ const comp = components[explicit];
176
+ if (!comp) {
177
+ log.warn("startGame", `Save component "${explicit}" not found; available: ${Object.keys(components).join(", ")}`);
178
+ return undefined;
179
+ }
180
+ return JSON.stringify(comp.data);
181
+ }
182
+ const keys = Object.keys(components).filter(
183
+ (k) => components[k]?.data !== undefined && components[k]?.data !== null,
184
+ );
185
+ if (keys.length === 0) return undefined;
186
+ if (keys.length === 1) return JSON.stringify(components[keys[0]]!.data);
187
+ return JSON.stringify(components);
188
+ }
189
+
190
+ /**
191
+ * A framework-managed UI handle. Returned by `GameModule.ui` — startGame()
192
+ * calls `start()` after renderer init (before `onReady`) and `dispose()` on
193
+ * hot-reload. Any { start, dispose } object is compatible (html-ui hosts,
194
+ * DOM-UI mounts, custom overlays).
195
+ */
196
+ export interface GameUiHandle {
197
+ /** Start the UI (spawn workers, mount overlays). Called after renderer init. */
198
+ start(): Promise<void> | void;
199
+ /** Tear down. Called on hot-reload dispose, before `module.onDispose`. */
200
+ dispose(): void;
201
+ }
202
+
203
+ /**
204
+ * The context passed to all game hooks. Carries typed references to every
205
+ * framework-managed resource — no module-scope `let` variables needed.
206
+ *
207
+ * The `Sim` type parameter lets games specify their concrete sim worker type
208
+ * so `ctx.sim` is typed correctly (no casting). For renderer-only games (no
209
+ * `sim` declared in the `GameModule`), `Sim` defaults to `GameSimWorker` and
210
+ * `ctx.sim` is `undefined` — hooks should not access it.
211
+ *
212
+ * Sim fields (`sim`, `simSAB`, `inputSAB`) are optional because renderer-only
213
+ * games don't have a sim worker. Games that declare `sim` can safely use
214
+ * non-null assertions (`ctx.sim!`) in their hooks — `startGame()` guarantees
215
+ * the sim worker is created when `module.sim` is declared.
216
+ */
217
+ export interface GameContext<Sim extends GameSimWorker = GameSimWorker, R extends GameRendererLike = GameRendererLike> {
218
+ /** The renderer instance. Typed as `R` — inferred from the module's
219
+ * `renderer` factory, so game-specific members resolve without casts
220
+ * when the factory returns the concrete renderer class. */
221
+ renderer: R;
222
+ /** The render surface the renderer is attached to (NativeSurface on the
223
+ * native runtime). */
224
+ surface: RenderSurface;
225
+ /** The sim worker instance. Undefined for renderer-only games (no `sim` declared). */
226
+ sim?: Sim;
227
+ /** The sim SAB (entity/component data, zero-copy shared with the sim worker).
228
+ * Undefined for renderer-only games. */
229
+ simSAB?: SharedArrayBuffer;
230
+ /** The input SAB (renderer writes, sim worker reads).
231
+ * Undefined for renderer-only games. */
232
+ inputSAB?: SharedArrayBuffer;
233
+ /** Extra SABs from `sim.getExtraBuffers()` (e.g. water, custom-game-data).
234
+ * For renderer-only games, this contains only library-allocated SABs (if any). */
235
+ extraBuffers: Record<string, SharedArrayBuffer>;
236
+ /** The save store, if save config was provided and init succeeded. May be null. */
237
+ saveStore: ISaveStore | null;
238
+ /** The save mode that was actually selected (may differ from config in fallback). */
239
+ saveMode: "inline" | "worker" | "host";
240
+ /**
241
+ * Mode-aware save: persists the current state to the selected backend
242
+ * (inline OPFS / worker OPFS / host store disk). Games should call this for
243
+ * manual saves instead of `sim.save()` directly — `sim.save()` only writes
244
+ * in inline mode and silently drops the save in host mode.
245
+ * Returns true if the save succeeded. Undefined when no save config was declared.
246
+ */
247
+ save?: (slotName: string) => Promise<boolean>;
248
+ /**
249
+ * Mode-aware load: restores state from the selected backend. Games should
250
+ * call this for manual loads instead of `sim.load()` directly.
251
+ * Returns the loaded state (shape depends on the save source), or null if
252
+ * no save exists. Undefined when no save config was declared.
253
+ */
254
+ load?: (slotName: string) => Promise<unknown | null>;
255
+ /** The renderer-side save source, if `module.saveSource` was declared.
256
+ * Used by the autosave wiring for renderer-only games. Undefined for
257
+ * sim-worker games (which use `sim.save()` instead). */
258
+ saveSource?: GameSaveSource;
259
+ /** The typed downdraft bridge (window.downdraft). */
260
+ bridge: typeof downdraft;
261
+ /** True if running in deterministic/test mode (DOWNDRAFT_DETERMINISTIC=1). */
262
+ deterministic: boolean;
263
+ /** True if running in dev mode (Vite dev or downdraft.isDev). */
264
+ isDev: boolean;
265
+ /** The library host (if engine libraries were declared). Games can access
266
+ * library-provided resources via DI tokens from onReady. */
267
+ libraryHost?: LibraryHost;
268
+ /** The plugin host (if `module.plugins` was declared). Games can access
269
+ * plugin diagnostics via `pluginHost.snapshot()` and trigger reloads. */
270
+ pluginHost?: PluginHost;
271
+ /** The UI handle created by `module.ui`. Set after renderer init, before
272
+ * `onReady` runs — hooks can `ctx.ui` to post events or wire
273
+ * subscriptions. */
274
+ ui?: GameUiHandle;
275
+ }
276
+
277
+ /**
278
+ * Plugin runtime configuration. Games opt into the user-authored plugin
279
+ * (modding) system by declaring a `plugins` field on their `GameModule`.
280
+ *
281
+ * The host constructs a renderer-side `PluginHost` and (for sim-thread
282
+ * plugins) forwards manifests to the sim worker. Games choose per-format
283
+ * whether worker-js plugins run on the sim worker or in a dedicated plugin
284
+ * worker; WASM is always forced to its own worker; QuickJS runs in-process on
285
+ * the renderer; asset plugins are data-only.
286
+ */
287
+ export interface PluginRuntimeConfig {
288
+ /** Default thread for worker-js plugins: "sim" (inside the game's sim
289
+ * worker) or "own-worker" (dedicated sandboxed worker). Default: "own-worker". */
290
+ workerJs?: "sim" | "own-worker";
291
+ /** Discovery sources. Local plugin dirs + remote workshop stores. */
292
+ sources?: PluginSource[];
293
+ /** Game-defined permission allowlist (further restricts tier). */
294
+ permissions?: ReadonlySet<PluginPermission>;
295
+ /** Game-defined event catalog for the plugin event bus. */
296
+ eventCatalog?: Record<string, unknown>;
297
+ /** Pre-resolved manifests to load (in addition to discovered sources).
298
+ * Useful for tests and for bundling first-party plugins. */
299
+ manifests?: PluginManifest[];
300
+ }
301
+
302
+ /**
303
+ * A declarative game definition.
304
+ *
305
+ * Games create a `GameModule` and pass it to `startGame()`. The module
306
+ * describes the renderer, sim worker (optional), UI, event routing, save
307
+ * config, devtools, and game-specific hooks. `startGame()` orchestrates the
308
+ * full bootstrap sequence.
309
+ *
310
+ * The `Sim` generic parameter lets games specify their concrete sim worker
311
+ * type so `GameContext.sim` is typed correctly (no casting). For renderer-only
312
+ * games, omit `sim` and `simConfig` — `Sim` defaults to `GameSimWorker` and
313
+ * the sim-related hooks (`events`, `onSimStart`) are ignored.
314
+ *
315
+ * Two topologies:
316
+ * - **Sim-worker**: declare `sim` + `simConfig`. `startGame()` spawns the
317
+ * worker, captures SABs, wires event routing, and starts the sim.
318
+ * - **Renderer-only**: omit `sim` + `simConfig`. All logic runs on the
319
+ * renderer thread. Declare `saveSource` if you need autosave. Use
320
+ * engine libraries (e.g. `WeatherFxLib`, `ModelsLib`) for GPU-side work.
321
+ */
322
+ export interface GameModule<Sim extends GameSimWorker = GameSimWorker, R extends GameRendererLike = GameRendererLike> {
323
+ // ── Required: renderer ──
324
+ /** Factory that creates the renderer from a canvas. */
325
+ renderer: RendererFactory<R>;
326
+
327
+ // ── Optional: sim worker (omit for renderer-only games) ──
328
+ /** Factory that creates the sim worker. Omit for renderer-only games. */
329
+ sim?: SimWorkerFactory<Sim>;
330
+ /** Config passed to `sim.start()`. Required when `sim` is declared. */
331
+ simConfig?: Record<string, unknown>;
332
+ /**
333
+ * Renderer-owned sim worker. For games where the renderer spawns and starts
334
+ * its own worker internally during `renderer.init()` (e.g. falling-sand's
335
+ * renderer creates its SandWorkerHost). Declare this INSTEAD of `sim` — it
336
+ * is called after renderer init to retrieve the worker, which is then
337
+ * exposed as `ctx.sim` and wired into `module.events` routing like a
338
+ * factory-created worker. This removes the need for no-op GameSimWorker
339
+ * adapter classes.
340
+ *
341
+ * The returned object must satisfy GameSimWorker (start + getSimBuffer +
342
+ * getInputBuffer, plus onEvent or subscribeEvents for event routing).
343
+ * `SimWorkerHost` subclasses satisfy this directly via `subscribeEvents`:
344
+ * `simFromRenderer: (r) => r.getWorkerHost() ?? undefined`
345
+ */
346
+ simFromRenderer?: (renderer: R, ctx: GameContext<Sim, R>) => Sim | undefined | Promise<Sim | undefined>;
347
+
348
+ // ── UI ──
349
+ /**
350
+ * Declarative UI lifecycle. Called once with the game context; the returned
351
+ * handle is started after renderer init (before `onReady`) and disposed on
352
+ * hot-reload (before `onDispose`). The handle is exposed as `ctx.ui`.
353
+ */
354
+ ui?: (ctx: GameContext<Sim, R>) => GameUiHandle | Promise<GameUiHandle>;
355
+
356
+ // ── Event routing (sim-worker games only) ──
357
+ /** Declarative sim→renderer event handler map. Replaces the switch block.
358
+ * Ignored for renderer-only games (no sim worker to emit events). */
359
+ events?: SimEventMap<GameContext<Sim, R>>;
360
+
361
+ // ── Save ──
362
+ /** Save configuration. If omitted, no autosave is wired. */
363
+ save?: GameSaveConfig;
364
+ /** Renderer-side save source for renderer-only games. When declared, the
365
+ * autosave wiring calls `saveSource.save()` instead of `sim.save()`.
366
+ * Ignored for sim-worker games (the sim worker's `save()` is used). */
367
+ saveSource?: GameSaveSource;
368
+
369
+ // ── Engine libraries ──
370
+ /**
371
+ * Engine libraries to auto-wire (water, physics, terrain, etc.).
372
+ * Each entry is either a bare `EngineLibrary` (uses default config) or
373
+ * a `[library, config]` tuple to override config.
374
+ *
375
+ * The host allocates SABs, instantiates sim-side systems + renderer-side
376
+ * passes, and registers provided resources in the DI graph.
377
+ *
378
+ * Games can still import and wire library classes manually (escape hatch)
379
+ * if they need more control than the descriptor provides.
380
+ */
381
+ libraries?: LibraryEntry[];
382
+
383
+ // ── User-authored plugins (modding) ──
384
+ /**
385
+ * Plugin runtime configuration. When declared, `startGame()` constructs a
386
+ * renderer-side `PluginHost`, discovers plugins from the configured sources,
387
+ * and loads them after renderer init. Sim-thread plugins are forwarded to
388
+ * the sim worker. See `PluginRuntimeConfig`.
389
+ */
390
+ plugins?: PluginRuntimeConfig;
391
+
392
+ // ── DevTools ──
393
+ /** DevTools config. If omitted, DevTools is not wired. */
394
+ devtools?: BootstrapDevToolsOptions;
395
+
396
+ // ── MCP ──
397
+ /** Called to register MCP tools (after renderer is started). Receives ctx. */
398
+ mcp?: (ctx: GameContext<Sim, R>) => void | Promise<void>;
399
+
400
+ // ── Hooks ──
401
+ /**
402
+ * Called after renderer creation, before init. Use to wire sim-ready
403
+ * listeners, capture early state, etc. The renderer exists but is not
404
+ * initialized yet.
405
+ */
406
+ onBeforeInit?: (ctx: GameContext<Sim, R>) => Promise<void> | void;
407
+ /**
408
+ * Called to initialize the renderer. Should return false on failure.
409
+ * Default: calls `renderer.init()`. The sim worker is started in parallel
410
+ * (see `onSimStart`). Override to add LUT waits, player spawn, etc.
411
+ */
412
+ onInit?: (ctx: GameContext<Sim, R>) => Promise<boolean> | boolean;
413
+ /**
414
+ * Called to start the sim worker (only when `sim` is declared and `onInit`
415
+ * is NOT overridden). Default: calls `sim.start(simConfig)`. Override to
416
+ * add player spawn after sim is ready. Ignored for renderer-only games.
417
+ *
418
+ * When `onInit` IS overridden, the game's `onInit` owns sim start — this
419
+ * hook is not called. This lets games start the sim in parallel with
420
+ * `renderer.init()` (e.g. to-the-ocean does `Promise.all([renderer.init(),
421
+ * sim.start(config)])` in its `onInit`).
422
+ */
423
+ onSimStart?: (ctx: GameContext<Sim, R>) => Promise<void> | void;
424
+ /**
425
+ * Called after renderer init + sim start succeed, before render loop.
426
+ * This is the main game-specific wiring hook: setBuffers, OSR, sim bridge,
427
+ * DevTools, gizmo handlers, HUD polling, debug toggles, hot-reload.
428
+ */
429
+ onReady?: (ctx: GameContext<Sim, R>) => Promise<void> | void;
430
+ /** Called on Vite hot-reload dispose to clean up resources. */
431
+ onDispose?: (ctx: GameContext<Sim, R>) => Promise<void> | void;
432
+ /** Called in deterministic mode to apply overrides (e.g. pause render loop). */
433
+ onDeterministic?: (ctx: GameContext<Sim, R>) => void;
434
+ /** Called periodically with the current render FPS. */
435
+ onFpsUpdate?: (fps: number, ctx: GameContext<Sim, R>) => void;
436
+ /** Called with the display refresh rate when available. */
437
+ onDisplayInfo?: (refreshRate: number, ctx: GameContext<Sim, R>) => void;
438
+
439
+ // ── Surface ──
440
+ /** Surface layer index. Default: 0 — the only layer on native hosts. */
441
+ canvasLayer?: number;
442
+ /** FPS polling interval in ms. Default: 500. */
443
+ fpsPollIntervalMs?: number;
444
+
445
+ // ── Feature log ──
446
+ /** Optional getter for active plugin names (populates the `plug` field of the
447
+ * renderer feature log line). e.g. () => gameWorld.moduleHost.listModules() */
448
+ getActiveModules?: () => string[];
449
+ }
450
+
451
+ // ── startGame() ──
452
+
453
+ /**
454
+ * Start a game from a declarative `GameModule`.
455
+ *
456
+ * This is the high-level entry point. It wraps `bootstrapGame()` and adds:
457
+ * - Engine library auto-wiring (SAB allocation, sim systems, renderer passes)
458
+ * - Sim worker spawn + SAB capture (skipped for renderer-only games)
459
+ * - Declarative event routing (the `events` map — sim-worker games only)
460
+ * - Save store initialization (sim-worker or renderer-side save source)
461
+ * - Typed `GameContext` passed to all hooks
462
+ *
463
+ * Two topologies are supported:
464
+ * - **Sim-worker**: `module.sim` is declared → worker spawned, SABs captured,
465
+ * events routed, sim started after renderer init.
466
+ * - **Renderer-only**: `module.sim` is omitted → no worker, no SABs, no
467
+ * event routing. All logic runs on the renderer thread. Declare
468
+ * `module.saveSource` for autosave support.
469
+ *
470
+ * Games that need full control can call `bootstrapGame()` directly.
471
+ */
472
+ export async function startGame<Sim extends GameSimWorker, R extends GameRendererLike = GameRendererLike>(module: GameModule<Sim, R>): Promise<void> {
473
+ const deterministic = !!(downdraft as any)?.deterministic;
474
+ const isDev = !!(downdraft?.isDev) || isDevMode;
475
+ const hasSim = !!module.sim;
476
+
477
+ // 0. Resolve the render surface (NativeSurface on the native runtime)
478
+ const surface = getSurface(module.canvasLayer ?? 0);
479
+
480
+ // 0b. Allocate library SABs (if any libraries declared) — before sim worker
481
+ // creation so the sim factory can receive externally-allocated SABs.
482
+ let libHost: LibraryHost | null = null;
483
+ let libBuffers: Record<string, SharedArrayBuffer> = {};
484
+ if (module.libraries && module.libraries.length > 0) {
485
+ libHost = new LibraryHostImpl(module.libraries);
486
+ libBuffers = libHost.allocateBuffers();
487
+ }
488
+
489
+ // 0c. Construct the renderer-side plugin host (if plugins declared).
490
+ // Sim-thread plugins are forwarded to the sim worker after it starts;
491
+ // renderer/own-worker plugins load here. The host is exposed on ctx so
492
+ // games + the doctor panel can query snapshots.
493
+ let pluginHost: PluginHost | null = null;
494
+ if (module.plugins) {
495
+ const pCfg = module.plugins;
496
+ const hostOpts: PluginHostOptions = {
497
+ gameId: (downdraft as any)?.appId ?? "unknown",
498
+ engineVersion: ENGINE_VERSION,
499
+ gameAllow: pCfg.permissions,
500
+ eventCatalog: pCfg.eventCatalog,
501
+ sources: pCfg.sources,
502
+ };
503
+ pluginHost = new PluginHost(hostOpts);
504
+ // Register the worker-js loader (handles own-worker plugins on renderer).
505
+ pluginHost.registerLoader(new WorkerPluginLoader());
506
+ // Pre-resolved manifests (tests / first-party plugins).
507
+ for (let _i23990 = 0, _it23990 = (pCfg.manifests ?? []), _n23990 = _it23990.length; _i23990 < _n23990; _i23990++) { const m = _it23990[_i23990];
508
+ pluginHost.discover(m, "inline");
509
+ };
510
+ // Manifests are discovered via the plugin host's discover() API. Here we
511
+ // only load what's been discovered so far.
512
+ }
513
+
514
+ // 1. Create sim worker + capture SABs (renderer-only games skip this).
515
+ // If libraries declared, pass the library-allocated SABs to the sim
516
+ // factory via a seed object so the sim can share them zero-copy.
517
+ const simSeed = Object.keys(libBuffers).length > 0 ? { libraryBuffers: libBuffers } : undefined;
518
+ const simWorker = hasSim ? module.sim!(simSeed as any) : null;
519
+ const simSAB = simWorker?.getSimBuffer();
520
+ const inputSAB = simWorker?.getInputBuffer();
521
+ const extraBuffers = simWorker?.getExtraBuffers?.() ?? {};
522
+
523
+ // 2. Create renderer
524
+ const renderer = module.renderer(surface);
525
+
526
+ // 3. Build the game context. Sim fields are undefined for renderer-only games.
527
+ const ctx: GameContext<Sim, R> = {
528
+ renderer,
529
+ surface,
530
+ sim: simWorker as Sim | undefined,
531
+ simSAB,
532
+ inputSAB,
533
+ extraBuffers,
534
+ saveStore: null,
535
+ saveMode: "host",
536
+ saveSource: module.saveSource,
537
+ bridge: downdraft,
538
+ deterministic,
539
+ isDev,
540
+ };
541
+
542
+ // 3b. Merge library SABs into extraBuffers + store host on ctx
543
+ if (libHost) {
544
+ for (const [name, sab] of Object.entries(libBuffers)) {
545
+ ctx.extraBuffers[name] = sab;
546
+ }
547
+ ctx.libraryHost = libHost;
548
+ }
549
+
550
+ // 3c. Expose the plugin host on ctx (if constructed).
551
+ if (pluginHost) {
552
+ ctx.pluginHost = pluginHost;
553
+ }
554
+
555
+ // Event kinds emitted by the engine itself (sim-worker-base lifecycle)
556
+ // that games are not required to handle — suppress the dev warning for
557
+ // these so autosave doesn't spam the console when no handler is wired.
558
+ const ENGINE_EMITTED_EVENT_KINDS = new Set(["ready", "saved", "loaded", "error"]);
559
+
560
+ // 4. Wire event routing from the declarative events map (sim-worker only).
561
+ // Supports both GameSimWorker.onEvent(cb) and SimWorkerHost's
562
+ // subscribeEvents(cb) (renderer-owned worker hosts).
563
+ const wireSimEvents = (worker: Sim) => {
564
+ if (!module.events || !worker) return;
565
+ const events = module.events;
566
+ // Prefer subscribeEvents when present: SimWorkerHost subclasses expose it
567
+ // as the public registration API, while their protected onEvent(kind,data)
568
+ // is the internal dispatcher (and would be incorrectly bound if we probed
569
+ // onEvent first — it exists on the prototype at runtime).
570
+ const onEvent: ((cb: (msg: any) => void) => void) | undefined =
571
+ (worker as any).subscribeEvents
572
+ ? (cb: (msg: any) => void) => { (worker as any).subscribeEvents(cb); }
573
+ : (worker as any).onEvent?.bind(worker);
574
+ if (!onEvent) return;
575
+ onEvent((msg) => {
576
+ const handler = events[msg.kind];
577
+ if (handler) {
578
+ try {
579
+ handler(msg.data, ctx);
580
+ } catch (err) {
581
+ log.error("startGame", `Event handler error for "${msg.kind}": ${err}`);
582
+ }
583
+ } else if (isDev && !ENGINE_EMITTED_EVENT_KINDS.has(msg.kind)) {
584
+ log.warn("startGame", `Unhandled sim event kind: "${msg.kind}"`);
585
+ }
586
+ });
587
+ };
588
+ if (simWorker) wireSimEvents(simWorker);
589
+
590
+ // 5. Run onBeforeInit hook
591
+ if (module.onBeforeInit) {
592
+ await module.onBeforeInit(ctx);
593
+ }
594
+
595
+ // 6. Initialize save store (if configured) — for non-inline modes this
596
+ // runs before bootstrapGame so onReady can use it. For inline mode
597
+ // (sim-worker + OPFS), the store is initialized inside onRendererInit
598
+ // after the sim worker has started.
599
+ if (module.save && !deterministic) {
600
+ try {
601
+ // Default to "host" (disk via the host's typed save store) when the
602
+ // bridge exposes one — on native this is HostSaveStore over
603
+ // HostServices. Fall back to "auto" (OPFS) only in a pure browser
604
+ // where there is no host bridge.
605
+ const saveMode = module.save.mode ?? (downdraft.saveStore ? "host" : "auto");
606
+ if (saveMode === "auto" && simWorker?.initSaveStore && isOpfsAvailable() && !downdraft.saveStore) {
607
+ // Inline mode — defer init to onRendererInit (after sim worker starts).
608
+ ctx.saveMode = "inline";
609
+ ctx.saveStore = null;
610
+ } else {
611
+ const { store, mode: resolvedMode } = await createSaveStore({
612
+ mode: saveMode,
613
+ opfsOptions: {
614
+ engineVersion: module.save.engineVersion,
615
+ maxGenerations: module.save.maxGenerations ?? 3,
616
+ },
617
+ bridge: downdraft,
618
+ });
619
+ ctx.saveStore = store;
620
+ // resolvedMode is "worker" | "host" | "inline" (inline returns a
621
+ // null store); narrow to the ctx.saveMode union accordingly.
622
+ ctx.saveMode = resolvedMode === "inline" ? "inline"
623
+ : resolvedMode === "worker" ? "worker" : "host";
624
+ }
625
+ } catch (e) {
626
+ log.warn("startGame", `Save store init failed, falling back to host bridge: ${e}`);
627
+ ctx.saveMode = "host";
628
+ }
629
+ }
630
+
631
+ // 6b. Mode-aware save/load helpers — exposed on ctx so games can trigger manual
632
+ // saves/loads that work regardless of the selected backend. This is the
633
+ // same logic the autosave interval uses below. Games MUST use ctx.save /
634
+ // ctx.load instead of sim.save / sim.load directly: sim.save only writes
635
+ // in inline mode (it has its own OPFS store) and silently drops the save
636
+ // in host mode (it returns stateJson but nothing forwards it to disk).
637
+ if (module.save && !deterministic) {
638
+ ctx.save = async (slotName: string): Promise<boolean> => {
639
+ try {
640
+ // Renderer-side save source takes priority (renderer-only games);
641
+ // otherwise fall back to the sim worker's save() (sim-worker games).
642
+ // ctx.sim covers simFromRenderer games, resolved after renderer init.
643
+ const sim = ctx.sim ?? simWorker;
644
+ const result = ctx.saveSource
645
+ ? await ctx.saveSource.save(slotName)
646
+ : sim?.save
647
+ ? await sim.save(slotName)
648
+ : null;
649
+ // In inline mode, the sim worker's save() already persisted to its own
650
+ // OPFS store — nothing more to do. In host/worker mode the sim worker
651
+ // only serialized — the renderer owns the store write.
652
+ if (result?.stateJson && ctx.saveMode !== "inline" && ctx.saveStore) {
653
+ const components = JSON.parse(result.stateJson);
654
+ const state: SaveState = {
655
+ components,
656
+ meta: {
657
+ engineVersion: module.save?.engineVersion ?? "",
658
+ timestamp: Date.now() / 1000,
659
+ entityCount: 0,
660
+ playerCount: 0,
661
+ // Real SaveMeta from the worker's save.meta() hook wins.
662
+ ...result.meta,
663
+ },
664
+ };
665
+ const sr = await ctx.saveStore.save(slotName, state);
666
+ return result.success !== false && sr.success;
667
+ }
668
+ return result?.success ?? false;
669
+ } catch (e) {
670
+ log.error("startGame", `Manual save failed: ${e}`);
671
+ return false;
672
+ }
673
+ };
674
+
675
+ ctx.load = async (slotName: string): Promise<unknown | null> => {
676
+ try {
677
+ // Renderer-side save source load (renderer-only games)
678
+ if (ctx.saveSource?.load) {
679
+ const stateJson = await ctx.saveSource.load(slotName);
680
+ return stateJson ? JSON.parse(stateJson) : null;
681
+ }
682
+ // ctx.sim covers simFromRenderer games (resolved post renderer-init).
683
+ const sim = ctx.sim ?? simWorker;
684
+ // Inline mode: sim worker loads directly from its own OPFS store.
685
+ // The sim worker's load() restores state internally; we just need a
686
+ // truthy return value so any onLoad hook fires.
687
+ if (ctx.saveMode === "inline" && sim?.load) {
688
+ const success = await sim.load(slotName);
689
+ return success ? { restored: true } : null;
690
+ }
691
+ if (ctx.saveStore) {
692
+ const result = await ctx.saveStore.load(slotName);
693
+ const state = result?.state ?? null;
694
+ if (state && sim?.restoreFromState) {
695
+ // The save store returns a SaveState with `components`. Each
696
+ // component has { v, data } structure — forward the restore
697
+ // payload to the sim worker.
698
+ const components = (state as any).components;
699
+ if (components) {
700
+ const payload = serializeRestorePayload(components, module.save?.componentName);
701
+ if (payload !== undefined) {
702
+ await sim.restoreFromState(payload);
703
+ }
704
+ }
705
+ }
706
+ return state;
707
+ }
708
+ if (downdraft?.loadGameState) {
709
+ const stateJson = await downdraft.loadGameState(slotName);
710
+ if (!stateJson) return null;
711
+ // The host bridge returns JSON.stringify(result.state.components),
712
+ // so the parsed result is the components map directly (not a
713
+ // SaveState). Find the game component (e.g. "sandbox") and
714
+ // forward its `data` to the sim worker.
715
+ let parsed: unknown = null;
716
+ try {
717
+ parsed = JSON.parse(stateJson);
718
+ } catch {
719
+ // Non-JSON payload — fall through to raw restore.
720
+ }
721
+ if (sim?.restoreFromState) {
722
+ const components = parsed as Record<string, { data?: unknown }> | null;
723
+ const payload = components && typeof components === "object"
724
+ ? serializeRestorePayload(components, module.save?.componentName)
725
+ : undefined;
726
+ if (payload !== undefined) {
727
+ await sim.restoreFromState(payload);
728
+ } else {
729
+ // No recognizable components map — forward the raw payload.
730
+ await sim.restoreFromState(stateJson);
731
+ }
732
+ }
733
+ // Return the parsed payload (or the raw string when it isn't JSON)
734
+ // — the previous version re-parsed unconditionally here, so a
735
+ // successful raw restore still reported failure.
736
+ return parsed ?? stateJson;
737
+ }
738
+ return null;
739
+ } catch (e) {
740
+ log.error("startGame", `Manual load failed: ${e}`);
741
+ return null;
742
+ }
743
+ };
744
+ }
745
+
746
+ // 7. Delegate to bootstrapGame() for the standard sequence
747
+ await bootstrapGame({
748
+ canvasLayer: module.canvasLayer,
749
+ fpsPollIntervalMs: module.fpsPollIntervalMs,
750
+ getActiveModules: module.getActiveModules,
751
+
752
+ createRenderer: () => renderer,
753
+
754
+ initRenderer: module.onInit
755
+ ? () => module.onInit!(ctx)
756
+ : (r) => r.init(),
757
+
758
+ onRendererInit: async (r) => {
759
+ // ── Library renderer setup ──
760
+ // Early renderer-only library setup (hosts, workers — no GPU needed).
761
+ // Runs before the GPU device is available so libraries can construct
762
+ // their host + provide DI tokens.
763
+ if (libHost && r) {
764
+ const device = r.getDevice?.();
765
+ const format = r.getFormat?.();
766
+ const moduleHost = r.getRendererModuleHost?.();
767
+ const libProvide = (token: any, value: unknown) => {
768
+ if (moduleHost) moduleHost.provideExternal("library", token, value);
769
+ };
770
+ const libInject = (token: any) => {
771
+ if (moduleHost) return moduleHost.injectResource(token);
772
+ throw new Error(`Library inject("${token.key}") failed — no renderer plugin host available`);
773
+ };
774
+ const libInjectOptional = (token: any) => {
775
+ if (moduleHost) return moduleHost.injectResourceOptional(token);
776
+ return undefined;
777
+ };
778
+ libHost.createRenderer({ provide: libProvide, inject: libInject, injectOptional: libInjectOptional });
779
+ // GPU-pass library init (after device is ready).
780
+ if (device && format) {
781
+ libHost.initRenderer({ device, format, provide: libProvide, inject: libInject, injectOptional: libInjectOptional });
782
+ libHost.setRendererBuffers(libBuffers);
783
+ }
784
+ }
785
+
786
+ // ── Renderer-owned sim resolution ──
787
+ // Games whose renderer spawns/starts the sim worker internally (declared
788
+ // via `module.simFromRenderer` instead of `module.sim`) get the worker
789
+ // resolved here — after renderer.init() has created it. ctx.sim is
790
+ // populated and declarative `events` routing is wired, matching the
791
+ // factory-created path. startGame() never calls start() on it — the
792
+ // renderer owns the lifecycle.
793
+ if (module.simFromRenderer) {
794
+ try {
795
+ const owned = await module.simFromRenderer(r, ctx);
796
+ if (owned) {
797
+ ctx.sim = owned;
798
+ ctx.simSAB = owned.getSimBuffer();
799
+ ctx.inputSAB = owned.getInputBuffer();
800
+ const extra = owned.getExtraBuffers?.() ?? {};
801
+ for (const [name, sab] of Object.entries(extra)) {
802
+ ctx.extraBuffers[name] = sab;
803
+ }
804
+ wireSimEvents(owned);
805
+ }
806
+ } catch (e) {
807
+ log.warn("startGame", `simFromRenderer resolution failed: ${e}`);
808
+ }
809
+ }
810
+
811
+ // ── Sim worker start ──
812
+ // When `onInit` is NOT overridden, startGame owns sim start — it runs
813
+ // here, after renderer.init() has succeeded. When `onInit` IS overridden,
814
+ // the game's onInit owns sim start (e.g. to-the-ocean starts the sim in
815
+ // parallel with renderer.init() inside its onInit). Renderer-only games
816
+ // have no sim worker to start.
817
+ if (simWorker && !module.onInit) {
818
+ if (module.onSimStart) {
819
+ await module.onSimStart(ctx);
820
+ } else {
821
+ await simWorker.start(module.simConfig ?? {});
822
+ }
823
+ }
824
+
825
+ // ── Inline save store init (sim-worker + OPFS) ──
826
+ // Now that the sim worker is started, initialize its inline OPFS store.
827
+ // This must happen before the autosave load (which runs in bootstrapGame
828
+ // after onRendererInit returns) so that the sim worker can load from OPFS.
829
+ if (ctx.saveMode === "inline" && (ctx.sim ?? simWorker)?.initSaveStore && module.save) {
830
+ try {
831
+ await (ctx.sim ?? simWorker)!.initSaveStore!({
832
+ engineVersion: module.save.engineVersion,
833
+ maxGenerations: module.save.maxGenerations ?? 3,
834
+ });
835
+ } catch (e) {
836
+ log.warn("startGame", `Inline save store init failed, falling back to host save store: ${e}`);
837
+ ctx.saveMode = "host";
838
+ }
839
+ }
840
+
841
+ // ── Plugin loading ──
842
+ // Load all discovered plugins (renderer + own-worker threads). Sim-
843
+ // thread plugins are forwarded to the sim worker by the game's sim
844
+ // bridge (the sim worker runs its own PluginHost); here we load the
845
+ // renderer/own-worker subset. Failures are recorded on the plugin
846
+ // snapshot (ctx.pluginHost.snapshot()) and do not abort startup.
847
+ if (pluginHost) {
848
+ try {
849
+ // Wire the renderer's ModuleHost now that it exists — required for
850
+ // native-tier plugins (their context bridges into the typed-DI
851
+ // graph). Without it a native-tier mod fails with "no ModuleHost
852
+ // configured on this thread".
853
+ const mh = r?.getRendererModuleHost?.();
854
+ if (mh) pluginHost.setModuleHost(mh);
855
+ await pluginHost.loadAll();
856
+ } catch (e) {
857
+ log.warn("startGame", `Plugin loading error: ${e}`);
858
+ }
859
+ }
860
+
861
+ // ── Declarative UI lifecycle ──
862
+ // Create + start the UI handle before onReady so
863
+ // hooks can wire subscriptions against ctx.ui.
864
+ if (module.ui) {
865
+ try {
866
+ ctx.ui = await module.ui(ctx);
867
+ await ctx.ui.start();
868
+ } catch (e) {
869
+ // UI failure is non-fatal — the game canvas still runs.
870
+ log.error("startGame", `UI start failed: ${e}`);
871
+ ctx.ui = undefined;
872
+ }
873
+ }
874
+
875
+ // ── Game-specific wiring ──
876
+ if (module.onReady) {
877
+ await module.onReady(ctx);
878
+ }
879
+ },
880
+
881
+ devtools: module.devtools,
882
+
883
+ autosave: module.save && !deterministic
884
+ ? {
885
+ // Reuse the mode-aware ctx.save / ctx.load helpers so the autosave
886
+ // interval and manual saves share one code path.
887
+ load: async () => {
888
+ const slotName = module.save!.slotName ?? "autosave";
889
+ return ctx.load!(slotName);
890
+ },
891
+ save: async () => {
892
+ const slotName = module.save!.slotName ?? "autosave";
893
+ await ctx.save!(slotName);
894
+ },
895
+ intervalMs: module.save?.intervalMs,
896
+ }
897
+ : undefined,
898
+
899
+ mcp: module.mcp ? () => module.mcp!(ctx) : undefined,
900
+
901
+ onDisplayInfo: module.onDisplayInfo
902
+ ? (rate) => module.onDisplayInfo!(rate, ctx)
903
+ : undefined,
904
+
905
+ onHotReloadDispose: () => {
906
+ ctx.ui?.dispose();
907
+ ctx.ui = undefined;
908
+ pluginHost?.disposeAll();
909
+ libHost?.disposeRenderer();
910
+ if (module.onDispose) {
911
+ module.onDispose(ctx);
912
+ }
913
+ },
914
+
915
+ onDeterministic: module.onDeterministic
916
+ ? () => module.onDeterministic!(ctx)
917
+ : undefined,
918
+
919
+ onFpsUpdate: module.onFpsUpdate
920
+ ? (fps) => module.onFpsUpdate!(fps, ctx)
921
+ : undefined,
922
+ });
923
+ }