@downdraft/engine 0.1.1 → 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 (1021) hide show
  1. package/app/README.md +11 -0
  2. package/app/src/renderer/bootstrap.ts +295 -19
  3. package/app/src/renderer/game-module.ts +60 -12
  4. package/app/src/renderer/hooks.ts +9 -1
  5. package/app/src/renderer/hot-reload.ts +9 -9
  6. package/app/src/renderer/mcp-harness.ts +2 -2
  7. package/app/src/renderer/standard-automation-tools.ts +104 -3
  8. package/app/src/shared/feature-log.ts +2 -1
  9. package/app/src/shared/mcp-discovery.ts +8 -3
  10. package/app/src/shared/mcp-proxy.ts +2 -2
  11. package/asset-bake/README.md +22 -0
  12. package/core/README.md +25 -0
  13. package/core/src/animation/skeleton-animator.ts +23 -5
  14. package/core/src/assets/manager.ts +4 -4
  15. package/core/src/ecs/events.ts +1 -1
  16. package/core/src/ecs/schedule.ts +1 -1
  17. package/core/src/ecs/world.ts +1 -1
  18. package/core/src/index.ts +3 -4
  19. package/core/src/library/host.ts +27 -13
  20. package/core/src/library/library.ts +13 -5
  21. package/core/src/module/cross-thread.ts +6 -0
  22. package/core/src/module/diagnostics.ts +10 -6
  23. package/core/src/module/host.ts +65 -18
  24. package/core/src/module/index.ts +1 -0
  25. package/core/src/module/module.ts +11 -5
  26. package/core/src/module/renderer-module.ts +15 -0
  27. package/core/src/physics/safety.ts +1 -1
  28. package/core/src/platform/bun-preload.ts +7 -2
  29. package/core/src/platform/glob-polyfill.ts +17 -8
  30. package/core/src/platform/pkg-root.ts +27 -0
  31. package/core/src/platform/runtime.ts +29 -0
  32. package/core/src/plugin/discovery.ts +1 -1
  33. package/core/src/plugin/extension-loaders.ts +6 -4
  34. package/core/src/plugin/host.ts +13 -13
  35. package/core/src/plugin/loader-asset.ts +5 -5
  36. package/core/src/plugin/loader-quickjs.ts +1 -1
  37. package/core/src/plugin/loader-wasm.ts +3 -3
  38. package/core/src/plugin/loader-worker.ts +1 -1
  39. package/core/src/plugin/manifest.ts +8 -3
  40. package/core/src/plugin/workshop.ts +3 -3
  41. package/core/src/profiling/index.ts +1 -1
  42. package/core/src/profiling/profiling-sab.ts +19 -0
  43. package/core/src/profiling/warnings.ts +1 -1
  44. package/core/src/profiling/worker-prelude.ts +1 -1
  45. package/core/src/render/bindless/frame-bindings.ts +1 -1
  46. package/core/src/render/bindless/material-manager.ts +2 -2
  47. package/core/src/render/bindless/texture-registry.ts +2 -2
  48. package/core/src/render/device.ts +5 -5
  49. package/core/src/render/frame-graph.ts +2 -2
  50. package/core/src/render/game-renderer.ts +42 -18
  51. package/core/src/render/hot-reload.ts +3 -3
  52. package/core/src/render/renderer-module-host.ts +32 -12
  53. package/core/src/render/shader-validator.ts +7 -7
  54. package/core/src/render/surface.ts +1 -1
  55. package/core/src/sab/errors.ts +1 -1
  56. package/core/src/sab/sab-polyfill.ts +1 -1
  57. package/core/src/save/migration-registry.ts +4 -4
  58. package/core/src/save/schema.ts +1 -1
  59. package/core/src/scene/prefab.ts +1 -1
  60. package/core/src/scene/scene-manager.ts +2 -2
  61. package/core/src/scene/scene.ts +4 -4
  62. package/core/src/scene/streaming.ts +2 -2
  63. package/core/src/scripting/hot-reload.ts +2 -2
  64. package/core/src/sim/hot-reload-pipeline.ts +30 -6
  65. package/core/src/sim/sim-state-helper.ts +1 -1
  66. package/core/src/sim/transient-state-registry.ts +1 -1
  67. package/core/src/sim/worker-loop.ts +2 -2
  68. package/core/src/telemetry/gpu-profiler.ts +3 -3
  69. package/core/src/util/index.ts +1 -1
  70. package/core/src/util/logger.ts +36 -5
  71. package/core/src/version.ts +13 -0
  72. package/core/src/worker/base-worker-host.ts +87 -25
  73. package/core/src/worker/buffer-sync.ts +1 -1
  74. package/core/src/worker/crash-recovery.ts +2 -2
  75. package/core/src/worker/instrumented-worker-host.ts +3 -3
  76. package/core/src/worker/rpc.ts +62 -11
  77. package/core/src/worker/sim-worker-base.ts +3 -8
  78. package/core/src/worker/task-pool.ts +2 -2
  79. package/dist/.dd-manifest.json +4119 -0
  80. package/dist/app/src/index.js +9 -0
  81. package/dist/app/src/renderer/bootstrap.js +446 -0
  82. package/dist/app/src/renderer/downdraft-base.css +93 -0
  83. package/dist/app/src/renderer/feature-log.js +180 -0
  84. package/dist/app/src/renderer/game-module.js +562 -0
  85. package/dist/app/src/renderer/hooks.js +82 -0
  86. package/dist/app/src/renderer/hot-reload.js +158 -0
  87. package/dist/app/src/renderer/import-cache.js +77 -0
  88. package/dist/app/src/renderer/index.js +149 -0
  89. package/dist/app/src/renderer/mcp-harness.js +112 -0
  90. package/dist/app/src/renderer/save-store-factory.js +180 -0
  91. package/dist/app/src/renderer/sim-bridge.js +138 -0
  92. package/dist/app/src/renderer/standard-automation-tools.js +720 -0
  93. package/dist/app/src/shared/feature-log.js +54 -0
  94. package/dist/app/src/shared/gpu-info.js +74 -0
  95. package/dist/app/src/shared/import-cache-store.js +123 -0
  96. package/dist/app/src/shared/index.js +4 -0
  97. package/dist/app/src/shared/mcp-discovery.js +55 -0
  98. package/dist/app/src/shared/mcp-proxy.js +71 -0
  99. package/dist/app/src/shared/types.js +13 -0
  100. package/dist/asset-bake/src/bake-audio.js +103 -0
  101. package/dist/asset-bake/src/bake-gltf.js +141 -0
  102. package/dist/asset-bake/src/bake.js +63 -0
  103. package/dist/asset-bake/src/cache.js +147 -0
  104. package/dist/asset-bake/src/config.js +93 -0
  105. package/dist/asset-bake/src/index.js +25 -0
  106. package/dist/core/src/animation/animation-event.js +24 -0
  107. package/dist/core/src/animation/bone-mask.js +103 -0
  108. package/dist/core/src/animation/clip.js +210 -0
  109. package/dist/core/src/animation/index.js +13 -0
  110. package/dist/core/src/animation/mixamo.js +78 -0
  111. package/dist/core/src/animation/morph-target.js +37 -0
  112. package/dist/core/src/animation/player.js +621 -0
  113. package/dist/core/src/animation/retarget.js +101 -0
  114. package/dist/core/src/animation/skeleton-animator.js +1361 -0
  115. package/dist/core/src/animation/skeleton.js +166 -0
  116. package/dist/core/src/animation/state-machine.js +252 -0
  117. package/dist/core/src/assets/blob-store.js +14 -0
  118. package/dist/core/src/assets/cache.js +168 -0
  119. package/dist/core/src/assets/cubemap-converter.js +129 -0
  120. package/dist/core/src/assets/environment-manager.js +84 -0
  121. package/dist/core/src/assets/import-cache.js +36 -0
  122. package/dist/core/src/assets/import-settings.js +34 -0
  123. package/dist/core/src/assets/importer.js +78 -0
  124. package/dist/core/src/assets/index.js +29 -0
  125. package/dist/core/src/assets/irradiance-generator.js +179 -0
  126. package/dist/core/src/assets/loader-audio.js +70 -0
  127. package/dist/core/src/assets/loader-cubemap.js +141 -0
  128. package/dist/core/src/assets/loader-dds.js +185 -0
  129. package/dist/core/src/assets/loader-hdr.js +430 -0
  130. package/dist/core/src/assets/loader-mesh.js +47 -0
  131. package/dist/core/src/assets/loader-shader.js +61 -0
  132. package/dist/core/src/assets/loader-texture.js +264 -0
  133. package/dist/core/src/assets/lod.js +150 -0
  134. package/dist/core/src/assets/manager.js +401 -0
  135. package/dist/core/src/assets/manifest.js +57 -0
  136. package/dist/core/src/assets/material-bridge.js +160 -0
  137. package/dist/core/src/assets/model-importer.js +32 -0
  138. package/dist/core/src/assets/model-normalizer.js +213 -0
  139. package/dist/core/src/assets/model-to-gpu.js +44 -0
  140. package/dist/core/src/assets/model-to-mesh.js +171 -0
  141. package/dist/core/src/assets/prefilter-generator.js +220 -0
  142. package/dist/core/src/audio/engine.js +153 -0
  143. package/dist/core/src/audio/interface.js +8 -0
  144. package/dist/core/src/audio/listener.js +19 -0
  145. package/dist/core/src/audio/mixer.js +124 -0
  146. package/dist/core/src/audio/registry.js +43 -0
  147. package/dist/core/src/audio/sab.js +74 -0
  148. package/dist/core/src/audio/source.js +60 -0
  149. package/dist/core/src/change-detection/atomics.js +1 -0
  150. package/dist/core/src/change-detection/tracker.js +26 -0
  151. package/dist/core/src/debug-draw/lines.js +27 -0
  152. package/dist/core/src/debug-draw/points.js +9 -0
  153. package/dist/core/src/debug-draw/queue.js +77 -0
  154. package/dist/core/src/debug-draw/text.js +12 -0
  155. package/dist/core/src/ecs/archetype.js +271 -0
  156. package/dist/core/src/ecs/component.js +109 -0
  157. package/dist/core/src/ecs/entity.js +11 -0
  158. package/dist/core/src/ecs/events.js +73 -0
  159. package/dist/core/src/ecs/hierarchy.js +104 -0
  160. package/dist/core/src/ecs/hmr-swap-registry.js +15 -0
  161. package/dist/core/src/ecs/index.js +14 -0
  162. package/dist/core/src/ecs/query.js +110 -0
  163. package/dist/core/src/ecs/resource.js +3 -0
  164. package/dist/core/src/ecs/schedule.js +157 -0
  165. package/dist/core/src/ecs/system-params.js +45 -0
  166. package/dist/core/src/ecs/system.js +18 -0
  167. package/dist/core/src/ecs/world.js +292 -0
  168. package/dist/core/src/index.js +191 -0
  169. package/dist/core/src/input/context.js +69 -0
  170. package/dist/core/src/input/dom-handler.js +288 -0
  171. package/dist/core/src/input/local-player-manager.js +145 -0
  172. package/dist/core/src/input/mapping.js +36 -0
  173. package/dist/core/src/input/multi-sab-bridge.js +224 -0
  174. package/dist/core/src/input/multi-state.js +48 -0
  175. package/dist/core/src/input/sab-bridge.js +66 -0
  176. package/dist/core/src/input/state.js +108 -0
  177. package/dist/core/src/input/ui-router.js +76 -0
  178. package/dist/core/src/library/host.js +291 -0
  179. package/dist/core/src/library/index.js +1 -0
  180. package/dist/core/src/library/library.js +20 -0
  181. package/dist/core/src/material/compiler.js +73 -0
  182. package/dist/core/src/material/graph-bridge.js +119 -0
  183. package/dist/core/src/material/index.js +6 -0
  184. package/dist/core/src/material/library.js +414 -0
  185. package/dist/core/src/material/material.js +120 -0
  186. package/dist/core/src/material/variants.js +37 -0
  187. package/dist/core/src/math/mat4.js +198 -0
  188. package/dist/core/src/math/perlin-noise-2d.js +66 -0
  189. package/dist/core/src/math/perlin-noise-3d.js +76 -0
  190. package/dist/core/src/math/quat.js +29 -0
  191. package/dist/core/src/math/rng.js +25 -0
  192. package/dist/core/src/math/trig.js +42 -0
  193. package/dist/core/src/math/value-noise.js +49 -0
  194. package/dist/core/src/mesh/builder.js +137 -0
  195. package/dist/core/src/mesh/csg.js +250 -0
  196. package/dist/core/src/mesh/greased-line.js +102 -0
  197. package/dist/core/src/mesh/mesh.js +6 -0
  198. package/dist/core/src/mesh/parametric.js +392 -0
  199. package/dist/core/src/mesh/skinning.js +30 -0
  200. package/dist/core/src/mesh/vertex-layout.js +65 -0
  201. package/dist/core/src/module/cross-thread.js +126 -0
  202. package/dist/core/src/module/diagnostics.js +99 -0
  203. package/dist/core/src/module/host.js +449 -0
  204. package/dist/core/src/module/index.js +6 -0
  205. package/dist/core/src/module/module.js +1 -0
  206. package/dist/core/src/module/registry.js +83 -0
  207. package/dist/core/src/module/renderer-module.js +13 -0
  208. package/dist/core/src/module/ts-loader.js +20 -0
  209. package/dist/core/src/particles/compute-pass.js +329 -0
  210. package/dist/core/src/particles/emitter.js +113 -0
  211. package/dist/core/src/particles/index.js +7 -0
  212. package/dist/core/src/particles/particle-data.js +33 -0
  213. package/dist/core/src/particles/render-pass.js +338 -0
  214. package/dist/core/src/particles/simulator.js +224 -0
  215. package/dist/core/src/particles/system.js +157 -0
  216. package/dist/core/src/physics/body.js +25 -0
  217. package/dist/core/src/physics/ccd-heuristic.js +46 -0
  218. package/dist/core/src/physics/character.js +184 -0
  219. package/dist/core/src/physics/collider.js +36 -0
  220. package/dist/core/src/physics/collision-system.js +62 -0
  221. package/dist/core/src/physics/events.js +74 -0
  222. package/dist/core/src/physics/index.js +24 -0
  223. package/dist/core/src/physics/interface.js +14 -0
  224. package/dist/core/src/physics/interpolation-buffer.js +182 -0
  225. package/dist/core/src/physics/lifecycle.js +66 -0
  226. package/dist/core/src/physics/load-shedder.js +155 -0
  227. package/dist/core/src/physics/physics-accumulator.js +94 -0
  228. package/dist/core/src/physics/physics-system.js +142 -0
  229. package/dist/core/src/physics/ragdoll-presets.js +248 -0
  230. package/dist/core/src/physics/ragdoll-system.js +193 -0
  231. package/dist/core/src/physics/ragdoll.js +117 -0
  232. package/dist/core/src/physics/raycast.js +97 -0
  233. package/dist/core/src/physics/realm-manager.js +431 -0
  234. package/dist/core/src/physics/realm-worker-pool.js +181 -0
  235. package/dist/core/src/physics/realm-worker.js +91 -0
  236. package/dist/core/src/physics/realm.js +137 -0
  237. package/dist/core/src/physics/registry.js +43 -0
  238. package/dist/core/src/physics/safety.js +211 -0
  239. package/dist/core/src/physics/snapshot-manager.js +118 -0
  240. package/dist/core/src/physics/worker-protocol.js +1 -0
  241. package/dist/core/src/platform/bun-preload.js +175 -0
  242. package/dist/core/src/platform/css-stub.js +4 -0
  243. package/dist/core/src/platform/glob-polyfill.js +137 -0
  244. package/dist/core/src/platform/hidpi.js +52 -0
  245. package/dist/core/src/platform/pkg-root.js +27 -0
  246. package/dist/core/src/platform/render-surface.js +15 -0
  247. package/dist/core/src/platform/rpc.js +82 -0
  248. package/dist/core/src/platform/runtime.js +93 -0
  249. package/dist/core/src/plugin/context.js +144 -0
  250. package/dist/core/src/plugin/diagnostics.js +20 -0
  251. package/dist/core/src/plugin/discovery.js +124 -0
  252. package/dist/core/src/plugin/extension-loaders.js +111 -0
  253. package/dist/core/src/plugin/host.js +542 -0
  254. package/dist/core/src/plugin/index.js +19 -0
  255. package/dist/core/src/plugin/loader-asset.js +105 -0
  256. package/dist/core/src/plugin/loader-quickjs.js +67 -0
  257. package/dist/core/src/plugin/loader-wasm.js +385 -0
  258. package/dist/core/src/plugin/loader-worker.js +228 -0
  259. package/dist/core/src/plugin/manifest.js +424 -0
  260. package/dist/core/src/plugin/material-registry.js +44 -0
  261. package/dist/core/src/plugin/mcp-tools.js +147 -0
  262. package/dist/core/src/plugin/permissions.js +152 -0
  263. package/dist/core/src/plugin/quickjs-bridge.js +219 -0
  264. package/dist/core/src/plugin/registry.js +92 -0
  265. package/dist/core/src/plugin/sandbox-shim.js +79 -0
  266. package/dist/core/src/plugin/sandbox-worker.js +194 -0
  267. package/dist/core/src/plugin/wasm-abi.js +62 -0
  268. package/dist/core/src/plugin/wasm-worker.js +234 -0
  269. package/dist/core/src/plugin/workshop.js +131 -0
  270. package/dist/core/src/profiling/event-loop.js +164 -0
  271. package/dist/core/src/profiling/index.js +23 -0
  272. package/dist/core/src/profiling/iops/idb-patch.js +211 -0
  273. package/dist/core/src/profiling/iops/opfs-patch.js +206 -0
  274. package/dist/core/src/profiling/profiling-sab.js +632 -0
  275. package/dist/core/src/profiling/task-latency.js +118 -0
  276. package/dist/core/src/profiling/thread-metrics.js +103 -0
  277. package/dist/core/src/profiling/trace-event-writer.js +165 -0
  278. package/dist/core/src/profiling/warnings.js +304 -0
  279. package/dist/core/src/profiling/worker-prelude.js +281 -0
  280. package/dist/core/src/render/bind-group.js +33 -0
  281. package/dist/core/src/render/bindless/bindless-struct.js +39 -0
  282. package/dist/core/src/render/bindless/bindless.wgsl.js +163 -0
  283. package/dist/core/src/render/bindless/frame-bindings.js +142 -0
  284. package/dist/core/src/render/bindless/index.js +6 -0
  285. package/dist/core/src/render/bindless/material-manager.js +182 -0
  286. package/dist/core/src/render/bindless/texture-registry.js +498 -0
  287. package/dist/core/src/render/buffer.js +74 -0
  288. package/dist/core/src/render/camera-2d.js +151 -0
  289. package/dist/core/src/render/camera-controller.js +370 -0
  290. package/dist/core/src/render/camera.js +332 -0
  291. package/dist/core/src/render/canvas-resize-watcher.js +36 -0
  292. package/dist/core/src/render/compute-kernel.js +130 -0
  293. package/dist/core/src/render/constants.js +2 -0
  294. package/dist/core/src/render/device.js +91 -0
  295. package/dist/core/src/render/frame-graph.js +594 -0
  296. package/dist/core/src/render/frustum.js +152 -0
  297. package/dist/core/src/render/fullscreen-vs.js +24 -0
  298. package/dist/core/src/render/g-buffer.js +156 -0
  299. package/dist/core/src/render/game-renderer.js +1165 -0
  300. package/dist/core/src/render/gpu-driven/cull-pass.js +352 -0
  301. package/dist/core/src/render/gpu-driven/hzb.js +183 -0
  302. package/dist/core/src/render/gpu-driven/index.js +6 -0
  303. package/dist/core/src/render/gpu-driven/indirect-draw-pass.js +300 -0
  304. package/dist/core/src/render/gpu-driven/instance-buffer.js +150 -0
  305. package/dist/core/src/render/gpu-driven/mesh-table.js +130 -0
  306. package/dist/core/src/render/gpu-driven/passes/hzb-build-pass.js +39 -0
  307. package/dist/core/src/render/gpu-utils.js +72 -0
  308. package/dist/core/src/render/hdr.js +69 -0
  309. package/dist/core/src/render/hot-reload.js +236 -0
  310. package/dist/core/src/render/ibl-bind-group.js +232 -0
  311. package/dist/core/src/render/ibl.js +148 -0
  312. package/dist/core/src/render/index.js +86 -0
  313. package/dist/core/src/render/input-manager.js +224 -0
  314. package/dist/core/src/render/lighting/area-light.js +142 -0
  315. package/dist/core/src/render/lighting/cluster-grid.js +255 -0
  316. package/dist/core/src/render/lighting/cluster-types.js +87 -0
  317. package/dist/core/src/render/lighting/ies-parser.js +111 -0
  318. package/dist/core/src/render/lighting.js +300 -0
  319. package/dist/core/src/render/material-types/depth.wgsl +44 -0
  320. package/dist/core/src/render/material-types/line.wgsl +50 -0
  321. package/dist/core/src/render/material-types/matcap.wgsl +51 -0
  322. package/dist/core/src/render/material-types/normal.wgsl +41 -0
  323. package/dist/core/src/render/material-types/physical.wgsl +152 -0
  324. package/dist/core/src/render/material-types/sprite.wgsl +46 -0
  325. package/dist/core/src/render/material-types/sss.wgsl +79 -0
  326. package/dist/core/src/render/material-types/toon.wgsl +79 -0
  327. package/dist/core/src/render/passes/README.md +121 -0
  328. package/dist/core/src/render/passes/atmosphere.js +107 -0
  329. package/dist/core/src/render/passes/cluster-lighting-pass.js +441 -0
  330. package/dist/core/src/render/passes/csm.js +338 -0
  331. package/dist/core/src/render/passes/cubemap-capture.js +93 -0
  332. package/dist/core/src/render/passes/debug-viz.js +248 -0
  333. package/dist/core/src/render/passes/debug.js +500 -0
  334. package/dist/core/src/render/passes/decal-mesh.js +86 -0
  335. package/dist/core/src/render/passes/decal-pass.js +344 -0
  336. package/dist/core/src/render/passes/deferred-lighting.js +406 -0
  337. package/dist/core/src/render/passes/depth-prepass.js +148 -0
  338. package/dist/core/src/render/passes/dome-360.js +68 -0
  339. package/dist/core/src/render/passes/fluid-render.js +116 -0
  340. package/dist/core/src/render/passes/gi-types.js +78 -0
  341. package/dist/core/src/render/passes/graph-compute.js +251 -0
  342. package/dist/core/src/render/passes/greased-line-pass.js +218 -0
  343. package/dist/core/src/render/passes/morph-target.js +35 -0
  344. package/dist/core/src/render/passes/opaque.js +966 -0
  345. package/dist/core/src/render/passes/point-light-shadow.js +221 -0
  346. package/dist/core/src/render/passes/procedural-texture.js +142 -0
  347. package/dist/core/src/render/passes/reflection-probe.js +100 -0
  348. package/dist/core/src/render/passes/rsm-pass.js +228 -0
  349. package/dist/core/src/render/passes/sdf-text.js +114 -0
  350. package/dist/core/src/render/passes/shadow-map.js +121 -0
  351. package/dist/core/src/render/passes/shadow.js +191 -0
  352. package/dist/core/src/render/passes/skinning-vs.js +102 -0
  353. package/dist/core/src/render/passes/skinning.js +282 -0
  354. package/dist/core/src/render/passes/sky-dome.js +380 -0
  355. package/dist/core/src/render/passes/skybox.js +146 -0
  356. package/dist/core/src/render/passes/spot-light-shadow.js +223 -0
  357. package/dist/core/src/render/passes/terrain.js +303 -0
  358. package/dist/core/src/render/passes/transparent.js +323 -0
  359. package/dist/core/src/render/passes/underwater-fog.js +173 -0
  360. package/dist/core/src/render/passes/video-texture.js +58 -0
  361. package/dist/core/src/render/passes/volumetric-pass.js +278 -0
  362. package/dist/core/src/render/passes/volumetric-types.js +96 -0
  363. package/dist/core/src/render/passes/water.js +697 -0
  364. package/dist/core/src/render/pbr.js +257 -0
  365. package/dist/core/src/render/pipeline.js +49 -0
  366. package/dist/core/src/render/render-pass.js +13 -0
  367. package/dist/core/src/render/renderer-input-bus.js +176 -0
  368. package/dist/core/src/render/renderer-module-host.js +539 -0
  369. package/dist/core/src/render/resource-tracker.js +59 -0
  370. package/dist/core/src/render/sab-canvas-overlay.js +83 -0
  371. package/dist/core/src/render/shader-validator.js +172 -0
  372. package/dist/core/src/render/shaders/debug/debug-line.wgsl +27 -0
  373. package/dist/core/src/render/shaders/debug/debug-point.wgsl +30 -0
  374. package/dist/core/src/render/shaders/debug/debug-text.wgsl +42 -0
  375. package/dist/core/src/render/shaders/debug-viz/aabb.wgsl +20 -0
  376. package/dist/core/src/render/shaders/debug-viz/depth.wgsl +29 -0
  377. package/dist/core/src/render/shaders/debug-viz/lod.wgsl +38 -0
  378. package/dist/core/src/render/shaders/debug-viz/normals.wgsl +30 -0
  379. package/dist/core/src/render/shaders/debug-viz/overdraw.wgsl +21 -0
  380. package/dist/core/src/render/shaders/debug-viz/tangents.wgsl +29 -0
  381. package/dist/core/src/render/shaders/debug-viz/wireframe.wgsl +33 -0
  382. package/dist/core/src/render/shaders/shadow-chunks.js +133 -0
  383. package/dist/core/src/render/skybox.js +123 -0
  384. package/dist/core/src/render/splitscreen.js +60 -0
  385. package/dist/core/src/render/surface.js +63 -0
  386. package/dist/core/src/render/tonemap.js +171 -0
  387. package/dist/core/src/render/tracked-render-pass.js +115 -0
  388. package/dist/core/src/render/viewport.js +81 -0
  389. package/dist/core/src/render/wgsl-hmr.js +66 -0
  390. package/dist/core/src/sab/core-input-channel.js +22 -0
  391. package/dist/core/src/sab/define.js +127 -0
  392. package/dist/core/src/sab/errors.js +60 -0
  393. package/dist/core/src/sab/game-input.js +299 -0
  394. package/dist/core/src/sab/gamepad-devices.js +205 -0
  395. package/dist/core/src/sab/grid-buffer.js +91 -0
  396. package/dist/core/src/sab/input.js +38 -0
  397. package/dist/core/src/sab/layout.js +160 -0
  398. package/dist/core/src/sab/multi-input-channel.js +39 -0
  399. package/dist/core/src/sab/record-buffer.js +130 -0
  400. package/dist/core/src/sab/sab-polyfill.js +47 -0
  401. package/dist/core/src/sab/sim-channel.js +397 -0
  402. package/dist/core/src/sab/slot-buffer.js +140 -0
  403. package/dist/core/src/sab/types.js +1 -0
  404. package/dist/core/src/safety/bounds.js +71 -0
  405. package/dist/core/src/safety/json.js +70 -0
  406. package/dist/core/src/safety/path.js +151 -0
  407. package/dist/core/src/save/binary-format.js +95 -0
  408. package/dist/core/src/save/game-save-system.js +101 -0
  409. package/dist/core/src/save/grid-save-system.js +102 -0
  410. package/dist/core/src/save/migrate.js +35 -0
  411. package/dist/core/src/save/migration-registry.js +66 -0
  412. package/dist/core/src/save/persist-types.js +4 -0
  413. package/dist/core/src/save/schema.js +36 -0
  414. package/dist/core/src/save/serializer.js +139 -0
  415. package/dist/core/src/scene/builder.js +31 -0
  416. package/dist/core/src/scene/camera.js +118 -0
  417. package/dist/core/src/scene/checkpoint.js +84 -0
  418. package/dist/core/src/scene/game-loop.js +155 -0
  419. package/dist/core/src/scene/index.js +14 -0
  420. package/dist/core/src/scene/layer.js +7 -0
  421. package/dist/core/src/scene/prefab.js +97 -0
  422. package/dist/core/src/scene/scene-manager.js +141 -0
  423. package/dist/core/src/scene/scene.js +147 -0
  424. package/dist/core/src/scene/sky.js +179 -0
  425. package/dist/core/src/scene/spatial-grid.js +140 -0
  426. package/dist/core/src/scene/streaming.js +247 -0
  427. package/dist/core/src/scene/vegetation.js +107 -0
  428. package/dist/core/src/scene/world.js +66 -0
  429. package/dist/core/src/scripting/binding.js +85 -0
  430. package/dist/core/src/scripting/hot-reload.js +123 -0
  431. package/dist/core/src/scripting/script.js +68 -0
  432. package/dist/core/src/sim/hot-reload-pipeline.js +65 -0
  433. package/dist/core/src/sim/sim-state-helper.js +40 -0
  434. package/dist/core/src/sim/transient-state-registry.js +63 -0
  435. package/dist/core/src/sim/types.js +4 -0
  436. package/dist/core/src/sim/worker-loop.js +168 -0
  437. package/dist/core/src/stores/game-store.js +81 -0
  438. package/dist/core/src/stores/hot-reload-store.js +19 -0
  439. package/dist/core/src/telemetry/collector.js +303 -0
  440. package/dist/core/src/telemetry/gc-controller.js +365 -0
  441. package/dist/core/src/telemetry/gc-profiler.js +82 -0
  442. package/dist/core/src/telemetry/gc-tracker.js +63 -0
  443. package/dist/core/src/telemetry/gpu-profiler.js +554 -0
  444. package/dist/core/src/telemetry/gpu-resource-tracker.js +234 -0
  445. package/dist/core/src/telemetry/gpu-timer-pool.js +223 -0
  446. package/dist/core/src/telemetry/gpu-timer.js +117 -0
  447. package/dist/core/src/telemetry/gpu-timestamp-gate.js +22 -0
  448. package/dist/core/src/telemetry/reporter.js +56 -0
  449. package/dist/core/src/types/engine-types.js +21 -0
  450. package/dist/core/src/ui-font-scale.js +111 -0
  451. package/dist/core/src/util/broad-phase-grid.js +77 -0
  452. package/dist/core/src/util/feature-log.js +176 -0
  453. package/dist/core/src/util/index.js +4 -0
  454. package/dist/core/src/util/logger.js +596 -0
  455. package/dist/core/src/version.js +11 -0
  456. package/dist/core/src/webgpu-destroy-augmentation.d.ts +25 -0
  457. package/dist/core/src/worker/base-worker-host.js +212 -0
  458. package/dist/core/src/worker/buffer-sync.js +454 -0
  459. package/dist/core/src/worker/crash-recovery.js +153 -0
  460. package/dist/core/src/worker/entity-sim-worker-host.js +128 -0
  461. package/dist/core/src/worker/instrumented-worker-host.js +139 -0
  462. package/dist/core/src/worker/rpc.js +244 -0
  463. package/dist/core/src/worker/sim-worker-base.js +558 -0
  464. package/dist/core/src/worker/sim-worker-host.js +271 -0
  465. package/dist/core/src/worker/task-pool.js +205 -0
  466. package/dist/core/src/worker/task-worker.js +77 -0
  467. package/dist/libraries/asset-browser/src/index.js +10 -0
  468. package/dist/libraries/asset-browser/src/software-thumbnails.js +940 -0
  469. package/dist/libraries/audio-kira/src/backend.js +405 -0
  470. package/dist/libraries/audio-kira/src/index.js +4 -0
  471. package/dist/libraries/audio-kira/src/library.js +54 -0
  472. package/dist/libraries/blitz-ui/src/index.js +13 -0
  473. package/dist/libraries/blitz-ui/src/native-module.js +162 -0
  474. package/dist/libraries/blitz-ui/src/native-osr-ffi.js +409 -0
  475. package/dist/libraries/blitz-ui/src/router.js +82 -0
  476. package/dist/libraries/blitz-ui/src/shaders/ui-blit.wgsl.js +32 -0
  477. package/dist/libraries/blitz-ui/src/ui-blit-pass.js +108 -0
  478. package/dist/libraries/character/src/character-animator.js +323 -0
  479. package/dist/libraries/character/src/customization.js +464 -0
  480. package/dist/libraries/character/src/index.js +19 -0
  481. package/dist/libraries/character/src/inspectable.js +77 -0
  482. package/dist/libraries/character/src/loader.js +336 -0
  483. package/dist/libraries/character/src/locomotion.js +84 -0
  484. package/dist/libraries/character/src/preview.js +280 -0
  485. package/dist/libraries/devtools/src/backend.js +449 -0
  486. package/dist/libraries/devtools/src/cdp-bridge.js +293 -0
  487. package/dist/libraries/devtools/src/collectors.js +318 -0
  488. package/dist/libraries/devtools/src/index.js +31 -0
  489. package/dist/libraries/devtools/src/native-providers.js +749 -0
  490. package/dist/libraries/devtools/src/snapshot.js +35 -0
  491. package/dist/libraries/devtools/src/verify.js +139 -0
  492. package/dist/libraries/devtools/src/web/browser.js +94 -0
  493. package/dist/libraries/devtools/src/web/host.js +183 -0
  494. package/dist/libraries/devtools/src/web/mirror.js +26 -0
  495. package/dist/libraries/devtools/src/web/server.js +187 -0
  496. package/dist/libraries/entities/src/index.js +3 -0
  497. package/dist/libraries/entities/src/library.js +46 -0
  498. package/dist/libraries/entities/src/model-renderer.js +1307 -0
  499. package/dist/libraries/entities/src/shaders/model.wgsl +375 -0
  500. package/dist/libraries/gamepad/src/feed-input.js +54 -0
  501. package/dist/libraries/gamepad/src/filters.js +44 -0
  502. package/dist/libraries/gamepad/src/glyphs.js +83 -0
  503. package/dist/libraries/gamepad/src/hub.js +164 -0
  504. package/dist/libraries/gamepad/src/index.js +10 -0
  505. package/dist/libraries/gamepad/src/library.js +56 -0
  506. package/dist/libraries/gamepad/src/source-sab.js +62 -0
  507. package/dist/libraries/gamepad/src/sysfs-enrich.js +125 -0
  508. package/dist/libraries/gaussian-splats/src/gpu-sort.js +506 -0
  509. package/dist/libraries/gaussian-splats/src/index.js +8 -0
  510. package/dist/libraries/gaussian-splats/src/library.js +44 -0
  511. package/dist/libraries/gaussian-splats/src/parser.js +297 -0
  512. package/dist/libraries/gaussian-splats/src/renderer.js +368 -0
  513. package/dist/libraries/gaussian-splats/src/sh-eval.js +196 -0
  514. package/dist/libraries/gaussian-splats/src/sorter.js +76 -0
  515. package/dist/libraries/gaussian-splats/src/tile-raster.js +424 -0
  516. package/dist/libraries/gpu-kernels/src/index.js +8 -0
  517. package/dist/libraries/gpu-kernels/src/kernel.js +591 -0
  518. package/dist/libraries/gpu-kernels/src/transpile.js +896 -0
  519. package/dist/libraries/html-ui-kit/src/behaviors.js +231 -0
  520. package/dist/libraries/html-ui-kit/src/components.js +219 -0
  521. package/dist/libraries/html-ui-kit/src/index.js +17 -0
  522. package/dist/libraries/html-ui-kit/src/nav/nav-controller.js +215 -0
  523. package/dist/libraries/html-ui-kit/src/nav/nav-input.js +138 -0
  524. package/dist/libraries/html-ui-kit/src/nav/osk.js +135 -0
  525. package/dist/libraries/html-ui-kit/src/nav/router.js +152 -0
  526. package/dist/libraries/html-ui-kit/src/nav/vcursor.js +177 -0
  527. package/dist/libraries/html-ui-kit/src/ten-foot.js +138 -0
  528. package/dist/libraries/html-ui-kit/src/theme.js +235 -0
  529. package/dist/libraries/inspectable/src/index.js +6 -0
  530. package/dist/libraries/inspectable/src/inspectable.js +205 -0
  531. package/dist/libraries/lighting/src/index.js +4 -0
  532. package/dist/libraries/lighting/src/library.js +48 -0
  533. package/dist/libraries/lighting/src/light-system.js +395 -0
  534. package/dist/libraries/lighting/src/lighting-system.js +57 -0
  535. package/dist/libraries/lighting/src/shaders/light-debug.wgsl +30 -0
  536. package/dist/libraries/marching-cubes/src/chunked-field.js +130 -0
  537. package/dist/libraries/marching-cubes/src/deformation.js +41 -0
  538. package/dist/libraries/marching-cubes/src/generator.js +356 -0
  539. package/dist/libraries/marching-cubes/src/index.js +13 -0
  540. package/dist/libraries/marching-cubes/src/library.js +54 -0
  541. package/dist/libraries/marching-cubes/src/lod.js +95 -0
  542. package/dist/libraries/marching-cubes/src/marching-tetrahedra.js +261 -0
  543. package/dist/libraries/marching-cubes/src/sab.js +40 -0
  544. package/dist/libraries/marching-cubes/src/streaming-config.js +28 -0
  545. package/dist/libraries/marching-cubes/src/streaming-manager.js +490 -0
  546. package/dist/libraries/marching-cubes/src/tables.js +314 -0
  547. package/dist/libraries/marching-cubes/src/types.js +1 -0
  548. package/dist/libraries/models/src/bake-node-transforms.js +146 -0
  549. package/dist/libraries/models/src/bind-unskinned-meshes.js +145 -0
  550. package/dist/libraries/models/src/codecs/basisu-codec.js +134 -0
  551. package/dist/libraries/models/src/codecs/draco-codec.js +236 -0
  552. package/dist/libraries/models/src/codecs/draco3dgltf.d.ts +40 -0
  553. package/dist/libraries/models/src/codecs/index.js +5 -0
  554. package/dist/libraries/models/src/codecs/meshopt-codec.js +59 -0
  555. package/dist/libraries/models/src/codecs/registry.js +111 -0
  556. package/dist/libraries/models/src/dae.js +665 -0
  557. package/dist/libraries/models/src/default-part-selection.js +58 -0
  558. package/dist/libraries/models/src/dxf.js +235 -0
  559. package/dist/libraries/models/src/fbx/index.js +438 -0
  560. package/dist/libraries/models/src/fbx/interpreter/animation.js +369 -0
  561. package/dist/libraries/models/src/fbx/interpreter/blend-shapes.js +283 -0
  562. package/dist/libraries/models/src/fbx/interpreter/connections.js +158 -0
  563. package/dist/libraries/models/src/fbx/interpreter/diagnostics.js +48 -0
  564. package/dist/libraries/models/src/fbx/interpreter/geometry.js +430 -0
  565. package/dist/libraries/models/src/fbx/interpreter/global-settings.js +77 -0
  566. package/dist/libraries/models/src/fbx/interpreter/materials.js +231 -0
  567. package/dist/libraries/models/src/fbx/interpreter/nodes.js +168 -0
  568. package/dist/libraries/models/src/fbx/interpreter/skeleton.js +454 -0
  569. package/dist/libraries/models/src/fbx/parsers/binary-parser.js +217 -0
  570. package/dist/libraries/models/src/fbx/types.js +88 -0
  571. package/dist/libraries/models/src/gltf-extensions.js +121 -0
  572. package/dist/libraries/models/src/gltf.js +724 -0
  573. package/dist/libraries/models/src/index.js +46 -0
  574. package/dist/libraries/models/src/library.js +44 -0
  575. package/dist/libraries/models/src/loader.js +218 -0
  576. package/dist/libraries/models/src/material-adapter.js +82 -0
  577. package/dist/libraries/models/src/mini-xml.js +145 -0
  578. package/dist/libraries/models/src/normalize.js +168 -0
  579. package/dist/libraries/models/src/obj.js +247 -0
  580. package/dist/libraries/models/src/off.js +94 -0
  581. package/dist/libraries/models/src/ply.js +329 -0
  582. package/dist/libraries/models/src/pose-sampler.js +183 -0
  583. package/dist/libraries/models/src/sidecar/blender-extras.js +32 -0
  584. package/dist/libraries/models/src/sidecar/ddmeta.js +98 -0
  585. package/dist/libraries/models/src/sidecar/godot-import.js +76 -0
  586. package/dist/libraries/models/src/sidecar/resolver.js +112 -0
  587. package/dist/libraries/models/src/sidecar/types.js +8 -0
  588. package/dist/libraries/models/src/sidecar/unity-meta.js +46 -0
  589. package/dist/libraries/models/src/skeleton-synthesis.js +122 -0
  590. package/dist/libraries/models/src/stl.js +129 -0
  591. package/dist/libraries/models/src/threeds.js +312 -0
  592. package/dist/libraries/models/src/threemf.js +203 -0
  593. package/dist/libraries/models/src/types.js +33 -0
  594. package/dist/libraries/models/src/vtk.js +242 -0
  595. package/dist/libraries/navmesh/src/crowd-system.js +207 -0
  596. package/dist/libraries/navmesh/src/debug-viz.js +52 -0
  597. package/dist/libraries/navmesh/src/index.js +7 -0
  598. package/dist/libraries/navmesh/src/library.js +47 -0
  599. package/dist/libraries/navmesh/src/navmesh-generator.js +364 -0
  600. package/dist/libraries/navmesh/src/navmesh.js +141 -0
  601. package/dist/libraries/navmesh/src/pathfinder.js +221 -0
  602. package/dist/libraries/navmesh/src/types.js +1 -0
  603. package/dist/libraries/networking/src/authority.js +107 -0
  604. package/dist/libraries/networking/src/connection.js +107 -0
  605. package/dist/libraries/networking/src/discovery.js +314 -0
  606. package/dist/libraries/networking/src/enhanced-replication.js +282 -0
  607. package/dist/libraries/networking/src/epic-adapter.js +101 -0
  608. package/dist/libraries/networking/src/index.js +16 -0
  609. package/dist/libraries/networking/src/library.js +45 -0
  610. package/dist/libraries/networking/src/lobby.js +84 -0
  611. package/dist/libraries/networking/src/platform-adapter.js +92 -0
  612. package/dist/libraries/networking/src/rcs-adapter.js +100 -0
  613. package/dist/libraries/networking/src/remote-input.js +162 -0
  614. package/dist/libraries/networking/src/replication.js +273 -0
  615. package/dist/libraries/networking/src/rpc.js +172 -0
  616. package/dist/libraries/networking/src/session.js +129 -0
  617. package/dist/libraries/networking/src/transport.js +156 -0
  618. package/dist/libraries/networking/src/webrtc.js +266 -0
  619. package/dist/libraries/pathfinding-2d/src/astar-grid.js +255 -0
  620. package/dist/libraries/pathfinding-2d/src/index.js +9 -0
  621. package/dist/libraries/persistence/src/autosave-manager.js +94 -0
  622. package/dist/libraries/persistence/src/binary-record-store.js +205 -0
  623. package/dist/libraries/persistence/src/browser.js +16 -0
  624. package/dist/libraries/persistence/src/file-save-store.js +507 -0
  625. package/dist/libraries/persistence/src/hash-utils.js +54 -0
  626. package/dist/libraries/persistence/src/index.js +17 -0
  627. package/dist/libraries/persistence/src/library.js +51 -0
  628. package/dist/libraries/persistence/src/mock-opfs.js +114 -0
  629. package/dist/libraries/persistence/src/node-fs-directory-handle.js +168 -0
  630. package/dist/libraries/persistence/src/opfs-save-store.js +584 -0
  631. package/dist/libraries/persistence/src/save-worker-proxy.js +96 -0
  632. package/dist/libraries/persistence/src/save-worker.js +76 -0
  633. package/dist/libraries/persistence/src/xxh3-ts.d.ts +10 -0
  634. package/dist/libraries/physics-native/src/backend.js +960 -0
  635. package/dist/libraries/physics-native/src/broadphase.js +79 -0
  636. package/dist/libraries/physics-native/src/index.js +6 -0
  637. package/dist/libraries/physics-native/src/library.js +57 -0
  638. package/dist/libraries/physics-native/src/narrowphase-shapes.js +348 -0
  639. package/dist/libraries/physics-native/src/narrowphase.js +60 -0
  640. package/dist/libraries/physics-native/src/solver.js +105 -0
  641. package/dist/libraries/physics-native/src/types.js +4 -0
  642. package/dist/libraries/physics-rapier/src/api.js +352 -0
  643. package/dist/libraries/physics-rapier/src/auto-backend.js +54 -0
  644. package/dist/libraries/physics-rapier/src/backend.js +1066 -0
  645. package/dist/libraries/physics-rapier/src/bulk-ops.js +46 -0
  646. package/dist/libraries/physics-rapier/src/ffi-backend.js +17 -0
  647. package/dist/libraries/physics-rapier/src/ffi-lib.js +605 -0
  648. package/dist/libraries/physics-rapier/src/index.js +9 -0
  649. package/dist/libraries/physics-rapier/src/library.js +71 -0
  650. package/dist/libraries/physics-rapier/src/rapier-backend.js +1102 -0
  651. package/dist/libraries/physics-rapier/src/realm-worker-script.js +233 -0
  652. package/dist/libraries/postfx/src/index.js +14 -0
  653. package/dist/libraries/postfx/src/library.js +207 -0
  654. package/dist/libraries/postfx/src/post-process-stack.js +1641 -0
  655. package/dist/libraries/postfx/src/shaders/post-process/afterimage.wgsl +14 -0
  656. package/dist/libraries/postfx/src/shaders/post-process/ascii.wgsl +24 -0
  657. package/dist/libraries/postfx/src/shaders/post-process/blit.wgsl +12 -0
  658. package/dist/libraries/postfx/src/shaders/post-process/bloom-blur.wgsl +21 -0
  659. package/dist/libraries/postfx/src/shaders/post-process/bloom-bright.wgsl +15 -0
  660. package/dist/libraries/postfx/src/shaders/post-process/bloom-composite.wgsl +14 -0
  661. package/dist/libraries/postfx/src/shaders/post-process/bloom-downsample.wgsl +60 -0
  662. package/dist/libraries/postfx/src/shaders/post-process/bloom-soft.wgsl +46 -0
  663. package/dist/libraries/postfx/src/shaders/post-process/bloom-upsample.wgsl +51 -0
  664. package/dist/libraries/postfx/src/shaders/post-process/channel-mixer.wgsl +36 -0
  665. package/dist/libraries/postfx/src/shaders/post-process/chromatic-aberration.wgsl +37 -0
  666. package/dist/libraries/postfx/src/shaders/post-process/dithering.wgsl +64 -0
  667. package/dist/libraries/postfx/src/shaders/post-process/dof.wgsl +131 -0
  668. package/dist/libraries/postfx/src/shaders/post-process/edges.wgsl +45 -0
  669. package/dist/libraries/postfx/src/shaders/post-process/fullscreen-vs.wgsl +15 -0
  670. package/dist/libraries/postfx/src/shaders/post-process/fxaa.wgsl +102 -0
  671. package/dist/libraries/postfx/src/shaders/post-process/gaussian-blur.wgsl +37 -0
  672. package/dist/libraries/postfx/src/shaders/post-process/glow-blur.wgsl +33 -0
  673. package/dist/libraries/postfx/src/shaders/post-process/glow-composite.wgsl +25 -0
  674. package/dist/libraries/postfx/src/shaders/post-process/grain.wgsl +37 -0
  675. package/dist/libraries/postfx/src/shaders/post-process/halftone.wgsl +80 -0
  676. package/dist/libraries/postfx/src/shaders/post-process/highlight-blur.wgsl +33 -0
  677. package/dist/libraries/postfx/src/shaders/post-process/highlight-composite.wgsl +32 -0
  678. package/dist/libraries/postfx/src/shaders/post-process/lens-distortion.wgsl +43 -0
  679. package/dist/libraries/postfx/src/shaders/post-process/lens-flare.wgsl +68 -0
  680. package/dist/libraries/postfx/src/shaders/post-process/lut.wgsl +30 -0
  681. package/dist/libraries/postfx/src/shaders/post-process/motion-blur.wgsl +55 -0
  682. package/dist/libraries/postfx/src/shaders/post-process/occluder-chunk.wgsl +28 -0
  683. package/dist/libraries/postfx/src/shaders/post-process/outline.wgsl +51 -0
  684. package/dist/libraries/postfx/src/shaders/post-process/pixelation.wgsl +47 -0
  685. package/dist/libraries/postfx/src/shaders/post-process/sharpen.wgsl +32 -0
  686. package/dist/libraries/postfx/src/shaders/post-process/sobel.wgsl +26 -0
  687. package/dist/libraries/postfx/src/shaders/post-process/split-tone.wgsl +36 -0
  688. package/dist/libraries/postfx/src/shaders/post-process/ssao-blur.wgsl +38 -0
  689. package/dist/libraries/postfx/src/shaders/post-process/ssao-composite.wgsl +25 -0
  690. package/dist/libraries/postfx/src/shaders/post-process/ssao.wgsl +147 -0
  691. package/dist/libraries/postfx/src/shaders/post-process/ssr.wgsl +155 -0
  692. package/dist/libraries/postfx/src/shaders/post-process/taa.wgsl +98 -0
  693. package/dist/libraries/postfx/src/shaders/post-process/tonemap.wgsl +40 -0
  694. package/dist/libraries/postfx/src/shaders/post-process/watercolor.wgsl +82 -0
  695. package/dist/libraries/postfx/src/shaders/post-process/white-balance.wgsl +41 -0
  696. package/dist/libraries/recast/src/backend.js +124 -0
  697. package/dist/libraries/recast/src/crowd-system.js +310 -0
  698. package/dist/libraries/recast/src/index.js +4 -0
  699. package/dist/libraries/recast/src/library.js +59 -0
  700. package/dist/libraries/recast/src/types.js +4 -0
  701. package/dist/libraries/sand/src/cell.js +32 -0
  702. package/dist/libraries/sand/src/fields.js +27 -0
  703. package/dist/libraries/sand/src/fluid-grid.js +267 -0
  704. package/dist/libraries/sand/src/grid-dims.js +47 -0
  705. package/dist/libraries/sand/src/grid-sim-buffer.js +184 -0
  706. package/dist/libraries/sand/src/index.js +20 -0
  707. package/dist/libraries/sand/src/library.js +67 -0
  708. package/dist/libraries/sand/src/materials.js +437 -0
  709. package/dist/libraries/sand/src/palette.js +87 -0
  710. package/dist/libraries/sand/src/particles.js +163 -0
  711. package/dist/libraries/sand/src/render/sand-grid-pass.js +377 -0
  712. package/dist/libraries/sand/src/rng.js +44 -0
  713. package/dist/libraries/sand/src/rules/builtin-rules.js +125 -0
  714. package/dist/libraries/sand/src/rules/rule-compiler.js +164 -0
  715. package/dist/libraries/sand/src/rules/rule-engine.js +210 -0
  716. package/dist/libraries/sand/src/rules/rule-types.js +27 -0
  717. package/dist/libraries/sand/src/sand-step-pool.js +458 -0
  718. package/dist/libraries/sand/src/sand-step-worker.js +101 -0
  719. package/dist/libraries/sand/src/sand-world.js +3382 -0
  720. package/dist/libraries/stickman/src/index.js +7 -0
  721. package/dist/libraries/stickman/src/library.js +44 -0
  722. package/dist/libraries/stickman/src/proportions.js +40 -0
  723. package/dist/libraries/stickman/src/shader.js +113 -0
  724. package/dist/libraries/stickman/src/skeleton.js +163 -0
  725. package/dist/libraries/stickman/src/stickman-pass.js +210 -0
  726. package/dist/libraries/stickman/src/thick-line.js +120 -0
  727. package/dist/libraries/surface-nets/src/chunked-field.js +5 -0
  728. package/dist/libraries/surface-nets/src/deformation.js +29 -0
  729. package/dist/libraries/surface-nets/src/index.js +15 -0
  730. package/dist/libraries/surface-nets/src/library.js +41 -0
  731. package/dist/libraries/surface-nets/src/lod.js +6 -0
  732. package/dist/libraries/surface-nets/src/sab.js +4 -0
  733. package/dist/libraries/surface-nets/src/streaming-config.js +4 -0
  734. package/dist/libraries/surface-nets/src/streaming-manager.js +9 -0
  735. package/dist/libraries/surface-nets/src/surface-nets.js +361 -0
  736. package/dist/libraries/surface-nets/src/types.js +1 -0
  737. package/dist/libraries/water/src/buoyancy.js +80 -0
  738. package/dist/libraries/water/src/index.js +12 -0
  739. package/dist/libraries/water/src/library.js +65 -0
  740. package/dist/libraries/water/src/shore-damping.js +70 -0
  741. package/dist/libraries/water/src/water-buffer.js +78 -0
  742. package/dist/libraries/water/src/water-chunks.js +5 -0
  743. package/dist/libraries/water/src/water-physics.js +315 -0
  744. package/dist/libraries/water/src/water-renderer.js +736 -0
  745. package/dist/libraries/water/src/water-sab.js +138 -0
  746. package/dist/libraries/water/src/wave-sources.js +45 -0
  747. package/dist/libraries/weather/src/index.js +5 -0
  748. package/dist/libraries/weather/src/library.js +48 -0
  749. package/dist/libraries/weather/src/types.js +29 -0
  750. package/dist/libraries/weather/src/weather-blend.js +108 -0
  751. package/dist/libraries/weather/src/weather-system.js +275 -0
  752. package/dist/libraries/weatherfx/src/cloud-provider.js +5 -0
  753. package/dist/libraries/weatherfx/src/cloud-system.js +294 -0
  754. package/dist/libraries/weatherfx/src/index.js +4 -0
  755. package/dist/libraries/weatherfx/src/library.js +41 -0
  756. package/dist/libraries/weatherfx/src/particle-system.js +350 -0
  757. package/dist/libraries/weatherfx/src/shaders/cloud.wgsl +111 -0
  758. package/dist/libraries/weatherfx/src/shaders/particle-compute.wgsl +187 -0
  759. package/dist/libraries/weatherfx/src/shaders/particle-render.wgsl +95 -0
  760. package/dist/mcp/src/client.js +669 -0
  761. package/dist/mcp/src/engine-context.js +99 -0
  762. package/dist/mcp/src/http-transport.js +423 -0
  763. package/dist/mcp/src/index.js +5 -0
  764. package/dist/mcp/src/prompts/add-entity.js +39 -0
  765. package/dist/mcp/src/prompts/create-scene.js +41 -0
  766. package/dist/mcp/src/prompts/debug-frame.js +36 -0
  767. package/dist/mcp/src/prompts/index.js +10 -0
  768. package/dist/mcp/src/resources/asset-list.js +28 -0
  769. package/dist/mcp/src/resources/checkpoint-list.js +29 -0
  770. package/dist/mcp/src/resources/entity-state.js +45 -0
  771. package/dist/mcp/src/resources/gpu-info.js +90 -0
  772. package/dist/mcp/src/resources/index.js +51 -0
  773. package/dist/mcp/src/resources/performance.js +33 -0
  774. package/dist/mcp/src/resources/scene-tree.js +37 -0
  775. package/dist/mcp/src/server.js +307 -0
  776. package/dist/mcp/src/tools/animation.js +102 -0
  777. package/dist/mcp/src/tools/asset.js +146 -0
  778. package/dist/mcp/src/tools/audio.js +80 -0
  779. package/dist/mcp/src/tools/build.js +128 -0
  780. package/dist/mcp/src/tools/camera.js +157 -0
  781. package/dist/mcp/src/tools/checkpoint.js +90 -0
  782. package/dist/mcp/src/tools/component.js +176 -0
  783. package/dist/mcp/src/tools/debug.js +273 -0
  784. package/dist/mcp/src/tools/entity.js +309 -0
  785. package/dist/mcp/src/tools/inspect.js +192 -0
  786. package/dist/mcp/src/tools/lighting.js +239 -0
  787. package/dist/mcp/src/tools/material.js +225 -0
  788. package/dist/mcp/src/tools/mesh.js +210 -0
  789. package/dist/mcp/src/tools/physics.js +251 -0
  790. package/dist/mcp/src/tools/scene.js +139 -0
  791. package/dist/mcp/src/tools/script.js +114 -0
  792. package/dist/mcp/src/types.js +9 -0
  793. package/dist/mcp/src/undo-redo.js +64 -0
  794. package/dist/modules/camera-controls/src/index.js +116 -0
  795. package/dist/modules/controller-ui/src/index.js +149 -0
  796. package/dist/modules/devtools/src/api.js +317 -0
  797. package/dist/modules/devtools/src/asset-utils.js +102 -0
  798. package/dist/modules/devtools/src/bind-debug-store.js +34 -0
  799. package/dist/modules/devtools/src/blitz/host.js +391 -0
  800. package/dist/modules/devtools/src/blitz/module.js +65 -0
  801. package/dist/modules/devtools/src/blitz/panels/console.js +217 -0
  802. package/dist/modules/devtools/src/blitz/panels/elements.js +79 -0
  803. package/dist/modules/devtools/src/blitz/panels/gpu.js +61 -0
  804. package/dist/modules/devtools/src/blitz/panels/performance.js +113 -0
  805. package/dist/modules/devtools/src/blitz/panels/snapshot.js +141 -0
  806. package/dist/modules/devtools/src/blitz/panels/types.js +55 -0
  807. package/dist/modules/devtools/src/blitz/theme.js +167 -0
  808. package/dist/modules/devtools/src/data-bridge.js +247 -0
  809. package/dist/modules/devtools/src/debug-overlay.js +181 -0
  810. package/dist/modules/devtools/src/debug-raycast.js +296 -0
  811. package/dist/modules/devtools/src/debug-store.js +28 -0
  812. package/dist/modules/devtools/src/debug-view-descriptors.js +24 -0
  813. package/dist/modules/devtools/src/doctor-panel.js +163 -0
  814. package/dist/modules/devtools/src/gizmo-module.js +95 -0
  815. package/dist/modules/devtools/src/graph-model.js +387 -0
  816. package/dist/modules/devtools/src/grid-renderer.js +145 -0
  817. package/dist/modules/devtools/src/height-ruler-renderer.js +189 -0
  818. package/dist/modules/devtools/src/index.js +46 -0
  819. package/dist/modules/devtools/src/init.js +204 -0
  820. package/dist/modules/devtools/src/label-overlay.js +129 -0
  821. package/dist/modules/devtools/src/material-stats-panel.js +171 -0
  822. package/dist/modules/devtools/src/profiling-bridge.js +288 -0
  823. package/dist/modules/devtools/src/profiling-hooks.js +63 -0
  824. package/dist/modules/devtools/src/renderer-adapter.js +61 -0
  825. package/dist/modules/devtools/src/scene-inspector.js +571 -0
  826. package/dist/modules/devtools/src/scene-store.js +212 -0
  827. package/dist/modules/devtools/src/scene-sync.js +92 -0
  828. package/dist/modules/devtools/src/shaders/transform-gizmo.wgsl +38 -0
  829. package/dist/modules/devtools/src/sim-stats-panel.js +250 -0
  830. package/dist/modules/devtools/src/sim-stats-provider.js +73 -0
  831. package/dist/modules/devtools/src/skeleton-renderer.js +326 -0
  832. package/dist/modules/devtools/src/transform-gizmo.js +677 -0
  833. package/dist/modules/devtools/src/types.js +5 -0
  834. package/dist/modules/devtools/src/worker-expose.js +59 -0
  835. package/dist/modules/devtools/src/worker-sync.js +115 -0
  836. package/dist/modules/editor/src/commands/component.js +151 -0
  837. package/dist/modules/editor/src/commands/entity.js +253 -0
  838. package/dist/modules/editor/src/commands/hierarchy.js +79 -0
  839. package/dist/modules/editor/src/commands/index.js +57 -0
  840. package/dist/modules/editor/src/commands/prefab.js +149 -0
  841. package/dist/modules/editor/src/commands/registry.js +246 -0
  842. package/dist/modules/editor/src/commands/scene-io.js +206 -0
  843. package/dist/modules/editor/src/commands/selection.js +71 -0
  844. package/dist/modules/editor/src/commands/transform.js +88 -0
  845. package/dist/modules/editor/src/ddscene.js +189 -0
  846. package/dist/modules/editor/src/document.js +96 -0
  847. package/dist/modules/editor/src/editor-context.js +115 -0
  848. package/dist/modules/editor/src/index.js +11 -0
  849. package/dist/modules/editor/src/mcp.js +91 -0
  850. package/dist/modules/editor/src/module.js +115 -0
  851. package/dist/modules/editor/src/selection.js +60 -0
  852. package/dist/modules/editor/src/shell.js +397 -0
  853. package/dist/modules/editor/src/viewport.js +186 -0
  854. package/dist/modules/html-ui/src/composite.js +116 -0
  855. package/dist/modules/html-ui/src/create-html-ui.js +137 -0
  856. package/dist/modules/html-ui/src/doc-backend.js +518 -0
  857. package/dist/modules/html-ui/src/host.js +819 -0
  858. package/dist/modules/html-ui/src/index.js +5 -0
  859. package/dist/modules/html-ui/src/jsx-dev-runtime.js +9 -0
  860. package/dist/modules/html-ui/src/jsx-runtime.js +121 -0
  861. package/dist/modules/html-ui/src/protocol.js +6 -0
  862. package/dist/modules/html-ui/src/ui-worker.js +10 -0
  863. package/dist/modules/mcp/src/index.js +62 -0
  864. package/dist/modules/movement-2d/src/grid-character.js +345 -0
  865. package/dist/modules/movement-2d/src/index.js +27 -0
  866. package/dist/modules/movement-3d/src/character-motor.js +166 -0
  867. package/dist/modules/movement-3d/src/index.js +27 -0
  868. package/dist/modules/native-osr/src/index.js +12 -0
  869. package/dist/modules/native-osr/src/input-router.js +335 -0
  870. package/dist/modules/native-osr/src/native-osr-manager.js +210 -0
  871. package/dist/modules/native-osr/src/native-texture-source.js +66 -0
  872. package/dist/modules/native-osr/src/types.js +8 -0
  873. package/dist/modules/native-osr/src/world-space-ui-pass.js +313 -0
  874. package/dist/modules/sailing/src/index.js +39 -0
  875. package/dist/modules/terrain/src/index.js +44 -0
  876. package/dist/modules/vitals/src/index.js +25 -0
  877. package/dist/modules/vitals/src/vitals.js +195 -0
  878. package/dist/modules/xr/src/camera-rig.js +119 -0
  879. package/dist/modules/xr/src/debug.js +45 -0
  880. package/dist/modules/xr/src/frame-loop.js +139 -0
  881. package/dist/modules/xr/src/index.js +10 -0
  882. package/dist/modules/xr/src/input.js +164 -0
  883. package/dist/modules/xr/src/layer.js +100 -0
  884. package/dist/modules/xr/src/session.js +133 -0
  885. package/dist/modules/xr/src/sim-module.js +21 -0
  886. package/dist/modules/xr/src/types.js +4 -0
  887. package/dist/modules/xr/src/webxr.d.ts +182 -0
  888. package/dist/modules/xr/src/xr-module.js +134 -0
  889. package/dist/shader-graph/src/chunks.js +340 -0
  890. package/dist/shader-graph/src/compiler.js +639 -0
  891. package/dist/shader-graph/src/compute-compiler.js +384 -0
  892. package/dist/shader-graph/src/compute-graph.js +55 -0
  893. package/dist/shader-graph/src/compute-profiles.js +39 -0
  894. package/dist/shader-graph/src/graph.js +38 -0
  895. package/dist/shader-graph/src/index.js +15 -0
  896. package/dist/shader-graph/src/profiles.js +305 -0
  897. package/dist/shader-graph/src/validator.js +42 -0
  898. package/dist/shader-graph/src/wgsl-binding-validator.js +110 -0
  899. package/dist/shader-graph/src/wgsl-struct-validator.js +222 -0
  900. package/dist/shader-graph/src/wgsl-struct.js +251 -0
  901. package/dist/test/src/index.js +1 -0
  902. package/dist/test/src/vision-test.js +228 -0
  903. package/libraries/asset-browser/src/software-thumbnails.ts +2 -2
  904. package/libraries/audio-kira/src/backend.ts +2 -1
  905. package/libraries/blitz-ui/native/src/shell.rs +35 -1
  906. package/libraries/blitz-ui/native-osr/Cargo.toml +8 -0
  907. package/libraries/blitz-ui/native-osr/src/lib.rs +213 -22
  908. package/libraries/blitz-ui/native-osr/src/mutate.rs +109 -14
  909. package/libraries/blitz-ui/src/native-osr-ffi.ts +71 -8
  910. package/libraries/blitz-ui/src/router.ts +3 -1
  911. package/libraries/blitz-ui/src/ui-blit-pass.ts +1 -1
  912. package/libraries/character/src/character-animator.ts +1 -1
  913. package/libraries/character/src/customization.ts +513 -0
  914. package/libraries/character/src/index.ts +6 -0
  915. package/libraries/character/src/inspectable.ts +111 -0
  916. package/libraries/character/src/loader.ts +38 -13
  917. package/libraries/character/src/locomotion.ts +13 -1
  918. package/libraries/character/src/preview.ts +94 -24
  919. package/libraries/devtools/README.md +16 -18
  920. package/libraries/devtools/src/backend.ts +505 -0
  921. package/libraries/devtools/src/cdp-bridge.ts +8 -8
  922. package/libraries/devtools/src/collectors.ts +41 -37
  923. package/libraries/devtools/src/index.ts +32 -14
  924. package/libraries/devtools/src/native-providers.ts +20 -12
  925. package/libraries/devtools/src/snapshot.ts +77 -0
  926. package/libraries/devtools/src/web/host.ts +11 -12
  927. package/libraries/devtools/src/web/mirror.ts +14 -405
  928. package/libraries/devtools/src/web/server.ts +4 -3
  929. package/libraries/entities/src/model-renderer.ts +96 -23
  930. package/libraries/gamepad/src/library.ts +2 -1
  931. package/libraries/inspectable/src/index.ts +11 -0
  932. package/libraries/inspectable/src/inspectable.ts +277 -0
  933. package/libraries/marching-cubes/src/streaming-manager.ts +4 -4
  934. package/libraries/models/src/bind-unskinned-meshes.ts +131 -0
  935. package/libraries/models/src/index.ts +1 -0
  936. package/libraries/models/src/types.ts +22 -0
  937. package/libraries/persistence/src/autosave-manager.ts +1 -1
  938. package/libraries/persistence/src/binary-record-store.ts +1 -1
  939. package/libraries/persistence/src/file-save-store.ts +4 -4
  940. package/libraries/persistence/src/library.ts +1 -1
  941. package/libraries/persistence/src/opfs-save-store.ts +5 -5
  942. package/libraries/persistence/src/save-worker.ts +13 -14
  943. package/libraries/physics-rapier/src/ffi-lib.ts +2 -1
  944. package/libraries/postfx/src/post-process-stack.ts +1 -1
  945. package/libraries/sand/src/sand-step-pool.ts +5 -0
  946. package/libraries/water/src/water-renderer.ts +1 -1
  947. package/libraries/weatherfx/src/cloud-system.ts +3 -3
  948. package/mcp/README.md +20 -0
  949. package/mcp/src/client.ts +75 -22
  950. package/mcp/src/undo-redo.ts +2 -2
  951. package/modules/devtools/src/blitz/host.ts +430 -0
  952. package/modules/devtools/src/blitz/module.ts +101 -0
  953. package/modules/devtools/src/blitz/panels/console.ts +223 -0
  954. package/modules/devtools/src/blitz/panels/elements.ts +92 -0
  955. package/modules/devtools/src/blitz/panels/gpu.ts +70 -0
  956. package/modules/devtools/src/blitz/panels/performance.ts +120 -0
  957. package/modules/devtools/src/blitz/panels/snapshot.ts +152 -0
  958. package/modules/devtools/src/blitz/panels/types.ts +120 -0
  959. package/modules/devtools/src/blitz/theme.ts +168 -0
  960. package/modules/devtools/src/data-bridge.ts +1 -1
  961. package/modules/devtools/src/index.ts +6 -0
  962. package/modules/devtools/src/profiling-bridge.ts +17 -13
  963. package/modules/devtools/src/profiling-hooks.ts +22 -13
  964. package/modules/devtools/src/scene-inspector.ts +1 -1
  965. package/modules/devtools/src/worker-sync.ts +9 -1
  966. package/modules/editor/src/commands/registry.ts +2 -2
  967. package/modules/editor/src/module.ts +1 -1
  968. package/modules/html-ui/src/composite.ts +1 -1
  969. package/modules/html-ui/src/create-html-ui.ts +21 -9
  970. package/modules/html-ui/src/doc-backend.ts +189 -10
  971. package/modules/html-ui/src/host.ts +354 -40
  972. package/modules/html-ui/src/index.ts +1 -1
  973. package/modules/html-ui/src/jsx-runtime.ts +1 -1
  974. package/modules/html-ui/src/protocol.ts +53 -6
  975. package/modules/mcp/README.md +6 -0
  976. package/modules/mcp/src/index.ts +70 -3
  977. package/modules/movement-3d/src/character-motor.ts +83 -10
  978. package/package.json +838 -165
  979. package/shader-graph/README.md +25 -0
  980. package/test/README.md +16 -0
  981. package/libraries/blitz-ui/native-osr-spike.ts +0 -70
  982. package/libraries/devtools/native/Cargo.toml +0 -12
  983. package/libraries/devtools/native/src/lib.rs +0 -1646
  984. package/libraries/devtools/native/src/panels/console.rs +0 -338
  985. package/libraries/devtools/native/src/panels/dom_tree.rs +0 -47
  986. package/libraries/devtools/native/src/panels/generic.rs +0 -317
  987. package/libraries/devtools/native/src/panels/gpu.rs +0 -107
  988. package/libraries/devtools/native/src/panels/input.rs +0 -88
  989. package/libraries/devtools/native/src/panels/mod.rs +0 -154
  990. package/libraries/devtools/native/src/panels/perf_metrics.rs +0 -91
  991. package/libraries/devtools/native/src/panels/perf_recorder.rs +0 -158
  992. package/libraries/devtools/native/src/panels/scene.rs +0 -72
  993. package/libraries/devtools/native/src/state.rs +0 -394
  994. package/libraries/devtools/src/egui-ffi.ts +0 -804
  995. package/libraries/devtools/src/egui-renderer.ts +0 -407
  996. package/libraries/devtools/src/host.ts +0 -363
  997. package/libraries/devtools/src/mirror.ts +0 -794
  998. package/libraries/models/test-fixtures/fbx/LICENSE-notice.txt +0 -24
  999. package/libraries/models/test-fixtures/fbx/README.md +0 -46
  1000. package/libraries/models/test-fixtures/fbx/m01_cube_phong.fbx +0 -0
  1001. package/libraries/models/test-fixtures/fbx/m02_geo_ngons.fbx +0 -0
  1002. package/libraries/models/test-fixtures/fbx/m03_normals.fbx +0 -0
  1003. package/libraries/models/test-fixtures/fbx/m04_material_properties.fbx +0 -0
  1004. package/libraries/models/test-fixtures/fbx/m05_external_diffuse.png +0 -0
  1005. package/libraries/models/test-fixtures/fbx/m05_textures.fbx +0 -0
  1006. package/libraries/models/test-fixtures/fbx/m06_uv_transform.fbx +0 -0
  1007. package/libraries/models/test-fixtures/fbx/m07_multimaterial.fbx +0 -0
  1008. package/libraries/models/test-fixtures/fbx/m08_transforms.fbx +0 -0
  1009. package/libraries/models/test-fixtures/fbx/m09_skinning.fbx +0 -0
  1010. package/libraries/models/test-fixtures/fbx/m10_morph.fbx +0 -0
  1011. package/libraries/models/test-fixtures/fbx/m11_node_anim.fbx +0 -0
  1012. package/libraries/models/test-fixtures/fbx/m12_skeletal_anim.fbx +0 -0
  1013. package/libraries/models/test-fixtures/fbx/m13_morph_anim.fbx +0 -0
  1014. package/libraries/models/test-fixtures/fbx/m14_multiclip.fbx +0 -0
  1015. package/libraries/models/test-fixtures/fbx/m15_camera_lights.fbx +0 -0
  1016. package/libraries/models/test-fixtures/fbx/m16_axis_yup.fbx +0 -0
  1017. package/libraries/models/test-fixtures/fbx/m16_axis_zup.fbx +0 -0
  1018. package/libraries/models/test-fixtures/fbx/m16_units_254.fbx +0 -0
  1019. package/libraries/physics-native/src/ffi-spike-worker.ts +0 -71
  1020. package/libraries/physics-rapier/bench/ffi-bench.ts +0 -79
  1021. package/libraries/physics-rapier/bench/wasm-baseline.ts +0 -90
@@ -0,0 +1,1361 @@
1
+ // ============================================================================
2
+ // Skeleton Animator — skeletal animation with crossfade blending, retargeting,
3
+ // procedural idle, and foot IK. Generic, game-agnostic.
4
+ // Uses AnimationPlayer internally for blending (bone masks, additive, root motion).
5
+ // ============================================================================
6
+ import { createLogger } from "../util/logger.js";
7
+ import { AnimationClip } from "./clip.js";
8
+ import { AnimationPlayer } from "./player.js";
9
+ import { Skeleton } from "./skeleton.js";
10
+ const log = createLogger();
11
+ // ── SkinData → SkeletonData conversion ──
12
+ export function skinDataToSkeletonData(skin) {
13
+ const bones = skin.bones.map((b) => ({
14
+ name: b.name,
15
+ parentIndex: b.parentIndex,
16
+ childrenIndices: [],
17
+ bindPosition: b.restTranslation,
18
+ bindRotation: b.restRotation,
19
+ bindScale: b.restScale,
20
+ inverseBindMatrix: b.inverseBindMatrix,
21
+ rootAncestorMatrix: b.rootAncestorMatrix,
22
+ }));
23
+ for (let i = 0; i < bones.length; i++) {
24
+ const parentIdx = bones[i].parentIndex;
25
+ if (parentIdx >= 0 && parentIdx < bones.length) {
26
+ bones[parentIdx].childrenIndices.push(i);
27
+ }
28
+ }
29
+ let rootBoneIndex = 0;
30
+ for (let i = 0; i < bones.length; i++) {
31
+ if (bones[i].parentIndex < 0) {
32
+ rootBoneIndex = i;
33
+ break;
34
+ }
35
+ }
36
+ return { bones, name: "skeleton", rootBoneIndex };
37
+ }
38
+ // ── Vec3 / Quaternion math helpers ──
39
+ const IDENTITY_QUAT = [0, 0, 0, 1];
40
+ function vec3Lerp(a, b, t, out) {
41
+ out[0] = a[0] + (b[0] - a[0]) * t;
42
+ out[1] = a[1] + (b[1] - a[1]) * t;
43
+ out[2] = a[2] + (b[2] - a[2]) * t;
44
+ }
45
+ function quatInvert(q, out) {
46
+ out[0] = -q[0];
47
+ out[1] = -q[1];
48
+ out[2] = -q[2];
49
+ out[3] = q[3];
50
+ }
51
+ function quatSlerp(a, b, t, out) {
52
+ let dot = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
53
+ if (dot < 0) {
54
+ out[0] = -b[0];
55
+ out[1] = -b[1];
56
+ out[2] = -b[2];
57
+ out[3] = -b[3];
58
+ dot = -dot;
59
+ }
60
+ else {
61
+ out[0] = b[0];
62
+ out[1] = b[1];
63
+ out[2] = b[2];
64
+ out[3] = b[3];
65
+ }
66
+ if (dot > 0.9995) {
67
+ out[0] = a[0] + (out[0] - a[0]) * t;
68
+ out[1] = a[1] + (out[1] - a[1]) * t;
69
+ out[2] = a[2] + (out[2] - a[2]) * t;
70
+ out[3] = a[3] + (out[3] - a[3]) * t;
71
+ const len = Math.sqrt(out[0] * out[0] + out[1] * out[1] + out[2] * out[2] + out[3] * out[3]);
72
+ if (len > 0) {
73
+ out[0] /= len;
74
+ out[1] /= len;
75
+ out[2] /= len;
76
+ out[3] /= len;
77
+ }
78
+ return;
79
+ }
80
+ const theta = Math.acos(dot);
81
+ const sinTheta = Math.sin(theta);
82
+ const sinT = Math.sin(t * theta) / sinTheta;
83
+ const oneMinusT = Math.sin((1 - t) * theta) / sinTheta;
84
+ out[0] = a[0] * oneMinusT + out[0] * sinT;
85
+ out[1] = a[1] * oneMinusT + out[1] * sinT;
86
+ out[2] = a[2] * oneMinusT + out[2] * sinT;
87
+ out[3] = a[3] * oneMinusT + out[3] * sinT;
88
+ }
89
+ function quatRotateVec(q, v) {
90
+ const x = q[0], y = q[1], z = q[2], w = q[3];
91
+ const c = 2 * (x * v[0] + y * v[1] + z * v[2]);
92
+ const ss = w * w - (x * x + y * y + z * z);
93
+ return [
94
+ c * x + ss * v[0] + 2 * w * (y * v[2] - z * v[1]),
95
+ c * y + ss * v[1] + 2 * w * (z * v[0] - x * v[2]),
96
+ c * z + ss * v[2] + 2 * w * (x * v[1] - y * v[0]),
97
+ ];
98
+ }
99
+ function quatMul(q1, q2, out) {
100
+ const ax = q1[0], ay = q1[1], az = q1[2], aw = q1[3];
101
+ const bx = q2[0], by = q2[1], bz = q2[2], bw = q2[3];
102
+ out[0] = aw * bx + ax * bw + ay * bz - az * by;
103
+ out[1] = aw * by - ax * bz + ay * bw + az * bx;
104
+ out[2] = aw * bz + ax * by - ay * bx + az * bw;
105
+ out[3] = aw * bw - ax * bx - ay * by - az * bz;
106
+ }
107
+ function buildLocalMatrix(pos, rot, scale, out) {
108
+ const x = rot[0], y = rot[1], z = rot[2], w = rot[3];
109
+ const x2 = x + x, y2 = y + y, z2 = z + z;
110
+ const xx = x * x2, xy = x * y2, xz = x * z2;
111
+ const yy = y * y2, yz = y * z2, zz = z * z2;
112
+ const wx = w * x2, wy = w * y2, wz = w * z2;
113
+ const sx = scale[0], sy = scale[1], sz = scale[2];
114
+ out[0] = (1 - (yy + zz)) * sx;
115
+ out[1] = (xy + wz) * sx;
116
+ out[2] = (xz - wy) * sx;
117
+ out[3] = 0;
118
+ out[4] = (xy - wz) * sy;
119
+ out[5] = (1 - (xx + zz)) * sy;
120
+ out[6] = (yz + wx) * sy;
121
+ out[7] = 0;
122
+ out[8] = (xz + wy) * sz;
123
+ out[9] = (yz - wx) * sz;
124
+ out[10] = (1 - (xx + yy)) * sz;
125
+ out[11] = 0;
126
+ out[12] = pos[0];
127
+ out[13] = pos[1];
128
+ out[14] = pos[2];
129
+ out[15] = 1;
130
+ }
131
+ /** Extract the rotation part of a column-major 4x4 matrix as a quaternion
132
+ * (column lengths are normalized out, so uniform scale is tolerated). */
133
+ function quatFromMat4Rotation(m) {
134
+ let m00 = m[0], m10 = m[1], m20 = m[2];
135
+ let m01 = m[4], m11 = m[5], m21 = m[6];
136
+ let m02 = m[8], m12 = m[9], m22 = m[10];
137
+ const n0 = Math.hypot(m00, m10, m20) || 1;
138
+ const n1 = Math.hypot(m01, m11, m21) || 1;
139
+ const n2 = Math.hypot(m02, m12, m22) || 1;
140
+ m00 /= n0;
141
+ m10 /= n0;
142
+ m20 /= n0;
143
+ m01 /= n1;
144
+ m11 /= n1;
145
+ m21 /= n1;
146
+ m02 /= n2;
147
+ m12 /= n2;
148
+ m22 /= n2;
149
+ const trace = m00 + m11 + m22;
150
+ const q = new Float32Array(4);
151
+ if (trace > 0) {
152
+ const s = Math.sqrt(trace + 1) * 2;
153
+ q[3] = s / 4;
154
+ q[0] = (m21 - m12) / s;
155
+ q[1] = (m02 - m20) / s;
156
+ q[2] = (m10 - m01) / s;
157
+ }
158
+ else if (m00 > m11 && m00 > m22) {
159
+ const s = Math.sqrt(1 + m00 - m11 - m22) * 2;
160
+ q[3] = (m21 - m12) / s;
161
+ q[0] = s / 4;
162
+ q[1] = (m01 + m10) / s;
163
+ q[2] = (m02 + m20) / s;
164
+ }
165
+ else if (m11 > m22) {
166
+ const s = Math.sqrt(1 + m11 - m00 - m22) * 2;
167
+ q[3] = (m02 - m20) / s;
168
+ q[0] = (m01 + m10) / s;
169
+ q[1] = s / 4;
170
+ q[2] = (m12 + m21) / s;
171
+ }
172
+ else {
173
+ const s = Math.sqrt(1 + m22 - m00 - m11) * 2;
174
+ q[3] = (m10 - m01) / s;
175
+ q[0] = (m02 + m20) / s;
176
+ q[1] = (m12 + m21) / s;
177
+ q[2] = s / 4;
178
+ }
179
+ return q;
180
+ }
181
+ /** Slerp a packed quaternion keyframe channel (times, values) at time t into out. */
182
+ function sampleQuatChannel(times, values, t, out) {
183
+ if (times.length <= 1 || t <= times[0]) {
184
+ out[0] = values[0];
185
+ out[1] = values[1];
186
+ out[2] = values[2];
187
+ out[3] = values[3];
188
+ return;
189
+ }
190
+ const last = times.length - 1;
191
+ if (t >= times[last]) {
192
+ const o = last * 4;
193
+ out[0] = values[o];
194
+ out[1] = values[o + 1];
195
+ out[2] = values[o + 2];
196
+ out[3] = values[o + 3];
197
+ return;
198
+ }
199
+ let lo = 0, hi = last;
200
+ while (hi - lo > 1) {
201
+ const mid = (lo + hi) >> 1;
202
+ if (times[mid] <= t)
203
+ lo = mid;
204
+ else
205
+ hi = mid;
206
+ }
207
+ const alpha = (t - times[lo]) / (times[hi] - times[lo]);
208
+ const a = new Float32Array([values[lo * 4], values[lo * 4 + 1], values[lo * 4 + 2], values[lo * 4 + 3]]);
209
+ const b = new Float32Array([values[hi * 4], values[hi * 4 + 1], values[hi * 4 + 2], values[hi * 4 + 3]]);
210
+ quatSlerp(a, b, alpha, out);
211
+ }
212
+ /** Swap a quaternion from Y-up (Mixamo/FBX source space) to Z-up (engine
213
+ * target space): (x, y, z, w) → (x, -z, y, w). Matches the position map
214
+ * (x, y, z) → (x, -z, y). */
215
+ function quatYupToZup(q, out) {
216
+ out[0] = q[0];
217
+ out[1] = -q[2];
218
+ out[2] = q[1];
219
+ out[3] = q[3];
220
+ }
221
+ function mat4Mul(a, b, out) {
222
+ for (let c = 0; c < 4; c++) {
223
+ const b0 = b[c * 4], b1 = b[c * 4 + 1], b2 = b[c * 4 + 2], b3 = b[c * 4 + 3];
224
+ out[c * 4] = a[0] * b0 + a[4] * b1 + a[8] * b2 + a[12] * b3;
225
+ out[c * 4 + 1] = a[1] * b0 + a[5] * b1 + a[9] * b2 + a[13] * b3;
226
+ out[c * 4 + 2] = a[2] * b0 + a[6] * b1 + a[10] * b2 + a[14] * b3;
227
+ out[c * 4 + 3] = a[3] * b0 + a[7] * b1 + a[11] * b2 + a[15] * b3;
228
+ }
229
+ }
230
+ export class SkeletonAnimator {
231
+ boneCount;
232
+ parentIndices;
233
+ inverseBindMatrices;
234
+ skeleton;
235
+ player;
236
+ localPos;
237
+ localRot;
238
+ localScale;
239
+ restPos;
240
+ restRot;
241
+ restScale;
242
+ // Rotation of the non-bone intermediate transform each bone hangs under
243
+ // (rootAncestorMatrix). Identity for bones directly under their bone parent.
244
+ intermediateRot;
245
+ // Full non-bone intermediate matrix (translation included) — needed to FK
246
+ // bind world positions for retargeting frame alignment.
247
+ intermediateMat;
248
+ worldMatrices;
249
+ localPosFlat;
250
+ localRotFlat;
251
+ localScaleFlat;
252
+ inverseBindMatricesFlat;
253
+ normalizationMatrix = null;
254
+ inverseNormalizationMatrix = null;
255
+ clips = new Map();
256
+ currentState = "Idle";
257
+ timeSinceLastStateChange = 0;
258
+ blendDuration = 0.2;
259
+ sourceRestRotations = new Map();
260
+ sourcePreRotations = new Map();
261
+ sourceRestTranslations = new Map();
262
+ ikEnabled = true;
263
+ leftFootTarget = null;
264
+ rightFootTarget = null;
265
+ boneNameToIndex;
266
+ boneNames = [];
267
+ leftLegUpIdx = -1;
268
+ leftLegDownIdx = -1;
269
+ leftFootIdx = -1;
270
+ rightLegUpIdx = -1;
271
+ rightLegDownIdx = -1;
272
+ rightFootIdx = -1;
273
+ leftUpperArmIdx = -1;
274
+ rightUpperArmIdx = -1;
275
+ spineIdx = -1;
276
+ headIdx = -1;
277
+ proceduralTime = 0;
278
+ isMixamoSkeleton = false;
279
+ /** True when the target skeleton's native bone space is Z-up (e.g. UE-style
280
+ * rigs like Aisha). Mixamo clips are Y-up, so world deltas and rest-pose
281
+ * direction alignment must be axis-swapped for Z-up targets but passed
282
+ * through unchanged for natively Y-up rigs (e.g. Humanling). Defaults to
283
+ * true for rigs loaded before SkinData.skeletonUpAxis existed. */
284
+ targetZUp = true;
285
+ constructor(skin) {
286
+ this.boneCount = skin.bones.length;
287
+ this.parentIndices = new Int32Array(this.boneCount);
288
+ this.inverseBindMatrices = [];
289
+ this.boneNameToIndex = skin.boneNameToIndex;
290
+ // Create Skeleton and AnimationPlayer from SkinData
291
+ const skelData = skinDataToSkeletonData(skin);
292
+ this.skeleton = new Skeleton(skelData);
293
+ this.player = new AnimationPlayer(this.skeleton);
294
+ this.localPos = [];
295
+ this.localRot = [];
296
+ this.localScale = [];
297
+ this.restPos = [];
298
+ this.restRot = [];
299
+ this.restScale = [];
300
+ this.intermediateRot = [];
301
+ this.intermediateMat = [];
302
+ this.worldMatrices = [];
303
+ for (let i = 0; i < this.boneCount; i++) {
304
+ const bone = skin.bones[i];
305
+ this.parentIndices[i] = bone.parentIndex;
306
+ this.boneNames[i] = bone.name;
307
+ const ibm = new Float32Array(16);
308
+ ibm.set(bone.inverseBindMatrix);
309
+ this.inverseBindMatrices.push(ibm);
310
+ const rp = new Float32Array(bone.restTranslation);
311
+ const rr = new Float32Array(bone.restRotation);
312
+ const rs = new Float32Array(bone.restScale);
313
+ this.restPos.push(rp);
314
+ this.restRot.push(rr);
315
+ this.restScale.push(rs);
316
+ this.intermediateRot.push(bone.rootAncestorMatrix ? quatFromMat4Rotation(bone.rootAncestorMatrix) : new Float32Array(IDENTITY_QUAT));
317
+ this.intermediateMat.push(bone.rootAncestorMatrix ? new Float32Array(bone.rootAncestorMatrix) : null);
318
+ this.localPos.push(new Float32Array(rp));
319
+ this.localRot.push(new Float32Array(rr));
320
+ this.localScale.push(new Float32Array(rs));
321
+ this.worldMatrices.push(new Float32Array(16));
322
+ }
323
+ this.inverseBindMatricesFlat = new Float32Array(this.boneCount * 16);
324
+ for (let i = 0; i < this.boneCount; i++) {
325
+ this.inverseBindMatricesFlat.set(this.inverseBindMatrices[i], i * 16);
326
+ }
327
+ this.localPosFlat = new Float32Array(this.boneCount * 4);
328
+ this.localRotFlat = new Float32Array(this.boneCount * 4);
329
+ this.localScaleFlat = new Float32Array(this.boneCount * 4);
330
+ this.leftLegUpIdx = this.findBone(["LegUp_Left", "thigh_l", "UpperLeg_Left", "mixamorig:LeftUpLeg"]);
331
+ this.leftLegDownIdx = this.findBone(["LegDown_Left", "calf_l", "LowerLeg_Left", "mixamorig:LeftLeg"]);
332
+ this.leftFootIdx = this.findBone(["FootStart_Left", "foot_l", "Foot_Left", "mixamorig:LeftFoot"]);
333
+ this.rightLegUpIdx = this.findBone(["LegUp_Right", "thigh_r", "UpperLeg_Right", "mixamorig:RightUpLeg"]);
334
+ this.rightLegDownIdx = this.findBone(["LegDown_Right", "calf_r", "LowerLeg_Right", "mixamorig:RightLeg"]);
335
+ this.rightFootIdx = this.findBone(["FootStart_Right", "foot_r", "Foot_Right", "mixamorig:RightFoot"]);
336
+ this.leftUpperArmIdx = this.findBone(["UpperArm_Left", "upperarm_l", "ArmUp_Left", "mixamorig:LeftArm"]);
337
+ this.rightUpperArmIdx = this.findBone(["UpperArm_Right", "upperarm_r", "ArmUp_Right", "mixamorig:RightArm"]);
338
+ this.spineIdx = this.findBone(["Spine", "spine_01", "Spine_01", "mixamorig:Spine"]);
339
+ this.headIdx = this.findBone(["Head", "head", "mixamorig:Head"]);
340
+ this.targetZUp = skin.skeletonUpAxis !== "y";
341
+ this.isMixamoSkeleton = this.boneNameToIndex.has("mixamorig:Hips");
342
+ if (this.isMixamoSkeleton) {
343
+ log.info("anim", "Mixamo skeleton detected — direct animation mapping (no retargeting)");
344
+ }
345
+ }
346
+ findBone(names) {
347
+ for (let i = 0; i < names.length; i++) {
348
+ const idx = this.boneNameToIndex.get(names[i]);
349
+ if (idx !== undefined)
350
+ return idx;
351
+ }
352
+ return -1;
353
+ }
354
+ registerAnimations(animations) {
355
+ for (let i = 0; i < animations.length; i++) {
356
+ const clip = this.animationDataToClip(animations[i], animations[i].name);
357
+ if (clip) {
358
+ this.clips.set(animations[i].name, clip);
359
+ }
360
+ }
361
+ }
362
+ /**
363
+ * Register a pre-built AnimationClip directly (bypassing the
364
+ * AnimationData→retargeting pipeline). Use this for procedural clips
365
+ * authored directly in the skeleton's local space, or clips loaded from
366
+ * glTF that are already in the correct coordinate space.
367
+ */
368
+ registerClip(name, clip) {
369
+ this.clips.set(name, clip);
370
+ }
371
+ /**
372
+ * Bake an external AnimationData (e.g. a Mixamo clip dropped onto a rigged
373
+ * model) into an AnimationClip for this skeleton — the same retargeting
374
+ * pipeline used by registerRetargetedAnimations, but the clip is returned
375
+ * instead of being registered under a state name. The clip's tracks are
376
+ * indexed against this skeleton's bone indices.
377
+ */
378
+ bakeAnimationClip(anim, clipName) {
379
+ if (anim.sourceRestRotations?.size) {
380
+ this.sourceRestRotations.set(clipName, new Map(anim.sourceRestRotations));
381
+ }
382
+ if (anim.sourcePreRotations?.size) {
383
+ this.sourcePreRotations.set(clipName, new Map(anim.sourcePreRotations));
384
+ }
385
+ if (anim.sourceRestTranslations?.size) {
386
+ this.sourceRestTranslations.set(clipName, new Map(anim.sourceRestTranslations));
387
+ }
388
+ return this.animationDataToClip(anim, clipName);
389
+ }
390
+ animationDataToClip(anim, animName) {
391
+ const tracks = [];
392
+ // Keyed by SOURCE node name; falls back to the AnimationData's own maps
393
+ // when the caller didn't go through registerRetargetedAnimations.
394
+ const preRotMap = this.sourcePreRotations.get(animName) ?? anim.sourcePreRotations;
395
+ const restRotMap = this.sourceRestRotations.get(animName) ?? anim.sourceRestRotations;
396
+ if (!this.isMixamoSkeleton) {
397
+ // Per-frame world-space retargeting for non-Mixamo skeletons.
398
+ //
399
+ // mixamorig:* channels are evaluated as world rotations on the SOURCE
400
+ // (Mixamo) hierarchy — the target hierarchy may differ (e.g. the target
401
+ // can skip intermediate bones like spine_02). Each source world delta is
402
+ // then applied to the target's bind world rotation, and the target local
403
+ // is solved against the target's own (possibly animated) parent chain:
404
+ //
405
+ // srcDelta(t) = srcWorld(t) * inv(srcRestWorld) [Y-up space]
406
+ // desiredWorld(t) = axisSwap(srcDelta(t)) * tgtBindWorld
407
+ // local(t) = inv(intermediate) * inv(parentWorld(t)) * desiredWorld(t)
408
+ //
409
+ // where parentWorld(t) is the target parent's animated world rotation,
410
+ // which keeps parent and child deltas from double-applying.
411
+ //
412
+ // Non-Mixamo channels are applied directly as locals (same-rig clips).
413
+ // Retargeted tracks are baked to plain keyframes — never emit
414
+ // "cubicspline" (that layout expects tangent triplets).
415
+ const toInterp = (s) => s === "STEP" ? "step" : "linear";
416
+ const srcRotChannels = new Map();
417
+ const directChannels = [];
418
+ let hipsPosChannel = null;
419
+ for (let c = 0; c < anim.channels.length; c++) {
420
+ const ch = anim.channels[c];
421
+ if (ch.targetNode.startsWith("mixamorig:")) {
422
+ if (ch.path === "rotation") {
423
+ const tgtName = SkeletonAnimator.MIXAMO_TO_UE[ch.targetNode] ?? ch.targetNode;
424
+ srcRotChannels.set(ch.targetNode, {
425
+ times: ch.keyframeTimes,
426
+ values: ch.keyframeValues,
427
+ boneIdx: this.boneNameToIndex.get(tgtName),
428
+ interpolation: ch.interpolation,
429
+ });
430
+ }
431
+ else if (ch.path === "translation" && ch.targetNode === "mixamorig:Hips") {
432
+ hipsPosChannel = ch;
433
+ }
434
+ // Mixamo scale channels are dropped — bone proportions differ across rigs.
435
+ }
436
+ else {
437
+ directChannels.push(ch);
438
+ }
439
+ }
440
+ // ── Source (Mixamo) world-rotation evaluator ──
441
+ const srcLocalAt = (name, t, out) => {
442
+ const ch = srcRotChannels.get(name);
443
+ if (ch) {
444
+ const q = new Float32Array(4);
445
+ sampleQuatChannel(ch.times, ch.values, t, q);
446
+ const pre = preRotMap?.get(name);
447
+ if (pre) {
448
+ quatMul(new Float32Array(pre), q, out);
449
+ }
450
+ else {
451
+ out.set(q);
452
+ }
453
+ }
454
+ else {
455
+ out.set(restRotMap?.get(name) ?? IDENTITY_QUAT);
456
+ }
457
+ };
458
+ const srcWorldMemo = new Map();
459
+ const srcWorld = (name, t) => {
460
+ let memo = srcWorldMemo.get(name);
461
+ if (!memo) {
462
+ memo = new Map();
463
+ srcWorldMemo.set(name, memo);
464
+ }
465
+ const hit = memo.get(t);
466
+ if (hit)
467
+ return hit;
468
+ const local = new Float32Array(4);
469
+ srcLocalAt(name, t, local);
470
+ const parent = SkeletonAnimator.MIXAMO_PARENT[name];
471
+ const world = new Float32Array(4);
472
+ if (parent) {
473
+ quatMul(srcWorld(parent, t), local, world);
474
+ }
475
+ else {
476
+ world.set(local);
477
+ }
478
+ memo.set(t, world);
479
+ return world;
480
+ };
481
+ // ── Target bind world rotations (including non-bone intermediates) ──
482
+ const ID = new Float32Array([0, 0, 0, 1]);
483
+ const tgtBindWorld = [];
484
+ for (let i = 0; i < this.boneCount; i++) {
485
+ const parentIdx = this.parentIndices[i];
486
+ const pw = parentIdx >= 0 ? tgtBindWorld[parentIdx] : ID;
487
+ const tmp = new Float32Array(4);
488
+ const w = new Float32Array(4);
489
+ quatMul(pw, this.intermediateRot[i], tmp);
490
+ quatMul(tmp, this.restRot[i], w);
491
+ tgtBindWorld.push(w);
492
+ }
493
+ // ── Source REST world rotations (Mixamo bind pose) ──
494
+ // The retarget delta must be measured against the source's rest pose,
495
+ // NOT the clip's first keyframe: locomotion clips start mid-stride, so
496
+ // a frame-0 reference would map that mid-stride pose onto the target's
497
+ // bind pose and shift every other frame by that offset (which shows up
498
+ // as e.g. knees hyperextending backwards).
499
+ const srcRestWorldMemo = new Map();
500
+ const srcRestWorld = (name) => {
501
+ const hit = srcRestWorldMemo.get(name);
502
+ if (hit)
503
+ return hit;
504
+ const w = new Float32Array(4);
505
+ w.set(restRotMap?.get(name) ?? IDENTITY_QUAT);
506
+ const parent = SkeletonAnimator.MIXAMO_PARENT[name];
507
+ if (parent) {
508
+ const out = new Float32Array(4);
509
+ quatMul(srcRestWorld(parent), w, out);
510
+ w.set(out);
511
+ }
512
+ srcRestWorldMemo.set(name, w);
513
+ return w;
514
+ };
515
+ // ── Rest-pose direction data ──
516
+ // Source rest (Mixamo T-pose) and target bind poses differ (e.g. A-pose
517
+ // arms). Bone rest directions are needed to align the two rest poses;
518
+ // they come from joint-to-child-joint vectors, so source rest
519
+ // translations and target bind positions are FK'd here.
520
+ const restTransMap = this.sourceRestTranslations.get(animName) ?? anim.sourceRestTranslations;
521
+ // Source rest world POSITIONS via the Mixamo chain.
522
+ const srcRestPosMemo = new Map();
523
+ const srcRestPos = (name) => {
524
+ const hit = srcRestPosMemo.get(name);
525
+ if (hit)
526
+ return hit;
527
+ const lt = restTransMap?.get(name) ?? [0, 0, 0];
528
+ const parent = SkeletonAnimator.MIXAMO_PARENT[name];
529
+ let pos;
530
+ if (parent) {
531
+ const pp = srcRestPos(parent);
532
+ const pr = srcRestWorld(parent);
533
+ const r = quatRotateVec(pr, lt);
534
+ pos = [pp[0] + r[0], pp[1] + r[1], pp[2] + r[2]];
535
+ }
536
+ else {
537
+ pos = [lt[0], lt[1], lt[2]];
538
+ }
539
+ srcRestPosMemo.set(name, pos);
540
+ return pos;
541
+ };
542
+ // Source "tip" child per node (defines the bone's rest direction).
543
+ const srcChildren = new Map();
544
+ for (const [child, parent] of Object.entries(SkeletonAnimator.MIXAMO_PARENT)) {
545
+ if (!parent)
546
+ continue;
547
+ let list = srcChildren.get(parent);
548
+ if (!list) {
549
+ list = [];
550
+ srcChildren.set(parent, list);
551
+ }
552
+ list.push(child);
553
+ }
554
+ const srcTip = (name) => {
555
+ const kids = srcChildren.get(name);
556
+ if (!kids || kids.length === 0)
557
+ return null;
558
+ // Prefer the axial continuation (spine/neck/head, middle finger, toe).
559
+ const preferred = kids.find((k) => /Spine|Neck|HeadTop|Middle1|Toe_End/.test(k));
560
+ return preferred ?? kids[0];
561
+ };
562
+ // Target bind world positions via matrix FK (includes non-bone
563
+ // intermediate transforms in full, translation included).
564
+ const tgtBindWPos = [];
565
+ {
566
+ const worldMats = [];
567
+ const localMat = new Float32Array(16);
568
+ const tmp = new Float32Array(16);
569
+ for (let i = 0; i < this.boneCount; i++) {
570
+ buildLocalMatrix(this.restPos[i], this.restRot[i], this.restScale[i], localMat);
571
+ const im = this.intermediateMat[i];
572
+ let lm = localMat;
573
+ if (im) {
574
+ mat4Mul(im, localMat, tmp);
575
+ lm = new Float32Array(tmp);
576
+ }
577
+ const pi = this.parentIndices[i];
578
+ const wm = new Float32Array(16);
579
+ if (pi >= 0 && worldMats[pi])
580
+ mat4Mul(worldMats[pi], lm, wm);
581
+ else
582
+ wm.set(lm);
583
+ worldMats[i] = wm;
584
+ tgtBindWPos.push([wm[12], wm[13], wm[14]]);
585
+ }
586
+ }
587
+ // Target "tip" child per bone index (first bone child; prefer the
588
+ // axial continuation for spine/hand/foot chains).
589
+ const tgtChildren = new Map();
590
+ for (let i = 0; i < this.boneCount; i++) {
591
+ const p = this.parentIndices[i];
592
+ if (p < 0)
593
+ continue;
594
+ let list = tgtChildren.get(p);
595
+ if (!list) {
596
+ list = [];
597
+ tgtChildren.set(p, list);
598
+ }
599
+ list.push(i);
600
+ }
601
+ const tgtTip = (i) => {
602
+ const kids = tgtChildren.get(i);
603
+ if (!kids || kids.length === 0)
604
+ return null;
605
+ const preferred = kids.find((k) => /spine|neck|head|middle_01|ball/.test(this.boneNames[k]));
606
+ return preferred ?? kids[0];
607
+ };
608
+ // Per-bone rest-direction alignment. The source (Mixamo T-pose) and
609
+ // target (e.g. A-pose) rest poses differ; measuring the animation delta
610
+ // against the raw source rest double-counts that difference (an A-pose
611
+ // arm receiving a "drop arm from T-pose" delta overshoots and crosses
612
+ // the chest). Instead, pre-rotate the source rest reference by R — the
613
+ // shortest-arc rotation taking the source bone's rest direction onto
614
+ // the target bone's bind direction (expressed in source space). With
615
+ // srcRest' = R·srcRest:
616
+ //
617
+ // desiredWorld(t) = axisSwap(srcW(t) · srcRest'⁻¹) · tgtBindWorld
618
+ //
619
+ // which makes the target bone's world direction exactly
620
+ // axisSwap(sourceBoneDirection(t)) at every frame, while twist about
621
+ // the bone axis still transfers through the delta. When the rest
622
+ // directions already match (e.g. legs), R ≈ identity and this reduces
623
+ // to the plain rest-pose delta.
624
+ const dirAlignMemo = new Map();
625
+ // UE target name → mixamorig source name, for leaf-bone alignment
626
+ // inheritance (reverse of MIXAMO_TO_UE).
627
+ const ueToSrc = new Map();
628
+ for (const [s, t] of Object.entries(SkeletonAnimator.MIXAMO_TO_UE))
629
+ ueToSrc.set(t, s);
630
+ const srcDirAlign = (srcName, boneIdx) => {
631
+ let r = dirAlignMemo.get(boneIdx);
632
+ if (r !== undefined)
633
+ return r;
634
+ r = null;
635
+ const sTip = restTransMap ? srcTip(srcName) : null;
636
+ const tTip = tgtTip(boneIdx);
637
+ if (sTip && tTip !== null) {
638
+ const a = srcRestPos(srcName), b = srcRestPos(sTip);
639
+ const ds = [b[0] - a[0], b[1] - a[1], b[2] - a[2]];
640
+ const ls = Math.hypot(ds[0], ds[1], ds[2]);
641
+ const c = tgtBindWPos[boneIdx], d = tgtBindWPos[tTip];
642
+ const dt = [d[0] - c[0], d[1] - c[1], d[2] - c[2]];
643
+ const lt = Math.hypot(dt[0], dt[1], dt[2]);
644
+ if (ls > 1e-4 && lt > 1e-4) {
645
+ const from = [ds[0] / ls, ds[1] / ls, ds[2] / ls];
646
+ // Target bind dir → source Y-up space. Z-up targets need
647
+ // (x,y,z) → (x,z,-y); Y-up targets are already in source space.
648
+ const to = this.targetZUp
649
+ ? [dt[0] / lt, dt[2] / lt, -dt[1] / lt]
650
+ : [dt[0] / lt, dt[1] / lt, dt[2] / lt];
651
+ const dot = from[0] * to[0] + from[1] * to[1] + from[2] * to[2];
652
+ if (dot < 0.999999) {
653
+ let ax, ay, az;
654
+ if (dot < -0.999999) {
655
+ // Antiparallel: pick any perpendicular axis.
656
+ const px = Math.abs(from[0]) < 0.9 ? 1 : 0;
657
+ const pxv = px ? [1, 0, 0] : [0, 1, 0];
658
+ ax = from[1] * pxv[2] - from[2] * pxv[1];
659
+ ay = from[2] * pxv[0] - from[0] * pxv[2];
660
+ az = from[0] * pxv[1] - from[1] * pxv[0];
661
+ const al = Math.hypot(ax, ay, az) || 1;
662
+ r = new Float32Array([ax / al, ay / al, az / al, 0]);
663
+ }
664
+ else {
665
+ ax = from[1] * to[2] - from[2] * to[1];
666
+ ay = from[2] * to[0] - from[0] * to[2];
667
+ az = from[0] * to[1] - from[1] * to[0];
668
+ const al = Math.hypot(ax, ay, az, 1 + dot) || 1;
669
+ r = new Float32Array([ax / al, ay / al, az / al, (1 + dot) / al]);
670
+ }
671
+ }
672
+ }
673
+ }
674
+ else {
675
+ // Leaf bone — no tip child to define a bone direction, so no R can
676
+ // be computed. Without one, the raw source delta carries the
677
+ // accumulated rest-pose mismatch of every ancestor in the chain
678
+ // (e.g. Mixamo finger tips deviating ~120° from the target bind).
679
+ // Inherit the parent's alignment so the leaf rides the corrected
680
+ // frame and stays at its bind local when the source is at rest.
681
+ const pIdx = this.parentIndices[boneIdx];
682
+ if (pIdx >= 0) {
683
+ const pSrc = ueToSrc.get(this.boneNames[pIdx]);
684
+ if (pSrc)
685
+ r = srcDirAlign(pSrc, pIdx);
686
+ }
687
+ }
688
+ dirAlignMemo.set(boneIdx, r);
689
+ return r;
690
+ };
691
+ const boneChannels = new Map();
692
+ const emitDesired = (srcName, boneIdx, times, interpolation) => {
693
+ const desired = new Float32Array(times.length * 4);
694
+ // srcRest' = R·srcRestW where R aligns the source rest bone direction
695
+ // with the target bind direction. inv(srcRest') = inv(srcRestW)·inv(R).
696
+ const srcRestW = srcRestWorld(srcName);
697
+ const invSrcW = new Float32Array(4);
698
+ quatInvert(srcRestW, invSrcW);
699
+ const align = srcDirAlign(srcName, boneIdx);
700
+ const invSrcRef = new Float32Array(4);
701
+ if (align) {
702
+ const invR = new Float32Array(4);
703
+ quatInvert(align, invR);
704
+ quatMul(invSrcW, invR, invSrcRef);
705
+ }
706
+ else {
707
+ invSrcRef.set(invSrcW);
708
+ }
709
+ const tgtRef = tgtBindWorld[boneIdx];
710
+ const tmpA = new Float32Array(4);
711
+ const tmpB = new Float32Array(4);
712
+ let prev = null;
713
+ for (let k = 0; k < times.length; k++) {
714
+ quatMul(srcWorld(srcName, times[k]), invSrcRef, tmpA); // source deviation from reference frame
715
+ if (this.targetZUp)
716
+ quatYupToZup(tmpA, tmpB);
717
+ else
718
+ tmpB.set(tmpA);
719
+ const w = new Float32Array(4);
720
+ quatMul(tmpB, tgtRef, w);
721
+ if (prev && w[0] * prev[0] + w[1] * prev[1] + w[2] * prev[2] + w[3] * prev[3] < 0) {
722
+ w[0] = -w[0];
723
+ w[1] = -w[1];
724
+ w[2] = -w[2];
725
+ w[3] = -w[3];
726
+ }
727
+ prev = w;
728
+ desired.set(w, k * 4);
729
+ }
730
+ boneChannels.set(boneIdx, { srcName, times, desired, interpolation });
731
+ };
732
+ for (const [srcName, ch] of srcRotChannels.entries()) {
733
+ if (ch.boneIdx === undefined)
734
+ continue;
735
+ emitDesired(srcName, ch.boneIdx, ch.times, ch.interpolation);
736
+ }
737
+ // A mapped target bone whose SOURCE node has no channel still needs a
738
+ // track when an ancestor in the source chain is animated (e.g.
739
+ // mixamorig:Spine2 → spine_03 when only mixamorig:Spine1 is keyed).
740
+ const hasChanneledAncestor = (srcName) => {
741
+ let p = SkeletonAnimator.MIXAMO_PARENT[srcName];
742
+ while (p) {
743
+ if (srcRotChannels.has(p))
744
+ return true;
745
+ p = SkeletonAnimator.MIXAMO_PARENT[p];
746
+ }
747
+ return false;
748
+ };
749
+ let unionTimes = null;
750
+ for (const [srcName, tgtName] of Object.entries(SkeletonAnimator.MIXAMO_TO_UE)) {
751
+ if (srcRotChannels.has(srcName))
752
+ continue;
753
+ const boneIdx = this.boneNameToIndex.get(tgtName);
754
+ if (boneIdx === undefined || !hasChanneledAncestor(srcName))
755
+ continue;
756
+ if (!unionTimes) {
757
+ const set = new Set();
758
+ for (const ch of srcRotChannels.values())
759
+ ch.times.forEach((t) => { set.add(t); ; });
760
+ unionTimes = new Float32Array([...set].sort((a, b) => a - b));
761
+ }
762
+ emitDesired(srcName, boneIdx, unionTimes, "LINEAR");
763
+ }
764
+ // ── Target animated world sampler (channels → desired; else bind-local) ──
765
+ const tgtWorldMemo = new Map();
766
+ const tgtWorldAnim = (i, t) => {
767
+ const ch = boneChannels.get(i);
768
+ if (ch) {
769
+ const out = new Float32Array(4);
770
+ sampleQuatChannel(ch.times, ch.desired, t, out);
771
+ return out;
772
+ }
773
+ let memo = tgtWorldMemo.get(i);
774
+ if (!memo) {
775
+ memo = new Map();
776
+ tgtWorldMemo.set(i, memo);
777
+ }
778
+ const hit = memo.get(t);
779
+ if (hit)
780
+ return hit;
781
+ const parentIdx = this.parentIndices[i];
782
+ const pw = parentIdx >= 0 ? tgtWorldAnim(parentIdx, t) : ID;
783
+ const tmp = new Float32Array(4);
784
+ const w = new Float32Array(4);
785
+ quatMul(pw, this.intermediateRot[i], tmp);
786
+ quatMul(tmp, this.restRot[i], w);
787
+ memo.set(t, w);
788
+ return w;
789
+ };
790
+ // ── Emit local rotation tracks ──
791
+ for (const [i, ch] of boneChannels.entries()) {
792
+ const times = ch.times;
793
+ const values = new Float32Array(times.length * 4);
794
+ const parentIdx = this.parentIndices[i];
795
+ const invIntermediate = new Float32Array(4);
796
+ quatInvert(this.intermediateRot[i], invIntermediate);
797
+ const tmpA = new Float32Array(4);
798
+ const tmpB = new Float32Array(4);
799
+ let prev = null;
800
+ for (let k = 0; k < times.length; k++) {
801
+ const pw = parentIdx >= 0 ? tgtWorldAnim(parentIdx, times[k]) : ID;
802
+ const o = k * 4;
803
+ const desired = new Float32Array([ch.desired[o], ch.desired[o + 1], ch.desired[o + 2], ch.desired[o + 3]]);
804
+ quatInvert(pw, tmpA);
805
+ quatMul(tmpA, desired, tmpB);
806
+ const local = new Float32Array(4);
807
+ quatMul(invIntermediate, tmpB, local);
808
+ if (prev && local[0] * prev[0] + local[1] * prev[1] + local[2] * prev[2] + local[3] * prev[3] < 0) {
809
+ local[0] = -local[0];
810
+ local[1] = -local[1];
811
+ local[2] = -local[2];
812
+ local[3] = -local[3];
813
+ }
814
+ prev = local;
815
+ values.set(local, o);
816
+ }
817
+ tracks.push({
818
+ boneName: this.boneNames[i],
819
+ boneIndex: i,
820
+ path: "rotation",
821
+ times,
822
+ values,
823
+ interpolation: toInterp(ch.interpolation),
824
+ });
825
+ }
826
+ // ── Hips translation → pelvis position track ──
827
+ // Applied as a scaled delta around the target's rest position. Forward
828
+ // motion is stripped (root motion is gameplay-driven); lateral sway and
829
+ // vertical bob are preserved.
830
+ const pelvisIdx = this.boneNameToIndex.get("pelvis");
831
+ if (hipsPosChannel && pelvisIdx !== undefined) {
832
+ const times = hipsPosChannel.keyframeTimes;
833
+ const v = hipsPosChannel.keyframeValues;
834
+ const rest = this.restPos[pelvisIdx];
835
+ // The pelvis' vertical rest component — Z for Z-up rigs, Y for Y-up.
836
+ const upAxis = this.targetZUp ? 2 : 1;
837
+ const srcY0 = v[1];
838
+ const scale = Math.abs(srcY0) > 1e-3 ? Math.abs(rest[upAxis]) / Math.abs(srcY0) : 0.01;
839
+ const values = new Float32Array(times.length * 3);
840
+ for (let k = 0; k < times.length; k++) {
841
+ const dx = (v[k * 3] - v[0]) * scale;
842
+ const dy = (v[k * 3 + 1] - v[1]) * scale;
843
+ values[k * 3] = rest[0] + dx;
844
+ values[k * 3 + 1] = rest[1] + (this.targetZUp ? 0 : dy);
845
+ values[k * 3 + 2] = rest[2] + (this.targetZUp ? dy : 0);
846
+ }
847
+ tracks.push({
848
+ boneName: this.boneNames[pelvisIdx],
849
+ boneIndex: pelvisIdx,
850
+ path: "position",
851
+ times,
852
+ values,
853
+ interpolation: toInterp(hipsPosChannel.interpolation),
854
+ });
855
+ }
856
+ // ── Non-Mixamo channels: applied directly as local-space tracks ──
857
+ for (let c = 0; c < directChannels.length; c++) {
858
+ const ch = directChannels[c];
859
+ const boneIdx = this.boneNameToIndex.get(ch.targetNode);
860
+ if (boneIdx === undefined)
861
+ continue;
862
+ const path = ch.path === "translation" ? "position" : ch.path === "rotation" ? "rotation" : "scale";
863
+ const interp = toInterp(ch.interpolation);
864
+ const times = ch.keyframeTimes;
865
+ const srcValues = ch.keyframeValues;
866
+ if (path === "rotation") {
867
+ const values = new Float32Array(srcValues.length);
868
+ const srcPreRot = preRotMap?.get(ch.targetNode);
869
+ for (let k = 0; k < times.length; k++) {
870
+ const v0 = k * 4;
871
+ const q = new Float32Array([srcValues[v0], srcValues[v0 + 1], srcValues[v0 + 2], srcValues[v0 + 3]]);
872
+ if (srcPreRot) {
873
+ const result = new Float32Array(4);
874
+ quatMul(new Float32Array(srcPreRot), q, result);
875
+ values[v0] = result[0];
876
+ values[v0 + 1] = result[1];
877
+ values[v0 + 2] = result[2];
878
+ values[v0 + 3] = result[3];
879
+ }
880
+ else {
881
+ values[v0] = q[0];
882
+ values[v0 + 1] = q[1];
883
+ values[v0 + 2] = q[2];
884
+ values[v0 + 3] = q[3];
885
+ }
886
+ }
887
+ tracks.push({ boneName: ch.targetNode, boneIndex: boneIdx, path, times, values, interpolation: interp });
888
+ }
889
+ else {
890
+ tracks.push({ boneName: ch.targetNode, boneIndex: boneIdx, path, times, values: srcValues, interpolation: interp });
891
+ }
892
+ }
893
+ }
894
+ else {
895
+ // Mixamo skeleton: simple pre-rotation application
896
+ for (let c = 0; c < anim.channels.length; c++) {
897
+ const ch = anim.channels[c];
898
+ const nodeName = ch.targetNode;
899
+ const boneIdx = this.boneNameToIndex.get(nodeName);
900
+ if (boneIdx === undefined)
901
+ continue;
902
+ const path = ch.path === "translation" ? "position" : ch.path === "rotation" ? "rotation" : "scale";
903
+ const interp = ch.interpolation === "LINEAR" ? "linear" : ch.interpolation === "STEP" ? "step" : "cubicspline";
904
+ const times = ch.keyframeTimes;
905
+ const srcValues = ch.keyframeValues;
906
+ if (path === "rotation") {
907
+ const values = new Float32Array(srcValues.length);
908
+ const srcPreRot = preRotMap?.get(nodeName);
909
+ for (let k = 0; k < times.length; k++) {
910
+ const v0 = k * 4;
911
+ const q = new Float32Array([srcValues[v0], srcValues[v0 + 1], srcValues[v0 + 2], srcValues[v0 + 3]]);
912
+ if (srcPreRot) {
913
+ const result = new Float32Array(4);
914
+ quatMul(new Float32Array(srcPreRot), q, result);
915
+ values[v0] = result[0];
916
+ values[v0 + 1] = result[1];
917
+ values[v0 + 2] = result[2];
918
+ values[v0 + 3] = result[3];
919
+ }
920
+ else {
921
+ values[v0] = q[0];
922
+ values[v0 + 1] = q[1];
923
+ values[v0 + 2] = q[2];
924
+ values[v0 + 3] = q[3];
925
+ }
926
+ }
927
+ tracks.push({ boneName: nodeName, boneIndex: boneIdx, path, times, values, interpolation: interp });
928
+ }
929
+ else {
930
+ tracks.push({ boneName: nodeName, boneIndex: boneIdx, path, times, values: srcValues, interpolation: interp });
931
+ }
932
+ }
933
+ }
934
+ if (tracks.length === 0)
935
+ return null;
936
+ return new AnimationClip({ name: animName, duration: anim.duration, tracks });
937
+ }
938
+ static MIXAMO_TO_UE = {
939
+ "mixamorig:Hips": "pelvis",
940
+ "mixamorig:Spine": "spine_01",
941
+ "mixamorig:Spine1": "spine_02",
942
+ "mixamorig:Spine2": "spine_03",
943
+ "mixamorig:Neck": "neck_01",
944
+ "mixamorig:Head": "head",
945
+ "mixamorig:LeftShoulder": "clavicle_l",
946
+ "mixamorig:LeftArm": "upperarm_l",
947
+ "mixamorig:LeftForeArm": "lowerarm_l",
948
+ "mixamorig:LeftHand": "hand_l",
949
+ "mixamorig:RightShoulder": "clavicle_r",
950
+ "mixamorig:RightArm": "upperarm_r",
951
+ "mixamorig:RightForeArm": "lowerarm_r",
952
+ "mixamorig:RightHand": "hand_r",
953
+ "mixamorig:LeftUpLeg": "thigh_l",
954
+ "mixamorig:LeftLeg": "calf_l",
955
+ "mixamorig:LeftFoot": "foot_l",
956
+ "mixamorig:LeftToeBase": "ball_l",
957
+ "mixamorig:RightUpLeg": "thigh_r",
958
+ "mixamorig:RightLeg": "calf_r",
959
+ "mixamorig:RightFoot": "foot_r",
960
+ "mixamorig:RightToeBase": "ball_r",
961
+ "mixamorig:LeftHandThumb1": "thumb_01_l",
962
+ "mixamorig:LeftHandThumb2": "thumb_02_l",
963
+ "mixamorig:LeftHandThumb3": "thumb_03_l",
964
+ "mixamorig:LeftHandIndex1": "index_01_l",
965
+ "mixamorig:LeftHandIndex2": "index_02_l",
966
+ "mixamorig:LeftHandIndex3": "index_03_l",
967
+ "mixamorig:LeftHandMiddle1": "middle_01_l",
968
+ "mixamorig:LeftHandMiddle2": "middle_02_l",
969
+ "mixamorig:LeftHandMiddle3": "middle_03_l",
970
+ "mixamorig:LeftHandRing1": "ring_01_l",
971
+ "mixamorig:LeftHandRing2": "ring_02_l",
972
+ "mixamorig:LeftHandRing3": "ring_03_l",
973
+ "mixamorig:LeftHandPinky1": "pinky_01_l",
974
+ "mixamorig:LeftHandPinky2": "pinky_02_l",
975
+ "mixamorig:LeftHandPinky3": "pinky_03_l",
976
+ "mixamorig:RightHandThumb1": "thumb_01_r",
977
+ "mixamorig:RightHandThumb2": "thumb_02_r",
978
+ "mixamorig:RightHandThumb3": "thumb_03_r",
979
+ "mixamorig:RightHandIndex1": "index_01_r",
980
+ "mixamorig:RightHandIndex2": "index_02_r",
981
+ "mixamorig:RightHandIndex3": "index_03_r",
982
+ "mixamorig:RightHandMiddle1": "middle_01_r",
983
+ "mixamorig:RightHandMiddle2": "middle_02_r",
984
+ "mixamorig:RightHandMiddle3": "middle_03_r",
985
+ "mixamorig:RightHandRing1": "ring_01_r",
986
+ "mixamorig:RightHandRing2": "ring_02_r",
987
+ "mixamorig:RightHandRing3": "ring_03_r",
988
+ "mixamorig:RightHandPinky1": "pinky_01_r",
989
+ "mixamorig:RightHandPinky2": "pinky_02_r",
990
+ "mixamorig:RightHandPinky3": "pinky_03_r",
991
+ };
992
+ /** Parent of each bone in the standard Mixamo rig. Used to evaluate source
993
+ * world rotations when retargeting mixamorig:* clips onto non-Mixamo
994
+ * skeletons — the source hierarchy is independent of the target's. */
995
+ static MIXAMO_PARENT = {
996
+ "mixamorig:Hips": null,
997
+ "mixamorig:Spine": "mixamorig:Hips",
998
+ "mixamorig:Spine1": "mixamorig:Spine",
999
+ "mixamorig:Spine2": "mixamorig:Spine1",
1000
+ "mixamorig:Neck": "mixamorig:Spine2",
1001
+ "mixamorig:Head": "mixamorig:Neck",
1002
+ "mixamorig:HeadTop_End": "mixamorig:Head",
1003
+ "mixamorig:LeftShoulder": "mixamorig:Spine2",
1004
+ "mixamorig:LeftArm": "mixamorig:LeftShoulder",
1005
+ "mixamorig:LeftForeArm": "mixamorig:LeftArm",
1006
+ "mixamorig:LeftHand": "mixamorig:LeftForeArm",
1007
+ "mixamorig:RightShoulder": "mixamorig:Spine2",
1008
+ "mixamorig:RightArm": "mixamorig:RightShoulder",
1009
+ "mixamorig:RightForeArm": "mixamorig:RightArm",
1010
+ "mixamorig:RightHand": "mixamorig:RightForeArm",
1011
+ "mixamorig:LeftUpLeg": "mixamorig:Hips",
1012
+ "mixamorig:LeftLeg": "mixamorig:LeftUpLeg",
1013
+ "mixamorig:LeftFoot": "mixamorig:LeftLeg",
1014
+ "mixamorig:LeftToeBase": "mixamorig:LeftFoot",
1015
+ "mixamorig:LeftToe_End": "mixamorig:LeftToeBase",
1016
+ "mixamorig:RightUpLeg": "mixamorig:Hips",
1017
+ "mixamorig:RightLeg": "mixamorig:RightUpLeg",
1018
+ "mixamorig:RightFoot": "mixamorig:RightLeg",
1019
+ "mixamorig:RightToeBase": "mixamorig:RightFoot",
1020
+ "mixamorig:RightToe_End": "mixamorig:RightToeBase",
1021
+ "mixamorig:LeftHandThumb1": "mixamorig:LeftHand",
1022
+ "mixamorig:LeftHandThumb2": "mixamorig:LeftHandThumb1",
1023
+ "mixamorig:LeftHandThumb3": "mixamorig:LeftHandThumb2",
1024
+ "mixamorig:LeftHandThumb4": "mixamorig:LeftHandThumb3",
1025
+ "mixamorig:LeftHandIndex1": "mixamorig:LeftHand",
1026
+ "mixamorig:LeftHandIndex2": "mixamorig:LeftHandIndex1",
1027
+ "mixamorig:LeftHandIndex3": "mixamorig:LeftHandIndex2",
1028
+ "mixamorig:LeftHandIndex4": "mixamorig:LeftHandIndex3",
1029
+ "mixamorig:LeftHandMiddle1": "mixamorig:LeftHand",
1030
+ "mixamorig:LeftHandMiddle2": "mixamorig:LeftHandMiddle1",
1031
+ "mixamorig:LeftHandMiddle3": "mixamorig:LeftHandMiddle2",
1032
+ "mixamorig:LeftHandMiddle4": "mixamorig:LeftHandMiddle3",
1033
+ "mixamorig:LeftHandRing1": "mixamorig:LeftHand",
1034
+ "mixamorig:LeftHandRing2": "mixamorig:LeftHandRing1",
1035
+ "mixamorig:LeftHandRing3": "mixamorig:LeftHandRing2",
1036
+ "mixamorig:LeftHandRing4": "mixamorig:LeftHandRing3",
1037
+ "mixamorig:LeftHandPinky1": "mixamorig:LeftHand",
1038
+ "mixamorig:LeftHandPinky2": "mixamorig:LeftHandPinky1",
1039
+ "mixamorig:LeftHandPinky3": "mixamorig:LeftHandPinky2",
1040
+ "mixamorig:LeftHandPinky4": "mixamorig:LeftHandPinky3",
1041
+ "mixamorig:RightHandThumb1": "mixamorig:RightHand",
1042
+ "mixamorig:RightHandThumb2": "mixamorig:RightHandThumb1",
1043
+ "mixamorig:RightHandThumb3": "mixamorig:RightHandThumb2",
1044
+ "mixamorig:RightHandThumb4": "mixamorig:RightHandThumb3",
1045
+ "mixamorig:RightHandIndex1": "mixamorig:RightHand",
1046
+ "mixamorig:RightHandIndex2": "mixamorig:RightHandIndex1",
1047
+ "mixamorig:RightHandIndex3": "mixamorig:RightHandIndex2",
1048
+ "mixamorig:RightHandIndex4": "mixamorig:RightHandIndex3",
1049
+ "mixamorig:RightHandMiddle1": "mixamorig:RightHand",
1050
+ "mixamorig:RightHandMiddle2": "mixamorig:RightHandMiddle1",
1051
+ "mixamorig:RightHandMiddle3": "mixamorig:RightHandMiddle2",
1052
+ "mixamorig:RightHandMiddle4": "mixamorig:RightHandMiddle3",
1053
+ "mixamorig:RightHandRing1": "mixamorig:RightHand",
1054
+ "mixamorig:RightHandRing2": "mixamorig:RightHandRing1",
1055
+ "mixamorig:RightHandRing3": "mixamorig:RightHandRing2",
1056
+ "mixamorig:RightHandRing4": "mixamorig:RightHandRing3",
1057
+ "mixamorig:RightHandPinky1": "mixamorig:RightHand",
1058
+ "mixamorig:RightHandPinky2": "mixamorig:RightHandPinky1",
1059
+ "mixamorig:RightHandPinky3": "mixamorig:RightHandPinky2",
1060
+ "mixamorig:RightHandPinky4": "mixamorig:RightHandPinky3",
1061
+ };
1062
+ registerRetargetedAnimations(animations, stateName) {
1063
+ // Extract and store source rest/pre-rotations for pre-baking
1064
+ const sourceRests = animations[0]?.sourceRestRotations;
1065
+ const sourcePreRots = animations[0]?.sourcePreRotations;
1066
+ const sourceTrans = animations[0]?.sourceRestTranslations;
1067
+ const restRotMap = new Map();
1068
+ const preRotMap = new Map();
1069
+ // Keys are SOURCE node names — for Mixamo sources the full map is kept
1070
+ // (including bones with no target counterpart, since they still
1071
+ // participate in the source world-rotation chain).
1072
+ if (sourcePreRots) {
1073
+ for (const [boneName, quat] of sourcePreRots.entries()) {
1074
+ preRotMap.set(boneName, quat);
1075
+ }
1076
+ }
1077
+ if (sourceRests) {
1078
+ for (const [boneName, quat] of sourceRests.entries()) {
1079
+ restRotMap.set(boneName, quat);
1080
+ }
1081
+ }
1082
+ if (restRotMap.size > 0) {
1083
+ this.sourceRestRotations.set(stateName, restRotMap);
1084
+ }
1085
+ if (preRotMap.size > 0) {
1086
+ this.sourcePreRotations.set(stateName, preRotMap);
1087
+ }
1088
+ if (sourceTrans && sourceTrans.size > 0) {
1089
+ this.sourceRestTranslations.set(stateName, new Map(sourceTrans));
1090
+ }
1091
+ // Merge all animation channels into one AnimationData, then pre-bake to AnimationClip
1092
+ const allChannels = [];
1093
+ let duration = 0;
1094
+ for (let i = 0; i < animations.length; i++) {
1095
+ const anim = animations[i];
1096
+ duration = Math.max(duration, anim.duration);
1097
+ for (let c = 0; c < anim.channels.length; c++) {
1098
+ const ch = anim.channels[c];
1099
+ const nodeName = ch.targetNode;
1100
+ if (this.isMixamoSkeleton) {
1101
+ if (this.boneNameToIndex.has(nodeName))
1102
+ allChannels.push(ch);
1103
+ continue;
1104
+ }
1105
+ // Non-Mixamo skeleton: keep mixamorig:* channels under their SOURCE
1106
+ // names (resolved by world-space retargeting, including unmapped bones
1107
+ // needed for the source chain); keep same-name channels that hit a bone.
1108
+ if (nodeName.startsWith("mixamorig:") || this.boneNameToIndex.has(nodeName)) {
1109
+ allChannels.push(ch);
1110
+ }
1111
+ }
1112
+ }
1113
+ if (allChannels.length === 0)
1114
+ return;
1115
+ const mergedAnim = {
1116
+ name: stateName,
1117
+ duration,
1118
+ channels: allChannels,
1119
+ };
1120
+ const clip = this.animationDataToClip(mergedAnim, stateName);
1121
+ if (clip) {
1122
+ this.clips.set(stateName, clip);
1123
+ log.info("anim", `Registered: ${stateName} (${allChannels.length} channels, ${this.isMixamoSkeleton ? "direct Mixamo" : "retargeted-v2"})`);
1124
+ }
1125
+ }
1126
+ /**
1127
+ * Minimum time between state changes. Callers re-request their desired
1128
+ * state every frame, so a blocked request lands as soon as the interval
1129
+ * passes — this only debounces frame-to-frame churn (e.g. a flag toggling
1130
+ * at a boundary), which would otherwise restart the crossfade each frame
1131
+ * and freeze the pose mid-blend. (Was a 0.5s gate, which deferred every
1132
+ * legitimate transition — entering water, landing — by up to half a
1133
+ * second.)
1134
+ */
1135
+ static MIN_STATE_INTERVAL = 0.1;
1136
+ setAnimationState(state, fadeDuration) {
1137
+ if (state === this.currentState && this.player.isPlaying(state))
1138
+ return;
1139
+ const clip = this.clips.get(state);
1140
+ if (!clip)
1141
+ return;
1142
+ if (this.timeSinceLastStateChange < SkeletonAnimator.MIN_STATE_INTERVAL && this.player.isPlaying())
1143
+ return;
1144
+ // Use AnimationPlayer's fade for crossfade blending
1145
+ this.player.play(state, clip, { fadeDuration: fadeDuration ?? this.blendDuration });
1146
+ this.currentState = state;
1147
+ this.timeSinceLastStateChange = 0;
1148
+ }
1149
+ /** Scale the playback speed of a currently-playing state's layer (e.g.
1150
+ * faster swim strokes at higher swim velocity). No-op if the state's
1151
+ * clip isn't active. */
1152
+ setStateSpeed(state, speed) {
1153
+ this.player.setSpeed(state, speed);
1154
+ }
1155
+ setFootTargets(left, right) {
1156
+ this.leftFootTarget = left;
1157
+ this.rightFootTarget = right;
1158
+ }
1159
+ setIKEnabled(enabled) {
1160
+ this.ikEnabled = enabled;
1161
+ }
1162
+ hasAnimation(name) {
1163
+ return this.clips.has(name);
1164
+ }
1165
+ /**
1166
+ * Advance the animation clock without changing state — for callers that
1167
+ * hold a SkeletonAnimator by composition (e.g. CharacterAnimator/Preview)
1168
+ * rather than subclassing it.
1169
+ */
1170
+ advance(dt) {
1171
+ this.tick(dt);
1172
+ }
1173
+ tick(dt) {
1174
+ if (dt > 0.1)
1175
+ dt = 0.1;
1176
+ this.timeSinceLastStateChange += dt;
1177
+ // AnimationPlayer handles time progression, blending, layering, and sampling
1178
+ this.player.update(dt);
1179
+ // Copy output to local arrays
1180
+ const transforms = this.player.getBoneTransforms();
1181
+ const hasActiveAnim = this.player.isPlaying();
1182
+ for (let i = 0; i < this.boneCount; i++) {
1183
+ this.localPos[i][0] = transforms.positions[i][0];
1184
+ this.localPos[i][1] = transforms.positions[i][1];
1185
+ this.localPos[i][2] = transforms.positions[i][2];
1186
+ this.localRot[i][0] = transforms.rotations[i][0];
1187
+ this.localRot[i][1] = transforms.rotations[i][1];
1188
+ this.localRot[i][2] = transforms.rotations[i][2];
1189
+ this.localRot[i][3] = transforms.rotations[i][3];
1190
+ this.localScale[i][0] = transforms.scales[i][0];
1191
+ this.localScale[i][1] = transforms.scales[i][1];
1192
+ this.localScale[i][2] = transforms.scales[i][2];
1193
+ }
1194
+ // Apply procedural idle when no animation is playing
1195
+ if (!hasActiveAnim) {
1196
+ this.applyProceduralIdle(dt);
1197
+ }
1198
+ // Apply foot IK as post-processing
1199
+ if (this.ikEnabled) {
1200
+ this.applyFootIK();
1201
+ }
1202
+ // Flatten for GPU upload
1203
+ for (let i = 0; i < this.boneCount; i++) {
1204
+ this.localPosFlat[i * 4] = this.localPos[i][0];
1205
+ this.localPosFlat[i * 4 + 1] = this.localPos[i][1];
1206
+ this.localPosFlat[i * 4 + 2] = this.localPos[i][2];
1207
+ this.localPosFlat[i * 4 + 3] = 0.0;
1208
+ this.localRotFlat[i * 4] = this.localRot[i][0];
1209
+ this.localRotFlat[i * 4 + 1] = this.localRot[i][1];
1210
+ this.localRotFlat[i * 4 + 2] = this.localRot[i][2];
1211
+ this.localRotFlat[i * 4 + 3] = this.localRot[i][3];
1212
+ this.localScaleFlat[i * 4] = this.localScale[i][0];
1213
+ this.localScaleFlat[i * 4 + 1] = this.localScale[i][1];
1214
+ this.localScaleFlat[i * 4 + 2] = this.localScale[i][2];
1215
+ this.localScaleFlat[i * 4 + 3] = 0.0;
1216
+ }
1217
+ }
1218
+ applyFootIK() {
1219
+ if (this.leftFootTarget && this.leftLegUpIdx >= 0 && this.leftLegDownIdx >= 0 && this.leftFootIdx >= 0) {
1220
+ this.applyTwoBoneIK(this.leftLegUpIdx, this.leftLegDownIdx, this.leftFootIdx, this.leftFootTarget);
1221
+ }
1222
+ if (this.rightFootTarget && this.rightLegUpIdx >= 0 && this.rightLegDownIdx >= 0 && this.rightFootIdx >= 0) {
1223
+ this.applyTwoBoneIK(this.rightLegUpIdx, this.rightLegDownIdx, this.rightFootIdx, this.rightFootTarget);
1224
+ }
1225
+ }
1226
+ applyTwoBoneIK(rootIdx, midIdx, endIdx, target) {
1227
+ const rootWorld = this.computeBoneWorldPos(rootIdx);
1228
+ const midWorld = this.computeBoneWorldPos(midIdx);
1229
+ const endWorld = this.computeBoneWorldPos(endIdx);
1230
+ const targetY = target[1];
1231
+ const dx = target[0] - rootWorld[0];
1232
+ const dy = targetY - rootWorld[1];
1233
+ const dz = target[2] - rootWorld[2];
1234
+ const targetDist = Math.sqrt(dx * dx + dy * dy + dz * dz);
1235
+ let upperLen = 0;
1236
+ let lowerLen = 0;
1237
+ for (let i = 0; i < 3; i++) {
1238
+ const d = midWorld[i] - rootWorld[i];
1239
+ upperLen += d * d;
1240
+ }
1241
+ upperLen = Math.sqrt(upperLen);
1242
+ for (let i = 0; i < 3; i++) {
1243
+ const d = endWorld[i] - midWorld[i];
1244
+ lowerLen += d * d;
1245
+ }
1246
+ lowerLen = Math.sqrt(lowerLen);
1247
+ if (upperLen < 0.001 || lowerLen < 0.001)
1248
+ return;
1249
+ const maxReach = upperLen + lowerLen - 0.001;
1250
+ const minReach = Math.abs(upperLen - lowerLen) + 0.001;
1251
+ const clampedDist = Math.max(minReach, Math.min(maxReach, targetDist));
1252
+ const cosKnee = (upperLen * upperLen + lowerLen * lowerLen - clampedDist * clampedDist) / (2 * upperLen * lowerLen);
1253
+ const kneeAngle = Math.acos(Math.max(-1, Math.min(1, cosKnee)));
1254
+ const dirX = dx / targetDist;
1255
+ const dirY = dy / targetDist;
1256
+ const dirZ = dz / targetDist;
1257
+ const restKneeAngle = Math.acos(Math.max(-1, Math.min(1, ((midWorld[0] - rootWorld[0]) * (endWorld[0] - midWorld[0]) +
1258
+ (midWorld[1] - rootWorld[1]) * (endWorld[1] - midWorld[1]) +
1259
+ (midWorld[2] - rootWorld[2]) * (endWorld[2] - midWorld[2])) / (upperLen * lowerLen))));
1260
+ const kneeDelta = kneeAngle - restKneeAngle;
1261
+ if (Math.abs(kneeDelta) < 0.001)
1262
+ return;
1263
+ const halfDelta = kneeDelta * 0.5;
1264
+ const rotQuat = new Float32Array([Math.sin(halfDelta), 0, 0, Math.cos(halfDelta)]);
1265
+ const newRot = new Float32Array(4);
1266
+ quatMul(this.localRot[midIdx], rotQuat, newRot);
1267
+ this.localRot[midIdx].set(newRot);
1268
+ }
1269
+ computeBoneWorldPos(boneIdx) {
1270
+ const chain = [];
1271
+ let idx = boneIdx;
1272
+ while (idx >= 0) {
1273
+ chain.unshift(idx);
1274
+ idx = this.parentIndices[idx];
1275
+ }
1276
+ const pos = new Float32Array(3);
1277
+ const tmpMat = new Float32Array(16);
1278
+ const accumMat = new Float32Array(16);
1279
+ accumMat[0] = 1;
1280
+ accumMat[5] = 1;
1281
+ accumMat[10] = 1;
1282
+ accumMat[15] = 1;
1283
+ for (let c = 0; c < chain.length; c++) {
1284
+ const bi = chain[c];
1285
+ buildLocalMatrix(this.localPos[bi], this.localRot[bi], this.localScale[bi], tmpMat);
1286
+ const newAccum = new Float32Array(16);
1287
+ mat4Mul(accumMat, tmpMat, newAccum);
1288
+ accumMat.set(newAccum);
1289
+ }
1290
+ pos[0] = accumMat[12];
1291
+ pos[1] = accumMat[13];
1292
+ pos[2] = accumMat[14];
1293
+ return pos;
1294
+ }
1295
+ applyProceduralIdle(dt) {
1296
+ this.proceduralTime += dt;
1297
+ const t = this.proceduralTime;
1298
+ const breath = Math.sin(t * 1.5) * 0.5 + 0.5;
1299
+ if (this.spineIdx >= 0) {
1300
+ this.localScale[this.spineIdx][1] = 1.0 + breath * 0.02;
1301
+ }
1302
+ const armSwing = Math.sin(t * 1.5) * 0.03;
1303
+ const tmpRot = new Float32Array(4);
1304
+ const deltaRot = new Float32Array(4);
1305
+ if (this.leftUpperArmIdx >= 0) {
1306
+ const a = armSwing;
1307
+ deltaRot[0] = 0;
1308
+ deltaRot[1] = 0;
1309
+ deltaRot[2] = Math.sin(a * 0.5);
1310
+ deltaRot[3] = Math.cos(a * 0.5);
1311
+ quatMul(this.localRot[this.leftUpperArmIdx], deltaRot, tmpRot);
1312
+ this.localRot[this.leftUpperArmIdx].set(tmpRot);
1313
+ }
1314
+ if (this.rightUpperArmIdx >= 0) {
1315
+ const a = -armSwing;
1316
+ deltaRot[0] = 0;
1317
+ deltaRot[1] = 0;
1318
+ deltaRot[2] = Math.sin(a * 0.5);
1319
+ deltaRot[3] = Math.cos(a * 0.5);
1320
+ quatMul(this.localRot[this.rightUpperArmIdx], deltaRot, tmpRot);
1321
+ this.localRot[this.rightUpperArmIdx].set(tmpRot);
1322
+ }
1323
+ if (this.headIdx >= 0) {
1324
+ const headSway = Math.sin(t * 0.8) * 0.03;
1325
+ deltaRot[0] = 0;
1326
+ deltaRot[1] = 0;
1327
+ deltaRot[2] = Math.sin(headSway * 0.5);
1328
+ deltaRot[3] = Math.cos(headSway * 0.5);
1329
+ quatMul(this.localRot[this.headIdx], deltaRot, tmpRot);
1330
+ this.localRot[this.headIdx].set(tmpRot);
1331
+ }
1332
+ }
1333
+ setNormalizationMatrix(mat, invMat) {
1334
+ this.normalizationMatrix = mat;
1335
+ this.inverseNormalizationMatrix = invMat;
1336
+ }
1337
+ getLocalPosFlat() { return this.localPosFlat; }
1338
+ getLocalRotFlat() { return this.localRotFlat; }
1339
+ getLocalScaleFlat() { return this.localScaleFlat; }
1340
+ getParentIndices() { return this.parentIndices; }
1341
+ getInverseBindMatricesFlat() { return this.inverseBindMatricesFlat; }
1342
+ getNormalizationMatrix() { return this.normalizationMatrix; }
1343
+ getInverseNormalizationMatrix() { return this.inverseNormalizationMatrix; }
1344
+ getBoneCount() { return this.boneCount; }
1345
+ getCurrentState() { return this.currentState; }
1346
+ getRootMotionDelta() { return this.player.getRootMotionDelta(); }
1347
+ getPlayer() { return this.player; }
1348
+ getSkeleton() { return this.skeleton; }
1349
+ onAnimationEvent(type, handler) {
1350
+ this.player.onEvent(type, handler);
1351
+ }
1352
+ offAnimationEvent(type, handler) {
1353
+ this.player.offEvent(type, handler);
1354
+ }
1355
+ getPendingAnimationEvents() {
1356
+ return this.player.getPendingEvents();
1357
+ }
1358
+ clearPendingAnimationEvents() {
1359
+ this.player.clearPendingEvents();
1360
+ }
1361
+ }