@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,88 @@
|
|
|
1
|
+
import type { Renderer } from '../render/renderer.js';
|
|
2
|
+
import type { AssetOf, Manifest } from './manifest.js';
|
|
3
|
+
/** What `read` resolves: the bytes, a decoded image, or bytes with the resource's full size. */
|
|
4
|
+
export type ReadResult = ArrayBuffer | Blob | ImageBitmap | {
|
|
5
|
+
data: ArrayBuffer | Blob | ImageBitmap;
|
|
6
|
+
total?: number;
|
|
7
|
+
};
|
|
8
|
+
/** The game's loader: never called twice for one uri inside one `load` batch. */
|
|
9
|
+
export type AssetReader = (uri: string) => Promise<ReadResult>;
|
|
10
|
+
/** Anything that decodes audio: an `AudioEngine` (its `context`, once unlocked) or a context. */
|
|
11
|
+
export type AudioDecoder = {
|
|
12
|
+
context: {
|
|
13
|
+
decodeAudioData(data: ArrayBuffer): Promise<AudioBuffer>;
|
|
14
|
+
} | null;
|
|
15
|
+
} | {
|
|
16
|
+
decodeAudioData(data: ArrayBuffer): Promise<AudioBuffer>;
|
|
17
|
+
};
|
|
18
|
+
export interface BundleOptions<M extends Manifest> {
|
|
19
|
+
read: AssetReader;
|
|
20
|
+
/** Needed by `texture`, `texture-array`, `gltf` and `atlas` entries. */
|
|
21
|
+
renderer?: Renderer;
|
|
22
|
+
/** Needed by `audio` entries. */
|
|
23
|
+
audio?: AudioDecoder;
|
|
24
|
+
/** Reads in flight at once (default 4). */
|
|
25
|
+
concurrency?: number;
|
|
26
|
+
/** Times a failed `read` is retried before the key fails (default 0). */
|
|
27
|
+
retries?: number;
|
|
28
|
+
/** Higher loads first (default 0 for every key). */
|
|
29
|
+
priority?: (key: keyof M & string) => number;
|
|
30
|
+
/** Reject `load` on the first failed asset and cancel the rest (default false: `errors`). */
|
|
31
|
+
strict?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* How bytes become an image for `texture`, `texture-array`, `image` and `atlas` entries
|
|
34
|
+
* (default `createImageBitmap(blob)`). Workers and tests without image decoding pass their own.
|
|
35
|
+
*/
|
|
36
|
+
decodeImage?: (blob: Blob) => Promise<ImageBitmap>;
|
|
37
|
+
}
|
|
38
|
+
export interface BundleProgress {
|
|
39
|
+
/** Assets loaded. */
|
|
40
|
+
loaded: number;
|
|
41
|
+
/** Assets that failed (counted as settled, so `fraction` still reaches 1). */
|
|
42
|
+
failed: number;
|
|
43
|
+
/** Assets requested so far through `load`. */
|
|
44
|
+
total: number;
|
|
45
|
+
/** Bytes read so far (`byteLength` of buffers, `size` of blobs). */
|
|
46
|
+
bytes: number;
|
|
47
|
+
/** Sum of the `total` sizes `read` reported, or null when it reported none. */
|
|
48
|
+
bytesTotal: number | null;
|
|
49
|
+
/** `(loaded + failed) / total`, 1 when nothing was requested. */
|
|
50
|
+
fraction: number;
|
|
51
|
+
}
|
|
52
|
+
export interface BundleError {
|
|
53
|
+
key: string;
|
|
54
|
+
/** The uri whose read or decode failed, when known. */
|
|
55
|
+
uri: string | null;
|
|
56
|
+
message: string;
|
|
57
|
+
cause: unknown;
|
|
58
|
+
}
|
|
59
|
+
export interface BundleEvents {
|
|
60
|
+
progress: BundleProgress;
|
|
61
|
+
asset: {
|
|
62
|
+
key: string;
|
|
63
|
+
asset: unknown;
|
|
64
|
+
};
|
|
65
|
+
error: BundleError;
|
|
66
|
+
/** A `load` batch finished (not emitted when it was cancelled). */
|
|
67
|
+
done: BundleProgress;
|
|
68
|
+
}
|
|
69
|
+
export interface Bundle<M extends Manifest> {
|
|
70
|
+
readonly manifest: M;
|
|
71
|
+
readonly progress: BundleProgress;
|
|
72
|
+
readonly errors: BundleError[];
|
|
73
|
+
/** True after `cancel()` until the next `load`. */
|
|
74
|
+
readonly cancelled: boolean;
|
|
75
|
+
/** Load `keys` (default every key not yet loaded or loading). Resolves when they settled. */
|
|
76
|
+
load(keys?: (keyof M & string)[]): Promise<void>;
|
|
77
|
+
/** The loaded asset; throws when the key is not loaded (naming its error if it failed). */
|
|
78
|
+
get<K extends keyof M & string>(key: K): AssetOf<M[K]>;
|
|
79
|
+
has(key: keyof M & string): boolean;
|
|
80
|
+
on<K extends keyof BundleEvents>(type: K, fn: (payload: BundleEvents[K]) => void): () => void;
|
|
81
|
+
/** Stop starting reads and decodes; in-flight reads finish but their assets are dropped. */
|
|
82
|
+
cancel(): void;
|
|
83
|
+
/** Destroy what the bundle made for `key` (or every key) and forget it. */
|
|
84
|
+
release(key?: keyof M & string): void;
|
|
85
|
+
/** Cancel, release everything and drop listeners. */
|
|
86
|
+
dispose(): void;
|
|
87
|
+
}
|
|
88
|
+
export declare function createBundle<M extends Manifest>(manifest: M, opts: BundleOptions<M>): Bundle<M>;
|
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The bundle: loads a `Manifest` through a game-supplied `read(uri)` with bounded concurrency,
|
|
3
|
+
* priorities, progress (assets and bytes), cancellation, per-key errors, retries and release.
|
|
4
|
+
* The engine never fetches (VISION rule 4): `read` is the game's `fetch`, a zip reader, an
|
|
5
|
+
* Electron file read. Decoding is the engine's: images through `createImageBitmap`, audio
|
|
6
|
+
* through the context the game passes, glTF through `parseGltf` + `loadGltf`, JSON and text
|
|
7
|
+
* directly.
|
|
8
|
+
*/
|
|
9
|
+
import { Emitter } from '../core/events.js';
|
|
10
|
+
import { loadTexture, loadTextureArray } from '../render/texture.js';
|
|
11
|
+
import { createAtlasTexture, packAtlas } from './atlas.js';
|
|
12
|
+
import { parseGltf } from './gltf.js';
|
|
13
|
+
import { loadGltf } from './gltf-load.js';
|
|
14
|
+
const GLB_MAGIC = 0x46546c67; // 'glTF'
|
|
15
|
+
class Cancelled extends Error {
|
|
16
|
+
constructor() {
|
|
17
|
+
super('bundle: cancelled');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** Bounded reads, highest priority first, insertion order among equals. */
|
|
21
|
+
class ReadGate {
|
|
22
|
+
limit;
|
|
23
|
+
active = 0;
|
|
24
|
+
seq = 0;
|
|
25
|
+
waiting = [];
|
|
26
|
+
constructor(limit) {
|
|
27
|
+
this.limit = limit;
|
|
28
|
+
}
|
|
29
|
+
acquire(priority) {
|
|
30
|
+
if (this.active < this.limit) {
|
|
31
|
+
this.active++;
|
|
32
|
+
return Promise.resolve();
|
|
33
|
+
}
|
|
34
|
+
return new Promise((resolve, reject) => {
|
|
35
|
+
this.waiting.push({ priority, seq: this.seq++, resolve, reject });
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
release() {
|
|
39
|
+
let best = -1;
|
|
40
|
+
for (let i = 0; i < this.waiting.length; i++) {
|
|
41
|
+
const w = this.waiting[i];
|
|
42
|
+
const b = best < 0 ? null : this.waiting[best];
|
|
43
|
+
if (!b || w.priority > b.priority || (w.priority === b.priority && w.seq < b.seq))
|
|
44
|
+
best = i;
|
|
45
|
+
}
|
|
46
|
+
if (best < 0) {
|
|
47
|
+
this.active--;
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const [next] = this.waiting.splice(best, 1);
|
|
51
|
+
next.resolve();
|
|
52
|
+
}
|
|
53
|
+
/** Turn every waiter away (its read never starts). */
|
|
54
|
+
drain() {
|
|
55
|
+
const w = this.waiting.splice(0);
|
|
56
|
+
for (const s of w)
|
|
57
|
+
s.reject(new Cancelled());
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async function toBuffer(data) {
|
|
61
|
+
return data instanceof Blob ? data.arrayBuffer() : data;
|
|
62
|
+
}
|
|
63
|
+
function isBitmap(x) {
|
|
64
|
+
return (typeof x === 'object' &&
|
|
65
|
+
x !== null &&
|
|
66
|
+
!(x instanceof ArrayBuffer) &&
|
|
67
|
+
!(x instanceof Blob) &&
|
|
68
|
+
'width' in x &&
|
|
69
|
+
'height' in x &&
|
|
70
|
+
!('data' in x));
|
|
71
|
+
}
|
|
72
|
+
function sizeOf(data) {
|
|
73
|
+
if (data instanceof ArrayBuffer)
|
|
74
|
+
return data.byteLength;
|
|
75
|
+
if (data instanceof Blob)
|
|
76
|
+
return data.size;
|
|
77
|
+
return 0;
|
|
78
|
+
}
|
|
79
|
+
export function createBundle(manifest, opts) {
|
|
80
|
+
return new BundleImpl(manifest, opts);
|
|
81
|
+
}
|
|
82
|
+
class BundleImpl {
|
|
83
|
+
manifest;
|
|
84
|
+
opts;
|
|
85
|
+
progress = {
|
|
86
|
+
loaded: 0,
|
|
87
|
+
failed: 0,
|
|
88
|
+
total: 0,
|
|
89
|
+
bytes: 0,
|
|
90
|
+
bytesTotal: null,
|
|
91
|
+
fraction: 1,
|
|
92
|
+
};
|
|
93
|
+
errors = [];
|
|
94
|
+
cancelled = false;
|
|
95
|
+
status = new Map();
|
|
96
|
+
assets = new Map();
|
|
97
|
+
/** Bitmaps the bundle created for `image` and `atlas` entries, closed on release. */
|
|
98
|
+
owned = new Map();
|
|
99
|
+
emitter = new Emitter();
|
|
100
|
+
gate;
|
|
101
|
+
retries;
|
|
102
|
+
cache = new Map();
|
|
103
|
+
/** Uris whose size was already counted into `bytes`/`bytesTotal`. */
|
|
104
|
+
counted = new Set();
|
|
105
|
+
inFlight = 0;
|
|
106
|
+
constructor(manifest, opts) {
|
|
107
|
+
this.manifest = manifest;
|
|
108
|
+
this.opts = opts;
|
|
109
|
+
this.gate = new ReadGate(Math.max(1, Math.floor(opts.concurrency ?? 4)));
|
|
110
|
+
this.retries = Math.max(0, Math.floor(opts.retries ?? 0));
|
|
111
|
+
for (const key of Object.keys(manifest))
|
|
112
|
+
this.status.set(key, 'idle');
|
|
113
|
+
}
|
|
114
|
+
// --------------------------------------------------------------------------------- public
|
|
115
|
+
async load(keys) {
|
|
116
|
+
this.cancelled = false;
|
|
117
|
+
const wanted = (keys ?? Object.keys(this.manifest)).filter((k) => {
|
|
118
|
+
const s = this.status.get(k);
|
|
119
|
+
if (s === undefined)
|
|
120
|
+
throw new Error(`bundle: unknown key "${k}"`);
|
|
121
|
+
return s === 'idle' || s === 'failed' || s === 'cancelled';
|
|
122
|
+
});
|
|
123
|
+
for (const k of wanted) {
|
|
124
|
+
const s = this.status.get(k);
|
|
125
|
+
if (s === 'failed') {
|
|
126
|
+
this.progress.failed--;
|
|
127
|
+
const i = this.errors.findIndex((e) => e.key === k);
|
|
128
|
+
if (i >= 0)
|
|
129
|
+
this.errors.splice(i, 1);
|
|
130
|
+
}
|
|
131
|
+
else if (s === 'idle')
|
|
132
|
+
this.progress.total++;
|
|
133
|
+
this.status.set(k, 'loading');
|
|
134
|
+
}
|
|
135
|
+
this.refresh();
|
|
136
|
+
if (wanted.length === 0) {
|
|
137
|
+
if (this.inFlight === 0 && !this.cancelled)
|
|
138
|
+
this.emitter.emit('done', this.progress);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const priority = this.opts.priority;
|
|
142
|
+
const ordered = wanted
|
|
143
|
+
.map((key, i) => ({ key, p: priority ? priority(key) : 0, i }))
|
|
144
|
+
.sort((a, b) => b.p - a.p || a.i - b.i);
|
|
145
|
+
this.inFlight += ordered.length;
|
|
146
|
+
const settled = await Promise.all(ordered.map(({ key, p }) => this.loadOne(key, p)));
|
|
147
|
+
this.inFlight -= ordered.length;
|
|
148
|
+
if (this.inFlight === 0)
|
|
149
|
+
this.cache.clear();
|
|
150
|
+
const firstError = settled.find((e) => e !== null) ?? null;
|
|
151
|
+
if (!this.cancelled && this.inFlight === 0)
|
|
152
|
+
this.emitter.emit('done', this.progress);
|
|
153
|
+
if (this.opts.strict && firstError)
|
|
154
|
+
throw firstError;
|
|
155
|
+
}
|
|
156
|
+
get(key) {
|
|
157
|
+
const s = this.status.get(key);
|
|
158
|
+
if (s === 'loaded')
|
|
159
|
+
return this.assets.get(key);
|
|
160
|
+
if (s === undefined)
|
|
161
|
+
throw new Error(`bundle: unknown key "${key}"`);
|
|
162
|
+
const err = this.errors.find((e) => e.key === key);
|
|
163
|
+
throw new Error(err ? `bundle: "${key}" failed to load: ${err.message}` : `bundle: "${key}" is not loaded`);
|
|
164
|
+
}
|
|
165
|
+
has(key) {
|
|
166
|
+
return this.status.get(key) === 'loaded';
|
|
167
|
+
}
|
|
168
|
+
on(type, fn) {
|
|
169
|
+
return this.emitter.on(type, fn);
|
|
170
|
+
}
|
|
171
|
+
cancel() {
|
|
172
|
+
this.cancelled = true;
|
|
173
|
+
this.gate.drain();
|
|
174
|
+
}
|
|
175
|
+
release(key) {
|
|
176
|
+
if (key === undefined) {
|
|
177
|
+
for (const k of Object.keys(this.manifest))
|
|
178
|
+
this.release(k);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const s = this.status.get(key);
|
|
182
|
+
if (s === undefined)
|
|
183
|
+
throw new Error(`bundle: unknown key "${key}"`);
|
|
184
|
+
if (s === 'loaded') {
|
|
185
|
+
this.destroyAsset(this.manifest[key], this.assets.get(key));
|
|
186
|
+
this.progress.loaded--;
|
|
187
|
+
this.progress.total--;
|
|
188
|
+
}
|
|
189
|
+
else if (s === 'failed') {
|
|
190
|
+
this.progress.failed--;
|
|
191
|
+
this.progress.total--;
|
|
192
|
+
const i = this.errors.findIndex((e) => e.key === key);
|
|
193
|
+
if (i >= 0)
|
|
194
|
+
this.errors.splice(i, 1);
|
|
195
|
+
}
|
|
196
|
+
else if (s === 'loading' || s === 'cancelled') {
|
|
197
|
+
// In flight: the task sees 'idle' when it finishes and destroys what it made.
|
|
198
|
+
this.progress.total--;
|
|
199
|
+
}
|
|
200
|
+
for (const b of this.owned.get(key) ?? [])
|
|
201
|
+
b.close();
|
|
202
|
+
this.owned.delete(key);
|
|
203
|
+
this.assets.delete(key);
|
|
204
|
+
this.status.set(key, 'idle');
|
|
205
|
+
this.refresh();
|
|
206
|
+
}
|
|
207
|
+
dispose() {
|
|
208
|
+
this.cancel();
|
|
209
|
+
this.release();
|
|
210
|
+
this.emitter.clear();
|
|
211
|
+
}
|
|
212
|
+
// -------------------------------------------------------------------------------- loading
|
|
213
|
+
refresh() {
|
|
214
|
+
const p = this.progress;
|
|
215
|
+
p.fraction = p.total === 0 ? 1 : (p.loaded + p.failed) / p.total;
|
|
216
|
+
this.emitter.emit('progress', p);
|
|
217
|
+
}
|
|
218
|
+
/** Resolves null on success, the error on failure (cancellation is neither). */
|
|
219
|
+
async loadOne(key, priority) {
|
|
220
|
+
const entry = this.manifest[key];
|
|
221
|
+
let uri = 'uri' in entry ? entry.uri : null;
|
|
222
|
+
try {
|
|
223
|
+
const asset = await this.decode(key, entry, priority, (u) => {
|
|
224
|
+
uri = u;
|
|
225
|
+
});
|
|
226
|
+
if (this.status.get(key) !== 'loading') {
|
|
227
|
+
// Released while loading: nothing to keep.
|
|
228
|
+
this.destroyAsset(entry, asset);
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
this.assets.set(key, asset);
|
|
232
|
+
this.status.set(key, 'loaded');
|
|
233
|
+
this.progress.loaded++;
|
|
234
|
+
this.refresh();
|
|
235
|
+
this.emitter.emit('asset', { key, asset });
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
catch (cause) {
|
|
239
|
+
if (cause instanceof Cancelled || this.status.get(key) !== 'loading') {
|
|
240
|
+
// Cancelled: still counted in `total` (so `fraction` stays below 1) until the next `load`.
|
|
241
|
+
if (this.status.get(key) === 'loading')
|
|
242
|
+
this.status.set(key, 'cancelled');
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
const err = {
|
|
246
|
+
key,
|
|
247
|
+
uri,
|
|
248
|
+
message: cause instanceof Error ? cause.message : String(cause),
|
|
249
|
+
cause,
|
|
250
|
+
};
|
|
251
|
+
this.errors.push(err);
|
|
252
|
+
this.status.set(key, 'failed');
|
|
253
|
+
this.progress.failed++;
|
|
254
|
+
this.refresh();
|
|
255
|
+
this.emitter.emit('error', err);
|
|
256
|
+
if (this.opts.strict)
|
|
257
|
+
this.cancel();
|
|
258
|
+
return err;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
checkCancelled() {
|
|
262
|
+
if (this.cancelled)
|
|
263
|
+
throw new Cancelled();
|
|
264
|
+
}
|
|
265
|
+
/** One `read` through the gate and the per-batch cache, with retries; counts bytes once per uri. */
|
|
266
|
+
async read(uri, priority) {
|
|
267
|
+
this.checkCancelled();
|
|
268
|
+
let pending = this.cache.get(uri);
|
|
269
|
+
if (!pending) {
|
|
270
|
+
pending = this.readUncached(uri, priority);
|
|
271
|
+
pending.catch(() => this.cache.delete(uri));
|
|
272
|
+
this.cache.set(uri, pending);
|
|
273
|
+
}
|
|
274
|
+
const res = await pending;
|
|
275
|
+
this.checkCancelled();
|
|
276
|
+
const data = res instanceof ArrayBuffer || res instanceof Blob || isBitmap(res) ? res : res.data;
|
|
277
|
+
if (!this.counted.has(uri)) {
|
|
278
|
+
this.counted.add(uri);
|
|
279
|
+
this.progress.bytes += sizeOf(data);
|
|
280
|
+
const total = !(res instanceof ArrayBuffer || res instanceof Blob || isBitmap(res))
|
|
281
|
+
? res.total
|
|
282
|
+
: undefined;
|
|
283
|
+
if (total !== undefined)
|
|
284
|
+
this.progress.bytesTotal = (this.progress.bytesTotal ?? 0) + total;
|
|
285
|
+
this.refresh();
|
|
286
|
+
}
|
|
287
|
+
return data;
|
|
288
|
+
}
|
|
289
|
+
async readUncached(uri, priority) {
|
|
290
|
+
await this.gate.acquire(priority);
|
|
291
|
+
try {
|
|
292
|
+
let attempt = 0;
|
|
293
|
+
for (;;) {
|
|
294
|
+
this.checkCancelled();
|
|
295
|
+
try {
|
|
296
|
+
return await this.opts.read(uri);
|
|
297
|
+
}
|
|
298
|
+
catch (e) {
|
|
299
|
+
if (attempt++ >= this.retries)
|
|
300
|
+
throw e;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
finally {
|
|
305
|
+
this.gate.release();
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
async bytes(uri, priority) {
|
|
309
|
+
const data = await this.read(uri, priority);
|
|
310
|
+
if (isBitmap(data))
|
|
311
|
+
throw new Error(`bundle: read("${uri}") returned an image, bytes needed`);
|
|
312
|
+
return toBuffer(data);
|
|
313
|
+
}
|
|
314
|
+
async bitmap(uri, priority, key) {
|
|
315
|
+
const data = await this.read(uri, priority);
|
|
316
|
+
if (isBitmap(data))
|
|
317
|
+
return data;
|
|
318
|
+
const blob = data instanceof Blob ? data : new Blob([data]);
|
|
319
|
+
const bmp = await (this.opts.decodeImage ?? defaultDecodeImage)(blob);
|
|
320
|
+
this.checkCancelled();
|
|
321
|
+
const list = this.owned.get(key) ?? [];
|
|
322
|
+
list.push(bmp);
|
|
323
|
+
this.owned.set(key, list);
|
|
324
|
+
return bmp;
|
|
325
|
+
}
|
|
326
|
+
renderer(kind, key) {
|
|
327
|
+
const r = this.opts.renderer;
|
|
328
|
+
if (!r)
|
|
329
|
+
throw new Error(`bundle: ${kind} "${key}" needs createBundle({ renderer })`);
|
|
330
|
+
return r;
|
|
331
|
+
}
|
|
332
|
+
async decode(key, entry, priority, setUri) {
|
|
333
|
+
switch (entry.kind) {
|
|
334
|
+
case 'bytes':
|
|
335
|
+
return this.bytes(entry.uri, priority);
|
|
336
|
+
case 'text':
|
|
337
|
+
return new TextDecoder().decode(await this.bytes(entry.uri, priority));
|
|
338
|
+
case 'json':
|
|
339
|
+
return JSON.parse(new TextDecoder().decode(await this.bytes(entry.uri, priority)));
|
|
340
|
+
case 'image': {
|
|
341
|
+
const bmp = await this.bitmap(entry.uri, priority, key);
|
|
342
|
+
this.owned.delete(key); // the asset itself; `release` closes it as the asset
|
|
343
|
+
return bmp;
|
|
344
|
+
}
|
|
345
|
+
case 'audio': {
|
|
346
|
+
const buf = await this.bytes(entry.uri, priority);
|
|
347
|
+
const audio = this.opts.audio;
|
|
348
|
+
const ctx = audio && 'decodeAudioData' in audio ? audio : audio?.context;
|
|
349
|
+
if (!ctx) {
|
|
350
|
+
throw new Error(`bundle: audio "${key}" needs createBundle({ audio }) with a context (an unlocked AudioEngine, or an OfflineAudioContext to decode before the first gesture)`);
|
|
351
|
+
}
|
|
352
|
+
// decodeAudioData detaches its buffer; another entry may share these bytes.
|
|
353
|
+
return ctx.decodeAudioData(buf.slice(0));
|
|
354
|
+
}
|
|
355
|
+
case 'texture': {
|
|
356
|
+
const device = this.renderer(entry.kind, key).device;
|
|
357
|
+
const bmp = await this.bitmap(entry.uri, priority, key);
|
|
358
|
+
const tex = loadTexture(device, bmp, { label: key, ...entry.options });
|
|
359
|
+
this.closeOwned(key);
|
|
360
|
+
return tex;
|
|
361
|
+
}
|
|
362
|
+
case 'texture-array': {
|
|
363
|
+
const device = this.renderer(entry.kind, key).device;
|
|
364
|
+
const bitmaps = await Promise.all(entry.uris.map((u) => {
|
|
365
|
+
setUri(u);
|
|
366
|
+
return this.bitmap(u, priority, key);
|
|
367
|
+
}));
|
|
368
|
+
const tex = loadTextureArray(device, bitmaps, { label: key, ...entry.options });
|
|
369
|
+
this.closeOwned(key);
|
|
370
|
+
return tex;
|
|
371
|
+
}
|
|
372
|
+
case 'atlas': {
|
|
373
|
+
const device = this.renderer(entry.kind, key).device;
|
|
374
|
+
const names = Object.keys(entry.uris);
|
|
375
|
+
const bitmaps = await Promise.all(names.map((n) => {
|
|
376
|
+
const u = entry.uris[n];
|
|
377
|
+
setUri(u);
|
|
378
|
+
return this.bitmap(u, priority, key);
|
|
379
|
+
}));
|
|
380
|
+
const images = {};
|
|
381
|
+
names.forEach((n, i) => {
|
|
382
|
+
images[n] = bitmaps[i];
|
|
383
|
+
});
|
|
384
|
+
const layout = packAtlas(images, entry.options);
|
|
385
|
+
const { texture, rects } = createAtlasTexture(device, layout, images, { label: key });
|
|
386
|
+
this.closeOwned(key);
|
|
387
|
+
const asset = { texture, rects, layout };
|
|
388
|
+
return asset;
|
|
389
|
+
}
|
|
390
|
+
case 'gltf': {
|
|
391
|
+
const renderer = this.renderer(entry.kind, key);
|
|
392
|
+
const mapped = (u) => entry.resources?.[u] ?? u;
|
|
393
|
+
const main = await this.bytes(entry.uri, priority);
|
|
394
|
+
const resources = {
|
|
395
|
+
...entry.options?.resources,
|
|
396
|
+
};
|
|
397
|
+
let doc;
|
|
398
|
+
if (main.byteLength >= 4 && new DataView(main).getUint32(0, true) === GLB_MAGIC) {
|
|
399
|
+
doc = parseGltf(main);
|
|
400
|
+
}
|
|
401
|
+
else {
|
|
402
|
+
// A .gltf: its external buffers must be in hand before the parse.
|
|
403
|
+
const json = JSON.parse(new TextDecoder().decode(main));
|
|
404
|
+
const bufferUris = (json.buffers ?? []).map((b) => b.uri !== undefined && !b.uri.startsWith('data:') ? b.uri : null);
|
|
405
|
+
const buffers = await Promise.all(bufferUris.map(async (u) => {
|
|
406
|
+
if (u === null)
|
|
407
|
+
return undefined;
|
|
408
|
+
const given = resources[u];
|
|
409
|
+
if (given instanceof ArrayBuffer)
|
|
410
|
+
return given;
|
|
411
|
+
setUri(mapped(u));
|
|
412
|
+
return this.bytes(mapped(u), priority);
|
|
413
|
+
}));
|
|
414
|
+
doc = parseGltf({ json, buffers: buffers });
|
|
415
|
+
// Consumed by the parse; keep them out of the image reads below.
|
|
416
|
+
for (const u of bufferUris)
|
|
417
|
+
if (u !== null)
|
|
418
|
+
resources[u] ??= new ArrayBuffer(0);
|
|
419
|
+
}
|
|
420
|
+
const external = doc.externalUris.filter((u) => !(u in resources));
|
|
421
|
+
const images = await Promise.all(external.map((u) => {
|
|
422
|
+
setUri(mapped(u));
|
|
423
|
+
return this.bytes(mapped(u), priority);
|
|
424
|
+
}));
|
|
425
|
+
external.forEach((u, i) => {
|
|
426
|
+
resources[u] = images[i];
|
|
427
|
+
});
|
|
428
|
+
setUri(entry.uri);
|
|
429
|
+
this.checkCancelled();
|
|
430
|
+
return loadGltf(renderer, doc, { label: key, ...entry.options, resources });
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
closeOwned(key) {
|
|
435
|
+
for (const b of this.owned.get(key) ?? [])
|
|
436
|
+
b.close();
|
|
437
|
+
this.owned.delete(key);
|
|
438
|
+
}
|
|
439
|
+
destroyAsset(entry, asset) {
|
|
440
|
+
switch (entry.kind) {
|
|
441
|
+
case 'texture':
|
|
442
|
+
case 'texture-array':
|
|
443
|
+
asset?.destroy();
|
|
444
|
+
break;
|
|
445
|
+
case 'gltf':
|
|
446
|
+
asset?.destroy();
|
|
447
|
+
break;
|
|
448
|
+
case 'atlas':
|
|
449
|
+
asset?.texture.destroy();
|
|
450
|
+
break;
|
|
451
|
+
case 'image':
|
|
452
|
+
asset?.close();
|
|
453
|
+
break;
|
|
454
|
+
default:
|
|
455
|
+
break;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
function defaultDecodeImage(blob) {
|
|
460
|
+
if (typeof createImageBitmap !== 'function') {
|
|
461
|
+
return Promise.reject(new Error('bundle: no createImageBitmap here; pass createBundle({ decodeImage })'));
|
|
462
|
+
}
|
|
463
|
+
return createImageBitmap(blob);
|
|
464
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The asset cache: one place that knows what a game has loaded and what it costs. Entries are
|
|
3
|
+
* keyed (a uri, usually), loaded once however many callers ask at the same time, refcounted,
|
|
4
|
+
* and sized by the caller (`size(value)`: bytes of GPU memory, of decoded data, whatever the
|
|
5
|
+
* budget counts). Once the total passes `budgetBytes`, unreferenced, unpinned entries go,
|
|
6
|
+
* least recently used first, through `onEvict` so the game frees what the value holds
|
|
7
|
+
* (`scene.destroy()`, `texture.destroy()`).
|
|
8
|
+
*
|
|
9
|
+
* The cache never fetches: `load` is the caller's, typically over the bundle's `read`
|
|
10
|
+
* (`() => read(uri).then(decode)`).
|
|
11
|
+
*/
|
|
12
|
+
export interface AssetCacheOptions<T> {
|
|
13
|
+
/** Total `size` the cache may hold before it evicts unreferenced entries. */
|
|
14
|
+
budgetBytes: number;
|
|
15
|
+
/** Called once per entry that leaves the cache (eviction or `dispose`): free it here. */
|
|
16
|
+
onEvict?: (key: string, value: T) => void;
|
|
17
|
+
}
|
|
18
|
+
/** Counters since the cache was made; `bytes` and `entries` are what it holds now. */
|
|
19
|
+
export interface AssetCacheStats {
|
|
20
|
+
/** Sum of `size` over loaded entries. */
|
|
21
|
+
bytes: number;
|
|
22
|
+
/** Entries held, loading ones included. */
|
|
23
|
+
entries: number;
|
|
24
|
+
/** `acquire` calls that found the key (loaded or loading). */
|
|
25
|
+
hits: number;
|
|
26
|
+
/** `acquire` calls that started a load. */
|
|
27
|
+
misses: number;
|
|
28
|
+
/** Entries the budget pushed out (not counting `dispose`). */
|
|
29
|
+
evictions: number;
|
|
30
|
+
}
|
|
31
|
+
export interface AssetCache<T = unknown> {
|
|
32
|
+
/**
|
|
33
|
+
* The value for `key`, loading it with `load` when the cache has none (concurrent calls for
|
|
34
|
+
* one key share one load). Each call holds one reference until `release(key)`; a held entry
|
|
35
|
+
* is never evicted. A load that rejects leaves nothing behind and rejects every waiter.
|
|
36
|
+
*/
|
|
37
|
+
acquire<V extends T>(key: string, load: () => Promise<V>, size: (value: V) => number): Promise<V>;
|
|
38
|
+
/** Drop one reference taken by `acquire`. Throws for a key with none. */
|
|
39
|
+
release(key: string): void;
|
|
40
|
+
/** Keep `key` past the budget even when unreferenced (a loading or loaded key). */
|
|
41
|
+
pin(key: string): void;
|
|
42
|
+
unpin(key: string): void;
|
|
43
|
+
/** Whether `key` is loaded or loading. */
|
|
44
|
+
has(key: string): boolean;
|
|
45
|
+
/** References `acquire` holds on `key` (0 when unknown). */
|
|
46
|
+
refs(key: string): number;
|
|
47
|
+
/**
|
|
48
|
+
* Remove an unreferenced, loaded entry now (pinned or not), through `onEvict`. False when
|
|
49
|
+
* the key is unknown or still loading; throws when references are held.
|
|
50
|
+
*/
|
|
51
|
+
dispose(key: string): boolean;
|
|
52
|
+
/** Running totals, read fresh on each access. */
|
|
53
|
+
readonly stats: AssetCacheStats;
|
|
54
|
+
}
|
|
55
|
+
/** Make an asset cache (`AssetCache`); see the module comment. */
|
|
56
|
+
export declare function createAssetCache<T = unknown>(opts: AssetCacheOptions<T>): AssetCache<T>;
|