@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
|
+
* Pose matching: a transition starts the target clip at the frame nearest the pose it leaves,
|
|
3
|
+
* instead of at 0, so a walk→run blend does not snap a planted foot to the other leg.
|
|
4
|
+
*
|
|
5
|
+
* `buildPoseFeatures` samples a clip at a fixed rate and stores, per sample, the root-space
|
|
6
|
+
* position and velocity of a few joints (feet, hands, head). `findBestFrame` compares a pose's
|
|
7
|
+
* world matrices (plus per-joint velocities) against every sample and returns the time of the
|
|
8
|
+
* cheapest one. Root space is the frame of one node (the first root by default) so a clip's
|
|
9
|
+
* baked travel and the instance's placement drop out. Allocates at build; the query allocates
|
|
10
|
+
* nothing when given an `out`.
|
|
11
|
+
*/
|
|
12
|
+
import { sampleClip } from './clip.js';
|
|
13
|
+
import { invertAffine, poseToWorld, WORLD_NODE_FLOATS } from './pose.js';
|
|
14
|
+
/** Floats per joint per sample. */
|
|
15
|
+
const PER_JOINT = 6;
|
|
16
|
+
const inv = new Float32Array(WORLD_NODE_FLOATS);
|
|
17
|
+
const p = new Float32Array(3);
|
|
18
|
+
/** `out = inverse root (3×4) · point`. */
|
|
19
|
+
function toRoot(out, m, px, py, pz) {
|
|
20
|
+
out[0] = m[0] * px + m[1] * py + m[2] * pz + m[3];
|
|
21
|
+
out[1] = m[4] * px + m[5] * py + m[6] * pz + m[7];
|
|
22
|
+
out[2] = m[8] * px + m[9] * py + m[10] * pz + m[11];
|
|
23
|
+
}
|
|
24
|
+
/** @internal The first node with no parent (0 when none). */
|
|
25
|
+
export function firstRoot(skeleton) {
|
|
26
|
+
const parents = skeleton.parents;
|
|
27
|
+
for (let i = 0; i < parents.length; i++)
|
|
28
|
+
if (parents[i] < 0)
|
|
29
|
+
return i;
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Sample `clip` on `skeleton` every `1 / sampleRate` seconds (the last sample at the clip's
|
|
34
|
+
* duration) and record, per sample and per joint of `opts.joints`, the joint's root-space
|
|
35
|
+
* position and velocity (finite difference to the next sample; the last sample wraps to the
|
|
36
|
+
* first, as a looping clip does). Allocates; call at load.
|
|
37
|
+
*/
|
|
38
|
+
export function buildPoseFeatures(clip, skeleton, opts) {
|
|
39
|
+
const rate = opts.sampleRate ?? 30;
|
|
40
|
+
if (!(rate > 0))
|
|
41
|
+
throw new Error(`buildPoseFeatures: sampleRate ${rate} must be > 0`);
|
|
42
|
+
const n = skeleton.parents.length;
|
|
43
|
+
const joints = Int16Array.from(opts.joints);
|
|
44
|
+
for (let j = 0; j < joints.length; j++) {
|
|
45
|
+
const node = joints[j];
|
|
46
|
+
if (node < 0 || node >= n)
|
|
47
|
+
throw new Error(`buildPoseFeatures: joint ${node} is not a node (${n} nodes)`);
|
|
48
|
+
}
|
|
49
|
+
const root = opts.root ?? firstRoot(skeleton);
|
|
50
|
+
if (root < 0 || root >= n)
|
|
51
|
+
throw new Error(`buildPoseFeatures: root ${root} is not a node (${n} nodes)`);
|
|
52
|
+
const duration = Math.max(0, clip.duration);
|
|
53
|
+
const count = Math.max(1, Math.round(duration * rate)) + 1;
|
|
54
|
+
const times = new Float32Array(count);
|
|
55
|
+
const stride = joints.length * PER_JOINT;
|
|
56
|
+
const data = new Float32Array(count * stride);
|
|
57
|
+
const pose = new Float32Array(skeleton.rest);
|
|
58
|
+
const world = new Float32Array(n * WORLD_NODE_FLOATS);
|
|
59
|
+
const cursor = new Uint32Array(Math.max(1, clip.channels.length));
|
|
60
|
+
// Positions first.
|
|
61
|
+
for (let s = 0; s < count; s++) {
|
|
62
|
+
const t = count > 1 ? (duration * s) / (count - 1) : 0;
|
|
63
|
+
times[s] = t;
|
|
64
|
+
pose.set(skeleton.rest);
|
|
65
|
+
sampleClip(clip, t, pose, 1, 'override', cursor);
|
|
66
|
+
poseToWorld(skeleton, pose, world);
|
|
67
|
+
invertAffine(inv, 0, world, root * WORLD_NODE_FLOATS);
|
|
68
|
+
for (let j = 0; j < joints.length; j++) {
|
|
69
|
+
const wo = joints[j] * WORLD_NODE_FLOATS;
|
|
70
|
+
toRoot(p, inv, world[wo + 3], world[wo + 7], world[wo + 11]);
|
|
71
|
+
const o = s * stride + j * PER_JOINT;
|
|
72
|
+
data[o] = p[0];
|
|
73
|
+
data[o + 1] = p[1];
|
|
74
|
+
data[o + 2] = p[2];
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Velocities: central difference, wrapping around the ends as a looping clip does (the
|
|
78
|
+
// last sample is the first again, so its neighbours are the second and the second to last).
|
|
79
|
+
const dt = count > 1 ? duration / (count - 1) : 1;
|
|
80
|
+
const span = count > 2 ? 2 * dt : dt;
|
|
81
|
+
for (let s = 0; s < count; s++) {
|
|
82
|
+
const next = s + 1 < count ? s + 1 : count > 2 ? 1 : s;
|
|
83
|
+
const prev = s > 0 ? s - 1 : count > 2 ? count - 2 : s;
|
|
84
|
+
for (let j = 0; j < joints.length; j++) {
|
|
85
|
+
const o = s * stride + j * PER_JOINT;
|
|
86
|
+
const no = next * stride + j * PER_JOINT;
|
|
87
|
+
const po = prev * stride + j * PER_JOINT;
|
|
88
|
+
data[o + 3] = span > 0 ? (data[no] - data[po]) / span : 0;
|
|
89
|
+
data[o + 4] = span > 0 ? (data[no + 1] - data[po + 1]) / span : 0;
|
|
90
|
+
data[o + 5] = span > 0 ? (data[no + 2] - data[po + 2]) / span : 0;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return { clip, joints, root, times, data, stride };
|
|
94
|
+
}
|
|
95
|
+
const DEFAULT_OUT = { time: 0, cost: 0 };
|
|
96
|
+
/**
|
|
97
|
+
* Root-space positions of `joints` (3 floats each into `out`) from a pose's world matrices:
|
|
98
|
+
* what a velocity for `findBestFrame` is the time derivative of. Allocation-free.
|
|
99
|
+
*/
|
|
100
|
+
export function rootSpacePositions(poseWorld, root, joints, out) {
|
|
101
|
+
invertAffine(inv, 0, poseWorld, root * WORLD_NODE_FLOATS);
|
|
102
|
+
for (let j = 0; j < joints.length; j++) {
|
|
103
|
+
const wo = joints[j] * WORLD_NODE_FLOATS;
|
|
104
|
+
toRoot(p, inv, poseWorld[wo + 3], poseWorld[wo + 7], poseWorld[wo + 11]);
|
|
105
|
+
out[j * 3] = p[0];
|
|
106
|
+
out[j * 3 + 1] = p[1];
|
|
107
|
+
out[j * 3 + 2] = p[2];
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* The sample of `features` nearest a pose: `poseWorld` is `poseToWorld` of that pose (skeleton
|
|
112
|
+
* space; the root node's matrix in it defines root space), `velocity` holds the root-space
|
|
113
|
+
* velocity of each feature joint (`3 × joints` floats in `features.joints` order: the
|
|
114
|
+
* derivative of `rootSpacePositions`, so the root's own travel drops out), or `null` to match
|
|
115
|
+
* on positions alone. Cost per sample is the summed squared position gap plus `velocityWeight`
|
|
116
|
+
* times the summed squared velocity gap. Writes and returns `out` (a shared object when none
|
|
117
|
+
* is given). No allocation with `out`.
|
|
118
|
+
*/
|
|
119
|
+
export function findBestFrame(features, poseWorld, velocity, opts, out = DEFAULT_OUT) {
|
|
120
|
+
const vw = opts?.velocityWeight ?? 0.05;
|
|
121
|
+
const joints = features.joints;
|
|
122
|
+
const stride = features.stride;
|
|
123
|
+
const data = features.data;
|
|
124
|
+
invertAffine(inv, 0, poseWorld, features.root * WORLD_NODE_FLOATS);
|
|
125
|
+
let best = -1;
|
|
126
|
+
let bestCost = Number.POSITIVE_INFINITY;
|
|
127
|
+
const count = features.times.length;
|
|
128
|
+
for (let s = 0; s < count; s++) {
|
|
129
|
+
let cost = 0;
|
|
130
|
+
for (let j = 0; j < joints.length; j++) {
|
|
131
|
+
const wo = joints[j] * WORLD_NODE_FLOATS;
|
|
132
|
+
const o = s * stride + j * PER_JOINT;
|
|
133
|
+
toRoot(p, inv, poseWorld[wo + 3], poseWorld[wo + 7], poseWorld[wo + 11]);
|
|
134
|
+
const dx = p[0] - data[o];
|
|
135
|
+
const dy = p[1] - data[o + 1];
|
|
136
|
+
const dz = p[2] - data[o + 2];
|
|
137
|
+
cost += dx * dx + dy * dy + dz * dz;
|
|
138
|
+
if (velocity && vw > 0) {
|
|
139
|
+
const vx = velocity[j * 3] - data[o + 3];
|
|
140
|
+
const vy = velocity[j * 3 + 1] - data[o + 4];
|
|
141
|
+
const vz = velocity[j * 3 + 2] - data[o + 5];
|
|
142
|
+
cost += vw * (vx * vx + vy * vy + vz * vz);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (cost < bestCost) {
|
|
146
|
+
bestCost = cost;
|
|
147
|
+
best = s;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
out.time = best >= 0 ? features.times[best] : 0;
|
|
151
|
+
out.cost = best >= 0 ? bestCost : 0;
|
|
152
|
+
return out;
|
|
153
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `AnimationMixer`: plays clips on a skeleton as weighted, layered actions and writes one
|
|
3
|
+
* `Pose` per `update(dt)`.
|
|
4
|
+
*
|
|
5
|
+
* Composition, per update: `pose = rest`; then for each layer in ascending order, the layer's
|
|
6
|
+
* override actions are averaged by effective weight (so a crossfade whose weights sum to 1
|
|
7
|
+
* neither shrinks nor overshoots) and lerped onto the pose by `min(1, Σ weights)`, then the
|
|
8
|
+
* layer's additive actions are added with their own weights. An action's effective weight is
|
|
9
|
+
* `action.weight × fade`, where fades come from `fadeIn`, `crossFade` and `stop(action, fade)`.
|
|
10
|
+
*
|
|
11
|
+
* Actions come from a fixed pool (`maxActions`, default 8); `play` reuses a finished slot and
|
|
12
|
+
* throws when none is free. After the pool and the per-action cursors exist, `update` allocates
|
|
13
|
+
* nothing.
|
|
14
|
+
*/
|
|
15
|
+
import { type AnimationClip, type AnimBlendMode, type ClipCursor } from './clip.js';
|
|
16
|
+
import { type Pose, type Skeleton } from './pose.js';
|
|
17
|
+
export interface AnimPlayOptions {
|
|
18
|
+
/** Layer, ascending order of application. Default 0. */
|
|
19
|
+
layer?: number;
|
|
20
|
+
/** Target weight, 0..1. Default 1. */
|
|
21
|
+
weight?: number;
|
|
22
|
+
/** Loop at `clip.duration` (default true); `false` holds the last frame and sets `finished`. */
|
|
23
|
+
loop?: boolean;
|
|
24
|
+
/** Time scale; negative plays backwards. Default 1. */
|
|
25
|
+
speed?: number;
|
|
26
|
+
/** Seconds to fade the weight in from 0. Default 0. */
|
|
27
|
+
fadeIn?: number;
|
|
28
|
+
/** `'override'` (default) or `'additive'`, see `sampleClip`. */
|
|
29
|
+
blend?: AnimBlendMode;
|
|
30
|
+
/** Start time in seconds. Default 0 (or `clip.duration` when `speed < 0`). */
|
|
31
|
+
startTime?: number;
|
|
32
|
+
}
|
|
33
|
+
export type AnimationEventListener = (name: string, action: AnimationAction) => void;
|
|
34
|
+
/** One playing clip. Fields marked settable may be changed between updates. */
|
|
35
|
+
export declare class AnimationAction {
|
|
36
|
+
/** The clip; `null` while the slot is free. */
|
|
37
|
+
clip: AnimationClip | null;
|
|
38
|
+
layer: number;
|
|
39
|
+
/** Target weight (settable). */
|
|
40
|
+
weight: number;
|
|
41
|
+
/** Settable. */
|
|
42
|
+
loop: boolean;
|
|
43
|
+
/** Settable. */
|
|
44
|
+
speed: number;
|
|
45
|
+
/** Current time in seconds, settable (wrapped into `[0, duration)` when looping). */
|
|
46
|
+
time: number;
|
|
47
|
+
/** Settable: a paused action keeps its pose and weight but does not advance. */
|
|
48
|
+
paused: boolean;
|
|
49
|
+
blend: AnimBlendMode;
|
|
50
|
+
/** True once a non-looping action reached its end (or start when reversed). */
|
|
51
|
+
finished: boolean;
|
|
52
|
+
/** `weight × fade` from the last update; what the pose actually used. */
|
|
53
|
+
effectiveWeight: number;
|
|
54
|
+
/** @internal */
|
|
55
|
+
fadeFrom: number;
|
|
56
|
+
/** @internal */
|
|
57
|
+
fadeTo: number;
|
|
58
|
+
/** @internal */
|
|
59
|
+
fadeDuration: number;
|
|
60
|
+
/** @internal */
|
|
61
|
+
fadeElapsed: number;
|
|
62
|
+
/** @internal first update after `play` includes events at exactly `startTime`. */
|
|
63
|
+
fresh: boolean;
|
|
64
|
+
/** @internal */
|
|
65
|
+
cursor: ClipCursor;
|
|
66
|
+
/** True while the action contributes to the mixer. */
|
|
67
|
+
get active(): boolean;
|
|
68
|
+
/** The fade factor now (0..1). */
|
|
69
|
+
get fade(): number;
|
|
70
|
+
/** @internal */
|
|
71
|
+
startFade(to: number, seconds: number): void;
|
|
72
|
+
}
|
|
73
|
+
export interface AnimationMixerOptions {
|
|
74
|
+
/** Pool size: the most actions playing (including fading out) at once. Default 8. */
|
|
75
|
+
maxActions?: number;
|
|
76
|
+
}
|
|
77
|
+
export declare class AnimationMixer {
|
|
78
|
+
readonly skeleton: Skeleton;
|
|
79
|
+
/** The composed pose, rewritten by every `update`. */
|
|
80
|
+
readonly pose: Pose;
|
|
81
|
+
/** Every slot of the pool, free or not; filter on `active`. */
|
|
82
|
+
readonly actions: readonly AnimationAction[];
|
|
83
|
+
private readonly scratch;
|
|
84
|
+
private readonly listeners;
|
|
85
|
+
constructor(skeleton: Skeleton, opts?: AnimationMixerOptions);
|
|
86
|
+
/** Number of active actions. */
|
|
87
|
+
get playing(): number;
|
|
88
|
+
/** Start `clip` in a free slot. Throws when the pool (`maxActions`) is full. */
|
|
89
|
+
play(clip: AnimationClip, opts?: AnimPlayOptions): AnimationAction;
|
|
90
|
+
/**
|
|
91
|
+
* Fade `from` out over `seconds` (it stops at 0) while `to` fades in on the same layer; the
|
|
92
|
+
* two effective weights sum to `from.weight` throughout when `to.weight` matches. `to` may be
|
|
93
|
+
* a clip (started here) or an action already playing. Returns the incoming action.
|
|
94
|
+
*/
|
|
95
|
+
crossFade(from: AnimationAction, to: AnimationClip | AnimationAction, seconds: number, opts?: AnimPlayOptions): AnimationAction;
|
|
96
|
+
/** Stop an action, at once or after a fade-out of `seconds`. */
|
|
97
|
+
stop(action: AnimationAction, seconds?: number): void;
|
|
98
|
+
/** Stop every action at once. */
|
|
99
|
+
stopAll(): void;
|
|
100
|
+
/** Listen for `clip.events` crossings. Returns the unsubscribe function. */
|
|
101
|
+
onEvent(cb: AnimationEventListener): () => void;
|
|
102
|
+
/** Advance every action by `dt` seconds and recompose `pose`. */
|
|
103
|
+
update(dt: number): void;
|
|
104
|
+
private release;
|
|
105
|
+
private advance;
|
|
106
|
+
/**
|
|
107
|
+
* Fire events whose time lies in `(prev, next]` (or `[prev, next]` when `inclusive`),
|
|
108
|
+
* unwrapped: looping actions see the clip repeated, so `e + k·duration` counts.
|
|
109
|
+
*/
|
|
110
|
+
private fireEvents;
|
|
111
|
+
private crosses;
|
|
112
|
+
private emit;
|
|
113
|
+
}
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `AnimationMixer`: plays clips on a skeleton as weighted, layered actions and writes one
|
|
3
|
+
* `Pose` per `update(dt)`.
|
|
4
|
+
*
|
|
5
|
+
* Composition, per update: `pose = rest`; then for each layer in ascending order, the layer's
|
|
6
|
+
* override actions are averaged by effective weight (so a crossfade whose weights sum to 1
|
|
7
|
+
* neither shrinks nor overshoots) and lerped onto the pose by `min(1, Σ weights)`, then the
|
|
8
|
+
* layer's additive actions are added with their own weights. An action's effective weight is
|
|
9
|
+
* `action.weight × fade`, where fades come from `fadeIn`, `crossFade` and `stop(action, fade)`.
|
|
10
|
+
*
|
|
11
|
+
* Actions come from a fixed pool (`maxActions`, default 8); `play` reuses a finished slot and
|
|
12
|
+
* throws when none is free. After the pool and the per-action cursors exist, `update` allocates
|
|
13
|
+
* nothing.
|
|
14
|
+
*/
|
|
15
|
+
import { createClipCursor, sampleClip, } from './clip.js';
|
|
16
|
+
import { blendPose, createPose } from './pose.js';
|
|
17
|
+
/** One playing clip. Fields marked settable may be changed between updates. */
|
|
18
|
+
export class AnimationAction {
|
|
19
|
+
/** The clip; `null` while the slot is free. */
|
|
20
|
+
clip = null;
|
|
21
|
+
layer = 0;
|
|
22
|
+
/** Target weight (settable). */
|
|
23
|
+
weight = 1;
|
|
24
|
+
/** Settable. */
|
|
25
|
+
loop = true;
|
|
26
|
+
/** Settable. */
|
|
27
|
+
speed = 1;
|
|
28
|
+
/** Current time in seconds, settable (wrapped into `[0, duration)` when looping). */
|
|
29
|
+
time = 0;
|
|
30
|
+
/** Settable: a paused action keeps its pose and weight but does not advance. */
|
|
31
|
+
paused = false;
|
|
32
|
+
blend = 'override';
|
|
33
|
+
/** True once a non-looping action reached its end (or start when reversed). */
|
|
34
|
+
finished = false;
|
|
35
|
+
/** `weight × fade` from the last update; what the pose actually used. */
|
|
36
|
+
effectiveWeight = 0;
|
|
37
|
+
/** @internal */
|
|
38
|
+
fadeFrom = 1;
|
|
39
|
+
/** @internal */
|
|
40
|
+
fadeTo = 1;
|
|
41
|
+
/** @internal */
|
|
42
|
+
fadeDuration = 0;
|
|
43
|
+
/** @internal */
|
|
44
|
+
fadeElapsed = 0;
|
|
45
|
+
/** @internal first update after `play` includes events at exactly `startTime`. */
|
|
46
|
+
fresh = true;
|
|
47
|
+
/** @internal */
|
|
48
|
+
cursor = new Uint32Array(1);
|
|
49
|
+
/** True while the action contributes to the mixer. */
|
|
50
|
+
get active() {
|
|
51
|
+
return this.clip !== null;
|
|
52
|
+
}
|
|
53
|
+
/** The fade factor now (0..1). */
|
|
54
|
+
get fade() {
|
|
55
|
+
if (this.fadeDuration <= 0)
|
|
56
|
+
return this.fadeTo;
|
|
57
|
+
const u = Math.min(1, this.fadeElapsed / this.fadeDuration);
|
|
58
|
+
return this.fadeFrom + (this.fadeTo - this.fadeFrom) * u;
|
|
59
|
+
}
|
|
60
|
+
/** @internal */
|
|
61
|
+
startFade(to, seconds) {
|
|
62
|
+
this.fadeFrom = this.fade;
|
|
63
|
+
this.fadeTo = to;
|
|
64
|
+
this.fadeDuration = seconds;
|
|
65
|
+
this.fadeElapsed = 0;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export class AnimationMixer {
|
|
69
|
+
skeleton;
|
|
70
|
+
/** The composed pose, rewritten by every `update`. */
|
|
71
|
+
pose;
|
|
72
|
+
/** Every slot of the pool, free or not; filter on `active`. */
|
|
73
|
+
actions;
|
|
74
|
+
scratch;
|
|
75
|
+
listeners = [];
|
|
76
|
+
constructor(skeleton, opts = {}) {
|
|
77
|
+
this.skeleton = skeleton;
|
|
78
|
+
this.pose = createPose(skeleton);
|
|
79
|
+
this.scratch = createPose(skeleton);
|
|
80
|
+
const n = Math.max(1, opts.maxActions ?? 8);
|
|
81
|
+
const pool = [];
|
|
82
|
+
for (let i = 0; i < n; i++)
|
|
83
|
+
pool.push(new AnimationAction());
|
|
84
|
+
this.actions = pool;
|
|
85
|
+
}
|
|
86
|
+
/** Number of active actions. */
|
|
87
|
+
get playing() {
|
|
88
|
+
let n = 0;
|
|
89
|
+
for (const a of this.actions)
|
|
90
|
+
if (a.clip)
|
|
91
|
+
n++;
|
|
92
|
+
return n;
|
|
93
|
+
}
|
|
94
|
+
/** Start `clip` in a free slot. Throws when the pool (`maxActions`) is full. */
|
|
95
|
+
play(clip, opts = {}) {
|
|
96
|
+
let slot = null;
|
|
97
|
+
for (const a of this.actions) {
|
|
98
|
+
if (!a.clip) {
|
|
99
|
+
slot = a;
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (!slot)
|
|
104
|
+
throw new Error(`AnimationMixer: all ${this.actions.length} action slots are playing`);
|
|
105
|
+
slot.clip = clip;
|
|
106
|
+
slot.layer = opts.layer ?? 0;
|
|
107
|
+
slot.weight = opts.weight ?? 1;
|
|
108
|
+
slot.loop = opts.loop ?? true;
|
|
109
|
+
slot.speed = opts.speed ?? 1;
|
|
110
|
+
slot.blend = opts.blend ?? 'override';
|
|
111
|
+
slot.paused = false;
|
|
112
|
+
slot.finished = false;
|
|
113
|
+
slot.fresh = true;
|
|
114
|
+
slot.time = opts.startTime ?? (slot.speed < 0 ? clip.duration : 0);
|
|
115
|
+
slot.fadeFrom = 1;
|
|
116
|
+
slot.fadeTo = 1;
|
|
117
|
+
slot.fadeDuration = 0;
|
|
118
|
+
slot.fadeElapsed = 0;
|
|
119
|
+
if (opts.fadeIn && opts.fadeIn > 0) {
|
|
120
|
+
slot.fadeFrom = 0;
|
|
121
|
+
slot.fadeDuration = opts.fadeIn;
|
|
122
|
+
}
|
|
123
|
+
slot.effectiveWeight = slot.weight * slot.fade;
|
|
124
|
+
if (slot.cursor.length < clip.channels.length)
|
|
125
|
+
slot.cursor = createClipCursor(clip);
|
|
126
|
+
else
|
|
127
|
+
slot.cursor.fill(0);
|
|
128
|
+
return slot;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Fade `from` out over `seconds` (it stops at 0) while `to` fades in on the same layer; the
|
|
132
|
+
* two effective weights sum to `from.weight` throughout when `to.weight` matches. `to` may be
|
|
133
|
+
* a clip (started here) or an action already playing. Returns the incoming action.
|
|
134
|
+
*/
|
|
135
|
+
crossFade(from, to, seconds, opts = {}) {
|
|
136
|
+
const target = to instanceof AnimationAction
|
|
137
|
+
? to
|
|
138
|
+
: this.play(to, {
|
|
139
|
+
layer: from.layer,
|
|
140
|
+
weight: from.weight,
|
|
141
|
+
blend: from.blend,
|
|
142
|
+
...opts,
|
|
143
|
+
fadeIn: seconds,
|
|
144
|
+
});
|
|
145
|
+
if (target !== from) {
|
|
146
|
+
if (to instanceof AnimationAction && (target.fade < 1 || target.fadeTo < 1)) {
|
|
147
|
+
target.startFade(1, seconds);
|
|
148
|
+
target.effectiveWeight = target.weight * target.fade;
|
|
149
|
+
}
|
|
150
|
+
this.stop(from, seconds);
|
|
151
|
+
}
|
|
152
|
+
return target;
|
|
153
|
+
}
|
|
154
|
+
/** Stop an action, at once or after a fade-out of `seconds`. */
|
|
155
|
+
stop(action, seconds = 0) {
|
|
156
|
+
if (!action.clip)
|
|
157
|
+
return;
|
|
158
|
+
if (seconds > 0)
|
|
159
|
+
action.startFade(0, seconds);
|
|
160
|
+
else
|
|
161
|
+
this.release(action);
|
|
162
|
+
}
|
|
163
|
+
/** Stop every action at once. */
|
|
164
|
+
stopAll() {
|
|
165
|
+
for (const a of this.actions)
|
|
166
|
+
if (a.clip)
|
|
167
|
+
this.release(a);
|
|
168
|
+
this.pose.set(this.skeleton.rest);
|
|
169
|
+
}
|
|
170
|
+
/** Listen for `clip.events` crossings. Returns the unsubscribe function. */
|
|
171
|
+
onEvent(cb) {
|
|
172
|
+
this.listeners.push(cb);
|
|
173
|
+
return () => {
|
|
174
|
+
const i = this.listeners.indexOf(cb);
|
|
175
|
+
if (i >= 0)
|
|
176
|
+
this.listeners.splice(i, 1);
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/** Advance every action by `dt` seconds and recompose `pose`. */
|
|
180
|
+
update(dt) {
|
|
181
|
+
const actions = this.actions;
|
|
182
|
+
let minLayer = Number.POSITIVE_INFINITY;
|
|
183
|
+
let maxLayer = Number.NEGATIVE_INFINITY;
|
|
184
|
+
for (const a of actions) {
|
|
185
|
+
if (!a.clip)
|
|
186
|
+
continue;
|
|
187
|
+
this.advance(a, dt);
|
|
188
|
+
if (!a.clip)
|
|
189
|
+
continue;
|
|
190
|
+
if (a.layer < minLayer)
|
|
191
|
+
minLayer = a.layer;
|
|
192
|
+
if (a.layer > maxLayer)
|
|
193
|
+
maxLayer = a.layer;
|
|
194
|
+
}
|
|
195
|
+
const pose = this.pose;
|
|
196
|
+
pose.set(this.skeleton.rest);
|
|
197
|
+
if (minLayer > maxLayer)
|
|
198
|
+
return;
|
|
199
|
+
const scratch = this.scratch;
|
|
200
|
+
for (let layer = minLayer; layer <= maxLayer; layer++) {
|
|
201
|
+
let sum = 0;
|
|
202
|
+
for (const a of actions) {
|
|
203
|
+
if (!a.clip || a.layer !== layer || a.blend !== 'override' || a.effectiveWeight <= 0)
|
|
204
|
+
continue;
|
|
205
|
+
if (sum === 0)
|
|
206
|
+
scratch.set(pose);
|
|
207
|
+
sum += a.effectiveWeight;
|
|
208
|
+
sampleClip(a.clip, a.time, scratch, a.effectiveWeight / sum, 'override', a.cursor);
|
|
209
|
+
}
|
|
210
|
+
if (sum > 0)
|
|
211
|
+
blendPose(pose, scratch, Math.min(sum, 1), pose);
|
|
212
|
+
for (const a of actions) {
|
|
213
|
+
if (!a.clip || a.layer !== layer || a.blend !== 'additive' || a.effectiveWeight <= 0)
|
|
214
|
+
continue;
|
|
215
|
+
sampleClip(a.clip, a.time, pose, a.effectiveWeight, 'additive', a.cursor);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
release(action) {
|
|
220
|
+
action.clip = null;
|
|
221
|
+
action.effectiveWeight = 0;
|
|
222
|
+
action.fadeTo = 1;
|
|
223
|
+
action.fadeFrom = 1;
|
|
224
|
+
action.fadeDuration = 0;
|
|
225
|
+
}
|
|
226
|
+
advance(a, dt) {
|
|
227
|
+
const clip = a.clip;
|
|
228
|
+
if (a.fadeDuration > 0) {
|
|
229
|
+
a.fadeElapsed += dt;
|
|
230
|
+
if (a.fadeElapsed >= a.fadeDuration) {
|
|
231
|
+
a.fadeFrom = a.fadeTo;
|
|
232
|
+
a.fadeDuration = 0;
|
|
233
|
+
if (a.fadeTo <= 0) {
|
|
234
|
+
this.release(a);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
a.effectiveWeight = a.weight * a.fade;
|
|
240
|
+
const d = clip.duration;
|
|
241
|
+
const prev = a.time;
|
|
242
|
+
const fresh = a.fresh;
|
|
243
|
+
a.fresh = false;
|
|
244
|
+
if (a.paused || (a.finished && !a.loop)) {
|
|
245
|
+
if (fresh)
|
|
246
|
+
this.fireEvents(a, prev, prev, true);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
let next = prev + dt * a.speed;
|
|
250
|
+
if (d <= 0) {
|
|
251
|
+
a.time = 0;
|
|
252
|
+
if (!a.loop)
|
|
253
|
+
a.finished = true;
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
if (!a.loop) {
|
|
257
|
+
if (a.speed >= 0 && next >= d) {
|
|
258
|
+
next = d;
|
|
259
|
+
a.finished = true;
|
|
260
|
+
}
|
|
261
|
+
else if (a.speed < 0 && next <= 0) {
|
|
262
|
+
next = 0;
|
|
263
|
+
a.finished = true;
|
|
264
|
+
}
|
|
265
|
+
this.fireEvents(a, prev, next, fresh);
|
|
266
|
+
a.time = next;
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
this.fireEvents(a, prev, next, fresh);
|
|
270
|
+
// Wrap into [0, d).
|
|
271
|
+
let w = next % d;
|
|
272
|
+
if (w < 0)
|
|
273
|
+
w += d;
|
|
274
|
+
a.time = w;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Fire events whose time lies in `(prev, next]` (or `[prev, next]` when `inclusive`),
|
|
278
|
+
* unwrapped: looping actions see the clip repeated, so `e + k·duration` counts.
|
|
279
|
+
*/
|
|
280
|
+
fireEvents(a, prev, next, inclusive) {
|
|
281
|
+
const clip = a.clip;
|
|
282
|
+
const events = clip.events;
|
|
283
|
+
if (!events || events.length === 0 || this.listeners.length === 0)
|
|
284
|
+
return;
|
|
285
|
+
const d = clip.duration;
|
|
286
|
+
const forward = next >= prev;
|
|
287
|
+
const lo = forward ? prev : next;
|
|
288
|
+
const hi = forward ? next : prev;
|
|
289
|
+
// Loop repetitions that can touch [lo, hi]; events fire in playback order (k outer, the
|
|
290
|
+
// clip's event order inner, both reversed when playing backwards).
|
|
291
|
+
const loops = a.loop && d > 0;
|
|
292
|
+
const kLo = loops ? Math.floor(lo / d) - 1 : 0;
|
|
293
|
+
const kHi = loops ? Math.floor(hi / d) + 1 : 0;
|
|
294
|
+
const n = events.length;
|
|
295
|
+
for (let s = 0; s <= kHi - kLo; s++) {
|
|
296
|
+
const k = forward ? kLo + s : kHi - s;
|
|
297
|
+
for (let j = 0; j < n; j++) {
|
|
298
|
+
const e = events[forward ? j : n - 1 - j];
|
|
299
|
+
const et = e.time + k * d;
|
|
300
|
+
if (this.crosses(et, prev, next, inclusive && k === 0, forward))
|
|
301
|
+
this.emit(e.name, a);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
crosses(et, prev, next, inclusive, forward) {
|
|
306
|
+
if (forward)
|
|
307
|
+
return (inclusive ? et >= prev : et > prev) && et <= next;
|
|
308
|
+
return (inclusive ? et <= prev : et < prev) && et >= next;
|
|
309
|
+
}
|
|
310
|
+
emit(name, a) {
|
|
311
|
+
for (let i = 0; i < this.listeners.length; i++)
|
|
312
|
+
this.listeners[i](name, a);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Morph targets (blend shapes) on the CPU: `base + Σ weight × delta` per vertex, written into
|
|
3
|
+
* the position and normal lanes of an interleaved vertex buffer the mesh then uploads
|
|
4
|
+
* (`Mesh.update`). The arithmetic is here; the parser (`assets/gltf.ts`) fills `MorphTarget`s
|
|
5
|
+
* and the loader (`assets/gltf-load.ts`) owns the buffers and the upload. Nothing allocates
|
|
6
|
+
* after `createMorphBlender`.
|
|
7
|
+
*/
|
|
8
|
+
/** Per-vertex deltas of one target, 3 floats per vertex, or null when it leaves that lane alone. */
|
|
9
|
+
export interface MorphTarget {
|
|
10
|
+
position: Float32Array | null;
|
|
11
|
+
normal: Float32Array | null;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Where positions and normals sit in an interleaved vertex: `floats` per vertex, and the float
|
|
15
|
+
* offsets of the position (default 0) and normal (default 3; null when the layout has none).
|
|
16
|
+
* `VERTEX_LAYOUT_3D` from `render/mesh.ts` fits as is.
|
|
17
|
+
*/
|
|
18
|
+
export interface MorphLayout {
|
|
19
|
+
readonly floats: number;
|
|
20
|
+
readonly positionOffset?: number;
|
|
21
|
+
readonly normalOffset?: number | null;
|
|
22
|
+
}
|
|
23
|
+
export interface MorphBlender {
|
|
24
|
+
/** One weight per target; the game (or `sampleWeights`) writes here, `apply` reads. */
|
|
25
|
+
readonly weights: Float32Array;
|
|
26
|
+
readonly targetCount: number;
|
|
27
|
+
readonly vertexCount: number;
|
|
28
|
+
/**
|
|
29
|
+
* Write `base + Σ weights[i] × targets[i]` into `out`'s position and normal lanes (normals
|
|
30
|
+
* renormalised). Returns false, writing nothing, when no weight changed since the last apply
|
|
31
|
+
* into this same `out`; a first call or a new `out` copies the whole base first. No allocation.
|
|
32
|
+
*/
|
|
33
|
+
apply(out: Float32Array): boolean;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* A blender over `base` (the primitive's interleaved vertices in `layout`) and its `targets`.
|
|
37
|
+
* `weights` may be the array the blender should read (shared between the primitives of a mesh);
|
|
38
|
+
* it defaults to zeros, `targets.length` long. Throws when a target's deltas do not cover
|
|
39
|
+
* `base`'s vertices or `weights` is shorter than `targets`.
|
|
40
|
+
*/
|
|
41
|
+
export declare function createMorphBlender(base: Float32Array, targets: readonly MorphTarget[], layout: MorphLayout, weights?: Float32Array): MorphBlender;
|