@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.
- package/CHANGELOG.md +390 -0
- package/LICENSE +21 -0
- package/README.md +333 -2
- package/dist/analytics/analytics.d.ts +80 -0
- package/dist/analytics/analytics.js +129 -0
- package/dist/analytics/index.d.ts +1 -0
- package/dist/analytics/index.js +1 -0
- package/dist/anim/aim.d.ts +43 -0
- package/dist/anim/aim.js +157 -0
- package/dist/anim/clip.d.ts +98 -0
- package/dist/anim/clip.js +282 -0
- package/dist/anim/compress.d.ts +65 -0
- package/dist/anim/compress.js +339 -0
- package/dist/anim/foot-ik.d.ts +74 -0
- package/dist/anim/foot-ik.js +241 -0
- package/dist/anim/graph.d.ts +153 -0
- package/dist/anim/graph.js +532 -0
- package/dist/anim/ik.d.ts +105 -0
- package/dist/anim/ik.js +435 -0
- package/dist/anim/index.d.ts +36 -0
- package/dist/anim/index.js +21 -0
- package/dist/anim/match.d.ts +66 -0
- package/dist/anim/match.js +153 -0
- package/dist/anim/mixer.d.ts +113 -0
- package/dist/anim/mixer.js +314 -0
- package/dist/anim/morph.d.ts +41 -0
- package/dist/anim/morph.js +94 -0
- package/dist/anim/pose.d.ts +74 -0
- package/dist/anim/pose.js +254 -0
- package/dist/anim/quat.d.ts +44 -0
- package/dist/anim/quat.js +187 -0
- package/dist/anim/retarget.d.ts +97 -0
- package/dist/anim/retarget.js +366 -0
- package/dist/anim/root-motion.d.ts +44 -0
- package/dist/anim/root-motion.js +224 -0
- package/dist/anim/skin-pose.d.ts +39 -0
- package/dist/anim/skin-pose.js +53 -0
- package/dist/anim/socket.d.ts +47 -0
- package/dist/anim/socket.js +84 -0
- package/dist/anim/spring-chain.d.ts +73 -0
- package/dist/anim/spring-chain.js +294 -0
- package/dist/assets/atlas.d.ts +90 -0
- package/dist/assets/atlas.js +212 -0
- package/dist/assets/baked.d.ts +33 -0
- package/dist/assets/baked.js +38 -0
- package/dist/assets/bundle.d.ts +88 -0
- package/dist/assets/bundle.js +464 -0
- package/dist/assets/cache.d.ts +56 -0
- package/dist/assets/cache.js +123 -0
- package/dist/assets/gltf-load.d.ts +252 -0
- package/dist/assets/gltf-load.js +661 -0
- package/dist/assets/gltf-skin.d.ts +36 -0
- package/dist/assets/gltf-skin.js +109 -0
- package/dist/assets/gltf.d.ts +706 -0
- package/dist/assets/gltf.js +1376 -0
- package/dist/assets/index.d.ts +20 -0
- package/dist/assets/index.js +10 -0
- package/dist/assets/ktx2.d.ts +71 -0
- package/dist/assets/ktx2.js +213 -0
- package/dist/assets/manifest.d.ts +79 -0
- package/dist/assets/manifest.js +7 -0
- package/dist/assets/meshopt.d.ts +23 -0
- package/dist/assets/meshopt.js +403 -0
- package/dist/audio/audio.d.ts +733 -0
- package/dist/audio/audio.js +2013 -0
- package/dist/audio/dsp.d.ts +61 -0
- package/dist/audio/dsp.js +159 -0
- package/dist/audio/duck.d.ts +44 -0
- package/dist/audio/duck.js +101 -0
- package/dist/audio/envelope.d.ts +53 -0
- package/dist/audio/envelope.js +106 -0
- package/dist/audio/index.d.ts +13 -0
- package/dist/audio/index.js +14 -0
- package/dist/audio/music.d.ts +113 -0
- package/dist/audio/music.js +548 -0
- package/dist/audio/occlusion.d.ts +55 -0
- package/dist/audio/occlusion.js +61 -0
- package/dist/audio/persist.d.ts +23 -0
- package/dist/audio/persist.js +27 -0
- package/dist/audio/recipes.d.ts +55 -0
- package/dist/audio/recipes.js +227 -0
- package/dist/audio/send.d.ts +41 -0
- package/dist/audio/send.js +118 -0
- package/dist/audio/sprites.d.ts +59 -0
- package/dist/audio/sprites.js +43 -0
- package/dist/audio/synth.d.ts +103 -0
- package/dist/audio/synth.js +197 -0
- package/dist/audio/variations.d.ts +25 -0
- package/dist/audio/variations.js +55 -0
- package/dist/audio/zones.d.ts +100 -0
- package/dist/audio/zones.js +167 -0
- package/dist/core/detached-surface.d.ts +44 -0
- package/dist/core/detached-surface.js +104 -0
- package/dist/core/events.d.ts +24 -0
- package/dist/core/events.js +43 -0
- package/dist/core/game.d.ts +409 -0
- package/dist/core/game.js +530 -0
- package/dist/core/hash.d.ts +24 -0
- package/dist/core/hash.js +49 -0
- package/dist/core/index.d.ts +17 -0
- package/dist/core/index.js +9 -0
- package/dist/core/loop.d.ts +113 -0
- package/dist/core/loop.js +185 -0
- package/dist/core/math.d.ts +58 -0
- package/dist/core/math.js +210 -0
- package/dist/core/noise.d.ts +40 -0
- package/dist/core/noise.js +247 -0
- package/dist/core/pool.d.ts +42 -0
- package/dist/core/pool.js +85 -0
- package/dist/core/random.d.ts +61 -0
- package/dist/core/random.js +199 -0
- package/dist/core/scene.d.ts +79 -0
- package/dist/core/scene.js +195 -0
- package/dist/core/timer.d.ts +66 -0
- package/dist/core/timer.js +286 -0
- package/dist/fx/billboard-wgsl.d.ts +29 -0
- package/dist/fx/billboard-wgsl.js +158 -0
- package/dist/fx/billboard.d.ts +249 -0
- package/dist/fx/billboard.js +702 -0
- package/dist/fx/debug-draw.d.ts +127 -0
- package/dist/fx/debug-draw.js +523 -0
- package/dist/fx/debug-wgsl.d.ts +7 -0
- package/dist/fx/debug-wgsl.js +32 -0
- package/dist/fx/decals-wgsl.d.ts +15 -0
- package/dist/fx/decals-wgsl.js +173 -0
- package/dist/fx/decals.d.ts +216 -0
- package/dist/fx/decals.js +607 -0
- package/dist/fx/effect.d.ts +129 -0
- package/dist/fx/effect.js +349 -0
- package/dist/fx/effects/hit-spark.json +48 -0
- package/dist/fx/effects/index.d.ts +8 -0
- package/dist/fx/effects/index.js +9 -0
- package/dist/fx/effects/magic-aura.json +47 -0
- package/dist/fx/effects/smoke-puff.json +34 -0
- package/dist/fx/emit-surface.d.ts +40 -0
- package/dist/fx/emit-surface.js +124 -0
- package/dist/fx/flicker.d.ts +30 -0
- package/dist/fx/flicker.js +42 -0
- package/dist/fx/index.d.ts +31 -0
- package/dist/fx/index.js +20 -0
- package/dist/fx/particles-wgsl.d.ts +57 -0
- package/dist/fx/particles-wgsl.js +828 -0
- package/dist/fx/particles.d.ts +566 -0
- package/dist/fx/particles.js +1533 -0
- package/dist/fx/random.d.ts +15 -0
- package/dist/fx/random.js +20 -0
- package/dist/fx/sky-wgsl.d.ts +23 -0
- package/dist/fx/sky-wgsl.js +127 -0
- package/dist/fx/sky.d.ts +96 -0
- package/dist/fx/sky.js +175 -0
- package/dist/fx/text-atlas.d.ts +143 -0
- package/dist/fx/text-atlas.js +327 -0
- package/dist/fx/trail-wgsl.d.ts +11 -0
- package/dist/fx/trail-wgsl.js +42 -0
- package/dist/fx/trail.d.ts +194 -0
- package/dist/fx/trail.js +555 -0
- package/dist/fx/water-wgsl.d.ts +34 -0
- package/dist/fx/water-wgsl.js +197 -0
- package/dist/fx/water.d.ts +176 -0
- package/dist/fx/water.js +371 -0
- package/dist/geom/collide/bvh.d.ts +151 -0
- package/dist/geom/collide/bvh.js +493 -0
- package/dist/geom/collide/debug.d.ts +14 -0
- package/dist/geom/collide/debug.js +74 -0
- package/dist/geom/collide/grid.d.ts +26 -0
- package/dist/geom/collide/grid.js +91 -0
- package/dist/geom/collide/index.d.ts +8 -0
- package/dist/geom/collide/index.js +8 -0
- package/dist/geom/collide/queries.d.ts +70 -0
- package/dist/geom/collide/queries.js +583 -0
- package/dist/geom/collide/serialize.d.ts +14 -0
- package/dist/geom/collide/serialize.js +145 -0
- package/dist/geom/collide/shapes.d.ts +161 -0
- package/dist/geom/collide/shapes.js +686 -0
- package/dist/geom/collide/slide.d.ts +66 -0
- package/dist/geom/collide/slide.js +375 -0
- package/dist/geom/collide/tile-slide.d.ts +88 -0
- package/dist/geom/collide/tile-slide.js +255 -0
- package/dist/geom/geometry.d.ts +95 -0
- package/dist/geom/geometry.js +322 -0
- package/dist/geom/heightfield.d.ts +72 -0
- package/dist/geom/heightfield.js +295 -0
- package/dist/geom/hull.d.ts +27 -0
- package/dist/geom/hull.js +279 -0
- package/dist/geom/index.d.ts +35 -0
- package/dist/geom/index.js +23 -0
- package/dist/geom/iso.d.ts +74 -0
- package/dist/geom/iso.js +89 -0
- package/dist/geom/lod.d.ts +29 -0
- package/dist/geom/lod.js +27 -0
- package/dist/geom/ops.d.ts +47 -0
- package/dist/geom/ops.js +285 -0
- package/dist/geom/primitives.d.ts +97 -0
- package/dist/geom/primitives.js +359 -0
- package/dist/geom/shapes.d.ts +43 -0
- package/dist/geom/shapes.js +88 -0
- package/dist/geom/simplify.d.ts +38 -0
- package/dist/geom/simplify.js +519 -0
- package/dist/geom/split.d.ts +37 -0
- package/dist/geom/split.js +413 -0
- package/dist/geom/sweep.d.ts +83 -0
- package/dist/geom/sweep.js +534 -0
- package/dist/geom/tangents.d.ts +16 -0
- package/dist/geom/tangents.js +124 -0
- package/dist/geom/triangulate.d.ts +19 -0
- package/dist/geom/triangulate.js +147 -0
- package/dist/host/default.d.ts +10 -0
- package/dist/host/default.js +10 -0
- package/dist/host/index.d.ts +4 -0
- package/dist/host/index.js +3 -0
- package/dist/host/types.d.ts +144 -0
- package/dist/host/types.js +1 -0
- package/dist/host/web-links.d.ts +38 -0
- package/dist/host/web-links.js +110 -0
- package/dist/host/web.d.ts +30 -0
- package/dist/host/web.js +216 -0
- package/dist/host/xr.d.ts +24 -0
- package/dist/host/xr.js +59 -0
- package/dist/i18n/i18n.d.ts +59 -0
- package/dist/i18n/i18n.js +241 -0
- package/dist/i18n/index.d.ts +3 -0
- package/dist/i18n/index.js +3 -0
- package/dist/i18n/message.d.ts +72 -0
- package/dist/i18n/message.js +369 -0
- package/dist/i18n/negotiate.d.ts +17 -0
- package/dist/i18n/negotiate.js +58 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +1 -0
- package/dist/input/bindings.d.ts +31 -0
- package/dist/input/bindings.js +141 -0
- package/dist/input/clock.d.ts +44 -0
- package/dist/input/clock.js +49 -0
- package/dist/input/follow.d.ts +133 -0
- package/dist/input/follow.js +218 -0
- package/dist/input/gestures.d.ts +281 -0
- package/dist/input/gestures.js +662 -0
- package/dist/input/glyphs.d.ts +35 -0
- package/dist/input/glyphs.js +216 -0
- package/dist/input/gyro.d.ts +85 -0
- package/dist/input/gyro.js +140 -0
- package/dist/input/index.d.ts +19 -0
- package/dist/input/index.js +16 -0
- package/dist/input/input.d.ts +543 -0
- package/dist/input/input.js +1492 -0
- package/dist/input/look.d.ts +327 -0
- package/dist/input/look.js +681 -0
- package/dist/input/magnify.d.ts +177 -0
- package/dist/input/magnify.js +131 -0
- package/dist/input/pointer-dispatch.d.ts +138 -0
- package/dist/input/pointer-dispatch.js +180 -0
- package/dist/input/pointer-router.d.ts +204 -0
- package/dist/input/pointer-router.js +533 -0
- package/dist/input/pointer-sources.d.ts +164 -0
- package/dist/input/pointer-sources.js +306 -0
- package/dist/input/rays.d.ts +138 -0
- package/dist/input/rays.js +615 -0
- package/dist/input/record.d.ts +209 -0
- package/dist/input/record.js +601 -0
- package/dist/input/touch-zones.d.ts +147 -0
- package/dist/input/touch-zones.js +300 -0
- package/dist/input/types.d.ts +158 -0
- package/dist/input/types.js +1 -0
- package/dist/input/xr-source.d.ts +53 -0
- package/dist/input/xr-source.js +164 -0
- package/dist/nav/astar.d.ts +45 -0
- package/dist/nav/astar.js +182 -0
- package/dist/nav/corridor.d.ts +40 -0
- package/dist/nav/corridor.js +95 -0
- package/dist/nav/crowd.d.ts +94 -0
- package/dist/nav/crowd.js +624 -0
- package/dist/nav/flow.d.ts +61 -0
- package/dist/nav/flow.js +193 -0
- package/dist/nav/grid.d.ts +108 -0
- package/dist/nav/grid.js +210 -0
- package/dist/nav/heap.d.ts +22 -0
- package/dist/nav/heap.js +92 -0
- package/dist/nav/index.d.ts +37 -0
- package/dist/nav/index.js +19 -0
- package/dist/nav/mesh/areas.d.ts +44 -0
- package/dist/nav/mesh/areas.js +98 -0
- package/dist/nav/mesh/bake-options.d.ts +33 -0
- package/dist/nav/mesh/bake-options.js +76 -0
- package/dist/nav/mesh/contour.d.ts +22 -0
- package/dist/nav/mesh/contour.js +323 -0
- package/dist/nav/mesh/flow3.d.ts +35 -0
- package/dist/nav/mesh/flow3.js +229 -0
- package/dist/nav/mesh/links.d.ts +38 -0
- package/dist/nav/mesh/links.js +72 -0
- package/dist/nav/mesh/mesh-path.d.ts +152 -0
- package/dist/nav/mesh/mesh-path.js +643 -0
- package/dist/nav/mesh/mesh-reach.d.ts +78 -0
- package/dist/nav/mesh/mesh-reach.js +450 -0
- package/dist/nav/mesh/navmesh.d.ts +117 -0
- package/dist/nav/mesh/navmesh.js +647 -0
- package/dist/nav/mesh/polymesh.d.ts +24 -0
- package/dist/nav/mesh/polymesh.js +384 -0
- package/dist/nav/mesh/regions.d.ts +12 -0
- package/dist/nav/mesh/regions.js +367 -0
- package/dist/nav/mesh/serialize.d.ts +13 -0
- package/dist/nav/mesh/serialize.js +197 -0
- package/dist/nav/mesh/voxelize.d.ts +111 -0
- package/dist/nav/mesh/voxelize.js +552 -0
- package/dist/nav/obstacles.d.ts +75 -0
- package/dist/nav/obstacles.js +294 -0
- package/dist/nav/path.d.ts +59 -0
- package/dist/nav/path.js +177 -0
- package/dist/nav/query-queue.d.ts +46 -0
- package/dist/nav/query-queue.js +308 -0
- package/dist/nav/reach.d.ts +53 -0
- package/dist/nav/reach.js +148 -0
- package/dist/nav/steer.d.ts +36 -0
- package/dist/nav/steer.js +78 -0
- package/dist/platform/boot.d.ts +28 -0
- package/dist/platform/boot.js +43 -0
- package/dist/platform/device-mode.d.ts +40 -0
- package/dist/platform/device-mode.js +104 -0
- package/dist/platform/device.d.ts +31 -0
- package/dist/platform/device.js +91 -0
- package/dist/platform/environment.d.ts +42 -0
- package/dist/platform/environment.js +82 -0
- package/dist/platform/gpu.d.ts +40 -0
- package/dist/platform/gpu.js +57 -0
- package/dist/platform/index.d.ts +18 -0
- package/dist/platform/index.js +10 -0
- package/dist/platform/letterbox.d.ts +43 -0
- package/dist/platform/letterbox.js +57 -0
- package/dist/platform/links.d.ts +20 -0
- package/dist/platform/links.js +43 -0
- package/dist/platform/screens.d.ts +36 -0
- package/dist/platform/screens.js +138 -0
- package/dist/platform/surface.d.ts +72 -0
- package/dist/platform/surface.js +157 -0
- package/dist/platform/xr-fake.d.ts +168 -0
- package/dist/platform/xr-fake.js +434 -0
- package/dist/platform/xr-surface.d.ts +120 -0
- package/dist/platform/xr-surface.js +214 -0
- package/dist/platform/xr-types.d.ts +262 -0
- package/dist/post/ao.d.ts +12 -0
- package/dist/post/ao.js +136 -0
- package/dist/post/blend.d.ts +27 -0
- package/dist/post/blend.js +129 -0
- package/dist/post/depth-pass.d.ts +43 -0
- package/dist/post/depth-pass.js +118 -0
- package/dist/post/dof.d.ts +1 -0
- package/dist/post/dof.js +66 -0
- package/dist/post/exposure.d.ts +80 -0
- package/dist/post/exposure.js +322 -0
- package/dist/post/index.d.ts +12 -0
- package/dist/post/index.js +11 -0
- package/dist/post/lens-dirt.d.ts +13 -0
- package/dist/post/lens-dirt.js +91 -0
- package/dist/post/lut.d.ts +19 -0
- package/dist/post/lut.js +50 -0
- package/dist/post/motion-blur.d.ts +9 -0
- package/dist/post/motion-blur.js +78 -0
- package/dist/post/post-stack.d.ts +302 -0
- package/dist/post/post-stack.js +1137 -0
- package/dist/post/settings.d.ts +485 -0
- package/dist/post/settings.js +416 -0
- package/dist/post/shaders.d.ts +25 -0
- package/dist/post/shaders.js +410 -0
- package/dist/post/ssr.d.ts +16 -0
- package/dist/post/ssr.js +155 -0
- package/dist/post/taa.d.ts +74 -0
- package/dist/post/taa.js +235 -0
- package/dist/post/white-balance.d.ts +25 -0
- package/dist/post/white-balance.js +98 -0
- package/dist/render/bindings.d.ts +98 -0
- package/dist/render/bindings.js +281 -0
- package/dist/render/blend.d.ts +13 -0
- package/dist/render/blend.js +26 -0
- package/dist/render/camera-2d.d.ts +72 -0
- package/dist/render/camera-2d.js +92 -0
- package/dist/render/camera.d.ts +302 -0
- package/dist/render/camera.js +671 -0
- package/dist/render/color.d.ts +16 -0
- package/dist/render/color.js +41 -0
- package/dist/render/compressed.d.ts +104 -0
- package/dist/render/compressed.js +248 -0
- package/dist/render/diagnostics.d.ts +15 -0
- package/dist/render/diagnostics.js +43 -0
- package/dist/render/dynamic-resolution.d.ts +70 -0
- package/dist/render/dynamic-resolution.js +126 -0
- package/dist/render/fake-gpu.d.ts +204 -0
- package/dist/render/fake-gpu.js +426 -0
- package/dist/render/flipbook.d.ts +56 -0
- package/dist/render/flipbook.js +87 -0
- package/dist/render/frame.d.ts +278 -0
- package/dist/render/frame.js +174 -0
- package/dist/render/fullscreen.d.ts +54 -0
- package/dist/render/fullscreen.js +91 -0
- package/dist/render/gpu-timer.d.ts +73 -0
- package/dist/render/gpu-timer.js +186 -0
- package/dist/render/index.d.ts +53 -0
- package/dist/render/index.js +29 -0
- package/dist/render/instance-list.d.ts +185 -0
- package/dist/render/instance-list.js +547 -0
- package/dist/render/lights.d.ts +181 -0
- package/dist/render/lights.js +233 -0
- package/dist/render/lod.d.ts +54 -0
- package/dist/render/lod.js +52 -0
- package/dist/render/material.d.ts +165 -0
- package/dist/render/material.js +292 -0
- package/dist/render/mesh.d.ts +284 -0
- package/dist/render/mesh.js +472 -0
- package/dist/render/mipmap.d.ts +16 -0
- package/dist/render/mipmap.js +121 -0
- package/dist/render/parallax.d.ts +50 -0
- package/dist/render/parallax.js +47 -0
- package/dist/render/pbr-wgsl.d.ts +31 -0
- package/dist/render/pbr-wgsl.js +119 -0
- package/dist/render/ping-pong.d.ts +42 -0
- package/dist/render/ping-pong.js +74 -0
- package/dist/render/renderer.d.ts +741 -0
- package/dist/render/renderer.js +2486 -0
- package/dist/render/scene-pipelines.d.ts +44 -0
- package/dist/render/scene-pipelines.js +92 -0
- package/dist/render/scene-target.d.ts +170 -0
- package/dist/render/scene-target.js +450 -0
- package/dist/render/shadow.d.ts +74 -0
- package/dist/render/shadow.js +208 -0
- package/dist/render/skin.d.ts +112 -0
- package/dist/render/skin.js +240 -0
- package/dist/render/snapshot.d.ts +36 -0
- package/dist/render/snapshot.js +34 -0
- package/dist/render/standard.d.ts +162 -0
- package/dist/render/standard.js +263 -0
- package/dist/render/texture.d.ts +142 -0
- package/dist/render/texture.js +228 -0
- package/dist/render/tile-layer.d.ts +110 -0
- package/dist/render/tile-layer.js +304 -0
- package/dist/render/transform.d.ts +115 -0
- package/dist/render/transform.js +318 -0
- package/dist/render/wgsl.d.ts +131 -0
- package/dist/render/wgsl.js +528 -0
- package/dist/save/codec.d.ts +49 -0
- package/dist/save/codec.js +169 -0
- package/dist/save/index.d.ts +8 -0
- package/dist/save/index.js +8 -0
- package/dist/save/journal.d.ts +24 -0
- package/dist/save/journal.js +102 -0
- package/dist/save/migrate.d.ts +15 -0
- package/dist/save/migrate.js +37 -0
- package/dist/save/schema.d.ts +72 -0
- package/dist/save/schema.js +154 -0
- package/dist/save/settings.d.ts +28 -0
- package/dist/save/settings.js +59 -0
- package/dist/save/slots.d.ts +56 -0
- package/dist/save/slots.js +200 -0
- package/dist/save/storage.d.ts +35 -0
- package/dist/save/storage.js +62 -0
- package/dist/save/store.d.ts +114 -0
- package/dist/save/store.js +269 -0
- package/dist/testing/fake-host.d.ts +103 -0
- package/dist/testing/fake-host.js +163 -0
- package/dist/testing/fixed-clock.d.ts +25 -0
- package/dist/testing/fixed-clock.js +30 -0
- package/dist/testing/index.d.ts +4 -0
- package/dist/testing/index.js +5 -0
- package/dist/testing/test-game.d.ts +76 -0
- package/dist/testing/test-game.js +92 -0
- package/dist/tween/ease.d.ts +77 -0
- package/dist/tween/ease.js +192 -0
- package/dist/tween/index.d.ts +8 -0
- package/dist/tween/index.js +7 -0
- package/dist/tween/timeline.d.ts +78 -0
- package/dist/tween/timeline.js +269 -0
- package/dist/tween/tween.d.ts +168 -0
- package/dist/tween/tween.js +320 -0
- package/dist/ui/anchor.d.ts +206 -0
- package/dist/ui/anchor.js +307 -0
- package/dist/ui/caption.d.ts +122 -0
- package/dist/ui/caption.js +286 -0
- package/dist/ui/cursor.d.ts +105 -0
- package/dist/ui/cursor.js +261 -0
- package/dist/ui/dom.d.ts +30 -0
- package/dist/ui/dom.js +92 -0
- package/dist/ui/floats.d.ts +86 -0
- package/dist/ui/floats.js +260 -0
- package/dist/ui/hud.d.ts +198 -0
- package/dist/ui/hud.js +431 -0
- package/dist/ui/index.d.ts +37 -0
- package/dist/ui/index.js +34 -0
- package/dist/ui/inventory-card.d.ts +52 -0
- package/dist/ui/inventory-card.js +173 -0
- package/dist/ui/inventory-context.d.ts +29 -0
- package/dist/ui/inventory-context.js +125 -0
- package/dist/ui/inventory-drag.d.ts +63 -0
- package/dist/ui/inventory-drag.js +394 -0
- package/dist/ui/inventory-grid.d.ts +66 -0
- package/dist/ui/inventory-grid.js +625 -0
- package/dist/ui/inventory-radial.d.ts +39 -0
- package/dist/ui/inventory-radial.js +168 -0
- package/dist/ui/inventory.d.ts +128 -0
- package/dist/ui/inventory.js +154 -0
- package/dist/ui/layout.d.ts +356 -0
- package/dist/ui/layout.js +856 -0
- package/dist/ui/link.d.ts +64 -0
- package/dist/ui/link.js +155 -0
- package/dist/ui/loading.d.ts +40 -0
- package/dist/ui/loading.js +157 -0
- package/dist/ui/loupe.d.ts +74 -0
- package/dist/ui/loupe.js +164 -0
- package/dist/ui/menu-nav.d.ts +33 -0
- package/dist/ui/menu-nav.js +28 -0
- package/dist/ui/minimap-canvas.d.ts +145 -0
- package/dist/ui/minimap-canvas.js +460 -0
- package/dist/ui/notify.d.ts +40 -0
- package/dist/ui/notify.js +141 -0
- package/dist/ui/orb.d.ts +53 -0
- package/dist/ui/orb.js +304 -0
- package/dist/ui/overlay.d.ts +213 -0
- package/dist/ui/overlay.js +394 -0
- package/dist/ui/padnav.d.ts +53 -0
- package/dist/ui/padnav.js +146 -0
- package/dist/ui/perf.d.ts +130 -0
- package/dist/ui/perf.js +329 -0
- package/dist/ui/rotate-card.d.ts +54 -0
- package/dist/ui/rotate-card.js +97 -0
- package/dist/ui/stack.d.ts +128 -0
- package/dist/ui/stack.js +312 -0
- package/dist/ui/styles.d.ts +13 -0
- package/dist/ui/styles.js +200 -0
- package/dist/ui/text-scale.d.ts +67 -0
- package/dist/ui/text-scale.js +102 -0
- package/dist/ui/theme.d.ts +70 -0
- package/dist/ui/theme.js +98 -0
- package/dist/ui/toast.d.ts +23 -0
- package/dist/ui/toast.js +46 -0
- package/dist/ui/tooltip.d.ts +89 -0
- package/dist/ui/tooltip.js +333 -0
- package/dist/ui/widgets-2.d.ts +134 -0
- package/dist/ui/widgets-2.js +399 -0
- package/dist/ui/widgets-3.d.ts +91 -0
- package/dist/ui/widgets-3.js +212 -0
- package/dist/ui/widgets.d.ts +34 -0
- package/dist/ui/widgets.js +50 -0
- package/dist/ui/world-panel/index.d.ts +5 -0
- package/dist/ui/world-panel/index.js +5 -0
- package/dist/ui/world-panel/layout.d.ts +38 -0
- package/dist/ui/world-panel/layout.js +68 -0
- package/dist/ui/world-panel/paint.d.ts +96 -0
- package/dist/ui/world-panel/paint.js +136 -0
- package/dist/ui/world-panel/panel.d.ts +235 -0
- package/dist/ui/world-panel/panel.js +762 -0
- package/dist/ui/world-panel/wgsl.d.ts +10 -0
- package/dist/ui/world-panel/wgsl.js +52 -0
- package/dist/ui/world-panel/widgets.d.ts +207 -0
- package/dist/ui/world-panel/widgets.js +569 -0
- package/dist/voxel/chunks.d.ts +77 -0
- package/dist/voxel/chunks.js +149 -0
- package/dist/voxel/grid.d.ts +84 -0
- package/dist/voxel/grid.js +223 -0
- package/dist/voxel/index.d.ts +22 -0
- package/dist/voxel/index.js +7 -0
- package/dist/voxel/mesher-worker.d.ts +14 -0
- package/dist/voxel/mesher-worker.js +47 -0
- package/dist/voxel/mesher.d.ts +73 -0
- package/dist/voxel/mesher.js +306 -0
- package/dist/voxel/ray.d.ts +32 -0
- package/dist/voxel/ray.js +73 -0
- package/dist/voxel/wgsl.d.ts +16 -0
- package/dist/voxel/wgsl.js +28 -0
- package/dist/voxel/worker-client.d.ts +79 -0
- package/dist/voxel/worker-client.js +122 -0
- package/package.json +177 -3
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `createAnimGraph`: a small state graph on top of `AnimationMixer`. States hold one clip or a
|
|
3
|
+
* 1D blend space; transitions carry a condition over a shared parameter object, a fade time
|
|
4
|
+
* and an optional exit time; the game sets parameters each frame and calls `update(dt)`.
|
|
5
|
+
*
|
|
6
|
+
* Every clip of every state is started on the mixer at construction with weight 0 and stays in
|
|
7
|
+
* its slot for the life of the graph: the graph owns the weights, so a transition is a lerp of
|
|
8
|
+
* every state's weight toward the target (1 for the state entered, 0 for the rest), and the
|
|
9
|
+
* weights sum to 1 at every instant, also when a fade is interrupted by another. A 1D blend
|
|
10
|
+
* space weights the two points around the parameter; a 2D one (two parameters, points
|
|
11
|
+
* anywhere in the plane: a strafe set) weights every point by gradient-band interpolation
|
|
12
|
+
* (Johansen: each point's weight is the smallest of its clamped "how far toward me rather than
|
|
13
|
+
* toward point j" terms, normalised) after clamping the query to the convex hull of the points,
|
|
14
|
+
* computed once. Both keep one normalised phase across their clips with `syncPhase` (default)
|
|
15
|
+
* so blended cycles stay in step. A transition with `matchPose` starts its target at the clip
|
|
16
|
+
* frame nearest the pose it leaves (`match.ts`) when the graph was built with `match`. After
|
|
17
|
+
* construction `update` allocates nothing; conditions receive the same parameter object every
|
|
18
|
+
* time.
|
|
19
|
+
*/
|
|
20
|
+
import type { AnimationClip } from './clip.js';
|
|
21
|
+
import type { AnimationAction, AnimationMixer } from './mixer.js';
|
|
22
|
+
/** The parameters the game sets; the same object is passed to every condition. */
|
|
23
|
+
export type AnimGraphParams = Record<string, number | boolean>;
|
|
24
|
+
/** A state playing one clip. `speed` default 1, `loop` default true. */
|
|
25
|
+
export interface AnimGraphClipState {
|
|
26
|
+
clip: AnimationClip;
|
|
27
|
+
speed?: number;
|
|
28
|
+
loop?: boolean;
|
|
29
|
+
}
|
|
30
|
+
/** One sample of a 1D blend space: `clip` at parameter value `at`. */
|
|
31
|
+
export interface AnimGraphBlendPoint {
|
|
32
|
+
at: number;
|
|
33
|
+
clip: AnimationClip;
|
|
34
|
+
}
|
|
35
|
+
/** One sample of a 2D blend space: `clip` at the parameter pair `at`. */
|
|
36
|
+
export interface AnimGraphBlendPoint2D {
|
|
37
|
+
at: [number, number];
|
|
38
|
+
clip: AnimationClip;
|
|
39
|
+
}
|
|
40
|
+
/** A 1D blend space: the two points around `param` share the weight linearly. */
|
|
41
|
+
export interface AnimGraphBlend1D {
|
|
42
|
+
param: string;
|
|
43
|
+
points: AnimGraphBlendPoint[];
|
|
44
|
+
syncPhase?: boolean;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* A 2D blend space over two parameters (a strafe set: `[forward, sideways]`). Weights come
|
|
48
|
+
* from gradient-band interpolation over the points (any layout, no triangulation): a query on
|
|
49
|
+
* a point returns that clip alone, the centre of three equal-sided points returns a third each,
|
|
50
|
+
* and a query outside the points' convex hull is clamped to the hull first.
|
|
51
|
+
*/
|
|
52
|
+
export interface AnimGraphBlend2D {
|
|
53
|
+
params: [string, string];
|
|
54
|
+
points: AnimGraphBlendPoint2D[];
|
|
55
|
+
syncPhase?: boolean;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* A state blending clips along one numeric parameter (`AnimGraphBlend1D`) or over two
|
|
59
|
+
* (`AnimGraphBlend2D`). `syncPhase` (default true) runs every clip at one normalised time, at
|
|
60
|
+
* the rate of the blended cycle length, so walk and run keep their feet in step; `false` plays
|
|
61
|
+
* each at its own speed.
|
|
62
|
+
*/
|
|
63
|
+
export interface AnimGraphBlendState {
|
|
64
|
+
blend: AnimGraphBlend1D | AnimGraphBlend2D;
|
|
65
|
+
}
|
|
66
|
+
export type AnimGraphStateDesc = AnimGraphClipState | AnimGraphBlendState;
|
|
67
|
+
/**
|
|
68
|
+
* Pose matching for transitions (`AnimGraphTransition.matchPose`): the graph builds
|
|
69
|
+
* `PoseFeatures` for every clip of every state over these joints at construction, tracks the
|
|
70
|
+
* pose's world matrices and joint velocities each update, and starts a matched transition's
|
|
71
|
+
* target at the nearest frame. Without this a `matchPose` transition starts at 0.
|
|
72
|
+
*/
|
|
73
|
+
export interface AnimGraphMatchDesc {
|
|
74
|
+
/** Node indices to match on (feet, hands, head). */
|
|
75
|
+
joints: ArrayLike<number>;
|
|
76
|
+
/** Samples per second of the features. Default 30. */
|
|
77
|
+
sampleRate?: number;
|
|
78
|
+
/** Weight of the velocity term, see `findBestFrame`. Default 0.05. */
|
|
79
|
+
velocityWeight?: number;
|
|
80
|
+
/** The node whose frame is root space. Default: the first node with no parent. */
|
|
81
|
+
root?: number;
|
|
82
|
+
}
|
|
83
|
+
export interface AnimGraphTransition {
|
|
84
|
+
/** The state this leaves, or `'*'` for any state other than `to`. */
|
|
85
|
+
from: string | '*';
|
|
86
|
+
to: string;
|
|
87
|
+
/** Read `params`; return true to take the transition. Must not allocate. */
|
|
88
|
+
when: (params: AnimGraphParams) => boolean;
|
|
89
|
+
/** Cross-fade seconds; 0 switches at once. */
|
|
90
|
+
fade: number;
|
|
91
|
+
/**
|
|
92
|
+
* Normalised time (0..1) the current state must have passed before the transition can fire:
|
|
93
|
+
* `time / duration` for a clip, the shared phase for a synced blend space (the first point's
|
|
94
|
+
* phase otherwise). A finished non-looping clip counts as 1.
|
|
95
|
+
*/
|
|
96
|
+
exitTime?: number;
|
|
97
|
+
/**
|
|
98
|
+
* Start the target at the clip frame nearest the pose being left (`findBestFrame` over the
|
|
99
|
+
* features built from `AnimGraphDesc.match`) instead of at 0. For a blend space the point
|
|
100
|
+
* with the largest weight at that instant is matched and its time sets the shared phase.
|
|
101
|
+
*/
|
|
102
|
+
matchPose?: boolean;
|
|
103
|
+
}
|
|
104
|
+
export interface AnimGraphDesc {
|
|
105
|
+
params: AnimGraphParams;
|
|
106
|
+
states: Record<string, AnimGraphStateDesc>;
|
|
107
|
+
/** Evaluated in order every update; the first whose condition holds wins. */
|
|
108
|
+
transitions: AnimGraphTransition[];
|
|
109
|
+
initial: string;
|
|
110
|
+
/** Pose-matching features for `matchPose` transitions; absent, they start at 0. */
|
|
111
|
+
match?: AnimGraphMatchDesc;
|
|
112
|
+
}
|
|
113
|
+
/** `(from, to)` of the change that fired the callback. */
|
|
114
|
+
export type AnimGraphListener = (from: string, to: string) => void;
|
|
115
|
+
export interface AnimGraph {
|
|
116
|
+
/** The parameters, the object `desc.params` was copied into; conditions read this. */
|
|
117
|
+
readonly params: AnimGraphParams;
|
|
118
|
+
/** The current state (the target of the latest transition, from the instant it fires). */
|
|
119
|
+
readonly state: string;
|
|
120
|
+
/** The state the latest transition left, or `state` before any transition. */
|
|
121
|
+
readonly previous: string;
|
|
122
|
+
/** Set one parameter. Throws for a name `desc.params` did not declare. */
|
|
123
|
+
set(param: string, value: number | boolean): void;
|
|
124
|
+
/** Read one parameter. */
|
|
125
|
+
get(param: string): number | boolean;
|
|
126
|
+
/**
|
|
127
|
+
* Evaluate the transitions (in order; first match wins), advance the fades and the blend
|
|
128
|
+
* phases, write every action's weight, speed and time, then `mixer.update(dt)`.
|
|
129
|
+
*/
|
|
130
|
+
update(dt: number): void;
|
|
131
|
+
/** Fired after the state changes to `state` (`from` is the state left). Returns unsubscribe. */
|
|
132
|
+
onEnter(state: string, fn: AnimGraphListener): () => void;
|
|
133
|
+
/** Fired before `onEnter` when the state leaves `state` (`to` is the state entered). */
|
|
134
|
+
onExit(state: string, fn: AnimGraphListener): () => void;
|
|
135
|
+
/** The state's share of the pose, 0..1 (1 once its fade-in finished). */
|
|
136
|
+
weight(state: string): number;
|
|
137
|
+
/** The mixer actions of a state, in `points` order for a blend space (one for a clip). */
|
|
138
|
+
actions(state: string): readonly AnimationAction[];
|
|
139
|
+
/** Normalised time (0..1) of a state: its clip's `time / duration` or the blend phase. */
|
|
140
|
+
phase(state: string): number;
|
|
141
|
+
/**
|
|
142
|
+
* Force `state` now (or over `fade` seconds), ignoring the transitions; `matchPose` as on a
|
|
143
|
+
* transition (needs the graph's `match`).
|
|
144
|
+
*/
|
|
145
|
+
go(state: string, fade?: number, opts?: {
|
|
146
|
+
matchPose?: boolean;
|
|
147
|
+
}): void;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Build a graph over `mixer`. Every clip of every state is started on the mixer here (weight
|
|
151
|
+
* 0, one action slot each: size `maxActions` to fit), so nothing is created later.
|
|
152
|
+
*/
|
|
153
|
+
export declare function createAnimGraph(mixer: AnimationMixer, desc: AnimGraphDesc): AnimGraph;
|
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
import { buildPoseFeatures, findBestFrame, firstRoot, rootSpacePositions, } from './match.js';
|
|
2
|
+
import { poseToWorld, WORLD_NODE_FLOATS } from './pose.js';
|
|
3
|
+
class AnimGraphImpl {
|
|
4
|
+
params;
|
|
5
|
+
mixer;
|
|
6
|
+
nodes = [];
|
|
7
|
+
byName = new Map();
|
|
8
|
+
transitions;
|
|
9
|
+
current;
|
|
10
|
+
prev;
|
|
11
|
+
fadeDuration = 0;
|
|
12
|
+
fadeElapsed = 0;
|
|
13
|
+
/**
|
|
14
|
+
* Pose matching (`desc.match`): the pose's world matrices after each update, the feature
|
|
15
|
+
* joints' root-space positions of this and the previous update, and their velocity.
|
|
16
|
+
*/
|
|
17
|
+
match;
|
|
18
|
+
matchJoints;
|
|
19
|
+
matchRoot;
|
|
20
|
+
world;
|
|
21
|
+
posNow;
|
|
22
|
+
posPrev;
|
|
23
|
+
velocity;
|
|
24
|
+
worldTicks = 0;
|
|
25
|
+
matchOut = { time: 0, cost: 0 };
|
|
26
|
+
constructor(mixer, desc) {
|
|
27
|
+
this.mixer = mixer;
|
|
28
|
+
this.params = { ...desc.params };
|
|
29
|
+
this.transitions = desc.transitions.slice();
|
|
30
|
+
this.match = desc.match ?? null;
|
|
31
|
+
this.matchJoints = Int16Array.from(desc.match?.joints ?? []);
|
|
32
|
+
const nodes = mixer.skeleton.parents.length;
|
|
33
|
+
this.world = new Float32Array(this.match ? nodes * WORLD_NODE_FLOATS : 0);
|
|
34
|
+
this.posNow = new Float32Array(this.matchJoints.length * 3);
|
|
35
|
+
this.posPrev = new Float32Array(this.matchJoints.length * 3);
|
|
36
|
+
this.velocity = new Float32Array(this.matchJoints.length * 3);
|
|
37
|
+
this.matchRoot = desc.match?.root ?? firstRoot(mixer.skeleton);
|
|
38
|
+
for (const name of Object.keys(desc.states)) {
|
|
39
|
+
const node = this.build(name, desc.states[name]);
|
|
40
|
+
this.nodes.push(node);
|
|
41
|
+
this.byName.set(name, node);
|
|
42
|
+
}
|
|
43
|
+
for (const t of this.transitions) {
|
|
44
|
+
if (t.from !== '*' && !this.byName.has(t.from))
|
|
45
|
+
throw new Error(`AnimGraph: transition from unknown state '${t.from}'`);
|
|
46
|
+
if (!this.byName.has(t.to))
|
|
47
|
+
throw new Error(`AnimGraph: transition to unknown state '${t.to}'`);
|
|
48
|
+
}
|
|
49
|
+
const initial = this.byName.get(desc.initial);
|
|
50
|
+
if (!initial)
|
|
51
|
+
throw new Error(`AnimGraph: unknown initial state '${desc.initial}'`);
|
|
52
|
+
this.current = initial;
|
|
53
|
+
this.prev = initial;
|
|
54
|
+
initial.weight = 1;
|
|
55
|
+
initial.fadeFrom = 1;
|
|
56
|
+
initial.target = 1;
|
|
57
|
+
this.restart(initial);
|
|
58
|
+
for (const n of this.nodes)
|
|
59
|
+
this.apply(n);
|
|
60
|
+
}
|
|
61
|
+
get state() {
|
|
62
|
+
return this.current.name;
|
|
63
|
+
}
|
|
64
|
+
get previous() {
|
|
65
|
+
return this.prev.name;
|
|
66
|
+
}
|
|
67
|
+
set(param, value) {
|
|
68
|
+
if (!(param in this.params))
|
|
69
|
+
throw new Error(`AnimGraph: unknown param '${param}'`);
|
|
70
|
+
this.params[param] = value;
|
|
71
|
+
}
|
|
72
|
+
get(param) {
|
|
73
|
+
const v = this.params[param];
|
|
74
|
+
if (v === undefined)
|
|
75
|
+
throw new Error(`AnimGraph: unknown param '${param}'`);
|
|
76
|
+
return v;
|
|
77
|
+
}
|
|
78
|
+
onEnter(state, fn) {
|
|
79
|
+
return subscribe(this.node(state).enter, fn);
|
|
80
|
+
}
|
|
81
|
+
onExit(state, fn) {
|
|
82
|
+
return subscribe(this.node(state).exit, fn);
|
|
83
|
+
}
|
|
84
|
+
weight(state) {
|
|
85
|
+
return this.node(state).weight;
|
|
86
|
+
}
|
|
87
|
+
actions(state) {
|
|
88
|
+
return this.node(state).actions;
|
|
89
|
+
}
|
|
90
|
+
phase(state) {
|
|
91
|
+
return this.phaseOf(this.node(state));
|
|
92
|
+
}
|
|
93
|
+
go(state, fade = 0, opts) {
|
|
94
|
+
this.transition(this.node(state), fade, opts?.matchPose === true);
|
|
95
|
+
}
|
|
96
|
+
update(dt) {
|
|
97
|
+
const transitions = this.transitions;
|
|
98
|
+
const current = this.current;
|
|
99
|
+
for (let i = 0; i < transitions.length; i++) {
|
|
100
|
+
const t = transitions[i];
|
|
101
|
+
if (t.from === '*' ? t.to === current.name : t.from !== current.name)
|
|
102
|
+
continue;
|
|
103
|
+
if (t.exitTime !== undefined && this.phaseOf(current) < t.exitTime)
|
|
104
|
+
continue;
|
|
105
|
+
if (!t.when(this.params))
|
|
106
|
+
continue;
|
|
107
|
+
this.transition(this.byName.get(t.to), t.fade, t.matchPose === true);
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
// Fades: every state lerps from where the fade found it toward its target.
|
|
111
|
+
const nodes = this.nodes;
|
|
112
|
+
if (this.fadeDuration > 0) {
|
|
113
|
+
this.fadeElapsed += dt;
|
|
114
|
+
const u = Math.min(1, this.fadeElapsed / this.fadeDuration);
|
|
115
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
116
|
+
const n = nodes[i];
|
|
117
|
+
n.weight = n.fadeFrom + (n.target - n.fadeFrom) * u;
|
|
118
|
+
}
|
|
119
|
+
if (u >= 1)
|
|
120
|
+
this.fadeDuration = 0;
|
|
121
|
+
}
|
|
122
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
123
|
+
const n = nodes[i];
|
|
124
|
+
this.apply(n);
|
|
125
|
+
if (n.dims > 0 && n.syncPhase) {
|
|
126
|
+
// The mixer advances every clip by dt × d_i / D this update, so the phase gains dt / D.
|
|
127
|
+
const cycle = this.blendedCycle(n);
|
|
128
|
+
if (cycle > 0) {
|
|
129
|
+
let p = (n.phase + dt / cycle) % 1;
|
|
130
|
+
if (p < 0)
|
|
131
|
+
p += 1;
|
|
132
|
+
n.phase = p;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
this.mixer.update(dt);
|
|
137
|
+
if (this.match)
|
|
138
|
+
this.track(dt);
|
|
139
|
+
}
|
|
140
|
+
/** Pose matching: world matrices of the new pose and the feature joints' root-space velocity. */
|
|
141
|
+
track(dt) {
|
|
142
|
+
const prev = this.posNow;
|
|
143
|
+
const now = this.posPrev;
|
|
144
|
+
this.posNow = now;
|
|
145
|
+
this.posPrev = prev;
|
|
146
|
+
poseToWorld(this.mixer.skeleton, this.mixer.pose, this.world);
|
|
147
|
+
rootSpacePositions(this.world, this.matchRoot, this.matchJoints, now);
|
|
148
|
+
this.worldTicks++;
|
|
149
|
+
// A frozen frame (dt 0, a pause) says nothing about the velocity: keep the last one.
|
|
150
|
+
if (this.worldTicks > 1 && dt > 0) {
|
|
151
|
+
const v = this.velocity;
|
|
152
|
+
const inv = 1 / dt;
|
|
153
|
+
for (let i = 0; i < v.length; i++)
|
|
154
|
+
v[i] = (now[i] - prev[i]) * inv;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
build(name, desc) {
|
|
158
|
+
const node = {
|
|
159
|
+
name,
|
|
160
|
+
actions: [],
|
|
161
|
+
dims: 0,
|
|
162
|
+
at: new Float32Array(0),
|
|
163
|
+
at2: new Float32Array(0),
|
|
164
|
+
hull: new Int16Array(0),
|
|
165
|
+
blendParamY: '',
|
|
166
|
+
features: [],
|
|
167
|
+
durations: new Float32Array(0),
|
|
168
|
+
blendWeights: new Float32Array(0),
|
|
169
|
+
blendParam: '',
|
|
170
|
+
syncPhase: false,
|
|
171
|
+
phase: 0,
|
|
172
|
+
speed: 1,
|
|
173
|
+
weight: 0,
|
|
174
|
+
fadeFrom: 0,
|
|
175
|
+
target: 0,
|
|
176
|
+
enter: [],
|
|
177
|
+
exit: [],
|
|
178
|
+
};
|
|
179
|
+
if ('blend' in desc) {
|
|
180
|
+
const blend = desc.blend;
|
|
181
|
+
const points = blend.points;
|
|
182
|
+
if (points.length === 0)
|
|
183
|
+
throw new Error(`AnimGraph: state '${name}' has no blend points`);
|
|
184
|
+
node.syncPhase = blend.syncPhase ?? true;
|
|
185
|
+
node.durations = new Float32Array(points.length);
|
|
186
|
+
node.blendWeights = new Float32Array(points.length);
|
|
187
|
+
if ('params' in blend) {
|
|
188
|
+
for (const param of blend.params) {
|
|
189
|
+
if (!(param in this.params))
|
|
190
|
+
throw new Error(`AnimGraph: state '${name}' blends on unknown param '${param}'`);
|
|
191
|
+
}
|
|
192
|
+
node.dims = 2;
|
|
193
|
+
node.blendParam = blend.params[0];
|
|
194
|
+
node.blendParamY = blend.params[1];
|
|
195
|
+
node.at2 = new Float32Array(points.length * 2);
|
|
196
|
+
for (let i = 0; i < points.length; i++) {
|
|
197
|
+
const p = blend.points[i];
|
|
198
|
+
node.at2[i * 2] = p.at[0];
|
|
199
|
+
node.at2[i * 2 + 1] = p.at[1];
|
|
200
|
+
node.durations[i] = p.clip.duration;
|
|
201
|
+
node.actions.push(this.mixer.play(p.clip, { weight: 0 }));
|
|
202
|
+
}
|
|
203
|
+
node.hull = convexHull(node.at2);
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
const param = blend.param;
|
|
207
|
+
if (!(param in this.params))
|
|
208
|
+
throw new Error(`AnimGraph: state '${name}' blends on unknown param '${param}'`);
|
|
209
|
+
node.dims = 1;
|
|
210
|
+
const sorted = blend.points.slice().sort((a, b) => a.at - b.at);
|
|
211
|
+
node.at = new Float32Array(sorted.length);
|
|
212
|
+
node.blendParam = param;
|
|
213
|
+
for (let i = 0; i < sorted.length; i++) {
|
|
214
|
+
const p = sorted[i];
|
|
215
|
+
node.at[i] = p.at;
|
|
216
|
+
node.durations[i] = p.clip.duration;
|
|
217
|
+
node.actions.push(this.mixer.play(p.clip, { weight: 0 }));
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
node.speed = desc.speed ?? 1;
|
|
223
|
+
node.actions.push(this.mixer.play(desc.clip, { weight: 0, speed: node.speed, loop: desc.loop ?? true }));
|
|
224
|
+
}
|
|
225
|
+
const match = this.match;
|
|
226
|
+
if (match) {
|
|
227
|
+
for (const a of node.actions) {
|
|
228
|
+
node.features.push(buildPoseFeatures(a.clip, this.mixer.skeleton, {
|
|
229
|
+
joints: match.joints,
|
|
230
|
+
sampleRate: match.sampleRate,
|
|
231
|
+
root: match.root,
|
|
232
|
+
}));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return node;
|
|
236
|
+
}
|
|
237
|
+
node(name) {
|
|
238
|
+
const n = this.byName.get(name);
|
|
239
|
+
if (!n)
|
|
240
|
+
throw new Error(`AnimGraph: unknown state '${name}'`);
|
|
241
|
+
return n;
|
|
242
|
+
}
|
|
243
|
+
/** Switch to `to`: callbacks, restart its clips (at the matched frame) and start the fade. */
|
|
244
|
+
transition(to, fade, matchPose = false) {
|
|
245
|
+
const from = this.current;
|
|
246
|
+
if (to === from)
|
|
247
|
+
return;
|
|
248
|
+
this.prev = from;
|
|
249
|
+
this.current = to;
|
|
250
|
+
const nodes = this.nodes;
|
|
251
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
252
|
+
const n = nodes[i];
|
|
253
|
+
n.fadeFrom = n.weight;
|
|
254
|
+
n.target = n === to ? 1 : 0;
|
|
255
|
+
}
|
|
256
|
+
this.restart(to);
|
|
257
|
+
if (matchPose && this.match && this.worldTicks > 0 && to.features.length > 0) {
|
|
258
|
+
// Match the pose being left against the target clip (the heaviest point of a blend).
|
|
259
|
+
let index = 0;
|
|
260
|
+
if (to.dims > 0) {
|
|
261
|
+
this.blendWeightsOf(to);
|
|
262
|
+
for (let i = 1; i < to.blendWeights.length; i++) {
|
|
263
|
+
if (to.blendWeights[i] > to.blendWeights[index])
|
|
264
|
+
index = i;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
const m = findBestFrame(to.features[index], this.world, this.velocity, this.match, this.matchOut);
|
|
268
|
+
const a = to.actions[index];
|
|
269
|
+
const d = a.clip.duration;
|
|
270
|
+
const time = d > 0 ? Math.min(m.time, d) : 0;
|
|
271
|
+
if (to.dims > 0 && to.syncPhase) {
|
|
272
|
+
to.phase = d > 0 ? time / d : 0;
|
|
273
|
+
for (let i = 0; i < to.actions.length; i++) {
|
|
274
|
+
to.actions[i].time = to.phase * to.durations[i];
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
a.time = time;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
if (fade > 0) {
|
|
282
|
+
this.fadeDuration = fade;
|
|
283
|
+
this.fadeElapsed = 0;
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
this.fadeDuration = 0;
|
|
287
|
+
for (let i = 0; i < nodes.length; i++)
|
|
288
|
+
nodes[i].weight = nodes[i].target;
|
|
289
|
+
}
|
|
290
|
+
fire(from.exit, from.name, to.name);
|
|
291
|
+
fire(to.enter, from.name, to.name);
|
|
292
|
+
}
|
|
293
|
+
/** Rewind a state's clips so it plays from its start when entered. */
|
|
294
|
+
restart(n) {
|
|
295
|
+
const actions = n.actions;
|
|
296
|
+
for (let i = 0; i < actions.length; i++) {
|
|
297
|
+
const a = actions[i];
|
|
298
|
+
a.time = a.speed < 0 ? a.clip.duration : 0;
|
|
299
|
+
a.finished = false;
|
|
300
|
+
a.paused = false;
|
|
301
|
+
}
|
|
302
|
+
n.phase = 0;
|
|
303
|
+
}
|
|
304
|
+
/** Write the node's weight (and blend weights, speeds, times) onto its actions. */
|
|
305
|
+
apply(n) {
|
|
306
|
+
const actions = n.actions;
|
|
307
|
+
if (n.dims === 0) {
|
|
308
|
+
actions[0].weight = n.weight;
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
this.blendWeightsOf(n);
|
|
312
|
+
const sync = n.syncPhase;
|
|
313
|
+
const cycle = sync ? this.blendedCycle(n) : 0;
|
|
314
|
+
for (let i = 0; i < actions.length; i++) {
|
|
315
|
+
const a = actions[i];
|
|
316
|
+
a.weight = n.weight * n.blendWeights[i];
|
|
317
|
+
if (sync) {
|
|
318
|
+
const d = n.durations[i];
|
|
319
|
+
a.speed = cycle > 0 ? d / cycle : 0;
|
|
320
|
+
a.time = n.phase * d;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
paramValue(name) {
|
|
325
|
+
const v = this.params[name];
|
|
326
|
+
return typeof v === 'number' ? v : v ? 1 : 0;
|
|
327
|
+
}
|
|
328
|
+
/** Blend weights of the state at the current parameters, into `n.blendWeights`. */
|
|
329
|
+
blendWeightsOf(n) {
|
|
330
|
+
if (n.dims === 2) {
|
|
331
|
+
gradientBand(n.at2, n.hull, this.paramValue(n.blendParam), this.paramValue(n.blendParamY), n.blendWeights);
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
const x = this.paramValue(n.blendParam);
|
|
335
|
+
const at = n.at;
|
|
336
|
+
const w = n.blendWeights;
|
|
337
|
+
w.fill(0);
|
|
338
|
+
const last = at.length - 1;
|
|
339
|
+
if (x <= at[0]) {
|
|
340
|
+
w[0] = 1;
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
if (x >= at[last]) {
|
|
344
|
+
w[last] = 1;
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
let i = 0;
|
|
348
|
+
while (at[i + 1] < x)
|
|
349
|
+
i++;
|
|
350
|
+
const span = at[i + 1] - at[i];
|
|
351
|
+
const t = span > 0 ? (x - at[i]) / span : 1;
|
|
352
|
+
w[i] = 1 - t;
|
|
353
|
+
w[i + 1] = t;
|
|
354
|
+
}
|
|
355
|
+
/** Cycle length of a blend space now: the weighted mean of its clips' durations. */
|
|
356
|
+
blendedCycle(n) {
|
|
357
|
+
let d = 0;
|
|
358
|
+
for (let i = 0; i < n.durations.length; i++)
|
|
359
|
+
d += n.blendWeights[i] * n.durations[i];
|
|
360
|
+
return d;
|
|
361
|
+
}
|
|
362
|
+
phaseOf(n) {
|
|
363
|
+
if (n.dims > 0 && n.syncPhase)
|
|
364
|
+
return n.phase;
|
|
365
|
+
const a = n.actions[0];
|
|
366
|
+
const d = a.clip.duration;
|
|
367
|
+
if (a.finished || d <= 0)
|
|
368
|
+
return 1;
|
|
369
|
+
return a.time / d;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
function subscribe(list, fn) {
|
|
373
|
+
list.push(fn);
|
|
374
|
+
return () => {
|
|
375
|
+
const i = list.indexOf(fn);
|
|
376
|
+
if (i >= 0)
|
|
377
|
+
list.splice(i, 1);
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
function fire(list, from, to) {
|
|
381
|
+
for (let i = 0; i < list.length; i++)
|
|
382
|
+
list[i](from, to);
|
|
383
|
+
}
|
|
384
|
+
/** Twice the signed area of (a, b, c): > 0 when counter-clockwise. */
|
|
385
|
+
function cross(pts, a, b, c) {
|
|
386
|
+
return ((pts[b * 2] - pts[a * 2]) * (pts[c * 2 + 1] - pts[a * 2 + 1]) -
|
|
387
|
+
(pts[b * 2 + 1] - pts[a * 2 + 1]) * (pts[c * 2] - pts[a * 2]));
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Convex hull of `x y` pairs (Andrew's monotone chain), counter-clockwise point indices;
|
|
391
|
+
* collinear points on an edge are left out. One point → `[i]`; a segment → its two ends.
|
|
392
|
+
* Called once per 2D blend state at construction.
|
|
393
|
+
*/
|
|
394
|
+
function convexHull(pts) {
|
|
395
|
+
const n = pts.length / 2;
|
|
396
|
+
const order = [];
|
|
397
|
+
for (let i = 0; i < n; i++)
|
|
398
|
+
order.push(i);
|
|
399
|
+
order.sort((a, b) => pts[a * 2] - pts[b * 2] || pts[a * 2 + 1] - pts[b * 2 + 1]);
|
|
400
|
+
// Drop duplicate points so a repeated sample cannot wedge the chain.
|
|
401
|
+
const unique = [];
|
|
402
|
+
for (const i of order) {
|
|
403
|
+
const last = unique[unique.length - 1];
|
|
404
|
+
if (last === undefined || pts[i * 2] !== pts[last * 2] || pts[i * 2 + 1] !== pts[last * 2 + 1])
|
|
405
|
+
unique.push(i);
|
|
406
|
+
}
|
|
407
|
+
if (unique.length < 3)
|
|
408
|
+
return Int16Array.from(unique);
|
|
409
|
+
const hull = [];
|
|
410
|
+
for (const i of unique) {
|
|
411
|
+
while (hull.length >= 2 && cross(pts, hull[hull.length - 2], hull[hull.length - 1], i) <= 0)
|
|
412
|
+
hull.pop();
|
|
413
|
+
hull.push(i);
|
|
414
|
+
}
|
|
415
|
+
const lowerLength = hull.length + 1;
|
|
416
|
+
for (let k = unique.length - 2; k >= 0; k--) {
|
|
417
|
+
const i = unique[k];
|
|
418
|
+
while (hull.length >= lowerLength &&
|
|
419
|
+
cross(pts, hull[hull.length - 2], hull[hull.length - 1], i) <= 0)
|
|
420
|
+
hull.pop();
|
|
421
|
+
hull.push(i);
|
|
422
|
+
}
|
|
423
|
+
hull.pop();
|
|
424
|
+
return Int16Array.from(hull);
|
|
425
|
+
}
|
|
426
|
+
/** Clamp (x, y) to the hull: nearest point on its boundary when outside. */
|
|
427
|
+
const clamped = new Float32Array(2);
|
|
428
|
+
function clampToHull(pts, hull, x, y) {
|
|
429
|
+
clamped[0] = x;
|
|
430
|
+
clamped[1] = y;
|
|
431
|
+
const h = hull.length;
|
|
432
|
+
if (h === 0)
|
|
433
|
+
return;
|
|
434
|
+
if (h === 1) {
|
|
435
|
+
clamped[0] = pts[hull[0] * 2];
|
|
436
|
+
clamped[1] = pts[hull[0] * 2 + 1];
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
if (h >= 3) {
|
|
440
|
+
let inside = true;
|
|
441
|
+
for (let k = 0; k < h; k++) {
|
|
442
|
+
const a = hull[k];
|
|
443
|
+
const b = hull[(k + 1) % h];
|
|
444
|
+
const c = (pts[b * 2] - pts[a * 2]) * (y - pts[a * 2 + 1]) -
|
|
445
|
+
(pts[b * 2 + 1] - pts[a * 2 + 1]) * (x - pts[a * 2]);
|
|
446
|
+
if (c < 0) {
|
|
447
|
+
inside = false;
|
|
448
|
+
break;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
if (inside)
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
// Outside (or a segment hull): the nearest point over every edge.
|
|
455
|
+
let best = Number.POSITIVE_INFINITY;
|
|
456
|
+
const edges = h === 2 ? 1 : h;
|
|
457
|
+
for (let k = 0; k < edges; k++) {
|
|
458
|
+
const a = hull[k];
|
|
459
|
+
const b = hull[(k + 1) % h];
|
|
460
|
+
const ax = pts[a * 2];
|
|
461
|
+
const ay = pts[a * 2 + 1];
|
|
462
|
+
const ex = pts[b * 2] - ax;
|
|
463
|
+
const ey = pts[b * 2 + 1] - ay;
|
|
464
|
+
const len2 = ex * ex + ey * ey;
|
|
465
|
+
let t = len2 > 0 ? ((x - ax) * ex + (y - ay) * ey) / len2 : 0;
|
|
466
|
+
t = Math.min(1, Math.max(0, t));
|
|
467
|
+
const px = ax + ex * t;
|
|
468
|
+
const py = ay + ey * t;
|
|
469
|
+
const d = (px - x) * (px - x) + (py - y) * (py - y);
|
|
470
|
+
if (d < best) {
|
|
471
|
+
best = d;
|
|
472
|
+
clamped[0] = px;
|
|
473
|
+
clamped[1] = py;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Gradient-band interpolation: `w_i = min over j≠i of clamp(1 − ((q − a_i)·(a_j − a_i)) /
|
|
479
|
+
* |a_j − a_i|², 0, 1)`, normalised to sum 1. A query on a sample gives that sample 1; the
|
|
480
|
+
* weights are continuous in `q`. The query is first clamped to the hull. Allocation-free.
|
|
481
|
+
*/
|
|
482
|
+
function gradientBand(pts, hull, x, y, w) {
|
|
483
|
+
clampToHull(pts, hull, x, y);
|
|
484
|
+
const qx = clamped[0];
|
|
485
|
+
const qy = clamped[1];
|
|
486
|
+
const n = pts.length / 2;
|
|
487
|
+
let sum = 0;
|
|
488
|
+
let nearest = 0;
|
|
489
|
+
let nearestD = Number.POSITIVE_INFINITY;
|
|
490
|
+
for (let i = 0; i < n; i++) {
|
|
491
|
+
const ix = pts[i * 2];
|
|
492
|
+
const iy = pts[i * 2 + 1];
|
|
493
|
+
const dx = qx - ix;
|
|
494
|
+
const dy = qy - iy;
|
|
495
|
+
const d = dx * dx + dy * dy;
|
|
496
|
+
if (d < nearestD) {
|
|
497
|
+
nearestD = d;
|
|
498
|
+
nearest = i;
|
|
499
|
+
}
|
|
500
|
+
let wi = 1;
|
|
501
|
+
for (let j = 0; j < n; j++) {
|
|
502
|
+
if (j === i)
|
|
503
|
+
continue;
|
|
504
|
+
const ex = pts[j * 2] - ix;
|
|
505
|
+
const ey = pts[j * 2 + 1] - iy;
|
|
506
|
+
const len2 = ex * ex + ey * ey;
|
|
507
|
+
if (len2 === 0)
|
|
508
|
+
continue;
|
|
509
|
+
let v = 1 - (dx * ex + dy * ey) / len2;
|
|
510
|
+
v = Math.min(1, Math.max(0, v));
|
|
511
|
+
if (v < wi)
|
|
512
|
+
wi = v;
|
|
513
|
+
}
|
|
514
|
+
w[i] = wi;
|
|
515
|
+
sum += wi;
|
|
516
|
+
}
|
|
517
|
+
if (sum > 0) {
|
|
518
|
+
for (let i = 0; i < n; i++)
|
|
519
|
+
w[i] = w[i] / sum;
|
|
520
|
+
}
|
|
521
|
+
else {
|
|
522
|
+
w.fill(0);
|
|
523
|
+
w[nearest] = 1;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Build a graph over `mixer`. Every clip of every state is started on the mixer here (weight
|
|
528
|
+
* 0, one action slot each: size `maxActions` to fit), so nothing is created later.
|
|
529
|
+
*/
|
|
530
|
+
export function createAnimGraph(mixer, desc) {
|
|
531
|
+
return new AnimGraphImpl(mixer, desc);
|
|
532
|
+
}
|