@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,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ear-clipping triangulation of a simple polygon (`triangulate`), the cap step of `extrude` and
|
|
3
|
+
* the whole of `polygon`. Pure arithmetic over x, y pairs.
|
|
4
|
+
*/
|
|
5
|
+
/** Twice the signed area of a profile: positive counter-clockwise, negative clockwise. */
|
|
6
|
+
export function profileArea2(profile) {
|
|
7
|
+
const n = profile.length >> 1;
|
|
8
|
+
let a = 0;
|
|
9
|
+
for (let i = 0, j = n - 1; i < n; j = i++) {
|
|
10
|
+
a += profile[j * 2] * profile[i * 2 + 1] - profile[i * 2] * profile[j * 2 + 1];
|
|
11
|
+
}
|
|
12
|
+
return a;
|
|
13
|
+
}
|
|
14
|
+
function cross(ax, ay, bx, by, cx, cy) {
|
|
15
|
+
return (bx - ax) * (cy - ay) - (by - ay) * (cx - ax);
|
|
16
|
+
}
|
|
17
|
+
/** `p` strictly inside, or on the edge of, triangle `a b c` (counter-clockwise). */
|
|
18
|
+
function inTriangle(ax, ay, bx, by, cx, cy, px, py) {
|
|
19
|
+
return (cross(ax, ay, bx, by, px, py) >= 0 &&
|
|
20
|
+
cross(bx, by, cx, cy, px, py) >= 0 &&
|
|
21
|
+
cross(cx, cy, ax, ay, px, py) >= 0);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Triangulate a simple polygon by ear clipping: up to `n - 2` triangles over the profile's vertex
|
|
25
|
+
* indices, wound counter-clockwise in the profile's plane whatever its input winding. Concave
|
|
26
|
+
* outlines are handled; collinear or repeated points are dropped as zero-area ears (so fewer
|
|
27
|
+
* triangles come back). Self-intersection detection is out of scope: a self-intersecting outline
|
|
28
|
+
* still triangulates completely, but which side is "inside" is undefined there. `Uint16Array` up
|
|
29
|
+
* to 65535 points, `Uint32Array` past it. Fewer than three points gives an empty array. Cost is
|
|
30
|
+
* O(n · r) for r reflex (inward-turning) corners, so convex outlines fan in O(n); a huge outline
|
|
31
|
+
* whose corners jitter in and out of convexity (float32 rounding on a 70000-gon) is quadratic.
|
|
32
|
+
*/
|
|
33
|
+
export function triangulate(profile) {
|
|
34
|
+
const n = profile.length >> 1;
|
|
35
|
+
const triCount = Math.max(0, n - 2);
|
|
36
|
+
const out = n > 0xffff ? new Uint32Array(triCount * 3) : new Uint16Array(triCount * 3);
|
|
37
|
+
if (n < 3)
|
|
38
|
+
return out;
|
|
39
|
+
// Doubly linked ring over the vertex indices, in counter-clockwise order.
|
|
40
|
+
const ccw = profileArea2(profile) >= 0;
|
|
41
|
+
const next = new Int32Array(n);
|
|
42
|
+
const prev = new Int32Array(n);
|
|
43
|
+
for (let k = 0; k < n; k++) {
|
|
44
|
+
const i = ccw ? k : n - 1 - k;
|
|
45
|
+
const iNext = ccw ? (k + 1) % n : n - 1 - ((k + 1) % n);
|
|
46
|
+
next[i] = iNext;
|
|
47
|
+
prev[iNext] = i;
|
|
48
|
+
}
|
|
49
|
+
const x = (i) => profile[i * 2];
|
|
50
|
+
const y = (i) => profile[i * 2 + 1];
|
|
51
|
+
// Reflex vertices (an inward turn) are the only ones that can sit inside a candidate ear, so
|
|
52
|
+
// the containment test skips the others; a convex outline has none and fans in O(n).
|
|
53
|
+
const reflex = new Uint8Array(n);
|
|
54
|
+
let reflexCount = 0;
|
|
55
|
+
for (let i = 0; i < n; i++) {
|
|
56
|
+
const a = prev[i];
|
|
57
|
+
const c = next[i];
|
|
58
|
+
if (cross(x(a), y(a), x(i), y(i), x(c), y(c)) < 0) {
|
|
59
|
+
reflex[i] = 1;
|
|
60
|
+
reflexCount++;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const updateReflex = (i) => {
|
|
64
|
+
const was = reflex[i];
|
|
65
|
+
const a = prev[i];
|
|
66
|
+
const c = next[i];
|
|
67
|
+
const now = cross(x(a), y(a), x(i), y(i), x(c), y(c)) < 0 ? 1 : 0;
|
|
68
|
+
if (was !== now) {
|
|
69
|
+
reflex[i] = now;
|
|
70
|
+
reflexCount += now - was;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
let remaining = n;
|
|
74
|
+
let o = 0;
|
|
75
|
+
let cur = ccw ? 0 : n - 1;
|
|
76
|
+
let guard = 0;
|
|
77
|
+
while (remaining > 3) {
|
|
78
|
+
const a = prev[cur];
|
|
79
|
+
const b = cur;
|
|
80
|
+
const c = next[cur];
|
|
81
|
+
const area = cross(x(a), y(a), x(b), y(b), x(c), y(c));
|
|
82
|
+
let ear = false;
|
|
83
|
+
if (Math.abs(area) <= 1e-12 * (1 + Math.abs(x(a)) + Math.abs(y(a)))) {
|
|
84
|
+
// Collinear or repeated: a zero-area ear, dropped without a triangle.
|
|
85
|
+
next[a] = c;
|
|
86
|
+
prev[c] = a;
|
|
87
|
+
if (reflex[b])
|
|
88
|
+
reflexCount--;
|
|
89
|
+
remaining--;
|
|
90
|
+
updateReflex(a);
|
|
91
|
+
updateReflex(c);
|
|
92
|
+
cur = c;
|
|
93
|
+
guard = 0;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (area > 0) {
|
|
97
|
+
ear = true;
|
|
98
|
+
for (let p = next[c]; reflexCount > 0 && p !== a; p = next[p]) {
|
|
99
|
+
if (reflex[p] === 1 &&
|
|
100
|
+
(x(p) !== x(a) || y(p) !== y(a)) &&
|
|
101
|
+
(x(p) !== x(b) || y(p) !== y(b)) &&
|
|
102
|
+
(x(p) !== x(c) || y(p) !== y(c)) &&
|
|
103
|
+
inTriangle(x(a), y(a), x(b), y(b), x(c), y(c), x(p), y(p))) {
|
|
104
|
+
ear = false;
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (ear) {
|
|
110
|
+
out[o++] = a;
|
|
111
|
+
out[o++] = b;
|
|
112
|
+
out[o++] = c;
|
|
113
|
+
next[a] = c;
|
|
114
|
+
prev[c] = a;
|
|
115
|
+
remaining--;
|
|
116
|
+
updateReflex(a);
|
|
117
|
+
updateReflex(c);
|
|
118
|
+
cur = a;
|
|
119
|
+
guard = 0;
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
cur = c;
|
|
123
|
+
// A full loop without an ear: the outline is not simple; clip anyway so the fan completes.
|
|
124
|
+
if (++guard > remaining) {
|
|
125
|
+
out[o++] = a;
|
|
126
|
+
out[o++] = b;
|
|
127
|
+
out[o++] = c;
|
|
128
|
+
next[a] = c;
|
|
129
|
+
prev[c] = a;
|
|
130
|
+
if (reflex[b])
|
|
131
|
+
reflexCount--;
|
|
132
|
+
remaining--;
|
|
133
|
+
updateReflex(a);
|
|
134
|
+
updateReflex(c);
|
|
135
|
+
cur = a;
|
|
136
|
+
guard = 0;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (remaining === 3) {
|
|
141
|
+
out[o++] = prev[cur];
|
|
142
|
+
out[o++] = cur;
|
|
143
|
+
out[o++] = next[cur];
|
|
144
|
+
}
|
|
145
|
+
// Dropped degenerate ears leave fewer triangles than n - 2: trim to what was written.
|
|
146
|
+
return o < out.length ? out.slice(0, o) : out;
|
|
147
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The host engine modules use when the caller passes none (`createSaveStore`, `listSlots`,
|
|
3
|
+
* `persistMixer`, `externalLink`): a web host, made on first use. A shell that is not the
|
|
4
|
+
* browser (Electron) calls `setDefaultHost` before anything else runs. Games should still pass
|
|
5
|
+
* their host explicitly.
|
|
6
|
+
*/
|
|
7
|
+
import type { Host } from './types.js';
|
|
8
|
+
export declare function defaultHost(): Host;
|
|
9
|
+
/** Replaces the default host (null: a fresh web host on next use). */
|
|
10
|
+
export declare function setDefaultHost(host: Host | null): void;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createWebHost } from './web.js';
|
|
2
|
+
let current = null;
|
|
3
|
+
export function defaultHost() {
|
|
4
|
+
current ??= createWebHost();
|
|
5
|
+
return current;
|
|
6
|
+
}
|
|
7
|
+
/** Replaces the default host (null: a fresh web host on next use). */
|
|
8
|
+
export function setDefaultHost(host) {
|
|
9
|
+
current = host;
|
|
10
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { defaultHost, setDefaultHost } from './default.js';
|
|
2
|
+
export type { FrameSource, HapticImpact, HapticNotification, Host, HostFullscreen, HostHaptics, HostInsets, HostKind, HostLifecycle, HostLifecycleState, HostSafeArea, HostStorage, HostWindow, } from './types.js';
|
|
3
|
+
export { createWebHaptics, createWebHost, createWebLifecycle, createWebSafeArea, type WebHostOptions, } from './web.js';
|
|
4
|
+
export { createXrHost, type XrHost } from './xr.js';
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The host: what the page or shell the game runs in can do for it (D-041, ARCHITECTURE.md
|
|
3
|
+
* "Host"). The engine reaches the outside world only through this: frame scheduling, opening a
|
|
4
|
+
* link, copying text, fullscreen, and where saves are kept. `createWebHost()` (host/web.ts) is the browser,
|
|
5
|
+
* at top level or in a frame such as itch.io's; `createElectronHost()` (`@thunderclap-engine/host-electron`)
|
|
6
|
+
* satisfies the same interface through a preload bridge and adds `window`;
|
|
7
|
+
* `createCapacitorHost()` (`@thunderclap-engine/host-capacitor`) fills it from Capacitor's plugins for a
|
|
8
|
+
* store app; `createXrHost()` (host/xr.ts) takes frames from an XR session and delegates the
|
|
9
|
+
* rest to the host it wraps. The optional facets `lifecycle`, `haptics` and `safeArea` (ws/host-mobile) are what
|
|
10
|
+
* a mobile shell adds and the web host can also answer.
|
|
11
|
+
*/
|
|
12
|
+
import type { CopyResult, EmbedContext, LinkActivation, OpenResult } from '../platform/links.js';
|
|
13
|
+
import type { StorageLike } from '../save/storage.js';
|
|
14
|
+
/** Which implementation this is. */
|
|
15
|
+
export type HostKind = 'web' | 'electron' | 'xr' | 'capacitor';
|
|
16
|
+
/**
|
|
17
|
+
* Where saves are kept. `open()` returns a working backend right now, or null when there is
|
|
18
|
+
* none (missing, blocked by the browser, or failing a round-trip). It never throws and it
|
|
19
|
+
* probes on every call, so a caller that got null can try again later (the save store does,
|
|
20
|
+
* on each write). Writes may still throw (quota); `engine/save` handles that.
|
|
21
|
+
*/
|
|
22
|
+
export interface HostStorage {
|
|
23
|
+
/** `local`: the web host's `localStorage`. Other hosts name their own. */
|
|
24
|
+
readonly kind: string;
|
|
25
|
+
open(): StorageLike | null;
|
|
26
|
+
}
|
|
27
|
+
/** Fullscreen for the game's page or window. */
|
|
28
|
+
export interface HostFullscreen {
|
|
29
|
+
/** True when going fullscreen can work here (false on iPhone Safari, or in a frame without `allowfullscreen`). */
|
|
30
|
+
available(): boolean;
|
|
31
|
+
/** True while fullscreen (a getter: read it each time). */
|
|
32
|
+
readonly active: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Enters or leaves fullscreen; call it inside a tap or click. `lockLandscape` also asks for
|
|
35
|
+
* landscape where the platform allows it. Resolves to whether it is fullscreen afterwards;
|
|
36
|
+
* a refusal leaves things as they were and never rejects.
|
|
37
|
+
*/
|
|
38
|
+
toggle(opts?: {
|
|
39
|
+
lockLandscape?: boolean;
|
|
40
|
+
}): Promise<boolean>;
|
|
41
|
+
/** Calls `fn` when fullscreen starts or ends. Returns unsubscribe. */
|
|
42
|
+
watch(fn: (on: boolean) => void): () => void;
|
|
43
|
+
}
|
|
44
|
+
/** Window controls a desktop shell offers. The web host has none. */
|
|
45
|
+
export interface HostWindow {
|
|
46
|
+
close(): void;
|
|
47
|
+
minimize?(): void;
|
|
48
|
+
toggleMaximize?(): void;
|
|
49
|
+
/** Sets the window's title bar text. */
|
|
50
|
+
setTitle?(title: string): void;
|
|
51
|
+
}
|
|
52
|
+
/** Whether the app is in front of the player or paged out (a hidden tab, a backgrounded app). */
|
|
53
|
+
export type HostLifecycleState = 'active' | 'background';
|
|
54
|
+
/**
|
|
55
|
+
* The app's lifecycle (ws/host-mobile). `createGame` stops requesting frames and flushes the
|
|
56
|
+
* save on `background` and starts them again on `active`; a game autosaves from
|
|
57
|
+
* `hooks.lifecycle`. The web host reads it from `visibilitychange` and `pagehide`/`pageshow`; a
|
|
58
|
+
* store app's host reads it from the shell (Capacitor's `appStateChange`).
|
|
59
|
+
*/
|
|
60
|
+
export interface HostLifecycle {
|
|
61
|
+
/**
|
|
62
|
+
* The state now (a getter, E-036: read it each time). Before ws/core-8 this was a method,
|
|
63
|
+
* `state()`; a custom host writes it as a getter.
|
|
64
|
+
*/
|
|
65
|
+
readonly state: HostLifecycleState;
|
|
66
|
+
/** Calls `fn` on every change (never twice with the same state). Returns unsubscribe. */
|
|
67
|
+
watch(fn: (state: HostLifecycleState) => void): () => void;
|
|
68
|
+
}
|
|
69
|
+
export type HapticImpact = 'light' | 'medium' | 'heavy';
|
|
70
|
+
export type HapticNotification = 'success' | 'warning' | 'error';
|
|
71
|
+
/**
|
|
72
|
+
* Haptic feedback. Every call is fire-and-forget and safe when `available()` is false (it does
|
|
73
|
+
* nothing). The web host maps everything onto `navigator.vibrate`; a store app's host onto the
|
|
74
|
+
* platform's haptics engine.
|
|
75
|
+
*/
|
|
76
|
+
export interface HostHaptics {
|
|
77
|
+
/** True when the device can produce any haptic at all. */
|
|
78
|
+
available(): boolean;
|
|
79
|
+
/** A short tap of the given weight, for a press or a landing. */
|
|
80
|
+
impact(style: HapticImpact): void;
|
|
81
|
+
/** A patterned buzz for an outcome. */
|
|
82
|
+
notification(kind: HapticNotification): void;
|
|
83
|
+
/** A plain vibration of `ms` milliseconds. */
|
|
84
|
+
vibrate(ms: number): void;
|
|
85
|
+
}
|
|
86
|
+
/** Safe-area insets in CSS px: what a notch, a home indicator or rounded corners cover. */
|
|
87
|
+
export interface HostInsets {
|
|
88
|
+
top: number;
|
|
89
|
+
right: number;
|
|
90
|
+
bottom: number;
|
|
91
|
+
left: number;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The viewport's safe-area insets, CSS px. The UI layout pads its regions by them
|
|
95
|
+
* (`followSafeArea` in `ui/layout`). The web host reads `env(safe-area-inset-*)` and re-reads
|
|
96
|
+
* on resize.
|
|
97
|
+
*/
|
|
98
|
+
export interface HostSafeArea {
|
|
99
|
+
/** The insets now. The object is reused: copy it to keep it. */
|
|
100
|
+
insets(): Readonly<HostInsets>;
|
|
101
|
+
/** Calls `fn` when the insets change (a rotation, a resize). Returns unsubscribe. */
|
|
102
|
+
watch(fn: (insets: Readonly<HostInsets>) => void): () => void;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Where frames come from: the display's refresh (`requestAnimationFrame` in a browser), a
|
|
106
|
+
* test's manual stepping, or an XR session's `requestAnimationFrame` (`createXrHost`). `GameLoop` schedules
|
|
107
|
+
* every frame through this, never through the globals.
|
|
108
|
+
*/
|
|
109
|
+
export interface FrameSource {
|
|
110
|
+
/**
|
|
111
|
+
* Calls `cb(timeMs)` once, at the next frame, with the frame's timestamp in ms on the same
|
|
112
|
+
* clock as `performance.now()`. Returns a handle for `cancelFrame`.
|
|
113
|
+
*/
|
|
114
|
+
requestFrame(cb: (timeMs: number) => void): number;
|
|
115
|
+
/** Drops a pending request; a handle already run or cancelled is ignored. */
|
|
116
|
+
cancelFrame(handle: number): void;
|
|
117
|
+
}
|
|
118
|
+
export interface Host extends FrameSource {
|
|
119
|
+
readonly kind: HostKind;
|
|
120
|
+
/** Where the page runs: top level, or framed by the same or another origin (itch.io). */
|
|
121
|
+
readonly embed: EmbedContext;
|
|
122
|
+
/**
|
|
123
|
+
* Opens `url` (a plain `https:` link, else `invalid`) outside the game. `activation` says how
|
|
124
|
+
* the player asked: `pointer` and `keyboard` are real gestures, `gamepad` and `script` are
|
|
125
|
+
* not, so the open may come back `blocked` (then show the URL for copying instead).
|
|
126
|
+
*/
|
|
127
|
+
openExternal(url: string, opts: {
|
|
128
|
+
activation: LinkActivation;
|
|
129
|
+
}): OpenResult;
|
|
130
|
+
/** Copies `text`; `manual` means every method failed (show it for copying by hand). */
|
|
131
|
+
copyText(text: string): Promise<CopyResult>;
|
|
132
|
+
/** False when the platform rules out writing the clipboard directly (itch's frame policy). */
|
|
133
|
+
clipboardWriteAllowed(): boolean;
|
|
134
|
+
readonly fullscreen: HostFullscreen;
|
|
135
|
+
readonly storage: HostStorage;
|
|
136
|
+
/** Desktop window controls, when the host has a window of its own. */
|
|
137
|
+
readonly window?: HostWindow;
|
|
138
|
+
/** The app's foreground/background state, when the host can tell (web and capacitor do; the XR host passes on its base host's). */
|
|
139
|
+
readonly lifecycle?: HostLifecycle;
|
|
140
|
+
/** Haptic feedback, when the host offers any (`available()` says whether the device does). */
|
|
141
|
+
readonly haptics?: HostHaptics;
|
|
142
|
+
/** The viewport's safe-area insets, when the host can measure them. */
|
|
143
|
+
readonly safeArea?: HostSafeArea;
|
|
144
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The web host's link service (D-036): opening and copying. Reached through `Host.openExternal`
|
|
3
|
+
* and `Host.copyText` (createWebHost); nothing else in the engine calls `window.open` or the
|
|
4
|
+
* clipboard.
|
|
5
|
+
*
|
|
6
|
+
* Rules: nothing here runs on its own (call it from a player action), and nothing is fetched.
|
|
7
|
+
*
|
|
8
|
+
* Facts this is built on (docs/research/itch-webgpu.md, "Clipboard and popups"):
|
|
9
|
+
* - A tab opened from a real click or key press on `<a target=_blank>` is allowed by popup
|
|
10
|
+
* blockers. A gamepad press is not a user activation, so `window.open` from it can be blocked
|
|
11
|
+
* (it then returns null).
|
|
12
|
+
* - Embeds may lack `clipboard-write` in the iframe's permissions policy (itch.io does:
|
|
13
|
+
* https://github.com/itchio/itch.io/issues/1202), so Chromium rejects `clipboard.writeText`
|
|
14
|
+
* there. `execCommand('copy')` on a selected textarea, inside the gesture, still works.
|
|
15
|
+
*/
|
|
16
|
+
import { type CopyResult, type LinkActivation, type OpenResult } from '../platform/links.js';
|
|
17
|
+
/**
|
|
18
|
+
* Opens `url` in a new tab. With a real gesture (`pointer`/`keyboard`) it clicks a temporary
|
|
19
|
+
* `<a target=_blank rel="noopener noreferrer">`, which popup blockers allow; the browser gives no
|
|
20
|
+
* signal back, so the result is `opened`. Otherwise (`gamepad`/`script`) it uses `window.open`,
|
|
21
|
+
* whose null return means `blocked`; the opened tab's `opener` is cleared.
|
|
22
|
+
*/
|
|
23
|
+
export declare function openExternal(url: string, opts: {
|
|
24
|
+
activation: LinkActivation;
|
|
25
|
+
}, win?: Window): OpenResult;
|
|
26
|
+
/**
|
|
27
|
+
* Copies `text`: the async Clipboard API, then a hidden textarea + `execCommand('copy')`, else
|
|
28
|
+
* `manual`. Call it from the player's click or key handler; both methods need that gesture.
|
|
29
|
+
*/
|
|
30
|
+
export declare function copyText(text: string, win?: Window): Promise<CopyResult>;
|
|
31
|
+
/**
|
|
32
|
+
* False when the frame's permissions policy rules out `clipboard-write` (itch's iframe: its
|
|
33
|
+
* `allow` list lacks it). Checked where the browser exposes the policy (Chromium), so the
|
|
34
|
+
* Clipboard API is not even tried there and no policy-violation error is logged. Elsewhere true.
|
|
35
|
+
*/
|
|
36
|
+
export declare function clipboardWriteAllowed(doc?: Document): boolean;
|
|
37
|
+
/** `execCommand('copy')` from an off-screen textarea; focus goes back where it was. */
|
|
38
|
+
export declare function execCopy(text: string, doc?: Document): boolean;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The web host's link service (D-036): opening and copying. Reached through `Host.openExternal`
|
|
3
|
+
* and `Host.copyText` (createWebHost); nothing else in the engine calls `window.open` or the
|
|
4
|
+
* clipboard.
|
|
5
|
+
*
|
|
6
|
+
* Rules: nothing here runs on its own (call it from a player action), and nothing is fetched.
|
|
7
|
+
*
|
|
8
|
+
* Facts this is built on (docs/research/itch-webgpu.md, "Clipboard and popups"):
|
|
9
|
+
* - A tab opened from a real click or key press on `<a target=_blank>` is allowed by popup
|
|
10
|
+
* blockers. A gamepad press is not a user activation, so `window.open` from it can be blocked
|
|
11
|
+
* (it then returns null).
|
|
12
|
+
* - Embeds may lack `clipboard-write` in the iframe's permissions policy (itch.io does:
|
|
13
|
+
* https://github.com/itchio/itch.io/issues/1202), so Chromium rejects `clipboard.writeText`
|
|
14
|
+
* there. `execCommand('copy')` on a selected textarea, inside the gesture, still works.
|
|
15
|
+
*/
|
|
16
|
+
import { safeExternalUrl, } from '../platform/links.js';
|
|
17
|
+
/**
|
|
18
|
+
* Opens `url` in a new tab. With a real gesture (`pointer`/`keyboard`) it clicks a temporary
|
|
19
|
+
* `<a target=_blank rel="noopener noreferrer">`, which popup blockers allow; the browser gives no
|
|
20
|
+
* signal back, so the result is `opened`. Otherwise (`gamepad`/`script`) it uses `window.open`,
|
|
21
|
+
* whose null return means `blocked`; the opened tab's `opener` is cleared.
|
|
22
|
+
*/
|
|
23
|
+
export function openExternal(url, opts, win = window) {
|
|
24
|
+
const href = safeExternalUrl(url);
|
|
25
|
+
if (!href)
|
|
26
|
+
return 'invalid';
|
|
27
|
+
if (opts.activation === 'pointer' || opts.activation === 'keyboard') {
|
|
28
|
+
const doc = win.document;
|
|
29
|
+
const a = doc.createElement('a');
|
|
30
|
+
a.href = href;
|
|
31
|
+
a.target = '_blank';
|
|
32
|
+
a.rel = 'noopener noreferrer';
|
|
33
|
+
a.style.display = 'none';
|
|
34
|
+
doc.body.append(a);
|
|
35
|
+
a.click();
|
|
36
|
+
a.remove();
|
|
37
|
+
return 'opened';
|
|
38
|
+
}
|
|
39
|
+
let w = null;
|
|
40
|
+
try {
|
|
41
|
+
// Not the 'noopener' feature: with it, window.open returns null even when the tab opened.
|
|
42
|
+
w = win.open(href, '_blank');
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
w = null;
|
|
46
|
+
}
|
|
47
|
+
if (!w)
|
|
48
|
+
return 'blocked';
|
|
49
|
+
try {
|
|
50
|
+
w.opener = null;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// Read-only in some browsers; the tab is open either way.
|
|
54
|
+
}
|
|
55
|
+
return 'opened';
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Copies `text`: the async Clipboard API, then a hidden textarea + `execCommand('copy')`, else
|
|
59
|
+
* `manual`. Call it from the player's click or key handler; both methods need that gesture.
|
|
60
|
+
*/
|
|
61
|
+
export async function copyText(text, win = window) {
|
|
62
|
+
try {
|
|
63
|
+
const clip = win.navigator.clipboard;
|
|
64
|
+
if (clip?.writeText && clipboardWriteAllowed(win.document)) {
|
|
65
|
+
await clip.writeText(text);
|
|
66
|
+
return 'copied';
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
// Refused (permissions policy, no focus, no gesture): try the older way.
|
|
71
|
+
}
|
|
72
|
+
return execCopy(text, win.document) ? 'copied' : 'manual';
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* False when the frame's permissions policy rules out `clipboard-write` (itch's iframe: its
|
|
76
|
+
* `allow` list lacks it). Checked where the browser exposes the policy (Chromium), so the
|
|
77
|
+
* Clipboard API is not even tried there and no policy-violation error is logged. Elsewhere true.
|
|
78
|
+
*/
|
|
79
|
+
export function clipboardWriteAllowed(doc = document) {
|
|
80
|
+
const d = doc;
|
|
81
|
+
const policy = d.permissionsPolicy ?? d.featurePolicy;
|
|
82
|
+
try {
|
|
83
|
+
return policy?.allowsFeature ? policy.allowsFeature('clipboard-write') : true;
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/** `execCommand('copy')` from an off-screen textarea; focus goes back where it was. */
|
|
90
|
+
export function execCopy(text, doc = document) {
|
|
91
|
+
const prev = doc.activeElement;
|
|
92
|
+
const ta = doc.createElement('textarea');
|
|
93
|
+
ta.value = text;
|
|
94
|
+
ta.setAttribute('readonly', '');
|
|
95
|
+
ta.setAttribute('aria-hidden', 'true');
|
|
96
|
+
ta.setAttribute('tabindex', '-1');
|
|
97
|
+
ta.style.cssText = 'position:fixed;left:-9999px;top:0;width:1px;height:1px;opacity:0;';
|
|
98
|
+
doc.body.append(ta);
|
|
99
|
+
ta.select();
|
|
100
|
+
let ok = false;
|
|
101
|
+
try {
|
|
102
|
+
ok = typeof doc.execCommand === 'function' && doc.execCommand('copy');
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
ok = false;
|
|
106
|
+
}
|
|
107
|
+
ta.remove();
|
|
108
|
+
prev?.focus?.({ preventScroll: true });
|
|
109
|
+
return ok;
|
|
110
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Host, HostHaptics, HostInsets, HostLifecycle, HostSafeArea } from './types.js';
|
|
2
|
+
export interface WebHostOptions {
|
|
3
|
+
/** The window to act on. Default: the global `window`. Tests pass a stub. */
|
|
4
|
+
win?: Window;
|
|
5
|
+
}
|
|
6
|
+
export declare function createWebHost(opts?: WebHostOptions): Host;
|
|
7
|
+
/**
|
|
8
|
+
* The page's lifecycle as a `HostLifecycle`: `background` once the document is hidden or paged
|
|
9
|
+
* out (`pagehide`, `freeze`), `active` when it is visible again (`visibilitychange`, `pageshow`,
|
|
10
|
+
* `resume`). Each watcher sees a change only when the state differs from what it last saw.
|
|
11
|
+
*/
|
|
12
|
+
export declare function createWebLifecycle(win: Window): HostLifecycle;
|
|
13
|
+
/**
|
|
14
|
+
* Haptics over `navigator.vibrate`, when the browser has it (Android Chrome does; iOS Safari
|
|
15
|
+
* does not, so `available()` is false there and every call is a no-op). A vibrate call outside a
|
|
16
|
+
* user gesture may be refused; that is ignored.
|
|
17
|
+
*/
|
|
18
|
+
export declare function createWebHaptics(win: Window): HostHaptics;
|
|
19
|
+
/**
|
|
20
|
+
* CSS px safe-area insets of `win`'s viewport, read through a probe element padded with
|
|
21
|
+
* `env(safe-area-inset-*)` (the `--tc-safe-*` custom properties override them, for emulation).
|
|
22
|
+
* Zero when the document has no body yet or the window cannot compute styles.
|
|
23
|
+
*/
|
|
24
|
+
export declare function readSafeAreaInsets(win: Window, out: HostInsets): HostInsets;
|
|
25
|
+
/**
|
|
26
|
+
* The viewport's safe area as a `HostSafeArea`. `insets()` reads the page once and then serves
|
|
27
|
+
* the cached values until a `resize` (or `orientationchange`) invalidates them; watchers are
|
|
28
|
+
* called after a resize only when a value changed.
|
|
29
|
+
*/
|
|
30
|
+
export declare function createWebSafeArea(win: Window): HostSafeArea;
|