@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,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The third set of HUD widgets (ws/ui-4): a radial progress ring and a compass strip. Both are
|
|
3
|
+
* placed in a layout region (`region`, like the meter and the heading strip) and write the DOM
|
|
4
|
+
* only when a value changed. Sizes are design px (`themePx`); colours and spacing come from the
|
|
5
|
+
* theme tokens. `WIDGETS3_CSS` is injected on first use (`ensureWidgets3Styles`).
|
|
6
|
+
*/
|
|
7
|
+
import { h } from './dom.js';
|
|
8
|
+
import { themePx, wrapDegrees } from './hud.js';
|
|
9
|
+
const clamp01 = (v) => Math.min(1, Math.max(0, v));
|
|
10
|
+
/**
|
|
11
|
+
* A radial progress ring: a conic gradient fills clockwise from the top by `value`, masked to a
|
|
12
|
+
* ring of `thickness`, with a label in the middle. `role="progressbar"` with `aria-valuenow`.
|
|
13
|
+
*/
|
|
14
|
+
export function createRing(host, opts = {}) {
|
|
15
|
+
ensureWidgets3Styles(host.layers.hud.ownerDocument);
|
|
16
|
+
const radius = opts.radius ?? 48;
|
|
17
|
+
const thickness = opts.thickness ?? 8;
|
|
18
|
+
const labelEl = h('span', { class: 'tc-ring-label' }, opts.label ?? '');
|
|
19
|
+
const fill = h('div', { class: 'tc-ring-fill', 'aria-hidden': 'true' });
|
|
20
|
+
const el = h('div', {
|
|
21
|
+
class: 'tc-ring',
|
|
22
|
+
role: 'progressbar',
|
|
23
|
+
'aria-label': opts.label,
|
|
24
|
+
'aria-valuemin': '0',
|
|
25
|
+
'aria-valuemax': '1',
|
|
26
|
+
style: {
|
|
27
|
+
'--tc-ring-size': themePx(radius * 2),
|
|
28
|
+
'--tc-ring-thickness': themePx(thickness),
|
|
29
|
+
...(opts.color ? { '--tc-ring-color': opts.color } : {}),
|
|
30
|
+
},
|
|
31
|
+
}, fill, labelEl);
|
|
32
|
+
let value = Number.NaN;
|
|
33
|
+
const set = (v) => {
|
|
34
|
+
const next = clamp01(v);
|
|
35
|
+
if (next === value)
|
|
36
|
+
return;
|
|
37
|
+
value = next;
|
|
38
|
+
el.setAttribute('aria-valuenow', String(next));
|
|
39
|
+
fill.style.setProperty('--tc-ring-value', String(next));
|
|
40
|
+
};
|
|
41
|
+
set(opts.value ?? 0);
|
|
42
|
+
const handle = host.layout.add(el, {
|
|
43
|
+
place: { default: opts.region ?? 'bottom' },
|
|
44
|
+
order: opts.order,
|
|
45
|
+
});
|
|
46
|
+
return {
|
|
47
|
+
el,
|
|
48
|
+
get value() {
|
|
49
|
+
return value;
|
|
50
|
+
},
|
|
51
|
+
set,
|
|
52
|
+
setLabel(label) {
|
|
53
|
+
if (labelEl.textContent === label)
|
|
54
|
+
return;
|
|
55
|
+
labelEl.textContent = label;
|
|
56
|
+
el.setAttribute('aria-label', label);
|
|
57
|
+
},
|
|
58
|
+
remove() {
|
|
59
|
+
handle.remove();
|
|
60
|
+
el.remove();
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/** The signed difference `bearing − heading`, wrapped to −180..180. */
|
|
65
|
+
export function bearingOffset(bearingDeg, headingDeg) {
|
|
66
|
+
const d = wrapDegrees(bearingDeg - headingDeg);
|
|
67
|
+
return d > 180 ? d - 360 : d;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* A compass strip: the cardinal ticks scroll under a centre mark as the heading turns, and each
|
|
71
|
+
* marker sits at its bearing's distance from the heading (`width / (2 × fov)` px per degree),
|
|
72
|
+
* hidden once it leaves the strip. `role="img"` labelled with the heading.
|
|
73
|
+
*/
|
|
74
|
+
export function createCompass(host, opts = {}) {
|
|
75
|
+
ensureWidgets3Styles(host.layers.hud.ownerDocument);
|
|
76
|
+
const width = opts.width ?? 480;
|
|
77
|
+
const fov = opts.fov ?? 180;
|
|
78
|
+
const labels = opts.labels ?? ['N', 'E', 'S', 'W'];
|
|
79
|
+
const ppd = width / (2 * fov);
|
|
80
|
+
const half = width / 2;
|
|
81
|
+
const strip = h('div', { class: 'tc-compass-strip', 'aria-hidden': 'true' });
|
|
82
|
+
// Ticks from −180 to 540 so the strip is covered at any heading (its offset is in 0..360).
|
|
83
|
+
for (let deg = -180; deg <= 540; deg += 15) {
|
|
84
|
+
const major = deg % 90 === 0;
|
|
85
|
+
strip.append(h('span', {
|
|
86
|
+
class: 'tc-compass-tick',
|
|
87
|
+
'data-major': major,
|
|
88
|
+
style: { left: themePx(deg * ppd) },
|
|
89
|
+
}));
|
|
90
|
+
if (major) {
|
|
91
|
+
strip.append(h('span', { class: 'tc-compass-label', style: { left: themePx(deg * ppd) } }, labels[wrapDegrees(deg) / 90] ?? ''));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const markerLayer = h('div', { class: 'tc-compass-markers', 'aria-hidden': 'true' });
|
|
95
|
+
const el = h('div', {
|
|
96
|
+
class: 'tc-compass',
|
|
97
|
+
role: 'img',
|
|
98
|
+
'aria-label': 'Compass',
|
|
99
|
+
style: { '--tc-compass-width': themePx(width) },
|
|
100
|
+
}, strip, markerLayer, h('span', { class: 'tc-compass-mark', 'aria-hidden': 'true' }));
|
|
101
|
+
const nodes = [];
|
|
102
|
+
let heading = Number.NaN;
|
|
103
|
+
let stripOffset = Number.NaN;
|
|
104
|
+
const placeMarker = (n) => {
|
|
105
|
+
const off = bearingOffset(n.marker.bearingDeg, heading) * ppd;
|
|
106
|
+
const shown = Math.abs(off) <= half;
|
|
107
|
+
if (shown !== n.shown) {
|
|
108
|
+
n.shown = shown;
|
|
109
|
+
n.el.hidden = !shown;
|
|
110
|
+
}
|
|
111
|
+
if (!shown || off === n.offset)
|
|
112
|
+
return;
|
|
113
|
+
n.offset = off;
|
|
114
|
+
n.el.style.transform = `translate3d(${themePx(off)}, 0, 0) translateX(-50%)`;
|
|
115
|
+
};
|
|
116
|
+
const setHeading = (deg) => {
|
|
117
|
+
const next = wrapDegrees(deg);
|
|
118
|
+
if (next === heading)
|
|
119
|
+
return;
|
|
120
|
+
heading = next;
|
|
121
|
+
// The strip's 0° tick sits `heading` degrees left of the centre.
|
|
122
|
+
const off = half - next * ppd;
|
|
123
|
+
if (off !== stripOffset) {
|
|
124
|
+
stripOffset = off;
|
|
125
|
+
strip.style.transform = `translate3d(${themePx(off)}, 0, 0)`;
|
|
126
|
+
}
|
|
127
|
+
el.setAttribute('aria-label', `Compass ${Math.round(next)}°`);
|
|
128
|
+
for (const n of nodes)
|
|
129
|
+
placeMarker(n);
|
|
130
|
+
};
|
|
131
|
+
const setMarkers = (markers) => {
|
|
132
|
+
for (let i = 0; i < markers.length; i++) {
|
|
133
|
+
const m = markers[i];
|
|
134
|
+
let n = nodes[i];
|
|
135
|
+
if (!n) {
|
|
136
|
+
const node = h('span', { class: 'tc-compass-marker', hidden: true });
|
|
137
|
+
markerLayer.append(node);
|
|
138
|
+
n = { el: node, marker: m, offset: Number.NaN, shown: false };
|
|
139
|
+
nodes.push(n);
|
|
140
|
+
}
|
|
141
|
+
n.marker = m;
|
|
142
|
+
n.el.textContent = m.icon ?? m.name.charAt(0);
|
|
143
|
+
n.el.dataset.name = m.name;
|
|
144
|
+
n.offset = Number.NaN;
|
|
145
|
+
placeMarker(n);
|
|
146
|
+
}
|
|
147
|
+
while (nodes.length > markers.length)
|
|
148
|
+
nodes.pop().el.remove();
|
|
149
|
+
};
|
|
150
|
+
setHeading(opts.headingDeg ?? 0);
|
|
151
|
+
setMarkers(opts.markers ?? []);
|
|
152
|
+
const handle = host.layout.add(el, {
|
|
153
|
+
place: { default: opts.region ?? 'top' },
|
|
154
|
+
order: opts.order,
|
|
155
|
+
});
|
|
156
|
+
return {
|
|
157
|
+
el,
|
|
158
|
+
get heading() {
|
|
159
|
+
return heading;
|
|
160
|
+
},
|
|
161
|
+
setHeading,
|
|
162
|
+
setMarkers,
|
|
163
|
+
offsetOf(name) {
|
|
164
|
+
const n = nodes.find((x) => x.marker.name === name);
|
|
165
|
+
return n ? bearingOffset(n.marker.bearingDeg, heading) * ppd : null;
|
|
166
|
+
},
|
|
167
|
+
remove() {
|
|
168
|
+
handle.remove();
|
|
169
|
+
el.remove();
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
// ------------------------------------------------------------------ styles
|
|
174
|
+
/**
|
|
175
|
+
* Stylesheet for these widgets (theme tokens).
|
|
176
|
+
*/
|
|
177
|
+
export const WIDGETS3_CSS = `
|
|
178
|
+
.tc-overlay .tc-ring { position: relative; display: grid; place-items: center; width: var(--tc-ring-size); height: var(--tc-ring-size);
|
|
179
|
+
font-family: var(--tc-font-ui); font-size: var(--tc-font-size-s); color: var(--tc-color-text); }
|
|
180
|
+
.tc-overlay .tc-ring-fill { position: absolute; inset: 0; border-radius: 50%; --tc-ring-value: 0;
|
|
181
|
+
background: conic-gradient(var(--tc-ring-color, var(--tc-color-accent)) calc(var(--tc-ring-value) * 360deg), var(--tc-color-border) 0);
|
|
182
|
+
-webkit-mask: radial-gradient(farthest-side, transparent calc(100% - var(--tc-ring-thickness) - 0.5px), #000 calc(100% - var(--tc-ring-thickness) + 0.5px));
|
|
183
|
+
mask: radial-gradient(farthest-side, transparent calc(100% - var(--tc-ring-thickness) - 0.5px), #000 calc(100% - var(--tc-ring-thickness) + 0.5px)); }
|
|
184
|
+
.tc-overlay .tc-ring-label { position: relative; font-weight: 600; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.7); }
|
|
185
|
+
|
|
186
|
+
.tc-overlay .tc-compass { position: relative; width: var(--tc-compass-width, ${themePx(480)}); height: var(--tc-space-6); overflow: hidden;
|
|
187
|
+
font-family: var(--tc-font-ui); font-size: var(--tc-font-size-s); color: var(--tc-color-text-muted);
|
|
188
|
+
-webkit-mask: linear-gradient(90deg, transparent, #000 15%, #000 85%, transparent);
|
|
189
|
+
mask: linear-gradient(90deg, transparent, #000 15%, #000 85%, transparent); }
|
|
190
|
+
.tc-overlay .tc-compass-strip, .tc-overlay .tc-compass-markers { position: absolute; left: 0; top: 0; height: 100%; will-change: transform; }
|
|
191
|
+
.tc-overlay .tc-compass-markers { left: 50%; }
|
|
192
|
+
.tc-overlay .tc-compass-tick { position: absolute; bottom: 0; width: var(--tc-border-width); height: var(--tc-space-2);
|
|
193
|
+
background: var(--tc-color-text-muted); transform: translateX(-50%); }
|
|
194
|
+
.tc-overlay .tc-compass-tick[data-major] { height: var(--tc-space-3); background: var(--tc-color-text); }
|
|
195
|
+
.tc-overlay .tc-compass-label { position: absolute; top: 0; transform: translateX(-50%); line-height: 1.2; font-weight: 600; letter-spacing: 0.08em; }
|
|
196
|
+
.tc-overlay .tc-compass-marker { position: absolute; top: 0; bottom: var(--tc-space-3); display: grid; place-items: center; min-width: var(--tc-space-4);
|
|
197
|
+
padding: 0 var(--tc-space-1); border-radius: var(--tc-radius-s); background: var(--tc-color-accent); color: var(--tc-color-accent-text);
|
|
198
|
+
font-weight: 700; line-height: 1; will-change: transform; }
|
|
199
|
+
.tc-overlay .tc-compass-marker[hidden] { display: none; }
|
|
200
|
+
.tc-overlay .tc-compass-mark { position: absolute; left: 50%; top: 0; bottom: 0; width: var(--tc-border-width); transform: translateX(-50%);
|
|
201
|
+
background: var(--tc-color-accent); }
|
|
202
|
+
`;
|
|
203
|
+
const STYLE_ID = 'tc-ui-widgets-3';
|
|
204
|
+
/** Add `WIDGETS3_CSS` to `doc` once (the first ring or compass does it). */
|
|
205
|
+
export function ensureWidgets3Styles(doc = document) {
|
|
206
|
+
if (doc.getElementById(STYLE_ID))
|
|
207
|
+
return;
|
|
208
|
+
const style = doc.createElement('style');
|
|
209
|
+
style.id = STYLE_ID;
|
|
210
|
+
style.textContent = WIDGETS3_CSS;
|
|
211
|
+
doc.head.appendChild(style);
|
|
212
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export interface ButtonOptions {
|
|
2
|
+
variant?: 'default' | 'primary' | 'ghost';
|
|
3
|
+
disabled?: boolean;
|
|
4
|
+
/** Accessible name when the label is an icon. */
|
|
5
|
+
ariaLabel?: string;
|
|
6
|
+
className?: string;
|
|
7
|
+
/**
|
|
8
|
+
* The button's stable id (ws/input-12; `data-tc-id`, `CONTROL_ID_ATTR`): what a recording
|
|
9
|
+
* stores when it fires and what `Overlay.activate` finds it by on replay. Omitted, the id is
|
|
10
|
+
* derived from its page and label (`controlId`); give one when the label is translated or
|
|
11
|
+
* not unique on its page.
|
|
12
|
+
*/
|
|
13
|
+
id?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function button(label: string | Node, onClick: (e: MouseEvent) => void, opts?: ButtonOptions): HTMLButtonElement;
|
|
16
|
+
export interface SliderOptions {
|
|
17
|
+
min?: number;
|
|
18
|
+
max?: number;
|
|
19
|
+
step?: number;
|
|
20
|
+
/** Format the value for `aria-valuetext` (e.g. `v => Math.round(v*100)+'%'`). */
|
|
21
|
+
format?: (v: number) => string;
|
|
22
|
+
}
|
|
23
|
+
/** Labelled range input. `onInput` fires continuously while dragging. */
|
|
24
|
+
export declare function slider(label: string, value: number, onInput: (v: number) => void, opts?: SliderOptions): {
|
|
25
|
+
element: HTMLLabelElement;
|
|
26
|
+
input: HTMLInputElement;
|
|
27
|
+
set(v: number): void;
|
|
28
|
+
};
|
|
29
|
+
/** Labelled checkbox. */
|
|
30
|
+
export declare function toggle(label: string, checked: boolean, onChange: (v: boolean) => void): {
|
|
31
|
+
element: HTMLLabelElement;
|
|
32
|
+
input: HTMLInputElement;
|
|
33
|
+
set(v: boolean): void;
|
|
34
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { h } from './dom.js';
|
|
2
|
+
export function button(label, onClick, opts = {}) {
|
|
3
|
+
return h('button', {
|
|
4
|
+
type: 'button',
|
|
5
|
+
class: ['tc-button', opts.className ?? ''].join(' ').trim(),
|
|
6
|
+
dataset: { variant: opts.variant ?? 'default' },
|
|
7
|
+
disabled: opts.disabled ?? false,
|
|
8
|
+
'aria-label': opts.ariaLabel,
|
|
9
|
+
'data-tc-id': opts.id,
|
|
10
|
+
on: { click: onClick },
|
|
11
|
+
}, label);
|
|
12
|
+
}
|
|
13
|
+
/** Labelled range input. `onInput` fires continuously while dragging. */
|
|
14
|
+
export function slider(label, value, onInput, opts = {}) {
|
|
15
|
+
const { min = 0, max = 1, step = 0.01, format } = opts;
|
|
16
|
+
const input = h('input', { type: 'range', min, max, step });
|
|
17
|
+
const setText = () => {
|
|
18
|
+
if (format)
|
|
19
|
+
input.setAttribute('aria-valuetext', format(Number(input.value)));
|
|
20
|
+
};
|
|
21
|
+
input.value = String(value);
|
|
22
|
+
setText();
|
|
23
|
+
input.addEventListener('input', () => {
|
|
24
|
+
setText();
|
|
25
|
+
onInput(Number(input.value));
|
|
26
|
+
});
|
|
27
|
+
const element = h('label', { class: 'tc-field' }, h('span', null, label), input);
|
|
28
|
+
return {
|
|
29
|
+
element,
|
|
30
|
+
input,
|
|
31
|
+
set(v) {
|
|
32
|
+
input.value = String(v);
|
|
33
|
+
setText();
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/** Labelled checkbox. */
|
|
38
|
+
export function toggle(label, checked, onChange) {
|
|
39
|
+
const input = h('input', { type: 'checkbox' });
|
|
40
|
+
input.checked = checked;
|
|
41
|
+
input.addEventListener('change', () => onChange(input.checked));
|
|
42
|
+
const element = h('label', { class: 'tc-field' }, input, h('span', null, label));
|
|
43
|
+
return {
|
|
44
|
+
element,
|
|
45
|
+
input,
|
|
46
|
+
set(v) {
|
|
47
|
+
input.checked = v;
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { type FlowItem, type FlowOptions, flowLayout, type PanelRect } from './layout.js';
|
|
2
|
+
export { makePanelCanvas, Painter, type PanelCanvas, type PanelContext2D, type PanelTheme, resolvePanelTheme, } from './paint.js';
|
|
3
|
+
export { createWorldPanel, WorldPanel, type WorldPanelHit, type WorldPanelInput, type WorldPanelOptions, type WorldPanelStats, worldPanelTarget, } from './panel.js';
|
|
4
|
+
export { WORLD_PANEL_WGSL } from './wgsl.js';
|
|
5
|
+
export { button as worldButton, label as worldLabel, list as worldList, type PanelKeyEvent, progress as worldProgress, slider as worldSlider, toggle as worldToggle, WorldButton, type WorldButtonOptions, WorldLabel, type WorldLabelOptions, WorldList, type WorldListOptions, WorldProgress, type WorldProgressOptions, WorldSlider, type WorldSliderOptions, WorldToggle, type WorldToggleOptions, WorldWidget, type WorldWidgetAlign, type WorldWidgetHost, type WorldWidgetSize, type WorldWidgetTone, } from './widgets.js';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { flowLayout } from './layout.js';
|
|
2
|
+
export { makePanelCanvas, Painter, resolvePanelTheme, } from './paint.js';
|
|
3
|
+
export { createWorldPanel, WorldPanel, worldPanelTarget, } from './panel.js';
|
|
4
|
+
export { WORLD_PANEL_WGSL } from './wgsl.js';
|
|
5
|
+
export { button as worldButton, label as worldLabel, list as worldList, progress as worldProgress, slider as worldSlider, toggle as worldToggle, WorldButton, WorldLabel, WorldList, WorldProgress, WorldSlider, WorldToggle, WorldWidget, } from './widgets.js';
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* World-panel layout: a vertical flow in panel px. Each widget is given the full inner width and
|
|
3
|
+
* the height it asks for; a widget with an explicit `rect` is placed there and skipped by the
|
|
4
|
+
* flow. Pure arithmetic, so it is tested without a canvas.
|
|
5
|
+
*/
|
|
6
|
+
/** A rect in panel px, from the top-left. */
|
|
7
|
+
export interface PanelRect {
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
w: number;
|
|
11
|
+
h: number;
|
|
12
|
+
}
|
|
13
|
+
/** What the flow needs from a widget. */
|
|
14
|
+
export interface FlowItem {
|
|
15
|
+
/** An explicit place; the flow leaves it alone. */
|
|
16
|
+
rect: PanelRect | null;
|
|
17
|
+
/** The height wanted for `width` px. */
|
|
18
|
+
measure(width: number): number;
|
|
19
|
+
/** The rect the layout assigned (written by `flowLayout`). */
|
|
20
|
+
readonly layoutRect: PanelRect;
|
|
21
|
+
}
|
|
22
|
+
export interface FlowOptions {
|
|
23
|
+
width: number;
|
|
24
|
+
padding: number;
|
|
25
|
+
gap: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Lay `items` out top to bottom inside `width` with `padding` on every side and `gap` between
|
|
29
|
+
* rows. Writes each item's `layoutRect` in place and returns the content height used (padding
|
|
30
|
+
* included), so nothing is allocated.
|
|
31
|
+
*/
|
|
32
|
+
export declare function flowLayout(items: readonly FlowItem[], opts: FlowOptions): number;
|
|
33
|
+
/** Whether the panel px point lies in `r`. */
|
|
34
|
+
export declare function rectContains(r: PanelRect, x: number, y: number): boolean;
|
|
35
|
+
/** Grow `acc` to include `r`; an empty `acc` (w or h ≤ 0) becomes `r`. */
|
|
36
|
+
export declare function rectUnion(acc: PanelRect, r: PanelRect): void;
|
|
37
|
+
/** Clamp `r` to `[0, w) × [0, h)` and snap it outward to whole px. */
|
|
38
|
+
export declare function rectClampSnap(r: PanelRect, w: number, h: number): void;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* World-panel layout: a vertical flow in panel px. Each widget is given the full inner width and
|
|
3
|
+
* the height it asks for; a widget with an explicit `rect` is placed there and skipped by the
|
|
4
|
+
* flow. Pure arithmetic, so it is tested without a canvas.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Lay `items` out top to bottom inside `width` with `padding` on every side and `gap` between
|
|
8
|
+
* rows. Writes each item's `layoutRect` in place and returns the content height used (padding
|
|
9
|
+
* included), so nothing is allocated.
|
|
10
|
+
*/
|
|
11
|
+
export function flowLayout(items, opts) {
|
|
12
|
+
const inner = Math.max(0, opts.width - opts.padding * 2);
|
|
13
|
+
let y = opts.padding;
|
|
14
|
+
let first = true;
|
|
15
|
+
for (const item of items) {
|
|
16
|
+
const r = item.layoutRect;
|
|
17
|
+
if (item.rect) {
|
|
18
|
+
r.x = item.rect.x;
|
|
19
|
+
r.y = item.rect.y;
|
|
20
|
+
r.w = item.rect.w;
|
|
21
|
+
r.h = item.rect.h;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (!first)
|
|
25
|
+
y += opts.gap;
|
|
26
|
+
first = false;
|
|
27
|
+
const h = Math.max(0, Math.round(item.measure(inner)));
|
|
28
|
+
r.x = opts.padding;
|
|
29
|
+
r.y = y;
|
|
30
|
+
r.w = inner;
|
|
31
|
+
r.h = h;
|
|
32
|
+
y += h;
|
|
33
|
+
}
|
|
34
|
+
return y + opts.padding;
|
|
35
|
+
}
|
|
36
|
+
/** Whether the panel px point lies in `r`. */
|
|
37
|
+
export function rectContains(r, x, y) {
|
|
38
|
+
return x >= r.x && y >= r.y && x < r.x + r.w && y < r.y + r.h;
|
|
39
|
+
}
|
|
40
|
+
/** Grow `acc` to include `r`; an empty `acc` (w or h ≤ 0) becomes `r`. */
|
|
41
|
+
export function rectUnion(acc, r) {
|
|
42
|
+
if (acc.w <= 0 || acc.h <= 0) {
|
|
43
|
+
acc.x = r.x;
|
|
44
|
+
acc.y = r.y;
|
|
45
|
+
acc.w = r.w;
|
|
46
|
+
acc.h = r.h;
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const x0 = Math.min(acc.x, r.x);
|
|
50
|
+
const y0 = Math.min(acc.y, r.y);
|
|
51
|
+
const x1 = Math.max(acc.x + acc.w, r.x + r.w);
|
|
52
|
+
const y1 = Math.max(acc.y + acc.h, r.y + r.h);
|
|
53
|
+
acc.x = x0;
|
|
54
|
+
acc.y = y0;
|
|
55
|
+
acc.w = x1 - x0;
|
|
56
|
+
acc.h = y1 - y0;
|
|
57
|
+
}
|
|
58
|
+
/** Clamp `r` to `[0, w) × [0, h)` and snap it outward to whole px. */
|
|
59
|
+
export function rectClampSnap(r, w, h) {
|
|
60
|
+
const x0 = Math.max(0, Math.floor(r.x));
|
|
61
|
+
const y0 = Math.max(0, Math.floor(r.y));
|
|
62
|
+
const x1 = Math.min(w, Math.ceil(r.x + r.w));
|
|
63
|
+
const y1 = Math.min(h, Math.ceil(r.y + r.h));
|
|
64
|
+
r.x = x0;
|
|
65
|
+
r.y = y0;
|
|
66
|
+
r.w = Math.max(0, x1 - x0);
|
|
67
|
+
r.h = Math.max(0, y1 - y0);
|
|
68
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* World-panel painting: a Canvas2D the panel texture is uploaded from, the theme read by value
|
|
3
|
+
* from `theme.ts`, and the small set of drawing helpers the widgets share. The canvas is
|
|
4
|
+
* injectable (`PanelCanvas`) so tests paint into a stub; `makePanelCanvas` picks `OffscreenCanvas`,
|
|
5
|
+
* then `document.createElement('canvas')`.
|
|
6
|
+
*/
|
|
7
|
+
import { type ThemeTokens } from '../theme.js';
|
|
8
|
+
import type { PanelRect } from './layout.js';
|
|
9
|
+
/** The Canvas2D subset the panel paints with (a `CanvasRenderingContext2D` satisfies it). */
|
|
10
|
+
export interface PanelContext2D {
|
|
11
|
+
font: string;
|
|
12
|
+
textAlign: CanvasTextAlign;
|
|
13
|
+
textBaseline: CanvasTextBaseline;
|
|
14
|
+
fillStyle: string | CanvasGradient | CanvasPattern;
|
|
15
|
+
strokeStyle: string | CanvasGradient | CanvasPattern;
|
|
16
|
+
lineWidth: number;
|
|
17
|
+
globalAlpha: number;
|
|
18
|
+
save(): void;
|
|
19
|
+
restore(): void;
|
|
20
|
+
beginPath(): void;
|
|
21
|
+
closePath(): void;
|
|
22
|
+
rect(x: number, y: number, w: number, h: number): void;
|
|
23
|
+
moveTo(x: number, y: number): void;
|
|
24
|
+
lineTo(x: number, y: number): void;
|
|
25
|
+
arcTo(x1: number, y1: number, x2: number, y2: number, r: number): void;
|
|
26
|
+
arc(x: number, y: number, r: number, a0: number, a1: number): void;
|
|
27
|
+
fill(): void;
|
|
28
|
+
stroke(): void;
|
|
29
|
+
clip(): void;
|
|
30
|
+
clearRect(x: number, y: number, w: number, h: number): void;
|
|
31
|
+
fillRect(x: number, y: number, w: number, h: number): void;
|
|
32
|
+
fillText(text: string, x: number, y: number): void;
|
|
33
|
+
measureText(text: string): {
|
|
34
|
+
width: number;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/** A canvas the panel owns: `width`/`height` in px and a 2D context. */
|
|
38
|
+
export interface PanelCanvas {
|
|
39
|
+
readonly width: number;
|
|
40
|
+
readonly height: number;
|
|
41
|
+
getContext(kind: '2d', opts?: {
|
|
42
|
+
alpha?: boolean;
|
|
43
|
+
}): PanelContext2D | null;
|
|
44
|
+
}
|
|
45
|
+
/** `OffscreenCanvas`, else a `<canvas>`; throws where neither exists. */
|
|
46
|
+
export declare function makePanelCanvas(width: number, height: number): PanelCanvas;
|
|
47
|
+
/** Theme tokens as numbers and strings the painter reads each paint. */
|
|
48
|
+
export interface PanelTheme {
|
|
49
|
+
tokens: ThemeTokens;
|
|
50
|
+
font: string;
|
|
51
|
+
fontSizeS: number;
|
|
52
|
+
fontSizeM: number;
|
|
53
|
+
fontSizeL: number;
|
|
54
|
+
space1: number;
|
|
55
|
+
space2: number;
|
|
56
|
+
space3: number;
|
|
57
|
+
space4: number;
|
|
58
|
+
radiusS: number;
|
|
59
|
+
radiusM: number;
|
|
60
|
+
borderWidth: number;
|
|
61
|
+
focusRing: number;
|
|
62
|
+
}
|
|
63
|
+
/** `'12px'` → 12 (any other unit or junk → `fallback`). */
|
|
64
|
+
export declare function tokenPx(value: string | undefined, fallback: number): number;
|
|
65
|
+
/**
|
|
66
|
+
* The panel's theme: `cssPxTheme` (the design tokens at CSS px, so a 256 px/unit panel reads at
|
|
67
|
+
* arm's length) under `overrides`. Every value is read once here; widgets paint from the result.
|
|
68
|
+
*/
|
|
69
|
+
export declare function resolvePanelTheme(overrides?: Partial<ThemeTokens>): PanelTheme;
|
|
70
|
+
/** Trace a rounded rect path (`r` clamped to half the shorter side). */
|
|
71
|
+
export declare function roundRectPath(ctx: PanelContext2D, x: number, y: number, w: number, h: number, r: number): void;
|
|
72
|
+
/**
|
|
73
|
+
* The painter the widgets draw through: the context, the theme and a text-width cache keyed by
|
|
74
|
+
* font and string (cleared when the font loads).
|
|
75
|
+
*/
|
|
76
|
+
export declare class Painter {
|
|
77
|
+
readonly ctx: PanelContext2D;
|
|
78
|
+
readonly theme: PanelTheme;
|
|
79
|
+
private readonly widths;
|
|
80
|
+
constructor(ctx: PanelContext2D, theme: PanelTheme);
|
|
81
|
+
/** `size`px of the theme font as a CSS font string. */
|
|
82
|
+
font(size: number, weight?: number): string;
|
|
83
|
+
/** Text width in px for `font`, measured once per (font, text). */
|
|
84
|
+
measure(text: string, font: string): number;
|
|
85
|
+
/** Drop every cached width (after the font loaded). */
|
|
86
|
+
clearMeasures(): void;
|
|
87
|
+
fillRoundRect(r: PanelRect, radius: number, fill: string): void;
|
|
88
|
+
strokeRoundRect(r: PanelRect, radius: number, stroke: string, width: number): void;
|
|
89
|
+
/** The focus ring: a stroke of `focusRing` px just outside `r`. */
|
|
90
|
+
focusRing(r: PanelRect, radius: number): void;
|
|
91
|
+
/**
|
|
92
|
+
* One line of `text` at `size`px, clipped to `r`, `align`ed inside it with `padX` px of inset
|
|
93
|
+
* and vertically centred.
|
|
94
|
+
*/
|
|
95
|
+
text(text: string, r: PanelRect, size: number, color: string, align?: 'left' | 'center' | 'right', padX?: number, weight?: number): void;
|
|
96
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* World-panel painting: a Canvas2D the panel texture is uploaded from, the theme read by value
|
|
3
|
+
* from `theme.ts`, and the small set of drawing helpers the widgets share. The canvas is
|
|
4
|
+
* injectable (`PanelCanvas`) so tests paint into a stub; `makePanelCanvas` picks `OffscreenCanvas`,
|
|
5
|
+
* then `document.createElement('canvas')`.
|
|
6
|
+
*/
|
|
7
|
+
import { cssPxTheme, defaultTheme } from '../theme.js';
|
|
8
|
+
/** `OffscreenCanvas`, else a `<canvas>`; throws where neither exists. */
|
|
9
|
+
export function makePanelCanvas(width, height) {
|
|
10
|
+
if (typeof OffscreenCanvas !== 'undefined') {
|
|
11
|
+
return new OffscreenCanvas(width, height);
|
|
12
|
+
}
|
|
13
|
+
if (typeof document !== 'undefined') {
|
|
14
|
+
const c = document.createElement('canvas');
|
|
15
|
+
c.width = width;
|
|
16
|
+
c.height = height;
|
|
17
|
+
return c;
|
|
18
|
+
}
|
|
19
|
+
throw new Error('world panel: no OffscreenCanvas or document to make a canvas');
|
|
20
|
+
}
|
|
21
|
+
/** `'12px'` → 12 (any other unit or junk → `fallback`). */
|
|
22
|
+
export function tokenPx(value, fallback) {
|
|
23
|
+
if (value === undefined)
|
|
24
|
+
return fallback;
|
|
25
|
+
const n = Number.parseFloat(value);
|
|
26
|
+
return Number.isFinite(n) ? n : fallback;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The panel's theme: `cssPxTheme` (the design tokens at CSS px, so a 256 px/unit panel reads at
|
|
30
|
+
* arm's length) under `overrides`. Every value is read once here; widgets paint from the result.
|
|
31
|
+
*/
|
|
32
|
+
export function resolvePanelTheme(overrides) {
|
|
33
|
+
const tokens = { ...defaultTheme, ...cssPxTheme, ...overrides };
|
|
34
|
+
return {
|
|
35
|
+
tokens,
|
|
36
|
+
font: tokens.fontUi,
|
|
37
|
+
fontSizeS: tokenPx(tokens.fontSizeS, 14),
|
|
38
|
+
fontSizeM: tokenPx(tokens.fontSizeM, 16),
|
|
39
|
+
fontSizeL: tokenPx(tokens.fontSizeL, 20),
|
|
40
|
+
space1: tokenPx(tokens.space1, 2),
|
|
41
|
+
space2: tokenPx(tokens.space2, 4),
|
|
42
|
+
space3: tokenPx(tokens.space3, 8),
|
|
43
|
+
space4: tokenPx(tokens.space4, 12),
|
|
44
|
+
radiusS: tokenPx(tokens.radiusS, 4),
|
|
45
|
+
radiusM: tokenPx(tokens.radiusM, 8),
|
|
46
|
+
borderWidth: tokenPx(tokens.borderWidth, 1),
|
|
47
|
+
focusRing: tokenPx(tokens.focusRing, 2),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/** Trace a rounded rect path (`r` clamped to half the shorter side). */
|
|
51
|
+
export function roundRectPath(ctx, x, y, w, h, r) {
|
|
52
|
+
const rr = Math.max(0, Math.min(r, w / 2, h / 2));
|
|
53
|
+
ctx.beginPath();
|
|
54
|
+
ctx.moveTo(x + rr, y);
|
|
55
|
+
ctx.arcTo(x + w, y, x + w, y + h, rr);
|
|
56
|
+
ctx.arcTo(x + w, y + h, x, y + h, rr);
|
|
57
|
+
ctx.arcTo(x, y + h, x, y, rr);
|
|
58
|
+
ctx.arcTo(x, y, x + w, y, rr);
|
|
59
|
+
ctx.closePath();
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The painter the widgets draw through: the context, the theme and a text-width cache keyed by
|
|
63
|
+
* font and string (cleared when the font loads).
|
|
64
|
+
*/
|
|
65
|
+
export class Painter {
|
|
66
|
+
ctx;
|
|
67
|
+
theme;
|
|
68
|
+
widths = new Map();
|
|
69
|
+
constructor(ctx, theme) {
|
|
70
|
+
this.ctx = ctx;
|
|
71
|
+
this.theme = theme;
|
|
72
|
+
}
|
|
73
|
+
/** `size`px of the theme font as a CSS font string. */
|
|
74
|
+
font(size, weight = 500) {
|
|
75
|
+
return `${weight} ${size}px ${this.theme.font}`;
|
|
76
|
+
}
|
|
77
|
+
/** Text width in px for `font`, measured once per (font, text). */
|
|
78
|
+
measure(text, font) {
|
|
79
|
+
const key = `${font}\u0000${text}`;
|
|
80
|
+
let w = this.widths.get(key);
|
|
81
|
+
if (w === undefined) {
|
|
82
|
+
this.ctx.font = font;
|
|
83
|
+
w = this.ctx.measureText(text).width;
|
|
84
|
+
this.widths.set(key, w);
|
|
85
|
+
}
|
|
86
|
+
return w;
|
|
87
|
+
}
|
|
88
|
+
/** Drop every cached width (after the font loaded). */
|
|
89
|
+
clearMeasures() {
|
|
90
|
+
this.widths.clear();
|
|
91
|
+
}
|
|
92
|
+
fillRoundRect(r, radius, fill) {
|
|
93
|
+
const ctx = this.ctx;
|
|
94
|
+
roundRectPath(ctx, r.x, r.y, r.w, r.h, radius);
|
|
95
|
+
ctx.fillStyle = fill;
|
|
96
|
+
ctx.fill();
|
|
97
|
+
}
|
|
98
|
+
strokeRoundRect(r, radius, stroke, width) {
|
|
99
|
+
const ctx = this.ctx;
|
|
100
|
+
const half = width / 2;
|
|
101
|
+
roundRectPath(ctx, r.x + half, r.y + half, r.w - width, r.h - width, Math.max(0, radius - half));
|
|
102
|
+
ctx.strokeStyle = stroke;
|
|
103
|
+
ctx.lineWidth = width;
|
|
104
|
+
ctx.stroke();
|
|
105
|
+
}
|
|
106
|
+
/** The focus ring: a stroke of `focusRing` px just outside `r`. */
|
|
107
|
+
focusRing(r, radius) {
|
|
108
|
+
const t = this.theme;
|
|
109
|
+
const w = t.focusRing;
|
|
110
|
+
const ctx = this.ctx;
|
|
111
|
+
roundRectPath(ctx, r.x - w / 2, r.y - w / 2, r.w + w, r.h + w, radius + w / 2);
|
|
112
|
+
ctx.strokeStyle = t.tokens.colorFocus;
|
|
113
|
+
ctx.lineWidth = w;
|
|
114
|
+
ctx.stroke();
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* One line of `text` at `size`px, clipped to `r`, `align`ed inside it with `padX` px of inset
|
|
118
|
+
* and vertically centred.
|
|
119
|
+
*/
|
|
120
|
+
text(text, r, size, color, align = 'left', padX = 0, weight = 500) {
|
|
121
|
+
if (text.length === 0 || r.w <= 0 || r.h <= 0)
|
|
122
|
+
return;
|
|
123
|
+
const ctx = this.ctx;
|
|
124
|
+
ctx.save();
|
|
125
|
+
ctx.beginPath();
|
|
126
|
+
ctx.rect(r.x, r.y, r.w, r.h);
|
|
127
|
+
ctx.clip();
|
|
128
|
+
ctx.font = this.font(size, weight);
|
|
129
|
+
ctx.fillStyle = color;
|
|
130
|
+
ctx.textBaseline = 'middle';
|
|
131
|
+
ctx.textAlign = align;
|
|
132
|
+
const x = align === 'left' ? r.x + padX : align === 'right' ? r.x + r.w - padX : r.x + r.w / 2;
|
|
133
|
+
ctx.fillText(text, x, r.y + r.h / 2);
|
|
134
|
+
ctx.restore();
|
|
135
|
+
}
|
|
136
|
+
}
|