@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,601 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input recording and replay (ws/input-replay). A recorder sits beside an `Input` through its
|
|
3
|
+
* feed hook (`Input.onFeed`) and writes down, tick by tick, every feed call and the gamepad
|
|
4
|
+
* snapshot `update()` read. A playback feeds the same calls back into an `Input` before each
|
|
5
|
+
* `update()` and hands it the recorded pads, so an identical game sees identical `pressed`,
|
|
6
|
+
* `held`, `released` and `value` per tick. Neither changes how `Input` evaluates bindings.
|
|
7
|
+
*
|
|
8
|
+
* The recording is plain JSON: `{ version: 3, ticks: [...] }`, deltas only. A tick with events
|
|
9
|
+
* is `{ t, k?, b?, p?, w?, r?, d?, g?, ptr?, cx?, cs?, ui? }`; a run of ticks with none is
|
|
10
|
+
* `{ t, n }`.
|
|
11
|
+
* Version 2 (ws/input-5) adds the `ptr` lane (every pointer the dispatcher saw, so touch zones,
|
|
12
|
+
* gestures and a second thumb replay) and the observational `cx` and `cs`. Version 3
|
|
13
|
+
* (ws/input-7) stamps each `ptr` entry with its time, so a replayed tap, long-press or
|
|
14
|
+
* double-tap classifies as it did live. Versions 1 and 2 still parse and play. A recording may
|
|
15
|
+
* carry `tickMs`, its tick spacing (ws/input-9), which a playback given a tick `clock` advances
|
|
16
|
+
* it by per fed tick, so a replay at any `speed` keeps game time. The `ui` lane (ws/input-12)
|
|
17
|
+
* holds the overlay controls that fired on a tick, by stable id (`Input.control`); a playback
|
|
18
|
+
* replays them through `Input.replayControl` and an older reader skips them.
|
|
19
|
+
*/
|
|
20
|
+
import { wallClock } from './clock.js';
|
|
21
|
+
/** The linked gestures' clock, else the linked look's, else the wall clock. */
|
|
22
|
+
function linkedClock(input) {
|
|
23
|
+
const g = input.gestures;
|
|
24
|
+
if (g)
|
|
25
|
+
return g.now;
|
|
26
|
+
const look = input.look;
|
|
27
|
+
if (look)
|
|
28
|
+
return () => look.clock.now();
|
|
29
|
+
return wallClock.now;
|
|
30
|
+
}
|
|
31
|
+
/** True when neither the linked gestures nor the linked look has a clock of its own. */
|
|
32
|
+
function onWallClock(input) {
|
|
33
|
+
const g = input.gestures;
|
|
34
|
+
if (g)
|
|
35
|
+
return g.clock === wallClock;
|
|
36
|
+
const look = input.look;
|
|
37
|
+
return !look || look.clock === wallClock;
|
|
38
|
+
}
|
|
39
|
+
const PHASES = ['down', 'move', 'up', 'cancel', 'leave'];
|
|
40
|
+
/** Called when a recording does not have the expected shape. */
|
|
41
|
+
export class InputRecordingError extends Error {
|
|
42
|
+
constructor(message) {
|
|
43
|
+
super(message);
|
|
44
|
+
this.name = 'InputRecordingError';
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/** Total ticks a recording covers. */
|
|
48
|
+
export function recordingLength(rec) {
|
|
49
|
+
const last = rec.ticks[rec.ticks.length - 1];
|
|
50
|
+
if (!last)
|
|
51
|
+
return 0;
|
|
52
|
+
return last.t + ('n' in last ? last.n : 1);
|
|
53
|
+
}
|
|
54
|
+
function isRun(tick) {
|
|
55
|
+
return 'n' in tick;
|
|
56
|
+
}
|
|
57
|
+
// ---------------------------------------------------------------- recorder
|
|
58
|
+
/**
|
|
59
|
+
* Record everything `input` is fed. The recorder installs a feed hook and closes one tick per
|
|
60
|
+
* `input.update()`; `stop()` removes it. `input.recorder` points at it meanwhile.
|
|
61
|
+
*/
|
|
62
|
+
export function createInputRecorder(input, opts = {}) {
|
|
63
|
+
const capturePads = opts.pads !== false;
|
|
64
|
+
const recording = { version: 3, ticks: [] };
|
|
65
|
+
const clock = opts.now ?? linkedClock(input);
|
|
66
|
+
const start = clock();
|
|
67
|
+
/** The spacing is measured on the recorder's clock unless that is the wall clock. */
|
|
68
|
+
const measure = opts.now !== undefined || !onWallClock(input);
|
|
69
|
+
/** ms since `start`, `age` ms ago, to 0.01 ms. */
|
|
70
|
+
const stamp = (age) => Math.round((clock() - age - start) * 100) / 100;
|
|
71
|
+
/** Pointers down (by id), for turning a blur into cancels. */
|
|
72
|
+
const live = new Map();
|
|
73
|
+
let t = 0;
|
|
74
|
+
/** The tick being built, or null while nothing happened on it. */
|
|
75
|
+
let cur = null;
|
|
76
|
+
/** The last pad snapshot written, for the delta comparison. */
|
|
77
|
+
let lastPads = [];
|
|
78
|
+
let padsWritten = false;
|
|
79
|
+
const open = () => {
|
|
80
|
+
if (!cur)
|
|
81
|
+
cur = { t };
|
|
82
|
+
return cur;
|
|
83
|
+
};
|
|
84
|
+
const key = (code, down) => {
|
|
85
|
+
const c = open();
|
|
86
|
+
if (c.k)
|
|
87
|
+
c.k.push([code, down]);
|
|
88
|
+
else
|
|
89
|
+
c.k = [[code, down]];
|
|
90
|
+
if (down && c.p)
|
|
91
|
+
c.d = 1;
|
|
92
|
+
};
|
|
93
|
+
const button = (b, down) => {
|
|
94
|
+
const c = open();
|
|
95
|
+
if (c.b)
|
|
96
|
+
c.b.push([b, down]);
|
|
97
|
+
else
|
|
98
|
+
c.b = [[b, down]];
|
|
99
|
+
};
|
|
100
|
+
const hook = {
|
|
101
|
+
keyDown: (code) => key(code, 1),
|
|
102
|
+
keyUp: (code) => key(code, 0),
|
|
103
|
+
buttonDown: (b) => button(b, 1),
|
|
104
|
+
buttonUp: (b) => button(b, 0),
|
|
105
|
+
wheel: (dx, dy) => {
|
|
106
|
+
const c = open();
|
|
107
|
+
if (c.w) {
|
|
108
|
+
c.w[0] += dx;
|
|
109
|
+
c.w[1] += dy;
|
|
110
|
+
}
|
|
111
|
+
else
|
|
112
|
+
c.w = [dx, dy];
|
|
113
|
+
},
|
|
114
|
+
pointerAt: (x, y, type) => {
|
|
115
|
+
const c = open();
|
|
116
|
+
c.p = type === 'mouse' ? [x, y] : [x, y, type];
|
|
117
|
+
if (c.d)
|
|
118
|
+
delete c.d;
|
|
119
|
+
},
|
|
120
|
+
releaseAll: () => {
|
|
121
|
+
open().r = 1;
|
|
122
|
+
},
|
|
123
|
+
rumble: (strong, weak, ms, pad) => {
|
|
124
|
+
const c = open();
|
|
125
|
+
const e = pad === undefined ? [strong, weak, ms] : [strong, weak, ms, pad];
|
|
126
|
+
if (c.rumble)
|
|
127
|
+
c.rumble.push(e);
|
|
128
|
+
else
|
|
129
|
+
c.rumble = [e];
|
|
130
|
+
},
|
|
131
|
+
pointer: (phase, p) => {
|
|
132
|
+
const c = open();
|
|
133
|
+
const ph = PHASES.indexOf(phase);
|
|
134
|
+
const e = [
|
|
135
|
+
ph,
|
|
136
|
+
p.id,
|
|
137
|
+
p.device,
|
|
138
|
+
p.clientX,
|
|
139
|
+
p.clientY,
|
|
140
|
+
p.button,
|
|
141
|
+
p.primary ? 1 : 0,
|
|
142
|
+
stamp(p.age),
|
|
143
|
+
];
|
|
144
|
+
if (!c.ptr)
|
|
145
|
+
c.ptr = [];
|
|
146
|
+
const lane = c.ptr;
|
|
147
|
+
const last = lane[lane.length - 1];
|
|
148
|
+
if (ph === 1 && last && last[0] === 1 && last[1] === p.id)
|
|
149
|
+
lane[lane.length - 1] = e;
|
|
150
|
+
else
|
|
151
|
+
lane.push(e);
|
|
152
|
+
if (ph === 0 || (ph === 1 && live.has(p.id)))
|
|
153
|
+
live.set(p.id, e);
|
|
154
|
+
else if (ph === 2 || ph === 3)
|
|
155
|
+
live.delete(p.id);
|
|
156
|
+
},
|
|
157
|
+
cancelPointers: () => {
|
|
158
|
+
if (live.size === 0)
|
|
159
|
+
return;
|
|
160
|
+
const c = open();
|
|
161
|
+
if (!c.ptr)
|
|
162
|
+
c.ptr = [];
|
|
163
|
+
const lane = c.ptr;
|
|
164
|
+
const at = stamp(0);
|
|
165
|
+
for (const e of live.values())
|
|
166
|
+
lane.push([3, e[1], e[2], e[3], e[4], e[5], e[6], at]);
|
|
167
|
+
live.clear();
|
|
168
|
+
},
|
|
169
|
+
context: (name, pushed) => {
|
|
170
|
+
const c = open();
|
|
171
|
+
if (!c.cx)
|
|
172
|
+
c.cx = [];
|
|
173
|
+
c.cx.push([name, pushed ? 1 : 0]);
|
|
174
|
+
},
|
|
175
|
+
consume: (action) => {
|
|
176
|
+
const c = open();
|
|
177
|
+
if (!c.cs)
|
|
178
|
+
c.cs = [];
|
|
179
|
+
c.cs.push(action);
|
|
180
|
+
},
|
|
181
|
+
control: (id) => {
|
|
182
|
+
const c = open();
|
|
183
|
+
if (!c.ui)
|
|
184
|
+
c.ui = [];
|
|
185
|
+
c.ui.push(id);
|
|
186
|
+
},
|
|
187
|
+
gamepads: (pads) => {
|
|
188
|
+
if (capturePads && !samePads(lastPads, pads, padsWritten)) {
|
|
189
|
+
lastPads = snapshotPads(pads);
|
|
190
|
+
padsWritten = true;
|
|
191
|
+
open().g = lastPads;
|
|
192
|
+
}
|
|
193
|
+
rec.tick();
|
|
194
|
+
return pads;
|
|
195
|
+
},
|
|
196
|
+
};
|
|
197
|
+
const rec = {
|
|
198
|
+
tick() {
|
|
199
|
+
if (cur) {
|
|
200
|
+
recording.ticks.push(cur);
|
|
201
|
+
cur = null;
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
const last = recording.ticks[recording.ticks.length - 1];
|
|
205
|
+
if (last && isRun(last) && last.t + last.n === t)
|
|
206
|
+
last.n++;
|
|
207
|
+
else
|
|
208
|
+
recording.ticks.push({ t, n: 1 });
|
|
209
|
+
}
|
|
210
|
+
t++;
|
|
211
|
+
const ms = measure ? (clock() - start) / t : input.tickMs;
|
|
212
|
+
if (ms > 0 && Number.isFinite(ms))
|
|
213
|
+
recording.tickMs = ms;
|
|
214
|
+
},
|
|
215
|
+
stop() {
|
|
216
|
+
remove();
|
|
217
|
+
if (input.recorder === rec)
|
|
218
|
+
input.recorder = null;
|
|
219
|
+
return recording;
|
|
220
|
+
},
|
|
221
|
+
get recording() {
|
|
222
|
+
return recording;
|
|
223
|
+
},
|
|
224
|
+
get ticks() {
|
|
225
|
+
return t;
|
|
226
|
+
},
|
|
227
|
+
};
|
|
228
|
+
const remove = input.onFeed(hook);
|
|
229
|
+
input.recorder = rec;
|
|
230
|
+
return rec;
|
|
231
|
+
}
|
|
232
|
+
/** Button value as recorded: `pressed` counts as 1, as `Input.evaluate` reads it. */
|
|
233
|
+
function buttonValue(b) {
|
|
234
|
+
return b.pressed ? Math.max(1, b.value) : b.value;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* True when the live pads equal the snapshot. Before any snapshot is written the implied state
|
|
238
|
+
* is "no pad connected", so a page whose `navigator.getGamepads()` is four empty slots records
|
|
239
|
+
* nothing. Allocation-free.
|
|
240
|
+
*/
|
|
241
|
+
function samePads(snap, pads, written) {
|
|
242
|
+
if (!written) {
|
|
243
|
+
for (const p of pads)
|
|
244
|
+
if (p && p.connected !== false)
|
|
245
|
+
return false;
|
|
246
|
+
return true;
|
|
247
|
+
}
|
|
248
|
+
if (snap.length !== pads.length)
|
|
249
|
+
return false;
|
|
250
|
+
for (let i = 0; i < pads.length; i++) {
|
|
251
|
+
const p = pads[i];
|
|
252
|
+
const s = snap[i];
|
|
253
|
+
const live = p && p.connected !== false ? p : null;
|
|
254
|
+
if (!live || !s) {
|
|
255
|
+
if (live || s)
|
|
256
|
+
return false;
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
if (s.buttons.length !== live.buttons.length || s.axes.length !== live.axes.length)
|
|
260
|
+
return false;
|
|
261
|
+
for (let j = 0; j < live.buttons.length; j++) {
|
|
262
|
+
if (s.buttons[j] !== buttonValue(live.buttons[j]))
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
for (let j = 0; j < live.axes.length; j++)
|
|
266
|
+
if (s.axes[j] !== live.axes[j])
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
return true;
|
|
270
|
+
}
|
|
271
|
+
function snapshotPads(pads) {
|
|
272
|
+
const out = [];
|
|
273
|
+
for (const p of pads) {
|
|
274
|
+
if (!p || p.connected === false)
|
|
275
|
+
out.push(null);
|
|
276
|
+
else
|
|
277
|
+
out.push({ buttons: p.buttons.map(buttonValue), axes: [...p.axes] });
|
|
278
|
+
}
|
|
279
|
+
return out;
|
|
280
|
+
}
|
|
281
|
+
// ---------------------------------------------------------------- playback
|
|
282
|
+
/**
|
|
283
|
+
* Replay `recording` into `input`. Call `step()` before each `input.update()`; the input's
|
|
284
|
+
* `getGamepads` result is replaced by the recorded snapshot while the playback is installed.
|
|
285
|
+
* `input.playback` points at it until `detach()`.
|
|
286
|
+
*/
|
|
287
|
+
export function createInputPlayback(input, recording, opts = {}) {
|
|
288
|
+
const ticks = recording.ticks;
|
|
289
|
+
const length = recordingLength(recording);
|
|
290
|
+
let tick = 0;
|
|
291
|
+
/** Index into `ticks` of the entry covering `tick`. */
|
|
292
|
+
let index = 0;
|
|
293
|
+
let pads = [];
|
|
294
|
+
let speed = Math.max(1, Math.floor(opts.speed ?? 1));
|
|
295
|
+
/** Replayed pointers still down, cancelled on `seek`. */
|
|
296
|
+
const live = new Map();
|
|
297
|
+
const driven = opts.clock ?? null;
|
|
298
|
+
const clock = opts.now ?? (driven ? () => driven.now() : linkedClock(input));
|
|
299
|
+
const tickMs = positive(opts.tickMs) ?? positive(recording.tickMs) ?? input.tickMs;
|
|
300
|
+
/**
|
|
301
|
+
* Anchor at the first `step()` (ws/input-10) unless the clock is the wall clock, whose readings
|
|
302
|
+
* between steps follow the replay's frame rate rather than its ticks.
|
|
303
|
+
*/
|
|
304
|
+
const anchorAtStep = opts.now !== undefined || driven !== null || !onWallClock(input);
|
|
305
|
+
/**
|
|
306
|
+
* The clock reading that recorded time 0 maps to. Off the wall clock it is set at the first
|
|
307
|
+
* `step()` (and the first after a `seek`): that reading less the fed tick's recorded start
|
|
308
|
+
* (`tick × tickMs`), so the first event keeps its recorded age however late the replay starts.
|
|
309
|
+
* On the wall clock, and wherever that anchor would put the first timed entry after the
|
|
310
|
+
* moment it is fed, the first timed entry sets it so that entry happens as it is fed (age 0),
|
|
311
|
+
* as before ws/input-10. `null` until then.
|
|
312
|
+
*/
|
|
313
|
+
let base = null;
|
|
314
|
+
/** Set at creation and by `seek`: the next `step()` anchors `base`. */
|
|
315
|
+
let fresh = true;
|
|
316
|
+
/** Set with `fresh`: the next timed entry may re-anchor `base` (see above). */
|
|
317
|
+
let firstTimed = true;
|
|
318
|
+
const replayPointer = (e) => {
|
|
319
|
+
// Version 3 entries happen at their recorded offset from tick 0; older ones (and the
|
|
320
|
+
// cancels `seek` makes) when their tick is fed, so their timing is the replay's tick spacing.
|
|
321
|
+
const time = e[7];
|
|
322
|
+
let age = 0;
|
|
323
|
+
if (time !== undefined) {
|
|
324
|
+
const now = clock();
|
|
325
|
+
// An event cannot happen after it is handled: a step anchor that would say so (a
|
|
326
|
+
// recording made with the clock advanced before the events, or a frozen replay clock)
|
|
327
|
+
// gives way to the entry itself.
|
|
328
|
+
if (base === null || (firstTimed && now < base + time))
|
|
329
|
+
base = now - time;
|
|
330
|
+
firstTimed = false;
|
|
331
|
+
age = now - (base + time);
|
|
332
|
+
}
|
|
333
|
+
input.replayPointer(PHASES[e[0]], e[1], e[2], e[3], e[4], e[5], e[6] === 1, age);
|
|
334
|
+
if (e[0] === 0 || (e[0] === 1 && live.has(e[1])))
|
|
335
|
+
live.set(e[1], e);
|
|
336
|
+
else if (e[0] === 2 || e[0] === 3)
|
|
337
|
+
live.delete(e[1]);
|
|
338
|
+
};
|
|
339
|
+
const feedTick = () => {
|
|
340
|
+
// Advance the entry cursor to the one covering this tick.
|
|
341
|
+
while (index < ticks.length) {
|
|
342
|
+
const e = ticks[index];
|
|
343
|
+
if (tick < e.t + (isRun(e) ? e.n : 1))
|
|
344
|
+
break;
|
|
345
|
+
index++;
|
|
346
|
+
}
|
|
347
|
+
const e = ticks[index];
|
|
348
|
+
tick++;
|
|
349
|
+
if (!e || isRun(e) || e.t !== tick - 1)
|
|
350
|
+
return;
|
|
351
|
+
if (e.r)
|
|
352
|
+
input.releaseAll();
|
|
353
|
+
// Only `keyDown` and `pointerAt` set `lastDevice`, so their relative order is all that is
|
|
354
|
+
// kept: the pointer goes first when a key came down after it (`d`), last otherwise.
|
|
355
|
+
if (e.d && e.p)
|
|
356
|
+
input.pointerAt(e.p[0], e.p[1], e.p[2] ?? 'mouse');
|
|
357
|
+
if (e.k) {
|
|
358
|
+
for (const [code, down] of e.k) {
|
|
359
|
+
if (down)
|
|
360
|
+
input.keyDown(code);
|
|
361
|
+
else
|
|
362
|
+
input.keyUp(code);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
// The pointer moves before the buttons (ws/input-8), as a DOM pointer event sets the
|
|
366
|
+
// position before its button: an orbit look's drag then starts where the press was, not at
|
|
367
|
+
// the previous position.
|
|
368
|
+
if (e.p && !e.d)
|
|
369
|
+
input.pointerAt(e.p[0], e.p[1], e.p[2] ?? 'mouse');
|
|
370
|
+
if (e.b) {
|
|
371
|
+
for (const [button, down] of e.b) {
|
|
372
|
+
if (down)
|
|
373
|
+
input.buttonDown(button);
|
|
374
|
+
else
|
|
375
|
+
input.buttonUp(button);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
if (e.w)
|
|
379
|
+
input.wheel(e.w[0], e.w[1]);
|
|
380
|
+
if (e.ptr)
|
|
381
|
+
for (const p of e.ptr)
|
|
382
|
+
replayPointer(p);
|
|
383
|
+
if (e.ui)
|
|
384
|
+
for (const id of e.ui)
|
|
385
|
+
input.replayControl(id);
|
|
386
|
+
if (e.g)
|
|
387
|
+
pads = e.g.map(padFromSnapshot);
|
|
388
|
+
};
|
|
389
|
+
const hook = {
|
|
390
|
+
keyDown: noop,
|
|
391
|
+
keyUp: noop,
|
|
392
|
+
buttonDown: noop,
|
|
393
|
+
buttonUp: noop,
|
|
394
|
+
wheel: noop,
|
|
395
|
+
pointerAt: noop,
|
|
396
|
+
releaseAll: noop,
|
|
397
|
+
padSource: () => pads,
|
|
398
|
+
gamepads: () => pads,
|
|
399
|
+
};
|
|
400
|
+
/** Feed one tick, then advance the driven clock past it, as a live fixed step does. */
|
|
401
|
+
const feedAndAdvance = () => {
|
|
402
|
+
feedTick();
|
|
403
|
+
driven?.advance(tickMs);
|
|
404
|
+
};
|
|
405
|
+
const pb = {
|
|
406
|
+
step() {
|
|
407
|
+
if (tick >= length)
|
|
408
|
+
return false;
|
|
409
|
+
if (fresh) {
|
|
410
|
+
fresh = false;
|
|
411
|
+
if (anchorAtStep)
|
|
412
|
+
base = clock() - tick * tickMs;
|
|
413
|
+
}
|
|
414
|
+
feedAndAdvance();
|
|
415
|
+
for (let i = 1; i < speed && tick < length; i++) {
|
|
416
|
+
input.update();
|
|
417
|
+
feedAndAdvance();
|
|
418
|
+
}
|
|
419
|
+
return true;
|
|
420
|
+
},
|
|
421
|
+
get done() {
|
|
422
|
+
return tick >= length;
|
|
423
|
+
},
|
|
424
|
+
get tick() {
|
|
425
|
+
return tick;
|
|
426
|
+
},
|
|
427
|
+
get length() {
|
|
428
|
+
return length;
|
|
429
|
+
},
|
|
430
|
+
seek(to) {
|
|
431
|
+
for (const e of [...live.values()])
|
|
432
|
+
replayPointer([3, e[1], e[2], e[3], e[4], e[5], e[6]]);
|
|
433
|
+
input.releaseAll();
|
|
434
|
+
tick = Math.max(0, Math.min(length, Math.floor(to)));
|
|
435
|
+
index = 0;
|
|
436
|
+
base = null;
|
|
437
|
+
fresh = true;
|
|
438
|
+
firstTimed = true;
|
|
439
|
+
// The pads in force at `to` are the last snapshot at or before it.
|
|
440
|
+
pads = [];
|
|
441
|
+
for (const e of ticks) {
|
|
442
|
+
if (e.t >= tick)
|
|
443
|
+
break;
|
|
444
|
+
if (!isRun(e) && e.g)
|
|
445
|
+
pads = e.g.map(padFromSnapshot);
|
|
446
|
+
}
|
|
447
|
+
},
|
|
448
|
+
get speed() {
|
|
449
|
+
return speed;
|
|
450
|
+
},
|
|
451
|
+
set speed(v) {
|
|
452
|
+
speed = Math.max(1, Math.floor(v));
|
|
453
|
+
},
|
|
454
|
+
clock: driven,
|
|
455
|
+
tickMs,
|
|
456
|
+
detach() {
|
|
457
|
+
remove();
|
|
458
|
+
if (input.playback === pb)
|
|
459
|
+
input.playback = null;
|
|
460
|
+
},
|
|
461
|
+
};
|
|
462
|
+
const remove = input.onFeed(hook);
|
|
463
|
+
input.playback = pb;
|
|
464
|
+
return pb;
|
|
465
|
+
}
|
|
466
|
+
function noop() { }
|
|
467
|
+
function positive(v) {
|
|
468
|
+
return v !== undefined && v > 0 && Number.isFinite(v) ? v : undefined;
|
|
469
|
+
}
|
|
470
|
+
function padFromSnapshot(s) {
|
|
471
|
+
if (!s)
|
|
472
|
+
return DISCONNECTED;
|
|
473
|
+
return {
|
|
474
|
+
connected: true,
|
|
475
|
+
buttons: s.buttons.map((v) => ({ pressed: v >= 1, value: v })),
|
|
476
|
+
axes: s.axes,
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
const DISCONNECTED = { connected: false, buttons: [], axes: [] };
|
|
480
|
+
// ---------------------------------------------------------------- JSON
|
|
481
|
+
/** The recording as a JSON string. */
|
|
482
|
+
export function serializeRecording(rec) {
|
|
483
|
+
return JSON.stringify(rec);
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* Parse and validate a recording (a JSON string or an already parsed value). Throws
|
|
487
|
+
* `InputRecordingError` on a wrong version or a malformed tick.
|
|
488
|
+
*/
|
|
489
|
+
export function parseRecording(source) {
|
|
490
|
+
let v;
|
|
491
|
+
if (typeof source === 'string') {
|
|
492
|
+
try {
|
|
493
|
+
v = JSON.parse(source);
|
|
494
|
+
}
|
|
495
|
+
catch (err) {
|
|
496
|
+
throw new InputRecordingError(`not JSON: ${err instanceof Error ? err.message : String(err)}`);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
else
|
|
500
|
+
v = source;
|
|
501
|
+
if (!isObject(v))
|
|
502
|
+
throw new InputRecordingError('recording is not an object');
|
|
503
|
+
const version = v.version;
|
|
504
|
+
if (version !== 1 && version !== 2 && version !== 3)
|
|
505
|
+
throw new InputRecordingError(`unsupported version ${String(v.version)}`);
|
|
506
|
+
if (!Array.isArray(v.ticks))
|
|
507
|
+
throw new InputRecordingError('ticks is not an array');
|
|
508
|
+
if (v.tickMs !== undefined &&
|
|
509
|
+
!(typeof v.tickMs === 'number' && v.tickMs > 0 && Number.isFinite(v.tickMs))) {
|
|
510
|
+
throw new InputRecordingError('bad tickMs');
|
|
511
|
+
}
|
|
512
|
+
let next = 0;
|
|
513
|
+
v.ticks.forEach((e, i) => {
|
|
514
|
+
if (!isObject(e) || typeof e.t !== 'number' || e.t !== next) {
|
|
515
|
+
throw new InputRecordingError(`tick ${i}: expected t ${next}`);
|
|
516
|
+
}
|
|
517
|
+
if ('n' in e) {
|
|
518
|
+
if (typeof e.n !== 'number' || e.n < 1 || !Number.isInteger(e.n)) {
|
|
519
|
+
throw new InputRecordingError(`tick ${i}: bad run count`);
|
|
520
|
+
}
|
|
521
|
+
next += e.n;
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
next++;
|
|
525
|
+
if (e.k !== undefined && !isPairs(e.k, 'string'))
|
|
526
|
+
throw bad(i, 'k');
|
|
527
|
+
if (e.b !== undefined && !isPairs(e.b, 'number'))
|
|
528
|
+
throw bad(i, 'b');
|
|
529
|
+
if (e.p !== undefined && !isPointer(e.p))
|
|
530
|
+
throw bad(i, 'p');
|
|
531
|
+
if (e.w !== undefined && !isNumbers(e.w, 2))
|
|
532
|
+
throw bad(i, 'w');
|
|
533
|
+
if (e.r !== undefined && e.r !== 1)
|
|
534
|
+
throw bad(i, 'r');
|
|
535
|
+
if (e.d !== undefined && e.d !== 1)
|
|
536
|
+
throw bad(i, 'd');
|
|
537
|
+
if (e.g !== undefined && !(Array.isArray(e.g) && e.g.every(isPadSnapshot)))
|
|
538
|
+
throw bad(i, 'g');
|
|
539
|
+
if (e.rumble !== undefined && !(Array.isArray(e.rumble) && e.rumble.every(isRumble))) {
|
|
540
|
+
throw bad(i, 'rumble');
|
|
541
|
+
}
|
|
542
|
+
if (e.ui !== undefined && !(Array.isArray(e.ui) && e.ui.every((u) => typeof u === 'string'))) {
|
|
543
|
+
throw bad(i, 'ui');
|
|
544
|
+
}
|
|
545
|
+
if (version === 1)
|
|
546
|
+
return;
|
|
547
|
+
const timed = version === 3;
|
|
548
|
+
if (e.ptr !== undefined &&
|
|
549
|
+
!(Array.isArray(e.ptr) && e.ptr.every((p) => isPointerEntry(p, timed)))) {
|
|
550
|
+
throw bad(i, 'ptr');
|
|
551
|
+
}
|
|
552
|
+
if (e.cx !== undefined && !isPairs(e.cx, 'string'))
|
|
553
|
+
throw bad(i, 'cx');
|
|
554
|
+
if (e.cs !== undefined && !(Array.isArray(e.cs) && e.cs.every((a) => typeof a === 'string'))) {
|
|
555
|
+
throw bad(i, 'cs');
|
|
556
|
+
}
|
|
557
|
+
});
|
|
558
|
+
return v;
|
|
559
|
+
}
|
|
560
|
+
function bad(i, field) {
|
|
561
|
+
return new InputRecordingError(`tick ${i}: bad ${field}`);
|
|
562
|
+
}
|
|
563
|
+
function isObject(v) {
|
|
564
|
+
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
565
|
+
}
|
|
566
|
+
function isNumbers(v, n) {
|
|
567
|
+
return (Array.isArray(v) &&
|
|
568
|
+
(n === undefined || v.length === n) &&
|
|
569
|
+
v.every((x) => typeof x === 'number' && Number.isFinite(x)));
|
|
570
|
+
}
|
|
571
|
+
function isPairs(v, kind) {
|
|
572
|
+
return (Array.isArray(v) &&
|
|
573
|
+
v.every((e) => Array.isArray(e) && e.length === 2 && typeof e[0] === kind && (e[1] === 0 || e[1] === 1)));
|
|
574
|
+
}
|
|
575
|
+
function isPointer(v) {
|
|
576
|
+
if (!Array.isArray(v) || v.length < 2 || v.length > 3)
|
|
577
|
+
return false;
|
|
578
|
+
if (!isNumbers(v.slice(0, 2)))
|
|
579
|
+
return false;
|
|
580
|
+
return v.length === 2 || v[2] === 'mouse' || v[2] === 'touch' || v[2] === 'pen';
|
|
581
|
+
}
|
|
582
|
+
/** A `ptr` entry: 7 fields in version 2, 8 (with a finite `time`) in version 3. */
|
|
583
|
+
function isPointerEntry(v, timed) {
|
|
584
|
+
return (Array.isArray(v) &&
|
|
585
|
+
v.length === (timed ? 8 : 7) &&
|
|
586
|
+
(!timed || (typeof v[7] === 'number' && Number.isFinite(v[7]))) &&
|
|
587
|
+
Number.isInteger(v[0]) &&
|
|
588
|
+
v[0] >= 0 &&
|
|
589
|
+
v[0] <= 4 &&
|
|
590
|
+
(v[2] === 'mouse' || v[2] === 'touch' || v[2] === 'pen') &&
|
|
591
|
+
isNumbers([v[1], v[3], v[4], v[5]]) &&
|
|
592
|
+
(v[6] === 0 || v[6] === 1));
|
|
593
|
+
}
|
|
594
|
+
function isRumble(v) {
|
|
595
|
+
return Array.isArray(v) && (v.length === 3 || v.length === 4) && isNumbers(v);
|
|
596
|
+
}
|
|
597
|
+
function isPadSnapshot(v) {
|
|
598
|
+
if (v === null)
|
|
599
|
+
return true;
|
|
600
|
+
return isObject(v) && isNumbers(v.buttons) && isNumbers(v.axes);
|
|
601
|
+
}
|