@downdraft/engine 0.0.0 → 0.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/app/src/index.ts +10 -0
- package/app/src/renderer/bootstrap.ts +271 -0
- package/app/src/renderer/downdraft-base.css +93 -0
- package/app/src/renderer/feature-log.ts +200 -0
- package/app/src/renderer/game-module.ts +923 -0
- package/app/src/renderer/hooks.ts +88 -0
- package/app/src/renderer/hot-reload.ts +178 -0
- package/app/src/renderer/import-cache.ts +88 -0
- package/app/src/renderer/index.ts +206 -0
- package/app/src/renderer/mcp-harness.ts +144 -0
- package/app/src/renderer/save-store-factory.ts +239 -0
- package/app/src/renderer/sim-bridge.ts +183 -0
- package/app/src/renderer/standard-automation-tools.ts +771 -0
- package/app/src/shared/feature-log.ts +71 -0
- package/app/src/shared/gpu-info.ts +82 -0
- package/app/src/shared/import-cache-store.ts +142 -0
- package/app/src/shared/index.ts +6 -0
- package/app/src/shared/mcp-discovery.ts +47 -0
- package/app/src/shared/mcp-proxy.ts +82 -0
- package/app/src/shared/types.ts +324 -0
- package/asset-bake/src/bake-audio.ts +119 -0
- package/asset-bake/src/bake-gltf.ts +172 -0
- package/asset-bake/src/bake.ts +78 -0
- package/asset-bake/src/cache.ts +188 -0
- package/asset-bake/src/config.ts +186 -0
- package/asset-bake/src/index.ts +36 -0
- package/core/src/animation/animation-event.ts +41 -0
- package/core/src/animation/bone-mask.ts +122 -0
- package/core/src/animation/clip.ts +252 -0
- package/core/src/animation/index.ts +22 -0
- package/core/src/animation/mixamo.ts +113 -0
- package/core/src/animation/morph-target.ts +69 -0
- package/core/src/animation/player.ts +697 -0
- package/core/src/animation/retarget.ts +158 -0
- package/core/src/animation/skeleton-animator.ts +1399 -0
- package/core/src/animation/skeleton.ts +214 -0
- package/core/src/animation/state-machine.ts +280 -0
- package/core/src/assets/blob-store.ts +66 -0
- package/core/src/assets/cache.ts +186 -0
- package/core/src/assets/cubemap-converter.ts +155 -0
- package/core/src/assets/environment-manager.ts +121 -0
- package/core/src/assets/import-cache.ts +65 -0
- package/core/src/assets/import-settings.ts +72 -0
- package/core/src/assets/importer.ts +108 -0
- package/core/src/assets/index.ts +74 -0
- package/core/src/assets/irradiance-generator.ts +198 -0
- package/core/src/assets/loader-audio.ts +86 -0
- package/core/src/assets/loader-cubemap.ts +211 -0
- package/core/src/assets/loader-dds.ts +236 -0
- package/core/src/assets/loader-hdr.ts +474 -0
- package/core/src/assets/loader-mesh.ts +143 -0
- package/core/src/assets/loader-shader.ts +73 -0
- package/core/src/assets/loader-texture.ts +349 -0
- package/core/src/assets/lod.ts +198 -0
- package/core/src/assets/manager.ts +480 -0
- package/core/src/assets/manifest.ts +81 -0
- package/core/src/assets/material-bridge.ts +186 -0
- package/core/src/assets/model-importer.ts +72 -0
- package/core/src/assets/model-normalizer.ts +248 -0
- package/core/src/assets/model-to-gpu.ts +70 -0
- package/core/src/assets/model-to-mesh.ts +237 -0
- package/core/src/assets/prefilter-generator.ts +250 -0
- package/core/src/audio/engine.ts +177 -0
- package/core/src/audio/interface.ts +130 -0
- package/core/src/audio/listener.ts +32 -0
- package/core/src/audio/mixer.ts +141 -0
- package/core/src/audio/registry.ts +52 -0
- package/core/src/audio/sab.ts +87 -0
- package/core/src/audio/source.ts +89 -0
- package/core/src/change-detection/atomics.ts +1 -0
- package/core/src/change-detection/tracker.ts +47 -0
- package/core/src/debug-draw/lines.ts +64 -0
- package/core/src/debug-draw/points.ts +17 -0
- package/core/src/debug-draw/queue.ts +124 -0
- package/core/src/debug-draw/text.ts +25 -0
- package/core/src/ecs/archetype.ts +323 -0
- package/core/src/ecs/component.ts +188 -0
- package/core/src/ecs/entity.ts +25 -0
- package/core/src/ecs/events.ts +93 -0
- package/core/src/ecs/hierarchy.ts +124 -0
- package/core/src/ecs/hmr-swap-registry.ts +22 -0
- package/core/src/ecs/index.ts +25 -0
- package/core/src/ecs/query.ts +141 -0
- package/core/src/ecs/resource.ts +8 -0
- package/core/src/ecs/schedule.ts +181 -0
- package/core/src/ecs/system-params.ts +99 -0
- package/core/src/ecs/system.ts +42 -0
- package/core/src/ecs/world.ts +348 -0
- package/core/src/index.ts +352 -0
- package/core/src/input/context.ts +73 -0
- package/core/src/input/dom-handler.ts +380 -0
- package/core/src/input/local-player-manager.ts +218 -0
- package/core/src/input/mapping.ts +40 -0
- package/core/src/input/multi-sab-bridge.ts +276 -0
- package/core/src/input/multi-state.ts +54 -0
- package/core/src/input/sab-bridge.ts +71 -0
- package/core/src/input/state.ts +132 -0
- package/core/src/input/ui-router.ts +87 -0
- package/core/src/library/host.ts +317 -0
- package/core/src/library/index.ts +16 -0
- package/core/src/library/library.ts +292 -0
- package/core/src/material/compiler.ts +80 -0
- package/core/src/material/graph-bridge.ts +172 -0
- package/core/src/material/index.ts +9 -0
- package/core/src/material/library.ts +442 -0
- package/core/src/material/material.ts +156 -0
- package/core/src/material/variants.ts +61 -0
- package/core/src/math/mat4.ts +202 -0
- package/core/src/math/perlin-noise-2d.ts +77 -0
- package/core/src/math/perlin-noise-3d.ts +110 -0
- package/core/src/math/quat.ts +33 -0
- package/core/src/math/rng.ts +29 -0
- package/core/src/math/trig.ts +47 -0
- package/core/src/math/value-noise.ts +67 -0
- package/core/src/mesh/builder.ts +177 -0
- package/core/src/mesh/csg.ts +312 -0
- package/core/src/mesh/greased-line.ts +145 -0
- package/core/src/mesh/mesh.ts +17 -0
- package/core/src/mesh/parametric.ts +501 -0
- package/core/src/mesh/skinning.ts +67 -0
- package/core/src/mesh/vertex-layout.ts +91 -0
- package/core/src/module/cross-thread.ts +163 -0
- package/core/src/module/diagnostics.ts +123 -0
- package/core/src/module/host.ts +451 -0
- package/core/src/module/index.ts +22 -0
- package/core/src/module/module.ts +109 -0
- package/core/src/module/registry.ts +94 -0
- package/core/src/module/renderer-module.ts +247 -0
- package/core/src/module/ts-loader.ts +26 -0
- package/core/src/particles/compute-pass.ts +378 -0
- package/core/src/particles/emitter.ts +156 -0
- package/core/src/particles/index.ts +11 -0
- package/core/src/particles/particle-data.ts +47 -0
- package/core/src/particles/render-pass.ts +365 -0
- package/core/src/particles/simulator.ts +264 -0
- package/core/src/particles/system.ts +193 -0
- package/core/src/physics/body.ts +59 -0
- package/core/src/physics/ccd-heuristic.ts +55 -0
- package/core/src/physics/character.ts +282 -0
- package/core/src/physics/collider.ts +55 -0
- package/core/src/physics/collision-system.ts +91 -0
- package/core/src/physics/events.ts +133 -0
- package/core/src/physics/index.ts +34 -0
- package/core/src/physics/interface.ts +473 -0
- package/core/src/physics/interpolation-buffer.ts +192 -0
- package/core/src/physics/lifecycle.ts +87 -0
- package/core/src/physics/load-shedder.ts +164 -0
- package/core/src/physics/physics-accumulator.ts +101 -0
- package/core/src/physics/physics-system.ts +240 -0
- package/core/src/physics/ragdoll-presets.ts +272 -0
- package/core/src/physics/ragdoll-system.ts +220 -0
- package/core/src/physics/ragdoll.ts +182 -0
- package/core/src/physics/raycast.ts +143 -0
- package/core/src/physics/realm-manager.ts +499 -0
- package/core/src/physics/realm-worker-pool.ts +191 -0
- package/core/src/physics/realm-worker.ts +102 -0
- package/core/src/physics/realm.ts +189 -0
- package/core/src/physics/registry.ts +52 -0
- package/core/src/physics/safety.ts +247 -0
- package/core/src/physics/snapshot-manager.ts +141 -0
- package/core/src/physics/worker-protocol.ts +30 -0
- package/core/src/platform/bun-preload.ts +169 -0
- package/core/src/platform/css-stub.ts +4 -0
- package/core/src/platform/glob-polyfill.ts +124 -0
- package/core/src/platform/hidpi.ts +57 -0
- package/core/src/platform/render-surface.ts +77 -0
- package/core/src/platform/rpc.ts +98 -0
- package/core/src/platform/runtime.ts +123 -0
- package/core/src/plugin/context.ts +364 -0
- package/core/src/plugin/diagnostics.ts +61 -0
- package/core/src/plugin/discovery.ts +186 -0
- package/core/src/plugin/extension-loaders.ts +172 -0
- package/core/src/plugin/host.ts +659 -0
- package/core/src/plugin/index.ts +106 -0
- package/core/src/plugin/loader-asset.ts +124 -0
- package/core/src/plugin/loader-quickjs.ts +84 -0
- package/core/src/plugin/loader-wasm.ts +411 -0
- package/core/src/plugin/loader-worker.ts +261 -0
- package/core/src/plugin/manifest.ts +653 -0
- package/core/src/plugin/material-registry.ts +65 -0
- package/core/src/plugin/mcp-tools.ts +165 -0
- package/core/src/plugin/permissions.ts +175 -0
- package/core/src/plugin/quickjs-bridge.ts +294 -0
- package/core/src/plugin/registry.ts +107 -0
- package/core/src/plugin/sandbox-shim.ts +86 -0
- package/core/src/plugin/sandbox-worker.ts +215 -0
- package/core/src/plugin/wasm-abi.ts +152 -0
- package/core/src/plugin/wasm-worker.ts +229 -0
- package/core/src/plugin/workshop.ts +169 -0
- package/core/src/profiling/event-loop.ts +180 -0
- package/core/src/profiling/index.ts +69 -0
- package/core/src/profiling/iops/idb-patch.ts +242 -0
- package/core/src/profiling/iops/opfs-patch.ts +276 -0
- package/core/src/profiling/profiling-sab.ts +839 -0
- package/core/src/profiling/task-latency.ts +134 -0
- package/core/src/profiling/thread-metrics.ts +126 -0
- package/core/src/profiling/trace-event-writer.ts +205 -0
- package/core/src/profiling/warnings.ts +423 -0
- package/core/src/profiling/worker-prelude.ts +376 -0
- package/core/src/render/bind-group.ts +38 -0
- package/core/src/render/bindless/bindless-struct.ts +42 -0
- package/core/src/render/bindless/bindless.wgsl.ts +167 -0
- package/core/src/render/bindless/frame-bindings.ts +176 -0
- package/core/src/render/bindless/index.ts +10 -0
- package/core/src/render/bindless/material-manager.ts +257 -0
- package/core/src/render/bindless/texture-registry.ts +609 -0
- package/core/src/render/buffer.ts +82 -0
- package/core/src/render/camera-2d.ts +217 -0
- package/core/src/render/camera-controller.ts +440 -0
- package/core/src/render/camera.ts +409 -0
- package/core/src/render/canvas-resize-watcher.ts +46 -0
- package/core/src/render/compute-kernel.ts +172 -0
- package/core/src/render/constants.ts +2 -0
- package/core/src/render/device.ts +111 -0
- package/core/src/render/frame-graph.ts +768 -0
- package/core/src/render/frustum.ts +185 -0
- package/core/src/render/fullscreen-vs.ts +25 -0
- package/core/src/render/g-buffer.ts +186 -0
- package/core/src/render/game-renderer.ts +1452 -0
- package/core/src/render/gpu-driven/cull-pass.ts +394 -0
- package/core/src/render/gpu-driven/hzb.ts +215 -0
- package/core/src/render/gpu-driven/index.ts +7 -0
- package/core/src/render/gpu-driven/indirect-draw-pass.ts +324 -0
- package/core/src/render/gpu-driven/instance-buffer.ts +178 -0
- package/core/src/render/gpu-driven/mesh-table.ts +175 -0
- package/core/src/render/gpu-driven/passes/hzb-build-pass.ts +47 -0
- package/core/src/render/gpu-utils.ts +96 -0
- package/core/src/render/hdr.ts +88 -0
- package/core/src/render/hot-reload.ts +295 -0
- package/core/src/render/ibl-bind-group.ts +266 -0
- package/core/src/render/ibl.ts +180 -0
- package/core/src/render/index.ts +163 -0
- package/core/src/render/input-manager.ts +259 -0
- package/core/src/render/lighting/area-light.ts +196 -0
- package/core/src/render/lighting/cluster-grid.ts +288 -0
- package/core/src/render/lighting/cluster-types.ts +193 -0
- package/core/src/render/lighting/ies-parser.ts +162 -0
- package/core/src/render/lighting.ts +454 -0
- package/core/src/render/material-types/depth.wgsl +44 -0
- package/core/src/render/material-types/line.wgsl +50 -0
- package/core/src/render/material-types/matcap.wgsl +51 -0
- package/core/src/render/material-types/normal.wgsl +41 -0
- package/core/src/render/material-types/physical.wgsl +152 -0
- package/core/src/render/material-types/sprite.wgsl +46 -0
- package/core/src/render/material-types/sss.wgsl +79 -0
- package/core/src/render/material-types/toon.wgsl +79 -0
- package/core/src/render/passes/README.md +121 -0
- package/core/src/render/passes/atmosphere.ts +152 -0
- package/core/src/render/passes/cluster-lighting-pass.ts +476 -0
- package/core/src/render/passes/csm.ts +408 -0
- package/core/src/render/passes/cubemap-capture.ts +114 -0
- package/core/src/render/passes/debug-viz.ts +278 -0
- package/core/src/render/passes/debug.ts +538 -0
- package/core/src/render/passes/decal-mesh.ts +111 -0
- package/core/src/render/passes/decal-pass.ts +377 -0
- package/core/src/render/passes/deferred-lighting.ts +434 -0
- package/core/src/render/passes/depth-prepass.ts +163 -0
- package/core/src/render/passes/dome-360.ts +83 -0
- package/core/src/render/passes/fluid-render.ts +137 -0
- package/core/src/render/passes/gi-types.ts +118 -0
- package/core/src/render/passes/graph-compute.ts +300 -0
- package/core/src/render/passes/greased-line-pass.ts +232 -0
- package/core/src/render/passes/morph-target.ts +40 -0
- package/core/src/render/passes/opaque.ts +1028 -0
- package/core/src/render/passes/point-light-shadow.ts +266 -0
- package/core/src/render/passes/procedural-texture.ts +185 -0
- package/core/src/render/passes/reflection-probe.ts +140 -0
- package/core/src/render/passes/rsm-pass.ts +248 -0
- package/core/src/render/passes/sdf-text.ts +155 -0
- package/core/src/render/passes/shadow-map.ts +163 -0
- package/core/src/render/passes/shadow.ts +220 -0
- package/core/src/render/passes/skinning-vs.ts +121 -0
- package/core/src/render/passes/skinning.ts +326 -0
- package/core/src/render/passes/sky-dome.ts +404 -0
- package/core/src/render/passes/skybox.ts +162 -0
- package/core/src/render/passes/spot-light-shadow.ts +273 -0
- package/core/src/render/passes/terrain.ts +326 -0
- package/core/src/render/passes/transparent.ts +353 -0
- package/core/src/render/passes/underwater-fog.ts +185 -0
- package/core/src/render/passes/video-texture.ts +79 -0
- package/core/src/render/passes/volumetric-pass.ts +312 -0
- package/core/src/render/passes/volumetric-types.ts +171 -0
- package/core/src/render/passes/water.ts +753 -0
- package/core/src/render/pbr.ts +296 -0
- package/core/src/render/pipeline.ts +52 -0
- package/core/src/render/render-pass.ts +30 -0
- package/core/src/render/renderer-input-bus.ts +220 -0
- package/core/src/render/renderer-module-host.ts +623 -0
- package/core/src/render/resource-tracker.ts +67 -0
- package/core/src/render/sab-canvas-overlay.ts +122 -0
- package/core/src/render/shader-validator.ts +200 -0
- package/core/src/render/shaders/debug/debug-line.wgsl +27 -0
- package/core/src/render/shaders/debug/debug-point.wgsl +30 -0
- package/core/src/render/shaders/debug/debug-text.wgsl +42 -0
- package/core/src/render/shaders/debug-viz/aabb.wgsl +20 -0
- package/core/src/render/shaders/debug-viz/depth.wgsl +29 -0
- package/core/src/render/shaders/debug-viz/lod.wgsl +38 -0
- package/core/src/render/shaders/debug-viz/normals.wgsl +30 -0
- package/core/src/render/shaders/debug-viz/overdraw.wgsl +21 -0
- package/core/src/render/shaders/debug-viz/tangents.wgsl +29 -0
- package/core/src/render/shaders/debug-viz/wireframe.wgsl +33 -0
- package/core/src/render/shaders/shadow-chunks.ts +135 -0
- package/core/src/render/skybox.ts +146 -0
- package/core/src/render/splitscreen.ts +85 -0
- package/core/src/render/surface.ts +78 -0
- package/core/src/render/tonemap.ts +180 -0
- package/core/src/render/tracked-render-pass.ts +158 -0
- package/core/src/render/viewport.ts +109 -0
- package/core/src/render/wgsl-hmr.ts +70 -0
- package/core/src/sab/core-input-channel.ts +23 -0
- package/core/src/sab/define.ts +239 -0
- package/core/src/sab/errors.ts +76 -0
- package/core/src/sab/game-input.ts +343 -0
- package/core/src/sab/gamepad-devices.ts +259 -0
- package/core/src/sab/grid-buffer.ts +117 -0
- package/core/src/sab/input.ts +55 -0
- package/core/src/sab/layout.ts +219 -0
- package/core/src/sab/multi-input-channel.ts +50 -0
- package/core/src/sab/record-buffer.ts +155 -0
- package/core/src/sab/sab-polyfill.ts +56 -0
- package/core/src/sab/sim-channel.ts +453 -0
- package/core/src/sab/slot-buffer.ts +190 -0
- package/core/src/sab/types.ts +158 -0
- package/core/src/safety/bounds.ts +76 -0
- package/core/src/safety/json.ts +80 -0
- package/core/src/safety/path.ts +167 -0
- package/core/src/save/binary-format.ts +117 -0
- package/core/src/save/game-save-system.ts +161 -0
- package/core/src/save/grid-save-system.ts +158 -0
- package/core/src/save/migrate.ts +44 -0
- package/core/src/save/migration-registry.ts +94 -0
- package/core/src/save/persist-types.ts +208 -0
- package/core/src/save/schema.ts +46 -0
- package/core/src/save/serializer.ts +180 -0
- package/core/src/scene/builder.ts +65 -0
- package/core/src/scene/camera.ts +142 -0
- package/core/src/scene/checkpoint.ts +109 -0
- package/core/src/scene/game-loop.ts +198 -0
- package/core/src/scene/index.ts +24 -0
- package/core/src/scene/layer.ts +6 -0
- package/core/src/scene/prefab.ts +145 -0
- package/core/src/scene/scene-manager.ts +157 -0
- package/core/src/scene/scene.ts +192 -0
- package/core/src/scene/sky.ts +256 -0
- package/core/src/scene/spatial-grid.ts +176 -0
- package/core/src/scene/streaming.ts +304 -0
- package/core/src/scene/vegetation.ts +163 -0
- package/core/src/scene/world.ts +89 -0
- package/core/src/scripting/binding.ts +129 -0
- package/core/src/scripting/hot-reload.ts +144 -0
- package/core/src/scripting/script.ts +99 -0
- package/core/src/sim/hot-reload-pipeline.ts +49 -0
- package/core/src/sim/sim-state-helper.ts +47 -0
- package/core/src/sim/transient-state-registry.ts +77 -0
- package/core/src/sim/types.ts +113 -0
- package/core/src/sim/worker-loop.ts +222 -0
- package/core/src/stores/game-store.ts +158 -0
- package/core/src/stores/hot-reload-store.ts +44 -0
- package/core/src/telemetry/collector.ts +410 -0
- package/core/src/telemetry/gc-controller.ts +453 -0
- package/core/src/telemetry/gc-profiler.ts +126 -0
- package/core/src/telemetry/gc-tracker.ts +69 -0
- package/core/src/telemetry/gpu-profiler.ts +703 -0
- package/core/src/telemetry/gpu-resource-tracker.ts +285 -0
- package/core/src/telemetry/gpu-timer-pool.ts +234 -0
- package/core/src/telemetry/gpu-timer.ts +123 -0
- package/core/src/telemetry/gpu-timestamp-gate.ts +21 -0
- package/core/src/telemetry/reporter.ts +62 -0
- package/core/src/types/engine-types.ts +129 -0
- package/core/src/ui-font-scale.ts +112 -0
- package/core/src/util/broad-phase-grid.ts +82 -0
- package/core/src/util/feature-log.ts +220 -0
- package/core/src/util/index.ts +17 -0
- package/core/src/util/logger.ts +604 -0
- package/core/src/webgpu-destroy-augmentation.d.ts +25 -0
- package/core/src/worker/base-worker-host.ts +183 -0
- package/core/src/worker/buffer-sync.ts +550 -0
- package/core/src/worker/crash-recovery.ts +201 -0
- package/core/src/worker/entity-sim-worker-host.ts +190 -0
- package/core/src/worker/instrumented-worker-host.ts +171 -0
- package/core/src/worker/rpc.ts +253 -0
- package/core/src/worker/sim-worker-base.ts +913 -0
- package/core/src/worker/sim-worker-host.ts +358 -0
- package/core/src/worker/task-pool.ts +256 -0
- package/core/src/worker/task-worker.ts +83 -0
- package/libraries/asset-browser/src/index.ts +11 -0
- package/libraries/asset-browser/src/software-thumbnails.ts +949 -0
- package/libraries/audio-kira/README.md +17 -0
- package/libraries/audio-kira/native/Cargo.toml +14 -0
- package/libraries/audio-kira/native/src/engine.rs +27 -0
- package/libraries/audio-kira/native/src/lib.rs +185 -0
- package/libraries/audio-kira/native/src/mixer.rs +11 -0
- package/libraries/audio-kira/native/src/source.rs +80 -0
- package/libraries/audio-kira/src/backend.ts +469 -0
- package/libraries/audio-kira/src/index.ts +8 -0
- package/libraries/audio-kira/src/library.ts +82 -0
- package/libraries/blitz-ui/native/Cargo.toml +33 -0
- package/libraries/blitz-ui/native/assets/DejaVuSans.woff2 +0 -0
- package/libraries/blitz-ui/native/src/bridge.rs +100 -0
- package/libraries/blitz-ui/native/src/fonts.rs +20 -0
- package/libraries/blitz-ui/native/src/input.rs +80 -0
- package/libraries/blitz-ui/native/src/lib.rs +96 -0
- package/libraries/blitz-ui/native/src/shell.rs +301 -0
- package/libraries/blitz-ui/native-osr/Cargo.toml +24 -0
- package/libraries/blitz-ui/native-osr/src/events.rs +237 -0
- package/libraries/blitz-ui/native-osr/src/lib.rs +846 -0
- package/libraries/blitz-ui/native-osr/src/mutate.rs +385 -0
- package/libraries/blitz-ui/native-osr/src/resources.rs +45 -0
- package/libraries/blitz-ui/native-osr-spike.ts +70 -0
- package/libraries/blitz-ui/src/index.ts +15 -0
- package/libraries/blitz-ui/src/native-module.ts +221 -0
- package/libraries/blitz-ui/src/native-osr-ffi.ts +423 -0
- package/libraries/blitz-ui/src/router.ts +101 -0
- package/libraries/blitz-ui/src/shaders/ui-blit.wgsl.ts +35 -0
- package/libraries/blitz-ui/src/ui-blit-pass.ts +116 -0
- package/libraries/character/README.md +25 -0
- package/libraries/character/src/character-animator.ts +374 -0
- package/libraries/character/src/index.ts +24 -0
- package/libraries/character/src/loader.ts +375 -0
- package/libraries/character/src/locomotion.ts +124 -0
- package/libraries/character/src/preview.ts +287 -0
- package/libraries/devtools/README.md +51 -0
- package/libraries/devtools/native/Cargo.toml +12 -0
- package/libraries/devtools/native/src/lib.rs +1646 -0
- package/libraries/devtools/native/src/panels/console.rs +338 -0
- package/libraries/devtools/native/src/panels/dom_tree.rs +47 -0
- package/libraries/devtools/native/src/panels/generic.rs +317 -0
- package/libraries/devtools/native/src/panels/gpu.rs +107 -0
- package/libraries/devtools/native/src/panels/input.rs +88 -0
- package/libraries/devtools/native/src/panels/mod.rs +154 -0
- package/libraries/devtools/native/src/panels/perf_metrics.rs +91 -0
- package/libraries/devtools/native/src/panels/perf_recorder.rs +158 -0
- package/libraries/devtools/native/src/panels/scene.rs +72 -0
- package/libraries/devtools/native/src/state.rs +394 -0
- package/libraries/devtools/src/cdp-bridge.ts +349 -0
- package/libraries/devtools/src/collectors.ts +346 -0
- package/libraries/devtools/src/egui-ffi.ts +804 -0
- package/libraries/devtools/src/egui-renderer.ts +407 -0
- package/libraries/devtools/src/host.ts +363 -0
- package/libraries/devtools/src/index.ts +40 -0
- package/libraries/devtools/src/mirror.ts +794 -0
- package/libraries/devtools/src/native-providers.ts +744 -0
- package/libraries/devtools/src/verify.ts +167 -0
- package/libraries/devtools/src/web/browser.ts +102 -0
- package/libraries/devtools/src/web/host.ts +212 -0
- package/libraries/devtools/src/web/mirror.ts +430 -0
- package/libraries/devtools/src/web/server.ts +198 -0
- package/libraries/entities/README.md +17 -0
- package/libraries/entities/src/index.ts +4 -0
- package/libraries/entities/src/library.ts +64 -0
- package/libraries/entities/src/model-renderer.ts +1345 -0
- package/libraries/entities/src/shaders/model.wgsl +375 -0
- package/libraries/gamepad/src/feed-input.ts +83 -0
- package/libraries/gamepad/src/filters.ts +49 -0
- package/libraries/gamepad/src/glyphs.ts +93 -0
- package/libraries/gamepad/src/hub.ts +206 -0
- package/libraries/gamepad/src/index.ts +22 -0
- package/libraries/gamepad/src/library.ts +68 -0
- package/libraries/gamepad/src/source-sab.ts +70 -0
- package/libraries/gamepad/src/sysfs-enrich.ts +138 -0
- package/libraries/gaussian-splats/README.md +25 -0
- package/libraries/gaussian-splats/src/gpu-sort.ts +595 -0
- package/libraries/gaussian-splats/src/index.ts +31 -0
- package/libraries/gaussian-splats/src/library.ts +60 -0
- package/libraries/gaussian-splats/src/parser.ts +382 -0
- package/libraries/gaussian-splats/src/renderer.ts +427 -0
- package/libraries/gaussian-splats/src/sh-eval.ts +211 -0
- package/libraries/gaussian-splats/src/sorter.ts +110 -0
- package/libraries/gaussian-splats/src/tile-raster.ts +473 -0
- package/libraries/gpu-kernels/README.md +154 -0
- package/libraries/gpu-kernels/src/index.ts +11 -0
- package/libraries/gpu-kernels/src/kernel.ts +696 -0
- package/libraries/gpu-kernels/src/transpile.ts +958 -0
- package/libraries/html-ui-kit/src/behaviors.ts +250 -0
- package/libraries/html-ui-kit/src/components.ts +309 -0
- package/libraries/html-ui-kit/src/index.ts +30 -0
- package/libraries/html-ui-kit/src/nav/nav-controller.ts +238 -0
- package/libraries/html-ui-kit/src/nav/nav-input.ts +145 -0
- package/libraries/html-ui-kit/src/nav/osk.ts +153 -0
- package/libraries/html-ui-kit/src/nav/router.ts +167 -0
- package/libraries/html-ui-kit/src/nav/vcursor.ts +203 -0
- package/libraries/html-ui-kit/src/ten-foot.ts +182 -0
- package/libraries/html-ui-kit/src/theme.ts +238 -0
- package/libraries/lighting/README.md +20 -0
- package/libraries/lighting/src/index.ts +5 -0
- package/libraries/lighting/src/library.ts +66 -0
- package/libraries/lighting/src/light-system.ts +452 -0
- package/libraries/lighting/src/lighting-system.ts +68 -0
- package/libraries/lighting/src/shaders/light-debug.wgsl +30 -0
- package/libraries/marching-cubes/README.md +25 -0
- package/libraries/marching-cubes/src/chunked-field.ts +177 -0
- package/libraries/marching-cubes/src/deformation.ts +63 -0
- package/libraries/marching-cubes/src/generator.ts +407 -0
- package/libraries/marching-cubes/src/index.ts +32 -0
- package/libraries/marching-cubes/src/library.ts +80 -0
- package/libraries/marching-cubes/src/lod.ts +122 -0
- package/libraries/marching-cubes/src/marching-tetrahedra.ts +252 -0
- package/libraries/marching-cubes/src/sab.ts +45 -0
- package/libraries/marching-cubes/src/streaming-config.ts +48 -0
- package/libraries/marching-cubes/src/streaming-manager.ts +686 -0
- package/libraries/marching-cubes/src/tables.ts +323 -0
- package/libraries/marching-cubes/src/types.ts +18 -0
- package/libraries/models/README.md +25 -0
- package/libraries/models/src/bake-node-transforms.ts +171 -0
- package/libraries/models/src/codecs/basisu-codec.ts +180 -0
- package/libraries/models/src/codecs/draco-codec.ts +372 -0
- package/libraries/models/src/codecs/draco3dgltf.d.ts +40 -0
- package/libraries/models/src/codecs/index.ts +22 -0
- package/libraries/models/src/codecs/meshopt-codec.ts +91 -0
- package/libraries/models/src/codecs/registry.ts +221 -0
- package/libraries/models/src/dae.ts +753 -0
- package/libraries/models/src/default-part-selection.ts +56 -0
- package/libraries/models/src/dxf.ts +200 -0
- package/libraries/models/src/fbx/index.ts +457 -0
- package/libraries/models/src/fbx/interpreter/animation.ts +431 -0
- package/libraries/models/src/fbx/interpreter/blend-shapes.ts +323 -0
- package/libraries/models/src/fbx/interpreter/connections.ts +166 -0
- package/libraries/models/src/fbx/interpreter/diagnostics.ts +65 -0
- package/libraries/models/src/fbx/interpreter/geometry.ts +535 -0
- package/libraries/models/src/fbx/interpreter/global-settings.ts +92 -0
- package/libraries/models/src/fbx/interpreter/materials.ts +265 -0
- package/libraries/models/src/fbx/interpreter/nodes.ts +197 -0
- package/libraries/models/src/fbx/interpreter/skeleton.ts +476 -0
- package/libraries/models/src/fbx/parsers/binary-parser.ts +244 -0
- package/libraries/models/src/fbx/types.ts +119 -0
- package/libraries/models/src/gltf-extensions.ts +196 -0
- package/libraries/models/src/gltf.ts +935 -0
- package/libraries/models/src/index.ts +87 -0
- package/libraries/models/src/library.ts +75 -0
- package/libraries/models/src/loader.ts +265 -0
- package/libraries/models/src/material-adapter.ts +108 -0
- package/libraries/models/src/mini-xml.ts +174 -0
- package/libraries/models/src/normalize.ts +216 -0
- package/libraries/models/src/obj.ts +264 -0
- package/libraries/models/src/off.ts +95 -0
- package/libraries/models/src/ply.ts +348 -0
- package/libraries/models/src/pose-sampler.ts +219 -0
- package/libraries/models/src/sidecar/blender-extras.ts +37 -0
- package/libraries/models/src/sidecar/ddmeta.ts +114 -0
- package/libraries/models/src/sidecar/godot-import.ts +86 -0
- package/libraries/models/src/sidecar/resolver.ts +145 -0
- package/libraries/models/src/sidecar/types.ts +11 -0
- package/libraries/models/src/sidecar/unity-meta.ts +61 -0
- package/libraries/models/src/skeleton-synthesis.ts +132 -0
- package/libraries/models/src/stl.ts +149 -0
- package/libraries/models/src/threeds.ts +363 -0
- package/libraries/models/src/threemf.ts +201 -0
- package/libraries/models/src/types.ts +188 -0
- package/libraries/models/src/vtk.ts +218 -0
- package/libraries/models/test-fixtures/fbx/LICENSE-notice.txt +24 -0
- package/libraries/models/test-fixtures/fbx/README.md +46 -0
- package/libraries/models/test-fixtures/fbx/m01_cube_phong.fbx +0 -0
- package/libraries/models/test-fixtures/fbx/m02_geo_ngons.fbx +0 -0
- package/libraries/models/test-fixtures/fbx/m03_normals.fbx +0 -0
- package/libraries/models/test-fixtures/fbx/m04_material_properties.fbx +0 -0
- package/libraries/models/test-fixtures/fbx/m05_external_diffuse.png +0 -0
- package/libraries/models/test-fixtures/fbx/m05_textures.fbx +0 -0
- package/libraries/models/test-fixtures/fbx/m06_uv_transform.fbx +0 -0
- package/libraries/models/test-fixtures/fbx/m07_multimaterial.fbx +0 -0
- package/libraries/models/test-fixtures/fbx/m08_transforms.fbx +0 -0
- package/libraries/models/test-fixtures/fbx/m09_skinning.fbx +0 -0
- package/libraries/models/test-fixtures/fbx/m10_morph.fbx +0 -0
- package/libraries/models/test-fixtures/fbx/m11_node_anim.fbx +0 -0
- package/libraries/models/test-fixtures/fbx/m12_skeletal_anim.fbx +0 -0
- package/libraries/models/test-fixtures/fbx/m13_morph_anim.fbx +0 -0
- package/libraries/models/test-fixtures/fbx/m14_multiclip.fbx +0 -0
- package/libraries/models/test-fixtures/fbx/m15_camera_lights.fbx +0 -0
- package/libraries/models/test-fixtures/fbx/m16_axis_yup.fbx +0 -0
- package/libraries/models/test-fixtures/fbx/m16_axis_zup.fbx +0 -0
- package/libraries/models/test-fixtures/fbx/m16_units_254.fbx +0 -0
- package/libraries/navmesh/README.md +23 -0
- package/libraries/navmesh/src/crowd-system.ts +240 -0
- package/libraries/navmesh/src/debug-viz.ts +74 -0
- package/libraries/navmesh/src/index.ts +15 -0
- package/libraries/navmesh/src/library.ts +64 -0
- package/libraries/navmesh/src/navmesh-generator.ts +407 -0
- package/libraries/navmesh/src/navmesh.ts +159 -0
- package/libraries/navmesh/src/pathfinder.ts +252 -0
- package/libraries/navmesh/src/types.ts +63 -0
- package/libraries/networking/README.md +25 -0
- package/libraries/networking/src/authority.ts +121 -0
- package/libraries/networking/src/connection.ts +139 -0
- package/libraries/networking/src/discovery.ts +373 -0
- package/libraries/networking/src/enhanced-replication.ts +355 -0
- package/libraries/networking/src/epic-adapter.ts +129 -0
- package/libraries/networking/src/index.ts +45 -0
- package/libraries/networking/src/library.ts +69 -0
- package/libraries/networking/src/lobby.ts +108 -0
- package/libraries/networking/src/platform-adapter.ts +163 -0
- package/libraries/networking/src/rcs-adapter.ts +127 -0
- package/libraries/networking/src/remote-input.ts +188 -0
- package/libraries/networking/src/replication.ts +327 -0
- package/libraries/networking/src/rpc.ts +188 -0
- package/libraries/networking/src/session.ts +173 -0
- package/libraries/networking/src/transport.ts +201 -0
- package/libraries/networking/src/webrtc.ts +323 -0
- package/libraries/pathfinding-2d/README.md +15 -0
- package/libraries/pathfinding-2d/src/astar-grid.ts +312 -0
- package/libraries/pathfinding-2d/src/index.ts +11 -0
- package/libraries/persistence/README.md +25 -0
- package/libraries/persistence/src/autosave-manager.ts +112 -0
- package/libraries/persistence/src/binary-record-store.ts +244 -0
- package/libraries/persistence/src/browser.ts +51 -0
- package/libraries/persistence/src/file-save-store.ts +553 -0
- package/libraries/persistence/src/hash-utils.ts +59 -0
- package/libraries/persistence/src/index.ts +57 -0
- package/libraries/persistence/src/library.ts +74 -0
- package/libraries/persistence/src/mock-opfs.ts +141 -0
- package/libraries/persistence/src/node-fs-directory-handle.ts +161 -0
- package/libraries/persistence/src/opfs-save-store.ts +745 -0
- package/libraries/persistence/src/save-worker-proxy.ts +127 -0
- package/libraries/persistence/src/save-worker.ts +99 -0
- package/libraries/persistence/src/xxh3-ts.d.ts +10 -0
- package/libraries/physics-native/README.md +21 -0
- package/libraries/physics-native/native/Cargo.toml +11 -0
- package/libraries/physics-native/native/src/body.rs +403 -0
- package/libraries/physics-native/native/src/character.rs +226 -0
- package/libraries/physics-native/native/src/collider.rs +299 -0
- package/libraries/physics-native/native/src/joint.rs +81 -0
- package/libraries/physics-native/native/src/lib.rs +830 -0
- package/libraries/physics-native/native/src/query.rs +261 -0
- package/libraries/physics-native/native/src/realm.rs +33 -0
- package/libraries/physics-native/native/src/step.rs +54 -0
- package/libraries/physics-native/native/src/world.rs +148 -0
- package/libraries/physics-native/src/backend.ts +1046 -0
- package/libraries/physics-native/src/broadphase.ts +101 -0
- package/libraries/physics-native/src/ffi-spike-worker.ts +71 -0
- package/libraries/physics-native/src/index.ts +11 -0
- package/libraries/physics-native/src/library.ts +79 -0
- package/libraries/physics-native/src/narrowphase-shapes.ts +420 -0
- package/libraries/physics-native/src/narrowphase.ts +123 -0
- package/libraries/physics-native/src/solver.ts +141 -0
- package/libraries/physics-native/src/types.ts +76 -0
- package/libraries/physics-rapier/README.md +21 -0
- package/libraries/physics-rapier/bench/ffi-bench.ts +79 -0
- package/libraries/physics-rapier/bench/wasm-baseline.ts +90 -0
- package/libraries/physics-rapier/src/api.ts +452 -0
- package/libraries/physics-rapier/src/auto-backend.ts +59 -0
- package/libraries/physics-rapier/src/backend.ts +1207 -0
- package/libraries/physics-rapier/src/bulk-ops.ts +68 -0
- package/libraries/physics-rapier/src/ffi-backend.ts +21 -0
- package/libraries/physics-rapier/src/ffi-lib.ts +597 -0
- package/libraries/physics-rapier/src/index.ts +12 -0
- package/libraries/physics-rapier/src/library.ts +107 -0
- package/libraries/physics-rapier/src/rapier-backend.ts +1052 -0
- package/libraries/physics-rapier/src/realm-worker-script.ts +237 -0
- package/libraries/postfx/README.md +17 -0
- package/libraries/postfx/src/index.ts +19 -0
- package/libraries/postfx/src/library.ts +337 -0
- package/libraries/postfx/src/post-process-stack.ts +1752 -0
- package/libraries/postfx/src/shaders/post-process/afterimage.wgsl +14 -0
- package/libraries/postfx/src/shaders/post-process/ascii.wgsl +24 -0
- package/libraries/postfx/src/shaders/post-process/blit.wgsl +12 -0
- package/libraries/postfx/src/shaders/post-process/bloom-blur.wgsl +21 -0
- package/libraries/postfx/src/shaders/post-process/bloom-bright.wgsl +15 -0
- package/libraries/postfx/src/shaders/post-process/bloom-composite.wgsl +14 -0
- package/libraries/postfx/src/shaders/post-process/bloom-downsample.wgsl +60 -0
- package/libraries/postfx/src/shaders/post-process/bloom-soft.wgsl +46 -0
- package/libraries/postfx/src/shaders/post-process/bloom-upsample.wgsl +51 -0
- package/libraries/postfx/src/shaders/post-process/channel-mixer.wgsl +36 -0
- package/libraries/postfx/src/shaders/post-process/chromatic-aberration.wgsl +37 -0
- package/libraries/postfx/src/shaders/post-process/dithering.wgsl +64 -0
- package/libraries/postfx/src/shaders/post-process/dof.wgsl +131 -0
- package/libraries/postfx/src/shaders/post-process/edges.wgsl +45 -0
- package/libraries/postfx/src/shaders/post-process/fullscreen-vs.wgsl +15 -0
- package/libraries/postfx/src/shaders/post-process/fxaa.wgsl +102 -0
- package/libraries/postfx/src/shaders/post-process/gaussian-blur.wgsl +37 -0
- package/libraries/postfx/src/shaders/post-process/glow-blur.wgsl +33 -0
- package/libraries/postfx/src/shaders/post-process/glow-composite.wgsl +25 -0
- package/libraries/postfx/src/shaders/post-process/grain.wgsl +37 -0
- package/libraries/postfx/src/shaders/post-process/halftone.wgsl +80 -0
- package/libraries/postfx/src/shaders/post-process/highlight-blur.wgsl +33 -0
- package/libraries/postfx/src/shaders/post-process/highlight-composite.wgsl +32 -0
- package/libraries/postfx/src/shaders/post-process/lens-distortion.wgsl +43 -0
- package/libraries/postfx/src/shaders/post-process/lens-flare.wgsl +68 -0
- package/libraries/postfx/src/shaders/post-process/lut.wgsl +30 -0
- package/libraries/postfx/src/shaders/post-process/motion-blur.wgsl +55 -0
- package/libraries/postfx/src/shaders/post-process/occluder-chunk.wgsl +28 -0
- package/libraries/postfx/src/shaders/post-process/outline.wgsl +51 -0
- package/libraries/postfx/src/shaders/post-process/pixelation.wgsl +47 -0
- package/libraries/postfx/src/shaders/post-process/sharpen.wgsl +32 -0
- package/libraries/postfx/src/shaders/post-process/sobel.wgsl +26 -0
- package/libraries/postfx/src/shaders/post-process/split-tone.wgsl +36 -0
- package/libraries/postfx/src/shaders/post-process/ssao-blur.wgsl +38 -0
- package/libraries/postfx/src/shaders/post-process/ssao-composite.wgsl +25 -0
- package/libraries/postfx/src/shaders/post-process/ssao.wgsl +147 -0
- package/libraries/postfx/src/shaders/post-process/ssr.wgsl +155 -0
- package/libraries/postfx/src/shaders/post-process/taa.wgsl +98 -0
- package/libraries/postfx/src/shaders/post-process/tonemap.wgsl +40 -0
- package/libraries/postfx/src/shaders/post-process/watercolor.wgsl +82 -0
- package/libraries/postfx/src/shaders/post-process/white-balance.wgsl +41 -0
- package/libraries/recast/README.md +21 -0
- package/libraries/recast/src/backend.ts +150 -0
- package/libraries/recast/src/crowd-system.ts +352 -0
- package/libraries/recast/src/index.ts +12 -0
- package/libraries/recast/src/library.ts +91 -0
- package/libraries/recast/src/types.ts +86 -0
- package/libraries/sand/README.md +25 -0
- package/libraries/sand/src/cell.ts +43 -0
- package/libraries/sand/src/fields.ts +29 -0
- package/libraries/sand/src/fluid-grid.ts +261 -0
- package/libraries/sand/src/grid-dims.ts +74 -0
- package/libraries/sand/src/grid-sim-buffer.ts +271 -0
- package/libraries/sand/src/index.ts +81 -0
- package/libraries/sand/src/library.ts +92 -0
- package/libraries/sand/src/materials.ts +492 -0
- package/libraries/sand/src/palette.ts +93 -0
- package/libraries/sand/src/particles.ts +185 -0
- package/libraries/sand/src/render/sand-grid-pass.ts +430 -0
- package/libraries/sand/src/rng.ts +51 -0
- package/libraries/sand/src/rules/builtin-rules.ts +132 -0
- package/libraries/sand/src/rules/rule-compiler.ts +162 -0
- package/libraries/sand/src/rules/rule-engine.ts +231 -0
- package/libraries/sand/src/rules/rule-types.ts +87 -0
- package/libraries/sand/src/sand-step-pool.ts +484 -0
- package/libraries/sand/src/sand-step-worker.ts +97 -0
- package/libraries/sand/src/sand-world.ts +3227 -0
- package/libraries/stickman/README.md +25 -0
- package/libraries/stickman/src/index.ts +25 -0
- package/libraries/stickman/src/library.ts +61 -0
- package/libraries/stickman/src/proportions.ts +45 -0
- package/libraries/stickman/src/shader.ts +117 -0
- package/libraries/stickman/src/skeleton.ts +197 -0
- package/libraries/stickman/src/stickman-pass.ts +255 -0
- package/libraries/stickman/src/thick-line.ts +123 -0
- package/libraries/surface-nets/README.md +25 -0
- package/libraries/surface-nets/src/chunked-field.ts +14 -0
- package/libraries/surface-nets/src/deformation.ts +45 -0
- package/libraries/surface-nets/src/index.ts +36 -0
- package/libraries/surface-nets/src/library.ts +59 -0
- package/libraries/surface-nets/src/lod.ts +7 -0
- package/libraries/surface-nets/src/sab.ts +4 -0
- package/libraries/surface-nets/src/streaming-config.ts +5 -0
- package/libraries/surface-nets/src/streaming-manager.ts +15 -0
- package/libraries/surface-nets/src/surface-nets.ts +334 -0
- package/libraries/surface-nets/src/types.ts +23 -0
- package/libraries/water/README.md +25 -0
- package/libraries/water/src/buoyancy.ts +103 -0
- package/libraries/water/src/index.ts +43 -0
- package/libraries/water/src/library.ts +85 -0
- package/libraries/water/src/shore-damping.ts +93 -0
- package/libraries/water/src/water-buffer.ts +89 -0
- package/libraries/water/src/water-chunks.ts +13 -0
- package/libraries/water/src/water-physics.ts +376 -0
- package/libraries/water/src/water-renderer.ts +809 -0
- package/libraries/water/src/water-sab.ts +161 -0
- package/libraries/water/src/wave-sources.ts +84 -0
- package/libraries/weather/README.md +20 -0
- package/libraries/weather/src/index.ts +9 -0
- package/libraries/weather/src/library.ts +72 -0
- package/libraries/weather/src/types.ts +64 -0
- package/libraries/weather/src/weather-blend.ts +112 -0
- package/libraries/weather/src/weather-system.ts +271 -0
- package/libraries/weatherfx/README.md +24 -0
- package/libraries/weatherfx/src/cloud-provider.ts +31 -0
- package/libraries/weatherfx/src/cloud-system.ts +372 -0
- package/libraries/weatherfx/src/index.ts +9 -0
- package/libraries/weatherfx/src/library.ts +58 -0
- package/libraries/weatherfx/src/particle-system.ts +434 -0
- package/libraries/weatherfx/src/shaders/cloud.wgsl +111 -0
- package/libraries/weatherfx/src/shaders/particle-compute.wgsl +187 -0
- package/libraries/weatherfx/src/shaders/particle-render.wgsl +95 -0
- package/lint-plugin.mjs +41 -0
- package/mcp/src/client.ts +703 -0
- package/mcp/src/engine-context.ts +186 -0
- package/mcp/src/http-transport.ts +471 -0
- package/mcp/src/index.ts +13 -0
- package/mcp/src/prompts/add-entity.ts +42 -0
- package/mcp/src/prompts/create-scene.ts +44 -0
- package/mcp/src/prompts/debug-frame.ts +39 -0
- package/mcp/src/prompts/index.ts +12 -0
- package/mcp/src/resources/asset-list.ts +32 -0
- package/mcp/src/resources/checkpoint-list.ts +33 -0
- package/mcp/src/resources/entity-state.ts +55 -0
- package/mcp/src/resources/gpu-info.ts +103 -0
- package/mcp/src/resources/index.ts +57 -0
- package/mcp/src/resources/performance.ts +37 -0
- package/mcp/src/resources/scene-tree.ts +43 -0
- package/mcp/src/server.ts +375 -0
- package/mcp/src/tools/animation.ts +118 -0
- package/mcp/src/tools/asset.ts +161 -0
- package/mcp/src/tools/audio.ts +96 -0
- package/mcp/src/tools/build.ts +143 -0
- package/mcp/src/tools/camera.ts +167 -0
- package/mcp/src/tools/checkpoint.ts +100 -0
- package/mcp/src/tools/component.ts +199 -0
- package/mcp/src/tools/debug.ts +300 -0
- package/mcp/src/tools/entity.ts +361 -0
- package/mcp/src/tools/inspect.ts +210 -0
- package/mcp/src/tools/lighting.ts +263 -0
- package/mcp/src/tools/material.ts +243 -0
- package/mcp/src/tools/mesh.ts +239 -0
- package/mcp/src/tools/physics.ts +266 -0
- package/mcp/src/tools/scene.ts +153 -0
- package/mcp/src/tools/script.ts +122 -0
- package/mcp/src/types.ts +92 -0
- package/mcp/src/undo-redo.ts +77 -0
- package/modules/camera-controls/README.md +20 -0
- package/modules/camera-controls/src/index.ts +161 -0
- package/modules/controller-ui/src/index.ts +164 -0
- package/modules/devtools/README.md +25 -0
- package/modules/devtools/src/api.ts +461 -0
- package/modules/devtools/src/asset-utils.ts +105 -0
- package/modules/devtools/src/bind-debug-store.ts +48 -0
- package/modules/devtools/src/data-bridge.ts +286 -0
- package/modules/devtools/src/debug-overlay.ts +238 -0
- package/modules/devtools/src/debug-raycast.ts +328 -0
- package/modules/devtools/src/debug-store.ts +92 -0
- package/modules/devtools/src/debug-view-descriptors.ts +59 -0
- package/modules/devtools/src/doctor-panel.ts +182 -0
- package/modules/devtools/src/gizmo-module.ts +136 -0
- package/modules/devtools/src/graph-model.ts +509 -0
- package/modules/devtools/src/grid-renderer.ts +157 -0
- package/modules/devtools/src/height-ruler-renderer.ts +216 -0
- package/modules/devtools/src/index.ts +81 -0
- package/modules/devtools/src/init.ts +261 -0
- package/modules/devtools/src/label-overlay.ts +154 -0
- package/modules/devtools/src/material-stats-panel.ts +188 -0
- package/modules/devtools/src/profiling-bridge.ts +377 -0
- package/modules/devtools/src/profiling-hooks.ts +98 -0
- package/modules/devtools/src/renderer-adapter.ts +76 -0
- package/modules/devtools/src/scene-inspector.ts +637 -0
- package/modules/devtools/src/scene-store.ts +320 -0
- package/modules/devtools/src/scene-sync.ts +116 -0
- package/modules/devtools/src/shaders/transform-gizmo.wgsl +38 -0
- package/modules/devtools/src/sim-stats-panel.ts +272 -0
- package/modules/devtools/src/sim-stats-provider.ts +105 -0
- package/modules/devtools/src/skeleton-renderer.ts +351 -0
- package/modules/devtools/src/transform-gizmo.ts +928 -0
- package/modules/devtools/src/types.ts +290 -0
- package/modules/devtools/src/worker-expose.ts +67 -0
- package/modules/devtools/src/worker-sync.ts +137 -0
- package/modules/editor/src/commands/component.ts +156 -0
- package/modules/editor/src/commands/entity.ts +287 -0
- package/modules/editor/src/commands/hierarchy.ts +83 -0
- package/modules/editor/src/commands/index.ts +61 -0
- package/modules/editor/src/commands/prefab.ts +163 -0
- package/modules/editor/src/commands/registry.ts +331 -0
- package/modules/editor/src/commands/scene-io.ts +211 -0
- package/modules/editor/src/commands/selection.ts +73 -0
- package/modules/editor/src/commands/transform.ts +91 -0
- package/modules/editor/src/ddscene.ts +267 -0
- package/modules/editor/src/document.ts +123 -0
- package/modules/editor/src/editor-context.ts +172 -0
- package/modules/editor/src/index.ts +41 -0
- package/modules/editor/src/mcp.ts +103 -0
- package/modules/editor/src/module.ts +148 -0
- package/modules/editor/src/selection.ts +70 -0
- package/modules/editor/src/shell.ts +456 -0
- package/modules/editor/src/viewport.ts +199 -0
- package/modules/html-ui/src/composite.ts +135 -0
- package/modules/html-ui/src/create-html-ui.ts +188 -0
- package/modules/html-ui/src/doc-backend.ts +343 -0
- package/modules/html-ui/src/host.ts +646 -0
- package/modules/html-ui/src/index.ts +13 -0
- package/modules/html-ui/src/jsx-dev-runtime.ts +12 -0
- package/modules/html-ui/src/jsx-runtime.ts +126 -0
- package/modules/html-ui/src/protocol.ts +88 -0
- package/modules/html-ui/src/ui-worker.ts +16 -0
- package/modules/mcp/README.md +18 -0
- package/modules/mcp/src/index.ts +27 -0
- package/modules/movement-2d/README.md +19 -0
- package/modules/movement-2d/src/grid-character.ts +455 -0
- package/modules/movement-2d/src/index.ts +45 -0
- package/modules/movement-3d/README.md +21 -0
- package/modules/movement-3d/src/character-motor.ts +230 -0
- package/modules/movement-3d/src/index.ts +46 -0
- package/modules/native-osr/src/index.ts +22 -0
- package/modules/native-osr/src/input-router.ts +401 -0
- package/modules/native-osr/src/native-osr-manager.ts +247 -0
- package/modules/native-osr/src/native-texture-source.ts +86 -0
- package/modules/native-osr/src/types.ts +112 -0
- package/modules/native-osr/src/world-space-ui-pass.ts +351 -0
- package/modules/sailing/README.md +18 -0
- package/modules/sailing/src/index.ts +51 -0
- package/modules/terrain/README.md +18 -0
- package/modules/terrain/src/index.ts +78 -0
- package/modules/vitals/README.md +17 -0
- package/modules/vitals/src/index.ts +43 -0
- package/modules/vitals/src/vitals.ts +265 -0
- package/modules/xr/README.md +25 -0
- package/modules/xr/src/camera-rig.ts +146 -0
- package/modules/xr/src/debug.ts +59 -0
- package/modules/xr/src/frame-loop.ts +197 -0
- package/modules/xr/src/index.ts +16 -0
- package/modules/xr/src/input.ts +208 -0
- package/modules/xr/src/layer.ts +140 -0
- package/modules/xr/src/session.ts +156 -0
- package/modules/xr/src/sim-module.ts +23 -0
- package/modules/xr/src/types.ts +32 -0
- package/modules/xr/src/webxr.d.ts +182 -0
- package/modules/xr/src/xr-module.ts +179 -0
- package/package.json +232 -3
- package/shader-graph/src/chunks.ts +349 -0
- package/shader-graph/src/compiler.ts +732 -0
- package/shader-graph/src/compute-compiler.ts +453 -0
- package/shader-graph/src/compute-graph.ts +112 -0
- package/shader-graph/src/compute-profiles.ts +54 -0
- package/shader-graph/src/graph.ts +52 -0
- package/shader-graph/src/index.ts +53 -0
- package/shader-graph/src/profiles.ts +407 -0
- package/shader-graph/src/validator.ts +48 -0
- package/shader-graph/src/wgsl-binding-validator.ts +143 -0
- package/shader-graph/src/wgsl-struct-validator.ts +245 -0
- package/shader-graph/src/wgsl-struct.ts +397 -0
- package/test/src/index.ts +7 -0
- package/test/src/vision-test.ts +369 -0
|
@@ -0,0 +1,923 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// GameModule — declarative game definition + startGame() entry point
|
|
3
|
+
//
|
|
4
|
+
// A `GameModule` is a declarative description of a game's renderer-side
|
|
5
|
+
// bootstrap: the renderer factory, sim worker factory, UI mount, event
|
|
6
|
+
// routing, save config, devtools, and game-specific hooks. `startGame()`
|
|
7
|
+
// consumes a module and orchestrates the full bootstrap sequence, collapsing
|
|
8
|
+
// the ~700-line per-game `main.tsx` into a ~100-line module declaration.
|
|
9
|
+
//
|
|
10
|
+
// Design goals:
|
|
11
|
+
// - Declarative: games declare *what* they need, not *how* to wire it.
|
|
12
|
+
// - Progressive: every field is optional except `renderer` and `sim`.
|
|
13
|
+
// Simple games get a 10-line module; complex games add hooks.
|
|
14
|
+
// - Typed: the `GameContext` passed to hooks carries typed references
|
|
15
|
+
// (renderer, simWorker, SABs, saveStore, bridge) — no module-scope `let`.
|
|
16
|
+
// - Escape hatches: `onInit` / `onReady` / `onDispose` hooks let games
|
|
17
|
+
// run bespoke logic at well-defined points in the sequence.
|
|
18
|
+
//
|
|
19
|
+
// `startGame()` wraps `bootstrapGame()` — games that need full control can
|
|
20
|
+
// still call `bootstrapGame()` directly.
|
|
21
|
+
// ============================================================================
|
|
22
|
+
|
|
23
|
+
import {
|
|
24
|
+
ENGINE_VERSION,
|
|
25
|
+
LibraryHostImpl,
|
|
26
|
+
PluginHost,
|
|
27
|
+
WorkerPluginLoader,
|
|
28
|
+
isDevMode,
|
|
29
|
+
type GameRendererLike,
|
|
30
|
+
type ISaveStore,
|
|
31
|
+
type LibraryEntry,
|
|
32
|
+
type LibraryHost,
|
|
33
|
+
type PluginHostOptions,
|
|
34
|
+
type PluginManifest,
|
|
35
|
+
type PluginPermission,
|
|
36
|
+
type PluginSource,
|
|
37
|
+
type RenderSurface,
|
|
38
|
+
type SaveMeta,
|
|
39
|
+
type SaveState
|
|
40
|
+
} from "@downdraft/engine";
|
|
41
|
+
import { createLogger } from "@downdraft/engine/util/logger";
|
|
42
|
+
import { bootstrapGame, type BootstrapDevToolsOptions } from "./bootstrap";
|
|
43
|
+
import { downdraft, getSurface } from "./index";
|
|
44
|
+
import { createSaveStore, isOpfsAvailable, type SaveStoreMode } from "./save-store-factory";
|
|
45
|
+
|
|
46
|
+
const log = createLogger("info");
|
|
47
|
+
|
|
48
|
+
// ── Types ──
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The sim worker abstraction. Games provide a factory that creates a sim
|
|
52
|
+
* worker; `startGame()` calls `start()`, captures SABs, wires event routing,
|
|
53
|
+
* and exposes the worker via `GameContext.sim`.
|
|
54
|
+
*
|
|
55
|
+
* This is intentionally minimal — games implement this interface on top of
|
|
56
|
+
* their own sim worker class (e.g. a game's `SimWebWorker`).
|
|
57
|
+
*
|
|
58
|
+
* Games that have a richer sim worker interface can pass their concrete type
|
|
59
|
+
* as the generic parameter `T` to `GameModule<T>` — `GameContext.sim` will
|
|
60
|
+
* then be typed as `T` (no casting needed).
|
|
61
|
+
*/
|
|
62
|
+
export interface GameSimWorker {
|
|
63
|
+
/** Start the sim worker. Config is opaque to the framework (game-specific).
|
|
64
|
+
* Not called for renderer-owned workers (see `module.simFromRenderer`). */
|
|
65
|
+
start(config: unknown): Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* `SimWorkerHost`-style event subscription — the callback receives
|
|
68
|
+
* `{ kind, data }` messages and the return value is an unsubscribe
|
|
69
|
+
* function. Preferred over `onEvent` when both exist.
|
|
70
|
+
*
|
|
71
|
+
* NOTE: `onEvent(cb)` is intentionally NOT declared on this interface —
|
|
72
|
+
* `SimWorkerHost`/`BaseWorkerHost` subclasses carry a *protected*
|
|
73
|
+
* `onEvent(kind, data)` dispatcher, and a class with a protected member
|
|
74
|
+
* can't satisfy an interface that declares the same name. Event wiring
|
|
75
|
+
* probes `subscribeEvents` first, then a public `onEvent` at runtime, so
|
|
76
|
+
* plain GameSimWorker implementations (e.g. falling-sand's worker host)
|
|
77
|
+
* still work.
|
|
78
|
+
*/
|
|
79
|
+
subscribeEvents?(cb: (msg: { kind: string; data: unknown }) => void): () => void;
|
|
80
|
+
getSimBuffer(): SharedArrayBuffer;
|
|
81
|
+
getInputBuffer(): SharedArrayBuffer;
|
|
82
|
+
/** Optional additional SABs the game wants exposed via GameContext. */
|
|
83
|
+
getExtraBuffers?(): Record<string, SharedArrayBuffer>;
|
|
84
|
+
addPlayer?(playerId: number, name: string): Promise<void> | void;
|
|
85
|
+
save?(slotName: string, opts?: unknown): Promise<{ stateJson: string; success: boolean; meta?: Partial<SaveMeta> } | null>;
|
|
86
|
+
load?(slotName: string, stateJson?: string): Promise<boolean>;
|
|
87
|
+
initSaveStore?(opts: unknown): Promise<void>;
|
|
88
|
+
restoreFromState?(stateJson: string): Promise<void>;
|
|
89
|
+
hotReload?(config: unknown, preserveState: boolean): Promise<void>;
|
|
90
|
+
getDevToolsProxy?(): unknown;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Optional seed passed to the sim worker factory. */
|
|
94
|
+
export interface SimWorkerSeed {
|
|
95
|
+
/** SABs allocated by EngineLibrary descriptors (keyed by channel name). */
|
|
96
|
+
libraryBuffers?: Record<string, SharedArrayBuffer>;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Factory that creates a sim worker. Receives a seed with library-allocated
|
|
100
|
+
* SABs (if any libraries declared). Games can pass these to their sim worker
|
|
101
|
+
* constructor to avoid double-allocating SABs. */
|
|
102
|
+
export type SimWorkerFactory<T extends GameSimWorker = GameSimWorker> = (seed?: SimWorkerSeed) => T;
|
|
103
|
+
|
|
104
|
+
/** Factory that creates the renderer from the render surface. The return
|
|
105
|
+
* type narrows `GameContext.renderer` — inferred from the factory. */
|
|
106
|
+
export type RendererFactory<R extends GameRendererLike = GameRendererLike> = (surface: RenderSurface) => R;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Renderer-side save source — an alternative to the sim worker for providing
|
|
110
|
+
* serializable game state. Renderer-only games (no sim worker) declare a
|
|
111
|
+
* `saveSource` in their `GameModule` so the autosave wiring can call it
|
|
112
|
+
* instead of `sim.save()`.
|
|
113
|
+
*
|
|
114
|
+
* Sim-worker games do NOT need this — the sim worker's optional `save()`
|
|
115
|
+
* method is used directly. A game that declares both `sim` and `saveSource`
|
|
116
|
+
* is a configuration error; `saveSource` takes priority.
|
|
117
|
+
*/
|
|
118
|
+
export interface GameSaveSource {
|
|
119
|
+
/** Serialize current state and return it as a JSON string. `meta` carries
|
|
120
|
+
* real SaveMeta for the renderer-side store write when available. */
|
|
121
|
+
save(slotName: string): Promise<{ stateJson: string; success: boolean; meta?: Partial<SaveMeta> } | null>;
|
|
122
|
+
/** Optional: load a previously saved state. If omitted, the save store's
|
|
123
|
+
* own load path is used (OPFS / host bridge). */
|
|
124
|
+
load?(slotName: string): Promise<string | null>;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Declarative event handler map. Each key is a sim→renderer message `kind`;
|
|
129
|
+
* each value is a handler that receives the message data and the game context.
|
|
130
|
+
*
|
|
131
|
+
* This replaces the manual `switch (msg.kind)` block in main.tsx. Unknown
|
|
132
|
+
* message kinds are logged as warnings in dev mode.
|
|
133
|
+
*/
|
|
134
|
+
export type SimEventMap<C extends GameContext = GameContext> = Record<string, (data: any, ctx: C) => void>;
|
|
135
|
+
|
|
136
|
+
/** Save configuration. If omitted, no autosave is wired. */
|
|
137
|
+
export interface GameSaveConfig {
|
|
138
|
+
/** Save mode. Default: "host" when a native host save store is installed
|
|
139
|
+
* (disk, stable), "auto" in browser. Games should pin an explicit mode
|
|
140
|
+
* rather than relying on "auto" — see createSaveStore for resolution. */
|
|
141
|
+
mode?: SaveStoreMode;
|
|
142
|
+
/** Engine version string for save slots. */
|
|
143
|
+
engineVersion: string;
|
|
144
|
+
/** Max save generations to keep. Default: 3. */
|
|
145
|
+
maxGenerations?: number;
|
|
146
|
+
/** Autosave interval in ms. Default: 3000. */
|
|
147
|
+
intervalMs?: number;
|
|
148
|
+
/** Slot name for autosave. Default: "autosave". */
|
|
149
|
+
slotName?: string;
|
|
150
|
+
/**
|
|
151
|
+
* Name of the save-state component that carries the game's data blob
|
|
152
|
+
* (the key under `SaveState.components`, e.g. "sandbox"). Declared
|
|
153
|
+
* explicitly so `ctx.load` forwards the right component to the sim —
|
|
154
|
+
* without it, load falls back to guessing "the first component whose
|
|
155
|
+
* data is an object", which silently picks the wrong blob when a save
|
|
156
|
+
* has multiple object-valued components.
|
|
157
|
+
*/
|
|
158
|
+
componentName?: string;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Serialize the restore payload for a SaveState components map.
|
|
163
|
+
* `explicit` (GameSaveConfig.componentName) selects a single component's
|
|
164
|
+
* `data`. Otherwise: a single-component save unwraps to its `data` (the raw
|
|
165
|
+
* payload restores expect), while a multi-component save forwards the whole
|
|
166
|
+
* map — the worker's extractRestoreData passes component-map input through
|
|
167
|
+
* to the game's restore, which selects the sections it owns. Picking the
|
|
168
|
+
* first component would silently drop the rest of the world.
|
|
169
|
+
*/
|
|
170
|
+
export function serializeRestorePayload(
|
|
171
|
+
components: Record<string, { data?: unknown } | null | undefined>,
|
|
172
|
+
explicit: string | undefined,
|
|
173
|
+
): string | undefined {
|
|
174
|
+
if (explicit) {
|
|
175
|
+
const comp = components[explicit];
|
|
176
|
+
if (!comp) {
|
|
177
|
+
log.warn("startGame", `Save component "${explicit}" not found; available: ${Object.keys(components).join(", ")}`);
|
|
178
|
+
return undefined;
|
|
179
|
+
}
|
|
180
|
+
return JSON.stringify(comp.data);
|
|
181
|
+
}
|
|
182
|
+
const keys = Object.keys(components).filter(
|
|
183
|
+
(k) => components[k]?.data !== undefined && components[k]?.data !== null,
|
|
184
|
+
);
|
|
185
|
+
if (keys.length === 0) return undefined;
|
|
186
|
+
if (keys.length === 1) return JSON.stringify(components[keys[0]]!.data);
|
|
187
|
+
return JSON.stringify(components);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* A framework-managed UI handle. Returned by `GameModule.ui` — startGame()
|
|
192
|
+
* calls `start()` after renderer init (before `onReady`) and `dispose()` on
|
|
193
|
+
* hot-reload. Any { start, dispose } object is compatible (html-ui hosts,
|
|
194
|
+
* DOM-UI mounts, custom overlays).
|
|
195
|
+
*/
|
|
196
|
+
export interface GameUiHandle {
|
|
197
|
+
/** Start the UI (spawn workers, mount overlays). Called after renderer init. */
|
|
198
|
+
start(): Promise<void> | void;
|
|
199
|
+
/** Tear down. Called on hot-reload dispose, before `module.onDispose`. */
|
|
200
|
+
dispose(): void;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* The context passed to all game hooks. Carries typed references to every
|
|
205
|
+
* framework-managed resource — no module-scope `let` variables needed.
|
|
206
|
+
*
|
|
207
|
+
* The `Sim` type parameter lets games specify their concrete sim worker type
|
|
208
|
+
* so `ctx.sim` is typed correctly (no casting). For renderer-only games (no
|
|
209
|
+
* `sim` declared in the `GameModule`), `Sim` defaults to `GameSimWorker` and
|
|
210
|
+
* `ctx.sim` is `undefined` — hooks should not access it.
|
|
211
|
+
*
|
|
212
|
+
* Sim fields (`sim`, `simSAB`, `inputSAB`) are optional because renderer-only
|
|
213
|
+
* games don't have a sim worker. Games that declare `sim` can safely use
|
|
214
|
+
* non-null assertions (`ctx.sim!`) in their hooks — `startGame()` guarantees
|
|
215
|
+
* the sim worker is created when `module.sim` is declared.
|
|
216
|
+
*/
|
|
217
|
+
export interface GameContext<Sim extends GameSimWorker = GameSimWorker, R extends GameRendererLike = GameRendererLike> {
|
|
218
|
+
/** The renderer instance. Typed as `R` — inferred from the module's
|
|
219
|
+
* `renderer` factory, so game-specific members resolve without casts
|
|
220
|
+
* when the factory returns the concrete renderer class. */
|
|
221
|
+
renderer: R;
|
|
222
|
+
/** The render surface the renderer is attached to (NativeSurface on the
|
|
223
|
+
* native runtime). */
|
|
224
|
+
surface: RenderSurface;
|
|
225
|
+
/** The sim worker instance. Undefined for renderer-only games (no `sim` declared). */
|
|
226
|
+
sim?: Sim;
|
|
227
|
+
/** The sim SAB (entity/component data, zero-copy shared with the sim worker).
|
|
228
|
+
* Undefined for renderer-only games. */
|
|
229
|
+
simSAB?: SharedArrayBuffer;
|
|
230
|
+
/** The input SAB (renderer writes, sim worker reads).
|
|
231
|
+
* Undefined for renderer-only games. */
|
|
232
|
+
inputSAB?: SharedArrayBuffer;
|
|
233
|
+
/** Extra SABs from `sim.getExtraBuffers()` (e.g. water, custom-game-data).
|
|
234
|
+
* For renderer-only games, this contains only library-allocated SABs (if any). */
|
|
235
|
+
extraBuffers: Record<string, SharedArrayBuffer>;
|
|
236
|
+
/** The save store, if save config was provided and init succeeded. May be null. */
|
|
237
|
+
saveStore: ISaveStore | null;
|
|
238
|
+
/** The save mode that was actually selected (may differ from config in fallback). */
|
|
239
|
+
saveMode: "inline" | "worker" | "host";
|
|
240
|
+
/**
|
|
241
|
+
* Mode-aware save: persists the current state to the selected backend
|
|
242
|
+
* (inline OPFS / worker OPFS / host store disk). Games should call this for
|
|
243
|
+
* manual saves instead of `sim.save()` directly — `sim.save()` only writes
|
|
244
|
+
* in inline mode and silently drops the save in host mode.
|
|
245
|
+
* Returns true if the save succeeded. Undefined when no save config was declared.
|
|
246
|
+
*/
|
|
247
|
+
save?: (slotName: string) => Promise<boolean>;
|
|
248
|
+
/**
|
|
249
|
+
* Mode-aware load: restores state from the selected backend. Games should
|
|
250
|
+
* call this for manual loads instead of `sim.load()` directly.
|
|
251
|
+
* Returns the loaded state (shape depends on the save source), or null if
|
|
252
|
+
* no save exists. Undefined when no save config was declared.
|
|
253
|
+
*/
|
|
254
|
+
load?: (slotName: string) => Promise<unknown | null>;
|
|
255
|
+
/** The renderer-side save source, if `module.saveSource` was declared.
|
|
256
|
+
* Used by the autosave wiring for renderer-only games. Undefined for
|
|
257
|
+
* sim-worker games (which use `sim.save()` instead). */
|
|
258
|
+
saveSource?: GameSaveSource;
|
|
259
|
+
/** The typed downdraft bridge (window.downdraft). */
|
|
260
|
+
bridge: typeof downdraft;
|
|
261
|
+
/** True if running in deterministic/test mode (DOWNDRAFT_DETERMINISTIC=1). */
|
|
262
|
+
deterministic: boolean;
|
|
263
|
+
/** True if running in dev mode (Vite dev or downdraft.isDev). */
|
|
264
|
+
isDev: boolean;
|
|
265
|
+
/** The library host (if engine libraries were declared). Games can access
|
|
266
|
+
* library-provided resources via DI tokens from onReady. */
|
|
267
|
+
libraryHost?: LibraryHost;
|
|
268
|
+
/** The plugin host (if `module.plugins` was declared). Games can access
|
|
269
|
+
* plugin diagnostics via `pluginHost.snapshot()` and trigger reloads. */
|
|
270
|
+
pluginHost?: PluginHost;
|
|
271
|
+
/** The UI handle created by `module.ui`. Set after renderer init, before
|
|
272
|
+
* `onReady` runs — hooks can `ctx.ui` to post events or wire
|
|
273
|
+
* subscriptions. */
|
|
274
|
+
ui?: GameUiHandle;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Plugin runtime configuration. Games opt into the user-authored plugin
|
|
279
|
+
* (modding) system by declaring a `plugins` field on their `GameModule`.
|
|
280
|
+
*
|
|
281
|
+
* The host constructs a renderer-side `PluginHost` and (for sim-thread
|
|
282
|
+
* plugins) forwards manifests to the sim worker. Games choose per-format
|
|
283
|
+
* whether worker-js plugins run on the sim worker or in a dedicated plugin
|
|
284
|
+
* worker; WASM is always forced to its own worker; QuickJS runs in-process on
|
|
285
|
+
* the renderer; asset plugins are data-only.
|
|
286
|
+
*/
|
|
287
|
+
export interface PluginRuntimeConfig {
|
|
288
|
+
/** Default thread for worker-js plugins: "sim" (inside the game's sim
|
|
289
|
+
* worker) or "own-worker" (dedicated sandboxed worker). Default: "own-worker". */
|
|
290
|
+
workerJs?: "sim" | "own-worker";
|
|
291
|
+
/** Discovery sources. Local plugin dirs + remote workshop stores. */
|
|
292
|
+
sources?: PluginSource[];
|
|
293
|
+
/** Game-defined permission allowlist (further restricts tier). */
|
|
294
|
+
permissions?: ReadonlySet<PluginPermission>;
|
|
295
|
+
/** Game-defined event catalog for the plugin event bus. */
|
|
296
|
+
eventCatalog?: Record<string, unknown>;
|
|
297
|
+
/** Pre-resolved manifests to load (in addition to discovered sources).
|
|
298
|
+
* Useful for tests and for bundling first-party plugins. */
|
|
299
|
+
manifests?: PluginManifest[];
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* A declarative game definition.
|
|
304
|
+
*
|
|
305
|
+
* Games create a `GameModule` and pass it to `startGame()`. The module
|
|
306
|
+
* describes the renderer, sim worker (optional), UI, event routing, save
|
|
307
|
+
* config, devtools, and game-specific hooks. `startGame()` orchestrates the
|
|
308
|
+
* full bootstrap sequence.
|
|
309
|
+
*
|
|
310
|
+
* The `Sim` generic parameter lets games specify their concrete sim worker
|
|
311
|
+
* type so `GameContext.sim` is typed correctly (no casting). For renderer-only
|
|
312
|
+
* games, omit `sim` and `simConfig` — `Sim` defaults to `GameSimWorker` and
|
|
313
|
+
* the sim-related hooks (`events`, `onSimStart`) are ignored.
|
|
314
|
+
*
|
|
315
|
+
* Two topologies:
|
|
316
|
+
* - **Sim-worker**: declare `sim` + `simConfig`. `startGame()` spawns the
|
|
317
|
+
* worker, captures SABs, wires event routing, and starts the sim.
|
|
318
|
+
* - **Renderer-only**: omit `sim` + `simConfig`. All logic runs on the
|
|
319
|
+
* renderer thread. Declare `saveSource` if you need autosave. Use
|
|
320
|
+
* engine libraries (e.g. `WeatherFxLib`, `ModelsLib`) for GPU-side work.
|
|
321
|
+
*/
|
|
322
|
+
export interface GameModule<Sim extends GameSimWorker = GameSimWorker, R extends GameRendererLike = GameRendererLike> {
|
|
323
|
+
// ── Required: renderer ──
|
|
324
|
+
/** Factory that creates the renderer from a canvas. */
|
|
325
|
+
renderer: RendererFactory<R>;
|
|
326
|
+
|
|
327
|
+
// ── Optional: sim worker (omit for renderer-only games) ──
|
|
328
|
+
/** Factory that creates the sim worker. Omit for renderer-only games. */
|
|
329
|
+
sim?: SimWorkerFactory<Sim>;
|
|
330
|
+
/** Config passed to `sim.start()`. Required when `sim` is declared. */
|
|
331
|
+
simConfig?: Record<string, unknown>;
|
|
332
|
+
/**
|
|
333
|
+
* Renderer-owned sim worker. For games where the renderer spawns and starts
|
|
334
|
+
* its own worker internally during `renderer.init()` (e.g. falling-sand's
|
|
335
|
+
* renderer creates its SandWorkerHost). Declare this INSTEAD of `sim` — it
|
|
336
|
+
* is called after renderer init to retrieve the worker, which is then
|
|
337
|
+
* exposed as `ctx.sim` and wired into `module.events` routing like a
|
|
338
|
+
* factory-created worker. This removes the need for no-op GameSimWorker
|
|
339
|
+
* adapter classes.
|
|
340
|
+
*
|
|
341
|
+
* The returned object must satisfy GameSimWorker (start + getSimBuffer +
|
|
342
|
+
* getInputBuffer, plus onEvent or subscribeEvents for event routing).
|
|
343
|
+
* `SimWorkerHost` subclasses satisfy this directly via `subscribeEvents`:
|
|
344
|
+
* `simFromRenderer: (r) => r.getWorkerHost() ?? undefined`
|
|
345
|
+
*/
|
|
346
|
+
simFromRenderer?: (renderer: R, ctx: GameContext<Sim, R>) => Sim | undefined | Promise<Sim | undefined>;
|
|
347
|
+
|
|
348
|
+
// ── UI ──
|
|
349
|
+
/**
|
|
350
|
+
* Declarative UI lifecycle. Called once with the game context; the returned
|
|
351
|
+
* handle is started after renderer init (before `onReady`) and disposed on
|
|
352
|
+
* hot-reload (before `onDispose`). The handle is exposed as `ctx.ui`.
|
|
353
|
+
*/
|
|
354
|
+
ui?: (ctx: GameContext<Sim, R>) => GameUiHandle | Promise<GameUiHandle>;
|
|
355
|
+
|
|
356
|
+
// ── Event routing (sim-worker games only) ──
|
|
357
|
+
/** Declarative sim→renderer event handler map. Replaces the switch block.
|
|
358
|
+
* Ignored for renderer-only games (no sim worker to emit events). */
|
|
359
|
+
events?: SimEventMap<GameContext<Sim, R>>;
|
|
360
|
+
|
|
361
|
+
// ── Save ──
|
|
362
|
+
/** Save configuration. If omitted, no autosave is wired. */
|
|
363
|
+
save?: GameSaveConfig;
|
|
364
|
+
/** Renderer-side save source for renderer-only games. When declared, the
|
|
365
|
+
* autosave wiring calls `saveSource.save()` instead of `sim.save()`.
|
|
366
|
+
* Ignored for sim-worker games (the sim worker's `save()` is used). */
|
|
367
|
+
saveSource?: GameSaveSource;
|
|
368
|
+
|
|
369
|
+
// ── Engine libraries ──
|
|
370
|
+
/**
|
|
371
|
+
* Engine libraries to auto-wire (water, physics, terrain, etc.).
|
|
372
|
+
* Each entry is either a bare `EngineLibrary` (uses default config) or
|
|
373
|
+
* a `[library, config]` tuple to override config.
|
|
374
|
+
*
|
|
375
|
+
* The host allocates SABs, instantiates sim-side systems + renderer-side
|
|
376
|
+
* passes, and registers provided resources in the DI graph.
|
|
377
|
+
*
|
|
378
|
+
* Games can still import and wire library classes manually (escape hatch)
|
|
379
|
+
* if they need more control than the descriptor provides.
|
|
380
|
+
*/
|
|
381
|
+
libraries?: LibraryEntry[];
|
|
382
|
+
|
|
383
|
+
// ── User-authored plugins (modding) ──
|
|
384
|
+
/**
|
|
385
|
+
* Plugin runtime configuration. When declared, `startGame()` constructs a
|
|
386
|
+
* renderer-side `PluginHost`, discovers plugins from the configured sources,
|
|
387
|
+
* and loads them after renderer init. Sim-thread plugins are forwarded to
|
|
388
|
+
* the sim worker. See `PluginRuntimeConfig`.
|
|
389
|
+
*/
|
|
390
|
+
plugins?: PluginRuntimeConfig;
|
|
391
|
+
|
|
392
|
+
// ── DevTools ──
|
|
393
|
+
/** DevTools config. If omitted, DevTools is not wired. */
|
|
394
|
+
devtools?: BootstrapDevToolsOptions;
|
|
395
|
+
|
|
396
|
+
// ── MCP ──
|
|
397
|
+
/** Called to register MCP tools (after renderer is started). Receives ctx. */
|
|
398
|
+
mcp?: (ctx: GameContext<Sim, R>) => void | Promise<void>;
|
|
399
|
+
|
|
400
|
+
// ── Hooks ──
|
|
401
|
+
/**
|
|
402
|
+
* Called after renderer creation, before init. Use to wire sim-ready
|
|
403
|
+
* listeners, capture early state, etc. The renderer exists but is not
|
|
404
|
+
* initialized yet.
|
|
405
|
+
*/
|
|
406
|
+
onBeforeInit?: (ctx: GameContext<Sim, R>) => Promise<void> | void;
|
|
407
|
+
/**
|
|
408
|
+
* Called to initialize the renderer. Should return false on failure.
|
|
409
|
+
* Default: calls `renderer.init()`. The sim worker is started in parallel
|
|
410
|
+
* (see `onSimStart`). Override to add LUT waits, player spawn, etc.
|
|
411
|
+
*/
|
|
412
|
+
onInit?: (ctx: GameContext<Sim, R>) => Promise<boolean> | boolean;
|
|
413
|
+
/**
|
|
414
|
+
* Called to start the sim worker (only when `sim` is declared and `onInit`
|
|
415
|
+
* is NOT overridden). Default: calls `sim.start(simConfig)`. Override to
|
|
416
|
+
* add player spawn after sim is ready. Ignored for renderer-only games.
|
|
417
|
+
*
|
|
418
|
+
* When `onInit` IS overridden, the game's `onInit` owns sim start — this
|
|
419
|
+
* hook is not called. This lets games start the sim in parallel with
|
|
420
|
+
* `renderer.init()` (e.g. to-the-ocean does `Promise.all([renderer.init(),
|
|
421
|
+
* sim.start(config)])` in its `onInit`).
|
|
422
|
+
*/
|
|
423
|
+
onSimStart?: (ctx: GameContext<Sim, R>) => Promise<void> | void;
|
|
424
|
+
/**
|
|
425
|
+
* Called after renderer init + sim start succeed, before render loop.
|
|
426
|
+
* This is the main game-specific wiring hook: setBuffers, OSR, sim bridge,
|
|
427
|
+
* DevTools, gizmo handlers, HUD polling, debug toggles, hot-reload.
|
|
428
|
+
*/
|
|
429
|
+
onReady?: (ctx: GameContext<Sim, R>) => Promise<void> | void;
|
|
430
|
+
/** Called on Vite hot-reload dispose to clean up resources. */
|
|
431
|
+
onDispose?: (ctx: GameContext<Sim, R>) => Promise<void> | void;
|
|
432
|
+
/** Called in deterministic mode to apply overrides (e.g. pause render loop). */
|
|
433
|
+
onDeterministic?: (ctx: GameContext<Sim, R>) => void;
|
|
434
|
+
/** Called periodically with the current render FPS. */
|
|
435
|
+
onFpsUpdate?: (fps: number, ctx: GameContext<Sim, R>) => void;
|
|
436
|
+
/** Called with the display refresh rate when available. */
|
|
437
|
+
onDisplayInfo?: (refreshRate: number, ctx: GameContext<Sim, R>) => void;
|
|
438
|
+
|
|
439
|
+
// ── Surface ──
|
|
440
|
+
/** Surface layer index. Default: 0 — the only layer on native hosts. */
|
|
441
|
+
canvasLayer?: number;
|
|
442
|
+
/** FPS polling interval in ms. Default: 500. */
|
|
443
|
+
fpsPollIntervalMs?: number;
|
|
444
|
+
|
|
445
|
+
// ── Feature log ──
|
|
446
|
+
/** Optional getter for active plugin names (populates the `plug` field of the
|
|
447
|
+
* renderer feature log line). e.g. () => gameWorld.moduleHost.listModules() */
|
|
448
|
+
getActiveModules?: () => string[];
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// ── startGame() ──
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Start a game from a declarative `GameModule`.
|
|
455
|
+
*
|
|
456
|
+
* This is the high-level entry point. It wraps `bootstrapGame()` and adds:
|
|
457
|
+
* - Engine library auto-wiring (SAB allocation, sim systems, renderer passes)
|
|
458
|
+
* - Sim worker spawn + SAB capture (skipped for renderer-only games)
|
|
459
|
+
* - Declarative event routing (the `events` map — sim-worker games only)
|
|
460
|
+
* - Save store initialization (sim-worker or renderer-side save source)
|
|
461
|
+
* - Typed `GameContext` passed to all hooks
|
|
462
|
+
*
|
|
463
|
+
* Two topologies are supported:
|
|
464
|
+
* - **Sim-worker**: `module.sim` is declared → worker spawned, SABs captured,
|
|
465
|
+
* events routed, sim started after renderer init.
|
|
466
|
+
* - **Renderer-only**: `module.sim` is omitted → no worker, no SABs, no
|
|
467
|
+
* event routing. All logic runs on the renderer thread. Declare
|
|
468
|
+
* `module.saveSource` for autosave support.
|
|
469
|
+
*
|
|
470
|
+
* Games that need full control can call `bootstrapGame()` directly.
|
|
471
|
+
*/
|
|
472
|
+
export async function startGame<Sim extends GameSimWorker, R extends GameRendererLike = GameRendererLike>(module: GameModule<Sim, R>): Promise<void> {
|
|
473
|
+
const deterministic = !!(downdraft as any)?.deterministic;
|
|
474
|
+
const isDev = !!(downdraft?.isDev) || isDevMode;
|
|
475
|
+
const hasSim = !!module.sim;
|
|
476
|
+
|
|
477
|
+
// 0. Resolve the render surface (NativeSurface on the native runtime)
|
|
478
|
+
const surface = getSurface(module.canvasLayer ?? 0);
|
|
479
|
+
|
|
480
|
+
// 0b. Allocate library SABs (if any libraries declared) — before sim worker
|
|
481
|
+
// creation so the sim factory can receive externally-allocated SABs.
|
|
482
|
+
let libHost: LibraryHost | null = null;
|
|
483
|
+
let libBuffers: Record<string, SharedArrayBuffer> = {};
|
|
484
|
+
if (module.libraries && module.libraries.length > 0) {
|
|
485
|
+
libHost = new LibraryHostImpl(module.libraries);
|
|
486
|
+
libBuffers = libHost.allocateBuffers();
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// 0c. Construct the renderer-side plugin host (if plugins declared).
|
|
490
|
+
// Sim-thread plugins are forwarded to the sim worker after it starts;
|
|
491
|
+
// renderer/own-worker plugins load here. The host is exposed on ctx so
|
|
492
|
+
// games + the doctor panel can query snapshots.
|
|
493
|
+
let pluginHost: PluginHost | null = null;
|
|
494
|
+
if (module.plugins) {
|
|
495
|
+
const pCfg = module.plugins;
|
|
496
|
+
const hostOpts: PluginHostOptions = {
|
|
497
|
+
gameId: (downdraft as any)?.appId ?? "unknown",
|
|
498
|
+
engineVersion: ENGINE_VERSION,
|
|
499
|
+
gameAllow: pCfg.permissions,
|
|
500
|
+
eventCatalog: pCfg.eventCatalog,
|
|
501
|
+
sources: pCfg.sources,
|
|
502
|
+
};
|
|
503
|
+
pluginHost = new PluginHost(hostOpts);
|
|
504
|
+
// Register the worker-js loader (handles own-worker plugins on renderer).
|
|
505
|
+
pluginHost.registerLoader(new WorkerPluginLoader());
|
|
506
|
+
// Pre-resolved manifests (tests / first-party plugins).
|
|
507
|
+
for (let _i23990 = 0, _it23990 = (pCfg.manifests ?? []), _n23990 = _it23990.length; _i23990 < _n23990; _i23990++) { const m = _it23990[_i23990];
|
|
508
|
+
pluginHost.discover(m, "inline");
|
|
509
|
+
};
|
|
510
|
+
// Manifests are discovered via the plugin host's discover() API. Here we
|
|
511
|
+
// only load what's been discovered so far.
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// 1. Create sim worker + capture SABs (renderer-only games skip this).
|
|
515
|
+
// If libraries declared, pass the library-allocated SABs to the sim
|
|
516
|
+
// factory via a seed object so the sim can share them zero-copy.
|
|
517
|
+
const simSeed = Object.keys(libBuffers).length > 0 ? { libraryBuffers: libBuffers } : undefined;
|
|
518
|
+
const simWorker = hasSim ? module.sim!(simSeed as any) : null;
|
|
519
|
+
const simSAB = simWorker?.getSimBuffer();
|
|
520
|
+
const inputSAB = simWorker?.getInputBuffer();
|
|
521
|
+
const extraBuffers = simWorker?.getExtraBuffers?.() ?? {};
|
|
522
|
+
|
|
523
|
+
// 2. Create renderer
|
|
524
|
+
const renderer = module.renderer(surface);
|
|
525
|
+
|
|
526
|
+
// 3. Build the game context. Sim fields are undefined for renderer-only games.
|
|
527
|
+
const ctx: GameContext<Sim, R> = {
|
|
528
|
+
renderer,
|
|
529
|
+
surface,
|
|
530
|
+
sim: simWorker as Sim | undefined,
|
|
531
|
+
simSAB,
|
|
532
|
+
inputSAB,
|
|
533
|
+
extraBuffers,
|
|
534
|
+
saveStore: null,
|
|
535
|
+
saveMode: "host",
|
|
536
|
+
saveSource: module.saveSource,
|
|
537
|
+
bridge: downdraft,
|
|
538
|
+
deterministic,
|
|
539
|
+
isDev,
|
|
540
|
+
};
|
|
541
|
+
|
|
542
|
+
// 3b. Merge library SABs into extraBuffers + store host on ctx
|
|
543
|
+
if (libHost) {
|
|
544
|
+
for (const [name, sab] of Object.entries(libBuffers)) {
|
|
545
|
+
ctx.extraBuffers[name] = sab;
|
|
546
|
+
}
|
|
547
|
+
ctx.libraryHost = libHost;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// 3c. Expose the plugin host on ctx (if constructed).
|
|
551
|
+
if (pluginHost) {
|
|
552
|
+
ctx.pluginHost = pluginHost;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// Event kinds emitted by the engine itself (sim-worker-base lifecycle)
|
|
556
|
+
// that games are not required to handle — suppress the dev warning for
|
|
557
|
+
// these so autosave doesn't spam the console when no handler is wired.
|
|
558
|
+
const ENGINE_EMITTED_EVENT_KINDS = new Set(["ready", "saved", "loaded", "error"]);
|
|
559
|
+
|
|
560
|
+
// 4. Wire event routing from the declarative events map (sim-worker only).
|
|
561
|
+
// Supports both GameSimWorker.onEvent(cb) and SimWorkerHost's
|
|
562
|
+
// subscribeEvents(cb) (renderer-owned worker hosts).
|
|
563
|
+
const wireSimEvents = (worker: Sim) => {
|
|
564
|
+
if (!module.events || !worker) return;
|
|
565
|
+
const events = module.events;
|
|
566
|
+
// Prefer subscribeEvents when present: SimWorkerHost subclasses expose it
|
|
567
|
+
// as the public registration API, while their protected onEvent(kind,data)
|
|
568
|
+
// is the internal dispatcher (and would be incorrectly bound if we probed
|
|
569
|
+
// onEvent first — it exists on the prototype at runtime).
|
|
570
|
+
const onEvent: ((cb: (msg: any) => void) => void) | undefined =
|
|
571
|
+
(worker as any).subscribeEvents
|
|
572
|
+
? (cb: (msg: any) => void) => { (worker as any).subscribeEvents(cb); }
|
|
573
|
+
: (worker as any).onEvent?.bind(worker);
|
|
574
|
+
if (!onEvent) return;
|
|
575
|
+
onEvent((msg) => {
|
|
576
|
+
const handler = events[msg.kind];
|
|
577
|
+
if (handler) {
|
|
578
|
+
try {
|
|
579
|
+
handler(msg.data, ctx);
|
|
580
|
+
} catch (err) {
|
|
581
|
+
log.error("startGame", `Event handler error for "${msg.kind}": ${err}`);
|
|
582
|
+
}
|
|
583
|
+
} else if (isDev && !ENGINE_EMITTED_EVENT_KINDS.has(msg.kind)) {
|
|
584
|
+
log.warn("startGame", `Unhandled sim event kind: "${msg.kind}"`);
|
|
585
|
+
}
|
|
586
|
+
});
|
|
587
|
+
};
|
|
588
|
+
if (simWorker) wireSimEvents(simWorker);
|
|
589
|
+
|
|
590
|
+
// 5. Run onBeforeInit hook
|
|
591
|
+
if (module.onBeforeInit) {
|
|
592
|
+
await module.onBeforeInit(ctx);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// 6. Initialize save store (if configured) — for non-inline modes this
|
|
596
|
+
// runs before bootstrapGame so onReady can use it. For inline mode
|
|
597
|
+
// (sim-worker + OPFS), the store is initialized inside onRendererInit
|
|
598
|
+
// after the sim worker has started.
|
|
599
|
+
if (module.save && !deterministic) {
|
|
600
|
+
try {
|
|
601
|
+
// Default to "host" (disk via the host's typed save store) when the
|
|
602
|
+
// bridge exposes one — on native this is HostSaveStore over
|
|
603
|
+
// HostServices. Fall back to "auto" (OPFS) only in a pure browser
|
|
604
|
+
// where there is no host bridge.
|
|
605
|
+
const saveMode = module.save.mode ?? (downdraft.saveStore ? "host" : "auto");
|
|
606
|
+
if (saveMode === "auto" && simWorker?.initSaveStore && isOpfsAvailable() && !downdraft.saveStore) {
|
|
607
|
+
// Inline mode — defer init to onRendererInit (after sim worker starts).
|
|
608
|
+
ctx.saveMode = "inline";
|
|
609
|
+
ctx.saveStore = null;
|
|
610
|
+
} else {
|
|
611
|
+
const { store, mode: resolvedMode } = await createSaveStore({
|
|
612
|
+
mode: saveMode,
|
|
613
|
+
opfsOptions: {
|
|
614
|
+
engineVersion: module.save.engineVersion,
|
|
615
|
+
maxGenerations: module.save.maxGenerations ?? 3,
|
|
616
|
+
},
|
|
617
|
+
bridge: downdraft,
|
|
618
|
+
});
|
|
619
|
+
ctx.saveStore = store;
|
|
620
|
+
// resolvedMode is "worker" | "host" | "inline" (inline returns a
|
|
621
|
+
// null store); narrow to the ctx.saveMode union accordingly.
|
|
622
|
+
ctx.saveMode = resolvedMode === "inline" ? "inline"
|
|
623
|
+
: resolvedMode === "worker" ? "worker" : "host";
|
|
624
|
+
}
|
|
625
|
+
} catch (e) {
|
|
626
|
+
log.warn("startGame", `Save store init failed, falling back to host bridge: ${e}`);
|
|
627
|
+
ctx.saveMode = "host";
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// 6b. Mode-aware save/load helpers — exposed on ctx so games can trigger manual
|
|
632
|
+
// saves/loads that work regardless of the selected backend. This is the
|
|
633
|
+
// same logic the autosave interval uses below. Games MUST use ctx.save /
|
|
634
|
+
// ctx.load instead of sim.save / sim.load directly: sim.save only writes
|
|
635
|
+
// in inline mode (it has its own OPFS store) and silently drops the save
|
|
636
|
+
// in host mode (it returns stateJson but nothing forwards it to disk).
|
|
637
|
+
if (module.save && !deterministic) {
|
|
638
|
+
ctx.save = async (slotName: string): Promise<boolean> => {
|
|
639
|
+
try {
|
|
640
|
+
// Renderer-side save source takes priority (renderer-only games);
|
|
641
|
+
// otherwise fall back to the sim worker's save() (sim-worker games).
|
|
642
|
+
// ctx.sim covers simFromRenderer games, resolved after renderer init.
|
|
643
|
+
const sim = ctx.sim ?? simWorker;
|
|
644
|
+
const result = ctx.saveSource
|
|
645
|
+
? await ctx.saveSource.save(slotName)
|
|
646
|
+
: sim?.save
|
|
647
|
+
? await sim.save(slotName)
|
|
648
|
+
: null;
|
|
649
|
+
// In inline mode, the sim worker's save() already persisted to its own
|
|
650
|
+
// OPFS store — nothing more to do. In host/worker mode the sim worker
|
|
651
|
+
// only serialized — the renderer owns the store write.
|
|
652
|
+
if (result?.stateJson && ctx.saveMode !== "inline" && ctx.saveStore) {
|
|
653
|
+
const components = JSON.parse(result.stateJson);
|
|
654
|
+
const state: SaveState = {
|
|
655
|
+
components,
|
|
656
|
+
meta: {
|
|
657
|
+
engineVersion: module.save?.engineVersion ?? "",
|
|
658
|
+
timestamp: Date.now() / 1000,
|
|
659
|
+
entityCount: 0,
|
|
660
|
+
playerCount: 0,
|
|
661
|
+
// Real SaveMeta from the worker's save.meta() hook wins.
|
|
662
|
+
...result.meta,
|
|
663
|
+
},
|
|
664
|
+
};
|
|
665
|
+
const sr = await ctx.saveStore.save(slotName, state);
|
|
666
|
+
return result.success !== false && sr.success;
|
|
667
|
+
}
|
|
668
|
+
return result?.success ?? false;
|
|
669
|
+
} catch (e) {
|
|
670
|
+
log.error("startGame", `Manual save failed: ${e}`);
|
|
671
|
+
return false;
|
|
672
|
+
}
|
|
673
|
+
};
|
|
674
|
+
|
|
675
|
+
ctx.load = async (slotName: string): Promise<unknown | null> => {
|
|
676
|
+
try {
|
|
677
|
+
// Renderer-side save source load (renderer-only games)
|
|
678
|
+
if (ctx.saveSource?.load) {
|
|
679
|
+
const stateJson = await ctx.saveSource.load(slotName);
|
|
680
|
+
return stateJson ? JSON.parse(stateJson) : null;
|
|
681
|
+
}
|
|
682
|
+
// ctx.sim covers simFromRenderer games (resolved post renderer-init).
|
|
683
|
+
const sim = ctx.sim ?? simWorker;
|
|
684
|
+
// Inline mode: sim worker loads directly from its own OPFS store.
|
|
685
|
+
// The sim worker's load() restores state internally; we just need a
|
|
686
|
+
// truthy return value so any onLoad hook fires.
|
|
687
|
+
if (ctx.saveMode === "inline" && sim?.load) {
|
|
688
|
+
const success = await sim.load(slotName);
|
|
689
|
+
return success ? { restored: true } : null;
|
|
690
|
+
}
|
|
691
|
+
if (ctx.saveStore) {
|
|
692
|
+
const result = await ctx.saveStore.load(slotName);
|
|
693
|
+
const state = result?.state ?? null;
|
|
694
|
+
if (state && sim?.restoreFromState) {
|
|
695
|
+
// The save store returns a SaveState with `components`. Each
|
|
696
|
+
// component has { v, data } structure — forward the restore
|
|
697
|
+
// payload to the sim worker.
|
|
698
|
+
const components = (state as any).components;
|
|
699
|
+
if (components) {
|
|
700
|
+
const payload = serializeRestorePayload(components, module.save?.componentName);
|
|
701
|
+
if (payload !== undefined) {
|
|
702
|
+
await sim.restoreFromState(payload);
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
return state;
|
|
707
|
+
}
|
|
708
|
+
if (downdraft?.loadGameState) {
|
|
709
|
+
const stateJson = await downdraft.loadGameState(slotName);
|
|
710
|
+
if (!stateJson) return null;
|
|
711
|
+
// The host bridge returns JSON.stringify(result.state.components),
|
|
712
|
+
// so the parsed result is the components map directly (not a
|
|
713
|
+
// SaveState). Find the game component (e.g. "sandbox") and
|
|
714
|
+
// forward its `data` to the sim worker.
|
|
715
|
+
let parsed: unknown = null;
|
|
716
|
+
try {
|
|
717
|
+
parsed = JSON.parse(stateJson);
|
|
718
|
+
} catch {
|
|
719
|
+
// Non-JSON payload — fall through to raw restore.
|
|
720
|
+
}
|
|
721
|
+
if (sim?.restoreFromState) {
|
|
722
|
+
const components = parsed as Record<string, { data?: unknown }> | null;
|
|
723
|
+
const payload = components && typeof components === "object"
|
|
724
|
+
? serializeRestorePayload(components, module.save?.componentName)
|
|
725
|
+
: undefined;
|
|
726
|
+
if (payload !== undefined) {
|
|
727
|
+
await sim.restoreFromState(payload);
|
|
728
|
+
} else {
|
|
729
|
+
// No recognizable components map — forward the raw payload.
|
|
730
|
+
await sim.restoreFromState(stateJson);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
// Return the parsed payload (or the raw string when it isn't JSON)
|
|
734
|
+
// — the previous version re-parsed unconditionally here, so a
|
|
735
|
+
// successful raw restore still reported failure.
|
|
736
|
+
return parsed ?? stateJson;
|
|
737
|
+
}
|
|
738
|
+
return null;
|
|
739
|
+
} catch (e) {
|
|
740
|
+
log.error("startGame", `Manual load failed: ${e}`);
|
|
741
|
+
return null;
|
|
742
|
+
}
|
|
743
|
+
};
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
// 7. Delegate to bootstrapGame() for the standard sequence
|
|
747
|
+
await bootstrapGame({
|
|
748
|
+
canvasLayer: module.canvasLayer,
|
|
749
|
+
fpsPollIntervalMs: module.fpsPollIntervalMs,
|
|
750
|
+
getActiveModules: module.getActiveModules,
|
|
751
|
+
|
|
752
|
+
createRenderer: () => renderer,
|
|
753
|
+
|
|
754
|
+
initRenderer: module.onInit
|
|
755
|
+
? () => module.onInit!(ctx)
|
|
756
|
+
: (r) => r.init(),
|
|
757
|
+
|
|
758
|
+
onRendererInit: async (r) => {
|
|
759
|
+
// ── Library renderer setup ──
|
|
760
|
+
// Early renderer-only library setup (hosts, workers — no GPU needed).
|
|
761
|
+
// Runs before the GPU device is available so libraries can construct
|
|
762
|
+
// their host + provide DI tokens.
|
|
763
|
+
if (libHost && r) {
|
|
764
|
+
const device = r.getDevice?.();
|
|
765
|
+
const format = r.getFormat?.();
|
|
766
|
+
const moduleHost = r.getRendererModuleHost?.();
|
|
767
|
+
const libProvide = (token: any, value: unknown) => {
|
|
768
|
+
if (moduleHost) moduleHost.provideExternal("library", token, value);
|
|
769
|
+
};
|
|
770
|
+
const libInject = (token: any) => {
|
|
771
|
+
if (moduleHost) return moduleHost.injectResource(token);
|
|
772
|
+
throw new Error(`Library inject("${token.key}") failed — no renderer plugin host available`);
|
|
773
|
+
};
|
|
774
|
+
const libInjectOptional = (token: any) => {
|
|
775
|
+
if (moduleHost) return moduleHost.injectResourceOptional(token);
|
|
776
|
+
return undefined;
|
|
777
|
+
};
|
|
778
|
+
libHost.createRenderer({ provide: libProvide, inject: libInject, injectOptional: libInjectOptional });
|
|
779
|
+
// GPU-pass library init (after device is ready).
|
|
780
|
+
if (device && format) {
|
|
781
|
+
libHost.initRenderer({ device, format, provide: libProvide, inject: libInject, injectOptional: libInjectOptional });
|
|
782
|
+
libHost.setRendererBuffers(libBuffers);
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
// ── Renderer-owned sim resolution ──
|
|
787
|
+
// Games whose renderer spawns/starts the sim worker internally (declared
|
|
788
|
+
// via `module.simFromRenderer` instead of `module.sim`) get the worker
|
|
789
|
+
// resolved here — after renderer.init() has created it. ctx.sim is
|
|
790
|
+
// populated and declarative `events` routing is wired, matching the
|
|
791
|
+
// factory-created path. startGame() never calls start() on it — the
|
|
792
|
+
// renderer owns the lifecycle.
|
|
793
|
+
if (module.simFromRenderer) {
|
|
794
|
+
try {
|
|
795
|
+
const owned = await module.simFromRenderer(r, ctx);
|
|
796
|
+
if (owned) {
|
|
797
|
+
ctx.sim = owned;
|
|
798
|
+
ctx.simSAB = owned.getSimBuffer();
|
|
799
|
+
ctx.inputSAB = owned.getInputBuffer();
|
|
800
|
+
const extra = owned.getExtraBuffers?.() ?? {};
|
|
801
|
+
for (const [name, sab] of Object.entries(extra)) {
|
|
802
|
+
ctx.extraBuffers[name] = sab;
|
|
803
|
+
}
|
|
804
|
+
wireSimEvents(owned);
|
|
805
|
+
}
|
|
806
|
+
} catch (e) {
|
|
807
|
+
log.warn("startGame", `simFromRenderer resolution failed: ${e}`);
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
// ── Sim worker start ──
|
|
812
|
+
// When `onInit` is NOT overridden, startGame owns sim start — it runs
|
|
813
|
+
// here, after renderer.init() has succeeded. When `onInit` IS overridden,
|
|
814
|
+
// the game's onInit owns sim start (e.g. to-the-ocean starts the sim in
|
|
815
|
+
// parallel with renderer.init() inside its onInit). Renderer-only games
|
|
816
|
+
// have no sim worker to start.
|
|
817
|
+
if (simWorker && !module.onInit) {
|
|
818
|
+
if (module.onSimStart) {
|
|
819
|
+
await module.onSimStart(ctx);
|
|
820
|
+
} else {
|
|
821
|
+
await simWorker.start(module.simConfig ?? {});
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// ── Inline save store init (sim-worker + OPFS) ──
|
|
826
|
+
// Now that the sim worker is started, initialize its inline OPFS store.
|
|
827
|
+
// This must happen before the autosave load (which runs in bootstrapGame
|
|
828
|
+
// after onRendererInit returns) so that the sim worker can load from OPFS.
|
|
829
|
+
if (ctx.saveMode === "inline" && (ctx.sim ?? simWorker)?.initSaveStore && module.save) {
|
|
830
|
+
try {
|
|
831
|
+
await (ctx.sim ?? simWorker)!.initSaveStore!({
|
|
832
|
+
engineVersion: module.save.engineVersion,
|
|
833
|
+
maxGenerations: module.save.maxGenerations ?? 3,
|
|
834
|
+
});
|
|
835
|
+
} catch (e) {
|
|
836
|
+
log.warn("startGame", `Inline save store init failed, falling back to host save store: ${e}`);
|
|
837
|
+
ctx.saveMode = "host";
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
// ── Plugin loading ──
|
|
842
|
+
// Load all discovered plugins (renderer + own-worker threads). Sim-
|
|
843
|
+
// thread plugins are forwarded to the sim worker by the game's sim
|
|
844
|
+
// bridge (the sim worker runs its own PluginHost); here we load the
|
|
845
|
+
// renderer/own-worker subset. Failures are recorded on the plugin
|
|
846
|
+
// snapshot (ctx.pluginHost.snapshot()) and do not abort startup.
|
|
847
|
+
if (pluginHost) {
|
|
848
|
+
try {
|
|
849
|
+
// Wire the renderer's ModuleHost now that it exists — required for
|
|
850
|
+
// native-tier plugins (their context bridges into the typed-DI
|
|
851
|
+
// graph). Without it a native-tier mod fails with "no ModuleHost
|
|
852
|
+
// configured on this thread".
|
|
853
|
+
const mh = r?.getRendererModuleHost?.();
|
|
854
|
+
if (mh) pluginHost.setModuleHost(mh);
|
|
855
|
+
await pluginHost.loadAll();
|
|
856
|
+
} catch (e) {
|
|
857
|
+
log.warn("startGame", `Plugin loading error: ${e}`);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
// ── Declarative UI lifecycle ──
|
|
862
|
+
// Create + start the UI handle before onReady so
|
|
863
|
+
// hooks can wire subscriptions against ctx.ui.
|
|
864
|
+
if (module.ui) {
|
|
865
|
+
try {
|
|
866
|
+
ctx.ui = await module.ui(ctx);
|
|
867
|
+
await ctx.ui.start();
|
|
868
|
+
} catch (e) {
|
|
869
|
+
// UI failure is non-fatal — the game canvas still runs.
|
|
870
|
+
log.error("startGame", `UI start failed: ${e}`);
|
|
871
|
+
ctx.ui = undefined;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// ── Game-specific wiring ──
|
|
876
|
+
if (module.onReady) {
|
|
877
|
+
await module.onReady(ctx);
|
|
878
|
+
}
|
|
879
|
+
},
|
|
880
|
+
|
|
881
|
+
devtools: module.devtools,
|
|
882
|
+
|
|
883
|
+
autosave: module.save && !deterministic
|
|
884
|
+
? {
|
|
885
|
+
// Reuse the mode-aware ctx.save / ctx.load helpers so the autosave
|
|
886
|
+
// interval and manual saves share one code path.
|
|
887
|
+
load: async () => {
|
|
888
|
+
const slotName = module.save!.slotName ?? "autosave";
|
|
889
|
+
return ctx.load!(slotName);
|
|
890
|
+
},
|
|
891
|
+
save: async () => {
|
|
892
|
+
const slotName = module.save!.slotName ?? "autosave";
|
|
893
|
+
await ctx.save!(slotName);
|
|
894
|
+
},
|
|
895
|
+
intervalMs: module.save?.intervalMs,
|
|
896
|
+
}
|
|
897
|
+
: undefined,
|
|
898
|
+
|
|
899
|
+
mcp: module.mcp ? () => module.mcp!(ctx) : undefined,
|
|
900
|
+
|
|
901
|
+
onDisplayInfo: module.onDisplayInfo
|
|
902
|
+
? (rate) => module.onDisplayInfo!(rate, ctx)
|
|
903
|
+
: undefined,
|
|
904
|
+
|
|
905
|
+
onHotReloadDispose: () => {
|
|
906
|
+
ctx.ui?.dispose();
|
|
907
|
+
ctx.ui = undefined;
|
|
908
|
+
pluginHost?.disposeAll();
|
|
909
|
+
libHost?.disposeRenderer();
|
|
910
|
+
if (module.onDispose) {
|
|
911
|
+
module.onDispose(ctx);
|
|
912
|
+
}
|
|
913
|
+
},
|
|
914
|
+
|
|
915
|
+
onDeterministic: module.onDeterministic
|
|
916
|
+
? () => module.onDeterministic!(ctx)
|
|
917
|
+
: undefined,
|
|
918
|
+
|
|
919
|
+
onFpsUpdate: module.onFpsUpdate
|
|
920
|
+
? (fps) => module.onFpsUpdate!(fps, ctx)
|
|
921
|
+
: undefined,
|
|
922
|
+
});
|
|
923
|
+
}
|