@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,281 @@
|
|
|
1
|
+
import { defaultTextures } from './texture.js';
|
|
2
|
+
/** First binding of `BindingDesc.buffers` (textures stop at 15, so up to 14 texture slots). */
|
|
3
|
+
export const BUFFER_BINDING_BASE = 16;
|
|
4
|
+
export function hasBindings(desc) {
|
|
5
|
+
return ((desc.uniformBytes ?? 0) > 0 || (desc.textures ?? 0) > 0 || (desc.buffers?.length ?? 0) > 0);
|
|
6
|
+
}
|
|
7
|
+
/** The view dimension of texture slot `slot` under `desc.viewDimension` (default `'2d'`). */
|
|
8
|
+
export function slotViewDimension(desc, slot) {
|
|
9
|
+
const d = desc.viewDimension;
|
|
10
|
+
if (d === undefined)
|
|
11
|
+
return '2d';
|
|
12
|
+
if (typeof d === 'string')
|
|
13
|
+
return d;
|
|
14
|
+
return d[slot] ?? '2d';
|
|
15
|
+
}
|
|
16
|
+
/** 1×1, 1-layer white `'2d-array'` views, one per device: the default for unbound array slots. */
|
|
17
|
+
const whiteArrays = new WeakMap();
|
|
18
|
+
function whiteArrayView(device) {
|
|
19
|
+
let view = whiteArrays.get(device);
|
|
20
|
+
if (!view) {
|
|
21
|
+
const texture = device.createTexture({
|
|
22
|
+
label: 'white-array',
|
|
23
|
+
size: [1, 1, 1],
|
|
24
|
+
format: 'rgba8unorm',
|
|
25
|
+
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST,
|
|
26
|
+
});
|
|
27
|
+
device.queue.writeTexture({ texture }, new Uint8Array([255, 255, 255, 255]), { bytesPerRow: 4 }, [1, 1, 1]);
|
|
28
|
+
view = texture.createView({ label: 'white-array', dimension: '2d-array' });
|
|
29
|
+
whiteArrays.set(device, view);
|
|
30
|
+
}
|
|
31
|
+
return view;
|
|
32
|
+
}
|
|
33
|
+
export function createBindingLayout(device, desc, label, dynamicUniform = false) {
|
|
34
|
+
const vis = desc.visibility ?? GPUShaderStage.FRAGMENT | GPUShaderStage.VERTEX;
|
|
35
|
+
const entries = [];
|
|
36
|
+
if ((desc.uniformBytes ?? 0) > 0) {
|
|
37
|
+
entries.push({
|
|
38
|
+
binding: 0,
|
|
39
|
+
visibility: vis,
|
|
40
|
+
buffer: dynamicUniform ? { hasDynamicOffset: true } : {},
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
const n = desc.textures ?? 0;
|
|
44
|
+
if (n > 0) {
|
|
45
|
+
entries.push({ binding: 1, visibility: vis, sampler: {} });
|
|
46
|
+
for (let i = 0; i < n; i++) {
|
|
47
|
+
const viewDimension = slotViewDimension(desc, i);
|
|
48
|
+
entries.push({
|
|
49
|
+
binding: 2 + i,
|
|
50
|
+
visibility: vis,
|
|
51
|
+
texture: viewDimension === '2d' ? { sampleType: 'float' } : { sampleType: 'float', viewDimension },
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const nb = desc.buffers?.length ?? 0;
|
|
56
|
+
for (let i = 0; i < nb; i++) {
|
|
57
|
+
entries.push({
|
|
58
|
+
binding: BUFFER_BINDING_BASE + i,
|
|
59
|
+
visibility: vis,
|
|
60
|
+
buffer: { type: 'read-only-storage' },
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return device.createBindGroupLayout({ label, entries });
|
|
64
|
+
}
|
|
65
|
+
/** Bind groups kept for recently used view sets (ping-pong flips between two). */
|
|
66
|
+
const GROUP_CACHE = 4;
|
|
67
|
+
/** Initial per-draw slots (including the shared slot 0). Grows by doubling. */
|
|
68
|
+
const INITIAL_DRAW_SLOTS = 16;
|
|
69
|
+
/**
|
|
70
|
+
* Owns the uniform buffer + bind group for one binding set; rebuilds the group lazily.
|
|
71
|
+
* Bind groups for the last few texture sets are cached, so alternating textures (ping-pong)
|
|
72
|
+
* allocates nothing after the first round. Every texture slot starts bound to a 1×1 white
|
|
73
|
+
* texture (`defaultView`, or `defaultTextures(device).white` when none is given; a 1-layer white
|
|
74
|
+
* array for `'2d-array'` slots), so a material with four slots draws with none of them set;
|
|
75
|
+
* `setTexture` later rebuilds the group.
|
|
76
|
+
*/
|
|
77
|
+
export class BindingSet {
|
|
78
|
+
device;
|
|
79
|
+
sampler;
|
|
80
|
+
label;
|
|
81
|
+
layout;
|
|
82
|
+
/** Replaced when a per-draw set grows. */
|
|
83
|
+
uniformBuffer;
|
|
84
|
+
/** True when the uniform binding takes a dynamic offset (see `BindingSetOptions.perDraw`). */
|
|
85
|
+
perDraw;
|
|
86
|
+
/** Uniform block size in bytes (rounded up to 16), 0 when there is none. */
|
|
87
|
+
blockBytes;
|
|
88
|
+
/** Byte distance between per-draw blocks (block size rounded up to the offset alignment). */
|
|
89
|
+
stride;
|
|
90
|
+
views;
|
|
91
|
+
buffers;
|
|
92
|
+
group = null;
|
|
93
|
+
cache = [];
|
|
94
|
+
staging = null;
|
|
95
|
+
stagingF32 = null;
|
|
96
|
+
drawSlots = 0;
|
|
97
|
+
constructor(device, desc, sampler, defaultView, label, opts = {}) {
|
|
98
|
+
this.device = device;
|
|
99
|
+
this.sampler = sampler;
|
|
100
|
+
this.label = label;
|
|
101
|
+
const bytes = desc.uniformBytes ?? 0;
|
|
102
|
+
this.blockBytes = Math.ceil(bytes / 16) * 16;
|
|
103
|
+
this.perDraw = !!opts.perDraw;
|
|
104
|
+
if (this.perDraw && bytes <= 0) {
|
|
105
|
+
throw new Error(`${label}: perDraw uniforms need uniformBytes > 0`);
|
|
106
|
+
}
|
|
107
|
+
const align = device.limits?.minUniformBufferOffsetAlignment ?? 256;
|
|
108
|
+
this.stride = this.perDraw ? Math.ceil(this.blockBytes / align) * align : this.blockBytes;
|
|
109
|
+
this.layout = createBindingLayout(device, desc, `${label}-layout`, this.perDraw);
|
|
110
|
+
if (this.perDraw) {
|
|
111
|
+
this.staging = new Uint8Array(this.stride * INITIAL_DRAW_SLOTS);
|
|
112
|
+
this.stagingF32 = new Float32Array(this.staging.buffer);
|
|
113
|
+
}
|
|
114
|
+
this.uniformBuffer = bytes > 0 ? this.makeUniformBuffer() : null;
|
|
115
|
+
const n = desc.textures ?? 0;
|
|
116
|
+
// Unset 2D slots read white: the caller's view when it has one, else the device's registry.
|
|
117
|
+
const white = n > 0 ? (defaultView ?? defaultTextures(device).white.view) : null;
|
|
118
|
+
this.views = new Array(n).fill(white);
|
|
119
|
+
for (let i = 0; i < n; i++) {
|
|
120
|
+
if (slotViewDimension(desc, i) === '2d-array')
|
|
121
|
+
this.views[i] = whiteArrayView(device);
|
|
122
|
+
}
|
|
123
|
+
this.buffers = desc.buffers ? [...desc.buffers] : [];
|
|
124
|
+
}
|
|
125
|
+
setUniforms(data, byteOffset = 0) {
|
|
126
|
+
if (!this.uniformBuffer)
|
|
127
|
+
throw new Error(`${this.label}: no uniforms declared`);
|
|
128
|
+
if (ArrayBuffer.isView(data)) {
|
|
129
|
+
this.device.queue.writeBuffer(this.uniformBuffer, byteOffset, data.buffer, data.byteOffset, data.byteLength);
|
|
130
|
+
// Keep slot 0 on the CPU too, so a grown buffer can be refilled.
|
|
131
|
+
if (this.staging)
|
|
132
|
+
this.stageShared(data.buffer, data.byteOffset, data.byteLength, byteOffset);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
this.device.queue.writeBuffer(this.uniformBuffer, byteOffset, data);
|
|
136
|
+
if (this.staging)
|
|
137
|
+
this.stageShared(data, 0, data.byteLength, byteOffset);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/** Per-draw blocks recorded since the last flush. */
|
|
141
|
+
get drawCount() {
|
|
142
|
+
return this.drawSlots;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Stage one per-draw uniform block (f32s; the rest of the block reads 0) and return its
|
|
146
|
+
* dynamic offset. Uploaded by `flushDrawUniforms`, normally called by the renderer.
|
|
147
|
+
*/
|
|
148
|
+
pushDrawUniforms(data) {
|
|
149
|
+
if (!this.perDraw)
|
|
150
|
+
throw new Error(`${this.label}: per-draw uniforms not enabled`);
|
|
151
|
+
if (data.length * 4 > this.blockBytes) {
|
|
152
|
+
throw new Error(`${this.label}: per-draw uniforms are ${data.length * 4} bytes, block is ${this.blockBytes}`);
|
|
153
|
+
}
|
|
154
|
+
const slot = ++this.drawSlots;
|
|
155
|
+
const offset = slot * this.stride;
|
|
156
|
+
if (offset + this.stride > this.staging.byteLength) {
|
|
157
|
+
const next = new Uint8Array(this.staging.byteLength * 2);
|
|
158
|
+
next.set(this.staging);
|
|
159
|
+
this.staging = next;
|
|
160
|
+
this.stagingF32 = new Float32Array(next.buffer);
|
|
161
|
+
}
|
|
162
|
+
const f = this.stagingF32;
|
|
163
|
+
const o = offset / 4;
|
|
164
|
+
const n = data.length;
|
|
165
|
+
for (let i = 0; i < n; i++)
|
|
166
|
+
f[o + i] = data[i];
|
|
167
|
+
f.fill(0, o + n, o + this.blockBytes / 4);
|
|
168
|
+
return offset;
|
|
169
|
+
}
|
|
170
|
+
/** Upload this frame's per-draw blocks (growing the buffer if needed) and reset the count. */
|
|
171
|
+
flushDrawUniforms() {
|
|
172
|
+
const n = this.drawSlots;
|
|
173
|
+
if (n === 0 || !this.staging)
|
|
174
|
+
return;
|
|
175
|
+
this.drawSlots = 0;
|
|
176
|
+
const needed = (n + 1) * this.stride;
|
|
177
|
+
if (needed > this.uniformBuffer.size) {
|
|
178
|
+
this.uniformBuffer.destroy();
|
|
179
|
+
this.uniformBuffer = this.makeUniformBuffer();
|
|
180
|
+
this.invalidateGroups();
|
|
181
|
+
this.device.queue.writeBuffer(this.uniformBuffer, 0, this.staging.buffer, 0, needed);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
this.device.queue.writeBuffer(this.uniformBuffer, this.stride, this.staging.buffer, this.stride, n * this.stride);
|
|
185
|
+
}
|
|
186
|
+
/** Drop this frame's per-draw blocks without uploading. */
|
|
187
|
+
discardDrawUniforms() {
|
|
188
|
+
this.drawSlots = 0;
|
|
189
|
+
}
|
|
190
|
+
setTexture(slot, tex) {
|
|
191
|
+
if (slot < 0 || slot >= this.views.length) {
|
|
192
|
+
throw new Error(`${this.label}: texture slot ${slot} out of range`);
|
|
193
|
+
}
|
|
194
|
+
const view = 'view' in tex ? tex.view : tex;
|
|
195
|
+
if (this.views[slot] === view)
|
|
196
|
+
return;
|
|
197
|
+
this.views[slot] = view;
|
|
198
|
+
this.group = null;
|
|
199
|
+
}
|
|
200
|
+
/** Rebind storage buffer slot `i` (`@binding(BUFFER_BINDING_BASE + i)`); groups rebuild lazily. */
|
|
201
|
+
setBuffer(slot, buffer) {
|
|
202
|
+
if (slot < 0 || slot >= this.buffers.length) {
|
|
203
|
+
throw new Error(`${this.label}: buffer slot ${slot} out of range`);
|
|
204
|
+
}
|
|
205
|
+
if (this.buffers[slot] === buffer)
|
|
206
|
+
return;
|
|
207
|
+
this.buffers[slot] = buffer;
|
|
208
|
+
this.invalidateGroups();
|
|
209
|
+
}
|
|
210
|
+
/** Build a bind group for an explicit set of views (callers cache it). */
|
|
211
|
+
createGroup(views = this.views) {
|
|
212
|
+
const entries = [];
|
|
213
|
+
if (this.uniformBuffer) {
|
|
214
|
+
entries.push({
|
|
215
|
+
binding: 0,
|
|
216
|
+
resource: this.perDraw
|
|
217
|
+
? { buffer: this.uniformBuffer, size: this.blockBytes }
|
|
218
|
+
: { buffer: this.uniformBuffer },
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
if (views.length) {
|
|
222
|
+
entries.push({ binding: 1, resource: this.sampler });
|
|
223
|
+
views.forEach((v, i) => {
|
|
224
|
+
entries.push({ binding: 2 + i, resource: v });
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
this.buffers.forEach((b, i) => {
|
|
228
|
+
entries.push({ binding: BUFFER_BINDING_BASE + i, resource: { buffer: b } });
|
|
229
|
+
});
|
|
230
|
+
return this.device.createBindGroup({
|
|
231
|
+
label: `${this.label}-group`,
|
|
232
|
+
layout: this.layout,
|
|
233
|
+
entries,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
get bindGroup() {
|
|
237
|
+
if (!this.group)
|
|
238
|
+
this.group = this.cachedGroup();
|
|
239
|
+
return this.group;
|
|
240
|
+
}
|
|
241
|
+
destroy() {
|
|
242
|
+
this.uniformBuffer?.destroy();
|
|
243
|
+
}
|
|
244
|
+
cachedGroup() {
|
|
245
|
+
const views = this.views;
|
|
246
|
+
const cache = this.cache;
|
|
247
|
+
for (let i = 0; i < cache.length; i++) {
|
|
248
|
+
const c = cache[i];
|
|
249
|
+
let same = true;
|
|
250
|
+
for (let j = 0; j < views.length; j++) {
|
|
251
|
+
if (c.views[j] !== views[j]) {
|
|
252
|
+
same = false;
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
if (same)
|
|
257
|
+
return c.group;
|
|
258
|
+
}
|
|
259
|
+
const group = this.createGroup();
|
|
260
|
+
if (cache.length >= GROUP_CACHE)
|
|
261
|
+
cache.shift();
|
|
262
|
+
cache.push({ views: views.slice(), group });
|
|
263
|
+
return group;
|
|
264
|
+
}
|
|
265
|
+
stageShared(src, srcOffset, bytes, at) {
|
|
266
|
+
const n = Math.max(0, Math.min(bytes, this.stride - at));
|
|
267
|
+
if (n > 0)
|
|
268
|
+
this.staging.set(new Uint8Array(src, srcOffset, n), at);
|
|
269
|
+
}
|
|
270
|
+
invalidateGroups() {
|
|
271
|
+
this.group = null;
|
|
272
|
+
this.cache.length = 0;
|
|
273
|
+
}
|
|
274
|
+
makeUniformBuffer() {
|
|
275
|
+
return this.device.createBuffer({
|
|
276
|
+
label: `${this.label}-uniforms`,
|
|
277
|
+
size: this.staging ? this.staging.byteLength : this.blockBytes,
|
|
278
|
+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a material or fullscreen pass blends into its target (`MaterialDesc.blend`,
|
|
3
|
+
* `FullscreenPassDesc.blend`):
|
|
4
|
+
*
|
|
5
|
+
* - `alpha`: straight alpha (`rgb * a + dst * (1 - a)`). Default.
|
|
6
|
+
* - `premultiplied`: shader outputs rgb already multiplied by alpha.
|
|
7
|
+
* - `additive`: `rgb * a + dst`. Destination alpha untouched. Glows, sparks.
|
|
8
|
+
* - `opaque`: overwrite.
|
|
9
|
+
* - `multiply`: `dst * rgb` (colour factors `dst` / `zero`); destination alpha kept (alpha
|
|
10
|
+
* factors `zero` / `one`). Decals, stains, tinted glass: white leaves the surface alone.
|
|
11
|
+
*/
|
|
12
|
+
export type RenderBlendMode = 'alpha' | 'premultiplied' | 'additive' | 'opaque' | 'multiply';
|
|
13
|
+
export declare function blendState(mode: RenderBlendMode): GPUBlendState | undefined;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export function blendState(mode) {
|
|
2
|
+
switch (mode) {
|
|
3
|
+
case 'opaque':
|
|
4
|
+
return undefined;
|
|
5
|
+
case 'alpha':
|
|
6
|
+
return {
|
|
7
|
+
color: { srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha', operation: 'add' },
|
|
8
|
+
alpha: { srcFactor: 'one', dstFactor: 'one-minus-src-alpha', operation: 'add' },
|
|
9
|
+
};
|
|
10
|
+
case 'premultiplied':
|
|
11
|
+
return {
|
|
12
|
+
color: { srcFactor: 'one', dstFactor: 'one-minus-src-alpha', operation: 'add' },
|
|
13
|
+
alpha: { srcFactor: 'one', dstFactor: 'one-minus-src-alpha', operation: 'add' },
|
|
14
|
+
};
|
|
15
|
+
case 'additive':
|
|
16
|
+
return {
|
|
17
|
+
color: { srcFactor: 'src-alpha', dstFactor: 'one', operation: 'add' },
|
|
18
|
+
alpha: { srcFactor: 'zero', dstFactor: 'one', operation: 'add' },
|
|
19
|
+
};
|
|
20
|
+
case 'multiply':
|
|
21
|
+
return {
|
|
22
|
+
color: { srcFactor: 'dst', dstFactor: 'zero', operation: 'add' },
|
|
23
|
+
alpha: { srcFactor: 'zero', dstFactor: 'one', operation: 'add' },
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 2D camera follow (ws/ergo-2d-2): the platformer camera every 2D game rewrote. A dead zone
|
|
3
|
+
* the target moves inside without the view moving, look-ahead toward the target's velocity,
|
|
4
|
+
* exponential smoothing, and a world rectangle the view never leaves. It drives an ortho2d
|
|
5
|
+
* `Camera` through `camera.x` and `camera.y` only (the view's top-left in design px) and reads
|
|
6
|
+
* `camera.screen` and `camera.zoom` for the view size; nothing else on the camera is touched.
|
|
7
|
+
*
|
|
8
|
+
* Per `update(dt, targetX, targetY, velX, velY)`:
|
|
9
|
+
* 1. the anchor moves just enough to keep the target inside the dead zone (none: it tracks);
|
|
10
|
+
* 2. the look-ahead eases toward `sign(vel) × lookAhead` with time constant `lookAheadSmoothing`;
|
|
11
|
+
* 3. the view centre eases toward `anchor + lookAhead` with time constant `smoothing`;
|
|
12
|
+
* 4. the view rect is clamped inside `bounds` (a view wider than the bounds is centred).
|
|
13
|
+
* Every easing is `1 - exp(-dt / tau)`, so the result depends on `dt` alone. `teleport` puts
|
|
14
|
+
* everything at a point with no easing. No allocation per frame.
|
|
15
|
+
*/
|
|
16
|
+
import type { Camera } from './camera.js';
|
|
17
|
+
/** What the follow needs from a `Camera`. */
|
|
18
|
+
export type Follow2DCamera = Pick<Camera, 'x' | 'y' | 'zoom' | 'screen'>;
|
|
19
|
+
export interface Follow2DBounds {
|
|
20
|
+
minX: number;
|
|
21
|
+
minY: number;
|
|
22
|
+
maxX: number;
|
|
23
|
+
maxY: number;
|
|
24
|
+
}
|
|
25
|
+
export interface Follow2DOptions {
|
|
26
|
+
/** Box around the anchor (world px) the target moves inside freely. Default `0 × 0`. */
|
|
27
|
+
deadZone?: {
|
|
28
|
+
w: number;
|
|
29
|
+
h: number;
|
|
30
|
+
};
|
|
31
|
+
/** How far ahead of the target (world px) the view leads along each moving axis. Default 0. */
|
|
32
|
+
lookAhead?: {
|
|
33
|
+
x: number;
|
|
34
|
+
y: number;
|
|
35
|
+
};
|
|
36
|
+
/** Time constant (s) of the look-ahead easing. Default 0.25; 0 is instant. */
|
|
37
|
+
lookAheadSmoothing?: number;
|
|
38
|
+
/** Time constant (s) of the view's easing toward its goal. Default 0 (instant). */
|
|
39
|
+
smoothing?: number;
|
|
40
|
+
/** World rect the view stays inside. Mutate `follow.bounds` later to change it. */
|
|
41
|
+
bounds?: Follow2DBounds;
|
|
42
|
+
/** First `update` snaps to the target instead of easing from the camera's position. Default true. */
|
|
43
|
+
snapOnStart?: boolean;
|
|
44
|
+
}
|
|
45
|
+
export interface Follow2D {
|
|
46
|
+
/** View centre, world px (what the camera shows at its middle). */
|
|
47
|
+
readonly x: number;
|
|
48
|
+
readonly y: number;
|
|
49
|
+
/** Dead-zone centre, world px. */
|
|
50
|
+
readonly anchorX: number;
|
|
51
|
+
readonly anchorY: number;
|
|
52
|
+
/** Current look-ahead offset, world px. */
|
|
53
|
+
readonly lookX: number;
|
|
54
|
+
readonly lookY: number;
|
|
55
|
+
readonly deadZone: {
|
|
56
|
+
w: number;
|
|
57
|
+
h: number;
|
|
58
|
+
};
|
|
59
|
+
readonly lookAhead: {
|
|
60
|
+
x: number;
|
|
61
|
+
y: number;
|
|
62
|
+
};
|
|
63
|
+
lookAheadSmoothing: number;
|
|
64
|
+
smoothing: number;
|
|
65
|
+
bounds: Follow2DBounds | null;
|
|
66
|
+
/** Advance by `dt` seconds toward `(targetX, targetY)` moving at `(velX, velY)`; writes the camera. */
|
|
67
|
+
update(dt: number, targetX: number, targetY: number, velX?: number, velY?: number): void;
|
|
68
|
+
/** Put the anchor and the view at `(x, y)` with no easing and no look-ahead; writes the camera. */
|
|
69
|
+
teleport(x: number, y: number): void;
|
|
70
|
+
}
|
|
71
|
+
/** Make a `Follow2D` over `camera`. Allocates once. */
|
|
72
|
+
export declare function createFollow2D(camera: Follow2DCamera, opts?: Follow2DOptions): Follow2D;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
function ease(dt, tau) {
|
|
2
|
+
return tau > 0 ? 1 - Math.exp(-dt / tau) : 1;
|
|
3
|
+
}
|
|
4
|
+
/** Make a `Follow2D` over `camera`. Allocates once. */
|
|
5
|
+
export function createFollow2D(camera, opts = {}) {
|
|
6
|
+
const deadZone = { w: opts.deadZone?.w ?? 0, h: opts.deadZone?.h ?? 0 };
|
|
7
|
+
const lookAhead = { x: opts.lookAhead?.x ?? 0, y: opts.lookAhead?.y ?? 0 };
|
|
8
|
+
let started = !(opts.snapOnStart ?? true);
|
|
9
|
+
let ax = camera.x + camera.screen.width / 2;
|
|
10
|
+
let ay = camera.y + camera.screen.height / 2;
|
|
11
|
+
let x = ax;
|
|
12
|
+
let y = ay;
|
|
13
|
+
let lx = 0;
|
|
14
|
+
let ly = 0;
|
|
15
|
+
function clampAndWrite() {
|
|
16
|
+
const b = follow.bounds;
|
|
17
|
+
if (b) {
|
|
18
|
+
const hw = camera.screen.width / (2 * camera.zoom);
|
|
19
|
+
const hh = camera.screen.height / (2 * camera.zoom);
|
|
20
|
+
x =
|
|
21
|
+
b.maxX - b.minX <= 2 * hw
|
|
22
|
+
? (b.minX + b.maxX) / 2
|
|
23
|
+
: Math.min(Math.max(x, b.minX + hw), b.maxX - hw);
|
|
24
|
+
y =
|
|
25
|
+
b.maxY - b.minY <= 2 * hh
|
|
26
|
+
? (b.minY + b.maxY) / 2
|
|
27
|
+
: Math.min(Math.max(y, b.minY + hh), b.maxY - hh);
|
|
28
|
+
}
|
|
29
|
+
camera.x = x - camera.screen.width / 2;
|
|
30
|
+
camera.y = y - camera.screen.height / 2;
|
|
31
|
+
}
|
|
32
|
+
const follow = {
|
|
33
|
+
get x() {
|
|
34
|
+
return x;
|
|
35
|
+
},
|
|
36
|
+
get y() {
|
|
37
|
+
return y;
|
|
38
|
+
},
|
|
39
|
+
get anchorX() {
|
|
40
|
+
return ax;
|
|
41
|
+
},
|
|
42
|
+
get anchorY() {
|
|
43
|
+
return ay;
|
|
44
|
+
},
|
|
45
|
+
get lookX() {
|
|
46
|
+
return lx;
|
|
47
|
+
},
|
|
48
|
+
get lookY() {
|
|
49
|
+
return ly;
|
|
50
|
+
},
|
|
51
|
+
deadZone,
|
|
52
|
+
lookAhead,
|
|
53
|
+
lookAheadSmoothing: opts.lookAheadSmoothing ?? 0.25,
|
|
54
|
+
smoothing: opts.smoothing ?? 0,
|
|
55
|
+
bounds: opts.bounds ?? null,
|
|
56
|
+
update(dt, tx, ty, vx = 0, vy = 0) {
|
|
57
|
+
if (!started) {
|
|
58
|
+
started = true;
|
|
59
|
+
follow.teleport(tx, ty);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const hw = deadZone.w / 2;
|
|
63
|
+
const hh = deadZone.h / 2;
|
|
64
|
+
if (tx < ax - hw)
|
|
65
|
+
ax = tx + hw;
|
|
66
|
+
else if (tx > ax + hw)
|
|
67
|
+
ax = tx - hw;
|
|
68
|
+
if (ty < ay - hh)
|
|
69
|
+
ay = ty + hh;
|
|
70
|
+
else if (ty > ay + hh)
|
|
71
|
+
ay = ty - hh;
|
|
72
|
+
const kl = ease(dt, follow.lookAheadSmoothing);
|
|
73
|
+
lx += (Math.sign(vx) * lookAhead.x - lx) * kl;
|
|
74
|
+
ly += (Math.sign(vy) * lookAhead.y - ly) * kl;
|
|
75
|
+
const k = ease(dt, follow.smoothing);
|
|
76
|
+
x += (ax + lx - x) * k;
|
|
77
|
+
y += (ay + ly - y) * k;
|
|
78
|
+
clampAndWrite();
|
|
79
|
+
},
|
|
80
|
+
teleport(px, py) {
|
|
81
|
+
started = true;
|
|
82
|
+
ax = px;
|
|
83
|
+
ay = py;
|
|
84
|
+
x = px;
|
|
85
|
+
y = py;
|
|
86
|
+
lx = 0;
|
|
87
|
+
ly = 0;
|
|
88
|
+
clampAndWrite();
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
return follow;
|
|
92
|
+
}
|