@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,40 @@
|
|
|
1
|
+
/** Default `phoneScale`: below this overlay scale the screen is phone-sized. Phones are 0.33–0.40, tablets 0.53+. */
|
|
2
|
+
export declare const PHONE_SCALE = 0.45;
|
|
3
|
+
export interface DeviceModeOptions {
|
|
4
|
+
/** Overlay scale (CSS px per design px) under which the screen counts as a phone. Default 0.45. */
|
|
5
|
+
phoneScale?: number;
|
|
6
|
+
}
|
|
7
|
+
export interface DeviceMode {
|
|
8
|
+
/** A phone-sized screen (see `DeviceModeOptions.phoneScale`). */
|
|
9
|
+
readonly phone: boolean;
|
|
10
|
+
/** The last input was touch. */
|
|
11
|
+
readonly touch: boolean;
|
|
12
|
+
/** Design px per CSS px (1 / overlay scale). */
|
|
13
|
+
readonly cssPx: number;
|
|
14
|
+
/** Width of each letterbox bar beside the canvas, design px (0 when it fills the width). */
|
|
15
|
+
readonly bar: number;
|
|
16
|
+
/**
|
|
17
|
+
* Design px cut off the top and bottom of the canvas when a phone fills the width (0
|
|
18
|
+
* otherwise): the visible band is `[cropT, designHeight - cropB]`.
|
|
19
|
+
*/
|
|
20
|
+
readonly cropT: number;
|
|
21
|
+
readonly cropB: number;
|
|
22
|
+
onChange(fn: () => void): () => void;
|
|
23
|
+
}
|
|
24
|
+
/** See `DeviceModeController.setScale`. */
|
|
25
|
+
export interface CropInfo {
|
|
26
|
+
readonly fitScale: number;
|
|
27
|
+
readonly top: number;
|
|
28
|
+
readonly bottom: number;
|
|
29
|
+
}
|
|
30
|
+
export interface DeviceModeController extends DeviceMode {
|
|
31
|
+
/**
|
|
32
|
+
* Call on every resize with the overlay scale. `barCss`: the letterbox bar each side of the
|
|
33
|
+
* canvas, CSS px. `crop` (a scene that fills the width on a phone): the contain fit's scale,
|
|
34
|
+
* which decides phone-ness so filling never flips the mode, and the CSS px cut off the top
|
|
35
|
+
* and bottom of the canvas.
|
|
36
|
+
*/
|
|
37
|
+
setScale(scale: number, barCss?: number, crop?: CropInfo): void;
|
|
38
|
+
destroy(): void;
|
|
39
|
+
}
|
|
40
|
+
export declare function createDeviceMode(root: HTMLElement, opts?: DeviceModeOptions): DeviceModeController;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phone and touch modes for a scaled overlay (interim API: Phase 2's layout regions retire it,
|
|
3
|
+
* D-041). Flags and density tokens on the overlay root, recomputed live:
|
|
4
|
+
*
|
|
5
|
+
* - `data-phone`: the design canvas is shown so small (under `phoneScale` CSS px per design px,
|
|
6
|
+
* i.e. a phone in landscape) that design-sized text and buttons would be unreadable and
|
|
7
|
+
* untappable, so the game should switch to a phone layout. While it is set the root carries,
|
|
8
|
+
* in CSS px:
|
|
9
|
+
* - `--tc-bar`: the letterbox bar beside the canvas;
|
|
10
|
+
* - `--tc-third`: a third of the viewport width less 6 px (the widest a transient card
|
|
11
|
+
* should grow).
|
|
12
|
+
* Desktop and tablets never get it.
|
|
13
|
+
* - `--tc-crop-t` / `--tc-crop-b` (always set, CSS px) and `data-fill`: what is cut off the top
|
|
14
|
+
* and bottom of the canvas when a phone fills the width instead of letterboxing (0 otherwise).
|
|
15
|
+
* - `data-touch`: the last input was a finger. A mouse press or a key switches it off again.
|
|
16
|
+
*
|
|
17
|
+
* The density tokens (`--tc-text-min`, `--tc-tap-min`) belong to the overlay's layout.
|
|
18
|
+
*/
|
|
19
|
+
import { isTouchOnly, watchPointerKind } from './device.js';
|
|
20
|
+
/** Default `phoneScale`: below this overlay scale the screen is phone-sized. Phones are 0.33–0.40, tablets 0.53+. */
|
|
21
|
+
export const PHONE_SCALE = 0.45;
|
|
22
|
+
export function createDeviceMode(root, opts = {}) {
|
|
23
|
+
const phoneScale = opts.phoneScale ?? PHONE_SCALE;
|
|
24
|
+
let phone = false;
|
|
25
|
+
let touch = isTouchOnly();
|
|
26
|
+
let cssPx = 1;
|
|
27
|
+
let bar = 0;
|
|
28
|
+
let cropT = 0;
|
|
29
|
+
let cropB = 0;
|
|
30
|
+
const subs = new Set();
|
|
31
|
+
const emit = () => {
|
|
32
|
+
for (const f of subs)
|
|
33
|
+
f();
|
|
34
|
+
};
|
|
35
|
+
const applyTouch = () => root.toggleAttribute('data-touch', touch);
|
|
36
|
+
applyTouch();
|
|
37
|
+
const unwatch = watchPointerKind((k) => {
|
|
38
|
+
const t = k === 'touch';
|
|
39
|
+
if (t === touch)
|
|
40
|
+
return;
|
|
41
|
+
touch = t;
|
|
42
|
+
applyTouch();
|
|
43
|
+
emit();
|
|
44
|
+
}, root.ownerDocument);
|
|
45
|
+
return {
|
|
46
|
+
get phone() {
|
|
47
|
+
return phone;
|
|
48
|
+
},
|
|
49
|
+
get touch() {
|
|
50
|
+
return touch;
|
|
51
|
+
},
|
|
52
|
+
get cssPx() {
|
|
53
|
+
return cssPx;
|
|
54
|
+
},
|
|
55
|
+
get bar() {
|
|
56
|
+
return bar;
|
|
57
|
+
},
|
|
58
|
+
get cropT() {
|
|
59
|
+
return cropT;
|
|
60
|
+
},
|
|
61
|
+
get cropB() {
|
|
62
|
+
return cropB;
|
|
63
|
+
},
|
|
64
|
+
onChange(fn) {
|
|
65
|
+
subs.add(fn);
|
|
66
|
+
return () => subs.delete(fn);
|
|
67
|
+
},
|
|
68
|
+
setScale(scale, barCss = 0, crop) {
|
|
69
|
+
const s = scale > 0 ? scale : 1;
|
|
70
|
+
const p = (crop && crop.fitScale > 0 ? crop.fitScale : s) < phoneScale;
|
|
71
|
+
const ct = p && crop ? Math.max(0, Math.round(crop.top / s)) : 0;
|
|
72
|
+
const cb = p && crop ? Math.max(0, Math.round(crop.bottom / s)) : 0;
|
|
73
|
+
// CSS px hidden above and below the screen: top- and bottom-anchored chrome moves in by it.
|
|
74
|
+
root.style.setProperty('--tc-crop-t', `${p && crop ? Math.max(0, crop.top) : 0}px`);
|
|
75
|
+
root.style.setProperty('--tc-crop-b', `${p && crop ? Math.max(0, crop.bottom) : 0}px`);
|
|
76
|
+
root.toggleAttribute('data-fill', ct + cb > 0);
|
|
77
|
+
const b = Math.max(0, Math.round(barCss / s));
|
|
78
|
+
const resized = Math.abs(cssPx - 1 / s) > 1e-3 || b !== bar || ct !== cropT || cb !== cropB;
|
|
79
|
+
cssPx = 1 / s;
|
|
80
|
+
bar = b;
|
|
81
|
+
cropT = ct;
|
|
82
|
+
cropB = cb;
|
|
83
|
+
if (p) {
|
|
84
|
+
root.style.setProperty('--tc-bar', `${Math.max(0, barCss)}px`);
|
|
85
|
+
// A third of the screen, less a margin: the widest any transient card may grow.
|
|
86
|
+
const vw = root.ownerDocument.defaultView?.innerWidth ?? 0;
|
|
87
|
+
root.style.setProperty('--tc-third', `${Math.round(vw / 3 - 6)}px`);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
root.style.removeProperty('--tc-bar');
|
|
91
|
+
root.style.removeProperty('--tc-third');
|
|
92
|
+
}
|
|
93
|
+
if (p === phone && !(p && resized))
|
|
94
|
+
return;
|
|
95
|
+
phone = p;
|
|
96
|
+
root.toggleAttribute('data-phone', p);
|
|
97
|
+
emit();
|
|
98
|
+
},
|
|
99
|
+
destroy() {
|
|
100
|
+
unwatch();
|
|
101
|
+
subs.clear();
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phone and tablet helpers: the kind of pointer the player is using, orientation and fullscreen.
|
|
3
|
+
* DOM-only, no game nouns. Every function is safe where an API is missing (it answers "no").
|
|
4
|
+
*/
|
|
5
|
+
/** True when the primary pointer is a finger and no mouse or trackpad is attached. */
|
|
6
|
+
export declare function isTouchOnly(): boolean;
|
|
7
|
+
export type PointerKind = 'touch' | 'mouse' | 'keyboard';
|
|
8
|
+
/**
|
|
9
|
+
* Calls `fn` with the device the player last used anywhere on the page (canvas, buttons or
|
|
10
|
+
* panels): a touch or pen press is `touch`, a mouse press or move is `mouse`, a key is
|
|
11
|
+
* `keyboard`. Capture-phase listeners, so a handler that stops propagation can't hide it.
|
|
12
|
+
* Returns unsubscribe.
|
|
13
|
+
*/
|
|
14
|
+
export declare function watchPointerKind(fn: (kind: PointerKind) => void, doc?: Document): () => void;
|
|
15
|
+
/** True when the viewport is taller than it is wide. */
|
|
16
|
+
export declare function isPortrait(win?: Window): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* True when the page may go fullscreen. iPhone Safari has no element fullscreen (only video),
|
|
19
|
+
* and an iframe needs `allowfullscreen`; both answer false here, so callers hide their button.
|
|
20
|
+
*/
|
|
21
|
+
export declare function fullscreenAvailable(doc?: Document): boolean;
|
|
22
|
+
export declare function isFullscreen(doc?: Document): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Enter or leave fullscreen (must run inside a tap or click). On entering, also asks for
|
|
25
|
+
* landscape where the browser allows it (Android Chrome); a refusal is ignored.
|
|
26
|
+
*/
|
|
27
|
+
export declare function toggleFullscreen(el?: HTMLElement, opts?: {
|
|
28
|
+
lockLandscape?: boolean;
|
|
29
|
+
}): Promise<boolean>;
|
|
30
|
+
/** Calls `fn` when fullscreen starts or ends. Returns unsubscribe. */
|
|
31
|
+
export declare function watchFullscreen(fn: (on: boolean) => void, doc?: Document): () => void;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phone and tablet helpers: the kind of pointer the player is using, orientation and fullscreen.
|
|
3
|
+
* DOM-only, no game nouns. Every function is safe where an API is missing (it answers "no").
|
|
4
|
+
*/
|
|
5
|
+
const COARSE = '(pointer: coarse)';
|
|
6
|
+
const ANY_FINE = '(any-pointer: fine)';
|
|
7
|
+
/** True when the primary pointer is a finger and no mouse or trackpad is attached. */
|
|
8
|
+
export function isTouchOnly() {
|
|
9
|
+
if (typeof matchMedia !== 'function')
|
|
10
|
+
return false;
|
|
11
|
+
return matchMedia(COARSE).matches && !matchMedia(ANY_FINE).matches;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Calls `fn` with the device the player last used anywhere on the page (canvas, buttons or
|
|
15
|
+
* panels): a touch or pen press is `touch`, a mouse press or move is `mouse`, a key is
|
|
16
|
+
* `keyboard`. Capture-phase listeners, so a handler that stops propagation can't hide it.
|
|
17
|
+
* Returns unsubscribe.
|
|
18
|
+
*/
|
|
19
|
+
export function watchPointerKind(fn, doc = document) {
|
|
20
|
+
const onPointer = (e) => {
|
|
21
|
+
if (e.pointerType === 'touch' || e.pointerType === 'pen')
|
|
22
|
+
fn('touch');
|
|
23
|
+
else if (e.pointerType === 'mouse' && (e.type === 'pointerdown' || e.movementX || e.movementY))
|
|
24
|
+
fn('mouse');
|
|
25
|
+
};
|
|
26
|
+
const onKey = (e) => {
|
|
27
|
+
// Modifier-only presses (a screenshot shortcut, a tab switch) don't mean "playing by keys".
|
|
28
|
+
if (e.key === 'Shift' || e.key === 'Control' || e.key === 'Meta' || e.key === 'Alt')
|
|
29
|
+
return;
|
|
30
|
+
fn('keyboard');
|
|
31
|
+
};
|
|
32
|
+
doc.addEventListener('pointerdown', onPointer, true);
|
|
33
|
+
doc.addEventListener('pointermove', onPointer, true);
|
|
34
|
+
doc.addEventListener('keydown', onKey, true);
|
|
35
|
+
return () => {
|
|
36
|
+
doc.removeEventListener('pointerdown', onPointer, true);
|
|
37
|
+
doc.removeEventListener('pointermove', onPointer, true);
|
|
38
|
+
doc.removeEventListener('keydown', onKey, true);
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/** True when the viewport is taller than it is wide. */
|
|
42
|
+
export function isPortrait(win = window) {
|
|
43
|
+
return win.innerHeight > win.innerWidth;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* True when the page may go fullscreen. iPhone Safari has no element fullscreen (only video),
|
|
47
|
+
* and an iframe needs `allowfullscreen`; both answer false here, so callers hide their button.
|
|
48
|
+
*/
|
|
49
|
+
export function fullscreenAvailable(doc = document) {
|
|
50
|
+
const d = doc;
|
|
51
|
+
const el = doc.documentElement;
|
|
52
|
+
const enabled = d.fullscreenEnabled ?? d.webkitFullscreenEnabled ?? false;
|
|
53
|
+
return !!enabled && (!!el.requestFullscreen || !!el.webkitRequestFullscreen);
|
|
54
|
+
}
|
|
55
|
+
export function isFullscreen(doc = document) {
|
|
56
|
+
const d = doc;
|
|
57
|
+
return !!(d.fullscreenElement ?? d.webkitFullscreenElement);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Enter or leave fullscreen (must run inside a tap or click). On entering, also asks for
|
|
61
|
+
* landscape where the browser allows it (Android Chrome); a refusal is ignored.
|
|
62
|
+
*/
|
|
63
|
+
export async function toggleFullscreen(el = document.documentElement, opts = {}) {
|
|
64
|
+
const doc = el.ownerDocument;
|
|
65
|
+
try {
|
|
66
|
+
if (isFullscreen(doc)) {
|
|
67
|
+
await (doc.exitFullscreen?.() ?? doc.webkitExitFullscreen?.());
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
const f = el;
|
|
71
|
+
await (f.requestFullscreen?.({ navigationUI: 'hide' }) ?? f.webkitRequestFullscreen?.());
|
|
72
|
+
if (opts.lockLandscape) {
|
|
73
|
+
const o = screen.orientation;
|
|
74
|
+
await o?.lock?.('landscape').catch(() => { });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// Refused (no gesture, iframe without permission): stay as we are.
|
|
79
|
+
}
|
|
80
|
+
return isFullscreen(doc);
|
|
81
|
+
}
|
|
82
|
+
/** Calls `fn` when fullscreen starts or ends. Returns unsubscribe. */
|
|
83
|
+
export function watchFullscreen(fn, doc = document) {
|
|
84
|
+
const h = () => fn(isFullscreen(doc));
|
|
85
|
+
doc.addEventListener('fullscreenchange', h);
|
|
86
|
+
doc.addEventListener('webkitfullscreenchange', h);
|
|
87
|
+
return () => {
|
|
88
|
+
doc.removeEventListener('fullscreenchange', h);
|
|
89
|
+
doc.removeEventListener('webkitfullscreenchange', h);
|
|
90
|
+
};
|
|
91
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/** Page visibility + user-preference helpers. */
|
|
2
|
+
/** Calls `fn(visible)` whenever the tab is hidden/shown. Returns unsubscribe. */
|
|
3
|
+
export declare function watchVisibility(fn: (visible: boolean) => void): () => void;
|
|
4
|
+
/** True when the player asked the OS for reduced motion. `win` defaults to the global window. */
|
|
5
|
+
export declare function isReducedMotion(win?: Window): boolean;
|
|
6
|
+
/** What the device looks like from the page: enough to pick sensible defaults, not to sniff. */
|
|
7
|
+
export interface DeviceTraits {
|
|
8
|
+
/** The primary pointer is coarse (a finger). */
|
|
9
|
+
coarsePointer: boolean;
|
|
10
|
+
/** The screen's shorter side in CSS px (`screen.width/height`, orientation-independent). */
|
|
11
|
+
shortSide: number;
|
|
12
|
+
/**
|
|
13
|
+
* A phone-sized touch device: coarse pointer and a screen whose short side is at most
|
|
14
|
+
* `HANDHELD_SHORT_SIDE` CSS px. Phones have small batteries, tiled GPUs and throttle when
|
|
15
|
+
* hot, so callers pick lighter defaults. Tablets (short side 744+) are not handheld.
|
|
16
|
+
*/
|
|
17
|
+
handheld: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** The largest phones are ~440 CSS px on the short side; the smallest tablets ~744. */
|
|
20
|
+
export declare const HANDHELD_SHORT_SIDE = 600;
|
|
21
|
+
export declare function deviceTraits(): DeviceTraits;
|
|
22
|
+
export interface LifecycleHandlers {
|
|
23
|
+
/**
|
|
24
|
+
* The page is going into the background or away: `visibilitychange` to hidden, `pagehide`
|
|
25
|
+
* (iOS app switch, closing the tab, bfcache) or `freeze` (Chrome on Android freezing a
|
|
26
|
+
* background tab, which it may later discard with no further event). Stop work and persist
|
|
27
|
+
* here: it may be the last chance. Can fire several times in a row (hidden, pagehide, freeze).
|
|
28
|
+
*/
|
|
29
|
+
onHide(reason: 'hidden' | 'pagehide' | 'freeze'): void;
|
|
30
|
+
/** The page is back and visible (`visibilitychange`, `pageshow`, `resume`). */
|
|
31
|
+
onShow(reason: 'visible' | 'pageshow' | 'resume'): void;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A game is input, not a document: stop double-tap, pinch and trackpad smart-zoom (and
|
|
35
|
+
* ctrl+wheel) from zooming the page. Keyboard zoom (Cmd/Ctrl +/-) is left alone for
|
|
36
|
+
* accessibility. Returns unsubscribe.
|
|
37
|
+
*/
|
|
38
|
+
export declare function blockBrowserZoom(doc?: Document): () => void;
|
|
39
|
+
/** Page lifecycle across the events phones actually send. Returns unsubscribe. */
|
|
40
|
+
export declare function watchLifecycle(h: LifecycleHandlers): () => void;
|
|
41
|
+
/** Calls `fn(reduced)` when the reduced-motion preference changes. Returns unsubscribe. */
|
|
42
|
+
export declare function watchReducedMotion(fn: (reduced: boolean) => void): () => void;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/** Page visibility + user-preference helpers. */
|
|
2
|
+
/** Calls `fn(visible)` whenever the tab is hidden/shown. Returns unsubscribe. */
|
|
3
|
+
export function watchVisibility(fn) {
|
|
4
|
+
const h = () => fn(document.visibilityState === 'visible');
|
|
5
|
+
document.addEventListener('visibilitychange', h);
|
|
6
|
+
return () => document.removeEventListener('visibilitychange', h);
|
|
7
|
+
}
|
|
8
|
+
const REDUCED = '(prefers-reduced-motion: reduce)';
|
|
9
|
+
/** True when the player asked the OS for reduced motion. `win` defaults to the global window. */
|
|
10
|
+
export function isReducedMotion(win) {
|
|
11
|
+
const mm = win ? win.matchMedia : typeof matchMedia === 'function' ? matchMedia : undefined;
|
|
12
|
+
return typeof mm === 'function' && mm.call(win ?? globalThis, REDUCED).matches;
|
|
13
|
+
}
|
|
14
|
+
/** The largest phones are ~440 CSS px on the short side; the smallest tablets ~744. */
|
|
15
|
+
export const HANDHELD_SHORT_SIDE = 600;
|
|
16
|
+
export function deviceTraits() {
|
|
17
|
+
const coarsePointer = typeof matchMedia === 'function' && matchMedia('(pointer: coarse)').matches;
|
|
18
|
+
const s = typeof screen !== 'undefined' ? screen : null;
|
|
19
|
+
const shortSide = s ? Math.min(s.width, s.height) : 0;
|
|
20
|
+
return {
|
|
21
|
+
coarsePointer,
|
|
22
|
+
shortSide,
|
|
23
|
+
handheld: coarsePointer && shortSide > 0 && shortSide <= HANDHELD_SHORT_SIDE,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* A game is input, not a document: stop double-tap, pinch and trackpad smart-zoom (and
|
|
28
|
+
* ctrl+wheel) from zooming the page. Keyboard zoom (Cmd/Ctrl +/-) is left alone for
|
|
29
|
+
* accessibility. Returns unsubscribe.
|
|
30
|
+
*/
|
|
31
|
+
export function blockBrowserZoom(doc = document) {
|
|
32
|
+
const block = (e) => e.preventDefault();
|
|
33
|
+
const wheel = (e) => {
|
|
34
|
+
if (e.ctrlKey)
|
|
35
|
+
e.preventDefault();
|
|
36
|
+
};
|
|
37
|
+
const types = ['gesturestart', 'gesturechange', 'dblclick'];
|
|
38
|
+
for (const t of types)
|
|
39
|
+
doc.addEventListener(t, block, { passive: false });
|
|
40
|
+
doc.addEventListener('wheel', wheel, { passive: false });
|
|
41
|
+
return () => {
|
|
42
|
+
for (const t of types)
|
|
43
|
+
doc.removeEventListener(t, block);
|
|
44
|
+
doc.removeEventListener('wheel', wheel);
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** Page lifecycle across the events phones actually send. Returns unsubscribe. */
|
|
48
|
+
export function watchLifecycle(h) {
|
|
49
|
+
const visible = () => document.visibilityState === 'visible';
|
|
50
|
+
const onVis = () => (visible() ? h.onShow('visible') : h.onHide('hidden'));
|
|
51
|
+
const onPageHide = () => h.onHide('pagehide');
|
|
52
|
+
const onPageShow = () => {
|
|
53
|
+
if (visible())
|
|
54
|
+
h.onShow('pageshow');
|
|
55
|
+
};
|
|
56
|
+
const onFreeze = () => h.onHide('freeze');
|
|
57
|
+
const onResume = () => {
|
|
58
|
+
if (visible())
|
|
59
|
+
h.onShow('resume');
|
|
60
|
+
};
|
|
61
|
+
document.addEventListener('visibilitychange', onVis);
|
|
62
|
+
window.addEventListener('pagehide', onPageHide);
|
|
63
|
+
window.addEventListener('pageshow', onPageShow);
|
|
64
|
+
document.addEventListener('freeze', onFreeze);
|
|
65
|
+
document.addEventListener('resume', onResume);
|
|
66
|
+
return () => {
|
|
67
|
+
document.removeEventListener('visibilitychange', onVis);
|
|
68
|
+
window.removeEventListener('pagehide', onPageHide);
|
|
69
|
+
window.removeEventListener('pageshow', onPageShow);
|
|
70
|
+
document.removeEventListener('freeze', onFreeze);
|
|
71
|
+
document.removeEventListener('resume', onResume);
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/** Calls `fn(reduced)` when the reduced-motion preference changes. Returns unsubscribe. */
|
|
75
|
+
export function watchReducedMotion(fn) {
|
|
76
|
+
if (typeof matchMedia !== 'function')
|
|
77
|
+
return () => { };
|
|
78
|
+
const mq = matchMedia(REDUCED);
|
|
79
|
+
const h = () => fn(mq.matches);
|
|
80
|
+
mq.addEventListener('change', h);
|
|
81
|
+
return () => mq.removeEventListener('change', h);
|
|
82
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** WebGPU capability check + device creation. */
|
|
2
|
+
export interface GpuContext {
|
|
3
|
+
adapter: GPUAdapter;
|
|
4
|
+
device: GPUDevice;
|
|
5
|
+
context: GPUCanvasContext;
|
|
6
|
+
/** Preferred swapchain format (bgra8unorm or rgba8unorm). */
|
|
7
|
+
format: GPUTextureFormat;
|
|
8
|
+
/**
|
|
9
|
+
* The device has `timestamp-query`, so GPU pass times can be measured directly
|
|
10
|
+
* (`@thunderclap-engine/engine/render` `GpuTimer`). Without it, timing falls back to submit → done.
|
|
11
|
+
*/
|
|
12
|
+
timestamps: boolean;
|
|
13
|
+
}
|
|
14
|
+
export type GpuFailureReason = 'no-api' | 'no-adapter' | 'no-device' | 'no-context';
|
|
15
|
+
export type GpuInitResult = {
|
|
16
|
+
ok: true;
|
|
17
|
+
gpu: GpuContext;
|
|
18
|
+
} | {
|
|
19
|
+
ok: false;
|
|
20
|
+
reason: GpuFailureReason;
|
|
21
|
+
detail?: string;
|
|
22
|
+
};
|
|
23
|
+
export interface GpuInitOptions {
|
|
24
|
+
powerPreference?: GPUPowerPreference;
|
|
25
|
+
/** Called when the device is lost for any reason other than an explicit `destroy()`. */
|
|
26
|
+
onLost?: (info: GPUDeviceLostInfo) => void;
|
|
27
|
+
/** Ask for `timestamp-query` when the adapter has it. Default true. */
|
|
28
|
+
timestamps?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Ask for the adapter's texture-compression features (`compressionFeatures(adapter)`:
|
|
31
|
+
* `texture-compression-bc`, `-etc2`, `-astc`), so `renderer.caps.compressed` reports what the
|
|
32
|
+
* adapter can upload without a second device (ws/render-6). Default true.
|
|
33
|
+
*/
|
|
34
|
+
compression?: boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Request an adapter + device and configure the canvas. Never throws: failures come back as
|
|
38
|
+
* `{ ok: false, reason }` so the caller can show the unsupported screen.
|
|
39
|
+
*/
|
|
40
|
+
export declare function initGpu(canvas: HTMLCanvasElement, opts?: GpuInitOptions): Promise<GpuInitResult>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/** WebGPU capability check + device creation. */
|
|
2
|
+
import { compressionFeatures } from '../render/compressed.js';
|
|
3
|
+
/**
|
|
4
|
+
* Request an adapter + device and configure the canvas. Never throws: failures come back as
|
|
5
|
+
* `{ ok: false, reason }` so the caller can show the unsupported screen.
|
|
6
|
+
*/
|
|
7
|
+
export async function initGpu(canvas, opts = {}) {
|
|
8
|
+
const gpu = navigator.gpu;
|
|
9
|
+
if (!gpu)
|
|
10
|
+
return { ok: false, reason: 'no-api' };
|
|
11
|
+
let adapter = null;
|
|
12
|
+
try {
|
|
13
|
+
adapter = await gpu.requestAdapter({
|
|
14
|
+
powerPreference: opts.powerPreference ?? 'high-performance',
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
catch (e) {
|
|
18
|
+
return { ok: false, reason: 'no-adapter', detail: String(e) };
|
|
19
|
+
}
|
|
20
|
+
if (!adapter)
|
|
21
|
+
return { ok: false, reason: 'no-adapter' };
|
|
22
|
+
// Optional features: requested only when the adapter offers them, so a device without
|
|
23
|
+
// them still comes up (and a refused request retries without any).
|
|
24
|
+
const wanted = [];
|
|
25
|
+
if ((opts.timestamps ?? true) && adapter.features.has('timestamp-query')) {
|
|
26
|
+
wanted.push('timestamp-query');
|
|
27
|
+
}
|
|
28
|
+
if (opts.compression ?? true)
|
|
29
|
+
wanted.push(...compressionFeatures(adapter));
|
|
30
|
+
let device;
|
|
31
|
+
try {
|
|
32
|
+
device = await adapter.requestDevice({ label: 'engine-device', requiredFeatures: wanted });
|
|
33
|
+
}
|
|
34
|
+
catch (e) {
|
|
35
|
+
if (wanted.length === 0)
|
|
36
|
+
return { ok: false, reason: 'no-device', detail: String(e) };
|
|
37
|
+
try {
|
|
38
|
+
device = await adapter.requestDevice({ label: 'engine-device' });
|
|
39
|
+
}
|
|
40
|
+
catch (e2) {
|
|
41
|
+
return { ok: false, reason: 'no-device', detail: String(e2) };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const timestamps = device.features.has('timestamp-query');
|
|
45
|
+
device.lost.then((info) => {
|
|
46
|
+
if (info.reason === 'destroyed')
|
|
47
|
+
return;
|
|
48
|
+
console.error(`[gpu] device lost: ${info.reason} ${info.message}`);
|
|
49
|
+
opts.onLost?.(info);
|
|
50
|
+
});
|
|
51
|
+
const context = canvas.getContext('webgpu');
|
|
52
|
+
if (!context)
|
|
53
|
+
return { ok: false, reason: 'no-context' };
|
|
54
|
+
const format = gpu.getPreferredCanvasFormat();
|
|
55
|
+
context.configure({ device, format, alphaMode: 'opaque' });
|
|
56
|
+
return { ok: true, gpu: { adapter, device, context, format, timestamps } };
|
|
57
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type { BootOptions, BootResult } from './boot.js';
|
|
2
|
+
export { boot } from './boot.js';
|
|
3
|
+
export type { PointerKind } from './device.js';
|
|
4
|
+
export { fullscreenAvailable, isFullscreen, isPortrait, isTouchOnly, toggleFullscreen, watchFullscreen, watchPointerKind, } from './device.js';
|
|
5
|
+
export { type CropInfo, createDeviceMode, type DeviceMode, type DeviceModeController, type DeviceModeOptions, PHONE_SCALE, } from './device-mode.js';
|
|
6
|
+
export type { DeviceTraits, LifecycleHandlers } from './environment.js';
|
|
7
|
+
export { blockBrowserZoom, deviceTraits, HANDHELD_SHORT_SIDE, isReducedMotion, watchLifecycle, watchReducedMotion, watchVisibility, } from './environment.js';
|
|
8
|
+
export type { GpuContext, GpuFailureReason, GpuInitOptions, GpuInitResult } from './gpu.js';
|
|
9
|
+
export { initGpu } from './gpu.js';
|
|
10
|
+
export type { BackbufferSize, Letterbox, LetterboxRect, Vec2 } from './letterbox.js';
|
|
11
|
+
export { clientToLogical, computeBackbuffer, computeLetterbox, logicalToClient, } from './letterbox.js';
|
|
12
|
+
export type { CopyResult, EmbedContext, LinkActivation, OpenResult } from './links.js';
|
|
13
|
+
export { embedContext, safeExternalUrl } from './links.js';
|
|
14
|
+
export type { MessageScreenAction, MessageScreenOptions, PlatformFamily } from './screens.js';
|
|
15
|
+
export { platformFamily, showDeviceLostScreen, showMessageScreen, showUnsupportedScreen, } from './screens.js';
|
|
16
|
+
export type { SurfaceOptions, SurfaceSize } from './surface.js';
|
|
17
|
+
export { mountSurface, Surface } from './surface.js';
|
|
18
|
+
export { type XrEyeView, XrSurface, type XrSurfaceOptions } from './xr-surface.js';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { boot } from './boot.js';
|
|
2
|
+
export { fullscreenAvailable, isFullscreen, isPortrait, isTouchOnly, toggleFullscreen, watchFullscreen, watchPointerKind, } from './device.js';
|
|
3
|
+
export { createDeviceMode, PHONE_SCALE, } from './device-mode.js';
|
|
4
|
+
export { blockBrowserZoom, deviceTraits, HANDHELD_SHORT_SIDE, isReducedMotion, watchLifecycle, watchReducedMotion, watchVisibility, } from './environment.js';
|
|
5
|
+
export { initGpu } from './gpu.js';
|
|
6
|
+
export { clientToLogical, computeBackbuffer, computeLetterbox, logicalToClient, } from './letterbox.js';
|
|
7
|
+
export { embedContext, safeExternalUrl } from './links.js';
|
|
8
|
+
export { platformFamily, showDeviceLostScreen, showMessageScreen, showUnsupportedScreen, } from './screens.js';
|
|
9
|
+
export { mountSurface, Surface } from './surface.js';
|
|
10
|
+
export { XrSurface } from './xr-surface.js';
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure letterbox + coordinate math. No DOM, so it is unit-testable in Node.
|
|
3
|
+
*
|
|
4
|
+
* Terms:
|
|
5
|
+
* - "client" = CSS pixels relative to the container's top-left corner.
|
|
6
|
+
* - "logical" = the fixed design space (default 1920×1080), origin top-left, y down.
|
|
7
|
+
* - "backbuffer" = physical pixels of the canvas drawing buffer.
|
|
8
|
+
*/
|
|
9
|
+
export interface LetterboxRect {
|
|
10
|
+
x: number;
|
|
11
|
+
y: number;
|
|
12
|
+
width: number;
|
|
13
|
+
height: number;
|
|
14
|
+
}
|
|
15
|
+
/** Letterboxed viewport inside a container, in client (CSS) pixels. */
|
|
16
|
+
export interface Letterbox extends LetterboxRect {
|
|
17
|
+
/** CSS pixels per logical unit. */
|
|
18
|
+
scale: number;
|
|
19
|
+
}
|
|
20
|
+
export interface Vec2 {
|
|
21
|
+
x: number;
|
|
22
|
+
y: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Fit a logicalW×logicalH design space into a container, preserving aspect ratio and centring
|
|
26
|
+
* it. Size is snapped to whole CSS pixels so the canvas edges stay crisp.
|
|
27
|
+
*/
|
|
28
|
+
export declare function computeLetterbox(containerW: number, containerH: number, logicalW: number, logicalH: number): Letterbox;
|
|
29
|
+
/** Map a client point (CSS px relative to the container) into logical space. */
|
|
30
|
+
export declare function clientToLogical(box: LetterboxRect, logicalW: number, logicalH: number, cx: number, cy: number, out?: Vec2): Vec2;
|
|
31
|
+
/** Map a logical point back to client CSS px relative to the container. */
|
|
32
|
+
export declare function logicalToClient(box: LetterboxRect, logicalW: number, logicalH: number, lx: number, ly: number, out?: Vec2): Vec2;
|
|
33
|
+
export interface BackbufferSize {
|
|
34
|
+
width: number;
|
|
35
|
+
height: number;
|
|
36
|
+
/** Effective pixel ratio actually used (after caps). */
|
|
37
|
+
pixelRatio: number;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Choose drawing-buffer size for a CSS rect: devicePixelRatio, capped by `maxDpr`, then scaled
|
|
41
|
+
* down further if the total pixel count would exceed `maxPixels` (perf budget on iGPUs).
|
|
42
|
+
*/
|
|
43
|
+
export declare function computeBackbuffer(cssW: number, cssH: number, devicePixelRatio: number, maxDpr?: number, maxPixels?: number): BackbufferSize;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure letterbox + coordinate math. No DOM, so it is unit-testable in Node.
|
|
3
|
+
*
|
|
4
|
+
* Terms:
|
|
5
|
+
* - "client" = CSS pixels relative to the container's top-left corner.
|
|
6
|
+
* - "logical" = the fixed design space (default 1920×1080), origin top-left, y down.
|
|
7
|
+
* - "backbuffer" = physical pixels of the canvas drawing buffer.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Fit a logicalW×logicalH design space into a container, preserving aspect ratio and centring
|
|
11
|
+
* it. Size is snapped to whole CSS pixels so the canvas edges stay crisp.
|
|
12
|
+
*/
|
|
13
|
+
export function computeLetterbox(containerW, containerH, logicalW, logicalH) {
|
|
14
|
+
if (!(containerW > 0) || !(containerH > 0) || !(logicalW > 0) || !(logicalH > 0)) {
|
|
15
|
+
return { x: 0, y: 0, width: 0, height: 0, scale: 0 };
|
|
16
|
+
}
|
|
17
|
+
const fit = Math.min(containerW / logicalW, containerH / logicalH);
|
|
18
|
+
const width = Math.max(1, Math.min(containerW, Math.round(logicalW * fit)));
|
|
19
|
+
const height = Math.max(1, Math.min(containerH, Math.round(logicalH * fit)));
|
|
20
|
+
const x = Math.floor((containerW - width) / 2);
|
|
21
|
+
const y = Math.floor((containerH - height) / 2);
|
|
22
|
+
return { x, y, width, height, scale: width / logicalW };
|
|
23
|
+
}
|
|
24
|
+
/** Map a client point (CSS px relative to the container) into logical space. */
|
|
25
|
+
export function clientToLogical(box, logicalW, logicalH, cx, cy, out = { x: 0, y: 0 }) {
|
|
26
|
+
if (box.width <= 0 || box.height <= 0) {
|
|
27
|
+
out.x = 0;
|
|
28
|
+
out.y = 0;
|
|
29
|
+
return out;
|
|
30
|
+
}
|
|
31
|
+
out.x = ((cx - box.x) / box.width) * logicalW;
|
|
32
|
+
out.y = ((cy - box.y) / box.height) * logicalH;
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
/** Map a logical point back to client CSS px relative to the container. */
|
|
36
|
+
export function logicalToClient(box, logicalW, logicalH, lx, ly, out = { x: 0, y: 0 }) {
|
|
37
|
+
out.x = box.x + (lx / logicalW) * box.width;
|
|
38
|
+
out.y = box.y + (ly / logicalH) * box.height;
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Choose drawing-buffer size for a CSS rect: devicePixelRatio, capped by `maxDpr`, then scaled
|
|
43
|
+
* down further if the total pixel count would exceed `maxPixels` (perf budget on iGPUs).
|
|
44
|
+
*/
|
|
45
|
+
export function computeBackbuffer(cssW, cssH, devicePixelRatio, maxDpr = 2, maxPixels = Number.POSITIVE_INFINITY) {
|
|
46
|
+
if (!(cssW > 0) || !(cssH > 0))
|
|
47
|
+
return { width: 1, height: 1, pixelRatio: 1 };
|
|
48
|
+
let ratio = Math.min(Math.max(devicePixelRatio || 1, 0.25), maxDpr);
|
|
49
|
+
const px = cssW * ratio * cssH * ratio;
|
|
50
|
+
if (px > maxPixels)
|
|
51
|
+
ratio *= Math.sqrt(maxPixels / px);
|
|
52
|
+
return {
|
|
53
|
+
width: Math.max(1, Math.round(cssW * ratio)),
|
|
54
|
+
height: Math.max(1, Math.round(cssH * ratio)),
|
|
55
|
+
pixelRatio: ratio,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External links (D-036): URL validation, embed detection and the result types. Opening and
|
|
3
|
+
* copying are host services: `Host.openExternal` and `Host.copyText` (engine/host; the web
|
|
4
|
+
* implementation is host/web-links.ts). The widget is `externalLink` in engine/ui.
|
|
5
|
+
*/
|
|
6
|
+
/** How the player asked for the link: a real gesture (pointer/keyboard) or not (gamepad/script). */
|
|
7
|
+
export type LinkActivation = 'pointer' | 'keyboard' | 'gamepad' | 'script';
|
|
8
|
+
/** `invalid`: the URL failed `safeExternalUrl`, so nothing was attempted. */
|
|
9
|
+
export type OpenResult = 'opened' | 'blocked' | 'invalid';
|
|
10
|
+
/** `manual`: every copy method failed; show the URL for the player to copy by hand. */
|
|
11
|
+
export type CopyResult = 'copied' | 'manual';
|
|
12
|
+
/** Where the page runs: top level, or in a frame of the same or another origin (e.g. itch.io). */
|
|
13
|
+
export type EmbedContext = 'top' | 'same-origin-frame' | 'cross-origin-frame';
|
|
14
|
+
/**
|
|
15
|
+
* The URL if it is a plain absolute `https:` link (no credentials, no whitespace), else null.
|
|
16
|
+
* Callers hide the control on null, so a blank or bad constant never renders a dead link.
|
|
17
|
+
*/
|
|
18
|
+
export declare function safeExternalUrl(url: string | null | undefined): string | null;
|
|
19
|
+
/** Detects (does not assume) whether the page is framed, and whether by another origin. */
|
|
20
|
+
export declare function embedContext(win?: Window): EmbedContext;
|