@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,703 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// GameClient — client for a running game's in-process MCP automation endpoint.
|
|
3
|
+
//
|
|
4
|
+
// A running game (draft dev / draft test / launchGame) exposes a JSON-RPC
|
|
5
|
+
// over HTTP endpoint on 127.0.0.1 (McpHttpTransport) and advertises its port
|
|
6
|
+
// via ~/.downdraft/port/<pid>. This module is the single implementation of
|
|
7
|
+
// the client side of that wire — previously triplicated across
|
|
8
|
+
// scripts/mcp-call.mjs, .devin/mcp-stdio-bridge.mjs, and tests/e2e/harness.ts.
|
|
9
|
+
//
|
|
10
|
+
// import { GameClient, launchGame } from "@downdraft/engine/mcp/client";
|
|
11
|
+
//
|
|
12
|
+
// const client = await GameClient.connect(); // PID-file discovery
|
|
13
|
+
// const tools = await client.listTools();
|
|
14
|
+
// const state = await client.callJson("get_world_state");
|
|
15
|
+
// await client.screenshot("shot.png");
|
|
16
|
+
//
|
|
17
|
+
// // Or launch + connect + kill in one:
|
|
18
|
+
// const game = await launchGame({ game: "to-the-ocean" });
|
|
19
|
+
// await game.client.callText("get_player_state");
|
|
20
|
+
// await game.kill();
|
|
21
|
+
//
|
|
22
|
+
// Node- and Bun-compatible: only node: APIs + fetch, no Bun.* globals.
|
|
23
|
+
// ============================================================================
|
|
24
|
+
|
|
25
|
+
import { spawn, type ChildProcess } from "node:child_process";
|
|
26
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
27
|
+
import { createServer } from "node:net";
|
|
28
|
+
import { homedir } from "node:os";
|
|
29
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
30
|
+
import type { MCPToolDef, MCPToolResult } from "./types";
|
|
31
|
+
|
|
32
|
+
export type { MCPToolDef, MCPToolResult } from "./types";
|
|
33
|
+
|
|
34
|
+
const DEFAULT_TIMEOUT_MS = 120_000;
|
|
35
|
+
|
|
36
|
+
export class McpClientError extends Error {}
|
|
37
|
+
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// Instance discovery — ~/.downdraft/port/<pid> PID files
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
|
|
42
|
+
/** Directory holding one PID file per running game instance. Each file is
|
|
43
|
+
* named `<pid>` and contains the bound MCP HTTP port; a sibling
|
|
44
|
+
* `<pid>.token` holds the bearer token when the instance requires auth. */
|
|
45
|
+
export function mcpPortDir(): string {
|
|
46
|
+
return join(homedir(), ".downdraft", "port");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface GameInstance {
|
|
50
|
+
pid: number;
|
|
51
|
+
port: number;
|
|
52
|
+
/** Bearer token from `<pid>.token`, when the instance wrote one. */
|
|
53
|
+
token?: string;
|
|
54
|
+
/** PID-file mtime — newest instance wins when no selector is given. */
|
|
55
|
+
mtimeMs: number;
|
|
56
|
+
/** The instance's appId when it can be recovered (Linux /proc only). */
|
|
57
|
+
appId?: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface InstanceSelector {
|
|
61
|
+
/** Match instances whose --user-data-dir basename equals this appId
|
|
62
|
+
* (Linux-only; ignored elsewhere). */
|
|
63
|
+
appId?: string;
|
|
64
|
+
/** Match exactly this PID. */
|
|
65
|
+
pid?: number;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function isAlive(pid: number): boolean {
|
|
69
|
+
try {
|
|
70
|
+
process.kill(pid, 0);
|
|
71
|
+
return true;
|
|
72
|
+
} catch (e) {
|
|
73
|
+
return (e as NodeJS.ErrnoException).code === "EPERM";
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Best-effort appId recovery: read /proc/<pid>/cmdline and return the
|
|
78
|
+
* basename of --user-data-dir=<path>. Returns undefined on non-Linux or
|
|
79
|
+
* when the arg is absent. */
|
|
80
|
+
function readAppId(pid: number): string | undefined {
|
|
81
|
+
if (process.platform !== "linux") return undefined;
|
|
82
|
+
try {
|
|
83
|
+
const raw = readFileSync(`/proc/${pid}/cmdline`, "utf8");
|
|
84
|
+
const m = /--user-data-dir=(\S+)/.exec(raw.replace(/\0+$/g, "").replace(/\0/g, " "));
|
|
85
|
+
return m ? basename(m[1]) : undefined;
|
|
86
|
+
} catch {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** List all live game instances, newest-first. Dead PID files are pruned
|
|
92
|
+
* as a side effect. */
|
|
93
|
+
export function listGameInstances(sel: InstanceSelector = {}): GameInstance[] {
|
|
94
|
+
let entries: string[];
|
|
95
|
+
try {
|
|
96
|
+
entries = readdirSync(mcpPortDir());
|
|
97
|
+
} catch {
|
|
98
|
+
return [];
|
|
99
|
+
}
|
|
100
|
+
const out: GameInstance[] = [];
|
|
101
|
+
for (let _i = 0, _it = entries, _n = _it.length; _i < _n; _i++) { const name = _it[_i];
|
|
102
|
+
if (!/^\d+$/.test(name)) continue;
|
|
103
|
+
const pid = Number(name);
|
|
104
|
+
if (!isAlive(pid)) {
|
|
105
|
+
try { unlinkSync(join(mcpPortDir(), name)); } catch { /* gone */ }
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (sel.pid !== undefined && pid !== sel.pid) continue;
|
|
109
|
+
const appId = readAppId(pid);
|
|
110
|
+
if (sel.appId !== undefined && appId !== undefined && appId !== sel.appId) continue;
|
|
111
|
+
if (sel.appId !== undefined && appId === undefined && process.platform === "linux") continue;
|
|
112
|
+
|
|
113
|
+
let port: number;
|
|
114
|
+
try {
|
|
115
|
+
const raw = readFileSync(join(mcpPortDir(), name), "utf8").trim();
|
|
116
|
+
if (!/^\d+$/.test(raw)) continue;
|
|
117
|
+
port = Number(raw);
|
|
118
|
+
} catch {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
let token: string | undefined;
|
|
122
|
+
try {
|
|
123
|
+
token = readFileSync(join(mcpPortDir(), `${name}.token`), "utf8").trim() || undefined;
|
|
124
|
+
} catch { /* no token file — auth not required */ }
|
|
125
|
+
let mtimeMs = 0;
|
|
126
|
+
try {
|
|
127
|
+
mtimeMs = statSync(join(mcpPortDir(), name)).mtimeMs;
|
|
128
|
+
} catch { /* treat as oldest */ }
|
|
129
|
+
out.push({ pid, port, token, mtimeMs, appId });
|
|
130
|
+
}
|
|
131
|
+
out.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
132
|
+
return out;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Pick the newest live instance matching the selector, or null. */
|
|
136
|
+
export function discoverGameInstance(sel: InstanceSelector = {}): GameInstance | null {
|
|
137
|
+
return listGameInstances(sel)[0] ?? null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ---------------------------------------------------------------------------
|
|
141
|
+
// GameClient
|
|
142
|
+
// ---------------------------------------------------------------------------
|
|
143
|
+
|
|
144
|
+
export interface GameClientOptions {
|
|
145
|
+
/** Narrow discovery to a specific game's appId. */
|
|
146
|
+
appId?: string;
|
|
147
|
+
/** Connect to a specific PID. */
|
|
148
|
+
pid?: number;
|
|
149
|
+
/** Explicit endpoint URL (e.g. http://localhost:9976/mcp) — skips
|
|
150
|
+
* PID-file discovery entirely. */
|
|
151
|
+
url?: string;
|
|
152
|
+
/** Bearer token; auto-read from <pid>.token on discovery. */
|
|
153
|
+
token?: string;
|
|
154
|
+
/** Per-request timeout in ms (default 120s). */
|
|
155
|
+
timeoutMs?: number;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export interface CallOptions {
|
|
159
|
+
timeoutMs?: number;
|
|
160
|
+
retries?: number;
|
|
161
|
+
backoffMs?: number;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
interface JsonRpcResponse {
|
|
165
|
+
result?: unknown;
|
|
166
|
+
error?: { code: number; message: string };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Minimal process handle for liveness checks during waitForReady —
|
|
170
|
+
* satisfied by node:child_process ChildProcess and Bun's Subprocess. */
|
|
171
|
+
export interface ProcessProbe {
|
|
172
|
+
exitCode: number | null;
|
|
173
|
+
killed?: boolean;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function sleep(ms: number): Promise<void> {
|
|
177
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export class GameClient {
|
|
181
|
+
readonly url: string;
|
|
182
|
+
readonly pid: number | undefined;
|
|
183
|
+
private token: string | undefined;
|
|
184
|
+
private sessionId: string | null = null;
|
|
185
|
+
private reqId = 0;
|
|
186
|
+
private defaultTimeout: number;
|
|
187
|
+
|
|
188
|
+
private constructor(url: string, token: string | undefined, pid: number | undefined, timeoutMs: number) {
|
|
189
|
+
this.url = url;
|
|
190
|
+
this.token = token;
|
|
191
|
+
this.pid = pid;
|
|
192
|
+
this.defaultTimeout = timeoutMs;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Connect to a running game instance. With no selector, attaches to the
|
|
197
|
+
* newest live instance in ~/.downdraft/port/. Performs the `initialize`
|
|
198
|
+
* handshake before returning.
|
|
199
|
+
*/
|
|
200
|
+
static async connect(opts: GameClientOptions = {}): Promise<GameClient> {
|
|
201
|
+
// Env fallbacks: DOWNDRAFT_MCP_URL/MCP_HTTP_URL for explicit targets,
|
|
202
|
+
// MCP_APP_ID/MCP_PID for discovery selectors — the same selectors the
|
|
203
|
+
// old stdio bridge honored, so existing configs keep working.
|
|
204
|
+
const envPid = Number(process.env.MCP_PID);
|
|
205
|
+
const appId = opts.appId ?? process.env.MCP_APP_ID;
|
|
206
|
+
let pid = opts.pid ?? (Number.isFinite(envPid) && envPid > 0 ? envPid : undefined);
|
|
207
|
+
let url = opts.url ?? process.env.DOWNDRAFT_MCP_URL ?? process.env.MCP_HTTP_URL;
|
|
208
|
+
let token = opts.token ?? process.env.DOWNDRAFT_MCP_TOKEN ?? process.env.MCP_TOKEN;
|
|
209
|
+
if (!url) {
|
|
210
|
+
const inst = discoverGameInstance({ appId, pid });
|
|
211
|
+
if (!inst) {
|
|
212
|
+
const filter = appId
|
|
213
|
+
? ` with appId "${appId}"`
|
|
214
|
+
: pid !== undefined
|
|
215
|
+
? ` with PID ${pid}`
|
|
216
|
+
: "";
|
|
217
|
+
throw new McpClientError(
|
|
218
|
+
`No running downdraft game instance found${filter} in ${mcpPortDir()}. ` +
|
|
219
|
+
`Start a game first (e.g. \`draft dev\`), or pass url / set DOWNDRAFT_MCP_URL.`,
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
url = `http://localhost:${inst.port}/mcp`;
|
|
223
|
+
token ??= inst.token;
|
|
224
|
+
pid = inst.pid;
|
|
225
|
+
}
|
|
226
|
+
const client = new GameClient(url, token, pid, opts.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
227
|
+
await client.rpc("initialize", {
|
|
228
|
+
protocolVersion: "2024-11-05",
|
|
229
|
+
capabilities: {},
|
|
230
|
+
clientInfo: { name: "downdraft-game-client", version: "0.1.0" },
|
|
231
|
+
}, 10_000);
|
|
232
|
+
return client;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
private headers(): Record<string, string> {
|
|
236
|
+
const h: Record<string, string> = {
|
|
237
|
+
"Content-Type": "application/json",
|
|
238
|
+
// Deliberately no text/event-stream — the transport then answers
|
|
239
|
+
// with plain JSON instead of SSE framing.
|
|
240
|
+
"Accept": "application/json",
|
|
241
|
+
};
|
|
242
|
+
if (this.sessionId) h["Mcp-Session-Id"] = this.sessionId;
|
|
243
|
+
if (this.token) h["X-Downdraft-Token"] = this.token;
|
|
244
|
+
return h;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
private async rpc(method: string, params: Record<string, unknown> = {}, timeoutMs?: number): Promise<unknown> {
|
|
248
|
+
const res = await fetch(this.url, {
|
|
249
|
+
method: "POST",
|
|
250
|
+
headers: this.headers(),
|
|
251
|
+
body: JSON.stringify({ jsonrpc: "2.0", id: ++this.reqId, method, params }),
|
|
252
|
+
signal: AbortSignal.timeout(timeoutMs ?? this.defaultTimeout),
|
|
253
|
+
});
|
|
254
|
+
const sid = res.headers.get("Mcp-Session-Id");
|
|
255
|
+
if (sid) this.sessionId = sid;
|
|
256
|
+
const text = await res.text();
|
|
257
|
+
if (!res.ok) throw new McpClientError(`MCP HTTP ${res.status}: ${text.slice(0, 500)}`);
|
|
258
|
+
let json: JsonRpcResponse;
|
|
259
|
+
try {
|
|
260
|
+
json = JSON.parse(text);
|
|
261
|
+
} catch {
|
|
262
|
+
throw new McpClientError(`Non-JSON response: ${text.slice(0, 500)}`);
|
|
263
|
+
}
|
|
264
|
+
if (json.error) throw new McpClientError(`MCP error ${json.error.code}: ${json.error.message}`);
|
|
265
|
+
// Proxy mode wraps handler errors in result.error — surface those too.
|
|
266
|
+
const result = json.result as { error?: { code: number; message: string } } | undefined;
|
|
267
|
+
if (result?.error) throw new McpClientError(`MCP error ${result.error.code}: ${result.error.message}`);
|
|
268
|
+
return json.result;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/** Raw JSON-RPC method call — for methods without a typed helper
|
|
272
|
+
* (resources/read, prompts/get) and the stdio bridge's forwarding. */
|
|
273
|
+
async request(method: string, params: Record<string, unknown> = {}, timeoutMs?: number): Promise<unknown> {
|
|
274
|
+
return this.rpc(method, params, timeoutMs);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/** tools/list — the tool defs the game registered. */
|
|
278
|
+
async listTools(): Promise<MCPToolDef[]> {
|
|
279
|
+
const result = (await this.rpc("tools/list", {}, 10_000)) as { tools?: MCPToolDef[] };
|
|
280
|
+
return result.tools ?? [];
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/** tools/call — returns the raw {content, isError} envelope. */
|
|
284
|
+
async call(name: string, args: Record<string, unknown> = {}, opts: CallOptions = {}): Promise<MCPToolResult> {
|
|
285
|
+
return (await this.rpc("tools/call", { name, arguments: args }, opts.timeoutMs)) as MCPToolResult;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
private textOrThrow(result: MCPToolResult): string {
|
|
289
|
+
const text = (result.content ?? [])
|
|
290
|
+
.filter((c): c is { type: "text"; text: string } => c.type === "text")
|
|
291
|
+
.map((c) => c.text)
|
|
292
|
+
.join("\n");
|
|
293
|
+
if (result.isError) throw new McpClientError(`MCP tool returned an error: ${text}`);
|
|
294
|
+
return text;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/** tools/call → concatenated text content; throws when isError. */
|
|
298
|
+
async callText(name: string, args: Record<string, unknown> = {}, opts: CallOptions = {}): Promise<string> {
|
|
299
|
+
return this.textOrThrow(await this.call(name, args, opts));
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/** tools/call → JSON.parse of the text content; throws on isError or
|
|
303
|
+
* non-JSON output. */
|
|
304
|
+
async callJson<T = unknown>(name: string, args: Record<string, unknown> = {}, opts: CallOptions = {}): Promise<T> {
|
|
305
|
+
const text = this.textOrThrow(await this.call(name, args, opts));
|
|
306
|
+
try {
|
|
307
|
+
return JSON.parse(text) as T;
|
|
308
|
+
} catch (e) {
|
|
309
|
+
throw new McpClientError(`MCP tool returned non-JSON text: ${(e as Error).message} | ${text.slice(0, 200)}`);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/** Retry on transport/connection errors only — tool-level isError
|
|
314
|
+
* results are thrown immediately. */
|
|
315
|
+
async callWithRetry(name: string, args: Record<string, unknown> = {}, opts: CallOptions = {}): Promise<MCPToolResult> {
|
|
316
|
+
const maxRetries = opts.retries ?? 3;
|
|
317
|
+
const backoffMs = opts.backoffMs ?? 500;
|
|
318
|
+
let lastError: Error | null = null;
|
|
319
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
320
|
+
try {
|
|
321
|
+
const result = await this.call(name, args, opts);
|
|
322
|
+
if (result.isError) {
|
|
323
|
+
throw new McpClientError(`MCP tool returned an error: ${result.content?.[0] && "text" in result.content[0] ? result.content[0].text : ""}`);
|
|
324
|
+
}
|
|
325
|
+
return result;
|
|
326
|
+
} catch (e) {
|
|
327
|
+
lastError = e as Error;
|
|
328
|
+
const msg = lastError.message;
|
|
329
|
+
const isTransportError =
|
|
330
|
+
msg.includes("MCP HTTP") ||
|
|
331
|
+
msg.includes("fetch failed") ||
|
|
332
|
+
msg.includes("aborted") ||
|
|
333
|
+
msg.includes("ECONNREFUSED") ||
|
|
334
|
+
msg.includes("MCP error");
|
|
335
|
+
if (!isTransportError || attempt === maxRetries) throw lastError;
|
|
336
|
+
await sleep(backoffMs * (attempt + 1));
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
throw lastError ?? new McpClientError("callWithRetry exhausted retries");
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/** capture_screenshot → write the image block to `path` as PNG. Returns
|
|
343
|
+
* the dimensions from the tool's text metadata. */
|
|
344
|
+
async screenshot(path: string, args: Record<string, unknown> = {}): Promise<{ width: number; height: number }> {
|
|
345
|
+
const result = await this.call("capture_screenshot", { fullPage: true, ...args });
|
|
346
|
+
const text = this.textOrThrow(result);
|
|
347
|
+
let meta: { width?: number; height?: number } = {};
|
|
348
|
+
try { meta = JSON.parse(text); } catch { /* older tools may not emit meta */ }
|
|
349
|
+
const image = result.content.find((c) => c.type === "image") as
|
|
350
|
+
| { type: "image"; data: string; mimeType: string }
|
|
351
|
+
| undefined;
|
|
352
|
+
if (!image?.data) throw new McpClientError("capture_screenshot returned no image data");
|
|
353
|
+
mkdirSync(dirname(resolve(path)), { recursive: true });
|
|
354
|
+
writeFileSync(path, Buffer.from(image.data, "base64"));
|
|
355
|
+
return { width: meta.width ?? 0, height: meta.height ?? 0 };
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Wait until the instance is serving MCP and has registered tools:
|
|
360
|
+
* poll GET /mcp/health, then initialize + tools/list until non-empty.
|
|
361
|
+
* `proc` (optional) enables fail-fast when a launched game dies early.
|
|
362
|
+
* A final capture_screenshot probe warns (non-fatal) when WebGPU isn't
|
|
363
|
+
* producing frames yet — mirrors the e2e harness's readiness check.
|
|
364
|
+
*/
|
|
365
|
+
async waitForReady(timeoutMs = 90_000, opts: { proc?: ProcessProbe } = {}): Promise<void> {
|
|
366
|
+
const healthUrl = this.url.replace(/\/mcp\/?$/, "/mcp/health");
|
|
367
|
+
const deadline = Date.now() + timeoutMs;
|
|
368
|
+
let lastErr = "";
|
|
369
|
+
const alive = () => !opts.proc || (opts.proc.exitCode === null && !opts.proc.killed);
|
|
370
|
+
const failIfDead = (stage: string) => {
|
|
371
|
+
if (!alive()) throw new McpClientError(`Game process exited before ${stage} became ready`);
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
while (Date.now() < deadline) {
|
|
375
|
+
failIfDead("MCP health endpoint");
|
|
376
|
+
try {
|
|
377
|
+
const res = await fetch(healthUrl, {
|
|
378
|
+
headers: this.token ? { "X-Downdraft-Token": this.token } : {},
|
|
379
|
+
signal: AbortSignal.timeout(5_000),
|
|
380
|
+
});
|
|
381
|
+
if (res.ok) break;
|
|
382
|
+
lastErr = `HTTP ${res.status}`;
|
|
383
|
+
} catch (e) {
|
|
384
|
+
lastErr = (e as Error).message;
|
|
385
|
+
}
|
|
386
|
+
await sleep(250);
|
|
387
|
+
}
|
|
388
|
+
if (Date.now() >= deadline) {
|
|
389
|
+
throw new McpClientError(`MCP health endpoint did not become ready at ${healthUrl}: ${lastErr}`);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
while (Date.now() < deadline) {
|
|
393
|
+
failIfDead("MCP tools");
|
|
394
|
+
try {
|
|
395
|
+
const tools = await this.listTools();
|
|
396
|
+
if (tools.length > 0) break;
|
|
397
|
+
lastErr = "tools list empty";
|
|
398
|
+
} catch (e) {
|
|
399
|
+
lastErr = (e as Error).message;
|
|
400
|
+
}
|
|
401
|
+
await sleep(1_000);
|
|
402
|
+
}
|
|
403
|
+
if (Date.now() >= deadline) {
|
|
404
|
+
throw new McpClientError(`MCP tools did not become available at ${this.url}: ${lastErr}`);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Best-effort readiness probe: a valid screenshot implies WebGPU is
|
|
408
|
+
// initialized. Warn but don't fail — some games can't screenshot in
|
|
409
|
+
// their initial state.
|
|
410
|
+
const probeDeadline = Math.min(Date.now() + 30_000, deadline + 30_000);
|
|
411
|
+
let lastProbeErr = "";
|
|
412
|
+
while (Date.now() < probeDeadline) {
|
|
413
|
+
failIfDead("readiness probe");
|
|
414
|
+
try {
|
|
415
|
+
const result = await this.call("capture_screenshot", { fullPage: false }, { timeoutMs: 10_000 });
|
|
416
|
+
if (!result.isError && result.content?.some((c) => c.type === "image" && c.data)) return;
|
|
417
|
+
lastProbeErr = result.isError
|
|
418
|
+
? `capture_screenshot error: ${result.content?.[0] && "text" in result.content[0] ? result.content[0].text : ""}`
|
|
419
|
+
: "capture_screenshot returned no image data";
|
|
420
|
+
} catch (e) {
|
|
421
|
+
lastProbeErr = (e as Error).message;
|
|
422
|
+
}
|
|
423
|
+
await sleep(1_000);
|
|
424
|
+
}
|
|
425
|
+
process.stderr.write(`[GameClient] readiness probe failed (non-fatal): ${lastProbeErr}\n`);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// ── Harness-compat aliases (the old tests/e2e McpClient interface) ──
|
|
429
|
+
callTool(name: string, args: Record<string, unknown> = {}, opts: CallOptions = {}): Promise<MCPToolResult> {
|
|
430
|
+
return this.call(name, args, opts);
|
|
431
|
+
}
|
|
432
|
+
callToolWithRetry(name: string, args: Record<string, unknown> = {}, opts: CallOptions = {}): Promise<MCPToolResult> {
|
|
433
|
+
return this.callWithRetry(name, args, opts);
|
|
434
|
+
}
|
|
435
|
+
close(): void {
|
|
436
|
+
// Stateless HTTP — nothing to tear down.
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// ---------------------------------------------------------------------------
|
|
441
|
+
// launchGame — spawn a game, wait for MCP, connect
|
|
442
|
+
// ---------------------------------------------------------------------------
|
|
443
|
+
|
|
444
|
+
export interface LaunchGameOptions {
|
|
445
|
+
/** Game name resolved to games/<name>/ or examples/<name>/ under cwd. */
|
|
446
|
+
game?: string;
|
|
447
|
+
/** Explicit entry file (default: <game>/src/native-entry.ts). */
|
|
448
|
+
entry?: string;
|
|
449
|
+
/** Working directory for the spawned process (default: process.cwd() —
|
|
450
|
+
* the monorepo root or a standalone game dir, where bunfig.toml's
|
|
451
|
+
* preload registers the ?raw/.wgsl/.css loaders). */
|
|
452
|
+
cwd?: string;
|
|
453
|
+
/** MCP_PORT pin; default is an OS-assigned free port. */
|
|
454
|
+
port?: number;
|
|
455
|
+
/** DOWNDRAFT_DETERMINISTIC=1 (fixed seed, paused render loop). */
|
|
456
|
+
deterministic?: boolean;
|
|
457
|
+
/** DOWNDRAFT_GPU value. Default: parent env, else "swiftshader". */
|
|
458
|
+
gpu?: "auto" | "hardware" | "swiftshader";
|
|
459
|
+
/** DOWNDRAFT_HEADED=1 — show the window instead of headless. */
|
|
460
|
+
headed?: boolean;
|
|
461
|
+
/** Extra env vars, applied last. */
|
|
462
|
+
env?: Record<string, string>;
|
|
463
|
+
/** Extra console-output patterns to ignore for getConsoleErrors(). */
|
|
464
|
+
ignoreErrorPatterns?: RegExp[];
|
|
465
|
+
/** Readiness budget in ms (default 90s). */
|
|
466
|
+
timeoutMs?: number;
|
|
467
|
+
/** Tee child stdout/stderr to this process's (default false). */
|
|
468
|
+
mirrorOutput?: boolean;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
export interface LaunchedGame {
|
|
472
|
+
client: GameClient;
|
|
473
|
+
process: ChildProcess;
|
|
474
|
+
pid: number;
|
|
475
|
+
port: number;
|
|
476
|
+
/** The instance's bearer token (may be undefined when the launch raced
|
|
477
|
+
* the pid-file write; tools still work unless auth is required). */
|
|
478
|
+
token?: string;
|
|
479
|
+
/** JS-error-looking lines captured from the child's console output. */
|
|
480
|
+
getConsoleErrors(): string[];
|
|
481
|
+
/** SIGTERM the process group + /proc descendants, SIGKILL after 5s. */
|
|
482
|
+
kill(): Promise<void>;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/** Find a free loopback TCP port (OS-assigned). */
|
|
486
|
+
export function findFreePort(): Promise<number> {
|
|
487
|
+
return new Promise((resolvePort, reject) => {
|
|
488
|
+
const srv = createServer();
|
|
489
|
+
srv.listen(0, "127.0.0.1", () => {
|
|
490
|
+
const addr = srv.address();
|
|
491
|
+
const port = typeof addr === "object" && addr ? addr.port : 0;
|
|
492
|
+
srv.close(() => (port ? resolvePort(port) : reject(new Error("no port assigned"))));
|
|
493
|
+
});
|
|
494
|
+
srv.on("error", reject);
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
const DEFAULT_ERROR_PATTERNS = [
|
|
499
|
+
/Uncaught/i,
|
|
500
|
+
/TypeError:/,
|
|
501
|
+
/ReferenceError:/,
|
|
502
|
+
/SyntaxError:/,
|
|
503
|
+
/RangeError:/,
|
|
504
|
+
/WrongDocumentError:/,
|
|
505
|
+
/is not a function/,
|
|
506
|
+
/is not defined/,
|
|
507
|
+
/cannot read propert/i,
|
|
508
|
+
/REJECTED action/i,
|
|
509
|
+
/GPU process exited unexpectedly/i,
|
|
510
|
+
/WebGPU.*not available/i,
|
|
511
|
+
/adapter request failed/i,
|
|
512
|
+
/\[.*WorkerHost.*\]\s*[Ww]orker error:/i,
|
|
513
|
+
];
|
|
514
|
+
|
|
515
|
+
const DEFAULT_IGNORE_PATTERNS = [
|
|
516
|
+
/ERROR:components\/services\/storage/,
|
|
517
|
+
/ERROR:storage\/browser/,
|
|
518
|
+
/Gtk-Message/,
|
|
519
|
+
/deprecated.*session\.loadExtension/,
|
|
520
|
+
/SandboxOriginDatabase/,
|
|
521
|
+
/Failed to load module.*xapp-gtk3/,
|
|
522
|
+
/Failed to delete the database/,
|
|
523
|
+
/Could not open the quota database/,
|
|
524
|
+
/WebSocket connection.*failed/,
|
|
525
|
+
/gc.*does not exist/,
|
|
526
|
+
/Physics re-initialized after panic/i,
|
|
527
|
+
/Slow (tick|physics)/,
|
|
528
|
+
];
|
|
529
|
+
|
|
530
|
+
function isRealError(line: string, extraIgnorePatterns: RegExp[] = []): boolean {
|
|
531
|
+
const stripped = line.replace(/\x1b\[[0-9;]*m/g, "").replace(/\x1b\[[0-9;]*/g, "");
|
|
532
|
+
if (!DEFAULT_ERROR_PATTERNS.some((p) => p.test(stripped))) return false;
|
|
533
|
+
if (DEFAULT_IGNORE_PATTERNS.some((p) => p.test(stripped))) return false;
|
|
534
|
+
return !extraIgnorePatterns.some((p) => p.test(stripped));
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/** Collect all descendant PIDs of `rootPid` by walking /proc/<pid>/stat on
|
|
538
|
+
* Linux. Backup for helpers that called setsid and escaped the process
|
|
539
|
+
* group — the group signal alone would miss them. */
|
|
540
|
+
function collectDescendants(rootPid: number): number[] {
|
|
541
|
+
const childrenOf = new Map<number, number[]>();
|
|
542
|
+
try {
|
|
543
|
+
for (const entry of readdirSync("/proc")) {
|
|
544
|
+
if (!/^\d+$/.test(entry)) continue;
|
|
545
|
+
const pid = Number(entry);
|
|
546
|
+
if (pid === rootPid) continue;
|
|
547
|
+
try {
|
|
548
|
+
const stat = readFileSync(`/proc/${entry}/stat`, "utf8");
|
|
549
|
+
const rparen = stat.lastIndexOf(")");
|
|
550
|
+
if (rparen < 0) continue;
|
|
551
|
+
const ppid = Number(stat.slice(rparen + 2).split(" ")[1]);
|
|
552
|
+
if (ppid === rootPid || childrenOf.has(ppid)) {
|
|
553
|
+
const list = childrenOf.get(ppid) ?? [];
|
|
554
|
+
list.push(pid);
|
|
555
|
+
childrenOf.set(ppid, list);
|
|
556
|
+
}
|
|
557
|
+
} catch {
|
|
558
|
+
// Process exited between readdir and read — ignore.
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
} catch {
|
|
562
|
+
return []; // /proc unavailable (non-Linux)
|
|
563
|
+
}
|
|
564
|
+
const result: number[] = [];
|
|
565
|
+
const queue = [rootPid];
|
|
566
|
+
while (queue.length) {
|
|
567
|
+
const cur = queue.shift()!;
|
|
568
|
+
(childrenOf.get(cur) ?? []).forEach((k) => {
|
|
569
|
+
result.push(k);
|
|
570
|
+
queue.push(k);
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
return result;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* Launch a game on the native runtime (`bun <entry>`), wait for its MCP
|
|
578
|
+
* endpoint to serve tools, and return a connected GameClient plus a kill()
|
|
579
|
+
* that tears down the whole process tree (detached group kill + /proc
|
|
580
|
+
* descendant sweep — the game must not outlive the caller).
|
|
581
|
+
*/
|
|
582
|
+
export async function launchGame(opts: LaunchGameOptions = {}): Promise<LaunchedGame> {
|
|
583
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
584
|
+
const game = opts.game ?? "to-the-ocean";
|
|
585
|
+
const entry = opts.entry
|
|
586
|
+
? resolve(cwd, opts.entry)
|
|
587
|
+
: [
|
|
588
|
+
resolve(cwd, "games", game, "src", "native-entry.ts"),
|
|
589
|
+
resolve(cwd, "examples", game, "src", "native-entry.ts"),
|
|
590
|
+
resolve(cwd, "src", "native-entry.ts"),
|
|
591
|
+
].find((p) => existsSync(p)) ?? resolve(cwd, "games", game, "src", "native-entry.ts");
|
|
592
|
+
if (!existsSync(entry)) {
|
|
593
|
+
throw new McpClientError(`Game entry not found: ${entry} (pass --entry or game:)`);
|
|
594
|
+
}
|
|
595
|
+
const port = opts.port ?? (await findFreePort());
|
|
596
|
+
|
|
597
|
+
const env: Record<string, string> = {
|
|
598
|
+
...process.env,
|
|
599
|
+
MCP_PORT: String(port),
|
|
600
|
+
MCP_TIMEOUT_MS: String(DEFAULT_TIMEOUT_MS),
|
|
601
|
+
DOWNDRAFT_GPU: opts.gpu ?? process.env.DOWNDRAFT_GPU ?? "swiftshader",
|
|
602
|
+
...(opts.deterministic ? { DOWNDRAFT_DETERMINISTIC: "1" } : {}),
|
|
603
|
+
...(opts.headed ? { DOWNDRAFT_HEADED: "1" } : {}),
|
|
604
|
+
...opts.env,
|
|
605
|
+
};
|
|
606
|
+
const proc = spawn("bun", [entry], {
|
|
607
|
+
cwd,
|
|
608
|
+
env,
|
|
609
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
610
|
+
// New session → child is a process-group leader, so kill(-pid)
|
|
611
|
+
// reaches helpers that get re-parented to init.
|
|
612
|
+
detached: true,
|
|
613
|
+
});
|
|
614
|
+
const exited = new Promise<number | null>((res) => proc.once("exit", (code) => res(code)));
|
|
615
|
+
|
|
616
|
+
// Capture console output lines to detect JS errors.
|
|
617
|
+
const consoleErrors: string[] = [];
|
|
618
|
+
const watchStream = (stream: NodeJS.ReadableStream | null, mirror: (s: string) => void) => {
|
|
619
|
+
if (!stream) return;
|
|
620
|
+
let buf = "";
|
|
621
|
+
stream.on("data", (chunk: Buffer) => {
|
|
622
|
+
const text = chunk.toString();
|
|
623
|
+
buf += text;
|
|
624
|
+
if (opts.mirrorOutput) mirror(text);
|
|
625
|
+
const lines = buf.split("\n");
|
|
626
|
+
buf = lines.pop() ?? "";
|
|
627
|
+
lines.forEach((line) => {
|
|
628
|
+
if (isRealError(line, opts.ignoreErrorPatterns)) {
|
|
629
|
+
consoleErrors.push(line.replace(/\x1b\[[0-9;]*m/g, "").trim());
|
|
630
|
+
}
|
|
631
|
+
});
|
|
632
|
+
});
|
|
633
|
+
};
|
|
634
|
+
watchStream(proc.stdout, (s) => process.stdout.write(s));
|
|
635
|
+
watchStream(proc.stderr, (s) => process.stderr.write(s));
|
|
636
|
+
|
|
637
|
+
const kill = async () => {
|
|
638
|
+
const pid = proc.pid;
|
|
639
|
+
const signalAll = (sig: NodeJS.Signals) => {
|
|
640
|
+
if (pid) {
|
|
641
|
+
try { process.kill(-pid, sig); } catch { /* group already gone */ }
|
|
642
|
+
[pid, ...collectDescendants(pid)].forEach((p) => {
|
|
643
|
+
try { process.kill(p, sig); } catch { /* already dead */ }
|
|
644
|
+
});
|
|
645
|
+
} else {
|
|
646
|
+
try { proc.kill(sig); } catch { /* already dead */ }
|
|
647
|
+
}
|
|
648
|
+
};
|
|
649
|
+
signalAll("SIGTERM");
|
|
650
|
+
try {
|
|
651
|
+
await Promise.race([
|
|
652
|
+
exited,
|
|
653
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), 5_000)),
|
|
654
|
+
]);
|
|
655
|
+
} catch {
|
|
656
|
+
signalAll("SIGKILL");
|
|
657
|
+
try { await exited; } catch { /* gone */ }
|
|
658
|
+
}
|
|
659
|
+
};
|
|
660
|
+
|
|
661
|
+
// The token file (when required) is written synchronously at server
|
|
662
|
+
// bind — poll briefly so callers don't race it.
|
|
663
|
+
let token: string | undefined;
|
|
664
|
+
{
|
|
665
|
+
const tokenFile = join(mcpPortDir(), `${proc.pid}.token`);
|
|
666
|
+
const deadline = Date.now() + 15_000;
|
|
667
|
+
while (Date.now() < deadline && proc.exitCode === null) {
|
|
668
|
+
if (existsSync(tokenFile)) {
|
|
669
|
+
try { token = readFileSync(tokenFile, "utf8").trim() || undefined; } catch { /* retry */ }
|
|
670
|
+
break;
|
|
671
|
+
}
|
|
672
|
+
// No token file → auth not required; don't wait for a file that
|
|
673
|
+
// will never appear. But it also may just not be written yet —
|
|
674
|
+
// the transport always writes one, so if the pid file exists
|
|
675
|
+
// but the token doesn't, auth is genuinely off.
|
|
676
|
+
if (existsSync(join(mcpPortDir(), String(proc.pid)))) break;
|
|
677
|
+
await sleep(100);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
const client = await GameClient.connect({
|
|
682
|
+
url: `http://localhost:${port}/mcp`,
|
|
683
|
+
token,
|
|
684
|
+
timeoutMs: opts.timeoutMs,
|
|
685
|
+
}).catch(async (e) => { await kill(); throw e; });
|
|
686
|
+
|
|
687
|
+
try {
|
|
688
|
+
await client.waitForReady(opts.timeoutMs ?? 90_000, { proc });
|
|
689
|
+
} catch (e) {
|
|
690
|
+
await kill();
|
|
691
|
+
throw e;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
return {
|
|
695
|
+
client,
|
|
696
|
+
process: proc,
|
|
697
|
+
pid: proc.pid ?? 0,
|
|
698
|
+
port,
|
|
699
|
+
token,
|
|
700
|
+
getConsoleErrors: () => [...consoleErrors],
|
|
701
|
+
kill,
|
|
702
|
+
};
|
|
703
|
+
}
|