@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,662 @@
|
|
|
1
|
+
import { Loupe } from '../ui/loupe.js';
|
|
2
|
+
import { resolveClock } from './clock.js';
|
|
3
|
+
import { loupeClear, loupeSpot, MAGNIFY_DEFAULTS, magnifySize, } from './magnify.js';
|
|
4
|
+
import { createPointerDispatcher, POINTER_PRIORITY, } from './pointer-dispatch.js';
|
|
5
|
+
const DEFAULTS = {
|
|
6
|
+
panThreshold: 10,
|
|
7
|
+
longPressMs: 450,
|
|
8
|
+
doubleTapMs: 300,
|
|
9
|
+
doubleTapDistance: 24,
|
|
10
|
+
};
|
|
11
|
+
/** Most taps (of one kind) queued for later ticks. */
|
|
12
|
+
const MAX_QUEUED = 8;
|
|
13
|
+
/** Fraction of `panThreshold` past which a pointer is a pan candidate. */
|
|
14
|
+
const CANDIDATE_FRACTION = 0.25;
|
|
15
|
+
const CONTINUOUS = ['pan', 'drag', 'pinch'];
|
|
16
|
+
/**
|
|
17
|
+
* Touch and pointer gestures: tap, double tap, long-press, pan, drag and pinch. Feed it pointer
|
|
18
|
+
* events (via `attach` or the public feed methods), call `update()` once per simulation tick,
|
|
19
|
+
* then read this tick's gestures. Thresholds are CSS px; positions are game space through the
|
|
20
|
+
* same `PointerTransform` as `Input`.
|
|
21
|
+
*
|
|
22
|
+
* ```ts
|
|
23
|
+
* const gestures = new Gestures();
|
|
24
|
+
* input.setGestures(gestures); // shares blocked(), the transform, attach and update()
|
|
25
|
+
* // each tick, after input.update():
|
|
26
|
+
* if (gestures.tap) select(gestures.tap.x, gestures.tap.y);
|
|
27
|
+
* if (gestures.drag?.phase === 'move') moveBy(gestures.drag.dx, gestures.drag.dy);
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* Or bind them as actions: `{ select: [{ gesture: 'tap' }], info: [{ gesture: 'longPress' }] }`.
|
|
31
|
+
*
|
|
32
|
+
* Rules:
|
|
33
|
+
* - A tap is a down and up that stays within `panThreshold` and ends before `longPressMs`. A
|
|
34
|
+
* double tap also reports a tap for each of its two taps.
|
|
35
|
+
* - A long-press fires once, after `longPressMs` within the threshold; no tap follows it.
|
|
36
|
+
* - Moving past the threshold starts a pan and a drag (one pointer) for the rest of the press.
|
|
37
|
+
* Travel is cumulative from the down point, so a slow drag crosses it too, and the threshold
|
|
38
|
+
* is checked before the long-press timer on every move: a pointer whose travel crosses it
|
|
39
|
+
* never long-presses, however long the frame took. A long-press that already fired stays.
|
|
40
|
+
* - A second pointer cancels the pan and drag (and any tap or long-press) and starts a pinch;
|
|
41
|
+
* while two or more pointers are down, pan and drag report nothing (pinch wins). Lifting
|
|
42
|
+
* either pointer ends the pinch; nothing more is reported until every pointer is up.
|
|
43
|
+
* - Discrete gestures that arrive faster than ticks are queued, one per kind per tick. Moves in
|
|
44
|
+
* one tick are merged; `start` and `end` each get their own tick. While a pan, drag or pinch
|
|
45
|
+
* runs, every tick reports it (a `move` with no change when nothing moved).
|
|
46
|
+
* - While `blocked()` nothing is reported, the press in progress is dropped, and a pan, drag or
|
|
47
|
+
* pinch that had started gets one `cancel`, so the game can put things back.
|
|
48
|
+
*/
|
|
49
|
+
export class Gestures {
|
|
50
|
+
/** This tick's gestures, or `null`. */
|
|
51
|
+
tap = null;
|
|
52
|
+
doubleTap = null;
|
|
53
|
+
longPress = null;
|
|
54
|
+
pan = null;
|
|
55
|
+
drag = null;
|
|
56
|
+
pinch = null;
|
|
57
|
+
/** This tick's aim while one touch pointer is down (with the `magnify` option), or `null`. */
|
|
58
|
+
aim = null;
|
|
59
|
+
blocked;
|
|
60
|
+
panThreshold;
|
|
61
|
+
longPressMs;
|
|
62
|
+
doubleTapMs;
|
|
63
|
+
doubleTapDistance;
|
|
64
|
+
/** `GestureOptions.pan`: `'prefer'` keeps a pan candidate from long-pressing. */
|
|
65
|
+
panMode;
|
|
66
|
+
/**
|
|
67
|
+
* The pointer-claim hook (ws/input-3): called on every `pointerDown` with the pointer id and
|
|
68
|
+
* device; when it returns true the pointer is not a gesture (its moves and lift are ignored
|
|
69
|
+
* too). `Input.setLook` installs one so an orbit look drag never pans; a game may install its
|
|
70
|
+
* own when nothing is linked.
|
|
71
|
+
*/
|
|
72
|
+
claim = null;
|
|
73
|
+
/**
|
|
74
|
+
* The clock gestures are timed on (`GestureOptions.now`). Recordings stamp pointer events on
|
|
75
|
+
* it and playbacks replay them on it (ws/input-7). `clock.now`, bound.
|
|
76
|
+
*/
|
|
77
|
+
now;
|
|
78
|
+
/** The clock (`GestureOptions.clock`, or one wrapping `now`, or the wall clock). */
|
|
79
|
+
clock;
|
|
80
|
+
onPanCandidate;
|
|
81
|
+
transform = null;
|
|
82
|
+
session = null;
|
|
83
|
+
/** Last tap, for double taps: client position and end time. */
|
|
84
|
+
lastTap = null;
|
|
85
|
+
lastInside = { x: 0, y: 0, inside: false };
|
|
86
|
+
/** Taps; `double` marks the second tap of a double tap (reported on the same tick). */
|
|
87
|
+
taps = [];
|
|
88
|
+
longPresses = [];
|
|
89
|
+
pans = [];
|
|
90
|
+
drags = [];
|
|
91
|
+
pinches = [];
|
|
92
|
+
/** Continuous gestures reported as started and not yet ended, with their last report. */
|
|
93
|
+
running = new Map();
|
|
94
|
+
/** The session whose long-press has been reported, while its pointer stays down. */
|
|
95
|
+
longPressSession = null;
|
|
96
|
+
detachFn = null;
|
|
97
|
+
magnify;
|
|
98
|
+
loupe = null;
|
|
99
|
+
/** The aim at the moment the finger lifted, reported (with `ended`) on the next tick. */
|
|
100
|
+
endedAim = null;
|
|
101
|
+
/** `onGesture` listeners, called at recognition time. */
|
|
102
|
+
listeners = [];
|
|
103
|
+
constructor(opts = {}) {
|
|
104
|
+
this.panThreshold = opts.panThreshold ?? DEFAULTS.panThreshold;
|
|
105
|
+
this.longPressMs = opts.longPressMs ?? DEFAULTS.longPressMs;
|
|
106
|
+
this.doubleTapMs = opts.doubleTapMs ?? DEFAULTS.doubleTapMs;
|
|
107
|
+
this.doubleTapDistance = opts.doubleTapDistance ?? DEFAULTS.doubleTapDistance;
|
|
108
|
+
this.blocked = opts.blocked ?? (() => false);
|
|
109
|
+
const c = resolveClock(opts.clock, opts.now);
|
|
110
|
+
this.clock = c.clock;
|
|
111
|
+
this.now = c.now;
|
|
112
|
+
this.magnify = opts.magnify ?? null;
|
|
113
|
+
this.panMode = opts.pan ?? null;
|
|
114
|
+
this.onPanCandidate = opts.onPanCandidate ?? null;
|
|
115
|
+
}
|
|
116
|
+
/** Turn magnify on (or off with `null`) after construction. */
|
|
117
|
+
setMagnify(opts) {
|
|
118
|
+
this.magnify = opts;
|
|
119
|
+
this.aim = null;
|
|
120
|
+
this.loupe?.destroy();
|
|
121
|
+
this.loupe = null;
|
|
122
|
+
}
|
|
123
|
+
/** The loupe element, once one has been shown (for styling and tests). */
|
|
124
|
+
get loupeElement() {
|
|
125
|
+
return this.loupe?.el ?? null;
|
|
126
|
+
}
|
|
127
|
+
/** Install the client → game-space mapping. `null` = identity (relative to the target when attached). */
|
|
128
|
+
setPointerTransform(fn) {
|
|
129
|
+
this.transform = fn;
|
|
130
|
+
this.ownDispatcher?.setTransform(fn);
|
|
131
|
+
}
|
|
132
|
+
// ---------------------------------------------------------------- observer
|
|
133
|
+
/**
|
|
134
|
+
* Observe the gesture stream: `listener` is called synchronously each time a gesture is
|
|
135
|
+
* recognised (a tap on lift, a long-press when its time is up, a pan's `start`, every `move`,
|
|
136
|
+
* `end` or `cancel`), not once per tick. It is an observer for tests, replays and logging; the
|
|
137
|
+
* per-tick fields (`tap`, `drag`, ...) and action bindings stay the way a game reads gestures.
|
|
138
|
+
* Returns the unsubscribe function.
|
|
139
|
+
*/
|
|
140
|
+
onGesture(listener) {
|
|
141
|
+
this.listeners.push(listener);
|
|
142
|
+
return () => {
|
|
143
|
+
const i = this.listeners.indexOf(listener);
|
|
144
|
+
if (i >= 0)
|
|
145
|
+
this.listeners.splice(i, 1);
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
emit(kind, phase, g) {
|
|
149
|
+
const ls = this.listeners;
|
|
150
|
+
for (let i = 0; i < ls.length; i++)
|
|
151
|
+
ls[i]?.(kind, phase, g);
|
|
152
|
+
}
|
|
153
|
+
// ---------------------------------------------------------------- queries
|
|
154
|
+
/**
|
|
155
|
+
* True while `kind` drives an action binding: on the tick a tap or double tap is reported;
|
|
156
|
+
* from a long-press until its pointer lifts; on a pan, drag or pinch's `start` and `move` ticks.
|
|
157
|
+
*/
|
|
158
|
+
active(kind) {
|
|
159
|
+
switch (kind) {
|
|
160
|
+
case 'tap':
|
|
161
|
+
return this.tap !== null;
|
|
162
|
+
case 'doubleTap':
|
|
163
|
+
return this.doubleTap !== null;
|
|
164
|
+
case 'longPress':
|
|
165
|
+
return this.longPress !== null || this.longPressSession !== null;
|
|
166
|
+
default:
|
|
167
|
+
return this.running.has(kind);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/** True when `kind` was reported fresh this tick: a new tap, double tap, long-press or `start`. */
|
|
171
|
+
fired(kind) {
|
|
172
|
+
switch (kind) {
|
|
173
|
+
case 'tap':
|
|
174
|
+
case 'doubleTap':
|
|
175
|
+
case 'longPress':
|
|
176
|
+
return this[kind] !== null;
|
|
177
|
+
default:
|
|
178
|
+
return this[kind]?.phase === 'start';
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// ---------------------------------------------------------------- tick
|
|
182
|
+
/** Advance one tick: fire due long-presses and publish one report per kind. */
|
|
183
|
+
update() {
|
|
184
|
+
const t = this.now();
|
|
185
|
+
if (this.blocked()) {
|
|
186
|
+
this.clearQueues();
|
|
187
|
+
if (this.session)
|
|
188
|
+
this.session.void = true;
|
|
189
|
+
this.longPressSession = null;
|
|
190
|
+
this.tap = null;
|
|
191
|
+
this.doubleTap = null;
|
|
192
|
+
this.longPress = null;
|
|
193
|
+
// A pan, drag or pinch that had started is cancelled once; nothing else is reported.
|
|
194
|
+
this.lastTap = null;
|
|
195
|
+
this.pan = this.cancelled('pan');
|
|
196
|
+
this.drag = this.cancelled('drag');
|
|
197
|
+
this.pinch = this.cancelled('pinch');
|
|
198
|
+
if (this.pan)
|
|
199
|
+
this.emit('pan', 'cancel', this.pan);
|
|
200
|
+
if (this.drag)
|
|
201
|
+
this.emit('drag', 'cancel', this.drag);
|
|
202
|
+
if (this.pinch)
|
|
203
|
+
this.emit('pinch', 'cancel', this.pinch);
|
|
204
|
+
this.running.clear();
|
|
205
|
+
this.updateAim();
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
this.checkLongPress(t);
|
|
209
|
+
const tap = this.taps.shift();
|
|
210
|
+
this.tap = tap?.tap ?? null;
|
|
211
|
+
this.doubleTap = tap?.double ? tap.tap : null;
|
|
212
|
+
this.longPress = this.longPresses.shift() ?? null;
|
|
213
|
+
if (this.longPress && this.session?.longPressed && !this.session.void) {
|
|
214
|
+
this.longPressSession = this.session;
|
|
215
|
+
}
|
|
216
|
+
this.pan = this.publish('pan', this.pans, mergePan, idlePan);
|
|
217
|
+
this.drag = this.publish('drag', this.drags, mergePan, idlePan);
|
|
218
|
+
this.pinch = this.publish('pinch', this.pinches, mergePinch, idlePinch);
|
|
219
|
+
this.updateAim();
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* This tick's aim (the `magnify` option): one touch pointer down, not blocked, `when()`. The
|
|
223
|
+
* aim point is the finger, raised by `lift` while it drags; `snap` picks the target; the
|
|
224
|
+
* loupe shows while the pitch is below `below` and the aim is over the targets.
|
|
225
|
+
*/
|
|
226
|
+
updateAim() {
|
|
227
|
+
const m = this.magnify;
|
|
228
|
+
const s = this.session;
|
|
229
|
+
const c = s && !s.void && !s.multi ? s.contacts.values().next().value : null;
|
|
230
|
+
// The aim the finger lifted at comes with the drag's `end` (moves before it get their own
|
|
231
|
+
// ticks first, still aiming there).
|
|
232
|
+
let ended = this.endedAim;
|
|
233
|
+
if (ended && this.drags.length > 0)
|
|
234
|
+
ended = { ...ended, ended: false };
|
|
235
|
+
else
|
|
236
|
+
this.endedAim = null;
|
|
237
|
+
const aim = !m || this.blocked() ? null : c ? this.aimOf(m, c, s?.moving === true) : ended;
|
|
238
|
+
this.aim = aim;
|
|
239
|
+
if (!m?.source || !aim?.loupe || aim.ended) {
|
|
240
|
+
this.loupe?.hide();
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const size = magnifySize(m);
|
|
244
|
+
if (this.loupe && this.loupe.size !== size) {
|
|
245
|
+
this.loupe.destroy();
|
|
246
|
+
this.loupe = null;
|
|
247
|
+
}
|
|
248
|
+
this.loupe ??= new Loupe(m.source, {
|
|
249
|
+
size,
|
|
250
|
+
zoom: m.zoom ?? MAGNIFY_DEFAULTS.zoom,
|
|
251
|
+
className: m.className,
|
|
252
|
+
parent: m.parent,
|
|
253
|
+
});
|
|
254
|
+
let ring = null;
|
|
255
|
+
const t = aim.target;
|
|
256
|
+
if (t) {
|
|
257
|
+
const to = m.toClient ?? ((tx, ty) => ({ x: tx, y: ty }));
|
|
258
|
+
const a = to(t.x, t.y);
|
|
259
|
+
const b = to(t.x + t.r, t.y);
|
|
260
|
+
ring = { x: a.x, y: a.y, r: Math.abs(b.x - a.x) };
|
|
261
|
+
}
|
|
262
|
+
this.loupe.show({ focus: aim.client, at: aim.at, ring, leader: m.leader ? ring : null });
|
|
263
|
+
}
|
|
264
|
+
/** The aim of touch contact `c` (`null` for mouse and pen, or while `when()` is false). */
|
|
265
|
+
aimOf(m, c, lifted) {
|
|
266
|
+
if (c.device !== 'touch' || (m.when && !m.when()))
|
|
267
|
+
return null;
|
|
268
|
+
const lift = lifted ? (m.lift ?? MAGNIFY_DEFAULTS.lift) : 0;
|
|
269
|
+
const finger = { x: c.lastX, y: c.lastY };
|
|
270
|
+
const client = { x: c.lastX, y: c.lastY - lift };
|
|
271
|
+
const p = this.transform ? this.transform(client.x, client.y) : { x: client.x, y: client.y };
|
|
272
|
+
const inside = p !== null;
|
|
273
|
+
const x = p?.x ?? this.lastInside.x;
|
|
274
|
+
const y = p?.y ?? this.lastInside.y;
|
|
275
|
+
const target = inside && m.snap ? m.snap(x, y) : null;
|
|
276
|
+
const over = inside && (m.over ? m.over(x, y) : target !== null);
|
|
277
|
+
const size = magnifySize(m);
|
|
278
|
+
const loupe = over && m.pitch() < (m.below ?? MAGNIFY_DEFAULTS.below);
|
|
279
|
+
const win = (m.source?.ownerDocument ?? globalThis.document)?.defaultView;
|
|
280
|
+
const view = win
|
|
281
|
+
? { width: win.innerWidth, height: win.innerHeight }
|
|
282
|
+
: { width: Number.POSITIVE_INFINITY, height: Number.POSITIVE_INFINITY };
|
|
283
|
+
const room = loupe && m.clear ? m.clear(target, { x, y }) : null;
|
|
284
|
+
const at = room
|
|
285
|
+
? loupeClear(finger, client, size, view, room.keep, room.avoid, room.spare)
|
|
286
|
+
: loupeSpot(finger, client, size, view);
|
|
287
|
+
return { x, y, inside, client, finger, lifted, target, loupe, at, ended: false };
|
|
288
|
+
}
|
|
289
|
+
/** The `cancel` report for a running `kind` (blocked), or `null`. */
|
|
290
|
+
cancelled(kind) {
|
|
291
|
+
const last = this.running.get(kind);
|
|
292
|
+
if (!last)
|
|
293
|
+
return null;
|
|
294
|
+
return (kind === 'pinch'
|
|
295
|
+
? { ...last, phase: 'cancel', delta: 1 }
|
|
296
|
+
: { ...last, phase: 'cancel', dx: 0, dy: 0 });
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* This tick's report for `kind`: the next queued event (consecutive moves merged), or, while
|
|
300
|
+
* the gesture runs with nothing new, the last report as a `move` with no change.
|
|
301
|
+
*/
|
|
302
|
+
publish(kind, queue, merge, idle) {
|
|
303
|
+
let e = queue.shift();
|
|
304
|
+
if (!e) {
|
|
305
|
+
const last = this.running.get(kind);
|
|
306
|
+
return last ? idle(last) : null;
|
|
307
|
+
}
|
|
308
|
+
if (e.phase === 'move') {
|
|
309
|
+
while (queue[0]?.phase === 'move')
|
|
310
|
+
e = merge(e, queue.shift());
|
|
311
|
+
}
|
|
312
|
+
if (e.phase === 'end' || e.phase === 'cancel')
|
|
313
|
+
this.running.delete(kind);
|
|
314
|
+
else
|
|
315
|
+
this.running.set(kind, e);
|
|
316
|
+
return e;
|
|
317
|
+
}
|
|
318
|
+
clearQueues() {
|
|
319
|
+
this.taps.length = 0;
|
|
320
|
+
this.longPresses.length = 0;
|
|
321
|
+
this.pans.length = 0;
|
|
322
|
+
this.drags.length = 0;
|
|
323
|
+
this.pinches.length = 0;
|
|
324
|
+
}
|
|
325
|
+
// ---------------------------------------------------------------- low-level feed
|
|
326
|
+
// Public so tests, replays and automated playtests can drive gestures without a DOM. Positions
|
|
327
|
+
// are client coordinates (CSS px), run through the transform. `time` defaults to the clock.
|
|
328
|
+
pointerDown(id, clientX, clientY, device = 'touch', time = this.now()) {
|
|
329
|
+
if (this.claim?.(id, device))
|
|
330
|
+
return;
|
|
331
|
+
if (!this.session) {
|
|
332
|
+
if (this.blocked())
|
|
333
|
+
return;
|
|
334
|
+
this.session = {
|
|
335
|
+
contacts: new Map(),
|
|
336
|
+
moving: false,
|
|
337
|
+
multi: false,
|
|
338
|
+
void: false,
|
|
339
|
+
longPressed: false,
|
|
340
|
+
pinchStartDist: 0,
|
|
341
|
+
pinchLastDist: 0,
|
|
342
|
+
pinching: false,
|
|
343
|
+
centreLast: null,
|
|
344
|
+
last: null,
|
|
345
|
+
at: null,
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
const s = this.session;
|
|
349
|
+
if (s.contacts.has(id))
|
|
350
|
+
return;
|
|
351
|
+
const contact = {
|
|
352
|
+
id,
|
|
353
|
+
device,
|
|
354
|
+
downAt: time,
|
|
355
|
+
startX: clientX,
|
|
356
|
+
startY: clientY,
|
|
357
|
+
lastX: clientX,
|
|
358
|
+
lastY: clientY,
|
|
359
|
+
origin: this.map(clientX, clientY),
|
|
360
|
+
travel: 0,
|
|
361
|
+
candidate: false,
|
|
362
|
+
};
|
|
363
|
+
s.contacts.set(id, contact);
|
|
364
|
+
if (s.void || s.contacts.size !== 2) {
|
|
365
|
+
// A third pointer is ignored; it still has to lift before the session ends.
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
// Second pointer: the press becomes a pinch; a running pan and drag are cancelled, and
|
|
369
|
+
// neither reports again until every pointer is up.
|
|
370
|
+
s.multi = true;
|
|
371
|
+
this.endOnePointer(s, s.contacts.values().next().value, 'cancel');
|
|
372
|
+
const [a, b] = [...s.contacts.values()];
|
|
373
|
+
s.pinchStartDist = Math.max(1, dist(a.lastX, a.lastY, b.lastX, b.lastY));
|
|
374
|
+
s.pinchLastDist = s.pinchStartDist;
|
|
375
|
+
const centre = this.map((a.lastX + b.lastX) / 2, (a.lastY + b.lastY) / 2);
|
|
376
|
+
s.centreLast = centre;
|
|
377
|
+
s.pinching = true;
|
|
378
|
+
this.pushPinch({ phase: 'start', ...centre, scale: 1, delta: 1 });
|
|
379
|
+
}
|
|
380
|
+
pointerMove(id, clientX, clientY, time = this.now()) {
|
|
381
|
+
const s = this.session;
|
|
382
|
+
const c = s?.contacts.get(id);
|
|
383
|
+
if (!s || !c || (clientX === c.lastX && clientY === c.lastY))
|
|
384
|
+
return;
|
|
385
|
+
c.travel += dist(c.lastX, c.lastY, clientX, clientY);
|
|
386
|
+
c.lastX = clientX;
|
|
387
|
+
c.lastY = clientY;
|
|
388
|
+
if (!c.candidate && c.travel > this.panThreshold * CANDIDATE_FRACTION) {
|
|
389
|
+
c.candidate = true;
|
|
390
|
+
this.onPanCandidate?.(id, c.travel);
|
|
391
|
+
}
|
|
392
|
+
if (s.void)
|
|
393
|
+
return;
|
|
394
|
+
if (s.multi) {
|
|
395
|
+
this.moveTwo(s);
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
if (s.longPressed)
|
|
399
|
+
return;
|
|
400
|
+
if (!s.moving) {
|
|
401
|
+
// The threshold first: travel that crosses it is a pan, however late this move arrives
|
|
402
|
+
// (a long frame), and the pending long-press is dropped. Only a still pointer may long-press.
|
|
403
|
+
if (c.travel <= this.panThreshold) {
|
|
404
|
+
this.checkLongPress(time);
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
s.moving = true;
|
|
408
|
+
s.last = c.origin;
|
|
409
|
+
const p = this.map(clientX, clientY);
|
|
410
|
+
this.pushMove(s, c, p, 'start');
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
this.pushMove(s, c, this.map(clientX, clientY), 'move');
|
|
414
|
+
}
|
|
415
|
+
pointerUp(id, clientX, clientY, time = this.now()) {
|
|
416
|
+
const s = this.session;
|
|
417
|
+
const c = s?.contacts.get(id);
|
|
418
|
+
if (!s || !c)
|
|
419
|
+
return;
|
|
420
|
+
if (clientX !== undefined && clientY !== undefined)
|
|
421
|
+
this.pointerMove(id, clientX, clientY, time);
|
|
422
|
+
if (this.magnify && !s.void && !s.multi && !this.blocked()) {
|
|
423
|
+
const aim = this.aimOf(this.magnify, c, s.moving);
|
|
424
|
+
this.endedAim = aim ? { ...aim, ended: true } : null;
|
|
425
|
+
}
|
|
426
|
+
s.contacts.delete(id);
|
|
427
|
+
if (this.longPressSession === s)
|
|
428
|
+
this.longPressSession = null;
|
|
429
|
+
if (!s.void) {
|
|
430
|
+
if (s.multi) {
|
|
431
|
+
this.endTwo(s, 'end');
|
|
432
|
+
s.void = true;
|
|
433
|
+
}
|
|
434
|
+
else if (s.moving) {
|
|
435
|
+
this.endOnePointer(s, c, 'end');
|
|
436
|
+
}
|
|
437
|
+
else if (!s.longPressed) {
|
|
438
|
+
if (time - c.downAt >= this.longPressMs) {
|
|
439
|
+
// Held long enough but no tick saw it (a stalled frame): still a long-press, not a tap.
|
|
440
|
+
// A pan candidate under `pan: 'prefer'` was on its way to a pan: nothing.
|
|
441
|
+
if (!this.preferPan(c))
|
|
442
|
+
this.longPressOf(s, c);
|
|
443
|
+
}
|
|
444
|
+
else {
|
|
445
|
+
this.emitTap(c, time);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
if (s.contacts.size === 0)
|
|
450
|
+
this.session = null;
|
|
451
|
+
}
|
|
452
|
+
/** The browser took the pointer (system gesture, palm rejection): drop the press. */
|
|
453
|
+
pointerCancel(id) {
|
|
454
|
+
const s = this.session;
|
|
455
|
+
if (!s?.contacts.has(id))
|
|
456
|
+
return;
|
|
457
|
+
this.cancelSession(s);
|
|
458
|
+
s.contacts.delete(id);
|
|
459
|
+
if (s.contacts.size === 0)
|
|
460
|
+
this.session = null;
|
|
461
|
+
}
|
|
462
|
+
/** Drop every pointer (focus loss, tab hidden). A started pan, drag or pinch is cancelled. */
|
|
463
|
+
cancelAll() {
|
|
464
|
+
const s = this.session;
|
|
465
|
+
if (s)
|
|
466
|
+
this.cancelSession(s);
|
|
467
|
+
this.session = null;
|
|
468
|
+
this.longPressSession = null;
|
|
469
|
+
}
|
|
470
|
+
cancelSession(s) {
|
|
471
|
+
if (!s.void) {
|
|
472
|
+
if (s.multi)
|
|
473
|
+
this.endTwo(s, 'cancel');
|
|
474
|
+
else
|
|
475
|
+
this.endOnePointer(s, s.contacts.values().next().value, 'cancel');
|
|
476
|
+
}
|
|
477
|
+
s.void = true;
|
|
478
|
+
if (this.longPressSession === s)
|
|
479
|
+
this.longPressSession = null;
|
|
480
|
+
}
|
|
481
|
+
// ---------------------------------------------------------------- recognisers
|
|
482
|
+
checkLongPress(t) {
|
|
483
|
+
const s = this.session;
|
|
484
|
+
if (!s || s.void || s.multi || s.moving || s.longPressed)
|
|
485
|
+
return;
|
|
486
|
+
const c = s.contacts.values().next().value;
|
|
487
|
+
if (!c || t - c.downAt < this.longPressMs || this.preferPan(c))
|
|
488
|
+
return;
|
|
489
|
+
this.longPressOf(s, c);
|
|
490
|
+
}
|
|
491
|
+
/** True when `c` may no longer long-press: a pan candidate under `pan: 'prefer'`. */
|
|
492
|
+
preferPan(c) {
|
|
493
|
+
return this.panMode === 'prefer' && c.candidate;
|
|
494
|
+
}
|
|
495
|
+
longPressOf(s, c) {
|
|
496
|
+
s.longPressed = true;
|
|
497
|
+
const g = { ...c.origin, device: c.device };
|
|
498
|
+
push(this.longPresses, g);
|
|
499
|
+
this.emit('longPress', 'end', g);
|
|
500
|
+
}
|
|
501
|
+
emitTap(c, time) {
|
|
502
|
+
const prev = this.lastTap;
|
|
503
|
+
const double = prev !== null &&
|
|
504
|
+
c.downAt - prev.at <= this.doubleTapMs &&
|
|
505
|
+
dist(prev.x, prev.y, c.startX, c.startY) <= this.doubleTapDistance;
|
|
506
|
+
const tap = { ...c.origin, device: c.device };
|
|
507
|
+
push(this.taps, { tap, double });
|
|
508
|
+
this.lastTap = double ? null : { x: c.startX, y: c.startY, at: time };
|
|
509
|
+
this.emit('tap', 'end', tap);
|
|
510
|
+
if (double)
|
|
511
|
+
this.emit('doubleTap', 'end', tap);
|
|
512
|
+
}
|
|
513
|
+
pushMove(s, c, p, phase) {
|
|
514
|
+
const last = s.last ?? c.origin;
|
|
515
|
+
const dx = p.inside && last.inside ? p.x - last.x : 0;
|
|
516
|
+
const dy = p.inside && last.inside ? p.y - last.y : 0;
|
|
517
|
+
const at = p.inside ? p : { ...last, inside: false };
|
|
518
|
+
s.last = p.inside ? p : last;
|
|
519
|
+
s.at = at;
|
|
520
|
+
this.pushPan(c, phase, at, dx, dy);
|
|
521
|
+
}
|
|
522
|
+
/** Queues one pan and one drag report and tells the listeners. */
|
|
523
|
+
pushPan(c, phase, at, dx, dy) {
|
|
524
|
+
const pan = { phase, ...at, dx, dy, pointers: 1, device: c.device };
|
|
525
|
+
const drag = { phase, ...at, origin: c.origin, dx, dy, device: c.device };
|
|
526
|
+
this.pans.push(pan);
|
|
527
|
+
this.drags.push(drag);
|
|
528
|
+
this.emit('pan', phase, pan);
|
|
529
|
+
this.emit('drag', phase, drag);
|
|
530
|
+
}
|
|
531
|
+
pushPinch(e) {
|
|
532
|
+
push(this.pinches, e);
|
|
533
|
+
this.emit('pinch', e.phase, e);
|
|
534
|
+
}
|
|
535
|
+
/** Ends (or cancels) a one-pointer pan and drag, if one is running in `s`. */
|
|
536
|
+
endOnePointer(s, c, phase) {
|
|
537
|
+
if (!s.moving)
|
|
538
|
+
return;
|
|
539
|
+
s.moving = false;
|
|
540
|
+
this.pushPan(c, phase, s.at ?? c.origin, 0, 0);
|
|
541
|
+
}
|
|
542
|
+
/** Two pointers: only the pinch moves. Their centre moving is not a pan (pinch wins). */
|
|
543
|
+
moveTwo(s) {
|
|
544
|
+
const [a, b] = [...s.contacts.values()];
|
|
545
|
+
const d = Math.max(1, dist(a.lastX, a.lastY, b.lastX, b.lastY));
|
|
546
|
+
const centre = this.map((a.lastX + b.lastX) / 2, (a.lastY + b.lastY) / 2);
|
|
547
|
+
if (centre.inside)
|
|
548
|
+
s.centreLast = centre;
|
|
549
|
+
if (d === s.pinchLastDist)
|
|
550
|
+
return;
|
|
551
|
+
const delta = d / s.pinchLastDist;
|
|
552
|
+
s.pinchLastDist = d;
|
|
553
|
+
const at = centre.inside ? centre : { ...(s.centreLast ?? centre), inside: false };
|
|
554
|
+
this.pushPinch({ phase: 'move', ...at, scale: d / s.pinchStartDist, delta });
|
|
555
|
+
}
|
|
556
|
+
endTwo(s, phase) {
|
|
557
|
+
if (!s.pinching)
|
|
558
|
+
return;
|
|
559
|
+
s.pinching = false;
|
|
560
|
+
const e = {
|
|
561
|
+
phase,
|
|
562
|
+
...(s.centreLast ?? this.lastInside),
|
|
563
|
+
scale: s.pinchLastDist / s.pinchStartDist,
|
|
564
|
+
delta: 1,
|
|
565
|
+
};
|
|
566
|
+
this.pinches.push(e);
|
|
567
|
+
this.emit('pinch', phase, e);
|
|
568
|
+
}
|
|
569
|
+
map(clientX, clientY) {
|
|
570
|
+
const p = this.transform ? this.transform(clientX, clientY) : { x: clientX, y: clientY };
|
|
571
|
+
if (p) {
|
|
572
|
+
this.lastInside = { x: p.x, y: p.y, inside: true };
|
|
573
|
+
return { x: p.x, y: p.y, inside: true };
|
|
574
|
+
}
|
|
575
|
+
return { x: this.lastInside.x, y: this.lastInside.y, inside: false };
|
|
576
|
+
}
|
|
577
|
+
// ---------------------------------------------------------------- DOM
|
|
578
|
+
/**
|
|
579
|
+
* Listen to pointer events on the target. Mouse: the primary button only. Touch and pen: up
|
|
580
|
+
* to two contacts. The target captures each pointer, so a drag off its edge keeps reporting.
|
|
581
|
+
* `Input.setGestures` calls this from `Input.attach`; call it yourself only when the gestures
|
|
582
|
+
* are used without an `Input`.
|
|
583
|
+
*/
|
|
584
|
+
attach(opts) {
|
|
585
|
+
this.detach();
|
|
586
|
+
const target = opts.pointerTarget;
|
|
587
|
+
const prevTouchAction = target.style.touchAction;
|
|
588
|
+
if (opts.disableTouchScroll !== false)
|
|
589
|
+
target.style.touchAction = 'none';
|
|
590
|
+
const shared = opts.dispatcher ?? null;
|
|
591
|
+
const dispatcher = shared ?? createPointerDispatcher(target, { transform: this.transform });
|
|
592
|
+
if (!shared)
|
|
593
|
+
this.ownDispatcher = dispatcher;
|
|
594
|
+
const remove = dispatcher.add(this.consumer, POINTER_PRIORITY.gestures);
|
|
595
|
+
this.detachFn = () => {
|
|
596
|
+
remove();
|
|
597
|
+
if (!shared)
|
|
598
|
+
dispatcher.destroy();
|
|
599
|
+
this.ownDispatcher = null;
|
|
600
|
+
target.style.touchAction = prevTouchAction;
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
/** The private dispatcher a standalone `attach` built, or `null` (shared or detached). */
|
|
604
|
+
ownDispatcher = null;
|
|
605
|
+
/**
|
|
606
|
+
* The dispatcher consumer: mouse primary button only; every touch and pen contact. Each event
|
|
607
|
+
* is timed by its `timeStamp` (`eventTime`: `now() - age`), not by when it was handled, so a
|
|
608
|
+
* tap delivered after a stalled frame is still a tap; a replayed event by its recorded time.
|
|
609
|
+
*/
|
|
610
|
+
consumer = {
|
|
611
|
+
pointerDown: (p) => {
|
|
612
|
+
if (p.device === 'mouse' && p.button !== 0)
|
|
613
|
+
return;
|
|
614
|
+
this.pointerDown(p.id, p.x, p.y, p.device, this.now() - p.age);
|
|
615
|
+
},
|
|
616
|
+
pointerMove: (p) => this.pointerMove(p.id, p.x, p.y, this.now() - p.age),
|
|
617
|
+
pointerUp: (p) => {
|
|
618
|
+
if (p.device === 'mouse' && p.button !== 0)
|
|
619
|
+
return;
|
|
620
|
+
this.pointerUp(p.id, p.x, p.y, this.now() - p.age);
|
|
621
|
+
},
|
|
622
|
+
pointerCancel: (p) => this.pointerCancel(p.id),
|
|
623
|
+
cancelAll: () => this.cancelAll(),
|
|
624
|
+
};
|
|
625
|
+
detach() {
|
|
626
|
+
this.detachFn?.();
|
|
627
|
+
this.detachFn = null;
|
|
628
|
+
this.cancelAll();
|
|
629
|
+
this.aim = null;
|
|
630
|
+
this.endedAim = null;
|
|
631
|
+
this.loupe?.hide();
|
|
632
|
+
}
|
|
633
|
+
/** Detach and remove the loupe element. */
|
|
634
|
+
destroy() {
|
|
635
|
+
this.detach();
|
|
636
|
+
this.loupe?.destroy();
|
|
637
|
+
this.loupe = null;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
function dist(ax, ay, bx, by) {
|
|
641
|
+
return Math.hypot(bx - ax, by - ay);
|
|
642
|
+
}
|
|
643
|
+
function push(queue, e) {
|
|
644
|
+
if (queue.length < MAX_QUEUED)
|
|
645
|
+
queue.push(e);
|
|
646
|
+
}
|
|
647
|
+
function idlePan(last) {
|
|
648
|
+
return { ...last, phase: 'move', dx: 0, dy: 0 };
|
|
649
|
+
}
|
|
650
|
+
function idlePinch(last) {
|
|
651
|
+
return { ...last, phase: 'move', delta: 1 };
|
|
652
|
+
}
|
|
653
|
+
function mergePan(a, b) {
|
|
654
|
+
return { ...b, dx: a.dx + b.dx, dy: a.dy + b.dy };
|
|
655
|
+
}
|
|
656
|
+
function mergePinch(a, b) {
|
|
657
|
+
return { ...b, delta: a.delta * b.delta };
|
|
658
|
+
}
|
|
659
|
+
/** `new Gestures(opts)`: gestures, on `opts.clock` when given (ws/input-8). */
|
|
660
|
+
export function createGestures(opts = {}) {
|
|
661
|
+
return new Gestures(opts);
|
|
662
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt glyphs (ws/input-3): the label a game shows for a binding ("Space", "A", "Cross", "Tap"),
|
|
3
|
+
* chosen for the device the player last used. Pure tables, no DOM; `Input.glyphFor(action,
|
|
4
|
+
* device?)` picks the binding and calls `glyphForBinding`. The engine draws nothing: `kind` says
|
|
5
|
+
* which icon set a game's UI should reach for, `label` is the text.
|
|
6
|
+
*/
|
|
7
|
+
import type { Binding, InputDevice } from './types.js';
|
|
8
|
+
/** What a glyph stands for. */
|
|
9
|
+
export type GlyphKind = 'key' | 'button' | 'axis' | 'pointer' | 'gesture' | 'xr';
|
|
10
|
+
/** A prompt glyph: `kind` picks the icon set, `label` is the text. */
|
|
11
|
+
export interface Glyph {
|
|
12
|
+
kind: GlyphKind;
|
|
13
|
+
label: string;
|
|
14
|
+
}
|
|
15
|
+
/** Button naming families. `guessPadLayout(gamepad.id)` picks one; `InputOptions.padLayout` overrides. */
|
|
16
|
+
export type PadLayout = 'xbox' | 'playstation' | 'nintendo' | 'generic';
|
|
17
|
+
/** The pad layout for a `Gamepad.id` (vendor words and USB vendor ids), `'generic'` when unknown. */
|
|
18
|
+
export declare function guessPadLayout(id: string | undefined): PadLayout;
|
|
19
|
+
/** Standard-mapping pad button `index` in `layout` (`'Button 7'` past the table or for `'generic'`). */
|
|
20
|
+
export declare function padButtonLabel(index: number, layout?: PadLayout): string;
|
|
21
|
+
/** Standard-mapping pad axis `axis` pushed in `dir`: `'LS →'`, `'RS ↑'`, or `'Axis 4 +'` past the sticks. */
|
|
22
|
+
export declare function padAxisLabel(axis: number, dir: 1 | -1): string;
|
|
23
|
+
/**
|
|
24
|
+
* Display text for a `KeyboardEvent.code`: `'KeyA'` → `'A'`, `'Digit1'` → `'1'`, `'Numpad1'` →
|
|
25
|
+
* `'Num 1'`, `'F5'` → `'F5'`, arrows as arrows, modifiers without their side; unknown codes are
|
|
26
|
+
* split at their capitals (`'AudioVolumeUp'` → `'Audio Volume Up'`).
|
|
27
|
+
*/
|
|
28
|
+
export declare function keyLabel(code: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* The glyph for one binding. A chord joins its members with ` + ` and takes the first member's
|
|
31
|
+
* kind; `trigger: 'hold'` prefixes `Hold `, `'doubleTap'` prefixes `Double-tap `.
|
|
32
|
+
*/
|
|
33
|
+
export declare function glyphForBinding(b: Binding, layout?: PadLayout): Glyph;
|
|
34
|
+
/** True when `b` is what `device` produces, so its glyph is the one to show for that device. */
|
|
35
|
+
export declare function bindingMatchesDevice(b: Binding, device: InputDevice): boolean;
|