@downdraft/engine 0.1.0 → 0.1.2-alpha.5

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 (1022) hide show
  1. package/README.md +33 -0
  2. package/app/README.md +11 -0
  3. package/app/src/renderer/bootstrap.ts +295 -19
  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/library/host.ts +27 -13
  21. package/core/src/library/library.ts +13 -5
  22. package/core/src/module/cross-thread.ts +6 -0
  23. package/core/src/module/diagnostics.ts +10 -6
  24. package/core/src/module/host.ts +65 -18
  25. package/core/src/module/index.ts +1 -0
  26. package/core/src/module/module.ts +11 -5
  27. package/core/src/module/renderer-module.ts +15 -0
  28. package/core/src/physics/safety.ts +1 -1
  29. package/core/src/platform/bun-preload.ts +7 -2
  30. package/core/src/platform/glob-polyfill.ts +17 -8
  31. package/core/src/platform/pkg-root.ts +27 -0
  32. package/core/src/platform/runtime.ts +38 -0
  33. package/core/src/plugin/discovery.ts +1 -1
  34. package/core/src/plugin/extension-loaders.ts +6 -4
  35. package/core/src/plugin/host.ts +13 -13
  36. package/core/src/plugin/loader-asset.ts +5 -5
  37. package/core/src/plugin/loader-quickjs.ts +1 -1
  38. package/core/src/plugin/loader-wasm.ts +3 -3
  39. package/core/src/plugin/loader-worker.ts +1 -1
  40. package/core/src/plugin/manifest.ts +8 -3
  41. package/core/src/plugin/workshop.ts +3 -3
  42. package/core/src/profiling/index.ts +1 -1
  43. package/core/src/profiling/profiling-sab.ts +19 -0
  44. package/core/src/profiling/warnings.ts +1 -1
  45. package/core/src/profiling/worker-prelude.ts +1 -1
  46. package/core/src/render/bindless/frame-bindings.ts +1 -1
  47. package/core/src/render/bindless/material-manager.ts +2 -2
  48. package/core/src/render/bindless/texture-registry.ts +2 -2
  49. package/core/src/render/device.ts +5 -5
  50. package/core/src/render/frame-graph.ts +2 -2
  51. package/core/src/render/game-renderer.ts +42 -18
  52. package/core/src/render/hot-reload.ts +3 -3
  53. package/core/src/render/renderer-module-host.ts +32 -12
  54. package/core/src/render/shader-validator.ts +7 -7
  55. package/core/src/render/surface.ts +1 -1
  56. package/core/src/sab/errors.ts +1 -1
  57. package/core/src/sab/sab-polyfill.ts +1 -1
  58. package/core/src/save/migration-registry.ts +4 -4
  59. package/core/src/save/schema.ts +1 -1
  60. package/core/src/scene/prefab.ts +1 -1
  61. package/core/src/scene/scene-manager.ts +2 -2
  62. package/core/src/scene/scene.ts +4 -4
  63. package/core/src/scene/streaming.ts +2 -2
  64. package/core/src/scripting/hot-reload.ts +2 -2
  65. package/core/src/sim/hot-reload-pipeline.ts +30 -6
  66. package/core/src/sim/sim-state-helper.ts +1 -1
  67. package/core/src/sim/transient-state-registry.ts +1 -1
  68. package/core/src/sim/worker-loop.ts +2 -2
  69. package/core/src/telemetry/gpu-profiler.ts +3 -3
  70. package/core/src/util/index.ts +1 -1
  71. package/core/src/util/logger.ts +36 -5
  72. package/core/src/version.ts +13 -0
  73. package/core/src/worker/base-worker-host.ts +87 -25
  74. package/core/src/worker/buffer-sync.ts +1 -1
  75. package/core/src/worker/crash-recovery.ts +2 -2
  76. package/core/src/worker/instrumented-worker-host.ts +3 -3
  77. package/core/src/worker/rpc.ts +62 -11
  78. package/core/src/worker/sim-worker-base.ts +3 -8
  79. package/core/src/worker/task-pool.ts +2 -2
  80. package/dist/.dd-manifest.json +4119 -0
  81. package/dist/app/src/index.js +9 -0
  82. package/dist/app/src/renderer/bootstrap.js +446 -0
  83. package/dist/app/src/renderer/downdraft-base.css +93 -0
  84. package/dist/app/src/renderer/feature-log.js +180 -0
  85. package/dist/app/src/renderer/game-module.js +562 -0
  86. package/dist/app/src/renderer/hooks.js +82 -0
  87. package/dist/app/src/renderer/hot-reload.js +158 -0
  88. package/dist/app/src/renderer/import-cache.js +77 -0
  89. package/dist/app/src/renderer/index.js +149 -0
  90. package/dist/app/src/renderer/mcp-harness.js +112 -0
  91. package/dist/app/src/renderer/save-store-factory.js +180 -0
  92. package/dist/app/src/renderer/sim-bridge.js +138 -0
  93. package/dist/app/src/renderer/standard-automation-tools.js +720 -0
  94. package/dist/app/src/shared/feature-log.js +54 -0
  95. package/dist/app/src/shared/gpu-info.js +74 -0
  96. package/dist/app/src/shared/import-cache-store.js +123 -0
  97. package/dist/app/src/shared/index.js +4 -0
  98. package/dist/app/src/shared/mcp-discovery.js +55 -0
  99. package/dist/app/src/shared/mcp-proxy.js +71 -0
  100. package/dist/app/src/shared/types.js +13 -0
  101. package/dist/asset-bake/src/bake-audio.js +103 -0
  102. package/dist/asset-bake/src/bake-gltf.js +141 -0
  103. package/dist/asset-bake/src/bake.js +63 -0
  104. package/dist/asset-bake/src/cache.js +147 -0
  105. package/dist/asset-bake/src/config.js +93 -0
  106. package/dist/asset-bake/src/index.js +25 -0
  107. package/dist/core/src/animation/animation-event.js +24 -0
  108. package/dist/core/src/animation/bone-mask.js +103 -0
  109. package/dist/core/src/animation/clip.js +210 -0
  110. package/dist/core/src/animation/index.js +13 -0
  111. package/dist/core/src/animation/mixamo.js +78 -0
  112. package/dist/core/src/animation/morph-target.js +37 -0
  113. package/dist/core/src/animation/player.js +621 -0
  114. package/dist/core/src/animation/retarget.js +101 -0
  115. package/dist/core/src/animation/skeleton-animator.js +1361 -0
  116. package/dist/core/src/animation/skeleton.js +166 -0
  117. package/dist/core/src/animation/state-machine.js +252 -0
  118. package/dist/core/src/assets/blob-store.js +14 -0
  119. package/dist/core/src/assets/cache.js +168 -0
  120. package/dist/core/src/assets/cubemap-converter.js +129 -0
  121. package/dist/core/src/assets/environment-manager.js +84 -0
  122. package/dist/core/src/assets/import-cache.js +36 -0
  123. package/dist/core/src/assets/import-settings.js +34 -0
  124. package/dist/core/src/assets/importer.js +78 -0
  125. package/dist/core/src/assets/index.js +29 -0
  126. package/dist/core/src/assets/irradiance-generator.js +179 -0
  127. package/dist/core/src/assets/loader-audio.js +70 -0
  128. package/dist/core/src/assets/loader-cubemap.js +141 -0
  129. package/dist/core/src/assets/loader-dds.js +185 -0
  130. package/dist/core/src/assets/loader-hdr.js +430 -0
  131. package/dist/core/src/assets/loader-mesh.js +47 -0
  132. package/dist/core/src/assets/loader-shader.js +61 -0
  133. package/dist/core/src/assets/loader-texture.js +264 -0
  134. package/dist/core/src/assets/lod.js +150 -0
  135. package/dist/core/src/assets/manager.js +401 -0
  136. package/dist/core/src/assets/manifest.js +57 -0
  137. package/dist/core/src/assets/material-bridge.js +160 -0
  138. package/dist/core/src/assets/model-importer.js +32 -0
  139. package/dist/core/src/assets/model-normalizer.js +213 -0
  140. package/dist/core/src/assets/model-to-gpu.js +44 -0
  141. package/dist/core/src/assets/model-to-mesh.js +171 -0
  142. package/dist/core/src/assets/prefilter-generator.js +220 -0
  143. package/dist/core/src/audio/engine.js +153 -0
  144. package/dist/core/src/audio/interface.js +8 -0
  145. package/dist/core/src/audio/listener.js +19 -0
  146. package/dist/core/src/audio/mixer.js +124 -0
  147. package/dist/core/src/audio/registry.js +43 -0
  148. package/dist/core/src/audio/sab.js +74 -0
  149. package/dist/core/src/audio/source.js +60 -0
  150. package/dist/core/src/change-detection/atomics.js +1 -0
  151. package/dist/core/src/change-detection/tracker.js +26 -0
  152. package/dist/core/src/debug-draw/lines.js +27 -0
  153. package/dist/core/src/debug-draw/points.js +9 -0
  154. package/dist/core/src/debug-draw/queue.js +77 -0
  155. package/dist/core/src/debug-draw/text.js +12 -0
  156. package/dist/core/src/ecs/archetype.js +271 -0
  157. package/dist/core/src/ecs/component.js +109 -0
  158. package/dist/core/src/ecs/entity.js +11 -0
  159. package/dist/core/src/ecs/events.js +73 -0
  160. package/dist/core/src/ecs/hierarchy.js +104 -0
  161. package/dist/core/src/ecs/hmr-swap-registry.js +15 -0
  162. package/dist/core/src/ecs/index.js +14 -0
  163. package/dist/core/src/ecs/query.js +110 -0
  164. package/dist/core/src/ecs/resource.js +3 -0
  165. package/dist/core/src/ecs/schedule.js +157 -0
  166. package/dist/core/src/ecs/system-params.js +45 -0
  167. package/dist/core/src/ecs/system.js +18 -0
  168. package/dist/core/src/ecs/world.js +292 -0
  169. package/dist/core/src/index.js +191 -0
  170. package/dist/core/src/input/context.js +69 -0
  171. package/dist/core/src/input/dom-handler.js +288 -0
  172. package/dist/core/src/input/local-player-manager.js +145 -0
  173. package/dist/core/src/input/mapping.js +36 -0
  174. package/dist/core/src/input/multi-sab-bridge.js +224 -0
  175. package/dist/core/src/input/multi-state.js +48 -0
  176. package/dist/core/src/input/sab-bridge.js +66 -0
  177. package/dist/core/src/input/state.js +108 -0
  178. package/dist/core/src/input/ui-router.js +76 -0
  179. package/dist/core/src/library/host.js +291 -0
  180. package/dist/core/src/library/index.js +1 -0
  181. package/dist/core/src/library/library.js +20 -0
  182. package/dist/core/src/material/compiler.js +73 -0
  183. package/dist/core/src/material/graph-bridge.js +119 -0
  184. package/dist/core/src/material/index.js +6 -0
  185. package/dist/core/src/material/library.js +414 -0
  186. package/dist/core/src/material/material.js +120 -0
  187. package/dist/core/src/material/variants.js +37 -0
  188. package/dist/core/src/math/mat4.js +198 -0
  189. package/dist/core/src/math/perlin-noise-2d.js +66 -0
  190. package/dist/core/src/math/perlin-noise-3d.js +76 -0
  191. package/dist/core/src/math/quat.js +29 -0
  192. package/dist/core/src/math/rng.js +25 -0
  193. package/dist/core/src/math/trig.js +42 -0
  194. package/dist/core/src/math/value-noise.js +49 -0
  195. package/dist/core/src/mesh/builder.js +137 -0
  196. package/dist/core/src/mesh/csg.js +250 -0
  197. package/dist/core/src/mesh/greased-line.js +102 -0
  198. package/dist/core/src/mesh/mesh.js +6 -0
  199. package/dist/core/src/mesh/parametric.js +392 -0
  200. package/dist/core/src/mesh/skinning.js +30 -0
  201. package/dist/core/src/mesh/vertex-layout.js +65 -0
  202. package/dist/core/src/module/cross-thread.js +126 -0
  203. package/dist/core/src/module/diagnostics.js +99 -0
  204. package/dist/core/src/module/host.js +449 -0
  205. package/dist/core/src/module/index.js +6 -0
  206. package/dist/core/src/module/module.js +1 -0
  207. package/dist/core/src/module/registry.js +83 -0
  208. package/dist/core/src/module/renderer-module.js +13 -0
  209. package/dist/core/src/module/ts-loader.js +20 -0
  210. package/dist/core/src/particles/compute-pass.js +329 -0
  211. package/dist/core/src/particles/emitter.js +113 -0
  212. package/dist/core/src/particles/index.js +7 -0
  213. package/dist/core/src/particles/particle-data.js +33 -0
  214. package/dist/core/src/particles/render-pass.js +338 -0
  215. package/dist/core/src/particles/simulator.js +224 -0
  216. package/dist/core/src/particles/system.js +157 -0
  217. package/dist/core/src/physics/body.js +25 -0
  218. package/dist/core/src/physics/ccd-heuristic.js +46 -0
  219. package/dist/core/src/physics/character.js +184 -0
  220. package/dist/core/src/physics/collider.js +36 -0
  221. package/dist/core/src/physics/collision-system.js +62 -0
  222. package/dist/core/src/physics/events.js +74 -0
  223. package/dist/core/src/physics/index.js +24 -0
  224. package/dist/core/src/physics/interface.js +14 -0
  225. package/dist/core/src/physics/interpolation-buffer.js +182 -0
  226. package/dist/core/src/physics/lifecycle.js +66 -0
  227. package/dist/core/src/physics/load-shedder.js +155 -0
  228. package/dist/core/src/physics/physics-accumulator.js +94 -0
  229. package/dist/core/src/physics/physics-system.js +142 -0
  230. package/dist/core/src/physics/ragdoll-presets.js +248 -0
  231. package/dist/core/src/physics/ragdoll-system.js +193 -0
  232. package/dist/core/src/physics/ragdoll.js +117 -0
  233. package/dist/core/src/physics/raycast.js +97 -0
  234. package/dist/core/src/physics/realm-manager.js +431 -0
  235. package/dist/core/src/physics/realm-worker-pool.js +181 -0
  236. package/dist/core/src/physics/realm-worker.js +91 -0
  237. package/dist/core/src/physics/realm.js +137 -0
  238. package/dist/core/src/physics/registry.js +43 -0
  239. package/dist/core/src/physics/safety.js +211 -0
  240. package/dist/core/src/physics/snapshot-manager.js +118 -0
  241. package/dist/core/src/physics/worker-protocol.js +1 -0
  242. package/dist/core/src/platform/bun-preload.js +175 -0
  243. package/dist/core/src/platform/css-stub.js +4 -0
  244. package/dist/core/src/platform/glob-polyfill.js +137 -0
  245. package/dist/core/src/platform/hidpi.js +52 -0
  246. package/dist/core/src/platform/pkg-root.js +27 -0
  247. package/dist/core/src/platform/render-surface.js +15 -0
  248. package/dist/core/src/platform/rpc.js +82 -0
  249. package/dist/core/src/platform/runtime.js +93 -0
  250. package/dist/core/src/plugin/context.js +144 -0
  251. package/dist/core/src/plugin/diagnostics.js +20 -0
  252. package/dist/core/src/plugin/discovery.js +124 -0
  253. package/dist/core/src/plugin/extension-loaders.js +111 -0
  254. package/dist/core/src/plugin/host.js +542 -0
  255. package/dist/core/src/plugin/index.js +19 -0
  256. package/dist/core/src/plugin/loader-asset.js +105 -0
  257. package/dist/core/src/plugin/loader-quickjs.js +67 -0
  258. package/dist/core/src/plugin/loader-wasm.js +385 -0
  259. package/dist/core/src/plugin/loader-worker.js +228 -0
  260. package/dist/core/src/plugin/manifest.js +424 -0
  261. package/dist/core/src/plugin/material-registry.js +44 -0
  262. package/dist/core/src/plugin/mcp-tools.js +147 -0
  263. package/dist/core/src/plugin/permissions.js +152 -0
  264. package/dist/core/src/plugin/quickjs-bridge.js +219 -0
  265. package/dist/core/src/plugin/registry.js +92 -0
  266. package/dist/core/src/plugin/sandbox-shim.js +79 -0
  267. package/dist/core/src/plugin/sandbox-worker.js +194 -0
  268. package/dist/core/src/plugin/wasm-abi.js +62 -0
  269. package/dist/core/src/plugin/wasm-worker.js +234 -0
  270. package/dist/core/src/plugin/workshop.js +131 -0
  271. package/dist/core/src/profiling/event-loop.js +164 -0
  272. package/dist/core/src/profiling/index.js +23 -0
  273. package/dist/core/src/profiling/iops/idb-patch.js +211 -0
  274. package/dist/core/src/profiling/iops/opfs-patch.js +206 -0
  275. package/dist/core/src/profiling/profiling-sab.js +632 -0
  276. package/dist/core/src/profiling/task-latency.js +118 -0
  277. package/dist/core/src/profiling/thread-metrics.js +103 -0
  278. package/dist/core/src/profiling/trace-event-writer.js +165 -0
  279. package/dist/core/src/profiling/warnings.js +304 -0
  280. package/dist/core/src/profiling/worker-prelude.js +281 -0
  281. package/dist/core/src/render/bind-group.js +33 -0
  282. package/dist/core/src/render/bindless/bindless-struct.js +39 -0
  283. package/dist/core/src/render/bindless/bindless.wgsl.js +163 -0
  284. package/dist/core/src/render/bindless/frame-bindings.js +142 -0
  285. package/dist/core/src/render/bindless/index.js +6 -0
  286. package/dist/core/src/render/bindless/material-manager.js +182 -0
  287. package/dist/core/src/render/bindless/texture-registry.js +498 -0
  288. package/dist/core/src/render/buffer.js +74 -0
  289. package/dist/core/src/render/camera-2d.js +151 -0
  290. package/dist/core/src/render/camera-controller.js +370 -0
  291. package/dist/core/src/render/camera.js +332 -0
  292. package/dist/core/src/render/canvas-resize-watcher.js +36 -0
  293. package/dist/core/src/render/compute-kernel.js +130 -0
  294. package/dist/core/src/render/constants.js +2 -0
  295. package/dist/core/src/render/device.js +91 -0
  296. package/dist/core/src/render/frame-graph.js +594 -0
  297. package/dist/core/src/render/frustum.js +152 -0
  298. package/dist/core/src/render/fullscreen-vs.js +24 -0
  299. package/dist/core/src/render/g-buffer.js +156 -0
  300. package/dist/core/src/render/game-renderer.js +1165 -0
  301. package/dist/core/src/render/gpu-driven/cull-pass.js +352 -0
  302. package/dist/core/src/render/gpu-driven/hzb.js +183 -0
  303. package/dist/core/src/render/gpu-driven/index.js +6 -0
  304. package/dist/core/src/render/gpu-driven/indirect-draw-pass.js +300 -0
  305. package/dist/core/src/render/gpu-driven/instance-buffer.js +150 -0
  306. package/dist/core/src/render/gpu-driven/mesh-table.js +130 -0
  307. package/dist/core/src/render/gpu-driven/passes/hzb-build-pass.js +39 -0
  308. package/dist/core/src/render/gpu-utils.js +72 -0
  309. package/dist/core/src/render/hdr.js +69 -0
  310. package/dist/core/src/render/hot-reload.js +236 -0
  311. package/dist/core/src/render/ibl-bind-group.js +232 -0
  312. package/dist/core/src/render/ibl.js +148 -0
  313. package/dist/core/src/render/index.js +86 -0
  314. package/dist/core/src/render/input-manager.js +224 -0
  315. package/dist/core/src/render/lighting/area-light.js +142 -0
  316. package/dist/core/src/render/lighting/cluster-grid.js +255 -0
  317. package/dist/core/src/render/lighting/cluster-types.js +87 -0
  318. package/dist/core/src/render/lighting/ies-parser.js +111 -0
  319. package/dist/core/src/render/lighting.js +300 -0
  320. package/dist/core/src/render/material-types/depth.wgsl +44 -0
  321. package/dist/core/src/render/material-types/line.wgsl +50 -0
  322. package/dist/core/src/render/material-types/matcap.wgsl +51 -0
  323. package/dist/core/src/render/material-types/normal.wgsl +41 -0
  324. package/dist/core/src/render/material-types/physical.wgsl +152 -0
  325. package/dist/core/src/render/material-types/sprite.wgsl +46 -0
  326. package/dist/core/src/render/material-types/sss.wgsl +79 -0
  327. package/dist/core/src/render/material-types/toon.wgsl +79 -0
  328. package/dist/core/src/render/passes/README.md +121 -0
  329. package/dist/core/src/render/passes/atmosphere.js +107 -0
  330. package/dist/core/src/render/passes/cluster-lighting-pass.js +441 -0
  331. package/dist/core/src/render/passes/csm.js +338 -0
  332. package/dist/core/src/render/passes/cubemap-capture.js +93 -0
  333. package/dist/core/src/render/passes/debug-viz.js +248 -0
  334. package/dist/core/src/render/passes/debug.js +500 -0
  335. package/dist/core/src/render/passes/decal-mesh.js +86 -0
  336. package/dist/core/src/render/passes/decal-pass.js +344 -0
  337. package/dist/core/src/render/passes/deferred-lighting.js +406 -0
  338. package/dist/core/src/render/passes/depth-prepass.js +148 -0
  339. package/dist/core/src/render/passes/dome-360.js +68 -0
  340. package/dist/core/src/render/passes/fluid-render.js +116 -0
  341. package/dist/core/src/render/passes/gi-types.js +78 -0
  342. package/dist/core/src/render/passes/graph-compute.js +251 -0
  343. package/dist/core/src/render/passes/greased-line-pass.js +218 -0
  344. package/dist/core/src/render/passes/morph-target.js +35 -0
  345. package/dist/core/src/render/passes/opaque.js +966 -0
  346. package/dist/core/src/render/passes/point-light-shadow.js +221 -0
  347. package/dist/core/src/render/passes/procedural-texture.js +142 -0
  348. package/dist/core/src/render/passes/reflection-probe.js +100 -0
  349. package/dist/core/src/render/passes/rsm-pass.js +228 -0
  350. package/dist/core/src/render/passes/sdf-text.js +114 -0
  351. package/dist/core/src/render/passes/shadow-map.js +121 -0
  352. package/dist/core/src/render/passes/shadow.js +191 -0
  353. package/dist/core/src/render/passes/skinning-vs.js +102 -0
  354. package/dist/core/src/render/passes/skinning.js +282 -0
  355. package/dist/core/src/render/passes/sky-dome.js +380 -0
  356. package/dist/core/src/render/passes/skybox.js +146 -0
  357. package/dist/core/src/render/passes/spot-light-shadow.js +223 -0
  358. package/dist/core/src/render/passes/terrain.js +303 -0
  359. package/dist/core/src/render/passes/transparent.js +323 -0
  360. package/dist/core/src/render/passes/underwater-fog.js +173 -0
  361. package/dist/core/src/render/passes/video-texture.js +58 -0
  362. package/dist/core/src/render/passes/volumetric-pass.js +278 -0
  363. package/dist/core/src/render/passes/volumetric-types.js +96 -0
  364. package/dist/core/src/render/passes/water.js +697 -0
  365. package/dist/core/src/render/pbr.js +257 -0
  366. package/dist/core/src/render/pipeline.js +49 -0
  367. package/dist/core/src/render/render-pass.js +13 -0
  368. package/dist/core/src/render/renderer-input-bus.js +176 -0
  369. package/dist/core/src/render/renderer-module-host.js +539 -0
  370. package/dist/core/src/render/resource-tracker.js +59 -0
  371. package/dist/core/src/render/sab-canvas-overlay.js +83 -0
  372. package/dist/core/src/render/shader-validator.js +172 -0
  373. package/dist/core/src/render/shaders/debug/debug-line.wgsl +27 -0
  374. package/dist/core/src/render/shaders/debug/debug-point.wgsl +30 -0
  375. package/dist/core/src/render/shaders/debug/debug-text.wgsl +42 -0
  376. package/dist/core/src/render/shaders/debug-viz/aabb.wgsl +20 -0
  377. package/dist/core/src/render/shaders/debug-viz/depth.wgsl +29 -0
  378. package/dist/core/src/render/shaders/debug-viz/lod.wgsl +38 -0
  379. package/dist/core/src/render/shaders/debug-viz/normals.wgsl +30 -0
  380. package/dist/core/src/render/shaders/debug-viz/overdraw.wgsl +21 -0
  381. package/dist/core/src/render/shaders/debug-viz/tangents.wgsl +29 -0
  382. package/dist/core/src/render/shaders/debug-viz/wireframe.wgsl +33 -0
  383. package/dist/core/src/render/shaders/shadow-chunks.js +133 -0
  384. package/dist/core/src/render/skybox.js +123 -0
  385. package/dist/core/src/render/splitscreen.js +60 -0
  386. package/dist/core/src/render/surface.js +63 -0
  387. package/dist/core/src/render/tonemap.js +171 -0
  388. package/dist/core/src/render/tracked-render-pass.js +115 -0
  389. package/dist/core/src/render/viewport.js +81 -0
  390. package/dist/core/src/render/wgsl-hmr.js +66 -0
  391. package/dist/core/src/sab/core-input-channel.js +22 -0
  392. package/dist/core/src/sab/define.js +127 -0
  393. package/dist/core/src/sab/errors.js +60 -0
  394. package/dist/core/src/sab/game-input.js +299 -0
  395. package/dist/core/src/sab/gamepad-devices.js +205 -0
  396. package/dist/core/src/sab/grid-buffer.js +91 -0
  397. package/dist/core/src/sab/input.js +38 -0
  398. package/dist/core/src/sab/layout.js +160 -0
  399. package/dist/core/src/sab/multi-input-channel.js +39 -0
  400. package/dist/core/src/sab/record-buffer.js +130 -0
  401. package/dist/core/src/sab/sab-polyfill.js +47 -0
  402. package/dist/core/src/sab/sim-channel.js +397 -0
  403. package/dist/core/src/sab/slot-buffer.js +140 -0
  404. package/dist/core/src/sab/types.js +1 -0
  405. package/dist/core/src/safety/bounds.js +71 -0
  406. package/dist/core/src/safety/json.js +70 -0
  407. package/dist/core/src/safety/path.js +151 -0
  408. package/dist/core/src/save/binary-format.js +95 -0
  409. package/dist/core/src/save/game-save-system.js +101 -0
  410. package/dist/core/src/save/grid-save-system.js +102 -0
  411. package/dist/core/src/save/migrate.js +35 -0
  412. package/dist/core/src/save/migration-registry.js +66 -0
  413. package/dist/core/src/save/persist-types.js +4 -0
  414. package/dist/core/src/save/schema.js +36 -0
  415. package/dist/core/src/save/serializer.js +139 -0
  416. package/dist/core/src/scene/builder.js +31 -0
  417. package/dist/core/src/scene/camera.js +118 -0
  418. package/dist/core/src/scene/checkpoint.js +84 -0
  419. package/dist/core/src/scene/game-loop.js +155 -0
  420. package/dist/core/src/scene/index.js +14 -0
  421. package/dist/core/src/scene/layer.js +7 -0
  422. package/dist/core/src/scene/prefab.js +97 -0
  423. package/dist/core/src/scene/scene-manager.js +141 -0
  424. package/dist/core/src/scene/scene.js +147 -0
  425. package/dist/core/src/scene/sky.js +179 -0
  426. package/dist/core/src/scene/spatial-grid.js +140 -0
  427. package/dist/core/src/scene/streaming.js +247 -0
  428. package/dist/core/src/scene/vegetation.js +107 -0
  429. package/dist/core/src/scene/world.js +66 -0
  430. package/dist/core/src/scripting/binding.js +85 -0
  431. package/dist/core/src/scripting/hot-reload.js +123 -0
  432. package/dist/core/src/scripting/script.js +68 -0
  433. package/dist/core/src/sim/hot-reload-pipeline.js +65 -0
  434. package/dist/core/src/sim/sim-state-helper.js +40 -0
  435. package/dist/core/src/sim/transient-state-registry.js +63 -0
  436. package/dist/core/src/sim/types.js +4 -0
  437. package/dist/core/src/sim/worker-loop.js +168 -0
  438. package/dist/core/src/stores/game-store.js +81 -0
  439. package/dist/core/src/stores/hot-reload-store.js +19 -0
  440. package/dist/core/src/telemetry/collector.js +303 -0
  441. package/dist/core/src/telemetry/gc-controller.js +365 -0
  442. package/dist/core/src/telemetry/gc-profiler.js +82 -0
  443. package/dist/core/src/telemetry/gc-tracker.js +63 -0
  444. package/dist/core/src/telemetry/gpu-profiler.js +554 -0
  445. package/dist/core/src/telemetry/gpu-resource-tracker.js +234 -0
  446. package/dist/core/src/telemetry/gpu-timer-pool.js +223 -0
  447. package/dist/core/src/telemetry/gpu-timer.js +117 -0
  448. package/dist/core/src/telemetry/gpu-timestamp-gate.js +22 -0
  449. package/dist/core/src/telemetry/reporter.js +56 -0
  450. package/dist/core/src/types/engine-types.js +21 -0
  451. package/dist/core/src/ui-font-scale.js +111 -0
  452. package/dist/core/src/util/broad-phase-grid.js +77 -0
  453. package/dist/core/src/util/feature-log.js +176 -0
  454. package/dist/core/src/util/index.js +4 -0
  455. package/dist/core/src/util/logger.js +596 -0
  456. package/dist/core/src/version.js +11 -0
  457. package/dist/core/src/webgpu-destroy-augmentation.d.ts +25 -0
  458. package/dist/core/src/worker/base-worker-host.js +212 -0
  459. package/dist/core/src/worker/buffer-sync.js +454 -0
  460. package/dist/core/src/worker/crash-recovery.js +153 -0
  461. package/dist/core/src/worker/entity-sim-worker-host.js +128 -0
  462. package/dist/core/src/worker/instrumented-worker-host.js +139 -0
  463. package/dist/core/src/worker/rpc.js +244 -0
  464. package/dist/core/src/worker/sim-worker-base.js +558 -0
  465. package/dist/core/src/worker/sim-worker-host.js +271 -0
  466. package/dist/core/src/worker/task-pool.js +205 -0
  467. package/dist/core/src/worker/task-worker.js +77 -0
  468. package/dist/libraries/asset-browser/src/index.js +10 -0
  469. package/dist/libraries/asset-browser/src/software-thumbnails.js +940 -0
  470. package/dist/libraries/audio-kira/src/backend.js +405 -0
  471. package/dist/libraries/audio-kira/src/index.js +4 -0
  472. package/dist/libraries/audio-kira/src/library.js +54 -0
  473. package/dist/libraries/blitz-ui/src/index.js +13 -0
  474. package/dist/libraries/blitz-ui/src/native-module.js +162 -0
  475. package/dist/libraries/blitz-ui/src/native-osr-ffi.js +409 -0
  476. package/dist/libraries/blitz-ui/src/router.js +82 -0
  477. package/dist/libraries/blitz-ui/src/shaders/ui-blit.wgsl.js +32 -0
  478. package/dist/libraries/blitz-ui/src/ui-blit-pass.js +108 -0
  479. package/dist/libraries/character/src/character-animator.js +323 -0
  480. package/dist/libraries/character/src/customization.js +464 -0
  481. package/dist/libraries/character/src/index.js +19 -0
  482. package/dist/libraries/character/src/inspectable.js +77 -0
  483. package/dist/libraries/character/src/loader.js +336 -0
  484. package/dist/libraries/character/src/locomotion.js +84 -0
  485. package/dist/libraries/character/src/preview.js +280 -0
  486. package/dist/libraries/devtools/src/backend.js +449 -0
  487. package/dist/libraries/devtools/src/cdp-bridge.js +293 -0
  488. package/dist/libraries/devtools/src/collectors.js +318 -0
  489. package/dist/libraries/devtools/src/index.js +31 -0
  490. package/dist/libraries/devtools/src/native-providers.js +749 -0
  491. package/dist/libraries/devtools/src/snapshot.js +35 -0
  492. package/dist/libraries/devtools/src/verify.js +139 -0
  493. package/dist/libraries/devtools/src/web/browser.js +94 -0
  494. package/dist/libraries/devtools/src/web/host.js +183 -0
  495. package/dist/libraries/devtools/src/web/mirror.js +26 -0
  496. package/dist/libraries/devtools/src/web/server.js +187 -0
  497. package/dist/libraries/entities/src/index.js +3 -0
  498. package/dist/libraries/entities/src/library.js +46 -0
  499. package/dist/libraries/entities/src/model-renderer.js +1307 -0
  500. package/dist/libraries/entities/src/shaders/model.wgsl +375 -0
  501. package/dist/libraries/gamepad/src/feed-input.js +54 -0
  502. package/dist/libraries/gamepad/src/filters.js +44 -0
  503. package/dist/libraries/gamepad/src/glyphs.js +83 -0
  504. package/dist/libraries/gamepad/src/hub.js +164 -0
  505. package/dist/libraries/gamepad/src/index.js +10 -0
  506. package/dist/libraries/gamepad/src/library.js +56 -0
  507. package/dist/libraries/gamepad/src/source-sab.js +62 -0
  508. package/dist/libraries/gamepad/src/sysfs-enrich.js +125 -0
  509. package/dist/libraries/gaussian-splats/src/gpu-sort.js +506 -0
  510. package/dist/libraries/gaussian-splats/src/index.js +8 -0
  511. package/dist/libraries/gaussian-splats/src/library.js +44 -0
  512. package/dist/libraries/gaussian-splats/src/parser.js +297 -0
  513. package/dist/libraries/gaussian-splats/src/renderer.js +368 -0
  514. package/dist/libraries/gaussian-splats/src/sh-eval.js +196 -0
  515. package/dist/libraries/gaussian-splats/src/sorter.js +76 -0
  516. package/dist/libraries/gaussian-splats/src/tile-raster.js +424 -0
  517. package/dist/libraries/gpu-kernels/src/index.js +8 -0
  518. package/dist/libraries/gpu-kernels/src/kernel.js +591 -0
  519. package/dist/libraries/gpu-kernels/src/transpile.js +896 -0
  520. package/dist/libraries/html-ui-kit/src/behaviors.js +231 -0
  521. package/dist/libraries/html-ui-kit/src/components.js +219 -0
  522. package/dist/libraries/html-ui-kit/src/index.js +17 -0
  523. package/dist/libraries/html-ui-kit/src/nav/nav-controller.js +215 -0
  524. package/dist/libraries/html-ui-kit/src/nav/nav-input.js +138 -0
  525. package/dist/libraries/html-ui-kit/src/nav/osk.js +135 -0
  526. package/dist/libraries/html-ui-kit/src/nav/router.js +152 -0
  527. package/dist/libraries/html-ui-kit/src/nav/vcursor.js +177 -0
  528. package/dist/libraries/html-ui-kit/src/ten-foot.js +138 -0
  529. package/dist/libraries/html-ui-kit/src/theme.js +235 -0
  530. package/dist/libraries/inspectable/src/index.js +6 -0
  531. package/dist/libraries/inspectable/src/inspectable.js +205 -0
  532. package/dist/libraries/lighting/src/index.js +4 -0
  533. package/dist/libraries/lighting/src/library.js +48 -0
  534. package/dist/libraries/lighting/src/light-system.js +395 -0
  535. package/dist/libraries/lighting/src/lighting-system.js +57 -0
  536. package/dist/libraries/lighting/src/shaders/light-debug.wgsl +30 -0
  537. package/dist/libraries/marching-cubes/src/chunked-field.js +130 -0
  538. package/dist/libraries/marching-cubes/src/deformation.js +41 -0
  539. package/dist/libraries/marching-cubes/src/generator.js +356 -0
  540. package/dist/libraries/marching-cubes/src/index.js +13 -0
  541. package/dist/libraries/marching-cubes/src/library.js +54 -0
  542. package/dist/libraries/marching-cubes/src/lod.js +95 -0
  543. package/dist/libraries/marching-cubes/src/marching-tetrahedra.js +261 -0
  544. package/dist/libraries/marching-cubes/src/sab.js +40 -0
  545. package/dist/libraries/marching-cubes/src/streaming-config.js +28 -0
  546. package/dist/libraries/marching-cubes/src/streaming-manager.js +490 -0
  547. package/dist/libraries/marching-cubes/src/tables.js +314 -0
  548. package/dist/libraries/marching-cubes/src/types.js +1 -0
  549. package/dist/libraries/models/src/bake-node-transforms.js +146 -0
  550. package/dist/libraries/models/src/bind-unskinned-meshes.js +145 -0
  551. package/dist/libraries/models/src/codecs/basisu-codec.js +134 -0
  552. package/dist/libraries/models/src/codecs/draco-codec.js +236 -0
  553. package/dist/libraries/models/src/codecs/draco3dgltf.d.ts +40 -0
  554. package/dist/libraries/models/src/codecs/index.js +5 -0
  555. package/dist/libraries/models/src/codecs/meshopt-codec.js +59 -0
  556. package/dist/libraries/models/src/codecs/registry.js +111 -0
  557. package/dist/libraries/models/src/dae.js +665 -0
  558. package/dist/libraries/models/src/default-part-selection.js +58 -0
  559. package/dist/libraries/models/src/dxf.js +235 -0
  560. package/dist/libraries/models/src/fbx/index.js +438 -0
  561. package/dist/libraries/models/src/fbx/interpreter/animation.js +369 -0
  562. package/dist/libraries/models/src/fbx/interpreter/blend-shapes.js +283 -0
  563. package/dist/libraries/models/src/fbx/interpreter/connections.js +158 -0
  564. package/dist/libraries/models/src/fbx/interpreter/diagnostics.js +48 -0
  565. package/dist/libraries/models/src/fbx/interpreter/geometry.js +430 -0
  566. package/dist/libraries/models/src/fbx/interpreter/global-settings.js +77 -0
  567. package/dist/libraries/models/src/fbx/interpreter/materials.js +231 -0
  568. package/dist/libraries/models/src/fbx/interpreter/nodes.js +168 -0
  569. package/dist/libraries/models/src/fbx/interpreter/skeleton.js +454 -0
  570. package/dist/libraries/models/src/fbx/parsers/binary-parser.js +217 -0
  571. package/dist/libraries/models/src/fbx/types.js +88 -0
  572. package/dist/libraries/models/src/gltf-extensions.js +121 -0
  573. package/dist/libraries/models/src/gltf.js +724 -0
  574. package/dist/libraries/models/src/index.js +46 -0
  575. package/dist/libraries/models/src/library.js +44 -0
  576. package/dist/libraries/models/src/loader.js +218 -0
  577. package/dist/libraries/models/src/material-adapter.js +82 -0
  578. package/dist/libraries/models/src/mini-xml.js +145 -0
  579. package/dist/libraries/models/src/normalize.js +168 -0
  580. package/dist/libraries/models/src/obj.js +247 -0
  581. package/dist/libraries/models/src/off.js +94 -0
  582. package/dist/libraries/models/src/ply.js +329 -0
  583. package/dist/libraries/models/src/pose-sampler.js +183 -0
  584. package/dist/libraries/models/src/sidecar/blender-extras.js +32 -0
  585. package/dist/libraries/models/src/sidecar/ddmeta.js +98 -0
  586. package/dist/libraries/models/src/sidecar/godot-import.js +76 -0
  587. package/dist/libraries/models/src/sidecar/resolver.js +112 -0
  588. package/dist/libraries/models/src/sidecar/types.js +8 -0
  589. package/dist/libraries/models/src/sidecar/unity-meta.js +46 -0
  590. package/dist/libraries/models/src/skeleton-synthesis.js +122 -0
  591. package/dist/libraries/models/src/stl.js +129 -0
  592. package/dist/libraries/models/src/threeds.js +312 -0
  593. package/dist/libraries/models/src/threemf.js +203 -0
  594. package/dist/libraries/models/src/types.js +33 -0
  595. package/dist/libraries/models/src/vtk.js +242 -0
  596. package/dist/libraries/navmesh/src/crowd-system.js +207 -0
  597. package/dist/libraries/navmesh/src/debug-viz.js +52 -0
  598. package/dist/libraries/navmesh/src/index.js +7 -0
  599. package/dist/libraries/navmesh/src/library.js +47 -0
  600. package/dist/libraries/navmesh/src/navmesh-generator.js +364 -0
  601. package/dist/libraries/navmesh/src/navmesh.js +141 -0
  602. package/dist/libraries/navmesh/src/pathfinder.js +221 -0
  603. package/dist/libraries/navmesh/src/types.js +1 -0
  604. package/dist/libraries/networking/src/authority.js +107 -0
  605. package/dist/libraries/networking/src/connection.js +107 -0
  606. package/dist/libraries/networking/src/discovery.js +314 -0
  607. package/dist/libraries/networking/src/enhanced-replication.js +282 -0
  608. package/dist/libraries/networking/src/epic-adapter.js +101 -0
  609. package/dist/libraries/networking/src/index.js +16 -0
  610. package/dist/libraries/networking/src/library.js +45 -0
  611. package/dist/libraries/networking/src/lobby.js +84 -0
  612. package/dist/libraries/networking/src/platform-adapter.js +92 -0
  613. package/dist/libraries/networking/src/rcs-adapter.js +100 -0
  614. package/dist/libraries/networking/src/remote-input.js +162 -0
  615. package/dist/libraries/networking/src/replication.js +273 -0
  616. package/dist/libraries/networking/src/rpc.js +172 -0
  617. package/dist/libraries/networking/src/session.js +129 -0
  618. package/dist/libraries/networking/src/transport.js +156 -0
  619. package/dist/libraries/networking/src/webrtc.js +266 -0
  620. package/dist/libraries/pathfinding-2d/src/astar-grid.js +255 -0
  621. package/dist/libraries/pathfinding-2d/src/index.js +9 -0
  622. package/dist/libraries/persistence/src/autosave-manager.js +94 -0
  623. package/dist/libraries/persistence/src/binary-record-store.js +205 -0
  624. package/dist/libraries/persistence/src/browser.js +16 -0
  625. package/dist/libraries/persistence/src/file-save-store.js +507 -0
  626. package/dist/libraries/persistence/src/hash-utils.js +54 -0
  627. package/dist/libraries/persistence/src/index.js +17 -0
  628. package/dist/libraries/persistence/src/library.js +51 -0
  629. package/dist/libraries/persistence/src/mock-opfs.js +114 -0
  630. package/dist/libraries/persistence/src/node-fs-directory-handle.js +168 -0
  631. package/dist/libraries/persistence/src/opfs-save-store.js +584 -0
  632. package/dist/libraries/persistence/src/save-worker-proxy.js +96 -0
  633. package/dist/libraries/persistence/src/save-worker.js +76 -0
  634. package/dist/libraries/persistence/src/xxh3-ts.d.ts +10 -0
  635. package/dist/libraries/physics-native/src/backend.js +960 -0
  636. package/dist/libraries/physics-native/src/broadphase.js +79 -0
  637. package/dist/libraries/physics-native/src/index.js +6 -0
  638. package/dist/libraries/physics-native/src/library.js +57 -0
  639. package/dist/libraries/physics-native/src/narrowphase-shapes.js +348 -0
  640. package/dist/libraries/physics-native/src/narrowphase.js +60 -0
  641. package/dist/libraries/physics-native/src/solver.js +105 -0
  642. package/dist/libraries/physics-native/src/types.js +4 -0
  643. package/dist/libraries/physics-rapier/src/api.js +352 -0
  644. package/dist/libraries/physics-rapier/src/auto-backend.js +54 -0
  645. package/dist/libraries/physics-rapier/src/backend.js +1066 -0
  646. package/dist/libraries/physics-rapier/src/bulk-ops.js +46 -0
  647. package/dist/libraries/physics-rapier/src/ffi-backend.js +17 -0
  648. package/dist/libraries/physics-rapier/src/ffi-lib.js +605 -0
  649. package/dist/libraries/physics-rapier/src/index.js +9 -0
  650. package/dist/libraries/physics-rapier/src/library.js +71 -0
  651. package/dist/libraries/physics-rapier/src/rapier-backend.js +1102 -0
  652. package/dist/libraries/physics-rapier/src/realm-worker-script.js +233 -0
  653. package/dist/libraries/postfx/src/index.js +14 -0
  654. package/dist/libraries/postfx/src/library.js +207 -0
  655. package/dist/libraries/postfx/src/post-process-stack.js +1641 -0
  656. package/dist/libraries/postfx/src/shaders/post-process/afterimage.wgsl +14 -0
  657. package/dist/libraries/postfx/src/shaders/post-process/ascii.wgsl +24 -0
  658. package/dist/libraries/postfx/src/shaders/post-process/blit.wgsl +12 -0
  659. package/dist/libraries/postfx/src/shaders/post-process/bloom-blur.wgsl +21 -0
  660. package/dist/libraries/postfx/src/shaders/post-process/bloom-bright.wgsl +15 -0
  661. package/dist/libraries/postfx/src/shaders/post-process/bloom-composite.wgsl +14 -0
  662. package/dist/libraries/postfx/src/shaders/post-process/bloom-downsample.wgsl +60 -0
  663. package/dist/libraries/postfx/src/shaders/post-process/bloom-soft.wgsl +46 -0
  664. package/dist/libraries/postfx/src/shaders/post-process/bloom-upsample.wgsl +51 -0
  665. package/dist/libraries/postfx/src/shaders/post-process/channel-mixer.wgsl +36 -0
  666. package/dist/libraries/postfx/src/shaders/post-process/chromatic-aberration.wgsl +37 -0
  667. package/dist/libraries/postfx/src/shaders/post-process/dithering.wgsl +64 -0
  668. package/dist/libraries/postfx/src/shaders/post-process/dof.wgsl +131 -0
  669. package/dist/libraries/postfx/src/shaders/post-process/edges.wgsl +45 -0
  670. package/dist/libraries/postfx/src/shaders/post-process/fullscreen-vs.wgsl +15 -0
  671. package/dist/libraries/postfx/src/shaders/post-process/fxaa.wgsl +102 -0
  672. package/dist/libraries/postfx/src/shaders/post-process/gaussian-blur.wgsl +37 -0
  673. package/dist/libraries/postfx/src/shaders/post-process/glow-blur.wgsl +33 -0
  674. package/dist/libraries/postfx/src/shaders/post-process/glow-composite.wgsl +25 -0
  675. package/dist/libraries/postfx/src/shaders/post-process/grain.wgsl +37 -0
  676. package/dist/libraries/postfx/src/shaders/post-process/halftone.wgsl +80 -0
  677. package/dist/libraries/postfx/src/shaders/post-process/highlight-blur.wgsl +33 -0
  678. package/dist/libraries/postfx/src/shaders/post-process/highlight-composite.wgsl +32 -0
  679. package/dist/libraries/postfx/src/shaders/post-process/lens-distortion.wgsl +43 -0
  680. package/dist/libraries/postfx/src/shaders/post-process/lens-flare.wgsl +68 -0
  681. package/dist/libraries/postfx/src/shaders/post-process/lut.wgsl +30 -0
  682. package/dist/libraries/postfx/src/shaders/post-process/motion-blur.wgsl +55 -0
  683. package/dist/libraries/postfx/src/shaders/post-process/occluder-chunk.wgsl +28 -0
  684. package/dist/libraries/postfx/src/shaders/post-process/outline.wgsl +51 -0
  685. package/dist/libraries/postfx/src/shaders/post-process/pixelation.wgsl +47 -0
  686. package/dist/libraries/postfx/src/shaders/post-process/sharpen.wgsl +32 -0
  687. package/dist/libraries/postfx/src/shaders/post-process/sobel.wgsl +26 -0
  688. package/dist/libraries/postfx/src/shaders/post-process/split-tone.wgsl +36 -0
  689. package/dist/libraries/postfx/src/shaders/post-process/ssao-blur.wgsl +38 -0
  690. package/dist/libraries/postfx/src/shaders/post-process/ssao-composite.wgsl +25 -0
  691. package/dist/libraries/postfx/src/shaders/post-process/ssao.wgsl +147 -0
  692. package/dist/libraries/postfx/src/shaders/post-process/ssr.wgsl +155 -0
  693. package/dist/libraries/postfx/src/shaders/post-process/taa.wgsl +98 -0
  694. package/dist/libraries/postfx/src/shaders/post-process/tonemap.wgsl +40 -0
  695. package/dist/libraries/postfx/src/shaders/post-process/watercolor.wgsl +82 -0
  696. package/dist/libraries/postfx/src/shaders/post-process/white-balance.wgsl +41 -0
  697. package/dist/libraries/recast/src/backend.js +124 -0
  698. package/dist/libraries/recast/src/crowd-system.js +310 -0
  699. package/dist/libraries/recast/src/index.js +4 -0
  700. package/dist/libraries/recast/src/library.js +59 -0
  701. package/dist/libraries/recast/src/types.js +4 -0
  702. package/dist/libraries/sand/src/cell.js +32 -0
  703. package/dist/libraries/sand/src/fields.js +27 -0
  704. package/dist/libraries/sand/src/fluid-grid.js +267 -0
  705. package/dist/libraries/sand/src/grid-dims.js +47 -0
  706. package/dist/libraries/sand/src/grid-sim-buffer.js +184 -0
  707. package/dist/libraries/sand/src/index.js +20 -0
  708. package/dist/libraries/sand/src/library.js +67 -0
  709. package/dist/libraries/sand/src/materials.js +437 -0
  710. package/dist/libraries/sand/src/palette.js +87 -0
  711. package/dist/libraries/sand/src/particles.js +163 -0
  712. package/dist/libraries/sand/src/render/sand-grid-pass.js +377 -0
  713. package/dist/libraries/sand/src/rng.js +44 -0
  714. package/dist/libraries/sand/src/rules/builtin-rules.js +125 -0
  715. package/dist/libraries/sand/src/rules/rule-compiler.js +164 -0
  716. package/dist/libraries/sand/src/rules/rule-engine.js +210 -0
  717. package/dist/libraries/sand/src/rules/rule-types.js +27 -0
  718. package/dist/libraries/sand/src/sand-step-pool.js +458 -0
  719. package/dist/libraries/sand/src/sand-step-worker.js +101 -0
  720. package/dist/libraries/sand/src/sand-world.js +3382 -0
  721. package/dist/libraries/stickman/src/index.js +7 -0
  722. package/dist/libraries/stickman/src/library.js +44 -0
  723. package/dist/libraries/stickman/src/proportions.js +40 -0
  724. package/dist/libraries/stickman/src/shader.js +113 -0
  725. package/dist/libraries/stickman/src/skeleton.js +163 -0
  726. package/dist/libraries/stickman/src/stickman-pass.js +210 -0
  727. package/dist/libraries/stickman/src/thick-line.js +120 -0
  728. package/dist/libraries/surface-nets/src/chunked-field.js +5 -0
  729. package/dist/libraries/surface-nets/src/deformation.js +29 -0
  730. package/dist/libraries/surface-nets/src/index.js +15 -0
  731. package/dist/libraries/surface-nets/src/library.js +41 -0
  732. package/dist/libraries/surface-nets/src/lod.js +6 -0
  733. package/dist/libraries/surface-nets/src/sab.js +4 -0
  734. package/dist/libraries/surface-nets/src/streaming-config.js +4 -0
  735. package/dist/libraries/surface-nets/src/streaming-manager.js +9 -0
  736. package/dist/libraries/surface-nets/src/surface-nets.js +361 -0
  737. package/dist/libraries/surface-nets/src/types.js +1 -0
  738. package/dist/libraries/water/src/buoyancy.js +80 -0
  739. package/dist/libraries/water/src/index.js +12 -0
  740. package/dist/libraries/water/src/library.js +65 -0
  741. package/dist/libraries/water/src/shore-damping.js +70 -0
  742. package/dist/libraries/water/src/water-buffer.js +78 -0
  743. package/dist/libraries/water/src/water-chunks.js +5 -0
  744. package/dist/libraries/water/src/water-physics.js +315 -0
  745. package/dist/libraries/water/src/water-renderer.js +736 -0
  746. package/dist/libraries/water/src/water-sab.js +138 -0
  747. package/dist/libraries/water/src/wave-sources.js +45 -0
  748. package/dist/libraries/weather/src/index.js +5 -0
  749. package/dist/libraries/weather/src/library.js +48 -0
  750. package/dist/libraries/weather/src/types.js +29 -0
  751. package/dist/libraries/weather/src/weather-blend.js +108 -0
  752. package/dist/libraries/weather/src/weather-system.js +275 -0
  753. package/dist/libraries/weatherfx/src/cloud-provider.js +5 -0
  754. package/dist/libraries/weatherfx/src/cloud-system.js +294 -0
  755. package/dist/libraries/weatherfx/src/index.js +4 -0
  756. package/dist/libraries/weatherfx/src/library.js +41 -0
  757. package/dist/libraries/weatherfx/src/particle-system.js +350 -0
  758. package/dist/libraries/weatherfx/src/shaders/cloud.wgsl +111 -0
  759. package/dist/libraries/weatherfx/src/shaders/particle-compute.wgsl +187 -0
  760. package/dist/libraries/weatherfx/src/shaders/particle-render.wgsl +95 -0
  761. package/dist/mcp/src/client.js +669 -0
  762. package/dist/mcp/src/engine-context.js +99 -0
  763. package/dist/mcp/src/http-transport.js +423 -0
  764. package/dist/mcp/src/index.js +5 -0
  765. package/dist/mcp/src/prompts/add-entity.js +39 -0
  766. package/dist/mcp/src/prompts/create-scene.js +41 -0
  767. package/dist/mcp/src/prompts/debug-frame.js +36 -0
  768. package/dist/mcp/src/prompts/index.js +10 -0
  769. package/dist/mcp/src/resources/asset-list.js +28 -0
  770. package/dist/mcp/src/resources/checkpoint-list.js +29 -0
  771. package/dist/mcp/src/resources/entity-state.js +45 -0
  772. package/dist/mcp/src/resources/gpu-info.js +90 -0
  773. package/dist/mcp/src/resources/index.js +51 -0
  774. package/dist/mcp/src/resources/performance.js +33 -0
  775. package/dist/mcp/src/resources/scene-tree.js +37 -0
  776. package/dist/mcp/src/server.js +307 -0
  777. package/dist/mcp/src/tools/animation.js +102 -0
  778. package/dist/mcp/src/tools/asset.js +146 -0
  779. package/dist/mcp/src/tools/audio.js +80 -0
  780. package/dist/mcp/src/tools/build.js +128 -0
  781. package/dist/mcp/src/tools/camera.js +157 -0
  782. package/dist/mcp/src/tools/checkpoint.js +90 -0
  783. package/dist/mcp/src/tools/component.js +176 -0
  784. package/dist/mcp/src/tools/debug.js +273 -0
  785. package/dist/mcp/src/tools/entity.js +309 -0
  786. package/dist/mcp/src/tools/inspect.js +192 -0
  787. package/dist/mcp/src/tools/lighting.js +239 -0
  788. package/dist/mcp/src/tools/material.js +225 -0
  789. package/dist/mcp/src/tools/mesh.js +210 -0
  790. package/dist/mcp/src/tools/physics.js +251 -0
  791. package/dist/mcp/src/tools/scene.js +139 -0
  792. package/dist/mcp/src/tools/script.js +114 -0
  793. package/dist/mcp/src/types.js +9 -0
  794. package/dist/mcp/src/undo-redo.js +64 -0
  795. package/dist/modules/camera-controls/src/index.js +116 -0
  796. package/dist/modules/controller-ui/src/index.js +149 -0
  797. package/dist/modules/devtools/src/api.js +317 -0
  798. package/dist/modules/devtools/src/asset-utils.js +102 -0
  799. package/dist/modules/devtools/src/bind-debug-store.js +34 -0
  800. package/dist/modules/devtools/src/blitz/host.js +391 -0
  801. package/dist/modules/devtools/src/blitz/module.js +65 -0
  802. package/dist/modules/devtools/src/blitz/panels/console.js +217 -0
  803. package/dist/modules/devtools/src/blitz/panels/elements.js +79 -0
  804. package/dist/modules/devtools/src/blitz/panels/gpu.js +61 -0
  805. package/dist/modules/devtools/src/blitz/panels/performance.js +113 -0
  806. package/dist/modules/devtools/src/blitz/panels/snapshot.js +141 -0
  807. package/dist/modules/devtools/src/blitz/panels/types.js +55 -0
  808. package/dist/modules/devtools/src/blitz/theme.js +167 -0
  809. package/dist/modules/devtools/src/data-bridge.js +247 -0
  810. package/dist/modules/devtools/src/debug-overlay.js +181 -0
  811. package/dist/modules/devtools/src/debug-raycast.js +296 -0
  812. package/dist/modules/devtools/src/debug-store.js +28 -0
  813. package/dist/modules/devtools/src/debug-view-descriptors.js +24 -0
  814. package/dist/modules/devtools/src/doctor-panel.js +163 -0
  815. package/dist/modules/devtools/src/gizmo-module.js +95 -0
  816. package/dist/modules/devtools/src/graph-model.js +387 -0
  817. package/dist/modules/devtools/src/grid-renderer.js +145 -0
  818. package/dist/modules/devtools/src/height-ruler-renderer.js +189 -0
  819. package/dist/modules/devtools/src/index.js +46 -0
  820. package/dist/modules/devtools/src/init.js +204 -0
  821. package/dist/modules/devtools/src/label-overlay.js +129 -0
  822. package/dist/modules/devtools/src/material-stats-panel.js +171 -0
  823. package/dist/modules/devtools/src/profiling-bridge.js +288 -0
  824. package/dist/modules/devtools/src/profiling-hooks.js +63 -0
  825. package/dist/modules/devtools/src/renderer-adapter.js +61 -0
  826. package/dist/modules/devtools/src/scene-inspector.js +571 -0
  827. package/dist/modules/devtools/src/scene-store.js +212 -0
  828. package/dist/modules/devtools/src/scene-sync.js +92 -0
  829. package/dist/modules/devtools/src/shaders/transform-gizmo.wgsl +38 -0
  830. package/dist/modules/devtools/src/sim-stats-panel.js +250 -0
  831. package/dist/modules/devtools/src/sim-stats-provider.js +73 -0
  832. package/dist/modules/devtools/src/skeleton-renderer.js +326 -0
  833. package/dist/modules/devtools/src/transform-gizmo.js +677 -0
  834. package/dist/modules/devtools/src/types.js +5 -0
  835. package/dist/modules/devtools/src/worker-expose.js +59 -0
  836. package/dist/modules/devtools/src/worker-sync.js +115 -0
  837. package/dist/modules/editor/src/commands/component.js +151 -0
  838. package/dist/modules/editor/src/commands/entity.js +253 -0
  839. package/dist/modules/editor/src/commands/hierarchy.js +79 -0
  840. package/dist/modules/editor/src/commands/index.js +57 -0
  841. package/dist/modules/editor/src/commands/prefab.js +149 -0
  842. package/dist/modules/editor/src/commands/registry.js +246 -0
  843. package/dist/modules/editor/src/commands/scene-io.js +206 -0
  844. package/dist/modules/editor/src/commands/selection.js +71 -0
  845. package/dist/modules/editor/src/commands/transform.js +88 -0
  846. package/dist/modules/editor/src/ddscene.js +189 -0
  847. package/dist/modules/editor/src/document.js +96 -0
  848. package/dist/modules/editor/src/editor-context.js +115 -0
  849. package/dist/modules/editor/src/index.js +11 -0
  850. package/dist/modules/editor/src/mcp.js +91 -0
  851. package/dist/modules/editor/src/module.js +115 -0
  852. package/dist/modules/editor/src/selection.js +60 -0
  853. package/dist/modules/editor/src/shell.js +397 -0
  854. package/dist/modules/editor/src/viewport.js +186 -0
  855. package/dist/modules/html-ui/src/composite.js +116 -0
  856. package/dist/modules/html-ui/src/create-html-ui.js +137 -0
  857. package/dist/modules/html-ui/src/doc-backend.js +518 -0
  858. package/dist/modules/html-ui/src/host.js +819 -0
  859. package/dist/modules/html-ui/src/index.js +5 -0
  860. package/dist/modules/html-ui/src/jsx-dev-runtime.js +9 -0
  861. package/dist/modules/html-ui/src/jsx-runtime.js +121 -0
  862. package/dist/modules/html-ui/src/protocol.js +6 -0
  863. package/dist/modules/html-ui/src/ui-worker.js +10 -0
  864. package/dist/modules/mcp/src/index.js +62 -0
  865. package/dist/modules/movement-2d/src/grid-character.js +345 -0
  866. package/dist/modules/movement-2d/src/index.js +27 -0
  867. package/dist/modules/movement-3d/src/character-motor.js +166 -0
  868. package/dist/modules/movement-3d/src/index.js +27 -0
  869. package/dist/modules/native-osr/src/index.js +12 -0
  870. package/dist/modules/native-osr/src/input-router.js +335 -0
  871. package/dist/modules/native-osr/src/native-osr-manager.js +210 -0
  872. package/dist/modules/native-osr/src/native-texture-source.js +66 -0
  873. package/dist/modules/native-osr/src/types.js +8 -0
  874. package/dist/modules/native-osr/src/world-space-ui-pass.js +313 -0
  875. package/dist/modules/sailing/src/index.js +39 -0
  876. package/dist/modules/terrain/src/index.js +44 -0
  877. package/dist/modules/vitals/src/index.js +25 -0
  878. package/dist/modules/vitals/src/vitals.js +195 -0
  879. package/dist/modules/xr/src/camera-rig.js +119 -0
  880. package/dist/modules/xr/src/debug.js +45 -0
  881. package/dist/modules/xr/src/frame-loop.js +139 -0
  882. package/dist/modules/xr/src/index.js +10 -0
  883. package/dist/modules/xr/src/input.js +164 -0
  884. package/dist/modules/xr/src/layer.js +100 -0
  885. package/dist/modules/xr/src/session.js +133 -0
  886. package/dist/modules/xr/src/sim-module.js +21 -0
  887. package/dist/modules/xr/src/types.js +4 -0
  888. package/dist/modules/xr/src/webxr.d.ts +182 -0
  889. package/dist/modules/xr/src/xr-module.js +134 -0
  890. package/dist/shader-graph/src/chunks.js +340 -0
  891. package/dist/shader-graph/src/compiler.js +639 -0
  892. package/dist/shader-graph/src/compute-compiler.js +384 -0
  893. package/dist/shader-graph/src/compute-graph.js +55 -0
  894. package/dist/shader-graph/src/compute-profiles.js +39 -0
  895. package/dist/shader-graph/src/graph.js +38 -0
  896. package/dist/shader-graph/src/index.js +15 -0
  897. package/dist/shader-graph/src/profiles.js +305 -0
  898. package/dist/shader-graph/src/validator.js +42 -0
  899. package/dist/shader-graph/src/wgsl-binding-validator.js +110 -0
  900. package/dist/shader-graph/src/wgsl-struct-validator.js +222 -0
  901. package/dist/shader-graph/src/wgsl-struct.js +251 -0
  902. package/dist/test/src/index.js +1 -0
  903. package/dist/test/src/vision-test.js +228 -0
  904. package/libraries/asset-browser/src/software-thumbnails.ts +2 -2
  905. package/libraries/audio-kira/src/backend.ts +2 -1
  906. package/libraries/blitz-ui/native/src/shell.rs +35 -1
  907. package/libraries/blitz-ui/native-osr/Cargo.toml +8 -0
  908. package/libraries/blitz-ui/native-osr/src/lib.rs +213 -22
  909. package/libraries/blitz-ui/native-osr/src/mutate.rs +109 -14
  910. package/libraries/blitz-ui/src/native-osr-ffi.ts +71 -8
  911. package/libraries/blitz-ui/src/router.ts +3 -1
  912. package/libraries/blitz-ui/src/ui-blit-pass.ts +1 -1
  913. package/libraries/character/src/character-animator.ts +1 -1
  914. package/libraries/character/src/customization.ts +513 -0
  915. package/libraries/character/src/index.ts +6 -0
  916. package/libraries/character/src/inspectable.ts +111 -0
  917. package/libraries/character/src/loader.ts +38 -13
  918. package/libraries/character/src/locomotion.ts +13 -1
  919. package/libraries/character/src/preview.ts +94 -24
  920. package/libraries/devtools/README.md +16 -18
  921. package/libraries/devtools/src/backend.ts +505 -0
  922. package/libraries/devtools/src/cdp-bridge.ts +8 -8
  923. package/libraries/devtools/src/collectors.ts +41 -37
  924. package/libraries/devtools/src/index.ts +32 -14
  925. package/libraries/devtools/src/native-providers.ts +20 -12
  926. package/libraries/devtools/src/snapshot.ts +77 -0
  927. package/libraries/devtools/src/web/host.ts +11 -12
  928. package/libraries/devtools/src/web/mirror.ts +14 -405
  929. package/libraries/devtools/src/web/server.ts +4 -3
  930. package/libraries/entities/src/model-renderer.ts +96 -23
  931. package/libraries/gamepad/src/library.ts +2 -1
  932. package/libraries/inspectable/src/index.ts +11 -0
  933. package/libraries/inspectable/src/inspectable.ts +277 -0
  934. package/libraries/marching-cubes/src/streaming-manager.ts +4 -4
  935. package/libraries/models/src/bind-unskinned-meshes.ts +131 -0
  936. package/libraries/models/src/index.ts +1 -0
  937. package/libraries/models/src/types.ts +22 -0
  938. package/libraries/persistence/src/autosave-manager.ts +1 -1
  939. package/libraries/persistence/src/binary-record-store.ts +1 -1
  940. package/libraries/persistence/src/file-save-store.ts +4 -4
  941. package/libraries/persistence/src/library.ts +1 -1
  942. package/libraries/persistence/src/opfs-save-store.ts +5 -5
  943. package/libraries/persistence/src/save-worker.ts +13 -14
  944. package/libraries/physics-rapier/src/ffi-lib.ts +2 -1
  945. package/libraries/postfx/src/post-process-stack.ts +1 -1
  946. package/libraries/sand/src/sand-step-pool.ts +5 -0
  947. package/libraries/water/src/water-renderer.ts +1 -1
  948. package/libraries/weatherfx/src/cloud-system.ts +3 -3
  949. package/mcp/README.md +20 -0
  950. package/mcp/src/client.ts +75 -22
  951. package/mcp/src/undo-redo.ts +2 -2
  952. package/modules/devtools/src/blitz/host.ts +430 -0
  953. package/modules/devtools/src/blitz/module.ts +101 -0
  954. package/modules/devtools/src/blitz/panels/console.ts +223 -0
  955. package/modules/devtools/src/blitz/panels/elements.ts +92 -0
  956. package/modules/devtools/src/blitz/panels/gpu.ts +70 -0
  957. package/modules/devtools/src/blitz/panels/performance.ts +120 -0
  958. package/modules/devtools/src/blitz/panels/snapshot.ts +152 -0
  959. package/modules/devtools/src/blitz/panels/types.ts +120 -0
  960. package/modules/devtools/src/blitz/theme.ts +168 -0
  961. package/modules/devtools/src/data-bridge.ts +1 -1
  962. package/modules/devtools/src/index.ts +6 -0
  963. package/modules/devtools/src/profiling-bridge.ts +17 -13
  964. package/modules/devtools/src/profiling-hooks.ts +22 -13
  965. package/modules/devtools/src/scene-inspector.ts +1 -1
  966. package/modules/devtools/src/worker-sync.ts +9 -1
  967. package/modules/editor/src/commands/registry.ts +2 -2
  968. package/modules/editor/src/module.ts +1 -1
  969. package/modules/html-ui/src/composite.ts +1 -1
  970. package/modules/html-ui/src/create-html-ui.ts +21 -9
  971. package/modules/html-ui/src/doc-backend.ts +189 -10
  972. package/modules/html-ui/src/host.ts +354 -40
  973. package/modules/html-ui/src/index.ts +1 -1
  974. package/modules/html-ui/src/jsx-runtime.ts +1 -1
  975. package/modules/html-ui/src/protocol.ts +53 -6
  976. package/modules/mcp/README.md +6 -0
  977. package/modules/mcp/src/index.ts +70 -3
  978. package/modules/movement-3d/src/character-motor.ts +83 -10
  979. package/package.json +838 -165
  980. package/shader-graph/README.md +25 -0
  981. package/test/README.md +16 -0
  982. package/libraries/blitz-ui/native-osr-spike.ts +0 -70
  983. package/libraries/devtools/native/Cargo.toml +0 -12
  984. package/libraries/devtools/native/src/lib.rs +0 -1646
  985. package/libraries/devtools/native/src/panels/console.rs +0 -338
  986. package/libraries/devtools/native/src/panels/dom_tree.rs +0 -47
  987. package/libraries/devtools/native/src/panels/generic.rs +0 -317
  988. package/libraries/devtools/native/src/panels/gpu.rs +0 -107
  989. package/libraries/devtools/native/src/panels/input.rs +0 -88
  990. package/libraries/devtools/native/src/panels/mod.rs +0 -154
  991. package/libraries/devtools/native/src/panels/perf_metrics.rs +0 -91
  992. package/libraries/devtools/native/src/panels/perf_recorder.rs +0 -158
  993. package/libraries/devtools/native/src/panels/scene.rs +0 -72
  994. package/libraries/devtools/native/src/state.rs +0 -394
  995. package/libraries/devtools/src/egui-ffi.ts +0 -804
  996. package/libraries/devtools/src/egui-renderer.ts +0 -407
  997. package/libraries/devtools/src/host.ts +0 -363
  998. package/libraries/devtools/src/mirror.ts +0 -794
  999. package/libraries/models/test-fixtures/fbx/LICENSE-notice.txt +0 -24
  1000. package/libraries/models/test-fixtures/fbx/README.md +0 -46
  1001. package/libraries/models/test-fixtures/fbx/m01_cube_phong.fbx +0 -0
  1002. package/libraries/models/test-fixtures/fbx/m02_geo_ngons.fbx +0 -0
  1003. package/libraries/models/test-fixtures/fbx/m03_normals.fbx +0 -0
  1004. package/libraries/models/test-fixtures/fbx/m04_material_properties.fbx +0 -0
  1005. package/libraries/models/test-fixtures/fbx/m05_external_diffuse.png +0 -0
  1006. package/libraries/models/test-fixtures/fbx/m05_textures.fbx +0 -0
  1007. package/libraries/models/test-fixtures/fbx/m06_uv_transform.fbx +0 -0
  1008. package/libraries/models/test-fixtures/fbx/m07_multimaterial.fbx +0 -0
  1009. package/libraries/models/test-fixtures/fbx/m08_transforms.fbx +0 -0
  1010. package/libraries/models/test-fixtures/fbx/m09_skinning.fbx +0 -0
  1011. package/libraries/models/test-fixtures/fbx/m10_morph.fbx +0 -0
  1012. package/libraries/models/test-fixtures/fbx/m11_node_anim.fbx +0 -0
  1013. package/libraries/models/test-fixtures/fbx/m12_skeletal_anim.fbx +0 -0
  1014. package/libraries/models/test-fixtures/fbx/m13_morph_anim.fbx +0 -0
  1015. package/libraries/models/test-fixtures/fbx/m14_multiclip.fbx +0 -0
  1016. package/libraries/models/test-fixtures/fbx/m15_camera_lights.fbx +0 -0
  1017. package/libraries/models/test-fixtures/fbx/m16_axis_yup.fbx +0 -0
  1018. package/libraries/models/test-fixtures/fbx/m16_axis_zup.fbx +0 -0
  1019. package/libraries/models/test-fixtures/fbx/m16_units_254.fbx +0 -0
  1020. package/libraries/physics-native/src/ffi-spike-worker.ts +0 -71
  1021. package/libraries/physics-rapier/bench/ffi-bench.ts +0 -79
  1022. package/libraries/physics-rapier/bench/wasm-baseline.ts +0 -90
@@ -0,0 +1,513 @@
1
+ // ============================================================================
2
+ // Character customization — variant catalogs + selection resolution for
3
+ // modular character kits.
4
+ //
5
+ // Kits like the builtin Aisha/Robin/Humanling packs ship every outfit, hair
6
+ // style, beard, and accessory as sibling mesh nodes named `slot.NNN` (with
7
+ // Blender `_ptN` splits folding into their canonical variant). The destructive
8
+ // selectVariantMeshes/filterOptionalMeshes pipeline picks one variant per
9
+ // group at load time; this module instead builds a catalog of every variant
10
+ // and resolves a JSON-serializable CharacterCustomization into the mesh
11
+ // subset to upload — the model-viewer's selectedPartIndices contract applied
12
+ // to characters.
13
+ //
14
+ // Group classification:
15
+ // internal — /collider/ meshes: never listed, never rendered.
16
+ // defaultOff — DEFAULT_OPTIONAL_MESH_PATTERNS (backpack, mask, vest,
17
+ // headgear/headwear/headphone, legpouch, *_acc): hidden by
18
+ // default (parity with filterOptionalMeshes) but equipable.
19
+ // required — body groups (head/torso/leg(s)/feet/hand(s)/eye(s)): must
20
+ // always render a variant — "None" is not offered.
21
+ // optional — everything else (hair, beard, facewear, …): defaults to the
22
+ // first variant, may be hidden or re-picked.
23
+ // ============================================================================
24
+
25
+ import type { MaterialData, MeshData, ModelData } from "@downdraft/engine/libraries/models";
26
+ import { DEFAULT_OPTIONAL_MESH_PATTERNS } from "./loader";
27
+
28
+ /** Serializable per-model customization — persisted in save state. */
29
+ export interface CharacterCustomization {
30
+ /** group key → selected variant part-key ("ash_torso.007"), or null = hidden. */
31
+ variants: Record<string, string | null>;
32
+ /** material name → chosen texture asset path, absent = model default. */
33
+ textures: Record<string, string>;
34
+ /** material name → RGB tint (linear 0-1), absent = material default. */
35
+ tints: Record<string, [number, number, number]>;
36
+ /** Body girth scale delta (-1..1 fraction; 0/absent = authored shape).
37
+ * Applied at upload as a horizontal scale weighted by a skin-derived
38
+ * body-region field, so skin and garments widen together. */
39
+ girth?: number;
40
+ }
41
+
42
+ /** One selectable variant inside a group. */
43
+ export interface VariantRef {
44
+ /** Canonical part key ("ash_torso.007"); `_ptN` splits fold into this. */
45
+ key: string;
46
+ /** Mesh indices the variant covers (node.mesh + node.meshes + _ptN parts). */
47
+ meshIndices: number[];
48
+ }
49
+
50
+ export type VariantGroupKind = "required" | "optional" | "defaultOff" | "internal";
51
+
52
+ /** A customization slot: one pickable variant (or None, when allowed). */
53
+ export interface VariantGroup {
54
+ /** Group key ("ash_torso"). */
55
+ key: string;
56
+ /** Display label ("Upper Torso"). */
57
+ label: string;
58
+ /** Variants in node order. */
59
+ variants: VariantRef[];
60
+ kind: VariantGroupKind;
61
+ }
62
+
63
+ export interface VariantCatalog {
64
+ groups: VariantGroup[];
65
+ /** Fast group lookup by key. */
66
+ byKey: Map<string, VariantGroup>;
67
+ }
68
+
69
+ export interface BuildCatalogOptions {
70
+ /** Group-name suffixes (after stripping the `prefix_` model namespace)
71
+ * that must always render a variant. */
72
+ requiredSuffixes?: readonly string[];
73
+ /** Patterns marking groups hidden-but-equipable (default: optional mesh patterns). */
74
+ defaultOffPatterns?: readonly RegExp[];
75
+ /** Patterns marking groups never rendered or listed (default: /collider/i). */
76
+ internalPatterns?: readonly RegExp[];
77
+ /** Explicit required group keys — overrides suffix classification when present. */
78
+ requiredGroups?: readonly string[];
79
+ }
80
+
81
+ const DEFAULT_REQUIRED_SUFFIXES: readonly string[] = [
82
+ "head", "torso", "leg", "legs", "feet", "foot", "hand", "hands", "eye", "eyes",
83
+ ];
84
+ const DEFAULT_INTERNAL_PATTERNS: readonly RegExp[] = [/collider/i];
85
+
86
+ /** Strip a Blender mesh-split `_ptN` suffix (shared with loader.selectVariantMeshes). */
87
+ function variantPartKey(name: string): string {
88
+ return name.replace(/_pt\d+$/i, "");
89
+ }
90
+
91
+ /** Strip the trailing `.NNN` / `_NNN` variant suffix (shared with loader). */
92
+ function variantGroupKey(name: string): string {
93
+ return variantPartKey(name).replace(/[._]\d+$/, "");
94
+ }
95
+
96
+ /** Group suffix used for required classification: "ash_torso" → "torso". */
97
+ function groupSuffix(key: string): string {
98
+ return key.replace(/^[a-z]+_/i, "").toLowerCase();
99
+ }
100
+
101
+ /** "ash_upperTorso" → "Upper Torso"; "rb_headwear" → "Headwear". */
102
+ export function slotLabel(groupKey: string): string {
103
+ const suffix = groupKey.replace(/^[a-z]+_/i, "");
104
+ return suffix
105
+ .replace(/([a-z])([A-Z])/g, "$1 $2")
106
+ .replace(/_/g, " ")
107
+ .replace(/\b\w/g, (c) => c.toUpperCase());
108
+ }
109
+
110
+ /** Short variant label for UI: "ash_torso.007" → "7"; unnumbered base → "Base". */
111
+ export function variantLabel(variantKey: string): string {
112
+ const m = /[._](\d+)$/.exec(variantKey);
113
+ return m ? String(parseInt(m[1], 10)) : "Base";
114
+ }
115
+
116
+ /**
117
+ * Build the variant catalog for a fully-loaded model (i.e. loaded WITHOUT the
118
+ * destructive filterOptionalMeshes/selectVariantMeshes passes).
119
+ */
120
+ export function buildVariantCatalog(model: ModelData, opts: BuildCatalogOptions = {}): VariantCatalog {
121
+ const requiredSuffixes = opts.requiredSuffixes ?? DEFAULT_REQUIRED_SUFFIXES;
122
+ const defaultOffPatterns = opts.defaultOffPatterns ?? DEFAULT_OPTIONAL_MESH_PATTERNS;
123
+ const internalPatterns = opts.internalPatterns ?? DEFAULT_INTERNAL_PATTERNS;
124
+ const requiredSet = opts.requiredGroups ? new Set(opts.requiredGroups) : null;
125
+
126
+ // Collect mesh-bearing nodes into groups, keyed by variantGroupKey.
127
+ // Within a group, variants are keyed by variantPartKey (canonical node name)
128
+ // so a variant split across `rb_headwear.005`, `.005_pt1`, `.005_pt2` nodes
129
+ // counts once and keeps every split mesh.
130
+ const groupMap = new Map<string, { key: string; parts: Map<string, number[]> }>();
131
+ const nodes = model.nodes ?? [];
132
+ for (let i = 0; i < nodes.length; i++) {
133
+ const node = nodes[i];
134
+ const idxs: number[] = [];
135
+ if (node.meshes) {
136
+ for (let _j = 0, _it = node.meshes, _m = _it.length; _j < _m; _j++) { const mi = _it[_j];
137
+ if (mi < model.meshes.length) idxs.push(mi);
138
+ }
139
+ } else if (node.mesh !== undefined && node.mesh < model.meshes.length) {
140
+ idxs.push(node.mesh);
141
+ }
142
+ if (idxs.length === 0) continue;
143
+
144
+ const gkey = variantGroupKey(node.name);
145
+ const pkey = variantPartKey(node.name);
146
+ let g = groupMap.get(gkey);
147
+ if (!g) { g = { key: gkey, parts: new Map() }; groupMap.set(gkey, g); }
148
+ let part = g.parts.get(pkey);
149
+ if (!part) { part = []; g.parts.set(pkey, part); }
150
+ for (let _j = 0, _n = idxs.length; _j < _n; _j++) part.push(idxs[_j]);
151
+ }
152
+
153
+ const groups: VariantGroup[] = [];
154
+ const byKey = new Map<string, VariantGroup>();
155
+ for (const g of groupMap.values()) {
156
+ const variants: VariantRef[] = [];
157
+ for (const [pkey, meshIndices] of g.parts.entries()) {
158
+ variants.push({ key: pkey, meshIndices });
159
+ }
160
+ let kind: VariantGroupKind;
161
+ if (internalPatterns.some((p) => p.test(g.key))) kind = "internal";
162
+ else if (requiredSet ? requiredSet.has(g.key) : requiredSuffixes.includes(groupSuffix(g.key))) kind = "required";
163
+ else if (defaultOffPatterns.some((p) => p.test(g.key))) kind = "defaultOff";
164
+ else kind = "optional";
165
+ const group: VariantGroup = { key: g.key, label: slotLabel(g.key), variants, kind };
166
+ groups.push(group);
167
+ byKey.set(g.key, group);
168
+ }
169
+ return { groups, byKey };
170
+ }
171
+
172
+ /**
173
+ * The kit default — reproduces the legacy filterOptionalMeshes +
174
+ * selectVariantMeshes pipeline exactly: required and optional groups keep
175
+ * their first variant; defaultOff groups are hidden; internal groups render
176
+ * nothing.
177
+ */
178
+ export function defaultCustomization(catalog: VariantCatalog): CharacterCustomization {
179
+ const variants: Record<string, string | null> = {};
180
+ for (let _i = 0, _it = catalog.groups, _n = _it.length; _i < _n; _i++) { const g = _it[_i];
181
+ if (g.kind === "internal") continue;
182
+ variants[g.key] = g.kind === "defaultOff" ? null : (g.variants[0]?.key ?? null);
183
+ }
184
+ return { variants, textures: {}, tints: {} };
185
+ }
186
+
187
+ /** Groups the UI should list: everything except internal groups and
188
+ * required groups with a single variant (nothing to choose). */
189
+ export function customizableGroups(catalog: VariantCatalog): VariantGroup[] {
190
+ const out: VariantGroup[] = [];
191
+ for (let _i = 0, _it = catalog.groups, _n = _it.length; _i < _n; _i++) { const g = _it[_i];
192
+ if (g.kind === "internal") continue;
193
+ if (g.kind === "required" && g.variants.length <= 1) continue;
194
+ out.push(g);
195
+ }
196
+ return out;
197
+ }
198
+
199
+ /** Validate a saved variant pick: returns the variant key, or the group's
200
+ * default when the saved value is missing/stale. */
201
+ export function effectiveVariantKey(group: VariantGroup, cust: CharacterCustomization): string | null {
202
+ const saved = cust.variants[group.key];
203
+ if (saved !== undefined) {
204
+ if (saved === null) return group.kind === "required" ? (group.variants[0]?.key ?? null) : null;
205
+ for (let _i = 0, _it = group.variants, _n = _it.length; _i < _n; _i++) { const v = _it[_i];
206
+ if (v.key === saved) return saved;
207
+ }
208
+ }
209
+ return group.kind === "defaultOff" ? null : (group.variants[0]?.key ?? null);
210
+ }
211
+
212
+ export interface ResolveMeshesOptions {
213
+ /** Group suffixes whose skin-material meshes are treated as "under layers"
214
+ * (bare skin tucked beneath garments — legs/hands under hems and sleeves).
215
+ * Defaults cover the body-clothing region; the head/eyes are excluded so
216
+ * the face can't sink behind eyeball meshes. */
217
+ innerLayerSuffixes?: readonly string[];
218
+ /** Material names (string or RegExp) treated as skin — the universal
219
+ * under-layer that garments render over. */
220
+ innerMaterials?: readonly (string | RegExp)[];
221
+ /** Inward normal offset for skin meshes in inner groups, in model units
222
+ * (default 0.005 ≈ ~5mm at the 1.8m fit). */
223
+ innerLayerOffset?: number;
224
+ /** Bone-name → girth weight pairs (first match wins, fallback 0.5).
225
+ * Drives the body-region field for `customization.girth` — verts skinned
226
+ * to core bones deform fully, extremities stay put. Defaults cover the
227
+ * UE-style naming shared by all bundled kits. */
228
+ girthBoneFactors?: readonly [RegExp, number][];
229
+ /** Girth weight for verts with no skin data (rigid pieces still track
230
+ * body width so they don't sink into a widened torso). Default 0.7. */
231
+ girthUnskinned?: number;
232
+ /** Height window for the girth falloff, as fractions of model height
233
+ * measured up from the floor: [fullBelow, capAbove, topMul]. Below
234
+ * `fullBelow` the bone weight applies at full strength; it eases to
235
+ * `topMul` by `capAbove` so collars/hoods near the head don't balloon
236
+ * wider than the head itself. Default [0.72, 0.88, 0.3]. */
237
+ girthUpWindow?: readonly [number, number, number];
238
+ }
239
+
240
+ const DEFAULT_INNER_SUFFIXES: readonly string[] = [
241
+ "leg", "legs", "hand", "hands", "torso", "uppertorso", "foot", "feet",
242
+ ];
243
+ const DEFAULT_INNER_MATERIALS: readonly RegExp[] = [/skin/i];
244
+ const DEFAULT_INNER_OFFSET = 0.01;
245
+
246
+ /** UE-style bone names → girth region weight. Ordered — first match wins. */
247
+ const DEFAULT_GIRTH_BONES: readonly [RegExp, number][] = [
248
+ [/pelvis|spine/i, 1.0],
249
+ [/thigh/i, 0.8],
250
+ [/clavicle/i, 0.7],
251
+ [/upperarm/i, 0.5],
252
+ [/calf/i, 0.4],
253
+ [/lowerarm/i, 0.3],
254
+ [/neck|head/i, 0],
255
+ [/foot|ball|toe/i, 0.15],
256
+ [/hand|thumb|index|middle|ring|pinky|metacarpal/i, 0.15],
257
+ ];
258
+ const DEFAULT_GIRTH_UNSKINNED = 0.7;
259
+ const GIRTH_FALLBACK = 0.5;
260
+ const DEFAULT_GIRTH_WINDOW: readonly [number, number, number] = [0.72, 0.88, 0.3];
261
+
262
+ function boneGirthFactor(name: string, table: readonly [RegExp, number][]): number {
263
+ for (let i = 0; i < table.length; i++) if (table[i][0].test(name)) return table[i][1];
264
+ return GIRTH_FALLBACK;
265
+ }
266
+
267
+ /** Per-mesh girth weights — cached so repeat resolves don't rescan skin
268
+ * weights. Keyed on the factors table + height window the field derives
269
+ * from (the window shifts if the selected mesh set's bounds change). */
270
+ const girthWeightCache = new WeakMap<MeshData, {
271
+ src: readonly [RegExp, number][]; uF: number; uC: number; tm: number; weights: Float32Array;
272
+ }>();
273
+
274
+ function girthWeightsFor(
275
+ model: ModelData, mesh: MeshData, table: readonly [RegExp, number][], unskinned: number,
276
+ up: number, uFull: number, uCap: number, topMul: number,
277
+ ): Float32Array {
278
+ const hit = girthWeightCache.get(mesh);
279
+ if (hit && hit.src === table && hit.uF === uFull && hit.uC === uCap && hit.tm === topMul) return hit.weights;
280
+ const out = new Float32Array(mesh.vertexCount);
281
+ if (mesh.joints && mesh.weights && mesh.joints.length >= mesh.vertexCount * 4 && model.skin) {
282
+ const bones = model.skin.bones;
283
+ const jf = new Float32Array(bones.length);
284
+ for (let i = 0; i < bones.length; i++) jf[i] = boneGirthFactor(bones[i].name, table);
285
+ for (let v = 0; v < mesh.vertexCount; v++) {
286
+ const b = v * 4;
287
+ out[v] =
288
+ jf[mesh.joints[b]] * mesh.weights[b] +
289
+ jf[mesh.joints[b + 1]] * mesh.weights[b + 1] +
290
+ jf[mesh.joints[b + 2]] * mesh.weights[b + 2] +
291
+ jf[mesh.joints[b + 3]] * mesh.weights[b + 3];
292
+ }
293
+ } else {
294
+ out.fill(unskinned);
295
+ }
296
+ // Height taper — weight gain lives in the torso/legs; ease toward
297
+ // topMul approaching the head so collars don't out-widen the face.
298
+ const span = uCap - uFull;
299
+ for (let v = 0; v < mesh.vertexCount; v++) {
300
+ const u = mesh.vertices[v * 6 + up];
301
+ if (u <= uFull || span <= 0) continue;
302
+ if (u >= uCap) { out[v] *= topMul; continue; }
303
+ const t = (u - uFull) / span;
304
+ out[v] *= 1 + (topMul - 1) * t * t * (3 - 2 * t);
305
+ }
306
+ girthWeightCache.set(mesh, { src: table, uF: uFull, uC: uCap, tm: topMul, weights: out });
307
+ return out;
308
+ }
309
+
310
+ /**
311
+ * Resolve a customization into the mesh subset to upload. Internal groups
312
+ * never contribute meshes; `null` selections contribute none. Required groups
313
+ * fall back to their first variant when the saved pick is stale.
314
+ *
315
+ * Skin-material meshes in "inner" groups are shallow-cloned with a
316
+ * `surfaceOffset` — modular kits author bare-skin shells that sit fractions
317
+ * of a millimeter under garments; without the offset the skin z-fights or
318
+ * pokes through where a garment variant doesn't fully cover it. The offset
319
+ * only applies to skin meshes substantially enclosed by a non-skin mesh in
320
+ * the same variant: a bare-skin pick (or one whose only non-skin meshes are
321
+ * small accessories like nails or partially-overlapping cuffs) must keep its
322
+ * authored surface, since a uniform inward offset on a limb-radius mesh
323
+ * collapses it to the bone.
324
+ */
325
+ export function resolveCustomizationMeshes(
326
+ model: ModelData,
327
+ catalog: VariantCatalog,
328
+ cust: CharacterCustomization,
329
+ opts: ResolveMeshesOptions = {},
330
+ ): { meshes: MeshData[]; meshIndices: Set<number> } {
331
+ const innerSuffixes = opts.innerLayerSuffixes ?? DEFAULT_INNER_SUFFIXES;
332
+ const innerMats = opts.innerMaterials ?? DEFAULT_INNER_MATERIALS;
333
+ const innerOffset = opts.innerLayerOffset ?? DEFAULT_INNER_OFFSET;
334
+ const isSkin = (meshIdx: number) => {
335
+ const name = model.materials?.[model.meshes[meshIdx].materialIndex ?? -1]?.name;
336
+ return name !== undefined && innerMats.some((p) => (typeof p === "string" ? p === name : p.test(name)));
337
+ };
338
+ const meshIndices = new Set<number>();
339
+ const innerIndices = new Set<number>();
340
+ const boundsCache = new Map<number, MeshBounds | null>();
341
+ for (let _i = 0, _it = catalog.groups, _n = _it.length; _i < _n; _i++) { const g = _it[_i];
342
+ if (g.kind === "internal") continue;
343
+ const pick = effectiveVariantKey(g, cust);
344
+ if (pick === null) continue;
345
+ const inner = innerOffset !== 0 && innerSuffixes.includes(groupSuffix(g.key));
346
+ for (let _j = 0, _jt = g.variants, _m = _jt.length; _j < _m; _j++) { const v = _jt[_j];
347
+ if (v.key !== pick) continue;
348
+ for (let _k = 0, _kt = v.meshIndices, _l = _kt.length; _k < _l; _k++) {
349
+ meshIndices.add(_kt[_k]);
350
+ }
351
+ if (!inner) continue;
352
+ for (let _k = 0, _kt = v.meshIndices, _l = _kt.length; _k < _l; _k++) {
353
+ const mi = _kt[_k];
354
+ if (!isSkin(mi)) continue;
355
+ const covered = v.meshIndices.some((j) => {
356
+ if (j === mi || isSkin(j)) return false;
357
+ const sb = meshBoundsCached(model.meshes, mi, boundsCache);
358
+ const gb = meshBoundsCached(model.meshes, j, boundsCache);
359
+ // ≥90% enclosed: the shell sits under the garment. Lower overlaps
360
+ // are exposed surfaces (bare picks, crease slivers) that must keep
361
+ // their authored shape — recessing them opens a gap at the seam.
362
+ return sb !== null && gb !== null && boxOverlapFraction(sb, gb) >= 0.9;
363
+ });
364
+ if (covered) innerIndices.add(mi);
365
+ }
366
+ }
367
+ }
368
+ // Girth: scale the two horizontal axes about the body-center line.
369
+ // Loaded vertex data is always engine y-up (normalizeModel bakes the
370
+ // source up-axis conversion into the verts — do NOT use sourceUpAxis
371
+ // here, it describes the file, not the stored data). Pivot on each
372
+ // scaled axis is its bounds midpoint.
373
+ const girth = cust.girth ?? 0;
374
+ let gAxes: readonly [number, number] | null = null;
375
+ let gCenters: readonly [number, number] | null = null;
376
+ let gUp = 1, gUFull = 0, gUCap = 0, gUTop = 0;
377
+ const gTable = opts.girthBoneFactors ?? DEFAULT_GIRTH_BONES;
378
+ const gUnskinned = opts.girthUnskinned ?? DEFAULT_GIRTH_UNSKINNED;
379
+ const gWindow = opts.girthUpWindow ?? DEFAULT_GIRTH_WINDOW;
380
+ if (girth !== 0) {
381
+ const b = computeMeshBounds(model.meshes, meshIndices);
382
+ if (b) {
383
+ const ext = [b.max[0] - b.min[0], b.max[1] - b.min[1], b.max[2] - b.min[2]];
384
+ const up = 1;
385
+ const h = [0, 1, 2].filter((a) => a !== up) as [number, number];
386
+ gAxes = h;
387
+ gCenters = [(b.min[h[0]] + b.max[h[0]]) / 2, (b.min[h[1]] + b.max[h[1]]) / 2];
388
+ gUp = up;
389
+ const uSpan = Math.max(1e-6, ext[up]);
390
+ gUFull = b.min[up] + uSpan * Math.min(gWindow[0], gWindow[1]);
391
+ gUCap = b.min[up] + uSpan * Math.max(gWindow[0], gWindow[1]);
392
+ gUTop = gWindow[2];
393
+ }
394
+ }
395
+ const meshes: MeshData[] = [];
396
+ for (let i = 0; i < model.meshes.length; i++) {
397
+ if (!meshIndices.has(i)) continue;
398
+ const m = model.meshes[i];
399
+ const inner = innerIndices.has(i);
400
+ if (!inner && !gAxes) { meshes.push(m); continue; }
401
+ meshes.push({
402
+ ...m,
403
+ ...(inner ? { surfaceOffset: innerOffset } : {}),
404
+ ...(gAxes ? { surfaceGirth: { factor: girth, weights: girthWeightsFor(model, m, gTable, gUnskinned, gUp, gUFull, gUCap, gUTop), axes: gAxes, centers: gCenters! } } : {}),
405
+ });
406
+ }
407
+ return { meshes, meshIndices };
408
+ }
409
+
410
+ /** Mesh indices of visible *required* groups — the body used for scale fit
411
+ * (outfits/hats shouldn't change how the avatar fits the 1.8m capsule). */
412
+ export function requiredMeshIndices(catalog: VariantCatalog, cust: CharacterCustomization): Set<number> {
413
+ const out = new Set<number>();
414
+ for (let _i = 0, _it = catalog.groups, _n = _it.length; _i < _n; _i++) { const g = _it[_i];
415
+ if (g.kind !== "required") continue;
416
+ const pick = effectiveVariantKey(g, cust);
417
+ if (pick === null) continue;
418
+ for (let _j = 0, _jt = g.variants, _m = _jt.length; _j < _m; _j++) { const v = _jt[_j];
419
+ if (v.key !== pick) continue;
420
+ for (let _k = 0, _kt = v.meshIndices, _l = _kt.length; _k < _l; _k++) out.add(_kt[_k]);
421
+ }
422
+ }
423
+ return out;
424
+ }
425
+
426
+ type MeshBounds = { min: [number, number, number]; max: [number, number, number] };
427
+
428
+ /** Per-mesh axis-aligned bounds (pos stride: xyz + normal xyz), or null for
429
+ * a mesh with no usable position data. */
430
+ function singleMeshBounds(mesh: MeshData): MeshBounds | null {
431
+ const verts = mesh.vertices;
432
+ const stride = mesh.vertexCount > 0 ? Math.floor(verts.length / mesh.vertexCount) : 0;
433
+ if (stride < 3) return null;
434
+ const min: [number, number, number] = [Infinity, Infinity, Infinity];
435
+ const max: [number, number, number] = [-Infinity, -Infinity, -Infinity];
436
+ for (let v = 0; v < mesh.vertexCount; v++) {
437
+ const x = verts[v * stride], y = verts[v * stride + 1], z = verts[v * stride + 2];
438
+ if (x < min[0]) min[0] = x; if (x > max[0]) max[0] = x;
439
+ if (y < min[1]) min[1] = y; if (y > max[1]) max[1] = y;
440
+ if (z < min[2]) min[2] = z; if (z > max[2]) max[2] = z;
441
+ }
442
+ return { min, max };
443
+ }
444
+
445
+ function meshBoundsCached(meshes: MeshData[], i: number, cache: Map<number, MeshBounds | null>): MeshBounds | null {
446
+ let b = cache.get(i);
447
+ if (b === undefined) {
448
+ b = singleMeshBounds(meshes[i]);
449
+ cache.set(i, b);
450
+ }
451
+ return b;
452
+ }
453
+
454
+ /** Fraction of box `a`'s volume overlapped by box `b` (0–1). */
455
+ function boxOverlapFraction(a: MeshBounds, b: MeshBounds): number {
456
+ let f = 1;
457
+ for (let i = 0; i < 3; i++) {
458
+ const ext = Math.max(1e-9, a.max[i] - a.min[i]);
459
+ f *= Math.max(0, Math.min(a.max[i], b.max[i]) - Math.max(a.min[i], b.min[i])) / ext;
460
+ }
461
+ return f;
462
+ }
463
+
464
+ /** Axis-aligned bounds over vertex positions (pos stride: xyz + normal xyz). */
465
+ export function computeMeshBounds(
466
+ meshes: MeshData[],
467
+ meshIndices?: Set<number>,
468
+ ): { min: [number, number, number]; max: [number, number, number] } | null {
469
+ const min: [number, number, number] = [Infinity, Infinity, Infinity];
470
+ const max: [number, number, number] = [-Infinity, -Infinity, -Infinity];
471
+ let any = false;
472
+ for (let i = 0; i < meshes.length; i++) {
473
+ if (meshIndices && !meshIndices.has(i)) continue;
474
+ const mesh = meshes[i];
475
+ const verts = mesh.vertices;
476
+ const stride = mesh.vertexCount > 0 ? Math.floor(verts.length / mesh.vertexCount) : 0;
477
+ if (stride < 3) continue;
478
+ for (let v = 0; v < mesh.vertexCount; v++) {
479
+ const x = verts[v * stride], y = verts[v * stride + 1], z = verts[v * stride + 2];
480
+ if (x < min[0]) min[0] = x; if (x > max[0]) max[0] = x;
481
+ if (y < min[1]) min[1] = y; if (y > max[1]) max[1] = y;
482
+ if (z < min[2]) min[2] = z; if (z > max[2]) max[2] = z;
483
+ any = true;
484
+ }
485
+ }
486
+ return any ? { min, max } : null;
487
+ }
488
+
489
+ /** Clone the materials array and apply a texture swap (bytes already fetched)
490
+ * and/or tint on the named material. Indices are preserved so mesh
491
+ * materialIndex lookups stay valid. Returns the ORIGINAL array untouched
492
+ * when no override applies. */
493
+ export function withMaterialOverrides(
494
+ materials: MaterialData[] | undefined,
495
+ overrides: Array<{ material: string; textureData?: ArrayBuffer | null; tint?: [number, number, number] }>,
496
+ ): MaterialData[] | undefined {
497
+ if (!materials || overrides.length === 0) return materials;
498
+ let out: MaterialData[] | null = null;
499
+ for (let _i = 0, _it = overrides, _n = _it.length; _i < _n; _i++) { const ov = _it[_i];
500
+ for (let mi = 0; mi < materials.length; mi++) {
501
+ if (materials[mi].name !== ov.material) continue;
502
+ if (!out) out = materials.slice();
503
+ const m = { ...out[mi] };
504
+ if (ov.textureData !== undefined) {
505
+ m.textureData = ov.textureData;
506
+ m.textureUri = undefined;
507
+ }
508
+ if (ov.tint) m.baseColor = [ov.tint[0], ov.tint[1], ov.tint[2], m.baseColor[3]];
509
+ out[mi] = m;
510
+ }
511
+ }
512
+ return out ?? materials;
513
+ }
@@ -13,6 +13,12 @@
13
13
  // ============================================================================
14
14
 
15
15
  export { buildLocomotionClips, CharacterAnimator, findBoneIndex, positionTrack, resolveHumanoidBones, rotationTrack, type HumanoidBoneIndices } from "./character-animator";
16
+ export {
17
+ buildVariantCatalog, computeMeshBounds, customizableGroups, defaultCustomization, effectiveVariantKey, requiredMeshIndices, resolveCustomizationMeshes, slotLabel, variantLabel, withMaterialOverrides, type BuildCatalogOptions, type CharacterCustomization, type ResolveMeshesOptions, type VariantCatalog, type VariantGroup, type VariantGroupKind, type VariantRef
18
+ } from "./customization";
19
+ export {
20
+ characterCustomizationNodes, CUSTOMIZATION_NONE, type CharacterCustomizationNodesOptions
21
+ } from "./inspectable";
16
22
  export {
17
23
  createCharacterModelLoader, DEFAULT_OPTIONAL_MESH_PATTERNS, filterOptionalMeshes, isDecodableImage, loadExternalTextures, selectVariantMeshes, type CharacterAnimationDef, type CharacterModelDef,
18
24
  type CharacterModelLoader, type CharacterModelLoaderOptions
@@ -0,0 +1,111 @@
1
+ // ============================================================================
2
+ // inspectable.ts — characterCustomizationNodes(): InspectableNode[] exposing
3
+ // a CharacterCustomization to automation (MCP inspectable_* tools, devtools).
4
+ //
5
+ // The nodes write through the game's `apply` callback — the SAME function the
6
+ // customization UI calls (store update → resolveCustomizationMeshes → mesh
7
+ // re-upload → sim dispatch) — so an agent setting `player.customization.
8
+ // variants.ash_torso` produces exactly the in-game effect of a user picking
9
+ // that variant.
10
+ //
11
+ // Group coverage is captured at call time: re-run the helper and re-register
12
+ // (the previous registerAll() unsubscribe makes this one line) after a model
13
+ // swap changes the group set. Option lists stay fresh within a fixed set —
14
+ // `enum` and `get` re-resolve the catalog lazily.
15
+ // ============================================================================
16
+
17
+ import type { InspectableNode } from "@downdraft/engine/libraries/inspectable";
18
+ import {
19
+ customizableGroups,
20
+ effectiveVariantKey,
21
+ slotLabel,
22
+ type CharacterCustomization,
23
+ type VariantCatalog,
24
+ type VariantGroup,
25
+ } from "./customization";
26
+
27
+ /** Sentinel enum value standing in for a `null` variant pick (hidden group). */
28
+ export const CUSTOMIZATION_NONE = "<none>";
29
+
30
+ export interface CharacterCustomizationNodesOptions {
31
+ /** Path prefix for the emitted nodes. Default "player.customization". */
32
+ prefix?: string;
33
+ /** The model's variant catalog, or a lazy accessor returning null before
34
+ * the model loads. Variant-group nodes are emitted for the groups
35
+ * `customizableGroups` reports at call time. */
36
+ catalog: VariantCatalog | (() => VariantCatalog | null);
37
+ /** Read the live customization (e.g. `() => store.getState().player.customization`). */
38
+ get: () => CharacterCustomization;
39
+ /** Apply a changed customization — pass the same function the game's
40
+ * customizer UI calls. */
41
+ apply(next: CharacterCustomization): void;
42
+ }
43
+
44
+ export function characterCustomizationNodes(opts: CharacterCustomizationNodesOptions): InspectableNode[] {
45
+ const prefix = opts.prefix ?? "player.customization";
46
+ const catalog = () => (typeof opts.catalog === "function" ? opts.catalog() : opts.catalog);
47
+ const patch = (update: Partial<CharacterCustomization>) => opts.apply({ ...opts.get(), ...update });
48
+
49
+ const nodes: InspectableNode[] = [
50
+ {
51
+ path: `${prefix}.girth`,
52
+ label: "Body girth",
53
+ description: "Horizontal body-width scale delta; 0 = authored shape.",
54
+ type: "number",
55
+ min: -1,
56
+ max: 1,
57
+ get: () => opts.get().girth ?? 0,
58
+ set: (v) => patch({ girth: v as number }),
59
+ },
60
+ {
61
+ path: `${prefix}.tints`,
62
+ label: "Material tints",
63
+ description: "Whole tint map (material name → linear RGB 0-1 triple).",
64
+ type: "json",
65
+ get: () => opts.get().tints,
66
+ set: (v) => patch({ tints: v as CharacterCustomization["tints"] }),
67
+ },
68
+ {
69
+ path: `${prefix}.textures`,
70
+ label: "Material textures",
71
+ description: "Whole texture map (material name → texture asset path).",
72
+ type: "json",
73
+ get: () => opts.get().textures,
74
+ set: (v) => patch({ textures: v as CharacterCustomization["textures"] }),
75
+ },
76
+ ];
77
+
78
+ for (const group of customizableGroups(catalog() ?? { groups: [], byKey: new Map() })) {
79
+ nodes.push(variantNode(prefix, group, catalog, opts.get, patch));
80
+ }
81
+ return nodes;
82
+ }
83
+
84
+ function variantNode(
85
+ prefix: string,
86
+ groupAtEmit: VariantGroup,
87
+ catalog: () => VariantCatalog | null,
88
+ get: () => CharacterCustomization,
89
+ patch: (u: Partial<CharacterCustomization>) => void,
90
+ ): InspectableNode {
91
+ // Group lookups re-resolve the catalog so a rebuilt catalog (same group
92
+ // set, refreshed variants) is honored without re-registration.
93
+ const group = () => catalog()?.byKey.get(groupAtEmit.key) ?? groupAtEmit;
94
+ const allowsNone = () => group().kind !== "required";
95
+ const options = () => {
96
+ const keys = group().variants.map((v) => v.key);
97
+ return allowsNone() ? [...keys, CUSTOMIZATION_NONE] : keys;
98
+ };
99
+ return {
100
+ path: `${prefix}.variants.${groupAtEmit.key}`,
101
+ label: groupAtEmit.label,
102
+ description: `Variant pick for the ${slotLabel(groupAtEmit.key)} slot`,
103
+ type: "enum",
104
+ enum: options,
105
+ get: () => effectiveVariantKey(group(), get()) ?? CUSTOMIZATION_NONE,
106
+ set: (v) => {
107
+ const cust = get();
108
+ patch({ variants: { ...cust.variants, [groupAtEmit.key]: v === CUSTOMIZATION_NONE ? null : (v as string) } });
109
+ },
110
+ };
111
+ }