@thunderclap-engine/engine 0.0.0-stage → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (566) hide show
  1. package/CHANGELOG.md +390 -0
  2. package/LICENSE +21 -0
  3. package/README.md +333 -2
  4. package/dist/analytics/analytics.d.ts +80 -0
  5. package/dist/analytics/analytics.js +129 -0
  6. package/dist/analytics/index.d.ts +1 -0
  7. package/dist/analytics/index.js +1 -0
  8. package/dist/anim/aim.d.ts +43 -0
  9. package/dist/anim/aim.js +157 -0
  10. package/dist/anim/clip.d.ts +98 -0
  11. package/dist/anim/clip.js +282 -0
  12. package/dist/anim/compress.d.ts +65 -0
  13. package/dist/anim/compress.js +339 -0
  14. package/dist/anim/foot-ik.d.ts +74 -0
  15. package/dist/anim/foot-ik.js +241 -0
  16. package/dist/anim/graph.d.ts +153 -0
  17. package/dist/anim/graph.js +532 -0
  18. package/dist/anim/ik.d.ts +105 -0
  19. package/dist/anim/ik.js +435 -0
  20. package/dist/anim/index.d.ts +36 -0
  21. package/dist/anim/index.js +21 -0
  22. package/dist/anim/match.d.ts +66 -0
  23. package/dist/anim/match.js +153 -0
  24. package/dist/anim/mixer.d.ts +113 -0
  25. package/dist/anim/mixer.js +314 -0
  26. package/dist/anim/morph.d.ts +41 -0
  27. package/dist/anim/morph.js +94 -0
  28. package/dist/anim/pose.d.ts +74 -0
  29. package/dist/anim/pose.js +254 -0
  30. package/dist/anim/quat.d.ts +44 -0
  31. package/dist/anim/quat.js +187 -0
  32. package/dist/anim/retarget.d.ts +97 -0
  33. package/dist/anim/retarget.js +366 -0
  34. package/dist/anim/root-motion.d.ts +44 -0
  35. package/dist/anim/root-motion.js +224 -0
  36. package/dist/anim/skin-pose.d.ts +39 -0
  37. package/dist/anim/skin-pose.js +53 -0
  38. package/dist/anim/socket.d.ts +47 -0
  39. package/dist/anim/socket.js +84 -0
  40. package/dist/anim/spring-chain.d.ts +73 -0
  41. package/dist/anim/spring-chain.js +294 -0
  42. package/dist/assets/atlas.d.ts +90 -0
  43. package/dist/assets/atlas.js +212 -0
  44. package/dist/assets/baked.d.ts +33 -0
  45. package/dist/assets/baked.js +38 -0
  46. package/dist/assets/bundle.d.ts +88 -0
  47. package/dist/assets/bundle.js +464 -0
  48. package/dist/assets/cache.d.ts +56 -0
  49. package/dist/assets/cache.js +123 -0
  50. package/dist/assets/gltf-load.d.ts +252 -0
  51. package/dist/assets/gltf-load.js +661 -0
  52. package/dist/assets/gltf-skin.d.ts +36 -0
  53. package/dist/assets/gltf-skin.js +109 -0
  54. package/dist/assets/gltf.d.ts +706 -0
  55. package/dist/assets/gltf.js +1376 -0
  56. package/dist/assets/index.d.ts +20 -0
  57. package/dist/assets/index.js +10 -0
  58. package/dist/assets/ktx2.d.ts +71 -0
  59. package/dist/assets/ktx2.js +213 -0
  60. package/dist/assets/manifest.d.ts +79 -0
  61. package/dist/assets/manifest.js +7 -0
  62. package/dist/assets/meshopt.d.ts +23 -0
  63. package/dist/assets/meshopt.js +403 -0
  64. package/dist/audio/audio.d.ts +733 -0
  65. package/dist/audio/audio.js +2013 -0
  66. package/dist/audio/dsp.d.ts +61 -0
  67. package/dist/audio/dsp.js +159 -0
  68. package/dist/audio/duck.d.ts +44 -0
  69. package/dist/audio/duck.js +101 -0
  70. package/dist/audio/envelope.d.ts +53 -0
  71. package/dist/audio/envelope.js +106 -0
  72. package/dist/audio/index.d.ts +13 -0
  73. package/dist/audio/index.js +14 -0
  74. package/dist/audio/music.d.ts +113 -0
  75. package/dist/audio/music.js +548 -0
  76. package/dist/audio/occlusion.d.ts +55 -0
  77. package/dist/audio/occlusion.js +61 -0
  78. package/dist/audio/persist.d.ts +23 -0
  79. package/dist/audio/persist.js +27 -0
  80. package/dist/audio/recipes.d.ts +55 -0
  81. package/dist/audio/recipes.js +227 -0
  82. package/dist/audio/send.d.ts +41 -0
  83. package/dist/audio/send.js +118 -0
  84. package/dist/audio/sprites.d.ts +59 -0
  85. package/dist/audio/sprites.js +43 -0
  86. package/dist/audio/synth.d.ts +103 -0
  87. package/dist/audio/synth.js +197 -0
  88. package/dist/audio/variations.d.ts +25 -0
  89. package/dist/audio/variations.js +55 -0
  90. package/dist/audio/zones.d.ts +100 -0
  91. package/dist/audio/zones.js +167 -0
  92. package/dist/core/detached-surface.d.ts +44 -0
  93. package/dist/core/detached-surface.js +104 -0
  94. package/dist/core/events.d.ts +24 -0
  95. package/dist/core/events.js +43 -0
  96. package/dist/core/game.d.ts +409 -0
  97. package/dist/core/game.js +530 -0
  98. package/dist/core/hash.d.ts +24 -0
  99. package/dist/core/hash.js +49 -0
  100. package/dist/core/index.d.ts +17 -0
  101. package/dist/core/index.js +9 -0
  102. package/dist/core/loop.d.ts +113 -0
  103. package/dist/core/loop.js +185 -0
  104. package/dist/core/math.d.ts +58 -0
  105. package/dist/core/math.js +210 -0
  106. package/dist/core/noise.d.ts +40 -0
  107. package/dist/core/noise.js +247 -0
  108. package/dist/core/pool.d.ts +42 -0
  109. package/dist/core/pool.js +85 -0
  110. package/dist/core/random.d.ts +61 -0
  111. package/dist/core/random.js +199 -0
  112. package/dist/core/scene.d.ts +79 -0
  113. package/dist/core/scene.js +195 -0
  114. package/dist/core/timer.d.ts +66 -0
  115. package/dist/core/timer.js +286 -0
  116. package/dist/fx/billboard-wgsl.d.ts +29 -0
  117. package/dist/fx/billboard-wgsl.js +158 -0
  118. package/dist/fx/billboard.d.ts +249 -0
  119. package/dist/fx/billboard.js +702 -0
  120. package/dist/fx/debug-draw.d.ts +127 -0
  121. package/dist/fx/debug-draw.js +523 -0
  122. package/dist/fx/debug-wgsl.d.ts +7 -0
  123. package/dist/fx/debug-wgsl.js +32 -0
  124. package/dist/fx/decals-wgsl.d.ts +15 -0
  125. package/dist/fx/decals-wgsl.js +173 -0
  126. package/dist/fx/decals.d.ts +216 -0
  127. package/dist/fx/decals.js +607 -0
  128. package/dist/fx/effect.d.ts +129 -0
  129. package/dist/fx/effect.js +349 -0
  130. package/dist/fx/effects/hit-spark.json +48 -0
  131. package/dist/fx/effects/index.d.ts +8 -0
  132. package/dist/fx/effects/index.js +9 -0
  133. package/dist/fx/effects/magic-aura.json +47 -0
  134. package/dist/fx/effects/smoke-puff.json +34 -0
  135. package/dist/fx/emit-surface.d.ts +40 -0
  136. package/dist/fx/emit-surface.js +124 -0
  137. package/dist/fx/flicker.d.ts +30 -0
  138. package/dist/fx/flicker.js +42 -0
  139. package/dist/fx/index.d.ts +31 -0
  140. package/dist/fx/index.js +20 -0
  141. package/dist/fx/particles-wgsl.d.ts +57 -0
  142. package/dist/fx/particles-wgsl.js +828 -0
  143. package/dist/fx/particles.d.ts +566 -0
  144. package/dist/fx/particles.js +1533 -0
  145. package/dist/fx/random.d.ts +15 -0
  146. package/dist/fx/random.js +20 -0
  147. package/dist/fx/sky-wgsl.d.ts +23 -0
  148. package/dist/fx/sky-wgsl.js +127 -0
  149. package/dist/fx/sky.d.ts +96 -0
  150. package/dist/fx/sky.js +175 -0
  151. package/dist/fx/text-atlas.d.ts +143 -0
  152. package/dist/fx/text-atlas.js +327 -0
  153. package/dist/fx/trail-wgsl.d.ts +11 -0
  154. package/dist/fx/trail-wgsl.js +42 -0
  155. package/dist/fx/trail.d.ts +194 -0
  156. package/dist/fx/trail.js +555 -0
  157. package/dist/fx/water-wgsl.d.ts +34 -0
  158. package/dist/fx/water-wgsl.js +197 -0
  159. package/dist/fx/water.d.ts +176 -0
  160. package/dist/fx/water.js +371 -0
  161. package/dist/geom/collide/bvh.d.ts +151 -0
  162. package/dist/geom/collide/bvh.js +493 -0
  163. package/dist/geom/collide/debug.d.ts +14 -0
  164. package/dist/geom/collide/debug.js +74 -0
  165. package/dist/geom/collide/grid.d.ts +26 -0
  166. package/dist/geom/collide/grid.js +91 -0
  167. package/dist/geom/collide/index.d.ts +8 -0
  168. package/dist/geom/collide/index.js +8 -0
  169. package/dist/geom/collide/queries.d.ts +70 -0
  170. package/dist/geom/collide/queries.js +583 -0
  171. package/dist/geom/collide/serialize.d.ts +14 -0
  172. package/dist/geom/collide/serialize.js +145 -0
  173. package/dist/geom/collide/shapes.d.ts +161 -0
  174. package/dist/geom/collide/shapes.js +686 -0
  175. package/dist/geom/collide/slide.d.ts +66 -0
  176. package/dist/geom/collide/slide.js +375 -0
  177. package/dist/geom/collide/tile-slide.d.ts +88 -0
  178. package/dist/geom/collide/tile-slide.js +255 -0
  179. package/dist/geom/geometry.d.ts +95 -0
  180. package/dist/geom/geometry.js +322 -0
  181. package/dist/geom/heightfield.d.ts +72 -0
  182. package/dist/geom/heightfield.js +295 -0
  183. package/dist/geom/hull.d.ts +27 -0
  184. package/dist/geom/hull.js +279 -0
  185. package/dist/geom/index.d.ts +35 -0
  186. package/dist/geom/index.js +23 -0
  187. package/dist/geom/iso.d.ts +74 -0
  188. package/dist/geom/iso.js +89 -0
  189. package/dist/geom/lod.d.ts +29 -0
  190. package/dist/geom/lod.js +27 -0
  191. package/dist/geom/ops.d.ts +47 -0
  192. package/dist/geom/ops.js +285 -0
  193. package/dist/geom/primitives.d.ts +97 -0
  194. package/dist/geom/primitives.js +359 -0
  195. package/dist/geom/shapes.d.ts +43 -0
  196. package/dist/geom/shapes.js +88 -0
  197. package/dist/geom/simplify.d.ts +38 -0
  198. package/dist/geom/simplify.js +519 -0
  199. package/dist/geom/split.d.ts +37 -0
  200. package/dist/geom/split.js +413 -0
  201. package/dist/geom/sweep.d.ts +83 -0
  202. package/dist/geom/sweep.js +534 -0
  203. package/dist/geom/tangents.d.ts +16 -0
  204. package/dist/geom/tangents.js +124 -0
  205. package/dist/geom/triangulate.d.ts +19 -0
  206. package/dist/geom/triangulate.js +147 -0
  207. package/dist/host/default.d.ts +10 -0
  208. package/dist/host/default.js +10 -0
  209. package/dist/host/index.d.ts +4 -0
  210. package/dist/host/index.js +3 -0
  211. package/dist/host/types.d.ts +144 -0
  212. package/dist/host/types.js +1 -0
  213. package/dist/host/web-links.d.ts +38 -0
  214. package/dist/host/web-links.js +110 -0
  215. package/dist/host/web.d.ts +30 -0
  216. package/dist/host/web.js +216 -0
  217. package/dist/host/xr.d.ts +24 -0
  218. package/dist/host/xr.js +59 -0
  219. package/dist/i18n/i18n.d.ts +59 -0
  220. package/dist/i18n/i18n.js +241 -0
  221. package/dist/i18n/index.d.ts +3 -0
  222. package/dist/i18n/index.js +3 -0
  223. package/dist/i18n/message.d.ts +72 -0
  224. package/dist/i18n/message.js +369 -0
  225. package/dist/i18n/negotiate.d.ts +17 -0
  226. package/dist/i18n/negotiate.js +58 -0
  227. package/dist/index.d.ts +7 -0
  228. package/dist/index.js +1 -0
  229. package/dist/input/bindings.d.ts +31 -0
  230. package/dist/input/bindings.js +141 -0
  231. package/dist/input/clock.d.ts +44 -0
  232. package/dist/input/clock.js +49 -0
  233. package/dist/input/follow.d.ts +133 -0
  234. package/dist/input/follow.js +218 -0
  235. package/dist/input/gestures.d.ts +281 -0
  236. package/dist/input/gestures.js +662 -0
  237. package/dist/input/glyphs.d.ts +35 -0
  238. package/dist/input/glyphs.js +216 -0
  239. package/dist/input/gyro.d.ts +85 -0
  240. package/dist/input/gyro.js +140 -0
  241. package/dist/input/index.d.ts +19 -0
  242. package/dist/input/index.js +16 -0
  243. package/dist/input/input.d.ts +543 -0
  244. package/dist/input/input.js +1492 -0
  245. package/dist/input/look.d.ts +327 -0
  246. package/dist/input/look.js +681 -0
  247. package/dist/input/magnify.d.ts +177 -0
  248. package/dist/input/magnify.js +131 -0
  249. package/dist/input/pointer-dispatch.d.ts +138 -0
  250. package/dist/input/pointer-dispatch.js +180 -0
  251. package/dist/input/pointer-router.d.ts +204 -0
  252. package/dist/input/pointer-router.js +533 -0
  253. package/dist/input/pointer-sources.d.ts +164 -0
  254. package/dist/input/pointer-sources.js +306 -0
  255. package/dist/input/rays.d.ts +138 -0
  256. package/dist/input/rays.js +615 -0
  257. package/dist/input/record.d.ts +209 -0
  258. package/dist/input/record.js +601 -0
  259. package/dist/input/touch-zones.d.ts +147 -0
  260. package/dist/input/touch-zones.js +300 -0
  261. package/dist/input/types.d.ts +158 -0
  262. package/dist/input/types.js +1 -0
  263. package/dist/input/xr-source.d.ts +53 -0
  264. package/dist/input/xr-source.js +164 -0
  265. package/dist/nav/astar.d.ts +45 -0
  266. package/dist/nav/astar.js +182 -0
  267. package/dist/nav/corridor.d.ts +40 -0
  268. package/dist/nav/corridor.js +95 -0
  269. package/dist/nav/crowd.d.ts +94 -0
  270. package/dist/nav/crowd.js +624 -0
  271. package/dist/nav/flow.d.ts +61 -0
  272. package/dist/nav/flow.js +193 -0
  273. package/dist/nav/grid.d.ts +108 -0
  274. package/dist/nav/grid.js +210 -0
  275. package/dist/nav/heap.d.ts +22 -0
  276. package/dist/nav/heap.js +92 -0
  277. package/dist/nav/index.d.ts +37 -0
  278. package/dist/nav/index.js +19 -0
  279. package/dist/nav/mesh/areas.d.ts +44 -0
  280. package/dist/nav/mesh/areas.js +98 -0
  281. package/dist/nav/mesh/bake-options.d.ts +33 -0
  282. package/dist/nav/mesh/bake-options.js +76 -0
  283. package/dist/nav/mesh/contour.d.ts +22 -0
  284. package/dist/nav/mesh/contour.js +323 -0
  285. package/dist/nav/mesh/flow3.d.ts +35 -0
  286. package/dist/nav/mesh/flow3.js +229 -0
  287. package/dist/nav/mesh/links.d.ts +38 -0
  288. package/dist/nav/mesh/links.js +72 -0
  289. package/dist/nav/mesh/mesh-path.d.ts +152 -0
  290. package/dist/nav/mesh/mesh-path.js +643 -0
  291. package/dist/nav/mesh/mesh-reach.d.ts +78 -0
  292. package/dist/nav/mesh/mesh-reach.js +450 -0
  293. package/dist/nav/mesh/navmesh.d.ts +117 -0
  294. package/dist/nav/mesh/navmesh.js +647 -0
  295. package/dist/nav/mesh/polymesh.d.ts +24 -0
  296. package/dist/nav/mesh/polymesh.js +384 -0
  297. package/dist/nav/mesh/regions.d.ts +12 -0
  298. package/dist/nav/mesh/regions.js +367 -0
  299. package/dist/nav/mesh/serialize.d.ts +13 -0
  300. package/dist/nav/mesh/serialize.js +197 -0
  301. package/dist/nav/mesh/voxelize.d.ts +111 -0
  302. package/dist/nav/mesh/voxelize.js +552 -0
  303. package/dist/nav/obstacles.d.ts +75 -0
  304. package/dist/nav/obstacles.js +294 -0
  305. package/dist/nav/path.d.ts +59 -0
  306. package/dist/nav/path.js +177 -0
  307. package/dist/nav/query-queue.d.ts +46 -0
  308. package/dist/nav/query-queue.js +308 -0
  309. package/dist/nav/reach.d.ts +53 -0
  310. package/dist/nav/reach.js +148 -0
  311. package/dist/nav/steer.d.ts +36 -0
  312. package/dist/nav/steer.js +78 -0
  313. package/dist/platform/boot.d.ts +28 -0
  314. package/dist/platform/boot.js +43 -0
  315. package/dist/platform/device-mode.d.ts +40 -0
  316. package/dist/platform/device-mode.js +104 -0
  317. package/dist/platform/device.d.ts +31 -0
  318. package/dist/platform/device.js +91 -0
  319. package/dist/platform/environment.d.ts +42 -0
  320. package/dist/platform/environment.js +82 -0
  321. package/dist/platform/gpu.d.ts +40 -0
  322. package/dist/platform/gpu.js +57 -0
  323. package/dist/platform/index.d.ts +18 -0
  324. package/dist/platform/index.js +10 -0
  325. package/dist/platform/letterbox.d.ts +43 -0
  326. package/dist/platform/letterbox.js +57 -0
  327. package/dist/platform/links.d.ts +20 -0
  328. package/dist/platform/links.js +43 -0
  329. package/dist/platform/screens.d.ts +36 -0
  330. package/dist/platform/screens.js +138 -0
  331. package/dist/platform/surface.d.ts +72 -0
  332. package/dist/platform/surface.js +157 -0
  333. package/dist/platform/xr-fake.d.ts +168 -0
  334. package/dist/platform/xr-fake.js +434 -0
  335. package/dist/platform/xr-surface.d.ts +120 -0
  336. package/dist/platform/xr-surface.js +214 -0
  337. package/dist/platform/xr-types.d.ts +262 -0
  338. package/dist/post/ao.d.ts +12 -0
  339. package/dist/post/ao.js +136 -0
  340. package/dist/post/blend.d.ts +27 -0
  341. package/dist/post/blend.js +129 -0
  342. package/dist/post/depth-pass.d.ts +43 -0
  343. package/dist/post/depth-pass.js +118 -0
  344. package/dist/post/dof.d.ts +1 -0
  345. package/dist/post/dof.js +66 -0
  346. package/dist/post/exposure.d.ts +80 -0
  347. package/dist/post/exposure.js +322 -0
  348. package/dist/post/index.d.ts +12 -0
  349. package/dist/post/index.js +11 -0
  350. package/dist/post/lens-dirt.d.ts +13 -0
  351. package/dist/post/lens-dirt.js +91 -0
  352. package/dist/post/lut.d.ts +19 -0
  353. package/dist/post/lut.js +50 -0
  354. package/dist/post/motion-blur.d.ts +9 -0
  355. package/dist/post/motion-blur.js +78 -0
  356. package/dist/post/post-stack.d.ts +302 -0
  357. package/dist/post/post-stack.js +1137 -0
  358. package/dist/post/settings.d.ts +485 -0
  359. package/dist/post/settings.js +416 -0
  360. package/dist/post/shaders.d.ts +25 -0
  361. package/dist/post/shaders.js +410 -0
  362. package/dist/post/ssr.d.ts +16 -0
  363. package/dist/post/ssr.js +155 -0
  364. package/dist/post/taa.d.ts +74 -0
  365. package/dist/post/taa.js +235 -0
  366. package/dist/post/white-balance.d.ts +25 -0
  367. package/dist/post/white-balance.js +98 -0
  368. package/dist/render/bindings.d.ts +98 -0
  369. package/dist/render/bindings.js +281 -0
  370. package/dist/render/blend.d.ts +13 -0
  371. package/dist/render/blend.js +26 -0
  372. package/dist/render/camera-2d.d.ts +72 -0
  373. package/dist/render/camera-2d.js +92 -0
  374. package/dist/render/camera.d.ts +302 -0
  375. package/dist/render/camera.js +671 -0
  376. package/dist/render/color.d.ts +16 -0
  377. package/dist/render/color.js +41 -0
  378. package/dist/render/compressed.d.ts +104 -0
  379. package/dist/render/compressed.js +248 -0
  380. package/dist/render/diagnostics.d.ts +15 -0
  381. package/dist/render/diagnostics.js +43 -0
  382. package/dist/render/dynamic-resolution.d.ts +70 -0
  383. package/dist/render/dynamic-resolution.js +126 -0
  384. package/dist/render/fake-gpu.d.ts +204 -0
  385. package/dist/render/fake-gpu.js +426 -0
  386. package/dist/render/flipbook.d.ts +56 -0
  387. package/dist/render/flipbook.js +87 -0
  388. package/dist/render/frame.d.ts +278 -0
  389. package/dist/render/frame.js +174 -0
  390. package/dist/render/fullscreen.d.ts +54 -0
  391. package/dist/render/fullscreen.js +91 -0
  392. package/dist/render/gpu-timer.d.ts +73 -0
  393. package/dist/render/gpu-timer.js +186 -0
  394. package/dist/render/index.d.ts +53 -0
  395. package/dist/render/index.js +29 -0
  396. package/dist/render/instance-list.d.ts +185 -0
  397. package/dist/render/instance-list.js +547 -0
  398. package/dist/render/lights.d.ts +181 -0
  399. package/dist/render/lights.js +233 -0
  400. package/dist/render/lod.d.ts +54 -0
  401. package/dist/render/lod.js +52 -0
  402. package/dist/render/material.d.ts +165 -0
  403. package/dist/render/material.js +292 -0
  404. package/dist/render/mesh.d.ts +284 -0
  405. package/dist/render/mesh.js +472 -0
  406. package/dist/render/mipmap.d.ts +16 -0
  407. package/dist/render/mipmap.js +121 -0
  408. package/dist/render/parallax.d.ts +50 -0
  409. package/dist/render/parallax.js +47 -0
  410. package/dist/render/pbr-wgsl.d.ts +31 -0
  411. package/dist/render/pbr-wgsl.js +119 -0
  412. package/dist/render/ping-pong.d.ts +42 -0
  413. package/dist/render/ping-pong.js +74 -0
  414. package/dist/render/renderer.d.ts +741 -0
  415. package/dist/render/renderer.js +2486 -0
  416. package/dist/render/scene-pipelines.d.ts +44 -0
  417. package/dist/render/scene-pipelines.js +92 -0
  418. package/dist/render/scene-target.d.ts +170 -0
  419. package/dist/render/scene-target.js +450 -0
  420. package/dist/render/shadow.d.ts +74 -0
  421. package/dist/render/shadow.js +208 -0
  422. package/dist/render/skin.d.ts +112 -0
  423. package/dist/render/skin.js +240 -0
  424. package/dist/render/snapshot.d.ts +36 -0
  425. package/dist/render/snapshot.js +34 -0
  426. package/dist/render/standard.d.ts +162 -0
  427. package/dist/render/standard.js +263 -0
  428. package/dist/render/texture.d.ts +142 -0
  429. package/dist/render/texture.js +228 -0
  430. package/dist/render/tile-layer.d.ts +110 -0
  431. package/dist/render/tile-layer.js +304 -0
  432. package/dist/render/transform.d.ts +115 -0
  433. package/dist/render/transform.js +318 -0
  434. package/dist/render/wgsl.d.ts +131 -0
  435. package/dist/render/wgsl.js +528 -0
  436. package/dist/save/codec.d.ts +49 -0
  437. package/dist/save/codec.js +169 -0
  438. package/dist/save/index.d.ts +8 -0
  439. package/dist/save/index.js +8 -0
  440. package/dist/save/journal.d.ts +24 -0
  441. package/dist/save/journal.js +102 -0
  442. package/dist/save/migrate.d.ts +15 -0
  443. package/dist/save/migrate.js +37 -0
  444. package/dist/save/schema.d.ts +72 -0
  445. package/dist/save/schema.js +154 -0
  446. package/dist/save/settings.d.ts +28 -0
  447. package/dist/save/settings.js +59 -0
  448. package/dist/save/slots.d.ts +56 -0
  449. package/dist/save/slots.js +200 -0
  450. package/dist/save/storage.d.ts +35 -0
  451. package/dist/save/storage.js +62 -0
  452. package/dist/save/store.d.ts +114 -0
  453. package/dist/save/store.js +269 -0
  454. package/dist/testing/fake-host.d.ts +103 -0
  455. package/dist/testing/fake-host.js +163 -0
  456. package/dist/testing/fixed-clock.d.ts +25 -0
  457. package/dist/testing/fixed-clock.js +30 -0
  458. package/dist/testing/index.d.ts +4 -0
  459. package/dist/testing/index.js +5 -0
  460. package/dist/testing/test-game.d.ts +76 -0
  461. package/dist/testing/test-game.js +92 -0
  462. package/dist/tween/ease.d.ts +77 -0
  463. package/dist/tween/ease.js +192 -0
  464. package/dist/tween/index.d.ts +8 -0
  465. package/dist/tween/index.js +7 -0
  466. package/dist/tween/timeline.d.ts +78 -0
  467. package/dist/tween/timeline.js +269 -0
  468. package/dist/tween/tween.d.ts +168 -0
  469. package/dist/tween/tween.js +320 -0
  470. package/dist/ui/anchor.d.ts +206 -0
  471. package/dist/ui/anchor.js +307 -0
  472. package/dist/ui/caption.d.ts +122 -0
  473. package/dist/ui/caption.js +286 -0
  474. package/dist/ui/cursor.d.ts +105 -0
  475. package/dist/ui/cursor.js +261 -0
  476. package/dist/ui/dom.d.ts +30 -0
  477. package/dist/ui/dom.js +92 -0
  478. package/dist/ui/floats.d.ts +86 -0
  479. package/dist/ui/floats.js +260 -0
  480. package/dist/ui/hud.d.ts +198 -0
  481. package/dist/ui/hud.js +431 -0
  482. package/dist/ui/index.d.ts +37 -0
  483. package/dist/ui/index.js +34 -0
  484. package/dist/ui/inventory-card.d.ts +52 -0
  485. package/dist/ui/inventory-card.js +173 -0
  486. package/dist/ui/inventory-context.d.ts +29 -0
  487. package/dist/ui/inventory-context.js +125 -0
  488. package/dist/ui/inventory-drag.d.ts +63 -0
  489. package/dist/ui/inventory-drag.js +394 -0
  490. package/dist/ui/inventory-grid.d.ts +66 -0
  491. package/dist/ui/inventory-grid.js +625 -0
  492. package/dist/ui/inventory-radial.d.ts +39 -0
  493. package/dist/ui/inventory-radial.js +168 -0
  494. package/dist/ui/inventory.d.ts +128 -0
  495. package/dist/ui/inventory.js +154 -0
  496. package/dist/ui/layout.d.ts +356 -0
  497. package/dist/ui/layout.js +856 -0
  498. package/dist/ui/link.d.ts +64 -0
  499. package/dist/ui/link.js +155 -0
  500. package/dist/ui/loading.d.ts +40 -0
  501. package/dist/ui/loading.js +157 -0
  502. package/dist/ui/loupe.d.ts +74 -0
  503. package/dist/ui/loupe.js +164 -0
  504. package/dist/ui/menu-nav.d.ts +33 -0
  505. package/dist/ui/menu-nav.js +28 -0
  506. package/dist/ui/minimap-canvas.d.ts +145 -0
  507. package/dist/ui/minimap-canvas.js +460 -0
  508. package/dist/ui/notify.d.ts +40 -0
  509. package/dist/ui/notify.js +141 -0
  510. package/dist/ui/orb.d.ts +53 -0
  511. package/dist/ui/orb.js +304 -0
  512. package/dist/ui/overlay.d.ts +213 -0
  513. package/dist/ui/overlay.js +394 -0
  514. package/dist/ui/padnav.d.ts +53 -0
  515. package/dist/ui/padnav.js +146 -0
  516. package/dist/ui/perf.d.ts +130 -0
  517. package/dist/ui/perf.js +329 -0
  518. package/dist/ui/rotate-card.d.ts +54 -0
  519. package/dist/ui/rotate-card.js +97 -0
  520. package/dist/ui/stack.d.ts +128 -0
  521. package/dist/ui/stack.js +312 -0
  522. package/dist/ui/styles.d.ts +13 -0
  523. package/dist/ui/styles.js +200 -0
  524. package/dist/ui/text-scale.d.ts +67 -0
  525. package/dist/ui/text-scale.js +102 -0
  526. package/dist/ui/theme.d.ts +70 -0
  527. package/dist/ui/theme.js +98 -0
  528. package/dist/ui/toast.d.ts +23 -0
  529. package/dist/ui/toast.js +46 -0
  530. package/dist/ui/tooltip.d.ts +89 -0
  531. package/dist/ui/tooltip.js +333 -0
  532. package/dist/ui/widgets-2.d.ts +134 -0
  533. package/dist/ui/widgets-2.js +399 -0
  534. package/dist/ui/widgets-3.d.ts +91 -0
  535. package/dist/ui/widgets-3.js +212 -0
  536. package/dist/ui/widgets.d.ts +34 -0
  537. package/dist/ui/widgets.js +50 -0
  538. package/dist/ui/world-panel/index.d.ts +5 -0
  539. package/dist/ui/world-panel/index.js +5 -0
  540. package/dist/ui/world-panel/layout.d.ts +38 -0
  541. package/dist/ui/world-panel/layout.js +68 -0
  542. package/dist/ui/world-panel/paint.d.ts +96 -0
  543. package/dist/ui/world-panel/paint.js +136 -0
  544. package/dist/ui/world-panel/panel.d.ts +235 -0
  545. package/dist/ui/world-panel/panel.js +762 -0
  546. package/dist/ui/world-panel/wgsl.d.ts +10 -0
  547. package/dist/ui/world-panel/wgsl.js +52 -0
  548. package/dist/ui/world-panel/widgets.d.ts +207 -0
  549. package/dist/ui/world-panel/widgets.js +569 -0
  550. package/dist/voxel/chunks.d.ts +77 -0
  551. package/dist/voxel/chunks.js +149 -0
  552. package/dist/voxel/grid.d.ts +84 -0
  553. package/dist/voxel/grid.js +223 -0
  554. package/dist/voxel/index.d.ts +22 -0
  555. package/dist/voxel/index.js +7 -0
  556. package/dist/voxel/mesher-worker.d.ts +14 -0
  557. package/dist/voxel/mesher-worker.js +47 -0
  558. package/dist/voxel/mesher.d.ts +73 -0
  559. package/dist/voxel/mesher.js +306 -0
  560. package/dist/voxel/ray.d.ts +32 -0
  561. package/dist/voxel/ray.js +73 -0
  562. package/dist/voxel/wgsl.d.ts +16 -0
  563. package/dist/voxel/wgsl.js +28 -0
  564. package/dist/voxel/worker-client.d.ts +79 -0
  565. package/dist/voxel/worker-client.js +122 -0
  566. package/package.json +177 -3
@@ -0,0 +1,43 @@
1
+ import { type Pose, type Skeleton } from './pose.js';
2
+ export interface AimOffsetDesc {
3
+ /** Joints from the base of the chain to the one that aims (the head), ancestors first. */
4
+ joints: ArrayLike<number>;
5
+ /** Share of the turn per joint, normalised to sum 1. Default: equal shares. */
6
+ weights?: ArrayLike<number>;
7
+ /** Largest yaw (radians) either way. Default `Math.PI / 2`. */
8
+ maxYaw?: number;
9
+ /** Largest pitch (radians) either way. Default `Math.PI / 3`. */
10
+ maxPitch?: number;
11
+ /** The aiming joint's local axis that should point at the target. Default `[0, 0, 1]`. */
12
+ forward?: ArrayLike<number>;
13
+ /** Skeleton-space up: yaw turns about it, pitch about the side axis. Default `[0, 1, 0]`. */
14
+ up?: ArrayLike<number>;
15
+ }
16
+ export interface AimOffsetOptions {
17
+ /** 0..1 blend against the sampled rotations. Default 1. */
18
+ weight?: number;
19
+ }
20
+ /** An aim chain with its scratch, from `createAimOffset`; `yaw`/`pitch` are the last applied. */
21
+ export interface AimOffset {
22
+ readonly joints: Int16Array;
23
+ readonly weights: Float32Array;
24
+ readonly maxYaw: number;
25
+ readonly maxPitch: number;
26
+ readonly forward: Float32Array;
27
+ readonly up: Float32Array;
28
+ /** The clamped yaw of the last `applyAimOffset` (radians, + toward the side axis). */
29
+ yaw: number;
30
+ /** The clamped pitch of the last `applyAimOffset` (radians, + toward `up`). */
31
+ pitch: number;
32
+ /** @internal the input local rotations per joint (for `weight`). */
33
+ readonly saved: Float32Array;
34
+ }
35
+ /** Validate and allocate an aim chain; call once. Weights are normalised to sum 1. */
36
+ export declare function createAimOffset(skeleton: Skeleton, desc: AimOffsetDesc): AimOffset;
37
+ /**
38
+ * Turn the chain of `aim` so the last joint's forward points at `targetWorld`, yaw and pitch
39
+ * each clamped, the turn shared by the joints' weights. The pivot is the last joint; the
40
+ * reference forward is that joint's as sampled (an aim offset of zero leaves the pose as it
41
+ * is). `weight` slerps every joint against its sampled rotation. No allocation.
42
+ */
43
+ export declare function applyAimOffset(pose: Pose, skeleton: Skeleton, worldPose: Float32Array, aim: AimOffset, targetWorld: ArrayLike<number>, instanceWorld: Float32Array | null, opts?: AimOffsetOptions): void;
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Aim offset: a multi-joint `lookAt`. The yaw and pitch from the last joint's forward axis
3
+ * toward a world target are clamped, then spread across a chain (spine, spine, head) by
4
+ * weight, additive on top of the sampled pose. Rotations about one skeleton-space axis add
5
+ * exactly, so the chain's summed turn reaches the clamped target. Same conventions as `ik.ts`:
6
+ * reads `worldPose` (the sampled pose's world matrices), writes local rotations into `pose`;
7
+ * `instanceWorld` is the 3×4 instance matrix or `null` for skeleton-space targets. Allocates
8
+ * in `createAimOffset`, nothing per call.
9
+ */
10
+ import { anyPerpendicular, applyDelta, IDENTITY, normalize, rotateByQuat, toSkeleton, transformDir, } from './ik.js';
11
+ import { POSE_NODE_FLOATS, WORLD_NODE_FLOATS } from './pose.js';
12
+ import { quatFromAxisAngle, quatMultiply, quatNormalize, quatSlerp } from './quat.js';
13
+ const EPS = 1e-6;
14
+ /** Validate and allocate an aim chain; call once. Weights are normalised to sum 1. */
15
+ export function createAimOffset(skeleton, desc) {
16
+ const n = skeleton.parents.length;
17
+ const joints = Int16Array.from(desc.joints);
18
+ if (joints.length === 0)
19
+ throw new Error('AimOffset: at least one joint');
20
+ for (let i = 0; i < joints.length; i++) {
21
+ const j = joints[i];
22
+ if (j < 0 || j >= n)
23
+ throw new Error(`AimOffset: joint ${j} must be in [0, ${n})`);
24
+ if (i > 0) {
25
+ // Each joint descends from the one before it.
26
+ let p = skeleton.parents[j];
27
+ while (p >= 0 && p !== joints[i - 1])
28
+ p = skeleton.parents[p];
29
+ if (p < 0)
30
+ throw new Error(`AimOffset: joint ${j} does not descend from ${joints[i - 1]}`);
31
+ }
32
+ }
33
+ const weights = new Float32Array(joints.length);
34
+ let sum = 0;
35
+ for (let i = 0; i < joints.length; i++) {
36
+ const w = desc.weights ? desc.weights[i] : 1;
37
+ if (w === undefined || w < 0)
38
+ throw new Error(`AimOffset: weight ${i} must be >= 0`);
39
+ weights[i] = w;
40
+ sum += w;
41
+ }
42
+ if (sum <= 0)
43
+ throw new Error('AimOffset: weights sum to 0');
44
+ for (let i = 0; i < weights.length; i++)
45
+ weights[i] = weights[i] / sum;
46
+ const forward = Float32Array.from(desc.forward ?? [0, 0, 1]);
47
+ const up = Float32Array.from(desc.up ?? [0, 1, 0]);
48
+ if (normalize(forward) <= EPS || normalize(up) <= EPS)
49
+ throw new Error('AimOffset: forward and up must be non-zero');
50
+ return {
51
+ joints,
52
+ weights,
53
+ maxYaw: desc.maxYaw ?? Math.PI / 2,
54
+ maxPitch: desc.maxPitch ?? Math.PI / 3,
55
+ forward,
56
+ up,
57
+ yaw: 0,
58
+ pitch: 0,
59
+ saved: new Float32Array(joints.length * 4),
60
+ };
61
+ }
62
+ const tgt = new Float32Array(3);
63
+ const fwd = new Float32Array(3);
64
+ const dir = new Float32Array(3);
65
+ const side = new Float32Array(3);
66
+ const flat = new Float32Array(3);
67
+ const qy = new Float32Array(4);
68
+ const qp = new Float32Array(4);
69
+ const q = new Float32Array(4);
70
+ const delta = new Float32Array(4);
71
+ /**
72
+ * Turn the chain of `aim` so the last joint's forward points at `targetWorld`, yaw and pitch
73
+ * each clamped, the turn shared by the joints' weights. The pivot is the last joint; the
74
+ * reference forward is that joint's as sampled (an aim offset of zero leaves the pose as it
75
+ * is). `weight` slerps every joint against its sampled rotation. No allocation.
76
+ */
77
+ export function applyAimOffset(pose, skeleton, worldPose, aim, targetWorld, instanceWorld, opts) {
78
+ const weight = opts?.weight ?? 1;
79
+ aim.yaw = 0;
80
+ aim.pitch = 0;
81
+ if (weight <= 0)
82
+ return;
83
+ const joints = aim.joints;
84
+ const head = joints[joints.length - 1];
85
+ const wo = head * WORLD_NODE_FLOATS;
86
+ toSkeleton(tgt, targetWorld, instanceWorld);
87
+ transformDir(fwd, worldPose, wo, aim.forward);
88
+ if (normalize(fwd) <= EPS)
89
+ return;
90
+ dir[0] = tgt[0] - worldPose[wo + 3];
91
+ dir[1] = tgt[1] - worldPose[wo + 7];
92
+ dir[2] = tgt[2] - worldPose[wo + 11];
93
+ if (normalize(dir) <= EPS)
94
+ return;
95
+ // A frame from up and the sampled forward: `flat` is forward levelled, `side` = up × flat.
96
+ const up = aim.up;
97
+ const fu = fwd[0] * up[0] + fwd[1] * up[1] + fwd[2] * up[2];
98
+ flat[0] = fwd[0] - up[0] * fu;
99
+ flat[1] = fwd[1] - up[1] * fu;
100
+ flat[2] = fwd[2] - up[2] * fu;
101
+ if (normalize(flat) <= EPS)
102
+ anyPerpendicular(flat, up);
103
+ side[0] = up[1] * flat[2] - up[2] * flat[1];
104
+ side[1] = up[2] * flat[0] - up[0] * flat[2];
105
+ side[2] = up[0] * flat[1] - up[1] * flat[0];
106
+ normalize(side);
107
+ // Yaw and pitch of the target direction relative to the sampled forward.
108
+ const dFlat = dir[0] * flat[0] + dir[1] * flat[1] + dir[2] * flat[2];
109
+ const dSide = dir[0] * side[0] + dir[1] * side[1] + dir[2] * side[2];
110
+ const dUp = dir[0] * up[0] + dir[1] * up[1] + dir[2] * up[2];
111
+ const fFlat = Math.hypot(flat[0] * fu - fwd[0], flat[1] * fu - fwd[1], flat[2] * fu - fwd[2]);
112
+ let yaw = Math.atan2(dSide, dFlat);
113
+ let pitch = Math.atan2(dUp, Math.hypot(dFlat, dSide)) - Math.atan2(fu, fFlat);
114
+ if (pitch > Math.PI)
115
+ pitch -= 2 * Math.PI;
116
+ if (pitch < -Math.PI)
117
+ pitch += 2 * Math.PI;
118
+ const maxYaw = Math.max(0, aim.maxYaw);
119
+ const maxPitch = Math.max(0, aim.maxPitch);
120
+ yaw = Math.min(maxYaw, Math.max(-maxYaw, yaw));
121
+ pitch = Math.min(maxPitch, Math.max(-maxPitch, pitch));
122
+ aim.yaw = yaw;
123
+ aim.pitch = pitch;
124
+ if (yaw === 0 && pitch === 0)
125
+ return;
126
+ // One rotation: pitch about the yawed side axis after yaw about up (q = qp · qy). A positive
127
+ // turn about `side = up × flat` lowers the forward, so pitch goes in negated.
128
+ quatFromAxisAngle(qy, 0, up[0], up[1], up[2], yaw);
129
+ rotateByQuat(side, qy, 0);
130
+ quatFromAxisAngle(qp, 0, side[0], side[1], side[2], -pitch);
131
+ quatMultiply(q, 0, qp, 0, qy, 0);
132
+ quatNormalize(q, 0);
133
+ const w = q[3];
134
+ const s = Math.sqrt(Math.max(0, 1 - w * w));
135
+ if (s <= EPS)
136
+ return;
137
+ delta[0] = q[0] / s;
138
+ delta[1] = q[1] / s;
139
+ delta[2] = q[2] / s;
140
+ const angle = 2 * Math.atan2(s, w);
141
+ // Share the angle out along the chain. The joints below the first rotate with it, so each
142
+ // delta is taken against the parent's sampled matrix (the axis is the same for all).
143
+ for (let i = 0; i < joints.length; i++) {
144
+ const j = joints[i];
145
+ const o = j * POSE_NODE_FLOATS + 3;
146
+ for (let c = 0; c < 4; c++)
147
+ aim.saved[i * 4 + c] = pose[o + c];
148
+ delta[3] = angle * aim.weights[i];
149
+ const parent = skeleton.parents[j];
150
+ if (parent < 0)
151
+ applyDelta(pose, j, delta, IDENTITY, 0, null);
152
+ else
153
+ applyDelta(pose, j, delta, worldPose, parent * WORLD_NODE_FLOATS, null);
154
+ if (weight < 1)
155
+ quatSlerp(pose, o, aim.saved, i * 4, pose, o, weight);
156
+ }
157
+ }
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Keyframe clips with glTF sampler semantics, sampled into a `Pose`.
3
+ *
4
+ * A channel is one glTF animation sampler + target: `times` (seconds, ascending) and `values`
5
+ * (packed components per key: 3 for translation and scale, 4 for rotation, N for morph
6
+ * `weights`). `CUBICSPLINE` stores three vectors per key: in-tangent, value, out-tangent
7
+ * (glTF order). Outside `[times[0], times[last]]` the first or last value holds; looping is the
8
+ * mixer's job.
9
+ *
10
+ * Sampling keeps a per-channel keyframe cursor (`ClipCursor`, one `Uint32Array` per clip, or one
11
+ * per playing action in the mixer) so a time that moves forward costs O(1) amortised; a jump
12
+ * falls back to a binary search. Nothing allocates per call.
13
+ */
14
+ import { type Pose } from './pose.js';
15
+ export type ChannelPath = 'translation' | 'rotation' | 'scale' | 'weights';
16
+ export type Interpolation = 'STEP' | 'LINEAR' | 'CUBICSPLINE';
17
+ export interface AnimationChannel {
18
+ /** Target node index (into the skeleton / pose). */
19
+ node: number;
20
+ path: ChannelPath;
21
+ interpolation: Interpolation;
22
+ /** Keyframe times in seconds, ascending. */
23
+ times: Float32Array;
24
+ /**
25
+ * Packed values: `times.length × components` floats, or `× 3` for `CUBICSPLINE`
26
+ * (in-tangent, value, out-tangent per key).
27
+ */
28
+ values: Float32Array;
29
+ /**
30
+ * Quantised rotation keys from `quantizeClip` (`compress.ts`): three `uint16` per key in
31
+ * smallest-three form (`unpackQuat`), read instead of `values` when present. Only on
32
+ * `rotation` channels with `STEP` or `LINEAR` interpolation.
33
+ */
34
+ packed?: Uint16Array;
35
+ }
36
+ /** A named time in a clip; the mixer reports each crossing through `onEvent`. */
37
+ export interface AnimationEvent {
38
+ time: number;
39
+ name: string;
40
+ }
41
+ export interface AnimationClip {
42
+ name: string;
43
+ /** Seconds. Normally `max(times)` over the channels; the mixer loops at it. */
44
+ duration: number;
45
+ channels: AnimationChannel[];
46
+ events?: AnimationEvent[];
47
+ }
48
+ /** Keyframe cursor per channel, see `createClipCursor`. */
49
+ export type ClipCursor = Uint32Array;
50
+ /** How `sampleClip` writes into the pose. */
51
+ export type AnimBlendMode = 'override' | 'additive';
52
+ /** Components per key of a channel (3, 4, or the morph weight count). */
53
+ export declare function channelComponents(channel: AnimationChannel): number;
54
+ /** A clip whose `duration` is the last keyframe time over its channels (0 when empty). */
55
+ export declare function clipDuration(channels: readonly AnimationChannel[]): number;
56
+ /** A fresh cursor for `clip` (one slot per channel). */
57
+ export declare function createClipCursor(clip: AnimationClip): ClipCursor;
58
+ /**
59
+ * Index `k` with `times[k] <= t < times[k+1]`, clamped to `[0, n-2]` (`0` for one key). Checks
60
+ * the hint and the key after it first, then binary-searches.
61
+ */
62
+ export declare function findKeyframe(times: Float32Array, t: number, hint: number): number;
63
+ /**
64
+ * Sample one channel at time `t` into `out[o..o+components)`. Rotations are slerped (`LINEAR`)
65
+ * or normalised (`CUBICSPLINE`). `cursor[ci]` (optional) is the keyframe hint, updated in place.
66
+ */
67
+ export declare function sampleChannel(channel: AnimationChannel, t: number, out: Float32Array, o: number, cursor?: Uint32Array, ci?: number): void;
68
+ /**
69
+ * Decode key `key` of a smallest-three packed rotation (`AnimationChannel.packed`) into
70
+ * `out[o..o+4)`. Each key is three `uint16`: bits 0..14 hold the three smaller components as
71
+ * `round((c + 1/√2) × 32767/√2)`; bit 15 of words 0 and 1 hold the index of the largest
72
+ * component, which is rebuilt as `sqrt(1 − Σc²)` (the quaternion was flipped to make it
73
+ * positive). No allocation.
74
+ */
75
+ export declare function unpackQuat(packed: Uint16Array, key: number, out: Float32Array, o: number): void;
76
+ /**
77
+ * Sample every channel of `clip` at `t` into `pose`.
78
+ *
79
+ * - `'override'`: each animated component becomes `lerp(pose, sampled, weight)` (slerp for
80
+ * rotations); `weight` 1 writes the value outright.
81
+ * - `'additive'`: the clip's values are deltas. Translation adds `weight × v`, scale multiplies
82
+ * by `lerp(1, v, weight)`, rotation post-multiplies `slerp(identity, q, weight)`. A "floating"
83
+ * idle on top of a walk is one additive channel on the root.
84
+ *
85
+ * `'weights'` (morph) channels are skipped: a pose has no morph slots; sample them with
86
+ * `sampleWeights`. A channel whose node is outside the pose is skipped. `cursor` defaults to a
87
+ * cursor shared per clip; pass your own when one clip plays at two times at once (the mixer
88
+ * does). No allocation.
89
+ */
90
+ export declare function sampleClip(clip: AnimationClip, t: number, pose: Pose, weight?: number, blend?: AnimBlendMode, cursor?: ClipCursor): void;
91
+ /**
92
+ * Sample the `'weights'` channel of `clip` targeting `node` at `t` into `out[0..n)`, where `n`
93
+ * is the channel's weight count (`channelComponents`): the same interpolation as `sampleClip`
94
+ * (STEP, LINEAR, CUBICSPLINE, hold outside the key range). Returns false, writing nothing, when
95
+ * the clip has no weights channel for `node`. Throws `RangeError` when `out` is too short.
96
+ * `cursor` as in `sampleClip`. No allocation.
97
+ */
98
+ export declare function sampleWeights(clip: AnimationClip, node: number, t: number, out: Float32Array, cursor?: ClipCursor): boolean;
@@ -0,0 +1,282 @@
1
+ /**
2
+ * Keyframe clips with glTF sampler semantics, sampled into a `Pose`.
3
+ *
4
+ * A channel is one glTF animation sampler + target: `times` (seconds, ascending) and `values`
5
+ * (packed components per key: 3 for translation and scale, 4 for rotation, N for morph
6
+ * `weights`). `CUBICSPLINE` stores three vectors per key: in-tangent, value, out-tangent
7
+ * (glTF order). Outside `[times[0], times[last]]` the first or last value holds; looping is the
8
+ * mixer's job.
9
+ *
10
+ * Sampling keeps a per-channel keyframe cursor (`ClipCursor`, one `Uint32Array` per clip, or one
11
+ * per playing action in the mixer) so a time that moves forward costs O(1) amortised; a jump
12
+ * falls back to a binary search. Nothing allocates per call.
13
+ */
14
+ import { POSE_NODE_FLOATS } from './pose.js';
15
+ import { quatIdentity, quatMultiply, quatNormalize, quatSlerp } from './quat.js';
16
+ /** Components per key of a channel (3, 4, or the morph weight count). */
17
+ export function channelComponents(channel) {
18
+ switch (channel.path) {
19
+ case 'translation':
20
+ case 'scale':
21
+ return 3;
22
+ case 'rotation':
23
+ return 4;
24
+ default: {
25
+ const keys = channel.times.length;
26
+ if (keys === 0)
27
+ return 0;
28
+ const per = channel.values.length / keys;
29
+ return channel.interpolation === 'CUBICSPLINE' ? per / 3 : per;
30
+ }
31
+ }
32
+ }
33
+ /** A clip whose `duration` is the last keyframe time over its channels (0 when empty). */
34
+ export function clipDuration(channels) {
35
+ let d = 0;
36
+ for (const c of channels) {
37
+ const n = c.times.length;
38
+ if (n > 0)
39
+ d = Math.max(d, c.times[n - 1]);
40
+ }
41
+ return d;
42
+ }
43
+ /** A fresh cursor for `clip` (one slot per channel). */
44
+ export function createClipCursor(clip) {
45
+ return new Uint32Array(Math.max(1, clip.channels.length));
46
+ }
47
+ const cursors = new WeakMap();
48
+ function cursorFor(clip) {
49
+ let c = cursors.get(clip);
50
+ if (!c || c.length < clip.channels.length) {
51
+ c = createClipCursor(clip);
52
+ cursors.set(clip, c);
53
+ }
54
+ return c;
55
+ }
56
+ /**
57
+ * Index `k` with `times[k] <= t < times[k+1]`, clamped to `[0, n-2]` (`0` for one key). Checks
58
+ * the hint and the key after it first, then binary-searches.
59
+ */
60
+ export function findKeyframe(times, t, hint) {
61
+ const n = times.length;
62
+ if (n < 2)
63
+ return 0;
64
+ const last = n - 2;
65
+ const h = Math.min(hint, last);
66
+ if (times[h] <= t) {
67
+ if (t < times[h + 1])
68
+ return h;
69
+ if (h < last && times[h + 1] <= t && t < times[h + 2])
70
+ return h + 1;
71
+ if (h === last)
72
+ return last;
73
+ }
74
+ if (t >= times[n - 1])
75
+ return last;
76
+ if (t <= times[0])
77
+ return 0;
78
+ let lo = 0;
79
+ let hi = last;
80
+ while (lo < hi) {
81
+ const mid = (lo + hi + 1) >> 1;
82
+ if (times[mid] <= t)
83
+ lo = mid;
84
+ else
85
+ hi = mid - 1;
86
+ }
87
+ return lo;
88
+ }
89
+ /**
90
+ * Sample one channel at time `t` into `out[o..o+components)`. Rotations are slerped (`LINEAR`)
91
+ * or normalised (`CUBICSPLINE`). `cursor[ci]` (optional) is the keyframe hint, updated in place.
92
+ */
93
+ export function sampleChannel(channel, t, out, o, cursor, ci = 0) {
94
+ const times = channel.times;
95
+ const n = times.length;
96
+ const comps = channelComponents(channel);
97
+ if (n === 0 || comps === 0)
98
+ return;
99
+ const cubic = channel.interpolation === 'CUBICSPLINE';
100
+ const stride = cubic ? comps * 3 : comps;
101
+ const k = findKeyframe(times, t, cursor ? cursor[ci] : 0);
102
+ if (cursor)
103
+ cursor[ci] = k;
104
+ const packed = channel.packed;
105
+ let values = channel.values;
106
+ let base0 = k * stride + (cubic ? comps : 0);
107
+ let base1 = (k + 1) * stride + (cubic ? comps : 0);
108
+ if (packed && channel.path === 'rotation' && !cubic) {
109
+ // Packed keys: decode the two around `t` into scratch and sample from there.
110
+ unpackQuat(packed, k, unpacked, 0);
111
+ if (n > 1)
112
+ unpackQuat(packed, k + 1, unpacked, 4);
113
+ values = unpacked;
114
+ base0 = 0;
115
+ base1 = 4;
116
+ }
117
+ const t0 = times[k];
118
+ const t1 = n > 1 ? times[k + 1] : t0;
119
+ if (n > 1 && t >= t1) {
120
+ // At or past the last key (k is clamped to n-2): hold the last value.
121
+ for (let i = 0; i < comps; i++)
122
+ out[o + i] = values[base1 + i];
123
+ return;
124
+ }
125
+ if (n === 1 || t <= t0 || channel.interpolation === 'STEP') {
126
+ for (let i = 0; i < comps; i++)
127
+ out[o + i] = values[base0 + i];
128
+ return;
129
+ }
130
+ const td = t1 - t0;
131
+ const u = (t - t0) / td;
132
+ if (cubic) {
133
+ // glTF: p(u) = h00·v0 + h10·td·b0 + h01·v1 + h11·td·a1 (a = in-tangent, b = out-tangent).
134
+ const u2 = u * u;
135
+ const u3 = u2 * u;
136
+ const h00 = 2 * u3 - 3 * u2 + 1;
137
+ const h10 = (u3 - 2 * u2 + u) * td;
138
+ const h01 = -2 * u3 + 3 * u2;
139
+ const h11 = (u3 - u2) * td;
140
+ const v0 = k * stride + comps;
141
+ const b0 = v0 + comps;
142
+ const a1 = (k + 1) * stride;
143
+ const v1 = a1 + comps;
144
+ for (let i = 0; i < comps; i++) {
145
+ out[o + i] =
146
+ h00 * values[v0 + i] +
147
+ h10 * values[b0 + i] +
148
+ h01 * values[v1 + i] +
149
+ h11 * values[a1 + i];
150
+ }
151
+ if (channel.path === 'rotation')
152
+ quatNormalize(out, o);
153
+ return;
154
+ }
155
+ if (channel.path === 'rotation') {
156
+ quatSlerp(out, o, values, base0, values, base1, u);
157
+ return;
158
+ }
159
+ const s = 1 - u;
160
+ for (let i = 0; i < comps; i++)
161
+ out[o + i] = s * values[base0 + i] + u * values[base1 + i];
162
+ }
163
+ const sample = new Float32Array(4);
164
+ const delta = new Float32Array(4);
165
+ const unpacked = new Float32Array(8);
166
+ /** Scale of a 15-bit smallest-three component: the range is ±1/√2. */
167
+ const PACK_SCALE = 32767 / Math.SQRT2;
168
+ /**
169
+ * Decode key `key` of a smallest-three packed rotation (`AnimationChannel.packed`) into
170
+ * `out[o..o+4)`. Each key is three `uint16`: bits 0..14 hold the three smaller components as
171
+ * `round((c + 1/√2) × 32767/√2)`; bit 15 of words 0 and 1 hold the index of the largest
172
+ * component, which is rebuilt as `sqrt(1 − Σc²)` (the quaternion was flipped to make it
173
+ * positive). No allocation.
174
+ */
175
+ export function unpackQuat(packed, key, out, o) {
176
+ const b = key * 3;
177
+ const w0 = packed[b];
178
+ const w1 = packed[b + 1];
179
+ const w2 = packed[b + 2];
180
+ const largest = ((w0 >> 15) << 1) | (w1 >> 15);
181
+ const a = (w0 & 0x7fff) / PACK_SCALE - Math.SQRT1_2;
182
+ const c = (w1 & 0x7fff) / PACK_SCALE - Math.SQRT1_2;
183
+ const d = (w2 & 0x7fff) / PACK_SCALE - Math.SQRT1_2;
184
+ const rest = 1 - a * a - c * c - d * d;
185
+ const big = rest > 0 ? Math.sqrt(rest) : 0;
186
+ // The three small components fill the slots other than `largest`, in order.
187
+ const s0 = largest === 0 ? 1 : 0;
188
+ const s1 = largest <= 1 ? 2 : 1;
189
+ const s2 = largest === 3 ? 2 : 3;
190
+ out[o + largest] = big;
191
+ out[o + s0] = a;
192
+ out[o + s1] = c;
193
+ out[o + s2] = d;
194
+ }
195
+ /**
196
+ * Sample every channel of `clip` at `t` into `pose`.
197
+ *
198
+ * - `'override'`: each animated component becomes `lerp(pose, sampled, weight)` (slerp for
199
+ * rotations); `weight` 1 writes the value outright.
200
+ * - `'additive'`: the clip's values are deltas. Translation adds `weight × v`, scale multiplies
201
+ * by `lerp(1, v, weight)`, rotation post-multiplies `slerp(identity, q, weight)`. A "floating"
202
+ * idle on top of a walk is one additive channel on the root.
203
+ *
204
+ * `'weights'` (morph) channels are skipped: a pose has no morph slots; sample them with
205
+ * `sampleWeights`. A channel whose node is outside the pose is skipped. `cursor` defaults to a
206
+ * cursor shared per clip; pass your own when one clip plays at two times at once (the mixer
207
+ * does). No allocation.
208
+ */
209
+ export function sampleClip(clip, t, pose, weight = 1, blend = 'override', cursor = cursorFor(clip)) {
210
+ const channels = clip.channels;
211
+ const nodes = (pose.length / POSE_NODE_FLOATS) | 0;
212
+ for (let ci = 0; ci < channels.length; ci++) {
213
+ const ch = channels[ci];
214
+ if (ch.path === 'weights' || ch.node < 0 || ch.node >= nodes)
215
+ continue;
216
+ sampleChannel(ch, t, sample, 0, cursor, ci);
217
+ const o = ch.node * POSE_NODE_FLOATS;
218
+ if (blend === 'override') {
219
+ if (ch.path === 'rotation') {
220
+ if (weight >= 1) {
221
+ pose[o + 3] = sample[0];
222
+ pose[o + 4] = sample[1];
223
+ pose[o + 5] = sample[2];
224
+ pose[o + 6] = sample[3];
225
+ }
226
+ else
227
+ quatSlerp(pose, o + 3, pose, o + 3, sample, 0, weight);
228
+ }
229
+ else {
230
+ const b = ch.path === 'translation' ? o : o + 7;
231
+ if (weight >= 1) {
232
+ pose[b] = sample[0];
233
+ pose[b + 1] = sample[1];
234
+ pose[b + 2] = sample[2];
235
+ }
236
+ else {
237
+ const s = 1 - weight;
238
+ pose[b] = s * pose[b] + weight * sample[0];
239
+ pose[b + 1] = s * pose[b + 1] + weight * sample[1];
240
+ pose[b + 2] = s * pose[b + 2] + weight * sample[2];
241
+ }
242
+ }
243
+ }
244
+ else if (ch.path === 'translation') {
245
+ pose[o] += weight * sample[0];
246
+ pose[o + 1] += weight * sample[1];
247
+ pose[o + 2] += weight * sample[2];
248
+ }
249
+ else if (ch.path === 'scale') {
250
+ pose[o + 7] *= 1 + weight * (sample[0] - 1);
251
+ pose[o + 8] *= 1 + weight * (sample[1] - 1);
252
+ pose[o + 9] *= 1 + weight * (sample[2] - 1);
253
+ }
254
+ else {
255
+ quatIdentity(delta, 0);
256
+ quatSlerp(delta, 0, delta, 0, sample, 0, weight);
257
+ quatMultiply(pose, o + 3, pose, o + 3, delta, 0);
258
+ quatNormalize(pose, o + 3);
259
+ }
260
+ }
261
+ }
262
+ /**
263
+ * Sample the `'weights'` channel of `clip` targeting `node` at `t` into `out[0..n)`, where `n`
264
+ * is the channel's weight count (`channelComponents`): the same interpolation as `sampleClip`
265
+ * (STEP, LINEAR, CUBICSPLINE, hold outside the key range). Returns false, writing nothing, when
266
+ * the clip has no weights channel for `node`. Throws `RangeError` when `out` is too short.
267
+ * `cursor` as in `sampleClip`. No allocation.
268
+ */
269
+ export function sampleWeights(clip, node, t, out, cursor = cursorFor(clip)) {
270
+ const channels = clip.channels;
271
+ for (let ci = 0; ci < channels.length; ci++) {
272
+ const ch = channels[ci];
273
+ if (ch.path !== 'weights' || ch.node !== node)
274
+ continue;
275
+ const n = channelComponents(ch);
276
+ if (out.length < n)
277
+ throw new RangeError(`sampleWeights: ${out.length} slots for ${n} weights`);
278
+ sampleChannel(ch, t, out, 0, cursor, ci);
279
+ return true;
280
+ }
281
+ return false;
282
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Clip compression: fewer keyframes and smaller ones, so a wardrobe of animations fits.
3
+ *
4
+ * `compressClip` keeps, per channel, only the keys a linear fit cannot reproduce within a
5
+ * tolerance (Ramer–Douglas–Peucker over the sampled curve: start from the two end keys, add
6
+ * the key with the largest error until every dropped key is within tolerance), collapses a
7
+ * channel whose keys never change to one key and drops it entirely when that value is the
8
+ * skeleton's rest (with `skeleton`). `quantizeClip` packs rotation keys into three `uint16`
9
+ * per key (smallest-three, `AnimationChannel.packed`), which `sampleChannel` reads directly.
10
+ * Both allocate (they build new clips); call them at load or in a bake step. `CUBICSPLINE`
11
+ * channels are copied unchanged by both.
12
+ */
13
+ import { type AnimationClip } from './clip.js';
14
+ import { type Skeleton } from './pose.js';
15
+ export interface CompressClipOptions {
16
+ /** Largest translation error a dropped key may introduce (units). Default 1e-3. */
17
+ positionError?: number;
18
+ /** Largest rotation error a dropped key may introduce (radians). Default 1e-3. */
19
+ rotationError?: number;
20
+ /** Largest scale error a dropped key may introduce. Default 1e-3. */
21
+ scaleError?: number;
22
+ /** Largest morph-weight error a dropped key may introduce. Default 1e-3. */
23
+ weightError?: number;
24
+ /**
25
+ * Collapse a channel whose keys never change (within the tolerance) to a single key, and
26
+ * drop it when that value is the node's rest in `skeleton`. Default true.
27
+ */
28
+ dropConstant?: boolean;
29
+ /** The skeleton whose rest decides which constant channels are redundant. */
30
+ skeleton?: Skeleton;
31
+ }
32
+ /** `compressClip`'s result: the new clip and the keyframe bytes before and after. */
33
+ export interface CompressedClip {
34
+ clip: AnimationClip;
35
+ /** Bytes of `times` + `values` (+ `packed`) over the input's channels. */
36
+ before: number;
37
+ /** The same over the output's channels. */
38
+ after: number;
39
+ }
40
+ export interface QuantizeClipOptions {
41
+ /** `'smallest-three'` packs `STEP`/`LINEAR` rotation channels; `'none'` copies. */
42
+ rotation: 'smallest-three' | 'none';
43
+ }
44
+ /** Keyframe bytes of a clip: `times`, `values` and `packed` over every channel. */
45
+ export declare function clipBytes(clip: AnimationClip): number;
46
+ /**
47
+ * A copy of `clip` with the keys a linear fit reproduces within tolerance removed, constant
48
+ * channels collapsed (and dropped when they equal the rest of `skeleton`), and the keyframe
49
+ * byte counts before and after. Packed channels are decoded first; `CUBICSPLINE` channels and
50
+ * events are copied as they are. Allocates.
51
+ */
52
+ export declare function compressClip(clip: AnimationClip, opts?: CompressClipOptions): CompressedClip;
53
+ /**
54
+ * Encode the unit quaternion at `q[o..o+4)` as three `uint16` at `out[b..b+3)` in the
55
+ * smallest-three form `unpackQuat` decodes: the quaternion is flipped so its largest
56
+ * component is positive, that component's index goes to bit 15 of words 0 and 1, and the
57
+ * other three components, each within ±1/√2, fill the low 15 bits of the words in order.
58
+ */
59
+ export declare function packQuat(q: ArrayLike<number>, o: number, out: Uint16Array, b: number): void;
60
+ /**
61
+ * A copy of `clip` whose `STEP`/`LINEAR` rotation channels carry `packed` keys (three
62
+ * `uint16` each, `packQuat`) and an empty `values`; other channels are copied. `'none'`
63
+ * copies everything. Allocates.
64
+ */
65
+ export declare function quantizeClip(clip: AnimationClip, opts: QuantizeClipOptions): AnimationClip;