@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,27 @@
|
|
|
1
|
+
import { createSaveStore, s } from '../save/index.js';
|
|
2
|
+
import { BUS_NAMES, DEFAULT_MIXER, sanitizeMixer, } from './audio.js';
|
|
3
|
+
const Bus = s.object({ volume: s.number({ min: 0, max: 1 }), muted: s.boolean() });
|
|
4
|
+
const Mixer = s.object(Object.fromEntries(BUS_NAMES.map((b) => [b, Bus])));
|
|
5
|
+
/**
|
|
6
|
+
* Load mixer settings from `engine/save`, apply them to `audio`, and save every change.
|
|
7
|
+
* Returns the store (check `store.persistent` to warn about non-persistent storage) and
|
|
8
|
+
* an `unbind` function.
|
|
9
|
+
*/
|
|
10
|
+
export function persistMixer(audio, opts) {
|
|
11
|
+
const store = createSaveStore({
|
|
12
|
+
game: opts.game,
|
|
13
|
+
slot: opts.slot ?? 'audio',
|
|
14
|
+
version: 1,
|
|
15
|
+
defaults: () => sanitizeMixer(DEFAULT_MIXER),
|
|
16
|
+
schema: (v) => Mixer.is(v),
|
|
17
|
+
host: opts.host,
|
|
18
|
+
storage: opts.storage,
|
|
19
|
+
debounceMs: opts.debounceMs ?? 300,
|
|
20
|
+
autoFlush: opts.autoFlush,
|
|
21
|
+
});
|
|
22
|
+
audio.applySettings(store.get());
|
|
23
|
+
const unbind = audio.onSettingsChange((next) => {
|
|
24
|
+
store.set(sanitizeMixer(next));
|
|
25
|
+
});
|
|
26
|
+
return { store, unbind };
|
|
27
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { SoundSpec } from './synth.js';
|
|
2
|
+
export interface RecipeOptions {
|
|
3
|
+
/** Base pitch in Hz (meaning varies per recipe). */
|
|
4
|
+
pitch?: number;
|
|
5
|
+
/** Overall length scale, 1 = default. */
|
|
6
|
+
length?: number;
|
|
7
|
+
/** 0..1, how much high end. Default 0.5. */
|
|
8
|
+
brightness?: number;
|
|
9
|
+
/** Seed for the random parts. */
|
|
10
|
+
seed?: number;
|
|
11
|
+
/** Peak level after normalisation. Default 0.8. */
|
|
12
|
+
level?: number;
|
|
13
|
+
}
|
|
14
|
+
/** Electric zap: a fast falling buzz with a hissing tail. */
|
|
15
|
+
export declare function zap(o?: RecipeOptions): SoundSpec;
|
|
16
|
+
/** Bell-like chime with inharmonic partials and an FM shimmer. `pitch` is the fundamental. */
|
|
17
|
+
export declare function chime(o?: RecipeOptions): SoundSpec;
|
|
18
|
+
/** Low, soft impact: a falling sine body plus a muffled noise knock. */
|
|
19
|
+
export declare function thud(o?: RecipeOptions): SoundSpec;
|
|
20
|
+
/** Short UI tick. `pitch` sets the tone (higher = lighter). */
|
|
21
|
+
export declare function click(o?: RecipeOptions): SoundSpec;
|
|
22
|
+
/** Rising (or falling) airy sweep, for transitions and panels. */
|
|
23
|
+
export declare function whoosh(o?: RecipeOptions & {
|
|
24
|
+
direction?: 'up' | 'down';
|
|
25
|
+
}): SoundSpec;
|
|
26
|
+
/** A scatter of tiny high plinks across the stereo field, like glints or magic. */
|
|
27
|
+
export declare function sparkle(o?: RecipeOptions & {
|
|
28
|
+
count?: number;
|
|
29
|
+
}): SoundSpec;
|
|
30
|
+
/**
|
|
31
|
+
* Seamless loop of crackling: sparse clicks over a faint low rumble. Fire, static, sparks.
|
|
32
|
+
* `pitch` moves the click band's centre.
|
|
33
|
+
*/
|
|
34
|
+
export declare function crackleLoop(o?: RecipeOptions & {
|
|
35
|
+
density?: number;
|
|
36
|
+
}): SoundSpec;
|
|
37
|
+
/**
|
|
38
|
+
* Seamless loop of a soft sustained chord (root, fifth, octave) with slow movement. Ambience
|
|
39
|
+
* and tension beds. Frequencies are snapped so every layer completes whole cycles per loop.
|
|
40
|
+
*/
|
|
41
|
+
export declare function dronePad(o?: RecipeOptions & {
|
|
42
|
+
chord?: readonly number[];
|
|
43
|
+
}): SoundSpec;
|
|
44
|
+
/** All recipes by name, for sound boards and data-driven sound tables. */
|
|
45
|
+
export declare const recipes: {
|
|
46
|
+
readonly zap: typeof zap;
|
|
47
|
+
readonly chime: typeof chime;
|
|
48
|
+
readonly thud: typeof thud;
|
|
49
|
+
readonly click: typeof click;
|
|
50
|
+
readonly whoosh: typeof whoosh;
|
|
51
|
+
readonly sparkle: typeof sparkle;
|
|
52
|
+
readonly crackleLoop: typeof crackleLoop;
|
|
53
|
+
readonly dronePad: typeof dronePad;
|
|
54
|
+
};
|
|
55
|
+
export type RecipeName = keyof typeof recipes;
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic named sound recipes. Each returns a `SoundSpec`; pass options to vary pitch,
|
|
3
|
+
* length, brightness or seed. Game-specific sound design builds on these or writes specs
|
|
4
|
+
* directly.
|
|
5
|
+
*/
|
|
6
|
+
import { loopSafeFreq, rng, semitones } from './dsp.js';
|
|
7
|
+
import { pluck } from './envelope.js';
|
|
8
|
+
const bright = (o) => Math.min(1, Math.max(0, o.brightness ?? 0.5));
|
|
9
|
+
/** Electric zap: a fast falling buzz with a hissing tail. */
|
|
10
|
+
export function zap(o = {}) {
|
|
11
|
+
const L = o.length ?? 1;
|
|
12
|
+
const p = o.pitch ?? 1400;
|
|
13
|
+
const b = bright(o);
|
|
14
|
+
return {
|
|
15
|
+
duration: 0.4 * L,
|
|
16
|
+
normalize: o.level ?? 0.8,
|
|
17
|
+
layers: [
|
|
18
|
+
{
|
|
19
|
+
source: { type: 'osc', wave: 'sawtooth', freq: p, freqEnd: p * 0.08, glide: 0.25 * L },
|
|
20
|
+
env: { attack: 0.002, decay: 0.3 * L, sustain: 0, release: 0.02, curve: 'exp' },
|
|
21
|
+
filter: { type: 'lowpass', freq: 3000 + 6000 * b, freqEnd: 600, q: 4 },
|
|
22
|
+
gain: 0.6,
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
source: { type: 'osc', wave: 'square', freq: p * 1.51, freqEnd: p * 0.11, glide: 0.2 * L },
|
|
26
|
+
env: pluck(0.18 * L),
|
|
27
|
+
gain: 0.25,
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
source: { type: 'noise', color: 'white', seed: o.seed ?? 7 },
|
|
31
|
+
env: { attack: 0.001, decay: 0.25 * L, sustain: 0, release: 0.02, curve: 'exp' },
|
|
32
|
+
filter: { type: 'bandpass', freq: 5000 + 3000 * b, freqEnd: 900, q: 1.2 },
|
|
33
|
+
gain: 0.5,
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/** Bell-like chime with inharmonic partials and an FM shimmer. `pitch` is the fundamental. */
|
|
39
|
+
export function chime(o = {}) {
|
|
40
|
+
const L = o.length ?? 1;
|
|
41
|
+
const f = o.pitch ?? 880;
|
|
42
|
+
const b = bright(o);
|
|
43
|
+
const ring = 1.6 * L;
|
|
44
|
+
const partials = [
|
|
45
|
+
[1, 1, ring],
|
|
46
|
+
[2.76, 0.4 * (0.5 + b), ring * 0.6],
|
|
47
|
+
[5.4, 0.2 * b, ring * 0.35],
|
|
48
|
+
[8.93, 0.08 * b, ring * 0.2],
|
|
49
|
+
];
|
|
50
|
+
const layers = partials
|
|
51
|
+
.filter(([ratio]) => f * ratio < 18000)
|
|
52
|
+
.map(([ratio, gain, decay]) => ({
|
|
53
|
+
source: { type: 'osc', wave: 'sine', freq: f * ratio },
|
|
54
|
+
env: pluck(decay, 0.003),
|
|
55
|
+
gain,
|
|
56
|
+
}));
|
|
57
|
+
layers.push({
|
|
58
|
+
source: { type: 'osc', wave: 'sine', freq: f, fm: { ratio: 3.5, index: 1.5 * b, indexEnd: 0 } },
|
|
59
|
+
env: pluck(ring * 0.5, 0.003),
|
|
60
|
+
gain: 0.3,
|
|
61
|
+
});
|
|
62
|
+
return { duration: ring + 0.05, normalize: o.level ?? 0.8, layers };
|
|
63
|
+
}
|
|
64
|
+
/** Low, soft impact: a falling sine body plus a muffled noise knock. */
|
|
65
|
+
export function thud(o = {}) {
|
|
66
|
+
const L = o.length ?? 1;
|
|
67
|
+
const p = o.pitch ?? 110;
|
|
68
|
+
const b = bright(o);
|
|
69
|
+
return {
|
|
70
|
+
duration: 0.5 * L,
|
|
71
|
+
normalize: o.level ?? 0.85,
|
|
72
|
+
layers: [
|
|
73
|
+
{
|
|
74
|
+
source: { type: 'osc', wave: 'sine', freq: p, freqEnd: p * 0.4, glide: 0.25 * L },
|
|
75
|
+
env: pluck(0.4 * L, 0.003),
|
|
76
|
+
gain: 1,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
source: { type: 'noise', color: 'brown', seed: o.seed ?? 3 },
|
|
80
|
+
env: pluck(0.08 * L, 0.001),
|
|
81
|
+
filter: { type: 'lowpass', freq: 300 + 1500 * b, q: 0.7 },
|
|
82
|
+
gain: 0.7,
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/** Short UI tick. `pitch` sets the tone (higher = lighter). */
|
|
88
|
+
export function click(o = {}) {
|
|
89
|
+
const p = o.pitch ?? 1800;
|
|
90
|
+
const b = bright(o);
|
|
91
|
+
return {
|
|
92
|
+
duration: 0.06 * (o.length ?? 1),
|
|
93
|
+
normalize: o.level ?? 0.6,
|
|
94
|
+
layers: [
|
|
95
|
+
{
|
|
96
|
+
source: { type: 'osc', wave: 'triangle', freq: p, freqEnd: p * 0.7 },
|
|
97
|
+
env: pluck(0.03, 0.001),
|
|
98
|
+
gain: 0.8,
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
source: { type: 'noise', color: 'white', seed: o.seed ?? 11 },
|
|
102
|
+
env: pluck(0.01, 0.0005),
|
|
103
|
+
filter: { type: 'highpass', freq: 2000 + 4000 * b },
|
|
104
|
+
gain: 0.4 * (0.5 + b),
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/** Rising (or falling) airy sweep, for transitions and panels. */
|
|
110
|
+
export function whoosh(o = {}) {
|
|
111
|
+
const L = o.length ?? 1;
|
|
112
|
+
const b = bright(o);
|
|
113
|
+
const lo = 250;
|
|
114
|
+
const hi = 1800 + 3000 * b;
|
|
115
|
+
const up = (o.direction ?? 'up') === 'up';
|
|
116
|
+
return {
|
|
117
|
+
duration: 0.7 * L,
|
|
118
|
+
normalize: o.level ?? 0.7,
|
|
119
|
+
layers: [
|
|
120
|
+
{
|
|
121
|
+
source: { type: 'noise', color: 'pink', seed: o.seed ?? 5 },
|
|
122
|
+
env: { attack: 0.3 * L, decay: 0.3 * L, sustain: 0, release: 0.05, curve: 'linear' },
|
|
123
|
+
filter: { type: 'bandpass', freq: up ? lo : hi, freqEnd: up ? hi : lo, q: 1.5 },
|
|
124
|
+
gain: 1,
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/** A scatter of tiny high plinks across the stereo field, like glints or magic. */
|
|
130
|
+
export function sparkle(o = {}) {
|
|
131
|
+
const L = o.length ?? 1;
|
|
132
|
+
const rand = rng(o.seed ?? 21);
|
|
133
|
+
const base = o.pitch ?? 1760;
|
|
134
|
+
const scale = [0, 2, 4, 7, 9, 12, 14, 16, 19];
|
|
135
|
+
const count = o.count ?? 9;
|
|
136
|
+
const span = 0.5 * L;
|
|
137
|
+
const layers = [];
|
|
138
|
+
for (let i = 0; i < count; i++) {
|
|
139
|
+
const st = scale[Math.floor(rand() * scale.length)];
|
|
140
|
+
layers.push({
|
|
141
|
+
source: { type: 'osc', wave: 'sine', freq: semitones(base, st) },
|
|
142
|
+
env: pluck(0.12 + 0.15 * rand(), 0.002),
|
|
143
|
+
start: (i / count) * span * (0.7 + 0.3 * rand()),
|
|
144
|
+
gain: 0.35 + 0.4 * rand(),
|
|
145
|
+
pan: rand() * 1.6 - 0.8,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
return { duration: span + 0.35, normalize: o.level ?? 0.7, channels: 2, layers };
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Seamless loop of crackling: sparse clicks over a faint low rumble. Fire, static, sparks.
|
|
152
|
+
* `pitch` moves the click band's centre.
|
|
153
|
+
*/
|
|
154
|
+
export function crackleLoop(o = {}) {
|
|
155
|
+
const dur = 4 * (o.length ?? 1);
|
|
156
|
+
const b = bright(o);
|
|
157
|
+
const hold = { attack: 0.005, decay: 0, sustain: 1, release: 0.01, curve: 'linear' };
|
|
158
|
+
return {
|
|
159
|
+
duration: dur,
|
|
160
|
+
loop: { crossfade: 0.25 },
|
|
161
|
+
normalize: o.level ?? 0.6,
|
|
162
|
+
layers: [
|
|
163
|
+
{
|
|
164
|
+
source: { type: 'crackle', density: o.density ?? 25, seed: o.seed ?? 13 },
|
|
165
|
+
env: hold,
|
|
166
|
+
filter: { type: 'bandpass', freq: o.pitch ?? 1500 + 2500 * b, q: 0.6 },
|
|
167
|
+
gain: 1,
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
source: { type: 'noise', color: 'brown', seed: (o.seed ?? 13) + 1 },
|
|
171
|
+
env: hold,
|
|
172
|
+
filter: { type: 'lowpass', freq: 220 },
|
|
173
|
+
gain: 0.25,
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Seamless loop of a soft sustained chord (root, fifth, octave) with slow movement. Ambience
|
|
180
|
+
* and tension beds. Frequencies are snapped so every layer completes whole cycles per loop.
|
|
181
|
+
*/
|
|
182
|
+
export function dronePad(o = {}) {
|
|
183
|
+
const dur = 8 * (o.length ?? 1);
|
|
184
|
+
const root = o.pitch ?? 110;
|
|
185
|
+
const b = bright(o);
|
|
186
|
+
const chord = o.chord ?? [0, 7, 12];
|
|
187
|
+
const hold = { attack: 0.005, decay: 0, sustain: 1, release: 0.01, curve: 'linear' };
|
|
188
|
+
const layers = [];
|
|
189
|
+
chord.forEach((st, i) => {
|
|
190
|
+
const f = semitones(root, st);
|
|
191
|
+
for (const [k, detune] of [
|
|
192
|
+
[0, 1],
|
|
193
|
+
[1, 1.004],
|
|
194
|
+
]) {
|
|
195
|
+
layers.push({
|
|
196
|
+
source: {
|
|
197
|
+
type: 'osc',
|
|
198
|
+
wave: k === 0 ? 'sawtooth' : 'triangle',
|
|
199
|
+
freq: loopSafeFreq(f * detune, dur),
|
|
200
|
+
},
|
|
201
|
+
env: hold,
|
|
202
|
+
filter: { type: 'lowpass', freq: 500 + 1500 * b, q: 0.5 },
|
|
203
|
+
gain: (k === 0 ? 0.35 : 0.5) / (1 + i * 0.4),
|
|
204
|
+
tremolo: { rate: loopSafeFreq(0.125 * (i + 1), dur), depth: 0.3 },
|
|
205
|
+
pan: chord.length > 1 ? ((i / (chord.length - 1)) * 2 - 1) * 0.5 * (k === 0 ? 1 : -1) : 0,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
return {
|
|
210
|
+
duration: dur,
|
|
211
|
+
loop: { crossfade: 0.5 },
|
|
212
|
+
normalize: o.level ?? 0.5,
|
|
213
|
+
channels: 2,
|
|
214
|
+
layers,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
/** All recipes by name, for sound boards and data-driven sound tables. */
|
|
218
|
+
export const recipes = {
|
|
219
|
+
zap,
|
|
220
|
+
chime,
|
|
221
|
+
thud,
|
|
222
|
+
click,
|
|
223
|
+
whoosh,
|
|
224
|
+
sparkle,
|
|
225
|
+
crackleLoop,
|
|
226
|
+
dronePad,
|
|
227
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An effect send: a parallel path from one bus through a reverb (`ConvolverNode` on a
|
|
3
|
+
* procedural impulse) or a lowpass (`BiquadFilterNode`) back into master. A zone drives
|
|
4
|
+
* `amount` (and `cutoff`) as the listener moves. Built with the context; safe before unlock.
|
|
5
|
+
*/
|
|
6
|
+
import type { AudioEngine, OutputBus } from './audio.js';
|
|
7
|
+
export type SendKind = 'reverb' | 'lowpass';
|
|
8
|
+
export interface SendOptions {
|
|
9
|
+
kind: SendKind;
|
|
10
|
+
/** Bus whose signal feeds the send. Default `sfx`. */
|
|
11
|
+
bus?: OutputBus;
|
|
12
|
+
/** Starting send level 0..1. Default 0 (silent until a zone raises it). */
|
|
13
|
+
amount?: number;
|
|
14
|
+
/** Reverb: impulse length in seconds. Default 2. */
|
|
15
|
+
seconds?: number;
|
|
16
|
+
/** Reverb: tail shape, `(1 - t)^decay`. Default 3. */
|
|
17
|
+
decay?: number;
|
|
18
|
+
/** Reverb: impulse noise seed. Default 1. */
|
|
19
|
+
seed?: number;
|
|
20
|
+
/** Lowpass: starting cutoff in Hz. Default 800. */
|
|
21
|
+
cutoff?: number;
|
|
22
|
+
/** Lowpass: resonance. Default 0.7. */
|
|
23
|
+
q?: number;
|
|
24
|
+
}
|
|
25
|
+
export interface Send {
|
|
26
|
+
readonly kind: SendKind;
|
|
27
|
+
/** Send level 0..1 (linear, ramped over ~15 ms). */
|
|
28
|
+
amount: number;
|
|
29
|
+
/** Lowpass cutoff in Hz (ramped). Undefined on a reverb send. */
|
|
30
|
+
cutoff: number | undefined;
|
|
31
|
+
/** The effect node (`ConvolverNode` or `BiquadFilterNode`), once the context exists. */
|
|
32
|
+
readonly node: ConvolverNode | BiquadFilterNode | null;
|
|
33
|
+
/**
|
|
34
|
+
* The send's input gain. Anything with `connect` (a voice's own node, another bus) can feed it
|
|
35
|
+
* directly; the source bus is connected for you.
|
|
36
|
+
*/
|
|
37
|
+
readonly input: GainNode | null;
|
|
38
|
+
/** Disconnect everything. */
|
|
39
|
+
dispose(): void;
|
|
40
|
+
}
|
|
41
|
+
export declare function createSend(mixer: AudioEngine, opts: SendOptions): Send;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { impulseResponse } from './dsp.js';
|
|
2
|
+
export function createSend(mixer, opts) {
|
|
3
|
+
const kind = opts.kind;
|
|
4
|
+
const bus = opts.bus ?? 'sfx';
|
|
5
|
+
let amount = clamp01(opts.amount ?? 0);
|
|
6
|
+
let cutoff = Math.max(10, opts.cutoff ?? 800);
|
|
7
|
+
const q = opts.q ?? 0.7;
|
|
8
|
+
let input = null;
|
|
9
|
+
let node = null;
|
|
10
|
+
let ret = null;
|
|
11
|
+
let builtOn = null;
|
|
12
|
+
let unsub = null;
|
|
13
|
+
let disposed = false;
|
|
14
|
+
function build() {
|
|
15
|
+
const ctx = mixer.context;
|
|
16
|
+
const from = mixer.busNode(bus);
|
|
17
|
+
const master = mixer.busNode('master');
|
|
18
|
+
if (disposed || !ctx || !from || !master || builtOn === ctx)
|
|
19
|
+
return;
|
|
20
|
+
let effect;
|
|
21
|
+
if (kind === 'reverb') {
|
|
22
|
+
if (typeof ctx.createConvolver !== 'function')
|
|
23
|
+
return;
|
|
24
|
+
const c = ctx.createConvolver();
|
|
25
|
+
c.normalize = true;
|
|
26
|
+
c.buffer = impulseResponse(ctx, {
|
|
27
|
+
seconds: opts.seconds,
|
|
28
|
+
decay: opts.decay,
|
|
29
|
+
seed: opts.seed,
|
|
30
|
+
});
|
|
31
|
+
effect = c;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
if (typeof ctx.createBiquadFilter !== 'function')
|
|
35
|
+
return;
|
|
36
|
+
const f = ctx.createBiquadFilter();
|
|
37
|
+
f.type = 'lowpass';
|
|
38
|
+
f.frequency.value = cutoff;
|
|
39
|
+
f.Q.value = q;
|
|
40
|
+
effect = f;
|
|
41
|
+
}
|
|
42
|
+
const g = ctx.createGain();
|
|
43
|
+
g.gain.value = amount;
|
|
44
|
+
const r = ctx.createGain();
|
|
45
|
+
r.gain.value = 1;
|
|
46
|
+
from.connect(g);
|
|
47
|
+
g.connect(effect);
|
|
48
|
+
effect.connect(r);
|
|
49
|
+
r.connect(master);
|
|
50
|
+
input = g;
|
|
51
|
+
node = effect;
|
|
52
|
+
ret = r;
|
|
53
|
+
builtOn = ctx;
|
|
54
|
+
}
|
|
55
|
+
function teardown() {
|
|
56
|
+
const from = mixer.busNode(bus);
|
|
57
|
+
if (input) {
|
|
58
|
+
try {
|
|
59
|
+
from?.disconnect(input);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
// Not connected (context replaced).
|
|
63
|
+
}
|
|
64
|
+
input.disconnect();
|
|
65
|
+
}
|
|
66
|
+
node?.disconnect();
|
|
67
|
+
ret?.disconnect();
|
|
68
|
+
input = null;
|
|
69
|
+
node = null;
|
|
70
|
+
ret = null;
|
|
71
|
+
builtOn = null;
|
|
72
|
+
}
|
|
73
|
+
build();
|
|
74
|
+
if (!builtOn) {
|
|
75
|
+
unsub = mixer.onStateChange((s) => {
|
|
76
|
+
if (s === 'running')
|
|
77
|
+
build();
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
kind,
|
|
82
|
+
get amount() {
|
|
83
|
+
return amount;
|
|
84
|
+
},
|
|
85
|
+
set amount(v) {
|
|
86
|
+
amount = clamp01(v);
|
|
87
|
+
const ctx = mixer.context;
|
|
88
|
+
if (input && ctx)
|
|
89
|
+
input.gain.setTargetAtTime(amount, ctx.currentTime, 0.015);
|
|
90
|
+
},
|
|
91
|
+
get cutoff() {
|
|
92
|
+
return kind === 'lowpass' ? cutoff : undefined;
|
|
93
|
+
},
|
|
94
|
+
set cutoff(v) {
|
|
95
|
+
if (kind !== 'lowpass' || v === undefined)
|
|
96
|
+
return;
|
|
97
|
+
cutoff = Math.max(10, Number.isFinite(v) ? v : cutoff);
|
|
98
|
+
const ctx = mixer.context;
|
|
99
|
+
if (node && ctx)
|
|
100
|
+
node.frequency.setTargetAtTime(cutoff, ctx.currentTime, 0.015);
|
|
101
|
+
},
|
|
102
|
+
get node() {
|
|
103
|
+
return node;
|
|
104
|
+
},
|
|
105
|
+
get input() {
|
|
106
|
+
return input;
|
|
107
|
+
},
|
|
108
|
+
dispose() {
|
|
109
|
+
disposed = true;
|
|
110
|
+
unsub?.();
|
|
111
|
+
unsub = null;
|
|
112
|
+
teardown();
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function clamp01(v) {
|
|
117
|
+
return Math.min(1, Math.max(0, Number.isFinite(v) ? v : 0));
|
|
118
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audio sprites (ws/audio-4): one buffer, many named ranges. `audio.defineSprites(name, sheet)`
|
|
3
|
+
* registers the sheet; `audio.play('name#clip')` then plays one range with the usual `Voice`
|
|
4
|
+
* surface, and `audio.loop('name#clip')` loops it between its `loopPoints` (or the whole
|
|
5
|
+
* range). This file is the pure part: the reference syntax, the range arithmetic and the JSON
|
|
6
|
+
* sidecar shape. Nothing here touches a node.
|
|
7
|
+
*/
|
|
8
|
+
/** `[startMs, lengthMs]` of one clip inside the sheet's buffer. */
|
|
9
|
+
export type SpriteRange = readonly [startMs: number, lengthMs: number];
|
|
10
|
+
/** What `audio.defineSprites` takes. */
|
|
11
|
+
export interface SpriteSheet {
|
|
12
|
+
/** The decoded buffer every clip is a range of. */
|
|
13
|
+
buffer?: AudioBuffer;
|
|
14
|
+
/**
|
|
15
|
+
* Or a factory that produces it (the game's own fetch and decode, so the engine makes no
|
|
16
|
+
* network call: a bundle `audio` entry, `fetch` + `decodeAudioData`). Rendered lazily, or by
|
|
17
|
+
* `audio.prepare`.
|
|
18
|
+
*/
|
|
19
|
+
source?: () => Promise<AudioBuffer>;
|
|
20
|
+
/** Clip name → `[startMs, lengthMs]`. */
|
|
21
|
+
sprites: Readonly<Record<string, SpriteRange>>;
|
|
22
|
+
/**
|
|
23
|
+
* Clip name → `[startMs, endMs]` inside the clip, the section `audio.loop('name#clip')` repeats
|
|
24
|
+
* once it has played into it (an intro before a loop). A clip without one loops its whole range.
|
|
25
|
+
*/
|
|
26
|
+
loopPoints?: Readonly<Record<string, readonly [startMs: number, endMs: number]>>;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The JSON sidecar a sprite packer writes next to its audio file: `src` names the audio file
|
|
30
|
+
* (relative to the sidecar), `sprites` and `loopPoints` are as in `SpriteSheet`. Load it as a
|
|
31
|
+
* bundle `json` entry and the audio as an `audio` entry, then `spriteSheetFrom(sidecar, buffer)`.
|
|
32
|
+
*/
|
|
33
|
+
export interface SpriteSidecar {
|
|
34
|
+
src: string;
|
|
35
|
+
sprites: Readonly<Record<string, SpriteRange>>;
|
|
36
|
+
loopPoints?: Readonly<Record<string, readonly [number, number]>>;
|
|
37
|
+
}
|
|
38
|
+
/** A sidecar plus its decoded buffer as a `SpriteSheet` for `audio.defineSprites`. */
|
|
39
|
+
export declare function spriteSheetFrom(sidecar: SpriteSidecar, buffer: AudioBuffer): SpriteSheet;
|
|
40
|
+
/** What a sprite voice schedules: `start(when, offset, duration)` or a loop between two points. */
|
|
41
|
+
export interface SpriteSchedule {
|
|
42
|
+
/** Seconds into the buffer the clip starts. */
|
|
43
|
+
offset: number;
|
|
44
|
+
/** Seconds the clip plays (a one-shot). */
|
|
45
|
+
duration: number;
|
|
46
|
+
/** Seconds into the buffer the loop section runs between (a loop). */
|
|
47
|
+
loopStart: number;
|
|
48
|
+
loopEnd: number;
|
|
49
|
+
}
|
|
50
|
+
/** Splits `name#clip`; null for a plain sound name. */
|
|
51
|
+
export declare function parseSpriteRef(ref: string): {
|
|
52
|
+
sheet: string;
|
|
53
|
+
clip: string;
|
|
54
|
+
} | null;
|
|
55
|
+
/**
|
|
56
|
+
* The schedule of `clip` in `sheet`, in seconds. Throws a readable error for a clip the sheet
|
|
57
|
+
* does not define. Writes `out` and returns it (no allocation when one is passed).
|
|
58
|
+
*/
|
|
59
|
+
export declare function spriteSchedule(sheet: SpriteSheet, sheetName: string, clip: string, out?: SpriteSchedule): SpriteSchedule;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audio sprites (ws/audio-4): one buffer, many named ranges. `audio.defineSprites(name, sheet)`
|
|
3
|
+
* registers the sheet; `audio.play('name#clip')` then plays one range with the usual `Voice`
|
|
4
|
+
* surface, and `audio.loop('name#clip')` loops it between its `loopPoints` (or the whole
|
|
5
|
+
* range). This file is the pure part: the reference syntax, the range arithmetic and the JSON
|
|
6
|
+
* sidecar shape. Nothing here touches a node.
|
|
7
|
+
*/
|
|
8
|
+
/** A sidecar plus its decoded buffer as a `SpriteSheet` for `audio.defineSprites`. */
|
|
9
|
+
export function spriteSheetFrom(sidecar, buffer) {
|
|
10
|
+
return { buffer, sprites: sidecar.sprites, loopPoints: sidecar.loopPoints };
|
|
11
|
+
}
|
|
12
|
+
/** Splits `name#clip`; null for a plain sound name. */
|
|
13
|
+
export function parseSpriteRef(ref) {
|
|
14
|
+
const i = ref.indexOf('#');
|
|
15
|
+
if (i < 0)
|
|
16
|
+
return null;
|
|
17
|
+
return { sheet: ref.slice(0, i), clip: ref.slice(i + 1) };
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The schedule of `clip` in `sheet`, in seconds. Throws a readable error for a clip the sheet
|
|
21
|
+
* does not define. Writes `out` and returns it (no allocation when one is passed).
|
|
22
|
+
*/
|
|
23
|
+
export function spriteSchedule(sheet, sheetName, clip, out = { offset: 0, duration: 0, loopStart: 0, loopEnd: 0 }) {
|
|
24
|
+
const range = sheet.sprites[clip];
|
|
25
|
+
if (!range) {
|
|
26
|
+
const known = Object.keys(sheet.sprites).join(', ') || '(none)';
|
|
27
|
+
throw new Error(`[audio] sprite sheet "${sheetName}" has no clip "${clip}" (clips: ${known})`);
|
|
28
|
+
}
|
|
29
|
+
const start = Math.max(0, range[0]) / 1000;
|
|
30
|
+
const length = Math.max(0, range[1]) / 1000;
|
|
31
|
+
out.offset = start;
|
|
32
|
+
out.duration = length;
|
|
33
|
+
const lp = sheet.loopPoints?.[clip];
|
|
34
|
+
if (lp) {
|
|
35
|
+
out.loopStart = start + Math.max(0, lp[0]) / 1000;
|
|
36
|
+
out.loopEnd = start + Math.min(length * 1000, Math.max(lp[0], lp[1])) / 1000;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
out.loopStart = start;
|
|
40
|
+
out.loopEnd = start + length;
|
|
41
|
+
}
|
|
42
|
+
return out;
|
|
43
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Procedural synth: a declarative `SoundSpec` (layers of oscillators / noise / crackle, each
|
|
3
|
+
* with an envelope, optional glide, FM, vibrato, tremolo and filters) rendered once into an
|
|
4
|
+
* `AudioBuffer` with an `OfflineAudioContext`. Specs are plain data: easy to tweak, diff and test.
|
|
5
|
+
*/
|
|
6
|
+
import { type NoiseColor } from './dsp.js';
|
|
7
|
+
import { type Envelope } from './envelope.js';
|
|
8
|
+
export type Wave = 'sine' | 'square' | 'sawtooth' | 'triangle';
|
|
9
|
+
export interface OscSource {
|
|
10
|
+
type: 'osc';
|
|
11
|
+
wave: Wave;
|
|
12
|
+
/** Start frequency, Hz. */
|
|
13
|
+
freq: number;
|
|
14
|
+
/** Glide target, Hz. */
|
|
15
|
+
freqEnd?: number;
|
|
16
|
+
/** Glide time, seconds from layer start. Default: the layer's whole envelope. */
|
|
17
|
+
glide?: number;
|
|
18
|
+
/** Default `exp` (musical pitch sweep). */
|
|
19
|
+
glideCurve?: 'exp' | 'linear';
|
|
20
|
+
/** Cents. */
|
|
21
|
+
detune?: number;
|
|
22
|
+
/** Pitch wobble: `rate` Hz, `depth` cents. */
|
|
23
|
+
vibrato?: {
|
|
24
|
+
rate: number;
|
|
25
|
+
depth: number;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Frequency modulation (bells, metallic tones): modulator at `freq * ratio`, deviation
|
|
29
|
+
* `index * freq` Hz, ramping to `indexEnd` over the envelope.
|
|
30
|
+
*/
|
|
31
|
+
fm?: {
|
|
32
|
+
ratio: number;
|
|
33
|
+
index: number;
|
|
34
|
+
indexEnd?: number;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export interface NoiseSource {
|
|
38
|
+
type: 'noise';
|
|
39
|
+
color: NoiseColor;
|
|
40
|
+
seed?: number;
|
|
41
|
+
}
|
|
42
|
+
export interface CrackleSource {
|
|
43
|
+
type: 'crackle';
|
|
44
|
+
/** Average clicks per second. */
|
|
45
|
+
density: number;
|
|
46
|
+
seed?: number;
|
|
47
|
+
/** Seconds each click rings. Default 0.004. */
|
|
48
|
+
clickDecay?: number;
|
|
49
|
+
}
|
|
50
|
+
export type Source = OscSource | NoiseSource | CrackleSource;
|
|
51
|
+
export interface FilterSpec {
|
|
52
|
+
type: BiquadFilterType;
|
|
53
|
+
/** Cutoff/centre Hz. */
|
|
54
|
+
freq: number;
|
|
55
|
+
/** Sweep target Hz (exponential, over the layer's envelope). */
|
|
56
|
+
freqEnd?: number;
|
|
57
|
+
q?: number;
|
|
58
|
+
/** dB, for shelf/peaking types. */
|
|
59
|
+
gain?: number;
|
|
60
|
+
}
|
|
61
|
+
export interface Layer {
|
|
62
|
+
source: Source;
|
|
63
|
+
env: Envelope;
|
|
64
|
+
/** Peak gain of this layer. Default 1. */
|
|
65
|
+
gain?: number;
|
|
66
|
+
/** Seconds after the sound starts. Default 0. */
|
|
67
|
+
start?: number;
|
|
68
|
+
/** Seconds from layer start to note-off. Default: as long as fits before `duration`. */
|
|
69
|
+
gate?: number;
|
|
70
|
+
/** -1..1. Makes the render stereo. */
|
|
71
|
+
pan?: number;
|
|
72
|
+
filter?: FilterSpec | readonly FilterSpec[];
|
|
73
|
+
/** Amplitude wobble: `rate` Hz, `depth` 0..1. */
|
|
74
|
+
tremolo?: {
|
|
75
|
+
rate: number;
|
|
76
|
+
depth: number;
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
export interface SoundSpec {
|
|
80
|
+
/** Seconds. For loops, the loop length. */
|
|
81
|
+
duration: number;
|
|
82
|
+
layers: readonly Layer[];
|
|
83
|
+
/** Master gain applied before normalisation. Default 1. */
|
|
84
|
+
gain?: number;
|
|
85
|
+
/** Peak-normalise to this level (e.g. 0.8). Default: no normalisation. */
|
|
86
|
+
normalize?: number;
|
|
87
|
+
/** Default 44100. */
|
|
88
|
+
sampleRate?: number;
|
|
89
|
+
/** Default: 2 if any layer pans, else 1. */
|
|
90
|
+
channels?: 1 | 2;
|
|
91
|
+
/** Render `crossfade` extra seconds and fold them into the head for a seamless loop. */
|
|
92
|
+
loop?: {
|
|
93
|
+
crossfade: number;
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
/** Default gate: note-off early enough for the release to finish inside `duration`. */
|
|
97
|
+
export declare function layerGate(layer: Layer, duration: number): number;
|
|
98
|
+
export declare function specChannels(spec: SoundSpec): 1 | 2;
|
|
99
|
+
/** Problems with a spec, or an empty array. Used by tests and in dev before rendering. */
|
|
100
|
+
export declare function validateSpec(spec: SoundSpec): string[];
|
|
101
|
+
export type OfflineContextFactory = (channels: number, length: number, sampleRate: number) => OfflineAudioContext;
|
|
102
|
+
/** Render a spec to an `AudioBuffer`. Rendering needs no user gesture. */
|
|
103
|
+
export declare function renderSound(spec: SoundSpec, createOffline?: OfflineContextFactory): Promise<AudioBuffer>;
|