@downdraft/engine 0.1.1 → 0.2.0

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 (1034) hide show
  1. package/app/README.md +11 -0
  2. package/app/src/renderer/bootstrap.ts +295 -19
  3. package/app/src/renderer/feature-log.ts +1 -1
  4. package/app/src/renderer/game-module.ts +60 -12
  5. package/app/src/renderer/hooks.ts +9 -1
  6. package/app/src/renderer/hot-reload.ts +9 -9
  7. package/app/src/renderer/mcp-harness.ts +2 -2
  8. package/app/src/renderer/standard-automation-tools.ts +104 -3
  9. package/app/src/shared/feature-log.ts +2 -1
  10. package/app/src/shared/mcp-discovery.ts +8 -3
  11. package/app/src/shared/mcp-proxy.ts +2 -2
  12. package/asset-bake/README.md +22 -0
  13. package/core/README.md +25 -0
  14. package/core/src/animation/skeleton-animator.ts +23 -5
  15. package/core/src/assets/manager.ts +4 -4
  16. package/core/src/ecs/events.ts +1 -1
  17. package/core/src/ecs/schedule.ts +1 -1
  18. package/core/src/ecs/world.ts +1 -1
  19. package/core/src/index.ts +3 -4
  20. package/core/src/input/local-player-manager.ts +2 -2
  21. package/core/src/library/host.ts +27 -13
  22. package/core/src/library/library.ts +13 -5
  23. package/core/src/module/cross-thread.ts +6 -0
  24. package/core/src/module/diagnostics.ts +10 -6
  25. package/core/src/module/host.ts +65 -18
  26. package/core/src/module/index.ts +1 -0
  27. package/core/src/module/module.ts +11 -5
  28. package/core/src/module/renderer-module.ts +15 -0
  29. package/core/src/physics/safety.ts +1 -1
  30. package/core/src/platform/bun-preload.ts +7 -2
  31. package/core/src/platform/glob-polyfill.ts +17 -8
  32. package/core/src/platform/pkg-root.ts +27 -0
  33. package/core/src/platform/runtime.ts +29 -0
  34. package/core/src/plugin/discovery.ts +1 -1
  35. package/core/src/plugin/extension-loaders.ts +6 -4
  36. package/core/src/plugin/host.ts +13 -13
  37. package/core/src/plugin/loader-asset.ts +5 -5
  38. package/core/src/plugin/loader-quickjs.ts +1 -1
  39. package/core/src/plugin/loader-wasm.ts +3 -3
  40. package/core/src/plugin/loader-worker.ts +1 -1
  41. package/core/src/plugin/manifest.ts +8 -3
  42. package/core/src/plugin/workshop.ts +3 -3
  43. package/core/src/profiling/index.ts +1 -1
  44. package/core/src/profiling/profiling-sab.ts +19 -0
  45. package/core/src/profiling/warnings.ts +1 -1
  46. package/core/src/profiling/worker-prelude.ts +1 -1
  47. package/core/src/render/bindless/frame-bindings.ts +1 -1
  48. package/core/src/render/bindless/material-manager.ts +2 -2
  49. package/core/src/render/bindless/texture-registry.ts +2 -2
  50. package/core/src/render/device.ts +5 -5
  51. package/core/src/render/frame-graph.ts +2 -2
  52. package/core/src/render/game-renderer.ts +42 -18
  53. package/core/src/render/hot-reload.ts +3 -3
  54. package/core/src/render/renderer-module-host.ts +32 -12
  55. package/core/src/render/shader-validator.ts +7 -7
  56. package/core/src/render/surface.ts +1 -1
  57. package/core/src/sab/errors.ts +1 -1
  58. package/core/src/sab/sab-polyfill.ts +1 -1
  59. package/core/src/save/migration-registry.ts +4 -4
  60. package/core/src/save/schema.ts +1 -1
  61. package/core/src/scene/prefab.ts +1 -1
  62. package/core/src/scene/scene-manager.ts +2 -2
  63. package/core/src/scene/scene.ts +4 -4
  64. package/core/src/scene/streaming.ts +2 -2
  65. package/core/src/scripting/hot-reload.ts +2 -2
  66. package/core/src/sim/hot-reload-pipeline.ts +30 -6
  67. package/core/src/sim/sim-state-helper.ts +1 -1
  68. package/core/src/sim/transient-state-registry.ts +1 -1
  69. package/core/src/sim/worker-loop.ts +2 -2
  70. package/core/src/telemetry/gpu-profiler.ts +3 -3
  71. package/core/src/util/index.ts +1 -1
  72. package/core/src/util/logger.ts +38 -7
  73. package/core/src/version.ts +13 -0
  74. package/core/src/worker/base-worker-host.ts +87 -25
  75. package/core/src/worker/buffer-sync.ts +1 -1
  76. package/core/src/worker/crash-recovery.ts +2 -2
  77. package/core/src/worker/instrumented-worker-host.ts +3 -3
  78. package/core/src/worker/rpc.ts +62 -11
  79. package/core/src/worker/sim-worker-base.ts +4 -9
  80. package/core/src/worker/task-pool.ts +2 -2
  81. package/dist/.dd-manifest.json +4119 -0
  82. package/dist/app/src/index.js +9 -0
  83. package/dist/app/src/renderer/bootstrap.js +446 -0
  84. package/dist/app/src/renderer/downdraft-base.css +93 -0
  85. package/dist/app/src/renderer/feature-log.js +180 -0
  86. package/dist/app/src/renderer/game-module.js +562 -0
  87. package/dist/app/src/renderer/hooks.js +82 -0
  88. package/dist/app/src/renderer/hot-reload.js +158 -0
  89. package/dist/app/src/renderer/import-cache.js +77 -0
  90. package/dist/app/src/renderer/index.js +149 -0
  91. package/dist/app/src/renderer/mcp-harness.js +112 -0
  92. package/dist/app/src/renderer/save-store-factory.js +180 -0
  93. package/dist/app/src/renderer/sim-bridge.js +138 -0
  94. package/dist/app/src/renderer/standard-automation-tools.js +720 -0
  95. package/dist/app/src/shared/feature-log.js +54 -0
  96. package/dist/app/src/shared/gpu-info.js +74 -0
  97. package/dist/app/src/shared/import-cache-store.js +123 -0
  98. package/dist/app/src/shared/index.js +4 -0
  99. package/dist/app/src/shared/mcp-discovery.js +55 -0
  100. package/dist/app/src/shared/mcp-proxy.js +71 -0
  101. package/dist/app/src/shared/types.js +13 -0
  102. package/dist/asset-bake/src/bake-audio.js +103 -0
  103. package/dist/asset-bake/src/bake-gltf.js +141 -0
  104. package/dist/asset-bake/src/bake.js +63 -0
  105. package/dist/asset-bake/src/cache.js +147 -0
  106. package/dist/asset-bake/src/config.js +93 -0
  107. package/dist/asset-bake/src/index.js +25 -0
  108. package/dist/core/src/animation/animation-event.js +24 -0
  109. package/dist/core/src/animation/bone-mask.js +103 -0
  110. package/dist/core/src/animation/clip.js +210 -0
  111. package/dist/core/src/animation/index.js +13 -0
  112. package/dist/core/src/animation/mixamo.js +78 -0
  113. package/dist/core/src/animation/morph-target.js +37 -0
  114. package/dist/core/src/animation/player.js +621 -0
  115. package/dist/core/src/animation/retarget.js +101 -0
  116. package/dist/core/src/animation/skeleton-animator.js +1361 -0
  117. package/dist/core/src/animation/skeleton.js +166 -0
  118. package/dist/core/src/animation/state-machine.js +252 -0
  119. package/dist/core/src/assets/blob-store.js +14 -0
  120. package/dist/core/src/assets/cache.js +168 -0
  121. package/dist/core/src/assets/cubemap-converter.js +129 -0
  122. package/dist/core/src/assets/environment-manager.js +84 -0
  123. package/dist/core/src/assets/import-cache.js +36 -0
  124. package/dist/core/src/assets/import-settings.js +34 -0
  125. package/dist/core/src/assets/importer.js +78 -0
  126. package/dist/core/src/assets/index.js +29 -0
  127. package/dist/core/src/assets/irradiance-generator.js +179 -0
  128. package/dist/core/src/assets/loader-audio.js +70 -0
  129. package/dist/core/src/assets/loader-cubemap.js +141 -0
  130. package/dist/core/src/assets/loader-dds.js +185 -0
  131. package/dist/core/src/assets/loader-hdr.js +430 -0
  132. package/dist/core/src/assets/loader-mesh.js +47 -0
  133. package/dist/core/src/assets/loader-shader.js +61 -0
  134. package/dist/core/src/assets/loader-texture.js +264 -0
  135. package/dist/core/src/assets/lod.js +150 -0
  136. package/dist/core/src/assets/manager.js +401 -0
  137. package/dist/core/src/assets/manifest.js +57 -0
  138. package/dist/core/src/assets/material-bridge.js +160 -0
  139. package/dist/core/src/assets/model-importer.js +32 -0
  140. package/dist/core/src/assets/model-normalizer.js +213 -0
  141. package/dist/core/src/assets/model-to-gpu.js +44 -0
  142. package/dist/core/src/assets/model-to-mesh.js +171 -0
  143. package/dist/core/src/assets/prefilter-generator.js +220 -0
  144. package/dist/core/src/audio/engine.js +153 -0
  145. package/dist/core/src/audio/interface.js +8 -0
  146. package/dist/core/src/audio/listener.js +19 -0
  147. package/dist/core/src/audio/mixer.js +124 -0
  148. package/dist/core/src/audio/registry.js +43 -0
  149. package/dist/core/src/audio/sab.js +74 -0
  150. package/dist/core/src/audio/source.js +60 -0
  151. package/dist/core/src/change-detection/atomics.js +1 -0
  152. package/dist/core/src/change-detection/tracker.js +26 -0
  153. package/dist/core/src/debug-draw/lines.js +27 -0
  154. package/dist/core/src/debug-draw/points.js +9 -0
  155. package/dist/core/src/debug-draw/queue.js +77 -0
  156. package/dist/core/src/debug-draw/text.js +12 -0
  157. package/dist/core/src/ecs/archetype.js +271 -0
  158. package/dist/core/src/ecs/component.js +109 -0
  159. package/dist/core/src/ecs/entity.js +11 -0
  160. package/dist/core/src/ecs/events.js +73 -0
  161. package/dist/core/src/ecs/hierarchy.js +104 -0
  162. package/dist/core/src/ecs/hmr-swap-registry.js +15 -0
  163. package/dist/core/src/ecs/index.js +14 -0
  164. package/dist/core/src/ecs/query.js +110 -0
  165. package/dist/core/src/ecs/resource.js +3 -0
  166. package/dist/core/src/ecs/schedule.js +157 -0
  167. package/dist/core/src/ecs/system-params.js +45 -0
  168. package/dist/core/src/ecs/system.js +18 -0
  169. package/dist/core/src/ecs/world.js +292 -0
  170. package/dist/core/src/index.js +191 -0
  171. package/dist/core/src/input/context.js +69 -0
  172. package/dist/core/src/input/dom-handler.js +288 -0
  173. package/dist/core/src/input/local-player-manager.js +145 -0
  174. package/dist/core/src/input/mapping.js +36 -0
  175. package/dist/core/src/input/multi-sab-bridge.js +224 -0
  176. package/dist/core/src/input/multi-state.js +48 -0
  177. package/dist/core/src/input/sab-bridge.js +66 -0
  178. package/dist/core/src/input/state.js +108 -0
  179. package/dist/core/src/input/ui-router.js +76 -0
  180. package/dist/core/src/library/host.js +291 -0
  181. package/dist/core/src/library/index.js +1 -0
  182. package/dist/core/src/library/library.js +20 -0
  183. package/dist/core/src/material/compiler.js +73 -0
  184. package/dist/core/src/material/graph-bridge.js +119 -0
  185. package/dist/core/src/material/index.js +6 -0
  186. package/dist/core/src/material/library.js +414 -0
  187. package/dist/core/src/material/material.js +120 -0
  188. package/dist/core/src/material/variants.js +37 -0
  189. package/dist/core/src/math/mat4.js +198 -0
  190. package/dist/core/src/math/perlin-noise-2d.js +66 -0
  191. package/dist/core/src/math/perlin-noise-3d.js +76 -0
  192. package/dist/core/src/math/quat.js +29 -0
  193. package/dist/core/src/math/rng.js +25 -0
  194. package/dist/core/src/math/trig.js +42 -0
  195. package/dist/core/src/math/value-noise.js +49 -0
  196. package/dist/core/src/mesh/builder.js +137 -0
  197. package/dist/core/src/mesh/csg.js +250 -0
  198. package/dist/core/src/mesh/greased-line.js +102 -0
  199. package/dist/core/src/mesh/mesh.js +6 -0
  200. package/dist/core/src/mesh/parametric.js +392 -0
  201. package/dist/core/src/mesh/skinning.js +30 -0
  202. package/dist/core/src/mesh/vertex-layout.js +65 -0
  203. package/dist/core/src/module/cross-thread.js +126 -0
  204. package/dist/core/src/module/diagnostics.js +99 -0
  205. package/dist/core/src/module/host.js +449 -0
  206. package/dist/core/src/module/index.js +6 -0
  207. package/dist/core/src/module/module.js +1 -0
  208. package/dist/core/src/module/registry.js +83 -0
  209. package/dist/core/src/module/renderer-module.js +13 -0
  210. package/dist/core/src/module/ts-loader.js +20 -0
  211. package/dist/core/src/particles/compute-pass.js +329 -0
  212. package/dist/core/src/particles/emitter.js +113 -0
  213. package/dist/core/src/particles/index.js +7 -0
  214. package/dist/core/src/particles/particle-data.js +33 -0
  215. package/dist/core/src/particles/render-pass.js +338 -0
  216. package/dist/core/src/particles/simulator.js +224 -0
  217. package/dist/core/src/particles/system.js +157 -0
  218. package/dist/core/src/physics/body.js +25 -0
  219. package/dist/core/src/physics/ccd-heuristic.js +46 -0
  220. package/dist/core/src/physics/character.js +184 -0
  221. package/dist/core/src/physics/collider.js +36 -0
  222. package/dist/core/src/physics/collision-system.js +62 -0
  223. package/dist/core/src/physics/events.js +74 -0
  224. package/dist/core/src/physics/index.js +24 -0
  225. package/dist/core/src/physics/interface.js +14 -0
  226. package/dist/core/src/physics/interpolation-buffer.js +182 -0
  227. package/dist/core/src/physics/lifecycle.js +66 -0
  228. package/dist/core/src/physics/load-shedder.js +155 -0
  229. package/dist/core/src/physics/physics-accumulator.js +94 -0
  230. package/dist/core/src/physics/physics-system.js +142 -0
  231. package/dist/core/src/physics/ragdoll-presets.js +248 -0
  232. package/dist/core/src/physics/ragdoll-system.js +193 -0
  233. package/dist/core/src/physics/ragdoll.js +117 -0
  234. package/dist/core/src/physics/raycast.js +97 -0
  235. package/dist/core/src/physics/realm-manager.js +431 -0
  236. package/dist/core/src/physics/realm-worker-pool.js +181 -0
  237. package/dist/core/src/physics/realm-worker.js +91 -0
  238. package/dist/core/src/physics/realm.js +137 -0
  239. package/dist/core/src/physics/registry.js +43 -0
  240. package/dist/core/src/physics/safety.js +211 -0
  241. package/dist/core/src/physics/snapshot-manager.js +118 -0
  242. package/dist/core/src/physics/worker-protocol.js +1 -0
  243. package/dist/core/src/platform/bun-preload.js +175 -0
  244. package/dist/core/src/platform/css-stub.js +4 -0
  245. package/dist/core/src/platform/glob-polyfill.js +137 -0
  246. package/dist/core/src/platform/hidpi.js +52 -0
  247. package/dist/core/src/platform/pkg-root.js +27 -0
  248. package/dist/core/src/platform/render-surface.js +15 -0
  249. package/dist/core/src/platform/rpc.js +82 -0
  250. package/dist/core/src/platform/runtime.js +93 -0
  251. package/dist/core/src/plugin/context.js +144 -0
  252. package/dist/core/src/plugin/diagnostics.js +20 -0
  253. package/dist/core/src/plugin/discovery.js +124 -0
  254. package/dist/core/src/plugin/extension-loaders.js +111 -0
  255. package/dist/core/src/plugin/host.js +542 -0
  256. package/dist/core/src/plugin/index.js +19 -0
  257. package/dist/core/src/plugin/loader-asset.js +105 -0
  258. package/dist/core/src/plugin/loader-quickjs.js +67 -0
  259. package/dist/core/src/plugin/loader-wasm.js +385 -0
  260. package/dist/core/src/plugin/loader-worker.js +228 -0
  261. package/dist/core/src/plugin/manifest.js +424 -0
  262. package/dist/core/src/plugin/material-registry.js +44 -0
  263. package/dist/core/src/plugin/mcp-tools.js +147 -0
  264. package/dist/core/src/plugin/permissions.js +152 -0
  265. package/dist/core/src/plugin/quickjs-bridge.js +219 -0
  266. package/dist/core/src/plugin/registry.js +92 -0
  267. package/dist/core/src/plugin/sandbox-shim.js +79 -0
  268. package/dist/core/src/plugin/sandbox-worker.js +194 -0
  269. package/dist/core/src/plugin/wasm-abi.js +62 -0
  270. package/dist/core/src/plugin/wasm-worker.js +234 -0
  271. package/dist/core/src/plugin/workshop.js +131 -0
  272. package/dist/core/src/profiling/event-loop.js +164 -0
  273. package/dist/core/src/profiling/index.js +23 -0
  274. package/dist/core/src/profiling/iops/idb-patch.js +211 -0
  275. package/dist/core/src/profiling/iops/opfs-patch.js +206 -0
  276. package/dist/core/src/profiling/profiling-sab.js +632 -0
  277. package/dist/core/src/profiling/task-latency.js +118 -0
  278. package/dist/core/src/profiling/thread-metrics.js +103 -0
  279. package/dist/core/src/profiling/trace-event-writer.js +165 -0
  280. package/dist/core/src/profiling/warnings.js +304 -0
  281. package/dist/core/src/profiling/worker-prelude.js +281 -0
  282. package/dist/core/src/render/bind-group.js +33 -0
  283. package/dist/core/src/render/bindless/bindless-struct.js +39 -0
  284. package/dist/core/src/render/bindless/bindless.wgsl.js +163 -0
  285. package/dist/core/src/render/bindless/frame-bindings.js +142 -0
  286. package/dist/core/src/render/bindless/index.js +6 -0
  287. package/dist/core/src/render/bindless/material-manager.js +182 -0
  288. package/dist/core/src/render/bindless/texture-registry.js +498 -0
  289. package/dist/core/src/render/buffer.js +74 -0
  290. package/dist/core/src/render/camera-2d.js +151 -0
  291. package/dist/core/src/render/camera-controller.js +370 -0
  292. package/dist/core/src/render/camera.js +332 -0
  293. package/dist/core/src/render/canvas-resize-watcher.js +36 -0
  294. package/dist/core/src/render/compute-kernel.js +130 -0
  295. package/dist/core/src/render/constants.js +2 -0
  296. package/dist/core/src/render/device.js +91 -0
  297. package/dist/core/src/render/frame-graph.js +594 -0
  298. package/dist/core/src/render/frustum.js +152 -0
  299. package/dist/core/src/render/fullscreen-vs.js +24 -0
  300. package/dist/core/src/render/g-buffer.js +156 -0
  301. package/dist/core/src/render/game-renderer.js +1165 -0
  302. package/dist/core/src/render/gpu-driven/cull-pass.js +352 -0
  303. package/dist/core/src/render/gpu-driven/hzb.js +183 -0
  304. package/dist/core/src/render/gpu-driven/index.js +6 -0
  305. package/dist/core/src/render/gpu-driven/indirect-draw-pass.js +300 -0
  306. package/dist/core/src/render/gpu-driven/instance-buffer.js +150 -0
  307. package/dist/core/src/render/gpu-driven/mesh-table.js +130 -0
  308. package/dist/core/src/render/gpu-driven/passes/hzb-build-pass.js +39 -0
  309. package/dist/core/src/render/gpu-utils.js +72 -0
  310. package/dist/core/src/render/hdr.js +69 -0
  311. package/dist/core/src/render/hot-reload.js +236 -0
  312. package/dist/core/src/render/ibl-bind-group.js +232 -0
  313. package/dist/core/src/render/ibl.js +148 -0
  314. package/dist/core/src/render/index.js +86 -0
  315. package/dist/core/src/render/input-manager.js +224 -0
  316. package/dist/core/src/render/lighting/area-light.js +142 -0
  317. package/dist/core/src/render/lighting/cluster-grid.js +255 -0
  318. package/dist/core/src/render/lighting/cluster-types.js +87 -0
  319. package/dist/core/src/render/lighting/ies-parser.js +111 -0
  320. package/dist/core/src/render/lighting.js +300 -0
  321. package/dist/core/src/render/material-types/depth.wgsl +44 -0
  322. package/dist/core/src/render/material-types/line.wgsl +50 -0
  323. package/dist/core/src/render/material-types/matcap.wgsl +51 -0
  324. package/dist/core/src/render/material-types/normal.wgsl +41 -0
  325. package/dist/core/src/render/material-types/physical.wgsl +152 -0
  326. package/dist/core/src/render/material-types/sprite.wgsl +46 -0
  327. package/dist/core/src/render/material-types/sss.wgsl +79 -0
  328. package/dist/core/src/render/material-types/toon.wgsl +79 -0
  329. package/dist/core/src/render/passes/README.md +121 -0
  330. package/dist/core/src/render/passes/atmosphere.js +107 -0
  331. package/dist/core/src/render/passes/cluster-lighting-pass.js +441 -0
  332. package/dist/core/src/render/passes/csm.js +338 -0
  333. package/dist/core/src/render/passes/cubemap-capture.js +93 -0
  334. package/dist/core/src/render/passes/debug-viz.js +248 -0
  335. package/dist/core/src/render/passes/debug.js +500 -0
  336. package/dist/core/src/render/passes/decal-mesh.js +86 -0
  337. package/dist/core/src/render/passes/decal-pass.js +344 -0
  338. package/dist/core/src/render/passes/deferred-lighting.js +406 -0
  339. package/dist/core/src/render/passes/depth-prepass.js +148 -0
  340. package/dist/core/src/render/passes/dome-360.js +68 -0
  341. package/dist/core/src/render/passes/fluid-render.js +116 -0
  342. package/dist/core/src/render/passes/gi-types.js +78 -0
  343. package/dist/core/src/render/passes/graph-compute.js +251 -0
  344. package/dist/core/src/render/passes/greased-line-pass.js +218 -0
  345. package/dist/core/src/render/passes/morph-target.js +35 -0
  346. package/dist/core/src/render/passes/opaque.js +966 -0
  347. package/dist/core/src/render/passes/point-light-shadow.js +221 -0
  348. package/dist/core/src/render/passes/procedural-texture.js +142 -0
  349. package/dist/core/src/render/passes/reflection-probe.js +100 -0
  350. package/dist/core/src/render/passes/rsm-pass.js +228 -0
  351. package/dist/core/src/render/passes/sdf-text.js +114 -0
  352. package/dist/core/src/render/passes/shadow-map.js +121 -0
  353. package/dist/core/src/render/passes/shadow.js +191 -0
  354. package/dist/core/src/render/passes/skinning-vs.js +102 -0
  355. package/dist/core/src/render/passes/skinning.js +282 -0
  356. package/dist/core/src/render/passes/sky-dome.js +380 -0
  357. package/dist/core/src/render/passes/skybox.js +146 -0
  358. package/dist/core/src/render/passes/spot-light-shadow.js +223 -0
  359. package/dist/core/src/render/passes/terrain.js +303 -0
  360. package/dist/core/src/render/passes/transparent.js +323 -0
  361. package/dist/core/src/render/passes/underwater-fog.js +173 -0
  362. package/dist/core/src/render/passes/video-texture.js +58 -0
  363. package/dist/core/src/render/passes/volumetric-pass.js +278 -0
  364. package/dist/core/src/render/passes/volumetric-types.js +96 -0
  365. package/dist/core/src/render/passes/water.js +697 -0
  366. package/dist/core/src/render/pbr.js +257 -0
  367. package/dist/core/src/render/pipeline.js +49 -0
  368. package/dist/core/src/render/render-pass.js +13 -0
  369. package/dist/core/src/render/renderer-input-bus.js +176 -0
  370. package/dist/core/src/render/renderer-module-host.js +539 -0
  371. package/dist/core/src/render/resource-tracker.js +59 -0
  372. package/dist/core/src/render/sab-canvas-overlay.js +83 -0
  373. package/dist/core/src/render/shader-validator.js +172 -0
  374. package/dist/core/src/render/shaders/debug/debug-line.wgsl +27 -0
  375. package/dist/core/src/render/shaders/debug/debug-point.wgsl +30 -0
  376. package/dist/core/src/render/shaders/debug/debug-text.wgsl +42 -0
  377. package/dist/core/src/render/shaders/debug-viz/aabb.wgsl +20 -0
  378. package/dist/core/src/render/shaders/debug-viz/depth.wgsl +29 -0
  379. package/dist/core/src/render/shaders/debug-viz/lod.wgsl +38 -0
  380. package/dist/core/src/render/shaders/debug-viz/normals.wgsl +30 -0
  381. package/dist/core/src/render/shaders/debug-viz/overdraw.wgsl +21 -0
  382. package/dist/core/src/render/shaders/debug-viz/tangents.wgsl +29 -0
  383. package/dist/core/src/render/shaders/debug-viz/wireframe.wgsl +33 -0
  384. package/dist/core/src/render/shaders/shadow-chunks.js +133 -0
  385. package/dist/core/src/render/skybox.js +123 -0
  386. package/dist/core/src/render/splitscreen.js +60 -0
  387. package/dist/core/src/render/surface.js +63 -0
  388. package/dist/core/src/render/tonemap.js +171 -0
  389. package/dist/core/src/render/tracked-render-pass.js +115 -0
  390. package/dist/core/src/render/viewport.js +81 -0
  391. package/dist/core/src/render/wgsl-hmr.js +66 -0
  392. package/dist/core/src/sab/core-input-channel.js +22 -0
  393. package/dist/core/src/sab/define.js +127 -0
  394. package/dist/core/src/sab/errors.js +60 -0
  395. package/dist/core/src/sab/game-input.js +299 -0
  396. package/dist/core/src/sab/gamepad-devices.js +205 -0
  397. package/dist/core/src/sab/grid-buffer.js +91 -0
  398. package/dist/core/src/sab/input.js +38 -0
  399. package/dist/core/src/sab/layout.js +160 -0
  400. package/dist/core/src/sab/multi-input-channel.js +39 -0
  401. package/dist/core/src/sab/record-buffer.js +130 -0
  402. package/dist/core/src/sab/sab-polyfill.js +47 -0
  403. package/dist/core/src/sab/sim-channel.js +397 -0
  404. package/dist/core/src/sab/slot-buffer.js +140 -0
  405. package/dist/core/src/sab/types.js +1 -0
  406. package/dist/core/src/safety/bounds.js +71 -0
  407. package/dist/core/src/safety/json.js +70 -0
  408. package/dist/core/src/safety/path.js +151 -0
  409. package/dist/core/src/save/binary-format.js +95 -0
  410. package/dist/core/src/save/game-save-system.js +101 -0
  411. package/dist/core/src/save/grid-save-system.js +102 -0
  412. package/dist/core/src/save/migrate.js +35 -0
  413. package/dist/core/src/save/migration-registry.js +66 -0
  414. package/dist/core/src/save/persist-types.js +4 -0
  415. package/dist/core/src/save/schema.js +36 -0
  416. package/dist/core/src/save/serializer.js +139 -0
  417. package/dist/core/src/scene/builder.js +31 -0
  418. package/dist/core/src/scene/camera.js +118 -0
  419. package/dist/core/src/scene/checkpoint.js +84 -0
  420. package/dist/core/src/scene/game-loop.js +155 -0
  421. package/dist/core/src/scene/index.js +14 -0
  422. package/dist/core/src/scene/layer.js +7 -0
  423. package/dist/core/src/scene/prefab.js +97 -0
  424. package/dist/core/src/scene/scene-manager.js +141 -0
  425. package/dist/core/src/scene/scene.js +147 -0
  426. package/dist/core/src/scene/sky.js +179 -0
  427. package/dist/core/src/scene/spatial-grid.js +140 -0
  428. package/dist/core/src/scene/streaming.js +247 -0
  429. package/dist/core/src/scene/vegetation.js +107 -0
  430. package/dist/core/src/scene/world.js +66 -0
  431. package/dist/core/src/scripting/binding.js +85 -0
  432. package/dist/core/src/scripting/hot-reload.js +123 -0
  433. package/dist/core/src/scripting/script.js +68 -0
  434. package/dist/core/src/sim/hot-reload-pipeline.js +65 -0
  435. package/dist/core/src/sim/sim-state-helper.js +40 -0
  436. package/dist/core/src/sim/transient-state-registry.js +63 -0
  437. package/dist/core/src/sim/types.js +4 -0
  438. package/dist/core/src/sim/worker-loop.js +168 -0
  439. package/dist/core/src/stores/game-store.js +81 -0
  440. package/dist/core/src/stores/hot-reload-store.js +19 -0
  441. package/dist/core/src/telemetry/collector.js +303 -0
  442. package/dist/core/src/telemetry/gc-controller.js +365 -0
  443. package/dist/core/src/telemetry/gc-profiler.js +82 -0
  444. package/dist/core/src/telemetry/gc-tracker.js +63 -0
  445. package/dist/core/src/telemetry/gpu-profiler.js +554 -0
  446. package/dist/core/src/telemetry/gpu-resource-tracker.js +234 -0
  447. package/dist/core/src/telemetry/gpu-timer-pool.js +223 -0
  448. package/dist/core/src/telemetry/gpu-timer.js +117 -0
  449. package/dist/core/src/telemetry/gpu-timestamp-gate.js +22 -0
  450. package/dist/core/src/telemetry/reporter.js +56 -0
  451. package/dist/core/src/types/engine-types.js +21 -0
  452. package/dist/core/src/ui-font-scale.js +111 -0
  453. package/dist/core/src/util/broad-phase-grid.js +77 -0
  454. package/dist/core/src/util/feature-log.js +176 -0
  455. package/dist/core/src/util/index.js +4 -0
  456. package/dist/core/src/util/logger.js +596 -0
  457. package/dist/core/src/version.js +11 -0
  458. package/dist/core/src/webgpu-destroy-augmentation.d.ts +25 -0
  459. package/dist/core/src/worker/base-worker-host.js +212 -0
  460. package/dist/core/src/worker/buffer-sync.js +454 -0
  461. package/dist/core/src/worker/crash-recovery.js +153 -0
  462. package/dist/core/src/worker/entity-sim-worker-host.js +128 -0
  463. package/dist/core/src/worker/instrumented-worker-host.js +139 -0
  464. package/dist/core/src/worker/rpc.js +244 -0
  465. package/dist/core/src/worker/sim-worker-base.js +558 -0
  466. package/dist/core/src/worker/sim-worker-host.js +271 -0
  467. package/dist/core/src/worker/task-pool.js +205 -0
  468. package/dist/core/src/worker/task-worker.js +77 -0
  469. package/dist/libraries/asset-browser/src/index.js +10 -0
  470. package/dist/libraries/asset-browser/src/software-thumbnails.js +940 -0
  471. package/dist/libraries/audio-kira/src/backend.js +405 -0
  472. package/dist/libraries/audio-kira/src/index.js +4 -0
  473. package/dist/libraries/audio-kira/src/library.js +54 -0
  474. package/dist/libraries/blitz-ui/src/index.js +13 -0
  475. package/dist/libraries/blitz-ui/src/native-module.js +162 -0
  476. package/dist/libraries/blitz-ui/src/native-osr-ffi.js +409 -0
  477. package/dist/libraries/blitz-ui/src/router.js +82 -0
  478. package/dist/libraries/blitz-ui/src/shaders/ui-blit.wgsl.js +32 -0
  479. package/dist/libraries/blitz-ui/src/ui-blit-pass.js +108 -0
  480. package/dist/libraries/character/src/character-animator.js +323 -0
  481. package/dist/libraries/character/src/customization.js +464 -0
  482. package/dist/libraries/character/src/index.js +19 -0
  483. package/dist/libraries/character/src/inspectable.js +77 -0
  484. package/dist/libraries/character/src/loader.js +336 -0
  485. package/dist/libraries/character/src/locomotion.js +84 -0
  486. package/dist/libraries/character/src/preview.js +280 -0
  487. package/dist/libraries/devtools/src/backend.js +449 -0
  488. package/dist/libraries/devtools/src/cdp-bridge.js +293 -0
  489. package/dist/libraries/devtools/src/collectors.js +318 -0
  490. package/dist/libraries/devtools/src/index.js +31 -0
  491. package/dist/libraries/devtools/src/native-providers.js +749 -0
  492. package/dist/libraries/devtools/src/snapshot.js +35 -0
  493. package/dist/libraries/devtools/src/verify.js +139 -0
  494. package/dist/libraries/devtools/src/web/browser.js +94 -0
  495. package/dist/libraries/devtools/src/web/host.js +183 -0
  496. package/dist/libraries/devtools/src/web/mirror.js +26 -0
  497. package/dist/libraries/devtools/src/web/server.js +187 -0
  498. package/dist/libraries/entities/src/index.js +3 -0
  499. package/dist/libraries/entities/src/library.js +46 -0
  500. package/dist/libraries/entities/src/model-renderer.js +1307 -0
  501. package/dist/libraries/entities/src/shaders/model.wgsl +375 -0
  502. package/dist/libraries/gamepad/src/feed-input.js +54 -0
  503. package/dist/libraries/gamepad/src/filters.js +44 -0
  504. package/dist/libraries/gamepad/src/glyphs.js +83 -0
  505. package/dist/libraries/gamepad/src/hub.js +164 -0
  506. package/dist/libraries/gamepad/src/index.js +10 -0
  507. package/dist/libraries/gamepad/src/library.js +56 -0
  508. package/dist/libraries/gamepad/src/source-sab.js +62 -0
  509. package/dist/libraries/gamepad/src/sysfs-enrich.js +125 -0
  510. package/dist/libraries/gaussian-splats/src/gpu-sort.js +506 -0
  511. package/dist/libraries/gaussian-splats/src/index.js +8 -0
  512. package/dist/libraries/gaussian-splats/src/library.js +44 -0
  513. package/dist/libraries/gaussian-splats/src/parser.js +297 -0
  514. package/dist/libraries/gaussian-splats/src/renderer.js +368 -0
  515. package/dist/libraries/gaussian-splats/src/sh-eval.js +196 -0
  516. package/dist/libraries/gaussian-splats/src/sorter.js +76 -0
  517. package/dist/libraries/gaussian-splats/src/tile-raster.js +424 -0
  518. package/dist/libraries/gpu-kernels/src/index.js +8 -0
  519. package/dist/libraries/gpu-kernels/src/kernel.js +591 -0
  520. package/dist/libraries/gpu-kernels/src/transpile.js +896 -0
  521. package/dist/libraries/html-ui-kit/src/behaviors.js +231 -0
  522. package/dist/libraries/html-ui-kit/src/components.js +219 -0
  523. package/dist/libraries/html-ui-kit/src/index.js +17 -0
  524. package/dist/libraries/html-ui-kit/src/nav/nav-controller.js +215 -0
  525. package/dist/libraries/html-ui-kit/src/nav/nav-input.js +138 -0
  526. package/dist/libraries/html-ui-kit/src/nav/osk.js +135 -0
  527. package/dist/libraries/html-ui-kit/src/nav/router.js +152 -0
  528. package/dist/libraries/html-ui-kit/src/nav/vcursor.js +177 -0
  529. package/dist/libraries/html-ui-kit/src/ten-foot.js +138 -0
  530. package/dist/libraries/html-ui-kit/src/theme.js +235 -0
  531. package/dist/libraries/inspectable/src/index.js +6 -0
  532. package/dist/libraries/inspectable/src/inspectable.js +205 -0
  533. package/dist/libraries/lighting/src/index.js +4 -0
  534. package/dist/libraries/lighting/src/library.js +48 -0
  535. package/dist/libraries/lighting/src/light-system.js +395 -0
  536. package/dist/libraries/lighting/src/lighting-system.js +57 -0
  537. package/dist/libraries/lighting/src/shaders/light-debug.wgsl +30 -0
  538. package/dist/libraries/marching-cubes/src/chunked-field.js +130 -0
  539. package/dist/libraries/marching-cubes/src/deformation.js +41 -0
  540. package/dist/libraries/marching-cubes/src/generator.js +356 -0
  541. package/dist/libraries/marching-cubes/src/index.js +13 -0
  542. package/dist/libraries/marching-cubes/src/library.js +54 -0
  543. package/dist/libraries/marching-cubes/src/lod.js +95 -0
  544. package/dist/libraries/marching-cubes/src/marching-tetrahedra.js +261 -0
  545. package/dist/libraries/marching-cubes/src/sab.js +40 -0
  546. package/dist/libraries/marching-cubes/src/streaming-config.js +28 -0
  547. package/dist/libraries/marching-cubes/src/streaming-manager.js +490 -0
  548. package/dist/libraries/marching-cubes/src/tables.js +314 -0
  549. package/dist/libraries/marching-cubes/src/types.js +1 -0
  550. package/dist/libraries/models/src/bake-node-transforms.js +146 -0
  551. package/dist/libraries/models/src/bind-unskinned-meshes.js +145 -0
  552. package/dist/libraries/models/src/codecs/basisu-codec.js +134 -0
  553. package/dist/libraries/models/src/codecs/draco-codec.js +236 -0
  554. package/dist/libraries/models/src/codecs/draco3dgltf.d.ts +40 -0
  555. package/dist/libraries/models/src/codecs/index.js +5 -0
  556. package/dist/libraries/models/src/codecs/meshopt-codec.js +59 -0
  557. package/dist/libraries/models/src/codecs/registry.js +111 -0
  558. package/dist/libraries/models/src/dae.js +665 -0
  559. package/dist/libraries/models/src/default-part-selection.js +58 -0
  560. package/dist/libraries/models/src/dxf.js +235 -0
  561. package/dist/libraries/models/src/fbx/index.js +438 -0
  562. package/dist/libraries/models/src/fbx/interpreter/animation.js +369 -0
  563. package/dist/libraries/models/src/fbx/interpreter/blend-shapes.js +283 -0
  564. package/dist/libraries/models/src/fbx/interpreter/connections.js +158 -0
  565. package/dist/libraries/models/src/fbx/interpreter/diagnostics.js +48 -0
  566. package/dist/libraries/models/src/fbx/interpreter/geometry.js +430 -0
  567. package/dist/libraries/models/src/fbx/interpreter/global-settings.js +77 -0
  568. package/dist/libraries/models/src/fbx/interpreter/materials.js +231 -0
  569. package/dist/libraries/models/src/fbx/interpreter/nodes.js +168 -0
  570. package/dist/libraries/models/src/fbx/interpreter/skeleton.js +454 -0
  571. package/dist/libraries/models/src/fbx/parsers/binary-parser.js +217 -0
  572. package/dist/libraries/models/src/fbx/types.js +88 -0
  573. package/dist/libraries/models/src/gltf-extensions.js +121 -0
  574. package/dist/libraries/models/src/gltf.js +724 -0
  575. package/dist/libraries/models/src/index.js +46 -0
  576. package/dist/libraries/models/src/library.js +44 -0
  577. package/dist/libraries/models/src/loader.js +218 -0
  578. package/dist/libraries/models/src/material-adapter.js +82 -0
  579. package/dist/libraries/models/src/mini-xml.js +145 -0
  580. package/dist/libraries/models/src/normalize.js +168 -0
  581. package/dist/libraries/models/src/obj.js +247 -0
  582. package/dist/libraries/models/src/off.js +94 -0
  583. package/dist/libraries/models/src/ply.js +329 -0
  584. package/dist/libraries/models/src/pose-sampler.js +183 -0
  585. package/dist/libraries/models/src/sidecar/blender-extras.js +32 -0
  586. package/dist/libraries/models/src/sidecar/ddmeta.js +98 -0
  587. package/dist/libraries/models/src/sidecar/godot-import.js +76 -0
  588. package/dist/libraries/models/src/sidecar/resolver.js +112 -0
  589. package/dist/libraries/models/src/sidecar/types.js +8 -0
  590. package/dist/libraries/models/src/sidecar/unity-meta.js +46 -0
  591. package/dist/libraries/models/src/skeleton-synthesis.js +122 -0
  592. package/dist/libraries/models/src/stl.js +129 -0
  593. package/dist/libraries/models/src/threeds.js +312 -0
  594. package/dist/libraries/models/src/threemf.js +203 -0
  595. package/dist/libraries/models/src/types.js +33 -0
  596. package/dist/libraries/models/src/vtk.js +242 -0
  597. package/dist/libraries/navmesh/src/crowd-system.js +207 -0
  598. package/dist/libraries/navmesh/src/debug-viz.js +52 -0
  599. package/dist/libraries/navmesh/src/index.js +7 -0
  600. package/dist/libraries/navmesh/src/library.js +47 -0
  601. package/dist/libraries/navmesh/src/navmesh-generator.js +364 -0
  602. package/dist/libraries/navmesh/src/navmesh.js +141 -0
  603. package/dist/libraries/navmesh/src/pathfinder.js +221 -0
  604. package/dist/libraries/navmesh/src/types.js +1 -0
  605. package/dist/libraries/networking/src/authority.js +107 -0
  606. package/dist/libraries/networking/src/connection.js +107 -0
  607. package/dist/libraries/networking/src/discovery.js +314 -0
  608. package/dist/libraries/networking/src/enhanced-replication.js +282 -0
  609. package/dist/libraries/networking/src/epic-adapter.js +101 -0
  610. package/dist/libraries/networking/src/index.js +16 -0
  611. package/dist/libraries/networking/src/library.js +45 -0
  612. package/dist/libraries/networking/src/lobby.js +84 -0
  613. package/dist/libraries/networking/src/platform-adapter.js +92 -0
  614. package/dist/libraries/networking/src/rcs-adapter.js +100 -0
  615. package/dist/libraries/networking/src/remote-input.js +162 -0
  616. package/dist/libraries/networking/src/replication.js +273 -0
  617. package/dist/libraries/networking/src/rpc.js +172 -0
  618. package/dist/libraries/networking/src/session.js +129 -0
  619. package/dist/libraries/networking/src/transport.js +156 -0
  620. package/dist/libraries/networking/src/webrtc.js +266 -0
  621. package/dist/libraries/pathfinding-2d/src/astar-grid.js +255 -0
  622. package/dist/libraries/pathfinding-2d/src/index.js +9 -0
  623. package/dist/libraries/persistence/src/autosave-manager.js +94 -0
  624. package/dist/libraries/persistence/src/binary-record-store.js +205 -0
  625. package/dist/libraries/persistence/src/browser.js +16 -0
  626. package/dist/libraries/persistence/src/file-save-store.js +507 -0
  627. package/dist/libraries/persistence/src/hash-utils.js +54 -0
  628. package/dist/libraries/persistence/src/index.js +17 -0
  629. package/dist/libraries/persistence/src/library.js +51 -0
  630. package/dist/libraries/persistence/src/mock-opfs.js +114 -0
  631. package/dist/libraries/persistence/src/node-fs-directory-handle.js +168 -0
  632. package/dist/libraries/persistence/src/opfs-save-store.js +584 -0
  633. package/dist/libraries/persistence/src/save-worker-proxy.js +96 -0
  634. package/dist/libraries/persistence/src/save-worker.js +76 -0
  635. package/dist/libraries/persistence/src/xxh3-ts.d.ts +10 -0
  636. package/dist/libraries/physics-native/src/backend.js +960 -0
  637. package/dist/libraries/physics-native/src/broadphase.js +79 -0
  638. package/dist/libraries/physics-native/src/index.js +6 -0
  639. package/dist/libraries/physics-native/src/library.js +57 -0
  640. package/dist/libraries/physics-native/src/narrowphase-shapes.js +348 -0
  641. package/dist/libraries/physics-native/src/narrowphase.js +60 -0
  642. package/dist/libraries/physics-native/src/solver.js +105 -0
  643. package/dist/libraries/physics-native/src/types.js +4 -0
  644. package/dist/libraries/physics-rapier/src/api.js +352 -0
  645. package/dist/libraries/physics-rapier/src/auto-backend.js +54 -0
  646. package/dist/libraries/physics-rapier/src/backend.js +1066 -0
  647. package/dist/libraries/physics-rapier/src/bulk-ops.js +46 -0
  648. package/dist/libraries/physics-rapier/src/ffi-backend.js +17 -0
  649. package/dist/libraries/physics-rapier/src/ffi-lib.js +605 -0
  650. package/dist/libraries/physics-rapier/src/index.js +9 -0
  651. package/dist/libraries/physics-rapier/src/library.js +71 -0
  652. package/dist/libraries/physics-rapier/src/rapier-backend.js +1102 -0
  653. package/dist/libraries/physics-rapier/src/realm-worker-script.js +233 -0
  654. package/dist/libraries/postfx/src/index.js +14 -0
  655. package/dist/libraries/postfx/src/library.js +207 -0
  656. package/dist/libraries/postfx/src/post-process-stack.js +1641 -0
  657. package/dist/libraries/postfx/src/shaders/post-process/afterimage.wgsl +14 -0
  658. package/dist/libraries/postfx/src/shaders/post-process/ascii.wgsl +24 -0
  659. package/dist/libraries/postfx/src/shaders/post-process/blit.wgsl +12 -0
  660. package/dist/libraries/postfx/src/shaders/post-process/bloom-blur.wgsl +21 -0
  661. package/dist/libraries/postfx/src/shaders/post-process/bloom-bright.wgsl +15 -0
  662. package/dist/libraries/postfx/src/shaders/post-process/bloom-composite.wgsl +14 -0
  663. package/dist/libraries/postfx/src/shaders/post-process/bloom-downsample.wgsl +60 -0
  664. package/dist/libraries/postfx/src/shaders/post-process/bloom-soft.wgsl +46 -0
  665. package/dist/libraries/postfx/src/shaders/post-process/bloom-upsample.wgsl +51 -0
  666. package/dist/libraries/postfx/src/shaders/post-process/channel-mixer.wgsl +36 -0
  667. package/dist/libraries/postfx/src/shaders/post-process/chromatic-aberration.wgsl +37 -0
  668. package/dist/libraries/postfx/src/shaders/post-process/dithering.wgsl +64 -0
  669. package/dist/libraries/postfx/src/shaders/post-process/dof.wgsl +131 -0
  670. package/dist/libraries/postfx/src/shaders/post-process/edges.wgsl +45 -0
  671. package/dist/libraries/postfx/src/shaders/post-process/fullscreen-vs.wgsl +15 -0
  672. package/dist/libraries/postfx/src/shaders/post-process/fxaa.wgsl +102 -0
  673. package/dist/libraries/postfx/src/shaders/post-process/gaussian-blur.wgsl +37 -0
  674. package/dist/libraries/postfx/src/shaders/post-process/glow-blur.wgsl +33 -0
  675. package/dist/libraries/postfx/src/shaders/post-process/glow-composite.wgsl +25 -0
  676. package/dist/libraries/postfx/src/shaders/post-process/grain.wgsl +37 -0
  677. package/dist/libraries/postfx/src/shaders/post-process/halftone.wgsl +80 -0
  678. package/dist/libraries/postfx/src/shaders/post-process/highlight-blur.wgsl +33 -0
  679. package/dist/libraries/postfx/src/shaders/post-process/highlight-composite.wgsl +32 -0
  680. package/dist/libraries/postfx/src/shaders/post-process/lens-distortion.wgsl +43 -0
  681. package/dist/libraries/postfx/src/shaders/post-process/lens-flare.wgsl +68 -0
  682. package/dist/libraries/postfx/src/shaders/post-process/lut.wgsl +30 -0
  683. package/dist/libraries/postfx/src/shaders/post-process/motion-blur.wgsl +55 -0
  684. package/dist/libraries/postfx/src/shaders/post-process/occluder-chunk.wgsl +28 -0
  685. package/dist/libraries/postfx/src/shaders/post-process/outline.wgsl +51 -0
  686. package/dist/libraries/postfx/src/shaders/post-process/pixelation.wgsl +47 -0
  687. package/dist/libraries/postfx/src/shaders/post-process/sharpen.wgsl +32 -0
  688. package/dist/libraries/postfx/src/shaders/post-process/sobel.wgsl +26 -0
  689. package/dist/libraries/postfx/src/shaders/post-process/split-tone.wgsl +36 -0
  690. package/dist/libraries/postfx/src/shaders/post-process/ssao-blur.wgsl +38 -0
  691. package/dist/libraries/postfx/src/shaders/post-process/ssao-composite.wgsl +25 -0
  692. package/dist/libraries/postfx/src/shaders/post-process/ssao.wgsl +147 -0
  693. package/dist/libraries/postfx/src/shaders/post-process/ssr.wgsl +155 -0
  694. package/dist/libraries/postfx/src/shaders/post-process/taa.wgsl +98 -0
  695. package/dist/libraries/postfx/src/shaders/post-process/tonemap.wgsl +40 -0
  696. package/dist/libraries/postfx/src/shaders/post-process/watercolor.wgsl +82 -0
  697. package/dist/libraries/postfx/src/shaders/post-process/white-balance.wgsl +41 -0
  698. package/dist/libraries/recast/src/backend.js +124 -0
  699. package/dist/libraries/recast/src/crowd-system.js +310 -0
  700. package/dist/libraries/recast/src/index.js +4 -0
  701. package/dist/libraries/recast/src/library.js +59 -0
  702. package/dist/libraries/recast/src/types.js +4 -0
  703. package/dist/libraries/sand/src/cell.js +32 -0
  704. package/dist/libraries/sand/src/fields.js +27 -0
  705. package/dist/libraries/sand/src/fluid-grid.js +267 -0
  706. package/dist/libraries/sand/src/grid-dims.js +47 -0
  707. package/dist/libraries/sand/src/grid-sim-buffer.js +184 -0
  708. package/dist/libraries/sand/src/index.js +20 -0
  709. package/dist/libraries/sand/src/library.js +67 -0
  710. package/dist/libraries/sand/src/materials.js +437 -0
  711. package/dist/libraries/sand/src/palette.js +87 -0
  712. package/dist/libraries/sand/src/particles.js +163 -0
  713. package/dist/libraries/sand/src/render/sand-grid-pass.js +377 -0
  714. package/dist/libraries/sand/src/rng.js +44 -0
  715. package/dist/libraries/sand/src/rules/builtin-rules.js +125 -0
  716. package/dist/libraries/sand/src/rules/rule-compiler.js +164 -0
  717. package/dist/libraries/sand/src/rules/rule-engine.js +210 -0
  718. package/dist/libraries/sand/src/rules/rule-types.js +27 -0
  719. package/dist/libraries/sand/src/sand-step-pool.js +458 -0
  720. package/dist/libraries/sand/src/sand-step-worker.js +101 -0
  721. package/dist/libraries/sand/src/sand-world.js +3382 -0
  722. package/dist/libraries/stickman/src/index.js +7 -0
  723. package/dist/libraries/stickman/src/library.js +44 -0
  724. package/dist/libraries/stickman/src/proportions.js +40 -0
  725. package/dist/libraries/stickman/src/shader.js +113 -0
  726. package/dist/libraries/stickman/src/skeleton.js +163 -0
  727. package/dist/libraries/stickman/src/stickman-pass.js +210 -0
  728. package/dist/libraries/stickman/src/thick-line.js +120 -0
  729. package/dist/libraries/surface-nets/src/chunked-field.js +5 -0
  730. package/dist/libraries/surface-nets/src/deformation.js +29 -0
  731. package/dist/libraries/surface-nets/src/index.js +15 -0
  732. package/dist/libraries/surface-nets/src/library.js +41 -0
  733. package/dist/libraries/surface-nets/src/lod.js +6 -0
  734. package/dist/libraries/surface-nets/src/sab.js +4 -0
  735. package/dist/libraries/surface-nets/src/streaming-config.js +4 -0
  736. package/dist/libraries/surface-nets/src/streaming-manager.js +9 -0
  737. package/dist/libraries/surface-nets/src/surface-nets.js +361 -0
  738. package/dist/libraries/surface-nets/src/types.js +1 -0
  739. package/dist/libraries/water/src/buoyancy.js +80 -0
  740. package/dist/libraries/water/src/index.js +12 -0
  741. package/dist/libraries/water/src/library.js +65 -0
  742. package/dist/libraries/water/src/shore-damping.js +70 -0
  743. package/dist/libraries/water/src/water-buffer.js +78 -0
  744. package/dist/libraries/water/src/water-chunks.js +5 -0
  745. package/dist/libraries/water/src/water-physics.js +315 -0
  746. package/dist/libraries/water/src/water-renderer.js +736 -0
  747. package/dist/libraries/water/src/water-sab.js +138 -0
  748. package/dist/libraries/water/src/wave-sources.js +45 -0
  749. package/dist/libraries/weather/src/index.js +5 -0
  750. package/dist/libraries/weather/src/library.js +48 -0
  751. package/dist/libraries/weather/src/types.js +29 -0
  752. package/dist/libraries/weather/src/weather-blend.js +108 -0
  753. package/dist/libraries/weather/src/weather-system.js +275 -0
  754. package/dist/libraries/weatherfx/src/cloud-provider.js +5 -0
  755. package/dist/libraries/weatherfx/src/cloud-system.js +294 -0
  756. package/dist/libraries/weatherfx/src/index.js +4 -0
  757. package/dist/libraries/weatherfx/src/library.js +41 -0
  758. package/dist/libraries/weatherfx/src/particle-system.js +350 -0
  759. package/dist/libraries/weatherfx/src/shaders/cloud.wgsl +111 -0
  760. package/dist/libraries/weatherfx/src/shaders/particle-compute.wgsl +187 -0
  761. package/dist/libraries/weatherfx/src/shaders/particle-render.wgsl +95 -0
  762. package/dist/mcp/src/client.js +669 -0
  763. package/dist/mcp/src/engine-context.js +99 -0
  764. package/dist/mcp/src/http-transport.js +423 -0
  765. package/dist/mcp/src/index.js +5 -0
  766. package/dist/mcp/src/prompts/add-entity.js +39 -0
  767. package/dist/mcp/src/prompts/create-scene.js +41 -0
  768. package/dist/mcp/src/prompts/debug-frame.js +36 -0
  769. package/dist/mcp/src/prompts/index.js +10 -0
  770. package/dist/mcp/src/resources/asset-list.js +28 -0
  771. package/dist/mcp/src/resources/checkpoint-list.js +29 -0
  772. package/dist/mcp/src/resources/entity-state.js +45 -0
  773. package/dist/mcp/src/resources/gpu-info.js +90 -0
  774. package/dist/mcp/src/resources/index.js +51 -0
  775. package/dist/mcp/src/resources/performance.js +33 -0
  776. package/dist/mcp/src/resources/scene-tree.js +37 -0
  777. package/dist/mcp/src/server.js +307 -0
  778. package/dist/mcp/src/tools/animation.js +102 -0
  779. package/dist/mcp/src/tools/asset.js +146 -0
  780. package/dist/mcp/src/tools/audio.js +80 -0
  781. package/dist/mcp/src/tools/build.js +128 -0
  782. package/dist/mcp/src/tools/camera.js +157 -0
  783. package/dist/mcp/src/tools/checkpoint.js +90 -0
  784. package/dist/mcp/src/tools/component.js +176 -0
  785. package/dist/mcp/src/tools/debug.js +273 -0
  786. package/dist/mcp/src/tools/entity.js +309 -0
  787. package/dist/mcp/src/tools/inspect.js +192 -0
  788. package/dist/mcp/src/tools/lighting.js +239 -0
  789. package/dist/mcp/src/tools/material.js +225 -0
  790. package/dist/mcp/src/tools/mesh.js +210 -0
  791. package/dist/mcp/src/tools/physics.js +251 -0
  792. package/dist/mcp/src/tools/scene.js +139 -0
  793. package/dist/mcp/src/tools/script.js +114 -0
  794. package/dist/mcp/src/types.js +9 -0
  795. package/dist/mcp/src/undo-redo.js +64 -0
  796. package/dist/modules/camera-controls/src/index.js +116 -0
  797. package/dist/modules/controller-ui/src/index.js +149 -0
  798. package/dist/modules/devtools/src/api.js +317 -0
  799. package/dist/modules/devtools/src/asset-utils.js +102 -0
  800. package/dist/modules/devtools/src/bind-debug-store.js +34 -0
  801. package/dist/modules/devtools/src/blitz/host.js +391 -0
  802. package/dist/modules/devtools/src/blitz/module.js +65 -0
  803. package/dist/modules/devtools/src/blitz/panels/console.js +217 -0
  804. package/dist/modules/devtools/src/blitz/panels/elements.js +79 -0
  805. package/dist/modules/devtools/src/blitz/panels/gpu.js +61 -0
  806. package/dist/modules/devtools/src/blitz/panels/performance.js +113 -0
  807. package/dist/modules/devtools/src/blitz/panels/snapshot.js +141 -0
  808. package/dist/modules/devtools/src/blitz/panels/types.js +55 -0
  809. package/dist/modules/devtools/src/blitz/theme.js +167 -0
  810. package/dist/modules/devtools/src/data-bridge.js +247 -0
  811. package/dist/modules/devtools/src/debug-overlay.js +181 -0
  812. package/dist/modules/devtools/src/debug-raycast.js +296 -0
  813. package/dist/modules/devtools/src/debug-store.js +28 -0
  814. package/dist/modules/devtools/src/debug-view-descriptors.js +24 -0
  815. package/dist/modules/devtools/src/doctor-panel.js +163 -0
  816. package/dist/modules/devtools/src/gizmo-module.js +95 -0
  817. package/dist/modules/devtools/src/graph-model.js +387 -0
  818. package/dist/modules/devtools/src/grid-renderer.js +145 -0
  819. package/dist/modules/devtools/src/height-ruler-renderer.js +189 -0
  820. package/dist/modules/devtools/src/index.js +46 -0
  821. package/dist/modules/devtools/src/init.js +204 -0
  822. package/dist/modules/devtools/src/label-overlay.js +129 -0
  823. package/dist/modules/devtools/src/material-stats-panel.js +171 -0
  824. package/dist/modules/devtools/src/profiling-bridge.js +288 -0
  825. package/dist/modules/devtools/src/profiling-hooks.js +63 -0
  826. package/dist/modules/devtools/src/renderer-adapter.js +61 -0
  827. package/dist/modules/devtools/src/scene-inspector.js +571 -0
  828. package/dist/modules/devtools/src/scene-store.js +212 -0
  829. package/dist/modules/devtools/src/scene-sync.js +92 -0
  830. package/dist/modules/devtools/src/shaders/transform-gizmo.wgsl +38 -0
  831. package/dist/modules/devtools/src/sim-stats-panel.js +250 -0
  832. package/dist/modules/devtools/src/sim-stats-provider.js +73 -0
  833. package/dist/modules/devtools/src/skeleton-renderer.js +326 -0
  834. package/dist/modules/devtools/src/transform-gizmo.js +677 -0
  835. package/dist/modules/devtools/src/types.js +5 -0
  836. package/dist/modules/devtools/src/worker-expose.js +59 -0
  837. package/dist/modules/devtools/src/worker-sync.js +115 -0
  838. package/dist/modules/editor/src/commands/component.js +151 -0
  839. package/dist/modules/editor/src/commands/entity.js +253 -0
  840. package/dist/modules/editor/src/commands/hierarchy.js +79 -0
  841. package/dist/modules/editor/src/commands/index.js +57 -0
  842. package/dist/modules/editor/src/commands/prefab.js +149 -0
  843. package/dist/modules/editor/src/commands/registry.js +246 -0
  844. package/dist/modules/editor/src/commands/scene-io.js +206 -0
  845. package/dist/modules/editor/src/commands/selection.js +71 -0
  846. package/dist/modules/editor/src/commands/transform.js +88 -0
  847. package/dist/modules/editor/src/ddscene.js +189 -0
  848. package/dist/modules/editor/src/document.js +96 -0
  849. package/dist/modules/editor/src/editor-context.js +115 -0
  850. package/dist/modules/editor/src/index.js +11 -0
  851. package/dist/modules/editor/src/mcp.js +91 -0
  852. package/dist/modules/editor/src/module.js +115 -0
  853. package/dist/modules/editor/src/selection.js +60 -0
  854. package/dist/modules/editor/src/shell.js +397 -0
  855. package/dist/modules/editor/src/viewport.js +186 -0
  856. package/dist/modules/html-ui/src/composite.js +116 -0
  857. package/dist/modules/html-ui/src/create-html-ui.js +137 -0
  858. package/dist/modules/html-ui/src/doc-backend.js +518 -0
  859. package/dist/modules/html-ui/src/host.js +819 -0
  860. package/dist/modules/html-ui/src/index.js +5 -0
  861. package/dist/modules/html-ui/src/jsx-dev-runtime.js +9 -0
  862. package/dist/modules/html-ui/src/jsx-runtime.js +121 -0
  863. package/dist/modules/html-ui/src/protocol.js +6 -0
  864. package/dist/modules/html-ui/src/ui-worker.js +10 -0
  865. package/dist/modules/mcp/src/index.js +62 -0
  866. package/dist/modules/movement-2d/src/grid-character.js +345 -0
  867. package/dist/modules/movement-2d/src/index.js +27 -0
  868. package/dist/modules/movement-3d/src/character-motor.js +166 -0
  869. package/dist/modules/movement-3d/src/index.js +27 -0
  870. package/dist/modules/native-osr/src/index.js +12 -0
  871. package/dist/modules/native-osr/src/input-router.js +335 -0
  872. package/dist/modules/native-osr/src/native-osr-manager.js +210 -0
  873. package/dist/modules/native-osr/src/native-texture-source.js +66 -0
  874. package/dist/modules/native-osr/src/types.js +8 -0
  875. package/dist/modules/native-osr/src/world-space-ui-pass.js +313 -0
  876. package/dist/modules/sailing/src/index.js +39 -0
  877. package/dist/modules/terrain/src/index.js +44 -0
  878. package/dist/modules/vitals/src/index.js +25 -0
  879. package/dist/modules/vitals/src/vitals.js +195 -0
  880. package/dist/modules/xr/src/camera-rig.js +119 -0
  881. package/dist/modules/xr/src/debug.js +45 -0
  882. package/dist/modules/xr/src/frame-loop.js +139 -0
  883. package/dist/modules/xr/src/index.js +10 -0
  884. package/dist/modules/xr/src/input.js +164 -0
  885. package/dist/modules/xr/src/layer.js +100 -0
  886. package/dist/modules/xr/src/session.js +133 -0
  887. package/dist/modules/xr/src/sim-module.js +21 -0
  888. package/dist/modules/xr/src/types.js +4 -0
  889. package/dist/modules/xr/src/webxr.d.ts +182 -0
  890. package/dist/modules/xr/src/xr-module.js +134 -0
  891. package/dist/shader-graph/src/chunks.js +340 -0
  892. package/dist/shader-graph/src/compiler.js +639 -0
  893. package/dist/shader-graph/src/compute-compiler.js +384 -0
  894. package/dist/shader-graph/src/compute-graph.js +55 -0
  895. package/dist/shader-graph/src/compute-profiles.js +39 -0
  896. package/dist/shader-graph/src/graph.js +38 -0
  897. package/dist/shader-graph/src/index.js +15 -0
  898. package/dist/shader-graph/src/profiles.js +305 -0
  899. package/dist/shader-graph/src/validator.js +42 -0
  900. package/dist/shader-graph/src/wgsl-binding-validator.js +110 -0
  901. package/dist/shader-graph/src/wgsl-struct-validator.js +222 -0
  902. package/dist/shader-graph/src/wgsl-struct.js +251 -0
  903. package/dist/test/src/index.js +1 -0
  904. package/dist/test/src/vision-test.js +228 -0
  905. package/libraries/asset-browser/src/software-thumbnails.ts +2 -2
  906. package/libraries/audio-kira/src/backend.ts +2 -1
  907. package/libraries/blitz-ui/native/src/shell.rs +35 -1
  908. package/libraries/blitz-ui/native-osr/Cargo.toml +8 -0
  909. package/libraries/blitz-ui/native-osr/src/lib.rs +213 -22
  910. package/libraries/blitz-ui/native-osr/src/mutate.rs +109 -14
  911. package/libraries/blitz-ui/src/native-osr-ffi.ts +71 -8
  912. package/libraries/blitz-ui/src/router.ts +3 -1
  913. package/libraries/blitz-ui/src/ui-blit-pass.ts +1 -1
  914. package/libraries/character/src/character-animator.ts +1 -1
  915. package/libraries/character/src/customization.ts +513 -0
  916. package/libraries/character/src/index.ts +6 -0
  917. package/libraries/character/src/inspectable.ts +111 -0
  918. package/libraries/character/src/loader.ts +38 -13
  919. package/libraries/character/src/locomotion.ts +13 -1
  920. package/libraries/character/src/preview.ts +94 -24
  921. package/libraries/devtools/README.md +16 -18
  922. package/libraries/devtools/src/backend.ts +505 -0
  923. package/libraries/devtools/src/cdp-bridge.ts +8 -8
  924. package/libraries/devtools/src/collectors.ts +41 -37
  925. package/libraries/devtools/src/index.ts +32 -14
  926. package/libraries/devtools/src/native-providers.ts +20 -12
  927. package/libraries/devtools/src/snapshot.ts +77 -0
  928. package/libraries/devtools/src/web/host.ts +11 -12
  929. package/libraries/devtools/src/web/mirror.ts +14 -405
  930. package/libraries/devtools/src/web/server.ts +4 -3
  931. package/libraries/entities/src/model-renderer.ts +96 -23
  932. package/libraries/gamepad/src/feed-input.ts +1 -1
  933. package/libraries/gamepad/src/hub.ts +2 -2
  934. package/libraries/gamepad/src/library.ts +2 -1
  935. package/libraries/gamepad/src/source-sab.ts +2 -2
  936. package/libraries/gamepad/src/sysfs-enrich.ts +2 -2
  937. package/libraries/gpu-kernels/src/kernel.ts +2 -2
  938. package/libraries/gpu-kernels/src/transpile.ts +1 -1
  939. package/libraries/html-ui-kit/src/nav/nav-controller.ts +1 -1
  940. package/libraries/html-ui-kit/src/nav/nav-input.ts +2 -2
  941. package/libraries/inspectable/src/index.ts +11 -0
  942. package/libraries/inspectable/src/inspectable.ts +277 -0
  943. package/libraries/marching-cubes/src/streaming-manager.ts +4 -4
  944. package/libraries/models/src/bind-unskinned-meshes.ts +131 -0
  945. package/libraries/models/src/index.ts +1 -0
  946. package/libraries/models/src/types.ts +22 -0
  947. package/libraries/networking/src/discovery.ts +8 -8
  948. package/libraries/persistence/src/autosave-manager.ts +1 -1
  949. package/libraries/persistence/src/binary-record-store.ts +1 -1
  950. package/libraries/persistence/src/file-save-store.ts +9 -9
  951. package/libraries/persistence/src/library.ts +1 -1
  952. package/libraries/persistence/src/opfs-save-store.ts +7 -7
  953. package/libraries/persistence/src/save-worker.ts +13 -14
  954. package/libraries/physics-rapier/src/ffi-lib.ts +2 -1
  955. package/libraries/physics-rapier/src/realm-worker-script.ts +1 -1
  956. package/libraries/postfx/src/post-process-stack.ts +1 -1
  957. package/libraries/sand/src/sand-step-pool.ts +5 -0
  958. package/libraries/water/src/water-renderer.ts +1 -1
  959. package/libraries/weatherfx/src/cloud-system.ts +3 -3
  960. package/mcp/README.md +20 -0
  961. package/mcp/src/client.ts +75 -22
  962. package/mcp/src/undo-redo.ts +2 -2
  963. package/modules/controller-ui/src/index.ts +1 -1
  964. package/modules/devtools/src/blitz/host.ts +430 -0
  965. package/modules/devtools/src/blitz/module.ts +101 -0
  966. package/modules/devtools/src/blitz/panels/console.ts +223 -0
  967. package/modules/devtools/src/blitz/panels/elements.ts +92 -0
  968. package/modules/devtools/src/blitz/panels/gpu.ts +70 -0
  969. package/modules/devtools/src/blitz/panels/performance.ts +120 -0
  970. package/modules/devtools/src/blitz/panels/snapshot.ts +152 -0
  971. package/modules/devtools/src/blitz/panels/types.ts +120 -0
  972. package/modules/devtools/src/blitz/theme.ts +168 -0
  973. package/modules/devtools/src/data-bridge.ts +1 -1
  974. package/modules/devtools/src/index.ts +6 -0
  975. package/modules/devtools/src/profiling-bridge.ts +17 -13
  976. package/modules/devtools/src/profiling-hooks.ts +22 -13
  977. package/modules/devtools/src/scene-inspector.ts +1 -1
  978. package/modules/devtools/src/worker-sync.ts +9 -1
  979. package/modules/editor/src/commands/registry.ts +2 -2
  980. package/modules/editor/src/module.ts +1 -1
  981. package/modules/html-ui/src/composite.ts +1 -1
  982. package/modules/html-ui/src/create-html-ui.ts +21 -9
  983. package/modules/html-ui/src/doc-backend.ts +189 -10
  984. package/modules/html-ui/src/host.ts +354 -40
  985. package/modules/html-ui/src/index.ts +1 -1
  986. package/modules/html-ui/src/jsx-runtime.ts +2 -2
  987. package/modules/html-ui/src/protocol.ts +53 -6
  988. package/modules/mcp/README.md +6 -0
  989. package/modules/mcp/src/index.ts +70 -3
  990. package/modules/movement-3d/src/character-motor.ts +83 -10
  991. package/package.json +838 -165
  992. package/shader-graph/README.md +25 -0
  993. package/test/README.md +16 -0
  994. package/libraries/blitz-ui/native-osr-spike.ts +0 -70
  995. package/libraries/devtools/native/Cargo.toml +0 -12
  996. package/libraries/devtools/native/src/lib.rs +0 -1646
  997. package/libraries/devtools/native/src/panels/console.rs +0 -338
  998. package/libraries/devtools/native/src/panels/dom_tree.rs +0 -47
  999. package/libraries/devtools/native/src/panels/generic.rs +0 -317
  1000. package/libraries/devtools/native/src/panels/gpu.rs +0 -107
  1001. package/libraries/devtools/native/src/panels/input.rs +0 -88
  1002. package/libraries/devtools/native/src/panels/mod.rs +0 -154
  1003. package/libraries/devtools/native/src/panels/perf_metrics.rs +0 -91
  1004. package/libraries/devtools/native/src/panels/perf_recorder.rs +0 -158
  1005. package/libraries/devtools/native/src/panels/scene.rs +0 -72
  1006. package/libraries/devtools/native/src/state.rs +0 -394
  1007. package/libraries/devtools/src/egui-ffi.ts +0 -804
  1008. package/libraries/devtools/src/egui-renderer.ts +0 -407
  1009. package/libraries/devtools/src/host.ts +0 -363
  1010. package/libraries/devtools/src/mirror.ts +0 -794
  1011. package/libraries/models/test-fixtures/fbx/LICENSE-notice.txt +0 -24
  1012. package/libraries/models/test-fixtures/fbx/README.md +0 -46
  1013. package/libraries/models/test-fixtures/fbx/m01_cube_phong.fbx +0 -0
  1014. package/libraries/models/test-fixtures/fbx/m02_geo_ngons.fbx +0 -0
  1015. package/libraries/models/test-fixtures/fbx/m03_normals.fbx +0 -0
  1016. package/libraries/models/test-fixtures/fbx/m04_material_properties.fbx +0 -0
  1017. package/libraries/models/test-fixtures/fbx/m05_external_diffuse.png +0 -0
  1018. package/libraries/models/test-fixtures/fbx/m05_textures.fbx +0 -0
  1019. package/libraries/models/test-fixtures/fbx/m06_uv_transform.fbx +0 -0
  1020. package/libraries/models/test-fixtures/fbx/m07_multimaterial.fbx +0 -0
  1021. package/libraries/models/test-fixtures/fbx/m08_transforms.fbx +0 -0
  1022. package/libraries/models/test-fixtures/fbx/m09_skinning.fbx +0 -0
  1023. package/libraries/models/test-fixtures/fbx/m10_morph.fbx +0 -0
  1024. package/libraries/models/test-fixtures/fbx/m11_node_anim.fbx +0 -0
  1025. package/libraries/models/test-fixtures/fbx/m12_skeletal_anim.fbx +0 -0
  1026. package/libraries/models/test-fixtures/fbx/m13_morph_anim.fbx +0 -0
  1027. package/libraries/models/test-fixtures/fbx/m14_multiclip.fbx +0 -0
  1028. package/libraries/models/test-fixtures/fbx/m15_camera_lights.fbx +0 -0
  1029. package/libraries/models/test-fixtures/fbx/m16_axis_yup.fbx +0 -0
  1030. package/libraries/models/test-fixtures/fbx/m16_axis_zup.fbx +0 -0
  1031. package/libraries/models/test-fixtures/fbx/m16_units_254.fbx +0 -0
  1032. package/libraries/physics-native/src/ffi-spike-worker.ts +0 -71
  1033. package/libraries/physics-rapier/bench/ffi-bench.ts +0 -79
  1034. package/libraries/physics-rapier/bench/wasm-baseline.ts +0 -90
@@ -0,0 +1,1165 @@
1
+ // ============================================================================
2
+ // GameRenderer — generic WebGPU render loop infrastructure
3
+ // Extracted from WebGPURenderer: device init, surface config, rAF loop,
4
+ // frame rate limiter, viewport management, telemetry, GPU UI pass, depth cache.
5
+ // Games register render passes via FrameGraph slots and provide game-specific
6
+ // logic through callback hooks.
7
+ // ============================================================================
8
+ import { UIInputRouter } from "../input/ui-router.js";
9
+ import { getHostCapabilities, getNativeHost } from "../platform/runtime.js";
10
+ import { TelemetryCollector } from "../telemetry/collector.js";
11
+ import { GPUProfiler } from "../telemetry/gpu-profiler.js";
12
+ import { GPUResourceTracker } from "../telemetry/gpu-resource-tracker.js";
13
+ import { createLogger } from "../util/logger.js";
14
+ import { CanvasResizeWatcher } from "./canvas-resize-watcher.js";
15
+ import { GPUDeviceManager } from "./device.js";
16
+ import { FrameGraph } from "./frame-graph.js";
17
+ import { InputManager } from "./input-manager.js";
18
+ import { RendererModuleHost } from "./renderer-module-host.js";
19
+ import { installShaderValidationGuard } from "./shader-validator.js";
20
+ const log = createLogger();
21
+ export class GameRenderer {
22
+ canvas;
23
+ device = null;
24
+ adapter = null;
25
+ context = null;
26
+ format = "bgra8unorm";
27
+ config;
28
+ depthFormat = "depth32float";
29
+ msaaSampleCount = 1;
30
+ mode = "3d";
31
+ // Infrastructure
32
+ deviceManager;
33
+ resizeWatcher = null;
34
+ inputManager;
35
+ frameGraph;
36
+ rendererModuleHost = null;
37
+ // Telemetry & profiling
38
+ gpuProfiler = null;
39
+ gpuResourceTracker = null;
40
+ telemetryCollector = null;
41
+ /** Input router for the active UI stack (html-ui via Blitz, or none). */
42
+ uiInputRouter = null;
43
+ /** Screen-space compositors (html-ui panels etc.) drawn in the UI pass. */
44
+ uiCompositors = new Set();
45
+ // Render loop state
46
+ running = false;
47
+ deviceLost = false;
48
+ /** True when init() borrowed the native host's device — the surface was
49
+ * already configured by the host, so the renderer must not reconfigure. */
50
+ hostConfiguredSurface = false;
51
+ lastTime = 0;
52
+ elapsedTime = 0;
53
+ fps = 0;
54
+ frameCount = 0;
55
+ fpsTimer = 0;
56
+ lastResourceStatsTime = 0;
57
+ static RESOURCE_STATS_INTERVAL = 1000;
58
+ // Frame rate limiter
59
+ targetFrameTime = 0;
60
+ limiterActive = false;
61
+ frameAccum = 0;
62
+ lastLimiterTick = 0;
63
+ rafInterval = 0;
64
+ rafSum = 0;
65
+ rafCount = 0;
66
+ lastRafTime = 0;
67
+ // Viewport management
68
+ viewportCount = 1;
69
+ viewports = [];
70
+ // Transient surface/depth handles (imported into the frame graph each frame)
71
+ colorHandle = null;
72
+ depthHandle = null;
73
+ graphCompiled = false;
74
+ // Reusable per-frame RenderContext (mutated per viewport — see renderViewport)
75
+ frameCtx = null;
76
+ // Depth texture cache (used when the graph does not own depth)
77
+ // LRU: Map insertion order = access order (delete + re-set on access).
78
+ depthTextures = new Map();
79
+ depthTextureCacheSize;
80
+ // Frame stats
81
+ frameDrawCalls = 0;
82
+ frameTriangles = 0;
83
+ // Callbacks
84
+ callbacks = {};
85
+ // Offscreen mode (set by game for postprocessing)
86
+ offscreenMode = null;
87
+ // XR render target provider (overrides canvas surface when set)
88
+ renderTargetProvider = null;
89
+ // rAF source override (for XR sessions)
90
+ rafSource = null;
91
+ cancelRaf = null;
92
+ currentRafId = 0;
93
+ // Dedup for the render chain: exactly one pending rAF may exist at a time.
94
+ // renderFrame() is also called outside the loop by renderOnce() (native
95
+ // screenshots, deterministic steps); letting it re-schedule leaked a
96
+ // permanent second (third, ...) render chain per call — each chain ran
97
+ // renderFrame() every pump tick, multiplying both real render work and the
98
+ // FPS counter (the "1100 fps" badge after MCP screenshot calls).
99
+ rafPending = false;
100
+ // Dpr
101
+ dpr = 1;
102
+ constructor(canvas, config = {}) {
103
+ this.canvas = canvas;
104
+ this.config = config;
105
+ this.depthFormat = config.depthFormat ?? "depth32float";
106
+ this.msaaSampleCount = config.msaaSampleCount ?? 1;
107
+ this.depthTextureCacheSize = config.depthTextureCacheSize ?? 3;
108
+ this.mode = config.mode ?? "3d";
109
+ this.deviceManager = new GPUDeviceManager();
110
+ this.inputManager = new InputManager(canvas, config.enablePointerLock ?? false);
111
+ this.frameGraph = new FrameGraph();
112
+ }
113
+ /** Build requiredLimits for the bindless binding model (clamped to adapter). */
114
+ buildRequiredLimits(adapter) {
115
+ const a = adapter.limits;
116
+ const clamp = (key, want) => {
117
+ const have = a[key];
118
+ if (have === undefined)
119
+ return null;
120
+ return [key, Math.min(want, Number(have))];
121
+ };
122
+ const entries = [];
123
+ [
124
+ clamp("maxTextureArrayLayers", 512),
125
+ clamp("maxStorageBuffersPerShaderStage", 8),
126
+ clamp("maxStorageBufferBindingSize", 64 * 1024 * 1024),
127
+ clamp("maxSampledTexturesPerShaderStage", 16),
128
+ ].forEach((e) => {
129
+ if (e)
130
+ entries.push(e);
131
+ });
132
+ return Object.fromEntries(entries);
133
+ }
134
+ async init() {
135
+ try {
136
+ // Device resolution order: explicit config → native host's device →
137
+ // self-acquire. On native the host owns the only wgpu device and the
138
+ // surface context — borrowing it avoids a second requestDevice() and
139
+ // a reconfigure race on the same surface. In-process there is
140
+ // exactly one device.
141
+ const nativeHost = getNativeHost();
142
+ const borrowedDevice = this.config.device ?? nativeHost?.device;
143
+ const borrowedAdapter = this.config.adapter ?? nativeHost?.adapter;
144
+ // An adapter is only required when we must acquire the device ourselves;
145
+ // a borrowed device is already usable (adapter.info is null-tolerated
146
+ // below).
147
+ const adapter = borrowedAdapter ?? await this.requestAdapterWithFallback();
148
+ if (!adapter && !borrowedDevice) {
149
+ log.error("game-renderer", "No GPU adapter found — check GPU drivers and /dev/dri permissions");
150
+ return false;
151
+ }
152
+ this.device = borrowedDevice ?? await this.requestDeviceFromAdapter(adapter);
153
+ this.adapter = adapter;
154
+ // The host configured the surface with its own usage set at creation —
155
+ // reconfiguring here would tear down the swapchain and race the host's
156
+ // readback hook. Skip when borrowing the host's device.
157
+ this.hostConfiguredSurface =
158
+ borrowedDevice !== undefined && borrowedDevice === nativeHost?.device;
159
+ // Install the shader validation guard so all createShaderModule calls
160
+ // route through getCompilationInfo() validation.
161
+ installShaderValidationGuard(this.device);
162
+ // Wrap device with GPU resource tracker for VRAM visibility
163
+ this.gpuResourceTracker = new GPUResourceTracker();
164
+ this.gpuResourceTracker.wrapDevice(this.device);
165
+ // GPU profiler
166
+ const adapterInfo = adapter?.info ?? null;
167
+ this.context = this.canvas.getContext("webgpu");
168
+ this.format = navigator.gpu.getPreferredCanvasFormat();
169
+ this.gpuProfiler = new GPUProfiler();
170
+ this.gpuProfiler.init(this.device, adapterInfo, this.format, 32);
171
+ log.debug("game-renderer", `GPU timer pool supported: ${this.gpuProfiler.isGpuTimerSupported()} features: ${Array.from(this.device.features).join(", ")}`);
172
+ // Device lost handler
173
+ this.device.lost.then((info) => {
174
+ this.handleDeviceLost(info);
175
+ });
176
+ // Configure surface — skipped when the surface was already configured
177
+ // by the device owner (native host) or the caller opted out. A borrowed
178
+ // host surface is never reconfigured: the host's usage set and
179
+ // pre-present readback hook are bound to its configure call.
180
+ if (!this.hostConfiguredSurface && (this.config.configureSurface ?? true)) {
181
+ this.context.configure({
182
+ device: this.device,
183
+ format: this.format,
184
+ alphaMode: "premultiplied",
185
+ });
186
+ }
187
+ // UI input router — the active UI stack (html-ui via Blitz) replaces
188
+ // this with its own router when its module registers.
189
+ this.uiInputRouter = new UIInputRouter();
190
+ this.inputManager.setUIInputRouter(this.uiInputRouter);
191
+ // Telemetry
192
+ this.telemetryCollector = new TelemetryCollector(this.config.enableTelemetry ?? true);
193
+ // Canvas resize watcher
194
+ this.resizeWatcher = new CanvasResizeWatcher(this.canvas, this);
195
+ // Input listeners
196
+ this.inputManager.setupListeners();
197
+ // Renderer plugin host — owns renderer-thread plugins (camera
198
+ // controllers, gizmos, XR frame loops, OSR). Created after InputManager
199
+ // so the host's input bus coexists with the FPS/pointer-lock layer.
200
+ this.rendererModuleHost = new RendererModuleHost(this.canvas, {
201
+ getSurface: () => this.canvas,
202
+ getDevice: () => this.device,
203
+ getFormat: () => this.format,
204
+ getGraph: () => this.frameGraph,
205
+ getSlotRegistry: () => this.frameGraph.getSlotRegistry(),
206
+ setOffscreenMode: (mode) => this.setOffscreenMode(mode),
207
+ setRenderTargetProvider: (provider) => this.setRenderTargetProvider(provider),
208
+ setRAFSource: (src, cancel) => {
209
+ if (src && cancel)
210
+ this.setRAFSource(src, cancel);
211
+ else
212
+ this.clearRAFSource();
213
+ },
214
+ setViewportCount: (count) => this.setViewportCount(count),
215
+ getUIInputRouter: () => this.uiInputRouter,
216
+ registerUiCompositor: (c) => {
217
+ this.uiCompositors.add(c);
218
+ return () => this.uiCompositors.delete(c);
219
+ },
220
+ });
221
+ // Initial viewport layout
222
+ this.updateViewports(1);
223
+ log.info("game-renderer", "initialized");
224
+ return true;
225
+ }
226
+ catch (err) {
227
+ log.error("game-renderer", `Init failed: ${err}`);
228
+ return false;
229
+ }
230
+ }
231
+ // --- Device acquisition + loss recovery ---
232
+ /** Adapter fallback chain: high-performance → low-power → any. */
233
+ async requestAdapterWithFallback() {
234
+ let adapter = await navigator.gpu.requestAdapter({
235
+ powerPreference: "high-performance",
236
+ });
237
+ if (!adapter) {
238
+ log.warn("game-renderer", "No high-performance GPU adapter, trying low-power...");
239
+ adapter = await navigator.gpu.requestAdapter({
240
+ powerPreference: "low-power",
241
+ });
242
+ }
243
+ if (!adapter) {
244
+ log.warn("game-renderer", "No low-power adapter, trying any...");
245
+ adapter = await navigator.gpu.requestAdapter({});
246
+ }
247
+ return adapter;
248
+ }
249
+ async requestDeviceFromAdapter(adapter) {
250
+ // Request timestamp-query features for GPU-side per-pass timing
251
+ const requiredFeatures = [];
252
+ if (adapter.features.has("timestamp-query")) {
253
+ requiredFeatures.push("timestamp-query");
254
+ }
255
+ return adapter.requestDevice({
256
+ requiredFeatures,
257
+ requiredLimits: this.buildRequiredLimits(adapter),
258
+ });
259
+ }
260
+ recoveringDevice = false;
261
+ handleDeviceLost(info) {
262
+ if (this.deviceLost || this.recoveringDevice)
263
+ return; // already handled
264
+ this.deviceLost = true;
265
+ log.error("game-renderer", `WebGPU device lost: ${info?.reason ?? "unknown"} — ${info?.message ?? ""}`);
266
+ try {
267
+ this.callbacks.onDeviceLost?.(info);
268
+ }
269
+ catch (err) {
270
+ log.error("game-renderer", `onDeviceLost callback threw: ${err}`);
271
+ }
272
+ if ((this.config.deviceLossRecovery ?? "auto") === "reload" ||
273
+ info?.reason === "destroyed" ||
274
+ this.hostConfiguredSurface) {
275
+ // "destroyed" = device.destroy() was called deliberately — a new device
276
+ // can't help, the app is tearing down or opted out. A borrowed host
277
+ // device can't be recovered in place either: the host's surface
278
+ // configure and readback hook are bound to the dead device, and every
279
+ // other holder of it (bridge, devtools hosts) would still point at
280
+ // the old handle. Restart instead.
281
+ this.reloadForDeviceLoss();
282
+ return;
283
+ }
284
+ this.recoverDevice();
285
+ }
286
+ reloadForDeviceLoss() {
287
+ setTimeout(() => {
288
+ // Host already tearing down (host.destroy() destroys the device,
289
+ // which resolves .lost with reason "destroyed") — restarting now
290
+ // would respawn a session on top of a dead window.
291
+ if (globalThis.__nativeHost?.destroyed)
292
+ return;
293
+ // Native runtime: window.location.reload() is a no-op. Route through
294
+ // the host's first-class restart hook (detached self-respawn — the
295
+ // real reload equivalent), then fall back to a dialog + clean quit if
296
+ // the restart budget is exhausted.
297
+ const req = globalThis.downdraft?.requestRestart;
298
+ if (typeof req === "function" && req("GPU device lost"))
299
+ return;
300
+ const nativeWin = globalThis.__nativeWindow;
301
+ if (nativeWin?.showMessageBox) {
302
+ try {
303
+ nativeWin.showMessageBox("GPU Device Lost", "The GPU device was lost and could not be recovered. The application will now close.");
304
+ }
305
+ catch { /* window may be gone */ }
306
+ try {
307
+ nativeWin.requestQuit?.();
308
+ }
309
+ catch { /* best-effort */ }
310
+ return;
311
+ }
312
+ log.warn("game-renderer", "Attempting page reload for GPU recovery...");
313
+ window.location.reload();
314
+ }, 2000);
315
+ }
316
+ /**
317
+ * Attempt in-place device recovery: re-acquire adapter+device, reconfigure
318
+ * the surface, re-prepare UI/profiler and every registered frame-graph
319
+ * pass, then recompile the graph (transient textures get fresh allocations
320
+ * on the new device). Falls back to a page reload on any failure.
321
+ */
322
+ async recoverDevice() {
323
+ this.recoveringDevice = true;
324
+ try {
325
+ const adapter = await this.requestAdapterWithFallback();
326
+ if (!adapter)
327
+ throw new Error("no GPU adapter after device loss");
328
+ const device = await this.requestDeviceFromAdapter(adapter);
329
+ device.lost.then((info) => this.handleDeviceLost(info));
330
+ this.device = device;
331
+ this.adapter = adapter;
332
+ installShaderValidationGuard(device);
333
+ this.gpuResourceTracker = new GPUResourceTracker();
334
+ this.gpuResourceTracker.wrapDevice(device);
335
+ this.context.configure({
336
+ device,
337
+ format: this.format,
338
+ alphaMode: "premultiplied",
339
+ });
340
+ const adapterInfo = adapter.info ?? null;
341
+ this.gpuProfiler?.init(device, adapterInfo, this.format, 32);
342
+ // Re-prepare every registered pass — pipelines/bind groups built on the
343
+ // dead device are invalid. Passes that can't recreate resources should
344
+ // throw here so we fall back to reload.
345
+ for (const pass of this.frameGraph.getPasses()) {
346
+ pass.prepare(device);
347
+ }
348
+ // Force graph recompile so transient textures are re-allocated on the
349
+ // new device — pooled physical textures and cached views all belong to
350
+ // the dead device and must not be reused.
351
+ this.frameGraph.invalidatePhysicalResources();
352
+ this.graphCompiled = false;
353
+ await this.onDeviceRecovered(device);
354
+ await this.callbacks.onDeviceRecovered?.(device);
355
+ this.deviceLost = false;
356
+ log.warn("game-renderer", "GPU device recovered — rendering resumed without reload");
357
+ }
358
+ catch (err) {
359
+ log.error("game-renderer", `Device recovery failed: ${err}`);
360
+ this.reloadForDeviceLoss();
361
+ }
362
+ finally {
363
+ this.recoveringDevice = false;
364
+ }
365
+ }
366
+ /**
367
+ * Subclass hook — called during device-loss recovery after the engine has
368
+ * re-prepared its own resources and all registered passes. Recreate
369
+ * subclass-owned GPU resources here. Throwing aborts recovery → reload.
370
+ */
371
+ async onDeviceRecovered(_device) { }
372
+ // --- CanvasResizeHandler ---
373
+ resolutionScale = 1;
374
+ lastCssW = 0;
375
+ lastCssH = 0;
376
+ lastRawDpr = 1;
377
+ /**
378
+ * Render-resolution scale [0.25..1]. Multiplies the effective DPR so the
379
+ * swap chain renders fewer pixels (performance) and the compositor
380
+ * upscales. Re-applies the last known canvas size immediately.
381
+ */
382
+ setResolutionScale(scale) {
383
+ this.resolutionScale = Math.max(0.25, Math.min(1, scale));
384
+ if (!getHostCapabilities().hasDom) {
385
+ // On the native host the swapchain extent must equal the window's
386
+ // real size — wgpu compares the configured size against the surface's
387
+ // currentExtent at acquire time and returns Outdated forever when
388
+ // they differ. Shrinking canvas.width/height would also corrupt
389
+ // clientWidth (UI layout + input coords). Resolution scaling needs
390
+ // an offscreen-render + upscale path to work here; for now it is a
391
+ // no-op rather than a brick.
392
+ if (this.resolutionScale < 1) {
393
+ log.warn("game-renderer", "resolutionScale is not supported on the native surface (swapchain must match the window size) — ignoring");
394
+ }
395
+ }
396
+ if (this.lastCssW > 0)
397
+ this.onResize(this.lastCssW, this.lastCssH, this.lastRawDpr);
398
+ }
399
+ getResolutionScale() {
400
+ return this.resolutionScale;
401
+ }
402
+ onResize(cssWidth, cssHeight, dpr) {
403
+ this.lastCssW = cssWidth;
404
+ this.lastCssH = cssHeight;
405
+ this.lastRawDpr = dpr;
406
+ // Render at the display's real DPR — resolutionScale is the opt-in
407
+ // performance knob when fill rate is a concern. On native the
408
+ // swapchain is window-sized (see setResolutionScale) so the scale is
409
+ // never applied to the backing store.
410
+ const cappedDpr = dpr * (getHostCapabilities().hasDom ? this.resolutionScale : 1);
411
+ this.dpr = cappedDpr;
412
+ const w = Math.round(cssWidth * cappedDpr);
413
+ const h = Math.round(cssHeight * cappedDpr);
414
+ if (this.canvas.width !== w)
415
+ this.canvas.width = w;
416
+ if (this.canvas.height !== h)
417
+ this.canvas.height = h;
418
+ this.updateViewports(this.viewportCount);
419
+ this.callbacks.onResize?.(cssWidth, cssHeight, dpr);
420
+ this.rendererModuleHost?.dispatchResize(cssWidth, cssHeight, dpr);
421
+ }
422
+ // --- Viewport management ---
423
+ setViewportCount(count) {
424
+ this.updateViewports(count);
425
+ }
426
+ getViewportCount() {
427
+ return this.viewportCount;
428
+ }
429
+ getViewport(idx) {
430
+ return this.viewports[idx] ?? null;
431
+ }
432
+ getViewports() {
433
+ return this.viewports;
434
+ }
435
+ updateViewports(count) {
436
+ this.viewportCount = count;
437
+ this.viewports = [];
438
+ const w = this.canvas.width;
439
+ const h = this.canvas.height;
440
+ if (count === 1) {
441
+ this.viewports.push({ x: 0, y: 0, w, h });
442
+ }
443
+ else if (count === 2) {
444
+ this.viewports.push({ x: 0, y: 0, w: w / 2, h });
445
+ this.viewports.push({ x: w / 2, y: 0, w: w / 2, h });
446
+ }
447
+ else if (count === 3) {
448
+ this.viewports.push({ x: 0, y: 0, w, h: h / 2 });
449
+ this.viewports.push({ x: 0, y: h / 2, w: w / 2, h: h / 2 });
450
+ this.viewports.push({ x: w / 2, y: h / 2, w: w / 2, h: h / 2 });
451
+ }
452
+ else if (count >= 4) {
453
+ this.viewports.push({ x: 0, y: 0, w: w / 2, h: h / 2 });
454
+ this.viewports.push({ x: w / 2, y: 0, w: w / 2, h: h / 2 });
455
+ this.viewports.push({ x: 0, y: h / 2, w: w / 2, h: h / 2 });
456
+ this.viewports.push({ x: w / 2, y: h / 2, w: w / 2, h: h / 2 });
457
+ }
458
+ }
459
+ // --- Frame rate limiter ---
460
+ setFrameRateLimit(refreshRate) {
461
+ if (refreshRate > 0) {
462
+ this.targetFrameTime = 1000 / refreshRate;
463
+ this.updateLimiterState();
464
+ }
465
+ else {
466
+ this.targetFrameTime = 0;
467
+ this.limiterActive = false;
468
+ }
469
+ }
470
+ updateLimiterState() {
471
+ if (this.targetFrameTime <= 0 || this.rafInterval <= 0) {
472
+ this.limiterActive = this.targetFrameTime > 0;
473
+ return;
474
+ }
475
+ this.limiterActive = this.rafInterval < this.targetFrameTime * 0.85;
476
+ }
477
+ // --- Render loop ---
478
+ start() {
479
+ this.running = true;
480
+ this.lastTime = performance.now();
481
+ // Go through scheduleRender() rather than invoking render() inline — a
482
+ // pending rAF (loop already primed) would otherwise survive alongside the
483
+ // new registration and double the chain.
484
+ this.scheduleRender();
485
+ }
486
+ stop() {
487
+ this.running = false;
488
+ // cancelRaf only exists when a rAF source override (XR) is installed —
489
+ // fall back to the global so the pending callback is actually removed.
490
+ const cancel = this.cancelRaf ?? (typeof cancelAnimationFrame === "function" ? cancelAnimationFrame : null);
491
+ if (cancel && this.currentRafId) {
492
+ cancel(this.currentRafId);
493
+ this.currentRafId = 0;
494
+ }
495
+ this.rafPending = false;
496
+ }
497
+ /** True while the render loop is started (frames are being scheduled). */
498
+ isRunning() {
499
+ return this.running;
500
+ }
501
+ /** Render a single frame on demand — deterministic/test mode and native
502
+ * screenshot capture call this while the loop is stopped. Bypasses the
503
+ * frame limiter; safe to call with the loop running or stopped. */
504
+ renderOnce() {
505
+ if (!this.device || !this.context || this.deviceLost)
506
+ return;
507
+ const savedLimiter = this.limiterActive;
508
+ this.limiterActive = false;
509
+ try {
510
+ this.prepareForcedFrame();
511
+ this.renderFrame();
512
+ }
513
+ finally {
514
+ this.limiterActive = savedLimiter;
515
+ }
516
+ }
517
+ /** Subclass hook: clear internal dirty-tracking so renderOnce() actually
518
+ * draws. Renderers that skip unchanged frames (e.g. MiningRenderer's
519
+ * forceDirty check) override this to force the next frame out. */
520
+ prepareForcedFrame() { }
521
+ /** Schedule the next render() invocation. Centralized here so renderFrame()
522
+ * stays scheduling-free — renderOnce() and test paths call renderFrame()
523
+ * directly and must never grow a parallel loop. */
524
+ scheduleRender() {
525
+ if (this.rafPending)
526
+ return;
527
+ this.rafPending = true;
528
+ this.currentRafId = this.rafSource ? this.rafSource(this.render) : requestAnimationFrame(this.render);
529
+ }
530
+ render = () => {
531
+ this.rafPending = false;
532
+ this.currentRafId = 0;
533
+ if (!this.running)
534
+ return;
535
+ if (!this.device || !this.context) {
536
+ // init() hasn't finished — keep the chain alive until it has.
537
+ this.scheduleRender();
538
+ return;
539
+ }
540
+ // Measure rAF interval (rolling average over 60 samples)
541
+ const rafNow = performance.now();
542
+ if (this.lastRafTime > 0) {
543
+ this.rafSum += rafNow - this.lastRafTime;
544
+ this.rafCount++;
545
+ if (this.rafCount >= 60) {
546
+ this.rafInterval = this.rafSum / this.rafCount;
547
+ this.rafSum = 0;
548
+ this.rafCount = 0;
549
+ this.updateLimiterState();
550
+ }
551
+ }
552
+ this.lastRafTime = rafNow;
553
+ if (this.deviceLost) {
554
+ // Keep the loop alive while the device is lost — handleDeviceLost()
555
+ // re-creates the device and clears this flag; returning without
556
+ // re-scheduling would permanently stop rendering after a transient
557
+ // GPU crash.
558
+ this.scheduleRender();
559
+ return;
560
+ }
561
+ try {
562
+ this.renderFrame();
563
+ }
564
+ catch (err) {
565
+ log.error("game-renderer", `Render loop error: ${err.message}\n${err.stack}`);
566
+ if (this.device?.lost) {
567
+ this.device.lost.then((info) => {
568
+ this.handleDeviceLost(info);
569
+ });
570
+ }
571
+ }
572
+ this.scheduleRender();
573
+ };
574
+ renderFrame() {
575
+ const now = performance.now();
576
+ // Frame rate limiter: phase accumulator (skip during XR — XR drives its own cadence)
577
+ // Accumulate real elapsed time in frame units — NOT rafInterval ratios.
578
+ // The ratio variant starved on hosts with a faster-than-vsync rAF pump
579
+ // (native SDL loop ticks at ~µs cadence): updateLimiterState() resets
580
+ // frameAccum every 60 rAF samples, and 60 × rafInterval/targetFrameTime
581
+ // never reached 1, so present() was never called.
582
+ if (!this.renderTargetProvider && this.limiterActive && this.targetFrameTime > 0) {
583
+ if (this.lastLimiterTick === 0)
584
+ this.lastLimiterTick = now;
585
+ this.frameAccum += (now - this.lastLimiterTick) / this.targetFrameTime;
586
+ this.lastLimiterTick = now;
587
+ if (this.frameAccum < 1) {
588
+ // render() owns re-scheduling — just skip the frame's work.
589
+ return;
590
+ }
591
+ // Cap carry at one frame — a stale lastLimiterTick (limiter toggled
592
+ // off→on) would otherwise burst-render to drain a huge accumulator.
593
+ this.frameAccum = Math.min(this.frameAccum - 1, 1);
594
+ }
595
+ const dt = Math.min(0.1, (now - this.lastTime) / 1000);
596
+ this.lastTime = now;
597
+ this.elapsedTime += dt;
598
+ // FPS counter
599
+ this.frameCount++;
600
+ this.fpsTimer += dt;
601
+ if (this.fpsTimer >= 1) {
602
+ this.fps = this.frameCount;
603
+ this.frameCount = 0;
604
+ this.fpsTimer = 0;
605
+ }
606
+ // Before frame callback (game-specific: camera updates, input processing)
607
+ this.callbacks.beforeFrame?.(dt, this.elapsedTime);
608
+ this.rendererModuleHost?.dispatchFrame("beforeFrame", dt, this.elapsedTime);
609
+ // Before viewports callback (game-specific: particle ticks, pre-viewport setup)
610
+ this.callbacks.beforeViewports?.(dt, this.elapsedTime);
611
+ this.rendererModuleHost?.dispatchFrame("beforeViewports", dt, this.elapsedTime);
612
+ // If an uncaptured GPU error has fired, skip all GPU work this frame to
613
+ // avoid the per-frame cascade of native "is invalid due to a previous
614
+ // error" validation warnings. Game logic callbacks still run so the
615
+ // simulation stays responsive. The flag is cleared by recovery code that
616
+ // recreates the invalid resources.
617
+ const gpuError = this.gpuProfiler?.hasUncapturedError() ?? false;
618
+ // XR render target provider beginFrame hook
619
+ if (this.renderTargetProvider && !gpuError) {
620
+ this.renderTargetProvider.beginFrame();
621
+ }
622
+ // Render each viewport
623
+ const offscreen = this.offscreenMode;
624
+ const useOffscreen = offscreen && offscreen.type !== "none";
625
+ if (offscreen && useOffscreen && offscreen.ensureTargets && !gpuError) {
626
+ offscreen.ensureTargets(this.canvas.width, this.canvas.height);
627
+ }
628
+ // Collect command buffers from all phases and submit once at the end
629
+ // (reduces CPU→GPU sync points from 3+ per frame to 1).
630
+ const frameCommandBuffers = [];
631
+ if (!gpuError) {
632
+ // 2D mode with viewportCount=0: clear the canvas if a clearColor is
633
+ // configured, then let the afterFrame callback do custom rendering.
634
+ if (this.viewportCount === 0 && this.device && this.context && this.config.clearColor !== null) {
635
+ const clearTex = this.getSurfaceTexture();
636
+ if (clearTex) {
637
+ const clearEncoder = this.device.createCommandEncoder();
638
+ const clearPass = clearEncoder.beginRenderPass({
639
+ colorAttachments: [{
640
+ view: clearTex.createView(),
641
+ clearValue: this.config.clearColor ?? { r: 0, g: 0, b: 0, a: 1 },
642
+ loadOp: "clear",
643
+ storeOp: "store",
644
+ }],
645
+ });
646
+ clearPass.end();
647
+ frameCommandBuffers.push(clearEncoder.finish());
648
+ }
649
+ }
650
+ for (let v = 0; v < this.viewportCount; v++) {
651
+ const cb = this.renderViewport(v, dt, offscreen);
652
+ if (cb)
653
+ frameCommandBuffers.push(cb);
654
+ }
655
+ // Apply postprocessing
656
+ if (offscreen && useOffscreen && offscreen.applyPostprocess) {
657
+ const canvasView = this.getSurfaceTexture()?.createView();
658
+ if (canvasView) {
659
+ const postEncoder = this.device.createCommandEncoder();
660
+ offscreen.applyPostprocess(postEncoder, canvasView, this.canvas.width, this.canvas.height);
661
+ frameCommandBuffers.push(postEncoder.finish());
662
+ }
663
+ }
664
+ }
665
+ // After viewports callback
666
+ this.callbacks.afterViewports?.(dt, this.elapsedTime);
667
+ this.rendererModuleHost?.dispatchFrame("afterViewports", dt, this.elapsedTime);
668
+ // Worker-produced passes (postPass → "preSubmit" slot on the native
669
+ // host's GpuPassMailbox) join this frame's submit batch — refs that
670
+ // arrived since the last drain execute after the owner's buffers.
671
+ // Stale-tolerant by design: a worker that misses the drain lands next
672
+ // frame instead of rendezvousing the render thread.
673
+ const passMailbox = getNativeHost()?.passMailbox;
674
+ if (passMailbox) {
675
+ frameCommandBuffers.push(...passMailbox.drain("preSubmit"));
676
+ }
677
+ // Submit all command buffers for this frame in a single queue.submit() call
678
+ if (frameCommandBuffers.length > 0) {
679
+ this.device.queue.submit(frameCommandBuffers);
680
+ }
681
+ // Read GPU timer results asynchronously (1-frame latency).
682
+ // Must be called AFTER queue.submit() — readGpuTimers() calls mapAsync on
683
+ // the read buffer, and a mapped/mapping-pending buffer cannot be used in a
684
+ // submitted command buffer (the copy-to-readBuffer was encoded above).
685
+ if (this.gpuProfiler) {
686
+ this.gpuProfiler.readGpuTimers().then(() => {
687
+ // Results available for next frame
688
+ }).catch(() => { });
689
+ }
690
+ // Record telemetry
691
+ if (this.telemetryCollector) {
692
+ this.telemetryCollector.recordFrame(dt * 1000);
693
+ this.telemetryCollector.recordDrawStats(this.frameDrawCalls, this.frameTriangles);
694
+ this.telemetryCollector.recordGraphSample(dt * 1000);
695
+ if (this.gpuProfiler) {
696
+ for (const timing of this.gpuProfiler.getPassTimings()) {
697
+ this.telemetryCollector.recordPassTiming(timing);
698
+ }
699
+ }
700
+ if (this.gpuResourceTracker && now - this.lastResourceStatsTime > GameRenderer.RESOURCE_STATS_INTERVAL) {
701
+ this.lastResourceStatsTime = now;
702
+ const resStats = this.gpuResourceTracker.getStats();
703
+ this.telemetryCollector.recordResourceStats({
704
+ textureCount: resStats.textureCount,
705
+ bufferCount: resStats.bufferCount,
706
+ totalBytes: resStats.totalBytes,
707
+ textureBytes: resStats.textureBytes,
708
+ bufferBytes: resStats.bufferBytes,
709
+ resources: resStats.resources.map((r) => ({
710
+ id: r.id,
711
+ type: r.type,
712
+ label: r.label,
713
+ size: r.size,
714
+ callsite: r.callsite,
715
+ width: r.width,
716
+ height: r.height,
717
+ format: r.format,
718
+ })),
719
+ });
720
+ }
721
+ this.frameDrawCalls = 0;
722
+ this.frameTriangles = 0;
723
+ }
724
+ // XR render target provider endFrame hook (skip on GPU error)
725
+ if (!gpuError && this.renderTargetProvider && this.device) {
726
+ this.renderTargetProvider.endFrame(this.device.createCommandEncoder());
727
+ }
728
+ // After frame callback
729
+ this.callbacks.afterFrame?.(dt, this.elapsedTime);
730
+ this.rendererModuleHost?.dispatchFrame("afterFrame", dt, this.elapsedTime);
731
+ // Composite registered screen-space UI (html-ui panels) on top of the
732
+ // final image (skip on GPU error to avoid cascade). This must run AFTER
733
+ // afterFrame — 2D games (viewportCount=0) do their custom rendering in
734
+ // the afterFrame callback, so drawing UI earlier would put it underneath
735
+ // their clear pass.
736
+ if (!gpuError && this.device && this.context) {
737
+ const compositors = [...this.uiCompositors]
738
+ .filter((c) => c.hasContent())
739
+ .sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
740
+ const uiCanvasView = compositors.length > 0
741
+ ? this.getSurfaceTexture()?.createView()
742
+ : undefined;
743
+ if (uiCanvasView) {
744
+ const uiEncoder = this.device.createCommandEncoder();
745
+ const uiPass = uiEncoder.beginRenderPass({
746
+ colorAttachments: [{
747
+ view: uiCanvasView,
748
+ clearValue: { r: 0, g: 0, b: 0, a: 0 },
749
+ loadOp: "load",
750
+ storeOp: "store",
751
+ }],
752
+ });
753
+ compositors.forEach((c) => { c.render(uiPass, this.canvas.width, this.canvas.height); });
754
+ uiPass.end();
755
+ // "preUi" slot — worker passes ordered ahead of the UI-composite
756
+ // submit so their output is visible to the compositor this frame.
757
+ this.device.queue.submit([...(passMailbox?.drain("preUi") ?? []), uiEncoder.finish()]);
758
+ }
759
+ }
760
+ // Present the surface (native wgpu requires explicit presentation;
761
+ // in browsers this is automatic at the end of the frame). Must be last —
762
+ // all submissions targeting the surface texture happen above.
763
+ if (this.context && this.context.present) {
764
+ this.context.present();
765
+ }
766
+ const __rfTotal = performance.now() - now;
767
+ if (this.config.debugTimingWarnings && __rfTotal > 20)
768
+ log.warn("game-renderer", `renderFrame took ${__rfTotal.toFixed(1)}ms`);
769
+ // NOTE: renderFrame() intentionally does NOT schedule the next frame —
770
+ // render() owns the rAF chain so one-shot callers (renderOnce, MCP
771
+ // screenshot capture) can't leak parallel loops.
772
+ }
773
+ /**
774
+ * Acquire this frame's swapchain texture. May return null on the native
775
+ * runtime while the surface can't produce a frame (in-flight resize,
776
+ * occluded window, transient swapchain failure) — callers must skip the
777
+ * canvas-targeted GPU work for that frame instead of crashing on
778
+ * `null.createView()`.
779
+ */
780
+ getSurfaceTexture() {
781
+ try {
782
+ return this.context?.getCurrentTexture() ?? null;
783
+ }
784
+ catch {
785
+ return null;
786
+ }
787
+ }
788
+ renderViewport(viewportIdx, dt, offscreen) {
789
+ if (!this.device || !this.context)
790
+ return null;
791
+ const xrProvider = this.renderTargetProvider;
792
+ const useOffscreen = !xrProvider && offscreen && offscreen.type !== "none";
793
+ const origViewport = xrProvider
794
+ ? xrProvider.getViewportRect(viewportIdx, this.canvas.width, this.canvas.height)
795
+ : this.viewports[viewportIdx];
796
+ if (!origViewport)
797
+ return null;
798
+ const viewport = (useOffscreen && offscreen?.scaleViewport)
799
+ ? offscreen.scaleViewport(origViewport)
800
+ : origViewport;
801
+ // Get camera info: viewport camera provider (XR) takes priority, then
802
+ // game callback, then renderer plugin host's camera controller fallback.
803
+ // The game callback is always called (even when the provider returns
804
+ // non-null) so side effects like per-eye uniform updates still run.
805
+ const providerInfo = this.rendererModuleHost?.getViewportCameraInfo(viewportIdx, dt, this.elapsedTime) ?? null;
806
+ const gameInfo = this.callbacks.onViewport?.(viewportIdx, dt, this.elapsedTime) ?? null;
807
+ let camInfo = providerInfo ?? gameInfo;
808
+ if (!camInfo && this.rendererModuleHost) {
809
+ const camState = this.rendererModuleHost.getCameraState(viewportIdx);
810
+ if (camState) {
811
+ camInfo = { camera: camState, viewport };
812
+ }
813
+ }
814
+ // 2D mode: if no camera info was provided, use a default orthographic
815
+ // camera that covers the full viewport. This allows 2D-only renderers
816
+ // (sand games, tile games) to use GameRenderer without a camera system.
817
+ if (!camInfo && this.mode === "2d") {
818
+ camInfo = {
819
+ camera: {
820
+ position: [0, 0, 1],
821
+ target: [0, 0, 0],
822
+ up: [0, 1, 0],
823
+ fov: 90,
824
+ near: 0.1,
825
+ far: 100,
826
+ aspect: viewport.w / viewport.h,
827
+ },
828
+ viewport,
829
+ };
830
+ }
831
+ if (!camInfo)
832
+ return null;
833
+ const isFirst = viewportIdx === 0;
834
+ const isLast = viewportIdx === this.viewportCount - 1;
835
+ // Determine color/depth views — XR provider takes precedence, then offscreen, then canvas
836
+ const __ctStart = performance.now();
837
+ const colorView = xrProvider
838
+ ? xrProvider.getColorView(viewportIdx)
839
+ : (useOffscreen && offscreen)
840
+ ? (offscreen.type === "pixelation"
841
+ ? offscreen.getColorView()
842
+ : offscreen.type === "postprocess"
843
+ ? (offscreen.getSceneColorView?.() ?? this.getSurfaceTexture()?.createView())
844
+ : this.getSurfaceTexture()?.createView())
845
+ : this.getSurfaceTexture()?.createView();
846
+ const __ctMs = performance.now() - __ctStart;
847
+ // Swapchain couldn't produce a frame (native resize in flight, occluded
848
+ // window, transient failure) — skip this viewport's GPU work; game
849
+ // callbacks already ran above and the loop stays alive for next frame.
850
+ if (!colorView)
851
+ return null;
852
+ if (this.config.debugTimingWarnings && __ctMs > 20)
853
+ log.warn("game-renderer", `getCurrentTexture took ${__ctMs.toFixed(1)}ms`);
854
+ const depthView = xrProvider
855
+ ? xrProvider.getDepthView(viewportIdx, origViewport.w, origViewport.h)
856
+ : (useOffscreen && offscreen)
857
+ ? (offscreen.type === "pixelation"
858
+ ? offscreen.getDepthView()
859
+ : offscreen.type === "postprocess"
860
+ ? (offscreen.getSceneDepthView?.() ?? this.createDepthTexture(origViewport.w, origViewport.h))
861
+ : this.createDepthTexture(origViewport.w, origViewport.h))
862
+ : this.createDepthTexture(origViewport.w, origViewport.h);
863
+ // Ensure graph handles exist for the imported color/depth views.
864
+ if (!this.colorHandle) {
865
+ this.colorHandle = this.frameGraph.importTextureView("color", null);
866
+ this.frameGraph.markDirty();
867
+ }
868
+ if (!this.depthHandle) {
869
+ this.depthHandle = this.frameGraph.importTextureView("depth", null);
870
+ this.frameGraph.markDirty();
871
+ }
872
+ this.frameGraph.setImportedTextureView(this.colorHandle, colorView);
873
+ this.frameGraph.setImportedTextureView(this.depthHandle, depthView);
874
+ if (isFirst) {
875
+ this.gpuProfiler.beginFrame();
876
+ }
877
+ if (this.frameGraph.isDirty() || !this.graphCompiled) {
878
+ this.frameGraph.compile(this.device, this.canvas.width, this.canvas.height);
879
+ this.graphCompiled = true;
880
+ }
881
+ const encoder = this.device.createCommandEncoder();
882
+ // Reuse a single RenderContext across viewports/frames — allocating the
883
+ // ~35-field literal per viewport per frame was pure GC churn. Fields that
884
+ // vary per viewport are reassigned below; the closures capture `this` and
885
+ // are created once.
886
+ if (!this.frameCtx) {
887
+ this.frameCtx = {
888
+ device: this.device,
889
+ encoder,
890
+ pass: null,
891
+ camera: camInfo.camera,
892
+ viewport,
893
+ viewportIdx,
894
+ viewportCount: this.viewportCount,
895
+ dt,
896
+ elapsedTime: this.elapsedTime,
897
+ isFirstViewport: isFirst,
898
+ isLastViewport: isLast,
899
+ width: viewport.w,
900
+ height: viewport.h,
901
+ viewProj: undefined,
902
+ invViewProj: undefined,
903
+ prevViewProj: undefined,
904
+ cameraPos: camInfo.camera.position,
905
+ lightData: null,
906
+ lightViewProj: undefined,
907
+ mesh: null,
908
+ modelMatrix: undefined,
909
+ shadowsEnabled: false,
910
+ bloomEnabled: false,
911
+ shadowSampler: null,
912
+ debugQueue: null,
913
+ opaqueVertexBuffer: null,
914
+ opaqueIndexBuffer: null,
915
+ opaqueIndexCount: 0,
916
+ opaqueIndexFormat: "uint32",
917
+ getView: (h) => this.frameGraph.getTextureView(h),
918
+ getTexture: (h) => this.frameGraph.getTexture(h),
919
+ addDrawCalls: (n) => { this.frameDrawCalls += n; },
920
+ addTriangles: (n) => { this.frameTriangles += n; },
921
+ };
922
+ }
923
+ const ctx = this.frameCtx;
924
+ ctx.device = this.device;
925
+ ctx.encoder = encoder;
926
+ ctx.camera = camInfo.camera;
927
+ ctx.viewport = viewport;
928
+ ctx.viewportIdx = viewportIdx;
929
+ ctx.viewportCount = this.viewportCount;
930
+ ctx.dt = dt;
931
+ ctx.elapsedTime = this.elapsedTime;
932
+ ctx.isFirstViewport = isFirst;
933
+ ctx.isLastViewport = isLast;
934
+ ctx.width = viewport.w;
935
+ ctx.height = viewport.h;
936
+ ctx.cameraPos = camInfo.camera.position;
937
+ this.frameGraph.execute(ctx);
938
+ // Resolve GPU timestamp queries on first viewport.
939
+ // NOTE: readGpuTimers() (which calls mapAsync on the read buffer) must NOT
940
+ // be called here — the command buffer containing the copy-to-readBuffer
941
+ // hasn't been submitted yet. Calling mapAsync before submit puts the buffer
942
+ // in a mapped-pending state, and the subsequent queue.submit() fails with
943
+ // "Buffer used in submit while mapped." readGpuTimers() is called after
944
+ // submit in renderFrame().
945
+ if (isFirst) {
946
+ this.gpuProfiler.resolveGpuTimers(encoder);
947
+ }
948
+ return encoder.finish();
949
+ }
950
+ // --- Depth texture cache ---
951
+ createDepthTexture(w, h) {
952
+ if (!this.device)
953
+ throw new Error("No device");
954
+ const key = `${w}x${h}`;
955
+ let tex = this.depthTextures.get(key);
956
+ if (tex) {
957
+ // LRU: move to most-recently-used by re-inserting.
958
+ this.depthTextures.delete(key);
959
+ this.depthTextures.set(key, tex);
960
+ }
961
+ else {
962
+ tex = this.device.createTexture({
963
+ size: [w, h],
964
+ format: this.depthFormat,
965
+ usage: GPUTextureUsage.RENDER_ATTACHMENT,
966
+ });
967
+ this.depthTextures.set(key, tex);
968
+ // Evict oldest entries if over cap.
969
+ while (this.depthTextures.size > this.depthTextureCacheSize) {
970
+ const oldestKey = this.depthTextures.keys().next().value;
971
+ if (oldestKey === undefined)
972
+ break;
973
+ const oldest = this.depthTextures.get(oldestKey);
974
+ this.depthTextures.delete(oldestKey);
975
+ oldest?.destroy();
976
+ }
977
+ }
978
+ return tex.createView();
979
+ }
980
+ // --- UI ---
981
+ // --- Offscreen mode ---
982
+ setOffscreenMode(mode) {
983
+ this.offscreenMode = mode;
984
+ }
985
+ getOffscreenMode() {
986
+ return this.offscreenMode;
987
+ }
988
+ // --- XR render target provider ---
989
+ setRenderTargetProvider(provider) {
990
+ this.renderTargetProvider = provider;
991
+ }
992
+ getRenderTargetProvider() {
993
+ return this.renderTargetProvider;
994
+ }
995
+ // --- rAF source override (for XR sessions) ---
996
+ setRAFSource(request, cancel) {
997
+ this.rafSource = request;
998
+ this.cancelRaf = cancel;
999
+ }
1000
+ clearRAFSource() {
1001
+ this.rafSource = null;
1002
+ this.cancelRaf = null;
1003
+ }
1004
+ // --- Callbacks ---
1005
+ setCallbacks(callbacks) {
1006
+ this.callbacks = callbacks;
1007
+ }
1008
+ /** Get the current frame callbacks (for wrapping/extending). */
1009
+ getCallbacks() {
1010
+ return this.callbacks;
1011
+ }
1012
+ // --- Renderer plugins ---
1013
+ useRendererModule(plugin) {
1014
+ if (!this.rendererModuleHost) {
1015
+ throw new Error("RendererModuleHost not initialized — call init() first");
1016
+ }
1017
+ this.rendererModuleHost.registerModule(plugin);
1018
+ }
1019
+ getRendererModuleHost() {
1020
+ return this.rendererModuleHost;
1021
+ }
1022
+ /**
1023
+ * Composite registered screen-space UI (html-ui panels via
1024
+ * ctx.registerUiCompositor) onto the current surface texture.
1025
+ *
1026
+ * Renderers with a custom drawFrame()/present path that bypass
1027
+ * renderFrame() must call this at end-of-frame — after post-processing
1028
+ * lands on the surface, before present — or module-registered UI will
1029
+ * never be drawn. renderFrame() itself uses the equivalent block inline;
1030
+ * this helper only runs the compositors.
1031
+ */
1032
+ renderScreenUiCompositors() {
1033
+ const compositors = [...this.uiCompositors]
1034
+ .filter((c) => c.hasContent())
1035
+ .sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
1036
+ if (compositors.length === 0 || !this.device || !this.context)
1037
+ return;
1038
+ const canvasView = this.getSurfaceTexture()?.createView();
1039
+ if (!canvasView)
1040
+ return;
1041
+ const uiEncoder = this.device.createCommandEncoder();
1042
+ const uiPass = uiEncoder.beginRenderPass({
1043
+ colorAttachments: [{
1044
+ view: canvasView,
1045
+ clearValue: { r: 0, g: 0, b: 0, a: 0 },
1046
+ loadOp: "load",
1047
+ storeOp: "store",
1048
+ }],
1049
+ });
1050
+ compositors.forEach((c) => { c.render(uiPass, this.canvas.width, this.canvas.height); });
1051
+ uiPass.end();
1052
+ this.device.queue.submit([uiEncoder.finish()]);
1053
+ }
1054
+ // --- Getters ---
1055
+ getDevice() {
1056
+ return this.device;
1057
+ }
1058
+ getAdapter() {
1059
+ return this.adapter;
1060
+ }
1061
+ getContext() {
1062
+ return this.context;
1063
+ }
1064
+ getFormat() {
1065
+ return this.format;
1066
+ }
1067
+ getDepthFormat() {
1068
+ return this.depthFormat;
1069
+ }
1070
+ getMSAASampleCount() {
1071
+ return this.msaaSampleCount;
1072
+ }
1073
+ /** The render surface this renderer draws into. Canonical accessor. */
1074
+ getSurface() {
1075
+ return this.canvas;
1076
+ }
1077
+ /** @deprecated Use getSurface() — the surface is not necessarily a DOM canvas. */
1078
+ getCanvas() {
1079
+ return this.canvas;
1080
+ }
1081
+ getCanvasWidth() {
1082
+ return this.canvas.width;
1083
+ }
1084
+ getCanvasHeight() {
1085
+ return this.canvas.height;
1086
+ }
1087
+ getFPS() {
1088
+ return this.fps;
1089
+ }
1090
+ getElapsedTime() {
1091
+ return this.elapsedTime;
1092
+ }
1093
+ getInputManager() {
1094
+ return this.inputManager;
1095
+ }
1096
+ getGraph() {
1097
+ return this.frameGraph;
1098
+ }
1099
+ getSlotRegistry() {
1100
+ return this.frameGraph.getSlotRegistry();
1101
+ }
1102
+ getUIInputRouter() {
1103
+ return this.uiInputRouter;
1104
+ }
1105
+ getTelemetryCollector() {
1106
+ return this.telemetryCollector;
1107
+ }
1108
+ getGPUProfiler() {
1109
+ return this.gpuProfiler;
1110
+ }
1111
+ getFrameGraph() {
1112
+ if (!this.gpuProfiler)
1113
+ return null;
1114
+ const passTimings = this.gpuProfiler.getPassTimings();
1115
+ const ppInfo = this.callbacks.getPostProcessInfo?.() ?? {
1116
+ pixelationEnabled: false, pixelSize: 4, postProcessEffects: [],
1117
+ };
1118
+ const passNames = this.frameGraph.getPassOrder();
1119
+ return GPUProfiler.buildFrameGraphData(passTimings, ppInfo, passNames);
1120
+ }
1121
+ getGPUResourceTracker() {
1122
+ return this.gpuResourceTracker;
1123
+ }
1124
+ getGPUInfo() {
1125
+ if (!this.gpuProfiler)
1126
+ return null;
1127
+ return this.gpuProfiler.getGPUInfo(this.canvas, this.msaaSampleCount);
1128
+ }
1129
+ getAdapterInfo() {
1130
+ return this.gpuProfiler?.getAdapterInfo() ?? null;
1131
+ }
1132
+ getGPUErrors() {
1133
+ return this.gpuProfiler?.getGPUErrors() ?? [];
1134
+ }
1135
+ clearGPUErrors() {
1136
+ this.gpuProfiler?.clearGPUErrors();
1137
+ }
1138
+ getDpr() {
1139
+ return this.dpr;
1140
+ }
1141
+ // --- Frame stats (for game passes to update) ---
1142
+ addDrawCalls(n) {
1143
+ this.frameDrawCalls += n;
1144
+ }
1145
+ addTriangles(n) {
1146
+ this.frameTriangles += n;
1147
+ }
1148
+ // --- Destroy ---
1149
+ destroy() {
1150
+ this.running = false;
1151
+ this.resizeWatcher?.destroy();
1152
+ this.resizeWatcher = null;
1153
+ this.rendererModuleHost?.disposeAll();
1154
+ this.rendererModuleHost = null;
1155
+ this.inputManager.destroy();
1156
+ this.gpuProfiler?.destroy();
1157
+ this.gpuProfiler = null;
1158
+ this.telemetryCollector = null;
1159
+ this.device = null;
1160
+ for (const tex of this.depthTextures.values()) {
1161
+ tex.destroy();
1162
+ }
1163
+ this.depthTextures.clear();
1164
+ }
1165
+ }