@zylem/behaviors 0.5.2 → 0.5.7
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/dist/{behavior-system-CldqNUgr.d.ts → behavior-system-HEt67el5.d.ts} +14 -1
- package/dist/{chunk-EIWQM6U3.js → chunk-2HKY6WF7.js} +0 -1
- package/dist/{chunk-IZJFUAXB.js → chunk-2HLZBWGD.js} +0 -1
- package/dist/{chunk-LL4FLHIY.js → chunk-2YF7J3H4.js} +0 -1
- package/dist/{chunk-SGHIGTVZ.js → chunk-3X3CL24Z.js} +0 -1
- package/dist/{chunk-HZMY3TT4.js → chunk-4DVDFCVY.js} +0 -1
- package/dist/{chunk-QVCMJ4Q2.js → chunk-4EWASZHB.js} +0 -1
- package/dist/{chunk-4LLK2FJI.js → chunk-55CFXXZH.js} +3 -4
- package/dist/{chunk-4MZ57HPD.js → chunk-57GLKGEX.js} +3 -4
- package/dist/{chunk-QS3VXWVO.js → chunk-7GGR26YA.js} +3 -4
- package/dist/{chunk-Y4PHT2HG.js → chunk-7LHXAEOZ.js} +4 -5
- package/dist/{chunk-PLIXVF7B.js → chunk-7TIIRJKF.js} +3 -4
- package/dist/{chunk-LZIHSJZR.js → chunk-CB3C7CRD.js} +4 -5
- package/dist/{chunk-G2KUXVU6.js → chunk-CTSYM56P.js} +30 -12
- package/dist/{chunk-2PAHQZZD.js → chunk-CVRN7YAI.js} +3 -4
- package/dist/{chunk-NW4SE5XW.js → chunk-DD4U42FG.js} +2 -3
- package/dist/{chunk-BAXJ7XHJ.js → chunk-E2MOFIDH.js} +3 -4
- package/dist/{chunk-WOMHL23C.js → chunk-ERS6SNA5.js} +1 -2
- package/dist/{chunk-4WH2ZN7P.js → chunk-F7E23E26.js} +0 -1
- package/dist/{chunk-DZ4LLQON.js → chunk-GZ3DQIIZ.js} +23 -2
- package/dist/{chunk-5WRI5ZAA.js → chunk-JSBRDJBE.js} +0 -1
- package/dist/{chunk-5A5AYP2C.js → chunk-K6CWKFHL.js} +0 -1
- package/dist/{chunk-52FJIDGL.js → chunk-LAN7U3AK.js} +1 -2
- package/dist/{chunk-WU6XXL3D.js → chunk-LLDLVVG4.js} +4 -5
- package/dist/{chunk-M3QDKKDF.js → chunk-LWM346FW.js} +0 -1
- package/dist/{chunk-7DGXUAPV.js → chunk-M25QJBDN.js} +4 -5
- package/dist/{chunk-7JLWZXPA.js → chunk-NDJO56BB.js} +3 -4
- package/dist/{chunk-AS3HR7AS.js → chunk-OBF6BIA2.js} +1 -2
- package/dist/{chunk-KIYUUSPK.js → chunk-OSPQFWQF.js} +2 -3
- package/dist/{chunk-4CEW64HO.js → chunk-OU2SW4U5.js} +3 -4
- package/dist/{chunk-H4TJ7X4O.js → chunk-QU6GQ657.js} +2 -3
- package/dist/{chunk-KFFETUAL.js → chunk-RR3XNDKG.js} +2 -3
- package/dist/{chunk-JVADRLWX.js → chunk-SHZZ2QRV.js} +2 -3
- package/dist/{chunk-7W3KY55G.js → chunk-TK3AXXXI.js} +3 -4
- package/dist/{chunk-OPZ2LVS2.js → chunk-TZQQYJYK.js} +0 -1
- package/dist/{chunk-7JJEIADR.js → chunk-UF7QPYUX.js} +299 -157
- package/dist/{chunk-NQPYMUDF.js → chunk-UKGBQTHL.js} +3 -4
- package/dist/{chunk-5XPPLTC7.js → chunk-UUMH3DC3.js} +1 -2
- package/dist/{chunk-TBUKJKY6.js → chunk-VJ3UA6OD.js} +1 -2
- package/dist/{chunk-OHCPV2NT.js → chunk-WHKPWIQO.js} +0 -1
- package/dist/{chunk-EZNCCO4L.js → chunk-YDLO5M7S.js} +0 -1
- package/dist/{components-BmievOxF.d.ts → components-JZQoO2sU.d.ts} +1 -1
- package/dist/cooldown.d.ts +1 -1
- package/dist/cooldown.js +3 -4
- package/dist/coordinators/boundary-ricochet-3d.d.ts +2 -2
- package/dist/coordinators/boundary-ricochet-3d.js +4 -5
- package/dist/coordinators/boundary-ricochet.d.ts +2 -2
- package/dist/coordinators/boundary-ricochet.js +4 -5
- package/dist/coordinators/first-person-shooter.js +4 -5
- package/dist/coordinators/multidirectional-space-shooter.d.ts +1 -1
- package/dist/coordinators/multidirectional-space-shooter.js +6 -7
- package/dist/coordinators/top-down-shooter.d.ts +1 -1
- package/dist/coordinators/top-down-shooter.js +6 -7
- package/dist/core.d.ts +21 -6
- package/dist/core.js +29 -7
- package/dist/destructible-3d.d.ts +1 -1
- package/dist/destructible-3d.js +4 -5
- package/dist/destructible-prebake.js +2 -3
- package/dist/{first-person-perspective-C9Mptl0-.d.ts → first-person-perspective-BxFHgFln.d.ts} +2 -0
- package/dist/first-person.d.ts +12 -3
- package/dist/first-person.js +7 -8
- package/dist/index.d.ts +5 -5
- package/dist/index.js +40 -41
- package/dist/jumper-2d.d.ts +1 -1
- package/dist/jumper-2d.js +5 -6
- package/dist/jumper-3d.d.ts +1 -1
- package/dist/jumper-3d.js +6 -7
- package/dist/{moveable-rdIvWiak.d.ts → moveable-BdFmI3s1.d.ts} +1 -1
- package/dist/particle-emitter/presets.d.ts +1 -1
- package/dist/particle-emitter/presets.js +2 -3
- package/dist/particle-emitter.d.ts +3 -3
- package/dist/particle-emitter.js +5 -6
- package/dist/platformer-2d.d.ts +1 -1
- package/dist/platformer-2d.js +5 -6
- package/dist/platformer-3d.d.ts +1 -1
- package/dist/platformer-3d.js +5 -6
- package/dist/ricochet-2d.d.ts +1 -1
- package/dist/ricochet-2d.js +5 -6
- package/dist/ricochet-3d.d.ts +1 -1
- package/dist/ricochet-3d.js +5 -6
- package/dist/runtime-2d.d.ts +1 -1
- package/dist/runtime-2d.js +2 -3
- package/dist/screen-visibility.d.ts +1 -1
- package/dist/screen-visibility.js +3 -4
- package/dist/screen-wrap.d.ts +1 -1
- package/dist/screen-wrap.js +5 -6
- package/dist/shooter-2d.d.ts +1 -1
- package/dist/shooter-2d.js +5 -6
- package/dist/{spark-Dx3cJbTW.d.ts → spark-C4Tp-52_.d.ts} +4 -2
- package/dist/thruster.d.ts +1 -1
- package/dist/thruster.js +5 -6
- package/dist/top-down-movement.d.ts +1 -1
- package/dist/top-down-movement.js +7 -8
- package/dist/world-boundary-2d.d.ts +1 -1
- package/dist/world-boundary-2d.js +6 -7
- package/dist/world-boundary-3d.d.ts +1 -1
- package/dist/world-boundary-3d.js +6 -7
- package/package.json +159 -161
- package/dist/chunk-2PAHQZZD.js.map +0 -1
- package/dist/chunk-4CEW64HO.js.map +0 -1
- package/dist/chunk-4LLK2FJI.js.map +0 -1
- package/dist/chunk-4MZ57HPD.js.map +0 -1
- package/dist/chunk-4WH2ZN7P.js.map +0 -1
- package/dist/chunk-52FJIDGL.js.map +0 -1
- package/dist/chunk-5A5AYP2C.js.map +0 -1
- package/dist/chunk-5WRI5ZAA.js.map +0 -1
- package/dist/chunk-5XPPLTC7.js.map +0 -1
- package/dist/chunk-7DGXUAPV.js.map +0 -1
- package/dist/chunk-7JJEIADR.js.map +0 -1
- package/dist/chunk-7JLWZXPA.js.map +0 -1
- package/dist/chunk-7W3KY55G.js.map +0 -1
- package/dist/chunk-AS3HR7AS.js.map +0 -1
- package/dist/chunk-BAXJ7XHJ.js.map +0 -1
- package/dist/chunk-DZ4LLQON.js.map +0 -1
- package/dist/chunk-EIWQM6U3.js.map +0 -1
- package/dist/chunk-EZNCCO4L.js.map +0 -1
- package/dist/chunk-G2KUXVU6.js.map +0 -1
- package/dist/chunk-H4TJ7X4O.js.map +0 -1
- package/dist/chunk-HZMY3TT4.js.map +0 -1
- package/dist/chunk-IZJFUAXB.js.map +0 -1
- package/dist/chunk-JVADRLWX.js.map +0 -1
- package/dist/chunk-KFFETUAL.js.map +0 -1
- package/dist/chunk-KIYUUSPK.js.map +0 -1
- package/dist/chunk-LL4FLHIY.js.map +0 -1
- package/dist/chunk-LZIHSJZR.js.map +0 -1
- package/dist/chunk-M3QDKKDF.js.map +0 -1
- package/dist/chunk-NQPYMUDF.js.map +0 -1
- package/dist/chunk-NW4SE5XW.js.map +0 -1
- package/dist/chunk-OHCPV2NT.js.map +0 -1
- package/dist/chunk-OPZ2LVS2.js.map +0 -1
- package/dist/chunk-PLIXVF7B.js.map +0 -1
- package/dist/chunk-QS3VXWVO.js.map +0 -1
- package/dist/chunk-QVCMJ4Q2.js.map +0 -1
- package/dist/chunk-SGHIGTVZ.js.map +0 -1
- package/dist/chunk-TBUKJKY6.js.map +0 -1
- package/dist/chunk-WOMHL23C.js.map +0 -1
- package/dist/chunk-WU6XXL3D.js.map +0 -1
- package/dist/chunk-Y4PHT2HG.js.map +0 -1
- package/dist/cooldown.js.map +0 -1
- package/dist/coordinators/boundary-ricochet-3d.js.map +0 -1
- package/dist/coordinators/boundary-ricochet.js.map +0 -1
- package/dist/coordinators/first-person-shooter.js.map +0 -1
- package/dist/coordinators/multidirectional-space-shooter.js.map +0 -1
- package/dist/coordinators/top-down-shooter.js.map +0 -1
- package/dist/core.js.map +0 -1
- package/dist/destructible-3d.js.map +0 -1
- package/dist/destructible-prebake.js.map +0 -1
- package/dist/first-person.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/jumper-2d.js.map +0 -1
- package/dist/jumper-3d.js.map +0 -1
- package/dist/particle-emitter/presets.js.map +0 -1
- package/dist/particle-emitter.js.map +0 -1
- package/dist/platformer-2d.js.map +0 -1
- package/dist/platformer-3d.js.map +0 -1
- package/dist/ricochet-2d.js.map +0 -1
- package/dist/ricochet-3d.js.map +0 -1
- package/dist/runtime-2d.js.map +0 -1
- package/dist/screen-visibility.js.map +0 -1
- package/dist/screen-wrap.js.map +0 -1
- package/dist/shooter-2d.js.map +0 -1
- package/dist/thruster.js.map +0 -1
- package/dist/top-down-movement.js.map +0 -1
- package/dist/world-boundary-2d.js.map +0 -1
- package/dist/world-boundary-3d.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/behaviors/thruster/thruster-fsm.ts","../src/lib/behaviors/thruster/thruster.descriptor.ts"],"sourcesContent":["/**\n * ThrusterFSM\n * \n * State machine controller for thruster behavior.\n * FSM does NOT touch physics or ThrusterSystem - it only writes ThrusterInputComponent.\n */\n\nimport { SyncStateMachine, t } from '../../core/utility/sync-state-machine';\nimport type { ThrusterInputComponent } from './components';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// FSM State Model\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport enum ThrusterState {\n\tIdle = 'idle',\n\tActive = 'active',\n\tBoosting = 'boosting',\n\tDisabled = 'disabled',\n\tDocked = 'docked',\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// FSM Events\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport enum ThrusterEvent {\n\tActivate = 'activate',\n\tDeactivate = 'deactivate',\n\tBoost = 'boost',\n\tEndBoost = 'endBoost',\n\tDisable = 'disable',\n\tEnable = 'enable',\n\tDock = 'dock',\n\tUndock = 'undock',\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// FSM Context Object\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface ThrusterFSMContext {\n\tinput: ThrusterInputComponent;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Player Input (raw input from controller/keyboard)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface PlayerInput {\n\tthrust: number;\n\trotate: number;\n\tthrustX?: number;\n\tthrustY?: number;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// ThrusterFSM Controller\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport class ThrusterFSM {\n\tmachine: SyncStateMachine<ThrusterState, ThrusterEvent, never>;\n\n\tconstructor(private ctx: ThrusterFSMContext) {\n\t\tthis.machine = new SyncStateMachine<ThrusterState, ThrusterEvent, never>(\n\t\t\tThrusterState.Idle,\n\t\t\t[\n\t\t\t\t// Core transitions\n\t\t\t\tt(ThrusterState.Idle, ThrusterEvent.Activate, ThrusterState.Active),\n\t\t\t\tt(ThrusterState.Active, ThrusterEvent.Deactivate, ThrusterState.Idle),\n\t\t\t\tt(ThrusterState.Active, ThrusterEvent.Boost, ThrusterState.Boosting),\n\t\t\t\tt(ThrusterState.Active, ThrusterEvent.Disable, ThrusterState.Disabled),\n\t\t\t\tt(ThrusterState.Active, ThrusterEvent.Dock, ThrusterState.Docked),\n\t\t\t\tt(ThrusterState.Boosting, ThrusterEvent.EndBoost, ThrusterState.Active),\n\t\t\t\tt(ThrusterState.Boosting, ThrusterEvent.Disable, ThrusterState.Disabled),\n\t\t\t\tt(ThrusterState.Disabled, ThrusterEvent.Enable, ThrusterState.Idle),\n\t\t\t\tt(ThrusterState.Docked, ThrusterEvent.Undock, ThrusterState.Idle),\n\t\t\t\t// Self-transitions (no-ops for redundant events)\n\t\t\t\tt(ThrusterState.Idle, ThrusterEvent.Deactivate, ThrusterState.Idle),\n\t\t\t\tt(ThrusterState.Active, ThrusterEvent.Activate, ThrusterState.Active),\n\t\t\t]\n\t\t);\n\t}\n\n\t/**\n\t * Get current state\n\t */\n\tgetState(): ThrusterState {\n\t\treturn this.machine.getState();\n\t}\n\n\t/**\n\t * Dispatch an event to transition state\n\t */\n\tdispatch(event: ThrusterEvent): void {\n\t\tif (this.machine.can(event)) {\n\t\t\tthis.machine.syncDispatch(event);\n\t\t}\n\t}\n\n\t/**\n\t * Update FSM state based on player input.\n\t * Auto-transitions between Idle/Active to report current state.\n\t * Does NOT modify input - just observes and reports.\n\t */\n\tupdate(playerInput: PlayerInput): void {\n\t\tconst state = this.machine.getState();\n\t\tconst hasInput =\n\t\t\tMath.abs(playerInput.thrust) > 0.01\n\t\t\t|| Math.abs(playerInput.rotate) > 0.01\n\t\t\t|| Math.abs(playerInput.thrustX ?? 0) > 0.01\n\t\t\t|| Math.abs(playerInput.thrustY ?? 0) > 0.01;\n\n\t\t// Auto-transition to report state based on input\n\t\tif (hasInput && state === ThrusterState.Idle) {\n\t\t\tthis.dispatch(ThrusterEvent.Activate);\n\t\t} else if (!hasInput && state === ThrusterState.Active) {\n\t\t\tthis.dispatch(ThrusterEvent.Deactivate);\n\t\t}\n\t}\n}\n","/**\n * Thruster Behavior Descriptor\n *\n * Type-safe descriptor for the thruster behavior using the entity.use() API.\n * The wasm runtime owns the thruster simulation; this system attaches the\n * Rust behavior and forwards input into the slot-indexed input buffer.\n */\n\nimport { defineBehavior } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport {\n\tcreateThrusterInputComponent,\n\tcreateThrusterMovementComponent,\n\ttype ThrusterMovementComponent,\n\ttype ThrusterInputComponent,\n} from './components';\nimport type { BehaviorRuntime } from '../../runtime/wasm-stage-runtime';\n\n/**\n * Entity with thruster components (input written by the game, state owned by\n * the wasm runtime).\n */\nexport interface ThrusterEntity {\n\tthruster: ThrusterMovementComponent;\n\t$thruster: ThrusterInputComponent;\n}\n\n/**\n * Thruster behavior options (typed for entity.use() autocomplete)\n */\nexport interface ThrusterBehaviorOptions {\n\t/** Forward thrust force (default: 10) */\n\tlinearThrust: number;\n\t/** Rotation torque (default: 5) */\n\tangularThrust: number;\n\t/** Optional linear damping override */\n\tlinearDamping?: number;\n}\n\nconst defaultOptions: ThrusterBehaviorOptions = {\n\tlinearThrust: 10,\n\tangularThrust: 5,\n\tlinearDamping: undefined,\n};\n\nconst THRUSTER_BEHAVIOR_KEY = Symbol.for('zylem:behavior:thruster');\n\n/**\n * Adapter that forwards thruster input into the wasm runtime.\n *\n * The Rust `thruster` Stage behavior is the single simulation path: this\n * system attaches it once per entity and writes `$thruster` input into the\n * slot-indexed input buffer each frame.\n */\nclass ThrusterBehaviorSystem implements BehaviorSystem {\n\tprivate attachedRuntimeSlots = new Set<number>();\n\n\tconstructor(\n\t\tprivate wasmStage: BehaviorRuntime | null,\n\t\tprivate getBehaviorLinks?: (key: symbol) => Iterable<BehaviorEntityLink>,\n\t) {}\n\n\tupdate(_ecs: unknown, _delta: number): void {\n\t\tconst links = this.getBehaviorLinks?.(THRUSTER_BEHAVIOR_KEY);\n\t\tif (!links) return;\n\n\t\tfor (const link of links) {\n\t\t\tconst gameEntity = link.entity as any;\n\t\t\tconst thrusterRef = link.ref as any;\n\n\t\t\tconst options = thrusterRef.options as ThrusterBehaviorOptions;\n\n\t\t\tif (!gameEntity.thruster) {\n\t\t\t\tgameEntity.thruster = createThrusterMovementComponent(\n\t\t\t\t\toptions.linearThrust,\n\t\t\t\t\toptions.angularThrust,\n\t\t\t\t\t{ linearDamping: options.linearDamping },\n\t\t\t\t) as ThrusterMovementComponent;\n\t\t\t}\n\n\t\t\tif (!gameEntity.$thruster) {\n\t\t\t\tgameEntity.$thruster = createThrusterInputComponent() as ThrusterInputComponent;\n\t\t\t}\n\n\t\t\tconst handle = (gameEntity.runtimeHandle ?? -1) as number;\n\t\t\tif (!this.wasmStage || handle < 0) continue;\n\n\t\t\tthis.ensureWasmAttached(handle, options);\n\t\t\tconst input = gameEntity.$thruster as ThrusterInputComponent | undefined;\n\t\t\tif (input) {\n\t\t\t\tthis.wasmStage.writeInputAxes(handle, input.thrust, input.rotate);\n\t\t\t\tthis.wasmStage.writeInputReserved(handle, input.thrustX, input.thrustY);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate ensureWasmAttached(handle: number, options: ThrusterBehaviorOptions): void {\n\t\tif (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;\n\t\tthis.wasmStage.attachThruster(handle, {\n\t\t\tmaxSpeed: 50,\n\t\t\tacceleration: options.linearThrust,\n\t\t\tturnRateRadPerSec: options.angularThrust,\n\t\t\tlinearDamping: options.linearDamping ?? 0,\n\t\t});\n\t\tthis.attachedRuntimeSlots.add(handle);\n\t}\n\n\tdestroy(_ecs: unknown): void {\n\t\tthis.attachedRuntimeSlots.clear();\n\t}\n}\n\n/**\n * ThrusterBehavior - typed descriptor for thruster movement.\n *\n * @example\n * ```typescript\n * import { ThrusterBehavior } from \"@zylem/game-lib/behavior\";\n *\n * const ship = createSprite({ ... });\n * ship.use(ThrusterBehavior, { linearThrust: 15, angularThrust: 8 });\n * ```\n */\nexport const ThrusterBehavior = defineBehavior<ThrusterBehaviorOptions, Record<string, never>, ThrusterEntity>({\n\tname: 'thruster',\n\tdefaultOptions,\n\tsystemFactory: (ctx) =>\n\t\tnew ThrusterBehaviorSystem(ctx.wasmStage ?? null, ctx.getBehaviorLinks),\n});\n"],"mappings":"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","names":["ThrusterState","ThrusterEvent"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/runtime/wasm-stage-runtime.ts"],"sourcesContent":["/**\n * `WasmStageRuntime` — owns one wasm `WebAssembly.Instance` of\n * `@zylem/runtime` and exposes the unified-Stage FFI as typed TypeScript\n * methods. This is the single simulation adapter for the whole framework:\n * behavior systems talk to it through the {@link BehaviorRuntime} contract,\n * and hosts (e.g. `@zylem/game-lib`) drive it through\n * {@link createSimulation} in `./simulation`.\n */\n\nimport {\n\tloadStageFfi,\n\ttype StageWasmExports,\n\tSTAGE_RENDER_STRIDE,\n\tSTAGE_INPUT_STRIDE,\n\tSTAGE_SNAPSHOT_STRIDE,\n\tSTAGE_EVENT_STRIDE,\n} from '@zylem/runtime';\n\nexport {\n\tSTAGE_RENDER_STRIDE,\n\tSTAGE_INPUT_STRIDE,\n\tSTAGE_SNAPSHOT_STRIDE,\n\tSTAGE_EVENT_STRIDE,\n};\nexport type { StageWasmExports };\n\n/** Sentinel handle for \"no entity / failed allocation\". Mirrors `INVALID_SLOT` in Rust. */\nexport const STAGE_INVALID_SLOT = 0xffffffff;\n\nexport const StageBodyKind = {\n\tDynamic: 0,\n\tStatic: 1,\n\tKinematicPosition: 2,\n\tKinematicVelocity: 3,\n} as const;\n\nexport type StageBodyKindValue = (typeof StageBodyKind)[keyof typeof StageBodyKind];\n\nexport const StageBoundaryDim = {\n\tTwo: 2,\n\tThree: 3,\n} as const;\n\nexport const StageRicochetDim = {\n\tTwo: 2,\n\tThree: 3,\n} as const;\n\nexport const StageRicochetReflection = {\n\tMirror: 0,\n\tAngled: 1,\n} as const;\n\nexport const StageTopDownPlane = {\n\tXy: 0,\n\tXz: 1,\n} as const;\n\nexport const StageEventType = {\n\tCollisionStarted: 1,\n\tCollisionStopped: 2,\n\tBoundaryHit: 3,\n\tRicochet: 4,\n\tRegionEntered: 5,\n\tJumpStarted: 6,\n\tLanded: 7,\n\tWrapped: 8,\n\tCooldownFired: 9,\n} as const;\n\nexport type StageBoundaryDimValue = (typeof StageBoundaryDim)[keyof typeof StageBoundaryDim];\nexport type StageRicochetDimValue = (typeof StageRicochetDim)[keyof typeof StageRicochetDim];\nexport type StageRicochetReflectionValue =\n\t(typeof StageRicochetReflection)[keyof typeof StageRicochetReflection];\nexport type StageTopDownPlaneValue = (typeof StageTopDownPlane)[keyof typeof StageTopDownPlane];\n\n/** Position + rotation snapshot for one runtime slot. */\nexport interface StagePose {\n\tposition: [number, number, number];\n\trotation: [number, number, number, number];\n}\n\nexport interface StageWorldBoundaryOptions {\n\ttop: number;\n\tbottom: number;\n\tleft: number;\n\tright: number;\n\tfront?: number;\n\tback?: number;\n\tpadding?: number;\n}\n\nexport interface StageScreenWrapOptions {\n\twidth: number;\n\theight: number;\n\tcenterX?: number;\n\tcenterY?: number;\n\tedgeThreshold?: number;\n}\n\nexport interface StageRicochetOptions {\n\tminSpeed: number;\n\tmaxSpeed: number;\n\tspeedMultiplier: number;\n\tmaxAngleDeg: number;\n\treflectionMode: StageRicochetReflectionValue;\n}\n\nexport interface StageThrusterOptions {\n\tmaxSpeed: number;\n\tacceleration: number;\n\tturnRateRadPerSec: number;\n\tlinearDamping: number;\n}\n\nexport interface StageTopDownOptions {\n\tplane: StageTopDownPlaneValue;\n\tspeed: number;\n\tfaceMovement?: boolean;\n}\n\nexport interface StageShooter2DOptions {\n\tfireRateHz: number;\n\tmuzzleOffsetX: number;\n\tmuzzleOffsetY: number;\n\tmuzzleSpeed: number;\n}\n\nexport interface StageJumper2DOptions {\n\tjumpForce: number;\n\tmaxJumps: number;\n\tjumpBufferTime: number;\n\tcoyoteTime: number;\n\tgravity: number;\n}\n\nexport interface StageJumper3DOptions {\n\tjumpForce: number;\n\tmaxJumps: number;\n\tgravity: number;\n\t/** Coyote time in seconds (default 0.1). */\n\tcoyoteTime?: number;\n\t/** Jump buffer window in seconds (default 0.08). */\n\tjumpBufferTime?: number;\n}\n\nexport interface StagePlatformer3DOptions {\n\thalfHeight: number;\n\tradius: number;\n\twalkSpeed: number;\n\trunSpeed: number;\n\tjumpForce: number;\n\tmaxJumps: number;\n\tgravity: number;\n\t/** Coyote time in seconds (default 0.1). */\n\tcoyoteTime?: number;\n\t/** Jump buffer window in seconds (default 0.1). */\n\tjumpBufferTime?: number;\n\t/** Velocity multiplier applied on early jump release (default 0.5). */\n\tjumpCutMultiplier?: number;\n\t/** Seconds before a multi-jump becomes available (default 0.15). */\n\tmultiJumpWindow?: number;\n\t/** Max slope angle in degrees the KCC can climb (default 50). */\n\tslopeClimbAngle?: number;\n\t/** Slope angle in degrees past which the character slides (default 40). */\n\tslopeSlideAngle?: number;\n\t/** Autostep max height in world units; 0 disables (default 0.3). */\n\tautostepHeight?: number;\n\t/** Minimum unobstructed width for an autostep (default 0.1). */\n\tautostepMinWidth?: number;\n\t/** Snap-to-ground distance in world units; 0 disables (default 0.3). */\n\tsnapToGroundDistance?: number;\n\t/** KCC collision offset between collider and environment (default 0.05). */\n\tcharacterOffset?: number;\n\t/** Collider local offset X (fallback / override). */\n\toffsetX?: number;\n\t/** Collider local offset Y (fallback / override). */\n\toffsetY?: number;\n\t/** Collider local offset Z (fallback / override). */\n\toffsetZ?: number;\n\t/** 0 = auto-read attached collider; 1 = use stored shape fields. */\n\tshapeSource?: number;\n}\n\nexport const StagePlatformerShapeSource = {\n\tAuto: 0,\n\tOverride: 1,\n} as const;\n\nexport interface StagePlatformer2DOptions {\n\thalfHeight: number;\n\tradius: number;\n\twalkSpeed: number;\n\trunSpeed: number;\n\tjumpForce: number;\n\tmaxJumps: number;\n\tgravity: number;\n\t/** Coyote time in seconds (default 0.1). */\n\tcoyoteTime?: number;\n\t/** Jump buffer window in seconds (default 0.1). */\n\tjumpBufferTime?: number;\n\t/** Velocity multiplier applied on early jump release (default 0.5). */\n\tjumpCutMultiplier?: number;\n\t/** Seconds before a multi-jump becomes available (default 0.15). */\n\tmultiJumpWindow?: number;\n\t/** Max slope angle in degrees the KCC can climb (default 50). */\n\tslopeClimbAngle?: number;\n\t/** Slope angle in degrees past which the character slides (default 40). */\n\tslopeSlideAngle?: number;\n\t/** Autostep max height in world units; 0 disables (default 0.25). */\n\tautostepHeight?: number;\n\t/** Minimum unobstructed width for an autostep (default 0.05). */\n\tautostepMinWidth?: number;\n\t/** Snap-to-ground distance in world units; 0 disables (default 0.2). */\n\tsnapToGroundDistance?: number;\n\t/** KCC collision offset between collider and environment (default 0.05). */\n\tcharacterOffset?: number;\n\t/** Collider local offset X (fallback / override). */\n\toffsetX?: number;\n\t/** Collider local offset Y (fallback / override). */\n\toffsetY?: number;\n\t/** Collider local offset Z (fallback / override). */\n\toffsetZ?: number;\n\t/** 0 = auto-read attached collider; 1 = use stored shape fields. */\n\tshapeSource?: number;\n}\n\nexport interface StageFirstPersonOptions {\n\twalkSpeed: number;\n\trunSpeed: number;\n\teyeHeight: number;\n\tlookSensitivity: number;\n}\n\nexport interface StageFirstPersonInput {\n\tmoveX: number;\n\tmoveZ: number;\n\tlookYawDelta: number;\n\tlookPitchDelta: number;\n\trun: boolean;\n}\n\n/** Button bits for the slot-indexed input buffer's bitmask field. */\nexport const STAGE_INPUT_BUTTON_JUMP = 1;\nexport const STAGE_INPUT_BUTTON_RUN = 2;\n\n/**\n * Decoded per-slot behavior snapshot written by the runtime after every\n * step: movement fields come from whichever character behavior the entity\n * has (platformer 3D/2D, jumper 3D/2D); first-person fills yaw/pitch.\n * Values reflect the end of the previous `step()` (one-frame read lag).\n */\nexport interface StageBehaviorSnapshot {\n\tgrounded: boolean;\n\tfsmState: number;\n\tjumpCount: number;\n\tverticalVelocity: number;\n\tspeed: number;\n\tyaw: number;\n\tpitch: number;\n}\n\n/**\n * Wasm fast-path backrefs a behavior system stores on its `BehaviorRef` every\n * frame so descriptor handles can read the runtime snapshot buffer instead of\n * a duplicate TS FSM (or hardcoded defaults).\n */\nexport interface WasmSnapshotBackref {\n\t__wasmStage?: BehaviorRuntime | null;\n\t__entity?: { runtimeHandle?: number } | null;\n}\n\n/**\n * Read the behavior snapshot for the entity a `BehaviorRef` is linked to.\n * Returns `null` off the wasm fast path (no stage runtime / no\n * `runtimeHandle` / no snapshot yet), in which case handles should fall back\n * to their TS FSM.\n */\nexport function readBehaviorSnapshot(ref: object): StageBehaviorSnapshot | null {\n\tconst backref = ref as WasmSnapshotBackref;\n\tconst wasmStage = backref.__wasmStage;\n\tconst handle = backref.__entity?.runtimeHandle ?? -1;\n\tif (!wasmStage || handle < 0) return null;\n\treturn wasmStage.readSnapshot(handle);\n}\n\n/**\n * Runtime surface behavior systems rely on. `WasmStageRuntime` is the real\n * wasm-backed implementation; `MockBehaviorRuntime` (see\n * `./mock-behavior-runtime`) implements the same contract for unit tests, so\n * descriptors stay runtime-agnostic.\n */\nexport interface BehaviorRuntime {\n\tgetPose(handle: number, out?: StagePose): StagePose | null;\n\tsetPosition(handle: number, x: number, y: number, z: number): boolean;\n\tsetRotation(handle: number, x: number, y: number, z: number, w: number): boolean;\n\n\t// ─── Batched input / snapshot buffers (preferred fast path) ─────────\n\t// Field-scoped writes into the slot-indexed input buffer, consumed by\n\t// the runtime in one pass at the start of each step. Behaviors composed\n\t// on one entity each write only their part of the slot.\n\twriteInputAxes(handle: number, axisA: number, axisB: number): boolean;\n\twriteInputLook(handle: number, yawDelta: number, pitchDelta: number): boolean;\n\t/** Write reserved input slots (thruster world-space vector X/Y). */\n\twriteInputReserved(handle: number, reservedA: number, reservedB: number): boolean;\n\twriteInputButton(handle: number, buttonMask: number, pressed: boolean): boolean;\n\t/** Read the per-slot behavior snapshot written at the end of the previous step. */\n\treadSnapshot(handle: number, out?: StageBehaviorSnapshot): StageBehaviorSnapshot | null;\n\n\tattachThruster(handle: number, opts: StageThrusterOptions): boolean;\n\tsetThrusterInput(\n\t\thandle: number,\n\t\tthrust: number,\n\t\trotate: number,\n\t\tvectorX?: number,\n\t\tvectorY?: number,\n\t): void;\n\n\tattachTopDown(handle: number, opts: StageTopDownOptions): boolean;\n\tsetTopDownInput(handle: number, moveX: number, moveY: number): void;\n\n\tattachShooter2D(handle: number, opts: StageShooter2DOptions): boolean;\n\n\tattachScreenWrap(handle: number, opts: StageScreenWrapOptions): boolean;\n\tqueryScreenWrap(handle: number): { fsm: number; lastWrappedAxes: number } | null;\n\n\tattachWorldBoundary(\n\t\thandle: number,\n\t\tdim: StageBoundaryDimValue,\n\t\topts: StageWorldBoundaryOptions,\n\t): boolean;\n\tqueryWorldBoundary(handle: number): { hits: number; clamped: [number, number, number] } | null;\n\n\tattachRicochet(handle: number, dim: StageRicochetDimValue, opts: StageRicochetOptions): boolean;\n\n\tattachPlatformer3D(handle: number, opts: StagePlatformer3DOptions): boolean;\n\tsetPlatformer3DInputAxes(handle: number, moveX: number, moveZ: number): void;\n\tsetPlatformer3DInputButtons(handle: number, jump: boolean, run: boolean): void;\n\n\tattachPlatformer2D(handle: number, opts: StagePlatformer2DOptions): boolean;\n\tsetPlatformer2DInputAxes(handle: number, moveX: number): void;\n\tsetPlatformer2DInputButtons(handle: number, jump: boolean, run: boolean): void;\n\n\tattachFirstPerson(handle: number, opts: StageFirstPersonOptions): boolean;\n\tsetFirstPersonInput(handle: number, input: StageFirstPersonInput): void;\n\n\tattachJumper2D(handle: number, opts: StageJumper2DOptions): boolean;\n\tsetJumper2DInput(handle: number, jumpPressed: boolean): void;\n\n\tattachJumper3D(handle: number, opts: StageJumper3DOptions): boolean;\n\tsetJumper3DInput(handle: number, jumpPressed: boolean): void;\n}\n\n/** Default options used when constructing a wasm-backed Stage runtime. */\nexport interface WasmStageRuntimeOptions {\n\tinitialCapacity?: number;\n\tgravity?: readonly [number, number, number];\n\timports?: WebAssembly.Imports;\n\t/**\n\t * Custom wasm source. Defaults to the `zylem_runtime.wasm` bundled with\n\t * `@zylem/runtime`.\n\t */\n\tsource?: RequestInfo | URL | ArrayBuffer | Uint8Array;\n}\n\nexport type StageEventTypeValue = (typeof StageEventType)[keyof typeof StageEventType];\n\n/** One decoded event drained from the runtime's per-step event buffer. */\nexport interface StageEvent {\n\ttype: StageEventTypeValue;\n\tprimarySlot: number | null;\n\tsecondarySlot: number | null;\n\tpayload: [number, number, number];\n}\n\n/**\n * Decoded view of one entity's slot in the unified render buffer.\n *\n * Mirrors the `STAGE_RENDER_STRIDE` (12-float) packing documented in\n * `runtime/stage/render.rs`:\n * `[0..3]` position, `[3..7]` rotation xyzw, `[7]` uniform scale,\n * `[8..12]` custom0..custom3 (per-behavior shading hints).\n */\nexport interface StageRenderSlot {\n\tposition: [number, number, number];\n\trotation: [number, number, number, number];\n\tscale: number;\n\tcustom: [number, number, number, number];\n}\n\n/**\n * Read a single entity slot out of a unified-Stage render buffer view.\n *\n * @param view The `Float32Array` over wasm memory (e.g. `WasmStageRuntime.render`).\n * @param slot The entity's wasm slot id (its `runtimeHandle`).\n * @param out Optional target object to write into (avoids per-call allocation).\n * @returns The decoded slot, or `null` when the slot is out of range.\n */\nexport function readStageRenderSlot(\n\tview: Float32Array,\n\tslot: number,\n\tout?: StageRenderSlot,\n): StageRenderSlot | null {\n\tconst base = slot * STAGE_RENDER_STRIDE;\n\tif (slot < 0 || base + STAGE_RENDER_STRIDE > view.length) {\n\t\treturn null;\n\t}\n\tconst result: StageRenderSlot = out ?? {\n\t\tposition: [0, 0, 0],\n\t\trotation: [0, 0, 0, 1],\n\t\tscale: 1,\n\t\tcustom: [0, 0, 0, 0],\n\t};\n\tresult.position[0] = view[base]!;\n\tresult.position[1] = view[base + 1]!;\n\tresult.position[2] = view[base + 2]!;\n\tresult.rotation[0] = view[base + 3]!;\n\tresult.rotation[1] = view[base + 4]!;\n\tresult.rotation[2] = view[base + 5]!;\n\tresult.rotation[3] = view[base + 6]!;\n\t// A freshly-zeroed slot reports scale 0; treat that as the identity scale so\n\t// entities aren't collapsed before the runtime writes a real value.\n\tconst scale = view[base + 7]!;\n\tresult.scale = scale === 0 ? 1 : scale;\n\tresult.custom[0] = view[base + 8]!;\n\tresult.custom[1] = view[base + 9]!;\n\tresult.custom[2] = view[base + 10]!;\n\tresult.custom[3] = view[base + 11]!;\n\treturn result;\n}\n\nexport interface StageBodyConfig {\n\tkind: StageBodyKindValue;\n\tposition: readonly [number, number, number];\n\trotation: readonly [number, number, number, number];\n\tlinearDamping: number;\n\tangularDamping: number;\n\tgravityScale: number;\n\tcanSleep: boolean;\n\tccdEnabled: boolean;\n\tlockRotation: readonly [boolean, boolean, boolean];\n\tlockTranslation: readonly [boolean, boolean, boolean];\n}\n\nexport type StageColliderShape =\n\t| { type: 'box'; halfExtents: readonly [number, number, number] }\n\t| { type: 'sphere'; radius: number }\n\t| { type: 'capsule'; halfHeight: number; radius: number }\n\t| { type: 'cylinder'; halfHeight: number; radius: number }\n\t| { type: 'cone'; halfHeight: number; radius: number }\n\t| { type: 'convexHull'; vertices: Float32Array }\n\t| { type: 'trimesh'; vertices: Float32Array; indices: Uint32Array }\n\t| {\n\t\ttype: 'heightfield';\n\t\trows: number;\n\t\tcols: number;\n\t\tscale: readonly [number, number, number];\n\t\theights: Float32Array;\n\t};\n\nexport interface StageColliderConfig {\n\tshape: StageColliderShape;\n\toffset: readonly [number, number, number];\n\tfriction: number;\n\trestitution: number;\n\tsensor: boolean;\n\t/** Packed interaction-groups: high 16 bits = membership, low 16 bits = filter. */\n\tcollisionGroups: number;\n}\n\n/** Result of a physics raycast against the stage. */\nexport interface StageRaycastHit {\n\tslot: number;\n\tdistance: number;\n\tnormal: [number, number, number];\n}\n\n/** Body introspection payload for debug tooling. */\nexport interface StageBodyInfo {\n\tbodyType: number;\n\tmass: number;\n\tisSleeping: boolean;\n\tisEnabled: boolean;\n\tlinearVelocity: [number, number, number];\n}\n\n/** Line-list wireframe for physics debug rendering. */\nexport interface StageDebugRender {\n\t/** `[x, y, z]` per vertex, two vertices per line. */\n\tvertices: Float32Array;\n\t/** RGBA per vertex. */\n\tcolors: Float32Array;\n}\n\n/**\n * Owns the wasm instance plus the live float-views over its render / event /\n * pose / scratch buffers. One instance per logical stage; each stage gets\n * its own `WebAssembly.Instance` so the singleton inside `stage_ffi.rs`\n * stays single-stage scoped (today's `thread_local!` contract).\n */\nexport class WasmStageRuntime implements BehaviorRuntime {\n\treadonly exports: StageWasmExports;\n\tprivate readonly memory: WebAssembly.Memory;\n\tprivate renderView: Float32Array = new Float32Array(0);\n\tprivate inputView: Float32Array = new Float32Array(0);\n\tprivate snapshotView: Float32Array = new Float32Array(0);\n\tprivate eventView: Float32Array = new Float32Array(0);\n\tprivate poseView: Float32Array = new Float32Array(0);\n\tprivate vec3View: Float32Array = new Float32Array(0);\n\tprivate queryView: Float32Array = new Float32Array(0);\n\tprivate scratchView: Float32Array = new Float32Array(0);\n\n\tconstructor(exports: StageWasmExports, options: WasmStageRuntimeOptions = {}) {\n\t\tthis.exports = exports;\n\t\tthis.memory = exports.memory;\n\t\tconst capacity = Math.max(options.initialCapacity ?? 64, 8);\n\t\texports.zylem_stage_create(capacity);\n\t\tif (options.gravity) {\n\t\t\texports.zylem_stage_set_gravity(\n\t\t\t\toptions.gravity[0],\n\t\t\t\toptions.gravity[1],\n\t\t\t\toptions.gravity[2],\n\t\t\t);\n\t\t}\n\t\tthis.refreshViews();\n\t}\n\n\t/** Recreate typed views over wasm memory. Call after step() or whenever memory may have grown. */\n\trefreshViews(): void {\n\t\tconst buffer = this.memory.buffer;\n\t\tconst renderPtr = this.exports.zylem_stage_render_ptr();\n\t\tconst renderLen = this.exports.zylem_stage_render_len();\n\t\tconst inputPtr = this.exports.zylem_stage_input_ptr();\n\t\tconst inputLen = this.exports.zylem_stage_input_len();\n\t\tconst snapshotPtr = this.exports.zylem_stage_snapshot_ptr();\n\t\tconst snapshotLen = this.exports.zylem_stage_snapshot_len();\n\t\tconst eventPtr = this.exports.zylem_stage_event_ptr();\n\t\tconst eventLen = this.exports.zylem_stage_event_len();\n\t\tconst posePtr = this.exports.zylem_stage_pose_ptr();\n\t\tconst poseLen = this.exports.zylem_stage_pose_len();\n\t\tconst vec3Ptr = this.exports.zylem_stage_vec3_ptr();\n\t\tconst queryPtr = this.exports.zylem_stage_query_ptr();\n\t\tconst queryLen = this.exports.zylem_stage_query_len();\n\t\tconst scratchPtr = this.exports.zylem_stage_scratch_ptr();\n\t\tconst scratchCap = this.exports.zylem_stage_scratch_capacity();\n\n\t\tthis.renderView = renderLen > 0 ? new Float32Array(buffer, renderPtr, renderLen) : new Float32Array(0);\n\t\tthis.inputView = inputLen > 0 ? new Float32Array(buffer, inputPtr, inputLen) : new Float32Array(0);\n\t\tthis.snapshotView = snapshotLen > 0 ? new Float32Array(buffer, snapshotPtr, snapshotLen) : new Float32Array(0);\n\t\tthis.eventView = eventLen > 0 ? new Float32Array(buffer, eventPtr, eventLen) : new Float32Array(0);\n\t\tthis.poseView = poseLen > 0 ? new Float32Array(buffer, posePtr, poseLen) : new Float32Array(0);\n\t\tthis.vec3View = vec3Ptr !== 0 ? new Float32Array(buffer, vec3Ptr, 3) : new Float32Array(0);\n\t\tthis.queryView = queryLen > 0 ? new Float32Array(buffer, queryPtr, queryLen) : new Float32Array(0);\n\t\tthis.scratchView = scratchCap > 0 ? new Float32Array(buffer, scratchPtr, scratchCap) : new Float32Array(0);\n\t}\n\n\t/** Step the simulation by `dt` seconds. Refreshes views afterwards. */\n\tstep(dt: number): number {\n\t\tconst active = this.exports.zylem_stage_step(dt);\n\t\tthis.refreshViews();\n\t\treturn active;\n\t}\n\n\tdispose(): void {\n\t\tthis.exports.zylem_stage_destroy();\n\t}\n\n\tget tickCount(): number {\n\t\treturn this.exports.zylem_stage_tick_count() >>> 0;\n\t}\n\n\tget activeCount(): number {\n\t\treturn this.exports.zylem_stage_active_count() >>> 0;\n\t}\n\n\tsetGravity(x: number, y: number, z: number): void {\n\t\tthis.exports.zylem_stage_set_gravity(x, y, z);\n\t}\n\n\t/**\n\t * Toggle per-step collision-event collection in the wasm stage. Hosts\n\t * with no collision listeners should disable it — with thousands of\n\t * touching bodies the per-step contact-pair hashing is a significant\n\t * fraction of `step()`.\n\t */\n\tsetEventsEnabled(enabled: boolean): void {\n\t\tthis.exports.zylem_stage_set_events_enabled(enabled ? 1 : 0);\n\t}\n\n\t// ─── Entity lifecycle ───────────────────────────────────────────────\n\n\tcreateEntity(): number {\n\t\tconst slot = this.exports.zylem_stage_create_entity() >>> 0;\n\t\t// The wasm may have grown memory while resizing the slot table; refresh views.\n\t\tthis.refreshViews();\n\t\treturn slot;\n\t}\n\n\tdestroyEntity(slot: number): boolean {\n\t\treturn this.exports.zylem_stage_destroy_entity(slot) !== 0;\n\t}\n\n\t// ─── Body / collider attach ────────────────────────────────────────\n\n\tattachBody(slot: number, config: StageBodyConfig): boolean {\n\t\tconst ok = this.exports.zylem_stage_attach_body(\n\t\t\tslot,\n\t\t\tconfig.kind,\n\t\t\tconfig.position[0], config.position[1], config.position[2],\n\t\t\tconfig.rotation[0], config.rotation[1], config.rotation[2], config.rotation[3],\n\t\t\tconfig.linearDamping,\n\t\t\tconfig.angularDamping,\n\t\t\tconfig.gravityScale,\n\t\t\tconfig.canSleep ? 1 : 0,\n\t\t\tconfig.ccdEnabled ? 1 : 0,\n\t\t\tconfig.lockRotation[0] ? 1 : 0, config.lockRotation[1] ? 1 : 0, config.lockRotation[2] ? 1 : 0,\n\t\t\tconfig.lockTranslation[0] ? 1 : 0, config.lockTranslation[1] ? 1 : 0, config.lockTranslation[2] ? 1 : 0,\n\t\t);\n\t\treturn ok !== 0;\n\t}\n\n\taddCollider(slot: number, config: StageColliderConfig): boolean {\n\t\tconst offset = config.offset;\n\t\tconst sensor = config.sensor ? 1 : 0;\n\t\tconst groups = config.collisionGroups >>> 0;\n\t\tconst friction = config.friction;\n\t\tconst restitution = config.restitution;\n\t\tswitch (config.shape.type) {\n\t\t\tcase 'box': {\n\t\t\t\tconst [hx, hy, hz] = config.shape.halfExtents;\n\t\t\t\treturn (\n\t\t\t\t\tthis.exports.zylem_stage_add_collider_box(\n\t\t\t\t\t\tslot, hx, hy, hz, offset[0], offset[1], offset[2],\n\t\t\t\t\t\tfriction, restitution, sensor, groups,\n\t\t\t\t\t) !== 0\n\t\t\t\t);\n\t\t\t}\n\t\t\tcase 'sphere': {\n\t\t\t\treturn (\n\t\t\t\t\tthis.exports.zylem_stage_add_collider_sphere(\n\t\t\t\t\t\tslot, config.shape.radius, offset[0], offset[1], offset[2],\n\t\t\t\t\t\tfriction, restitution, sensor, groups,\n\t\t\t\t\t) !== 0\n\t\t\t\t);\n\t\t\t}\n\t\t\tcase 'capsule': {\n\t\t\t\treturn (\n\t\t\t\t\tthis.exports.zylem_stage_add_collider_capsule(\n\t\t\t\t\t\tslot, config.shape.halfHeight, config.shape.radius,\n\t\t\t\t\t\toffset[0], offset[1], offset[2], friction, restitution, sensor, groups,\n\t\t\t\t\t) !== 0\n\t\t\t\t);\n\t\t\t}\n\t\t\tcase 'cylinder': {\n\t\t\t\treturn (\n\t\t\t\t\tthis.exports.zylem_stage_add_collider_cylinder(\n\t\t\t\t\t\tslot, config.shape.halfHeight, config.shape.radius,\n\t\t\t\t\t\toffset[0], offset[1], offset[2], friction, restitution, sensor, groups,\n\t\t\t\t\t) !== 0\n\t\t\t\t);\n\t\t\t}\n\t\t\tcase 'cone': {\n\t\t\t\treturn (\n\t\t\t\t\tthis.exports.zylem_stage_add_collider_cone(\n\t\t\t\t\t\tslot, config.shape.halfHeight, config.shape.radius,\n\t\t\t\t\t\toffset[0], offset[1], offset[2], friction, restitution, sensor, groups,\n\t\t\t\t\t) !== 0\n\t\t\t\t);\n\t\t\t}\n\t\t\tcase 'convexHull': {\n\t\t\t\tconst verts = config.shape.vertices;\n\t\t\t\tif (verts.length % 3 !== 0) return false;\n\t\t\t\tconst offsetFloats = this.stageScratch(verts);\n\t\t\t\treturn (\n\t\t\t\t\tthis.exports.zylem_stage_add_collider_convex_hull(\n\t\t\t\t\t\tslot, offsetFloats, verts.length / 3,\n\t\t\t\t\t\toffset[0], offset[1], offset[2], friction, restitution, sensor, groups,\n\t\t\t\t\t) !== 0\n\t\t\t\t);\n\t\t\t}\n\t\t\tcase 'trimesh': {\n\t\t\t\tconst verts = config.shape.vertices;\n\t\t\t\tconst indices = config.shape.indices;\n\t\t\t\tif (verts.length % 3 !== 0 || indices.length % 3 !== 0) return false;\n\t\t\t\tconst vertOffset = this.stageScratch(verts);\n\t\t\t\tconst indexOffset = this.stageScratchIndices(indices, vertOffset + verts.length);\n\t\t\t\treturn (\n\t\t\t\t\tthis.exports.zylem_stage_add_collider_trimesh(\n\t\t\t\t\t\tslot, vertOffset, verts.length / 3, indexOffset, indices.length,\n\t\t\t\t\t\toffset[0], offset[1], offset[2], friction, restitution, sensor, groups,\n\t\t\t\t\t) !== 0\n\t\t\t\t);\n\t\t\t}\n\t\t\tcase 'heightfield': {\n\t\t\t\tconst heights = config.shape.heights;\n\t\t\t\tconst heightOffset = this.stageScratch(heights);\n\t\t\t\treturn (\n\t\t\t\t\tthis.exports.zylem_stage_add_collider_heightfield(\n\t\t\t\t\t\tslot, config.shape.rows, config.shape.cols,\n\t\t\t\t\t\tconfig.shape.scale[0], config.shape.scale[1], config.shape.scale[2],\n\t\t\t\t\t\theightOffset, offset[0], offset[1], offset[2],\n\t\t\t\t\t\tfriction, restitution, sensor, groups,\n\t\t\t\t\t) !== 0\n\t\t\t\t);\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\tconst _exhaustive: never = config.shape;\n\t\t\t\tvoid _exhaustive;\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate stageScratch(values: Float32Array, baseOffset = 0): number {\n\t\tthis.scratchView.set(values, baseOffset);\n\t\treturn baseOffset;\n\t}\n\n\tprivate stageScratchIndices(indices: Uint32Array, baseOffset: number): number {\n\t\tfor (let i = 0; i < indices.length; i++) {\n\t\t\tthis.scratchView[baseOffset + i] = indices[i]!;\n\t\t}\n\t\treturn baseOffset;\n\t}\n\n\t// ─── Pose / velocity ───────────────────────────────────────────────\n\n\tgetPose(slot: number, out?: StagePose): StagePose | null {\n\t\tconst ok = this.exports.zylem_stage_get_pose(slot) !== 0;\n\t\tif (!ok) return null;\n\t\tconst v = this.poseView;\n\t\tconst result: StagePose = out ?? {\n\t\t\tposition: [0, 0, 0],\n\t\t\trotation: [0, 0, 0, 1],\n\t\t};\n\t\tresult.position[0] = v[0]!;\n\t\tresult.position[1] = v[1]!;\n\t\tresult.position[2] = v[2]!;\n\t\tresult.rotation[0] = v[3]!;\n\t\tresult.rotation[1] = v[4]!;\n\t\tresult.rotation[2] = v[5]!;\n\t\tresult.rotation[3] = v[6]!;\n\t\treturn result;\n\t}\n\n\tsetPosition(slot: number, x: number, y: number, z: number): boolean {\n\t\treturn this.exports.zylem_stage_set_position(slot, x, y, z) !== 0;\n\t}\n\n\tsetRotation(slot: number, x: number, y: number, z: number, w: number): boolean {\n\t\treturn this.exports.zylem_stage_set_rotation(slot, x, y, z, w) !== 0;\n\t}\n\n\tsetLinearVelocity(slot: number, x: number, y: number, z: number): boolean {\n\t\treturn this.exports.zylem_stage_set_linvel(slot, x, y, z) !== 0;\n\t}\n\n\tgetLinearVelocity(slot: number, out?: [number, number, number]): [number, number, number] | null {\n\t\tif (this.exports.zylem_stage_get_linvel(slot) === 0) return null;\n\t\tconst v = this.vec3View;\n\t\tconst result = out ?? ([0, 0, 0] as [number, number, number]);\n\t\tresult[0] = v[0]!;\n\t\tresult[1] = v[1]!;\n\t\tresult[2] = v[2]!;\n\t\treturn result;\n\t}\n\n\tsetAngularVelocity(slot: number, x: number, y: number, z: number): boolean {\n\t\treturn this.exports.zylem_stage_set_angvel(slot, x, y, z) !== 0;\n\t}\n\n\tgetAngularVelocity(slot: number, out?: [number, number, number]): [number, number, number] | null {\n\t\tif (this.exports.zylem_stage_get_angvel(slot) === 0) return null;\n\t\tconst v = this.vec3View;\n\t\tconst result = out ?? ([0, 0, 0] as [number, number, number]);\n\t\tresult[0] = v[0]!;\n\t\tresult[1] = v[1]!;\n\t\tresult[2] = v[2]!;\n\t\treturn result;\n\t}\n\n\tapplyImpulse(slot: number, x: number, y: number, z: number): boolean {\n\t\treturn this.exports.zylem_stage_apply_impulse(slot, x, y, z) !== 0;\n\t}\n\n\t// ─── Queries / diagnostics ─────────────────────────────────────────\n\n\t/** Cast a ray against the physics world. Returns the closest hit or `null`. */\n\tcastRay(\n\t\torigin: readonly [number, number, number],\n\t\tdir: readonly [number, number, number],\n\t\tmaxDistance: number,\n\t\tsolidOnly = true,\n\t): StageRaycastHit | null {\n\t\tconst hit = this.exports.zylem_stage_cast_ray(\n\t\t\torigin[0], origin[1], origin[2],\n\t\t\tdir[0], dir[1], dir[2],\n\t\t\tmaxDistance, solidOnly ? 1 : 0,\n\t\t);\n\t\tif (hit === 0) return null;\n\t\tconst v = this.queryView;\n\t\treturn {\n\t\t\tslot: v[0]! >>> 0,\n\t\t\tdistance: v[1]!,\n\t\t\tnormal: [v[2]!, v[3]!, v[4]!],\n\t\t};\n\t}\n\n\t/** Body introspection for debug tooling. */\n\tgetBodyInfo(slot: number): StageBodyInfo | null {\n\t\tif (this.exports.zylem_stage_body_info(slot) === 0) return null;\n\t\tconst v = this.queryView;\n\t\treturn {\n\t\t\tbodyType: v[0]! | 0,\n\t\t\tmass: v[1]!,\n\t\t\tisSleeping: v[2]! > 0.5,\n\t\t\tisEnabled: v[3]! > 0.5,\n\t\t\tlinearVelocity: [v[4]!, v[5]!, v[6]!],\n\t\t};\n\t}\n\n\t/** Wireframe debug render of every collider (all shapes). */\n\tgetDebugRender(): StageDebugRender | null {\n\t\tconst vertexCount = this.exports.zylem_stage_debug_render() >>> 0;\n\t\tthis.refreshViews();\n\t\tif (vertexCount === 0) return null;\n\t\tconst buffer = this.memory.buffer;\n\t\tconst vertices = new Float32Array(\n\t\t\tbuffer,\n\t\t\tthis.exports.zylem_stage_debug_vertices_ptr(),\n\t\t\tthis.exports.zylem_stage_debug_vertices_len(),\n\t\t);\n\t\tconst colors = new Float32Array(\n\t\t\tbuffer,\n\t\t\tthis.exports.zylem_stage_debug_colors_ptr(),\n\t\t\tthis.exports.zylem_stage_debug_colors_len(),\n\t\t);\n\t\treturn {\n\t\t\tvertices: new Float32Array(vertices),\n\t\t\tcolors: new Float32Array(colors),\n\t\t};\n\t}\n\n\t// ─── Render / event reads ──────────────────────────────────────────\n\n\t/** Read-only view over the render buffer; one slot occupies {@link STAGE_RENDER_STRIDE} floats. */\n\tget render(): Float32Array {\n\t\treturn this.renderView;\n\t}\n\n\tget renderStride(): number {\n\t\treturn STAGE_RENDER_STRIDE;\n\t}\n\n\t/**\n\t * Decode a single entity slot from the live render buffer. Convenience\n\t * wrapper over {@link readStageRenderSlot} bound to this runtime's view.\n\t */\n\treadRenderSlot(slot: number, out?: StageRenderSlot): StageRenderSlot | null {\n\t\treturn readStageRenderSlot(this.renderView, slot, out);\n\t}\n\n\t/** Drain the wasm event buffer into a fresh array of typed events. */\n\tdrainEvents(): StageEvent[] {\n\t\tconst count = this.exports.zylem_stage_event_count() >>> 0;\n\t\tif (count === 0) return [];\n\t\tconst view = this.eventView;\n\t\tconst events: StageEvent[] = new Array(count);\n\t\tfor (let i = 0; i < count; i++) {\n\t\t\tconst base = i * STAGE_EVENT_STRIDE;\n\t\t\tconst primaryRaw = view[base + 1]!;\n\t\t\tconst secondaryRaw = view[base + 2]!;\n\t\t\tevents[i] = {\n\t\t\t\ttype: (view[base]! | 0) as StageEventTypeValue,\n\t\t\t\tprimarySlot: Number.isNaN(primaryRaw) ? null : primaryRaw >>> 0,\n\t\t\t\tsecondarySlot: Number.isNaN(secondaryRaw) ? null : secondaryRaw >>> 0,\n\t\t\t\tpayload: [view[base + 3]!, view[base + 4]!, view[base + 5]!],\n\t\t\t};\n\t\t}\n\t\treturn events;\n\t}\n\n\t// ─── Batched input / snapshot buffers ─────────────────────────────\n\n\t/** Writable view over the slot-indexed input buffer ({@link STAGE_INPUT_STRIDE} floats/slot). */\n\tget input(): Float32Array {\n\t\treturn this.inputView;\n\t}\n\n\tget inputStride(): number {\n\t\treturn STAGE_INPUT_STRIDE;\n\t}\n\n\t/** Read-only view over the per-slot behavior snapshot buffer ({@link STAGE_SNAPSHOT_STRIDE} floats/slot). */\n\tget snapshot(): Float32Array {\n\t\treturn this.snapshotView;\n\t}\n\n\tget snapshotStride(): number {\n\t\treturn STAGE_SNAPSHOT_STRIDE;\n\t}\n\n\t/**\n\t * Write the primary movement axes for a slot into the slot-indexed input\n\t * buffer and mark the slot dirty. Field-scoped (doesn't touch look\n\t * deltas or buttons) so multiple behaviors composed on one entity can\n\t * each write their part.\n\t */\n\twriteInputAxes(slot: number, axisA: number, axisB: number): boolean {\n\t\tconst base = slot * STAGE_INPUT_STRIDE;\n\t\tconst view = this.inputView;\n\t\tif (slot < 0 || base + STAGE_INPUT_STRIDE > view.length) return false;\n\t\tview[base] = axisA;\n\t\tview[base + 1] = axisB;\n\t\tview[base + 7] = 1;\n\t\treturn true;\n\t}\n\n\t/** Write the look deltas (first-person yaw/pitch) for a slot. */\n\twriteInputLook(slot: number, yawDelta: number, pitchDelta: number): boolean {\n\t\tconst base = slot * STAGE_INPUT_STRIDE;\n\t\tconst view = this.inputView;\n\t\tif (slot < 0 || base + STAGE_INPUT_STRIDE > view.length) return false;\n\t\tview[base + 2] = yawDelta;\n\t\tview[base + 3] = pitchDelta;\n\t\tview[base + 7] = 1;\n\t\treturn true;\n\t}\n\n\t/** Write reserved input slots (thruster world-space vector X/Y). */\n\twriteInputReserved(slot: number, reservedA: number, reservedB: number): boolean {\n\t\tconst base = slot * STAGE_INPUT_STRIDE;\n\t\tconst view = this.inputView;\n\t\tif (slot < 0 || base + STAGE_INPUT_STRIDE > view.length) return false;\n\t\tview[base + 5] = reservedA;\n\t\tview[base + 6] = reservedB;\n\t\tview[base + 7] = 1;\n\t\treturn true;\n\t}\n\n\t/**\n\t * Set or clear one button bit ({@link STAGE_INPUT_BUTTON_JUMP} /\n\t * {@link STAGE_INPUT_BUTTON_RUN}) in a slot's input bitmask.\n\t */\n\twriteInputButton(slot: number, buttonMask: number, pressed: boolean): boolean {\n\t\tconst base = slot * STAGE_INPUT_STRIDE;\n\t\tconst view = this.inputView;\n\t\tif (slot < 0 || base + STAGE_INPUT_STRIDE > view.length) return false;\n\t\tconst current = view[base + 4]! | 0;\n\t\tview[base + 4] = pressed ? (current | buttonMask) : (current & ~buttonMask);\n\t\tview[base + 7] = 1;\n\t\treturn true;\n\t}\n\n\t/**\n\t * Decode a slot's behavior snapshot from the buffer written at the end of\n\t * the previous step. Returns `null` when the slot has no behavior data.\n\t */\n\treadSnapshot(slot: number, out?: StageBehaviorSnapshot): StageBehaviorSnapshot | null {\n\t\tconst base = slot * STAGE_SNAPSHOT_STRIDE;\n\t\tconst view = this.snapshotView;\n\t\tif (slot < 0 || base + STAGE_SNAPSHOT_STRIDE > view.length) return null;\n\t\tif (view[base + 7] === 0) return null;\n\t\tconst result: StageBehaviorSnapshot = out ?? {\n\t\t\tgrounded: false,\n\t\t\tfsmState: 0,\n\t\t\tjumpCount: 0,\n\t\t\tverticalVelocity: 0,\n\t\t\tspeed: 0,\n\t\t\tyaw: 0,\n\t\t\tpitch: 0,\n\t\t};\n\t\tresult.grounded = view[base]! > 0.5;\n\t\tresult.fsmState = view[base + 1]! | 0;\n\t\tresult.jumpCount = view[base + 2]! | 0;\n\t\tresult.verticalVelocity = view[base + 3]!;\n\t\tresult.speed = view[base + 4]!;\n\t\tresult.yaw = view[base + 5]!;\n\t\tresult.pitch = view[base + 6]!;\n\t\treturn result;\n\t}\n\n\t// ─── Behavior helpers ─────────────────────────────────────────────\n\n\tget queryScratch(): Float32Array {\n\t\treturn this.queryView;\n\t}\n\n\tattachCooldown(slot: number): boolean {\n\t\treturn this.exports.zylem_stage_attach_cooldown(slot) !== 0;\n\t}\n\n\tregisterCooldown(slot: number, id: number, durationSeconds: number, immediate = false): boolean {\n\t\treturn (\n\t\t\tthis.exports.zylem_stage_cooldown_register(slot, id >>> 0, durationSeconds, immediate ? 1 : 0) !== 0\n\t\t);\n\t}\n\n\tfireCooldown(slot: number, id: number): boolean {\n\t\treturn this.exports.zylem_stage_cooldown_fire(slot, id >>> 0) !== 0;\n\t}\n\n\tresetCooldown(slot: number, id: number): boolean {\n\t\treturn this.exports.zylem_stage_cooldown_reset(slot, id >>> 0) !== 0;\n\t}\n\n\tcooldownRemaining(slot: number, id: number): number {\n\t\treturn this.exports.zylem_stage_cooldown_remaining(slot, id >>> 0);\n\t}\n\n\tattachWorldBoundary(\n\t\tslot: number,\n\t\tdim: StageBoundaryDimValue,\n\t\tbounds: StageWorldBoundaryOptions,\n\t): boolean {\n\t\treturn (\n\t\t\tthis.exports.zylem_stage_attach_world_boundary(\n\t\t\t\tslot,\n\t\t\t\tdim,\n\t\t\t\tbounds.top, bounds.bottom, bounds.left, bounds.right,\n\t\t\t\tbounds.front ?? 0, bounds.back ?? 0, bounds.padding ?? 0,\n\t\t\t) !== 0\n\t\t);\n\t}\n\n\tqueryWorldBoundary(slot: number): { hits: number; clamped: [number, number, number] } | null {\n\t\tif (this.exports.zylem_stage_query_world_boundary(slot) === 0) return null;\n\t\tconst v = this.queryView;\n\t\treturn {\n\t\t\thits: v[0]! | 0,\n\t\t\tclamped: [v[1]!, v[2]!, v[3]!],\n\t\t};\n\t}\n\n\tattachScreenWrap(slot: number, opts: StageScreenWrapOptions): boolean {\n\t\treturn (\n\t\t\tthis.exports.zylem_stage_attach_screen_wrap(\n\t\t\t\tslot, opts.width, opts.height,\n\t\t\t\topts.centerX ?? 0, opts.centerY ?? 0, opts.edgeThreshold ?? 0,\n\t\t\t) !== 0\n\t\t);\n\t}\n\n\tqueryScreenWrap(slot: number): { fsm: number; lastWrappedAxes: number } | null {\n\t\tif (this.exports.zylem_stage_query_screen_wrap(slot) === 0) return null;\n\t\tconst v = this.queryView;\n\t\treturn { fsm: v[0]! | 0, lastWrappedAxes: v[1]! | 0 };\n\t}\n\n\tattachRicochet(\n\t\tslot: number,\n\t\tdim: StageRicochetDimValue,\n\t\topts: StageRicochetOptions,\n\t): boolean {\n\t\treturn (\n\t\t\tthis.exports.zylem_stage_attach_ricochet(\n\t\t\t\tslot, dim, opts.minSpeed, opts.maxSpeed, opts.speedMultiplier,\n\t\t\t\topts.maxAngleDeg, opts.reflectionMode,\n\t\t\t) !== 0\n\t\t);\n\t}\n\n\tqueryRicochet(slot: number): { bounces: number; lastKind: number } | null {\n\t\tif (this.exports.zylem_stage_query_ricochet(slot) === 0) return null;\n\t\tconst v = this.queryView;\n\t\treturn { bounces: v[0]! | 0, lastKind: v[1]! | 0 };\n\t}\n\n\tattachThruster(slot: number, opts: StageThrusterOptions): boolean {\n\t\treturn (\n\t\t\tthis.exports.zylem_stage_attach_thruster(\n\t\t\t\tslot, opts.maxSpeed, opts.acceleration, opts.turnRateRadPerSec, opts.linearDamping,\n\t\t\t) !== 0\n\t\t);\n\t}\n\n\tsetThrusterInput(\n\t\tslot: number,\n\t\tthrust: number,\n\t\tturn: number,\n\t\tvectorX = 0,\n\t\tvectorY = 0,\n\t): void {\n\t\tthis.exports.zylem_stage_set_thruster_input(slot, thrust, turn, vectorX, vectorY);\n\t}\n\n\tqueryThruster(slot: number): { headingRad: number; speed: number } | null {\n\t\tif (this.exports.zylem_stage_query_thruster(slot) === 0) return null;\n\t\tconst v = this.queryView;\n\t\treturn { headingRad: v[0]!, speed: v[1]! };\n\t}\n\n\tattachTopDown(slot: number, opts: StageTopDownOptions): boolean {\n\t\treturn this.exports.zylem_stage_attach_top_down(slot, opts.plane, opts.speed, opts.faceMovement ? 1 : 0) !== 0;\n\t}\n\n\tsetTopDownInput(slot: number, axisA: number, axisB: number): void {\n\t\tthis.exports.zylem_stage_set_top_down_input(slot, axisA, axisB);\n\t}\n\n\tattachJumper2D(slot: number, opts: StageJumper2DOptions): boolean {\n\t\treturn (\n\t\t\tthis.exports.zylem_stage_attach_jumper_2d(\n\t\t\t\tslot, opts.jumpForce, opts.maxJumps >>> 0,\n\t\t\t\topts.jumpBufferTime, opts.coyoteTime, opts.gravity,\n\t\t\t) !== 0\n\t\t);\n\t}\n\n\tsetJumper2DInput(slot: number, jumpPressed: boolean): void {\n\t\tthis.exports.zylem_stage_set_jumper_2d_input(slot, jumpPressed ? 1 : 0);\n\t}\n\n\tqueryJumper2D(slot: number): { grounded: boolean; jumpCount: number; coyote: number; jumpBuffer: number } | null {\n\t\tif (this.exports.zylem_stage_query_jumper_2d(slot) === 0) return null;\n\t\tconst v = this.queryView;\n\t\treturn {\n\t\t\tgrounded: v[0]! > 0.5,\n\t\t\tjumpCount: v[1]! | 0,\n\t\t\tcoyote: v[2]!,\n\t\t\tjumpBuffer: v[3]!,\n\t\t};\n\t}\n\n\tattachJumper3D(slot: number, opts: StageJumper3DOptions): boolean {\n\t\treturn this.exports.zylem_stage_attach_jumper_3d(\n\t\t\tslot, opts.jumpForce, opts.maxJumps >>> 0, opts.gravity,\n\t\t\topts.coyoteTime ?? 0.1, opts.jumpBufferTime ?? 0.08,\n\t\t) !== 0;\n\t}\n\n\tsetJumper3DInput(slot: number, jump: boolean): void {\n\t\tthis.exports.zylem_stage_set_jumper_3d_input(slot, jump ? 1 : 0);\n\t}\n\n\tqueryJumper3D(slot: number): { grounded: boolean; jumpCount: number; verticalVelocity: number } | null {\n\t\tif (this.exports.zylem_stage_query_jumper_3d(slot) === 0) return null;\n\t\tconst v = this.queryView;\n\t\treturn { grounded: v[0]! > 0.5, jumpCount: v[1]! | 0, verticalVelocity: v[2]! };\n\t}\n\n\tattachShooter2D(slot: number, opts: StageShooter2DOptions): boolean {\n\t\treturn (\n\t\t\tthis.exports.zylem_stage_attach_shooter_2d(\n\t\t\t\tslot, opts.fireRateHz, opts.muzzleOffsetX, opts.muzzleOffsetY, opts.muzzleSpeed,\n\t\t\t) !== 0\n\t\t);\n\t}\n\n\tfireShooter2D(slot: number, x: number, y: number, z: number, yaw: number): boolean {\n\t\treturn this.exports.zylem_stage_shooter_2d_fire(slot, x, y, z, yaw) !== 0;\n\t}\n\n\tqueryShooter2D(slot: number): { cooldown: number; firedCount: number } | null {\n\t\tif (this.exports.zylem_stage_query_shooter_2d(slot) === 0) return null;\n\t\tconst v = this.queryView;\n\t\treturn { cooldown: v[0]!, firedCount: v[1]! | 0 };\n\t}\n\n\tattachPlatformer3D(slot: number, opts: StagePlatformer3DOptions): boolean {\n\t\treturn (\n\t\t\tthis.exports.zylem_stage_attach_platformer_3d(\n\t\t\t\tslot, opts.halfHeight, opts.radius,\n\t\t\t\topts.walkSpeed, opts.runSpeed, opts.jumpForce,\n\t\t\t\topts.maxJumps >>> 0, opts.gravity,\n\t\t\t\topts.coyoteTime ?? 0.1, opts.jumpBufferTime ?? 0.1,\n\t\t\t\topts.jumpCutMultiplier ?? 0.5, opts.multiJumpWindow ?? 0.15,\n\t\t\t\topts.slopeClimbAngle ?? 50, opts.slopeSlideAngle ?? 40,\n\t\t\t\topts.autostepHeight ?? 0.3, opts.autostepMinWidth ?? 0.1,\n\t\t\t\topts.snapToGroundDistance ?? 0.3, opts.characterOffset ?? 0.05,\n\t\t\t\topts.offsetX ?? 0, opts.offsetY ?? 0, opts.offsetZ ?? 0,\n\t\t\t\topts.shapeSource ?? StagePlatformerShapeSource.Auto,\n\t\t\t) !== 0\n\t\t);\n\t}\n\n\tsetPlatformer3DInputAxes(slot: number, moveX: number, moveZ: number): void {\n\t\tthis.exports.zylem_stage_set_platformer_3d_input_axes(slot, moveX, moveZ);\n\t}\n\n\tsetPlatformer3DInputButtons(slot: number, jump: boolean, run: boolean): void {\n\t\tthis.exports.zylem_stage_set_platformer_3d_input_buttons(slot, jump ? 1 : 0, run ? 1 : 0);\n\t}\n\n\tqueryPlatformer3D(slot: number): { grounded: boolean; jumpCount: number; fsmState: number; speed: number } | null {\n\t\tif (this.exports.zylem_stage_query_platformer_3d(slot) === 0) return null;\n\t\tconst v = this.queryView;\n\t\treturn {\n\t\t\tgrounded: v[0]! > 0.5,\n\t\t\tjumpCount: v[1]! | 0,\n\t\t\tfsmState: v[2]! | 0,\n\t\t\tspeed: v[3]!,\n\t\t};\n\t}\n\n\tattachPlatformer2D(slot: number, opts: StagePlatformer2DOptions): boolean {\n\t\treturn (\n\t\t\tthis.exports.zylem_stage_attach_platformer_2d(\n\t\t\t\tslot, opts.halfHeight, opts.radius,\n\t\t\t\topts.walkSpeed, opts.runSpeed, opts.jumpForce,\n\t\t\t\topts.maxJumps >>> 0, opts.gravity,\n\t\t\t\topts.coyoteTime ?? 0.1, opts.jumpBufferTime ?? 0.1,\n\t\t\t\topts.jumpCutMultiplier ?? 0.5, opts.multiJumpWindow ?? 0.15,\n\t\t\t\topts.slopeClimbAngle ?? 50, opts.slopeSlideAngle ?? 40,\n\t\t\t\topts.autostepHeight ?? 0.25, opts.autostepMinWidth ?? 0.05,\n\t\t\t\topts.snapToGroundDistance ?? 0.2, opts.characterOffset ?? 0.05,\n\t\t\t\topts.offsetX ?? 0, opts.offsetY ?? 0, opts.offsetZ ?? 0,\n\t\t\t\topts.shapeSource ?? StagePlatformerShapeSource.Auto,\n\t\t\t) !== 0\n\t\t);\n\t}\n\n\tsetPlatformer2DInputAxes(slot: number, moveX: number): void {\n\t\tthis.exports.zylem_stage_set_platformer_2d_input_axes(slot, moveX);\n\t}\n\n\tsetPlatformer2DInputButtons(slot: number, jump: boolean, run: boolean): void {\n\t\tthis.exports.zylem_stage_set_platformer_2d_input_buttons(slot, jump ? 1 : 0, run ? 1 : 0);\n\t}\n\n\tqueryPlatformer2D(slot: number): { grounded: boolean; jumpCount: number; fsmState: number; verticalVelocity: number } | null {\n\t\tif (this.exports.zylem_stage_query_platformer_2d(slot) === 0) return null;\n\t\tconst v = this.queryView;\n\t\treturn {\n\t\t\tgrounded: v[0]! > 0.5,\n\t\t\tjumpCount: v[1]! | 0,\n\t\t\tfsmState: v[2]! | 0,\n\t\t\tverticalVelocity: v[3]!,\n\t\t};\n\t}\n\n\tattachFirstPerson(slot: number, opts: StageFirstPersonOptions): boolean {\n\t\treturn (\n\t\t\tthis.exports.zylem_stage_attach_first_person(\n\t\t\t\tslot, opts.walkSpeed, opts.runSpeed, opts.eyeHeight, opts.lookSensitivity,\n\t\t\t) !== 0\n\t\t);\n\t}\n\n\tsetFirstPersonInput(slot: number, input: StageFirstPersonInput): void {\n\t\tthis.exports.zylem_stage_set_first_person_input(\n\t\t\tslot, input.moveX, input.moveZ, input.lookYawDelta, input.lookPitchDelta, input.run ? 1 : 0,\n\t\t);\n\t}\n\n\tqueryFirstPerson(slot: number): { yaw: number; pitch: number; speed: number; eyeHeight: number } | null {\n\t\tif (this.exports.zylem_stage_query_first_person(slot) === 0) return null;\n\t\tconst v = this.queryView;\n\t\treturn { yaw: v[0]!, pitch: v[1]!, speed: v[2]!, eyeHeight: v[3]! };\n\t}\n}\n\n/**\n * Load the bundled `@zylem/runtime` wasm (or a custom `source`), instantiate\n * it, and construct a `WasmStageRuntime` around the exports.\n */\nexport async function createWasmStageRuntime(\n\toptions: WasmStageRuntimeOptions = {},\n): Promise<WasmStageRuntime> {\n\tconst { exports } = await loadStageFfi({\n\t\tsource: options.source,\n\t\timports: options.imports,\n\t});\n\treturn new WasmStageRuntime(exports, options);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/behaviors/top-down-movement/components.ts"],"sourcesContent":["export interface TopDownMovementComponent {\n\tmoveSpeed: number;\n}\n\nexport function createTopDownMovementComponent(\n\toptions: Partial<TopDownMovementComponent> = {},\n): TopDownMovementComponent {\n\treturn {\n\t\tmoveSpeed: options.moveSpeed ?? 8,\n\t};\n}\n\nexport interface TopDownMovementInputComponent {\n\tmoveX: number;\n\tmoveY: number;\n\tfaceX: number;\n\tfaceY: number;\n}\n\nexport function createTopDownMovementInputComponent(): TopDownMovementInputComponent {\n\treturn {\n\t\tmoveX: 0,\n\t\tmoveY: 0,\n\t\tfaceX: 0,\n\t\tfaceY: 0,\n\t};\n}\n\nexport interface TopDownMovementStateComponent {\n\tfacingAngle: number;\n\tmoving: boolean;\n}\n\nexport function createTopDownMovementStateComponent(): TopDownMovementStateComponent {\n\treturn {\n\t\tfacingAngle: 0,\n\t\tmoving: false,\n\t};\n}\n"],"mappings":";AAIO,SAAS,+BACf,UAA6C,CAAC,GACnB;AAC3B,SAAO;AAAA,IACN,WAAW,QAAQ,aAAa;AAAA,EACjC;AACD;AASO,SAAS,sCAAqE;AACpF,SAAO;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,EACR;AACD;AAOO,SAAS,sCAAqE;AACpF,SAAO;AAAA,IACN,aAAa;AAAA,IACb,QAAQ;AAAA,EACT;AACD;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/behaviors/behavior-descriptor.ts"],"sourcesContent":["/**\n * BehaviorDescriptor\n *\n * Type-safe behavior descriptors that provide options inference.\n * Used with entity.use() to declaratively attach behaviors to entities.\n *\n * Each behavior can define its own handle type via `createHandle`,\n * providing behavior-specific methods with full type safety.\n */\n\nimport type { BehaviorSystemFactory } from './behavior-system';\n\n/**\n * Base handle returned by entity.use() for lazy access to behavior runtime.\n * FSM is null until entity is spawned and components are initialized.\n */\nexport interface BaseBehaviorHandle<\n O extends Record<string, any> = Record<string, any>,\n> {\n /** Get the FSM instance (null until entity is spawned) */\n getFSM(): any | null;\n /** Get the current options */\n getOptions(): O;\n /** Access the underlying behavior ref */\n readonly ref: BehaviorRef<O>;\n}\n\n/**\n * Reference to a behavior stored on an entity\n */\nexport interface BehaviorRef<\n O extends Record<string, any> = Record<string, any>,\n> {\n /** The behavior descriptor */\n descriptor: BehaviorDescriptor<O, any>;\n /** Merged options (defaults + overrides) */\n options: O;\n /** Optional FSM instance - set lazily when entity is spawned */\n fsm?: any;\n}\n\n/**\n * A typed behavior descriptor that associates a symbol key with:\n * - Default options (providing type inference)\n * - A system factory to create the behavior system\n * - An optional handle factory for behavior-specific methods\n */\nexport interface BehaviorDescriptor<\n O extends Record<string, any> = Record<string, any>,\n H extends Record<string, any> = Record<string, never>,\n I = unknown,\n> {\n /** Unique symbol identifying this behavior */\n readonly key: symbol;\n /** Default options (used for type inference) */\n readonly defaultOptions: O;\n /** Factory to create the behavior system */\n readonly systemFactory: any;\n /**\n * Optional factory to create behavior-specific handle methods.\n * These methods are merged into the handle returned by entity.use().\n */\n readonly createHandle?: (ref: any) => H;\n}\n\n/**\n * The full handle type returned by entity.use().\n * Combines base handle with behavior-specific methods.\n */\nexport type BehaviorHandle<\n O extends Record<string, any> = Record<string, any>,\n H extends Record<string, any> = Record<string, never>,\n> = BaseBehaviorHandle<O> & H;\n\n/**\n * Configuration for defining a new behavior\n */\nexport interface DefineBehaviorConfig<\n O extends Record<string, any>,\n H extends Record<string, any> = Record<string, never>,\n I = unknown,\n> {\n /** Human-readable name for debugging */\n name: string;\n /** Default options - these define the type */\n defaultOptions: O;\n /** Factory function to create the system */\n systemFactory: BehaviorSystemFactory;\n /**\n * Optional factory to create behavior-specific handle methods.\n * The returned object is merged into the handle returned by entity.use().\n *\n * @example\n * ```typescript\n * createHandle: (ref) => ({\n * getLastHits: () => ref.fsm?.getLastHits() ?? null,\n * getMovement: (moveX, moveY) => ref.fsm?.getMovement(moveX, moveY) ?? { moveX, moveY },\n * }),\n * ```\n */\n createHandle?: (ref: BehaviorRef<O>) => H;\n}\n\n/**\n * Define a typed behavior descriptor.\n *\n * @example\n * ```typescript\n * export const WorldBoundary2DBehavior = defineBehavior({\n * name: 'world-boundary-2d',\n * defaultOptions: { boundaries: { top: 0, bottom: 0, left: 0, right: 0 } },\n * systemFactory: (ctx) => new WorldBoundary2DSystem(ctx.world),\n * createHandle: (ref) => ({\n * getLastHits: () => ref.fsm?.getLastHits() ?? null,\n * getMovement: (moveX: number, moveY: number) =>\n * ref.fsm?.getMovement(moveX, moveY) ?? { moveX, moveY },\n * }),\n * });\n *\n * // Usage - handle has getLastHits and getMovement with full types\n * const boundary = ship.use(WorldBoundary2DBehavior, { ... });\n * const hits = boundary.getLastHits(); // Fully typed!\n * ```\n */\nexport function defineBehavior<\n O extends Record<string, any>,\n H extends Record<string, any> = Record<string, never>,\n I = unknown,\n>(\n config: DefineBehaviorConfig<O, H, I>,\n): BehaviorDescriptor<O, H, I> {\n return {\n key: Symbol.for(`zylem:behavior:${config.name}`),\n defaultOptions: config.defaultOptions,\n systemFactory: config.systemFactory,\n createHandle: config.createHandle,\n };\n}\n"],"mappings":";AA4HO,SAAS,eAKd,QAC6B;AAC7B,SAAO;AAAA,IACL,KAAK,uBAAO,IAAI,kBAAkB,OAAO,IAAI,EAAE;AAAA,IAC/C,gBAAgB,OAAO;AAAA,IACvB,eAAe,OAAO;AAAA,IACtB,cAAc,OAAO;AAAA,EACvB;AACF;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/behaviors/first-person/first-person-fsm.ts","../src/lib/behaviors/first-person/first-person.system.ts","../src/lib/behaviors/first-person/first-person.descriptor.ts"],"sourcesContent":["/**\n * First Person Controller Finite State Machine\n *\n * Manages state transitions for first-person movement:\n * - Idle: Standing still\n * - Walking: Moving at walk speed\n * - Running: Moving at run/sprint speed\n */\n\nimport { SyncStateMachine, t } from '../../core/utility/sync-state-machine';\nimport type { FirstPersonInputComponent, FirstPersonStateComponent } from './components';\n\n/**\n * First-person movement states\n */\nexport enum FirstPersonState {\n\tIdle = 'idle',\n\tWalking = 'walking',\n\tRunning = 'running',\n}\n\n/**\n * Events that trigger state transitions\n */\nexport enum FirstPersonEvent {\n\tWalk = 'walk',\n\tRun = 'run',\n\tStop = 'stop',\n}\n\n/**\n * Context for the FSM\n */\nexport interface FirstPersonContext {\n\tinput: FirstPersonInputComponent;\n\tstate: FirstPersonStateComponent;\n}\n\n/**\n * First Person Controller FSM\n */\nexport class FirstPersonFSM {\n\tmachine: SyncStateMachine<FirstPersonState, FirstPersonEvent, never>;\n\n\tconstructor(private ctx: FirstPersonContext) {\n\t\tthis.machine = new SyncStateMachine<FirstPersonState, FirstPersonEvent, never>(\n\t\t\tFirstPersonState.Idle,\n\t\t\t[\n\t\t\t\t// Idle transitions\n\t\t\t\tt(FirstPersonState.Idle, FirstPersonEvent.Walk, FirstPersonState.Walking),\n\t\t\t\tt(FirstPersonState.Idle, FirstPersonEvent.Run, FirstPersonState.Running),\n\t\t\t\tt(FirstPersonState.Idle, FirstPersonEvent.Stop, FirstPersonState.Idle),\n\n\t\t\t\t// Walking transitions\n\t\t\t\tt(FirstPersonState.Walking, FirstPersonEvent.Run, FirstPersonState.Running),\n\t\t\t\tt(FirstPersonState.Walking, FirstPersonEvent.Stop, FirstPersonState.Idle),\n\t\t\t\tt(FirstPersonState.Walking, FirstPersonEvent.Walk, FirstPersonState.Walking),\n\n\t\t\t\t// Running transitions\n\t\t\t\tt(FirstPersonState.Running, FirstPersonEvent.Walk, FirstPersonState.Walking),\n\t\t\t\tt(FirstPersonState.Running, FirstPersonEvent.Stop, FirstPersonState.Idle),\n\t\t\t\tt(FirstPersonState.Running, FirstPersonEvent.Run, FirstPersonState.Running),\n\t\t\t],\n\t\t);\n\t}\n\n\t/** Get the current state */\n\tgetState(): FirstPersonState {\n\t\treturn this.machine.getState();\n\t}\n\n\t/** Dispatch an event to the FSM */\n\tdispatch(event: FirstPersonEvent): void {\n\t\tif (this.machine.can(event)) {\n\t\t\tthis.machine.syncDispatch(event);\n\t\t}\n\t}\n\n\t/** Get the current yaw from context */\n\tgetYaw(): number {\n\t\treturn this.ctx.state.yaw;\n\t}\n\n\t/** Get the current pitch from context */\n\tgetPitch(): number {\n\t\treturn this.ctx.state.pitch;\n\t}\n\n\t/**\n\t * Update FSM based on current input and state.\n\t */\n\tupdate(input: FirstPersonInputComponent, state: FirstPersonStateComponent): void {\n\t\tthis.ctx.input = input;\n\t\tthis.ctx.state = state;\n\n\t\tconst hasMovement = Math.abs(input.moveX) > 0.1 || Math.abs(input.moveZ) > 0.1;\n\n\t\tif (hasMovement) {\n\t\t\tif (input.sprint) {\n\t\t\t\tthis.dispatch(FirstPersonEvent.Run);\n\t\t\t} else {\n\t\t\t\tthis.dispatch(FirstPersonEvent.Walk);\n\t\t\t}\n\t\t} else {\n\t\t\tthis.dispatch(FirstPersonEvent.Stop);\n\t\t}\n\t}\n}\n","/**\n * First Person Presentation System\n *\n * Presentation-only companion to the wasm `first_person` Stage behavior:\n * - Syncs the FirstPersonPerspective eye position from the runtime pose\n * - Applies the runtime's yaw/pitch (from the behavior snapshot) to the\n * perspective so the camera matches the simulated look state\n * - Positions an optional viewmodel entity relative to the camera\n *\n * All movement/look simulation happens in the wasm runtime; this system only\n * reads poses and snapshots.\n */\n\nimport { Vector3, Quaternion, Euler } from 'three';\nimport type { FirstPersonPerspective } from '../../camera/perspectives/first-person-perspective';\nimport type {\n\tBehaviorRuntime,\n\tStagePose,\n\tStageBehaviorSnapshot,\n} from '../../runtime/wasm-stage-runtime';\nimport type {\n\tFirstPersonMovementComponent,\n\tFirstPersonInputComponent,\n\tFirstPersonStateComponent,\n} from './components';\nimport type { TransformState } from '../../capabilities/transform-store';\n\n/**\n * Entity interface for the first-person controller.\n * Entities with this behavior have these components attached.\n */\nexport interface FirstPersonEntity {\n\tuuid: string;\n\ttransformStore: TransformState;\n\tfirstPerson: FirstPersonMovementComponent;\n\t$fps: FirstPersonInputComponent;\n\tfirstPersonState: FirstPersonStateComponent;\n}\n\n/**\n * Viewmodel configuration for an entity that follows the camera.\n */\nexport interface ViewmodelConfig {\n\t/** The entity whose visual group should be positioned relative to the camera. */\n\tentity: any;\n\t/** Offset from the eye position in camera-local space (right, down, forward). */\n\toffset: Vector3;\n\t/** Additional rotation applied to the viewmodel in local space (Euler angles in radians). */\n\trotation?: Euler;\n}\n\n// Reusable temporaries (avoid per-frame allocations)\nconst _viewmodelQuat = new Quaternion();\nconst _viewmodelLocalQuat = new Quaternion();\nconst _viewmodelEuler = new Euler();\nconst _offset = new Vector3();\nconst _pose: StagePose = { position: [0, 0, 0], rotation: [0, 0, 0, 1] };\nconst _snapshot = {} as StageBehaviorSnapshot;\n\n/**\n * Presentation system driven by runtime pose + snapshot reads.\n */\nexport class FirstPersonPresentation {\n\tprivate perspectives = new Map<string, FirstPersonPerspective>();\n\tprivate viewmodels = new Map<string, ViewmodelConfig>();\n\n\t/**\n\t * Associate a FirstPersonPerspective with an entity (by uuid).\n\t * Called once by the descriptor system when the behavior is initialized.\n\t */\n\tsetPerspective(entityUuid: string, perspective: FirstPersonPerspective): void {\n\t\tthis.perspectives.set(entityUuid, perspective);\n\t}\n\n\thasPerspective(entityUuid: string): boolean {\n\t\treturn this.perspectives.has(entityUuid);\n\t}\n\n\t/**\n\t * Attach a viewmodel (weapon/item) to an entity.\n\t * The viewmodel entity's group will be positioned relative to the camera each frame.\n\t */\n\tsetViewmodel(entityUuid: string, config: ViewmodelConfig): void {\n\t\tthis.viewmodels.set(entityUuid, config);\n\t}\n\n\thasViewmodel(entityUuid: string): boolean {\n\t\treturn this.viewmodels.has(entityUuid);\n\t}\n\n\t/**\n\t * Sync camera + viewmodel for one entity from the runtime state.\n\t */\n\tsyncEntity(\n\t\tentityUuid: string,\n\t\truntime: BehaviorRuntime,\n\t\thandle: number,\n\t\tmovement: FirstPersonMovementComponent,\n\t\tstate: FirstPersonStateComponent | undefined,\n\t): void {\n\t\tconst perspective = this.perspectives.get(entityUuid);\n\t\tconst pose = runtime.getPose(handle, _pose);\n\t\tconst snapshot = runtime.readSnapshot(handle, _snapshot);\n\n\t\tif (perspective && snapshot) {\n\t\t\tperspective.setLook?.(snapshot.yaw, snapshot.pitch);\n\t\t\tif (state) {\n\t\t\t\tstate.yaw = snapshot.yaw;\n\t\t\t\tstate.pitch = snapshot.pitch;\n\t\t\t\tstate.currentSpeed = snapshot.speed;\n\t\t\t}\n\t\t}\n\n\t\tif (perspective?.initialPosition && pose) {\n\t\t\tperspective.initialPosition.set(\n\t\t\t\tpose.position[0],\n\t\t\t\tpose.position[1] + movement.eyeHeight,\n\t\t\t\tpose.position[2],\n\t\t\t);\n\t\t}\n\n\t\tconst vm = this.viewmodels.get(entityUuid);\n\t\tif (vm && perspective?.initialPosition && state) {\n\t\t\tthis.positionViewmodel(vm, perspective, state, runtime);\n\t\t}\n\t}\n\n\t/**\n\t * Position a viewmodel entity relative to the camera's eye position and rotation.\n\t */\n\tprivate positionViewmodel(\n\t\tvm: ViewmodelConfig,\n\t\tperspective: FirstPersonPerspective,\n\t\tstate: FirstPersonStateComponent,\n\t\truntime: BehaviorRuntime,\n\t): void {\n\t\tconst eyePos = perspective.initialPosition;\n\t\tif (!eyePos) return;\n\n\t\t// Build camera rotation quaternion\n\t\t_viewmodelQuat.setFromEuler(\n\t\t\t_viewmodelEuler.set(state.pitch, state.yaw, 0, 'YXZ'),\n\t\t);\n\n\t\t// Compose with the viewmodel's local rotation (model orientation fix)\n\t\tif (vm.rotation) {\n\t\t\t_viewmodelLocalQuat.setFromEuler(vm.rotation);\n\t\t\t_viewmodelQuat.multiply(_viewmodelLocalQuat);\n\t\t}\n\n\t\t// Transform the local offset into world space\n\t\t_offset.copy(vm.offset).applyQuaternion(_viewmodelQuat);\n\n\t\tconst wx = eyePos.x + _offset.x;\n\t\tconst wy = eyePos.y + _offset.y;\n\t\tconst wz = eyePos.z + _offset.z;\n\n\t\tconst entity = vm.entity;\n\n\t\t// Move the runtime body (if registered) so physics stays in sync\n\t\tconst handle = (entity?.runtimeHandle ?? -1) as number;\n\t\tif (handle >= 0) {\n\t\t\truntime.setPosition(handle, wx, wy, wz);\n\t\t\truntime.setRotation(\n\t\t\t\thandle,\n\t\t\t\t_viewmodelQuat.x, _viewmodelQuat.y, _viewmodelQuat.z, _viewmodelQuat.w,\n\t\t\t);\n\t\t}\n\n\t\t// Also set the group directly for immediate visual update\n\t\tif (entity?.group) {\n\t\t\tentity.group.position.set(wx, wy, wz);\n\t\t\tentity.group.quaternion.copy(_viewmodelQuat);\n\t\t}\n\t}\n\n\t/** Cleanup */\n\tdestroy(): void {\n\t\tthis.perspectives.clear();\n\t\tthis.viewmodels.clear();\n\t}\n}\n","/**\n * First Person Controller Behavior Descriptor\n *\n * Type-safe descriptor for the first-person controller behavior system.\n * Provides entity.use() API for FPS movement and camera control.\n */\n\nimport { Euler } from 'three';\nimport { defineBehavior } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport type { FirstPersonPerspective } from '../../camera/perspectives/first-person-perspective';\nimport { Vec3Input, VEC3_ZERO, toThreeVector3 } from '../../core/vector';\nimport {\n\tFirstPersonPresentation,\n\ttype FirstPersonEntity,\n\ttype ViewmodelConfig,\n} from './first-person.system';\nimport { FirstPersonState } from './first-person-fsm';\nimport {\n\tcreateFirstPersonMovementComponent,\n\tcreateFirstPersonInputComponent,\n\tcreateFirstPersonStateComponent,\n} from './components';\nimport {\n\tSTAGE_INPUT_BUTTON_RUN,\n\treadBehaviorSnapshot,\n\ttype BehaviorRuntime,\n} from '../../runtime/wasm-stage-runtime';\n\n/**\n * First-person controller behavior options (typed for entity.use() autocomplete).\n */\nexport interface FirstPersonBehaviorOptions {\n\t/** Base walking speed (default: 8) */\n\twalkSpeed?: number;\n\t/** Sprint/run speed (default: 16) */\n\trunSpeed?: number;\n\t/** Look sensitivity multiplier (default: 2) */\n\tlookSensitivity?: number;\n\t/** Eye height offset above entity position (default: 1.7) */\n\teyeHeight?: number;\n\t/** The FirstPersonPerspective to drive (from camera.getPerspective()) */\n\tperspective?: FirstPersonPerspective;\n\t/** Optional viewmodel (weapon/item) to position relative to the camera */\n\tviewmodel?: { entity: any; offset: Vec3Input; rotation?: Euler };\n}\n\nconst defaultOptions: FirstPersonBehaviorOptions = {\n\twalkSpeed: 8,\n\trunSpeed: 16,\n\tlookSensitivity: 2,\n\teyeHeight: 1.7,\n};\n\nconst FIRST_PERSON_BEHAVIOR_KEY = Symbol.for(\n\t'zylem:behavior:first-person-controller',\n);\n\n/**\n * Forwards look/move input into the wasm runtime and syncs the camera\n * perspective + optional viewmodel from the runtime's pose/snapshot\n * (presentation only — the Rust `first_person` behavior owns simulation).\n */\nclass FirstPersonBehaviorSystem implements BehaviorSystem {\n\tprivate presentation = new FirstPersonPresentation();\n\tprivate attachedRuntimeSlots = new Set<number>();\n\n\tconstructor(\n\t\tprivate wasmStage: BehaviorRuntime | null,\n\t\tprivate getBehaviorLinks?: (key: symbol) => Iterable<BehaviorEntityLink>,\n\t) {}\n\n\tupdate(_ecs: unknown, _delta: number): void {\n\t\tconst links = this.getBehaviorLinks?.(FIRST_PERSON_BEHAVIOR_KEY);\n\t\tif (!links) return;\n\n\t\tfor (const link of links) {\n\t\t\tconst gameEntity = link.entity as any;\n\t\t\tconst fpsRef = link.ref as any;\n\n\t\t\tconst options = fpsRef.options as FirstPersonBehaviorOptions;\n\n\t\t\t// Initialize components (once)\n\t\t\tif (!gameEntity.firstPerson) {\n\t\t\t\tgameEntity.firstPerson = createFirstPersonMovementComponent(options);\n\t\t\t}\n\t\t\tif (!gameEntity.$fps) {\n\t\t\t\tgameEntity.$fps = createFirstPersonInputComponent();\n\t\t\t}\n\t\t\tif (!gameEntity.firstPersonState) {\n\t\t\t\tgameEntity.firstPersonState = createFirstPersonStateComponent();\n\t\t\t}\n\n\t\t\t// Wire up perspective (once)\n\t\t\tif (options.perspective && !this.presentation.hasPerspective(gameEntity.uuid)) {\n\t\t\t\tthis.presentation.setPerspective(gameEntity.uuid, options.perspective);\n\t\t\t}\n\n\t\t\t// Wire up viewmodel (once)\n\t\t\tif (options.viewmodel && !this.presentation.hasViewmodel(gameEntity.uuid)) {\n\t\t\t\tthis.presentation.setViewmodel(gameEntity.uuid, {\n\t\t\t\t\t...options.viewmodel,\n\t\t\t\t\toffset: toThreeVector3(options.viewmodel.offset, VEC3_ZERO),\n\t\t\t\t} as ViewmodelConfig);\n\t\t\t}\n\n\t\t\tconst handle = (gameEntity.runtimeHandle ?? -1) as number;\n\t\t\tif (!this.wasmStage || handle < 0) continue;\n\n\t\t\tthis.ensureWasmAttached(handle, options);\n\t\t\tfpsRef.__wasmStage = this.wasmStage;\n\t\t\tfpsRef.__entity = gameEntity;\n\t\t\tconst input = gameEntity.$fps;\n\t\t\tif (input) {\n\t\t\t\tthis.wasmStage.writeInputAxes(handle, input.moveX ?? 0, input.moveZ ?? 0);\n\t\t\t\tthis.wasmStage.writeInputLook(handle, input.lookX ?? 0, input.lookY ?? 0);\n\t\t\t\tthis.wasmStage.writeInputButton(handle, STAGE_INPUT_BUTTON_RUN, !!input.sprint);\n\t\t\t}\n\n\t\t\tthis.presentation.syncEntity(\n\t\t\t\tgameEntity.uuid,\n\t\t\t\tthis.wasmStage,\n\t\t\t\thandle,\n\t\t\t\tgameEntity.firstPerson,\n\t\t\t\tgameEntity.firstPersonState,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate ensureWasmAttached(handle: number, options: FirstPersonBehaviorOptions): void {\n\t\tif (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;\n\t\tthis.wasmStage.attachFirstPerson(handle, {\n\t\t\twalkSpeed: options.walkSpeed ?? defaultOptions.walkSpeed!,\n\t\t\trunSpeed: options.runSpeed ?? defaultOptions.runSpeed!,\n\t\t\teyeHeight: options.eyeHeight ?? defaultOptions.eyeHeight!,\n\t\t\tlookSensitivity: options.lookSensitivity ?? defaultOptions.lookSensitivity!,\n\t\t});\n\t\tthis.attachedRuntimeSlots.add(handle);\n\t}\n\n\tdestroy(_ecs: unknown): void {\n\t\tthis.presentation.destroy();\n\t\tthis.attachedRuntimeSlots.clear();\n\t}\n}\n\n/**\n * FirstPersonBehavior - typed descriptor for first-person movement and camera control.\n *\n * Provides complete first-person controller including:\n * - WASD movement relative to camera yaw\n * - Mouse look driving a FirstPersonPerspective\n * - Optional viewmodel positioning (weapon/item following camera)\n * - Walk/run state tracking via FSM\n *\n * @example\n * ```typescript\n * import { FirstPersonBehavior } from \"@zylem/game-lib/behavior\";\n * import { createCamera, Perspectives, FirstPersonPerspective } from \"@zylem/game-lib/core\";\n * import { createActor } from \"@zylem/game-lib/entity\";\n *\n * const fpsCamera = createCamera({ perspective: Perspectives.FirstPerson, ... });\n * const fps = fpsCamera.getPerspective<FirstPersonPerspective>();\n *\n * const player = createActor({ name: 'player', ... });\n * const controller = player.use(FirstPersonBehavior, {\n * perspective: fps,\n * walkSpeed: 8,\n * runSpeed: 16,\n * lookSensitivity: 2,\n * });\n *\n * // In update loop - write input, behavior handles the rest\n * player.onUpdate(({ inputs }) => {\n * player.$fps.moveX = inputs.p1.axes.Horizontal.value;\n * player.$fps.moveZ = inputs.p1.axes.Vertical.value;\n * player.$fps.lookX = inputs.p1.axes.SecondaryHorizontal.value;\n * player.$fps.lookY = inputs.p1.axes.SecondaryVertical.value;\n * player.$fps.sprint = inputs.p1.shoulders.LTrigger.held > 0;\n * });\n * ```\n */\nexport const FirstPersonBehavior = defineBehavior<\n\tFirstPersonBehaviorOptions,\n\t{\n\t\tgetState: () => FirstPersonState;\n\t\tgetYaw: () => number;\n\t\tgetPitch: () => number;\n\t\tattachViewmodel: (entity: any, offset: Vec3Input) => void;\n\t},\n\tFirstPersonEntity\n>({\n\tname: 'first-person-controller',\n\tdefaultOptions,\n\tsystemFactory: (ctx) =>\n\t\tnew FirstPersonBehaviorSystem(ctx.wasmStage ?? null, ctx.getBehaviorLinks),\n\t// Handles read the runtime snapshot buffer (previous-step values). The\n\t// Rust behavior is the single source of truth.\n\tcreateHandle: (ref) => ({\n\t\tgetState: () => {\n\t\t\tconst snapshot = readBehaviorSnapshot(ref);\n\t\t\tif (!snapshot) return FirstPersonState.Idle;\n\t\t\tif (snapshot.speed <= 0.01) return FirstPersonState.Idle;\n\t\t\tconst walkSpeed = ref.options.walkSpeed ?? defaultOptions.walkSpeed!;\n\t\t\treturn snapshot.speed > walkSpeed\n\t\t\t\t? FirstPersonState.Running\n\t\t\t\t: FirstPersonState.Walking;\n\t\t},\n\t\tgetYaw: () => readBehaviorSnapshot(ref)?.yaw ?? 0,\n\t\tgetPitch: () => readBehaviorSnapshot(ref)?.pitch ?? 0,\n\t\tattachViewmodel: (entity: any, offset: Vec3Input) => {\n\t\t\tif (ref.options) {\n\t\t\t\tref.options.viewmodel = { entity, offset };\n\t\t\t}\n\t\t},\n\t}),\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAeO,IAAK,mBAAL,kBAAKA,sBAAL;AACN,EAAAA,kBAAA,UAAO;AACP,EAAAA,kBAAA,aAAU;AACV,EAAAA,kBAAA,aAAU;AAHC,SAAAA;AAAA,GAAA;AASL,IAAK,mBAAL,kBAAKC,sBAAL;AACN,EAAAA,kBAAA,UAAO;AACP,EAAAA,kBAAA,SAAM;AACN,EAAAA,kBAAA,UAAO;AAHI,SAAAA;AAAA,GAAA;AAiBL,IAAM,iBAAN,MAAqB;AAAA,EAG3B,YAAoB,KAAyB;AAAzB;AACnB,SAAK,UAAU,IAAI;AAAA,MAClB;AAAA,MACA;AAAA;AAAA,YAEC,yBAAE,mBAAuB,mBAAuB,uBAAwB;AAAA,YACxE,yBAAE,mBAAuB,iBAAsB,uBAAwB;AAAA,YACvE,yBAAE,mBAAuB,mBAAuB,iBAAqB;AAAA;AAAA,YAGrE,yBAAE,yBAA0B,iBAAsB,uBAAwB;AAAA,YAC1E,yBAAE,yBAA0B,mBAAuB,iBAAqB;AAAA,YACxE,yBAAE,yBAA0B,mBAAuB,uBAAwB;AAAA;AAAA,YAG3E,yBAAE,yBAA0B,mBAAuB,uBAAwB;AAAA,YAC3E,yBAAE,yBAA0B,mBAAuB,iBAAqB;AAAA,YACxE,yBAAE,yBAA0B,iBAAsB,uBAAwB;AAAA,MAC3E;AAAA,IACD;AAAA,EACD;AAAA,EApBoB;AAAA,EAFpB;AAAA;AAAA,EAyBA,WAA6B;AAC5B,WAAO,KAAK,QAAQ,SAAS;AAAA,EAC9B;AAAA;AAAA,EAGA,SAAS,OAA+B;AACvC,QAAI,KAAK,QAAQ,IAAI,KAAK,GAAG;AAC5B,WAAK,QAAQ,aAAa,KAAK;AAAA,IAChC;AAAA,EACD;AAAA;AAAA,EAGA,SAAiB;AAChB,WAAO,KAAK,IAAI,MAAM;AAAA,EACvB;AAAA;AAAA,EAGA,WAAmB;AAClB,WAAO,KAAK,IAAI,MAAM;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,OAAkC,OAAwC;AAChF,SAAK,IAAI,QAAQ;AACjB,SAAK,IAAI,QAAQ;AAEjB,UAAM,cAAc,KAAK,IAAI,MAAM,KAAK,IAAI,OAAO,KAAK,IAAI,MAAM,KAAK,IAAI;AAE3E,QAAI,aAAa;AAChB,UAAI,MAAM,QAAQ;AACjB,aAAK,SAAS,eAAoB;AAAA,MACnC,OAAO;AACN,aAAK,SAAS,iBAAqB;AAAA,MACpC;AAAA,IACD,OAAO;AACN,WAAK,SAAS,iBAAqB;AAAA,IACpC;AAAA,EACD;AACD;;;AC9FA,SAAS,SAAS,YAAY,aAAa;AAuC3C,IAAM,iBAAiB,IAAI,WAAW;AACtC,IAAM,sBAAsB,IAAI,WAAW;AAC3C,IAAM,kBAAkB,IAAI,MAAM;AAClC,IAAM,UAAU,IAAI,QAAQ;AAC5B,IAAM,QAAmB,EAAE,UAAU,CAAC,GAAG,GAAG,CAAC,GAAG,UAAU,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE;AACvE,IAAM,YAAY,CAAC;AAKZ,IAAM,0BAAN,MAA8B;AAAA,EAC5B,eAAe,oBAAI,IAAoC;AAAA,EACvD,aAAa,oBAAI,IAA6B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMtD,eAAe,YAAoB,aAA2C;AAC7E,SAAK,aAAa,IAAI,YAAY,WAAW;AAAA,EAC9C;AAAA,EAEA,eAAe,YAA6B;AAC3C,WAAO,KAAK,aAAa,IAAI,UAAU;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,YAAoB,QAA+B;AAC/D,SAAK,WAAW,IAAI,YAAY,MAAM;AAAA,EACvC;AAAA,EAEA,aAAa,YAA6B;AACzC,WAAO,KAAK,WAAW,IAAI,UAAU;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKA,WACC,YACA,SACA,QACA,UACA,OACO;AACP,UAAM,cAAc,KAAK,aAAa,IAAI,UAAU;AACpD,UAAM,OAAO,QAAQ,QAAQ,QAAQ,KAAK;AAC1C,UAAM,WAAW,QAAQ,aAAa,QAAQ,SAAS;AAEvD,QAAI,eAAe,UAAU;AAC5B,kBAAY,UAAU,SAAS,KAAK,SAAS,KAAK;AAClD,UAAI,OAAO;AACV,cAAM,MAAM,SAAS;AACrB,cAAM,QAAQ,SAAS;AACvB,cAAM,eAAe,SAAS;AAAA,MAC/B;AAAA,IACD;AAEA,QAAI,aAAa,mBAAmB,MAAM;AACzC,kBAAY,gBAAgB;AAAA,QAC3B,KAAK,SAAS,CAAC;AAAA,QACf,KAAK,SAAS,CAAC,IAAI,SAAS;AAAA,QAC5B,KAAK,SAAS,CAAC;AAAA,MAChB;AAAA,IACD;AAEA,UAAM,KAAK,KAAK,WAAW,IAAI,UAAU;AACzC,QAAI,MAAM,aAAa,mBAAmB,OAAO;AAChD,WAAK,kBAAkB,IAAI,aAAa,OAAO,OAAO;AAAA,IACvD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKQ,kBACP,IACA,aACA,OACA,SACO;AACP,UAAM,SAAS,YAAY;AAC3B,QAAI,CAAC,OAAQ;AAGb,mBAAe;AAAA,MACd,gBAAgB,IAAI,MAAM,OAAO,MAAM,KAAK,GAAG,KAAK;AAAA,IACrD;AAGA,QAAI,GAAG,UAAU;AAChB,0BAAoB,aAAa,GAAG,QAAQ;AAC5C,qBAAe,SAAS,mBAAmB;AAAA,IAC5C;AAGA,YAAQ,KAAK,GAAG,MAAM,EAAE,gBAAgB,cAAc;AAEtD,UAAM,KAAK,OAAO,IAAI,QAAQ;AAC9B,UAAM,KAAK,OAAO,IAAI,QAAQ;AAC9B,UAAM,KAAK,OAAO,IAAI,QAAQ;AAE9B,UAAM,SAAS,GAAG;AAGlB,UAAM,SAAU,QAAQ,iBAAiB;AACzC,QAAI,UAAU,GAAG;AAChB,cAAQ,YAAY,QAAQ,IAAI,IAAI,EAAE;AACtC,cAAQ;AAAA,QACP;AAAA,QACA,eAAe;AAAA,QAAG,eAAe;AAAA,QAAG,eAAe;AAAA,QAAG,eAAe;AAAA,MACtE;AAAA,IACD;AAGA,QAAI,QAAQ,OAAO;AAClB,aAAO,MAAM,SAAS,IAAI,IAAI,IAAI,EAAE;AACpC,aAAO,MAAM,WAAW,KAAK,cAAc;AAAA,IAC5C;AAAA,EACD;AAAA;AAAA,EAGA,UAAgB;AACf,SAAK,aAAa,MAAM;AACxB,SAAK,WAAW,MAAM;AAAA,EACvB;AACD;;;ACtIA,IAAM,iBAA6C;AAAA,EAClD,WAAW;AAAA,EACX,UAAU;AAAA,EACV,iBAAiB;AAAA,EACjB,WAAW;AACZ;AAEA,IAAM,4BAA4B,uBAAO;AAAA,EACxC;AACD;AAOA,IAAM,4BAAN,MAA0D;AAAA,EAIzD,YACS,WACA,kBACP;AAFO;AACA;AAAA,EACN;AAAA,EAFM;AAAA,EACA;AAAA,EALD,eAAe,IAAI,wBAAwB;AAAA,EAC3C,uBAAuB,oBAAI,IAAY;AAAA,EAO/C,OAAO,MAAe,QAAsB;AAC3C,UAAM,QAAQ,KAAK,mBAAmB,yBAAyB;AAC/D,QAAI,CAAC,MAAO;AAEZ,eAAW,QAAQ,OAAO;AACzB,YAAM,aAAa,KAAK;AACxB,YAAM,SAAS,KAAK;AAEpB,YAAM,UAAU,OAAO;AAGvB,UAAI,CAAC,WAAW,aAAa;AAC5B,mBAAW,cAAc,mCAAmC,OAAO;AAAA,MACpE;AACA,UAAI,CAAC,WAAW,MAAM;AACrB,mBAAW,OAAO,gCAAgC;AAAA,MACnD;AACA,UAAI,CAAC,WAAW,kBAAkB;AACjC,mBAAW,mBAAmB,gCAAgC;AAAA,MAC/D;AAGA,UAAI,QAAQ,eAAe,CAAC,KAAK,aAAa,eAAe,WAAW,IAAI,GAAG;AAC9E,aAAK,aAAa,eAAe,WAAW,MAAM,QAAQ,WAAW;AAAA,MACtE;AAGA,UAAI,QAAQ,aAAa,CAAC,KAAK,aAAa,aAAa,WAAW,IAAI,GAAG;AAC1E,aAAK,aAAa,aAAa,WAAW,MAAM;AAAA,UAC/C,GAAG,QAAQ;AAAA,UACX,QAAQ,eAAe,QAAQ,UAAU,QAAQ,SAAS;AAAA,QAC3D,CAAoB;AAAA,MACrB;AAEA,YAAM,SAAU,WAAW,iBAAiB;AAC5C,UAAI,CAAC,KAAK,aAAa,SAAS,EAAG;AAEnC,WAAK,mBAAmB,QAAQ,OAAO;AACvC,aAAO,cAAc,KAAK;AAC1B,aAAO,WAAW;AAClB,YAAM,QAAQ,WAAW;AACzB,UAAI,OAAO;AACV,aAAK,UAAU,eAAe,QAAQ,MAAM,SAAS,GAAG,MAAM,SAAS,CAAC;AACxE,aAAK,UAAU,eAAe,QAAQ,MAAM,SAAS,GAAG,MAAM,SAAS,CAAC;AACxE,aAAK,UAAU,iBAAiB,QAAQ,wBAAwB,CAAC,CAAC,MAAM,MAAM;AAAA,MAC/E;AAEA,WAAK,aAAa;AAAA,QACjB,WAAW;AAAA,QACX,KAAK;AAAA,QACL;AAAA,QACA,WAAW;AAAA,QACX,WAAW;AAAA,MACZ;AAAA,IACD;AAAA,EACD;AAAA,EAEQ,mBAAmB,QAAgB,SAA2C;AACrF,QAAI,CAAC,KAAK,aAAa,KAAK,qBAAqB,IAAI,MAAM,EAAG;AAC9D,SAAK,UAAU,kBAAkB,QAAQ;AAAA,MACxC,WAAW,QAAQ,aAAa,eAAe;AAAA,MAC/C,UAAU,QAAQ,YAAY,eAAe;AAAA,MAC7C,WAAW,QAAQ,aAAa,eAAe;AAAA,MAC/C,iBAAiB,QAAQ,mBAAmB,eAAe;AAAA,IAC5D,CAAC;AACD,SAAK,qBAAqB,IAAI,MAAM;AAAA,EACrC;AAAA,EAEA,QAAQ,MAAqB;AAC5B,SAAK,aAAa,QAAQ;AAC1B,SAAK,qBAAqB,MAAM;AAAA,EACjC;AACD;AAsCO,IAAM,sBAAsB,eASjC;AAAA,EACD,MAAM;AAAA,EACN;AAAA,EACA,eAAe,CAAC,QACf,IAAI,0BAA0B,IAAI,aAAa,MAAM,IAAI,gBAAgB;AAAA;AAAA;AAAA,EAG1E,cAAc,CAAC,SAAS;AAAA,IACvB,UAAU,MAAM;AACf,YAAM,WAAW,qBAAqB,GAAG;AACzC,UAAI,CAAC,SAAU;AACf,UAAI,SAAS,SAAS,KAAM;AAC5B,YAAM,YAAY,IAAI,QAAQ,aAAa,eAAe;AAC1D,aAAO,SAAS,QAAQ;AAAA,IAGzB;AAAA,IACA,QAAQ,MAAM,qBAAqB,GAAG,GAAG,OAAO;AAAA,IAChD,UAAU,MAAM,qBAAqB,GAAG,GAAG,SAAS;AAAA,IACpD,iBAAiB,CAAC,QAAa,WAAsB;AACpD,UAAI,IAAI,SAAS;AAChB,YAAI,QAAQ,YAAY,EAAE,QAAQ,OAAO;AAAA,MAC1C;AAAA,IACD;AAAA,EACD;AACD,CAAC;","names":["FirstPersonState","FirstPersonEvent"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/coordinators/first-person-shooter.coordinator.ts"],"sourcesContent":["import {\n\tcreateFirstPersonInputComponent,\n\ttype FirstPersonInputComponent,\n} from '../behaviors/first-person/components';\nimport {\n\tcreateJumpInput3D,\n\ttype JumpInput3D,\n} from '../behaviors/jumper-3d/components';\n\nexport interface FirstPersonShooterInput {\n\tmoveX: number;\n\tmoveZ: number;\n\tlookX: number;\n\tlookY: number;\n\tsprint: boolean;\n\tjumpPressed: boolean;\n\tjumpHeld: boolean;\n\tjumpReleased: boolean;\n\tfastFall?: boolean;\n}\n\ninterface FirstPersonShooterControllerHandle {\n\tgetYaw(): number;\n}\n\nexport type FirstPersonShooterEntity = {\n\t$fps?: FirstPersonInputComponent;\n\t$jumper?: JumpInput3D;\n};\n\n/**\n * Coordinator that fans a single input snapshot out to the first-person\n * behavior (`$fps`) and the Jumper3D behavior (`$jumper`), converting local\n * move axes into the camera-relative world direction the jumper uses for\n * air control.\n */\nexport class FirstPersonShooterCoordinator {\n\tconstructor(\n\t\tprivate entity: FirstPersonShooterEntity,\n\t\tprivate fpsController: FirstPersonShooterControllerHandle,\n\t) {}\n\n\tpublic update(input: FirstPersonShooterInput): void {\n\t\tif (!this.entity.$fps) {\n\t\t\tthis.entity.$fps = createFirstPersonInputComponent();\n\t\t}\n\t\tif (!this.entity.$jumper) {\n\t\t\tthis.entity.$jumper = createJumpInput3D();\n\t\t}\n\n\t\tconst fpsInput = this.entity.$fps;\n\t\tfpsInput.moveX = input.moveX;\n\t\tfpsInput.moveZ = input.moveZ;\n\t\tfpsInput.lookX = input.lookX;\n\t\tfpsInput.lookY = input.lookY;\n\t\tfpsInput.sprint = input.sprint;\n\n\t\tconst jumperInput = this.entity.$jumper;\n\t\tjumperInput.jumpPressed = input.jumpPressed;\n\t\tjumperInput.jumpHeld = input.jumpHeld;\n\t\tjumperInput.jumpReleased = input.jumpReleased;\n\t\tjumperInput.fastFall = input.fastFall ?? false;\n\t\tjumperInput.moveDirWorld = this.getMoveDirWorld(\n\t\t\tinput.moveX,\n\t\t\tinput.moveZ,\n\t\t\tthis.fpsController.getYaw(),\n\t\t);\n\t}\n\n\tprivate getMoveDirWorld(\n\t\tmoveX: number,\n\t\tmoveZ: number,\n\t\tyaw: number,\n\t): { x: number; y: number; z: number } | undefined {\n\t\tconst sinYaw = Math.sin(yaw);\n\t\tconst cosYaw = Math.cos(yaw);\n\t\tconst rightX = cosYaw;\n\t\tconst rightZ = -sinYaw;\n\t\tconst forwardX = -sinYaw;\n\t\tconst forwardZ = -cosYaw;\n\t\tconst worldX = rightX * moveX + forwardX * -moveZ;\n\t\tconst worldZ = rightZ * moveX + forwardZ * -moveZ;\n\t\tconst length = Math.hypot(worldX, worldZ);\n\t\tif (length <= 1e-6) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn {\n\t\t\tx: worldX / length,\n\t\t\ty: 0,\n\t\t\tz: worldZ / length,\n\t\t};\n\t}\n}\n"],"mappings":";;;;;;;;AAoCO,IAAM,gCAAN,MAAoC;AAAA,EAC1C,YACS,QACA,eACP;AAFO;AACA;AAAA,EACN;AAAA,EAFM;AAAA,EACA;AAAA,EAGF,OAAO,OAAsC;AACnD,QAAI,CAAC,KAAK,OAAO,MAAM;AACtB,WAAK,OAAO,OAAO,gCAAgC;AAAA,IACpD;AACA,QAAI,CAAC,KAAK,OAAO,SAAS;AACzB,WAAK,OAAO,UAAU,kBAAkB;AAAA,IACzC;AAEA,UAAM,WAAW,KAAK,OAAO;AAC7B,aAAS,QAAQ,MAAM;AACvB,aAAS,QAAQ,MAAM;AACvB,aAAS,QAAQ,MAAM;AACvB,aAAS,QAAQ,MAAM;AACvB,aAAS,SAAS,MAAM;AAExB,UAAM,cAAc,KAAK,OAAO;AAChC,gBAAY,cAAc,MAAM;AAChC,gBAAY,WAAW,MAAM;AAC7B,gBAAY,eAAe,MAAM;AACjC,gBAAY,WAAW,MAAM,YAAY;AACzC,gBAAY,eAAe,KAAK;AAAA,MAC/B,MAAM;AAAA,MACN,MAAM;AAAA,MACN,KAAK,cAAc,OAAO;AAAA,IAC3B;AAAA,EACD;AAAA,EAEQ,gBACP,OACA,OACA,KACkD;AAClD,UAAM,SAAS,KAAK,IAAI,GAAG;AAC3B,UAAM,SAAS,KAAK,IAAI,GAAG;AAC3B,UAAM,SAAS;AACf,UAAM,SAAS,CAAC;AAChB,UAAM,WAAW,CAAC;AAClB,UAAM,WAAW,CAAC;AAClB,UAAM,SAAS,SAAS,QAAQ,WAAW,CAAC;AAC5C,UAAM,SAAS,SAAS,QAAQ,WAAW,CAAC;AAC5C,UAAM,SAAS,KAAK,MAAM,QAAQ,MAAM;AACxC,QAAI,UAAU,MAAM;AACnB,aAAO;AAAA,IACR;AAEA,WAAO;AAAA,MACN,GAAG,SAAS;AAAA,MACZ,GAAG;AAAA,MACH,GAAG,SAAS;AAAA,IACb;AAAA,EACD;AACD;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/destructible-prebake/source-geometry.ts","../src/lib/destructible-prebake/cache-key.ts","../src/lib/destructible-prebake/payload.ts"],"sourcesContent":["/**\n * Normalizes source mesh geometry for Voronoi prebake / fracture so runtime and\n * CLI tooling share one code path (float attributes, non-indexed, root-relative transform).\n */\n\nimport {\n\tBufferAttribute,\n\tBufferGeometry,\n\tMatrix4,\n\ttype Group,\n\ttype Mesh,\n} from 'three';\n\ntype ReadableGeometryAttribute = Pick<\n\tBufferAttribute,\n\t'count' | 'itemSize' | 'getComponent'\n>;\n\nfunction cloneAttributeAsFloat32(\n\tattribute: ReadableGeometryAttribute,\n): BufferAttribute {\n\tconst values = new Float32Array(attribute.count * attribute.itemSize);\n\tlet offset = 0;\n\tfor (let index = 0; index < attribute.count; index += 1) {\n\t\tfor (let component = 0; component < attribute.itemSize; component += 1) {\n\t\t\tvalues[offset] = attribute.getComponent(index, component);\n\t\t\toffset += 1;\n\t\t}\n\t}\n\n\treturn new BufferAttribute(values, attribute.itemSize);\n}\n\n/**\n * Clones geometry with float32 attributes and expands indexed meshes to non-indexed.\n */\nexport function normalizeFractureSourceGeometry(\n\tsourceGeometry: BufferGeometry,\n): BufferGeometry {\n\tconst geometry = sourceGeometry.clone();\n\tfor (const [name, attribute] of Object.entries(geometry.attributes)) {\n\t\tgeometry.setAttribute(name, cloneAttributeAsFloat32(attribute));\n\t}\n\n\tconst index = geometry.getIndex();\n\tif (!index) {\n\t\treturn geometry;\n\t}\n\n\tconst indices = new Uint32Array(index.count);\n\tfor (let cursor = 0; cursor < index.count; cursor += 1) {\n\t\tindices[cursor] = index.getX(cursor);\n\t}\n\n\tgeometry.setIndex(new BufferAttribute(indices, 1));\n\treturn geometry.toNonIndexed();\n}\n\n/**\n * Produces fracture-space geometry: normalized mesh vertices in root-local space.\n */\nexport function buildNormalizedFractureSourceGeometry(\n\tmesh: Mesh,\n\troot: Group,\n): BufferGeometry {\n\tconst geometry = normalizeFractureSourceGeometry(mesh.geometry);\n\troot.updateMatrixWorld(true);\n\tmesh.updateMatrixWorld(true);\n\n\tconst relativeMatrix = new Matrix4()\n\t\t.copy(root.matrixWorld)\n\t\t.invert()\n\t\t.multiply(mesh.matrixWorld);\n\n\tgeometry.applyMatrix4(relativeMatrix);\n\tgeometry.computeBoundingBox();\n\tgeometry.computeBoundingSphere();\n\treturn geometry;\n}\n","/**\n * Stable JSON key for matching prebaked fragment templates to fracture options.\n */\n\nimport type { FractureOptions as PinataFractureOptions } from '@dgreenheck/three-pinata';\nimport { Vector2, Vector3 } from 'three';\n\nfunction vector2ToTuple(value?: Vector2): [number, number] | null {\n\tif (!value) {\n\t\treturn null;\n\t}\n\n\treturn [value.x, value.y];\n}\n\nfunction vector3ToTuple(value?: Vector3): [number, number, number] | null {\n\tif (!value) {\n\t\treturn null;\n\t}\n\n\treturn [value.x, value.y, value.z];\n}\n\n/**\n * Serializes fracture options for prebake cache identity (mesh not included).\n */\nexport function buildFractureGeometryCacheKey(\n\toptions: PinataFractureOptions,\n): string {\n\treturn JSON.stringify({\n\t\tfractureMethod: options.fractureMethod,\n\t\tfragmentCount: options.fragmentCount,\n\t\tfracturePlanes: {\n\t\t\tx: options.fracturePlanes?.x ?? true,\n\t\t\ty: options.fracturePlanes?.y ?? true,\n\t\t\tz: options.fracturePlanes?.z ?? true,\n\t\t},\n\t\ttextureScale: vector2ToTuple(options.textureScale),\n\t\ttextureOffset: vector2ToTuple(options.textureOffset),\n\t\tseed: options.seed ?? null,\n\t\tvoronoiOptions: options.voronoiOptions\n\t\t\t? {\n\t\t\t\tmode: options.voronoiOptions.mode,\n\t\t\t\tseedPoints:\n\t\t\t\t\toptions.voronoiOptions.seedPoints?.map((point) => vector3ToTuple(point)),\n\t\t\t\tprojectionAxis: options.voronoiOptions.projectionAxis ?? null,\n\t\t\t\tprojectionNormal: vector3ToTuple(options.voronoiOptions.projectionNormal),\n\t\t\t\tuseApproximation: options.voronoiOptions.useApproximation ?? false,\n\t\t\t\tapproximationNeighborCount:\n\t\t\t\t\toptions.voronoiOptions.approximationNeighborCount ?? 12,\n\t\t\t}\n\t\t\t: null,\n\t});\n}\n","/**\n * Serializable payloads for destructible Voronoi prebake in a Web Worker.\n */\n\nimport { FractureOptions, type DestructibleMesh } from '@dgreenheck/three-pinata';\nimport {\n\tBufferAttribute,\n\tBufferGeometry,\n\tQuaternion,\n\tVector2,\n\tVector3,\n} from 'three';\n\nexport interface PlainBufferGeometryPayload {\n\tattributes: Record<\n\t\tstring,\n\t\t{\n\t\t\tarray: ArrayBuffer;\n\t\t\titemSize: number;\n\t\t\tnormalized?: boolean;\n\t\t}\n\t>;\n}\n\nexport type PlainFractureOptions = {\n\tfractureMethod: 'voronoi' | 'simple';\n\tfragmentCount: number;\n\tfracturePlanes: { x: boolean; y: boolean; z: boolean };\n\ttextureScale: [number, number];\n\ttextureOffset: [number, number];\n\tseed?: number;\n\tvoronoiOptions?: {\n\t\tmode: '3D' | '2.5D';\n\t\tseedPoints?: [number, number, number][];\n\t\timpactPoint?: [number, number, number];\n\t\timpactRadius?: number;\n\t\tprojectionAxis?: 'x' | 'y' | 'z' | 'auto' | null;\n\t\tprojectionNormal?: [number, number, number];\n\t\tuseApproximation: boolean;\n\t\tapproximationNeighborCount: number;\n\t};\n};\n\nexport type PlainWorkerFragmentPayload = {\n\tattributes: PlainBufferGeometryPayload['attributes'];\n\tposition: [number, number, number];\n\tquaternion: [number, number, number, number];\n\tscale: [number, number, number];\n};\n\nexport type PrebakeWorkerRequest = {\n\tgeometry: PlainBufferGeometryPayload;\n\toptions: PlainFractureOptions;\n};\n\nexport type PrebakeWorkerResponse = {\n\tfragments: PlainWorkerFragmentPayload[];\n};\n\nexport interface DestructiblePrebakeWorkerAPI {\n\tprebake(request: PrebakeWorkerRequest): Promise<PrebakeWorkerResponse>;\n}\n\n/**\n * Copies a buffer geometry into detached ArrayBuffers suitable for postMessage transfer.\n */\nexport function bufferGeometryToPlain(geometry: BufferGeometry): {\n\tpayload: PlainBufferGeometryPayload;\n\ttransferables: ArrayBuffer[];\n} {\n\tconst attributes: PlainBufferGeometryPayload['attributes'] = {};\n\tconst transferables: ArrayBuffer[] = [];\n\n\tfor (const name of Object.keys(geometry.attributes)) {\n\t\tconst attr = geometry.getAttribute(name);\n\t\tif (!attr || !(attr instanceof BufferAttribute)) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst view = attr.array as ArrayBufferView;\n\t\tconst buffer = view.buffer.slice(\n\t\t\tview.byteOffset,\n\t\t\tview.byteOffset + view.byteLength,\n\t\t);\n\t\ttransferables.push(buffer);\n\t\tattributes[name] = {\n\t\t\tarray: buffer,\n\t\t\titemSize: attr.itemSize,\n\t\t\tnormalized: attr.normalized,\n\t\t};\n\t}\n\n\treturn { payload: { attributes }, transferables };\n}\n\n/**\n * Rebuilds a BufferGeometry from a plain payload (e.g. in a worker).\n */\nexport function plainToBufferGeometry(\n\tpayload: PlainBufferGeometryPayload,\n): BufferGeometry {\n\tconst geometry = new BufferGeometry();\n\n\tfor (const [name, spec] of Object.entries(payload.attributes)) {\n\t\tconst array = new Float32Array(spec.array);\n\t\tgeometry.setAttribute(\n\t\t\tname,\n\t\t\tnew BufferAttribute(array, spec.itemSize, spec.normalized),\n\t\t);\n\t}\n\n\treturn geometry;\n}\n\n/**\n * Serializes {@link FractureOptions} for structured clone / worker transfer.\n */\nexport function pinataFractureOptionsToPlain(\n\toptions: FractureOptions,\n): PlainFractureOptions {\n\tconst voronoi = options.voronoiOptions;\n\treturn {\n\t\tfractureMethod: options.fractureMethod,\n\t\tfragmentCount: options.fragmentCount,\n\t\tfracturePlanes: {\n\t\t\tx: options.fracturePlanes.x,\n\t\t\ty: options.fracturePlanes.y,\n\t\t\tz: options.fracturePlanes.z,\n\t\t},\n\t\ttextureScale: [options.textureScale.x, options.textureScale.y],\n\t\ttextureOffset: [options.textureOffset.x, options.textureOffset.y],\n\t\tseed: options.seed,\n\t\tvoronoiOptions: voronoi\n\t\t\t? {\n\t\t\t\tmode: voronoi.mode,\n\t\t\t\tseedPoints: voronoi.seedPoints?.map((p) => [p.x, p.y, p.z]),\n\t\t\t\timpactPoint: voronoi.impactPoint\n\t\t\t\t\t? [voronoi.impactPoint.x, voronoi.impactPoint.y, voronoi.impactPoint.z]\n\t\t\t\t\t: undefined,\n\t\t\t\timpactRadius: voronoi.impactRadius,\n\t\t\t\tprojectionAxis: voronoi.projectionAxis ?? null,\n\t\t\t\tprojectionNormal: voronoi.projectionNormal\n\t\t\t\t\t? [\n\t\t\t\t\t\tvoronoi.projectionNormal.x,\n\t\t\t\t\t\tvoronoi.projectionNormal.y,\n\t\t\t\t\t\tvoronoi.projectionNormal.z,\n\t\t\t\t\t]\n\t\t\t\t\t: undefined,\n\t\t\t\tuseApproximation: voronoi.useApproximation ?? false,\n\t\t\t\tapproximationNeighborCount:\n\t\t\t\t\tvoronoi.approximationNeighborCount ?? 12,\n\t\t\t}\n\t\t\t: undefined,\n\t};\n}\n\n/**\n * Reconstructs {@link FractureOptions} from a plain payload.\n */\nexport function plainFractureOptionsToPinata(\n\tplain: PlainFractureOptions,\n): FractureOptions {\n\treturn new FractureOptions({\n\t\tfractureMethod: plain.fractureMethod,\n\t\tfragmentCount: plain.fragmentCount,\n\t\tfracturePlanes: plain.fracturePlanes,\n\t\ttextureScale: new Vector2(plain.textureScale[0], plain.textureScale[1]),\n\t\ttextureOffset: new Vector2(plain.textureOffset[0], plain.textureOffset[1]),\n\t\tseed: plain.seed,\n\t\tvoronoiOptions: plain.voronoiOptions\n\t\t\t? {\n\t\t\t\tmode: plain.voronoiOptions.mode,\n\t\t\t\tseedPoints: plain.voronoiOptions.seedPoints?.map(\n\t\t\t\t\t([x, y, z]) => new Vector3(x, y, z),\n\t\t\t\t),\n\t\t\t\timpactPoint: plain.voronoiOptions.impactPoint\n\t\t\t\t\t? new Vector3(\n\t\t\t\t\t\tplain.voronoiOptions.impactPoint[0],\n\t\t\t\t\t\tplain.voronoiOptions.impactPoint[1],\n\t\t\t\t\t\tplain.voronoiOptions.impactPoint[2],\n\t\t\t\t\t)\n\t\t\t\t\t: undefined,\n\t\t\t\timpactRadius: plain.voronoiOptions.impactRadius,\n\t\t\t\tprojectionAxis:\n\t\t\t\t\tplain.voronoiOptions.projectionAxis === null\n\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t: plain.voronoiOptions.projectionAxis ?? undefined,\n\t\t\t\tprojectionNormal: plain.voronoiOptions.projectionNormal\n\t\t\t\t\t? new Vector3(\n\t\t\t\t\t\tplain.voronoiOptions.projectionNormal[0],\n\t\t\t\t\t\tplain.voronoiOptions.projectionNormal[1],\n\t\t\t\t\t\tplain.voronoiOptions.projectionNormal[2],\n\t\t\t\t\t)\n\t\t\t\t\t: undefined,\n\t\t\t\tuseApproximation: plain.voronoiOptions.useApproximation,\n\t\t\t\tapproximationNeighborCount:\n\t\t\t\t\tplain.voronoiOptions.approximationNeighborCount,\n\t\t\t}\n\t\t\t: undefined,\n\t});\n}\n\n/**\n * Converts worker response fragments into template parts for the main-thread cache.\n */\nexport function plainWorkerResultToTemplateParts(response: PrebakeWorkerResponse): Array<{\n\tgeometry: BufferGeometry;\n\tposition: Vector3;\n\tquaternion: Quaternion;\n\tscale: Vector3;\n}> {\n\treturn response.fragments.map((fragment) => {\n\t\tconst geometry = plainToBufferGeometry({ attributes: fragment.attributes });\n\t\tgeometry.computeBoundingBox();\n\t\tgeometry.computeBoundingSphere();\n\t\treturn {\n\t\t\tgeometry,\n\t\t\tposition: new Vector3(\n\t\t\t\tfragment.position[0],\n\t\t\t\tfragment.position[1],\n\t\t\t\tfragment.position[2],\n\t\t\t),\n\t\t\tquaternion: new Quaternion(\n\t\t\t\tfragment.quaternion[0],\n\t\t\t\tfragment.quaternion[1],\n\t\t\t\tfragment.quaternion[2],\n\t\t\t\tfragment.quaternion[3],\n\t\t\t),\n\t\t\tscale: new Vector3(\n\t\t\t\tfragment.scale[0],\n\t\t\t\tfragment.scale[1],\n\t\t\t\tfragment.scale[2],\n\t\t\t),\n\t\t};\n\t});\n}\n\n/**\n * Serializes fracture fragments for Comlink.transfer (used in the worker).\n */\nexport function destructibleFragmentsToPlainResponse(\n\tfragments: readonly DestructibleMesh[],\n): {\n\tresponse: PrebakeWorkerResponse;\n\ttransferables: ArrayBuffer[];\n} {\n\tconst out: PlainWorkerFragmentPayload[] = [];\n\tconst transferables: ArrayBuffer[] = [];\n\n\tfor (const fragment of fragments) {\n\t\tconst { payload, transferables: geoTransfer } = bufferGeometryToPlain(\n\t\t\tfragment.geometry,\n\t\t);\n\t\tfor (const buffer of geoTransfer) {\n\t\t\ttransferables.push(buffer);\n\t\t}\n\t\tout.push({\n\t\t\tattributes: payload.attributes,\n\t\t\tposition: [fragment.position.x, fragment.position.y, fragment.position.z],\n\t\t\tquaternion: [\n\t\t\t\tfragment.quaternion.x,\n\t\t\t\tfragment.quaternion.y,\n\t\t\t\tfragment.quaternion.z,\n\t\t\t\tfragment.quaternion.w,\n\t\t\t],\n\t\t\tscale: [fragment.scale.x, fragment.scale.y, fragment.scale.z],\n\t\t});\n\t\tfragment.geometry.dispose();\n\t}\n\n\treturn { response: { fragments: out }, transferables };\n}\n"],"mappings":"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","names":["BufferAttribute","BufferGeometry"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/behaviors/thruster/components.ts"],"sourcesContent":["/**\n * Thruster-specific ECS Components\n * \n * These components are specific to the thruster movement system.\n */\n\n// ─────────────────────────────────────────────────────────────────────────────\n// ThrusterMovementComponent (capability / hardware spec)\n// Defines the thrust capabilities of an entity\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface ThrusterMovementComponent {\n\t/** Linear thrust force in Newtons (or scaled units) */\n\tlinearThrust: number;\n\t/** Angular thrust torque scalar */\n\tangularThrust: number;\n\t/** Optional linear damping override */\n\tlinearDamping?: number;\n\t/** Optional angular damping override */\n\tangularDamping?: number;\n}\n\nexport function createThrusterMovementComponent(\n\tlinearThrust: number,\n\tangularThrust: number,\n\toptions?: { linearDamping?: number; angularDamping?: number }\n): ThrusterMovementComponent {\n\treturn {\n\t\tlinearThrust,\n\t\tangularThrust,\n\t\tlinearDamping: options?.linearDamping,\n\t\tangularDamping: options?.angularDamping,\n\t};\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// ThrusterInputComponent (intent)\n// Written by: Player controller, AI controller, FSM adapter\n// Read by: ThrusterSystem\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface ThrusterInputComponent {\n\t/** Forward thrust intent: 0..1 */\n\tthrust: number;\n\t/** Rotation intent: -1..1 */\n\trotate: number;\n\t/** World-space X thrust intent: -1..1 */\n\tthrustX: number;\n\t/** World-space Y thrust intent: -1..1 */\n\tthrustY: number;\n}\n\nexport function createThrusterInputComponent(): ThrusterInputComponent {\n\treturn {\n\t\tthrust: 0,\n\t\trotate: 0,\n\t\tthrustX: 0,\n\t\tthrustY: 0,\n\t};\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// ThrusterStateComponent (optional but useful)\n// Useful for: damage, EMP, overheating, UI feedback\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface ThrusterStateComponent {\n\t/** Whether the thruster is enabled */\n\tenabled: boolean;\n\t/** Current thrust after FSM/gating */\n\tcurrentThrust: number;\n}\n\nexport function createThrusterStateComponent(): ThrusterStateComponent {\n\treturn {\n\t\tenabled: true,\n\t\tcurrentThrust: 0,\n\t};\n}\n"],"mappings":";AAsBO,SAAS,gCACf,cACA,eACA,SAC4B;AAC5B,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA,eAAe,SAAS;AAAA,IACxB,gBAAgB,SAAS;AAAA,EAC1B;AACD;AAmBO,SAAS,+BAAuD;AACtE,SAAO;AAAA,IACN,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,SAAS;AAAA,EACV;AACD;AAcO,SAAS,+BAAuD;AACtE,SAAO;AAAA,IACN,SAAS;AAAA,IACT,eAAe;AAAA,EAChB;AACD;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/behaviors/destructible-3d/destructible-3d.descriptor.ts","../src/lib/behaviors/destructible-3d/index.ts"],"sourcesContent":["import {\n\tDestructibleMesh,\n\tFractureOptions as PinataFractureOptions,\n} from '@dgreenheck/three-pinata';\nimport {\n\tBox3,\n\tBufferAttribute,\n\tBufferGeometry,\n\tGroup,\n\tMatrix4,\n\tQuaternion,\n\tVector2,\n\tVector3,\n\ttype Material,\n\ttype Mesh,\n\ttype Object3D,\n} from 'three';\n\nimport * as Comlink from 'comlink';\n\nimport { defineBehavior, type BehaviorRef } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport type { CreateEntityFn, GameEntity } from '../../entities/entity';\n\nimport {\n\tbuildFractureGeometryCacheKey,\n\tbuildNormalizedFractureSourceGeometry,\n\tbufferGeometryToPlain,\n\ttype DestructiblePrebakeWorkerAPI,\n\tpinataFractureOptionsToPlain,\n\tplainWorkerResultToTemplateParts,\n} from '../../destructible-prebake';\n\nexport type FractureOptionsInput =\n\tNonNullable<ConstructorParameters<typeof PinataFractureOptions>[0]>;\n\nexport type Destructible3DFragmentColliderShape =\n\t| 'convexHull'\n\t| 'cuboid'\n\t| 'trimesh';\n\nexport interface Destructible3DColliderOptions {\n\tshape?: Destructible3DFragmentColliderShape;\n\tsensor?: boolean;\n\tcollisionGroups?: number;\n}\n\n/**\n * Plain-data collider definition produced for fracture fragments. The host\n * (game-lib) translates these into simulation colliders when it attaches\n * fragment entities to the WASM stage.\n */\nexport interface Destructible3DFragmentColliderDefinition {\n\tshape:\n\t\t| { type: 'convexHull'; vertices: Float32Array }\n\t\t| { type: 'trimesh'; vertices: Float32Array; indices: Uint32Array }\n\t\t| { type: 'box'; halfExtents: [number, number, number] };\n\toffset?: [number, number, number];\n\tsensor: boolean;\n\tcollisionGroups?: number;\n}\n\n/** Plain-data body definition produced for independent fracture fragments. */\nexport interface Destructible3DFragmentBodyDefinition {\n\tkind: 'dynamic';\n\tposition: [number, number, number];\n\trotation: [number, number, number, number];\n\tcanSleep: boolean;\n\tccdEnabled: boolean;\n}\n\nexport interface Destructible3DFragmentPhysicsOptions {\n\tmode?: 'compound' | 'independent';\n\tinheritSourceVelocity?: boolean;\n\toutwardVelocity?: number;\n\tangularVelocity?: number;\n}\n\nexport interface Destructible3DBehaviorOptions {\n\tfractureOptions?: FractureOptionsInput | PinataFractureOptions;\n\tinnerMaterial?: Material | null;\n\tcollider?: Destructible3DColliderOptions;\n\tfragmentPhysics?: Destructible3DFragmentPhysicsOptions;\n\t/**\n\t * When set, {@link Destructible3DHandle.prebakeAsync} runs Voronoi fracture\n\t * in a Web Worker (see `destructible-prebake-worker` bundle).\n\t */\n\tprebakeWorkerUrl?: URL | string;\n}\n\nexport interface Destructible3DHandle {\n\tfracture(\n\t\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n\t): readonly DestructibleMesh[];\n\tprebake(\n\t\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n\t): void;\n\tprebakeAsync(\n\t\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n\t): Promise<void>;\n\trepair(): void;\n\tisFractured(): boolean;\n\tgetFragments(): readonly DestructibleMesh[];\n}\n\ninterface PrebakedFragmentTemplate {\n\tgeometry: BufferGeometry;\n\tposition: Vector3;\n\tquaternion: Quaternion;\n\tscale: Vector3;\n}\n\ninterface RuntimeState {\n\tfragmentContainer: Group | null;\n\tfragmentEntities: GameEntity<any>[];\n\tfragments: DestructibleMesh[];\n\tprebakedFragments: PrebakedFragmentTemplate[];\n\tprebakedFractureKey: string | null;\n\tcreatedRootGroup: boolean;\n\tfractureMode: 'compound' | 'independent' | null;\n\tisFractured: boolean;\n\toriginalMeshParent: Object3D | null;\n\toriginalColliderDesc: unknown | undefined;\n\toriginalColliderDescs: unknown[];\n\toriginalMeshVisible: boolean;\n\toriginalGroupVisible: boolean;\n\tsourceBodySnapshot: PhysicsSnapshot | null;\n\tsourcePhysicsAttached: boolean;\n}\n\ninterface PhysicsSnapshot {\n\ttranslation: { x: number; y: number; z: number };\n\trotation: { x: number; y: number; z: number; w: number };\n\tlinearVelocity: { x: number; y: number; z: number };\n\tangularVelocity: { x: number; y: number; z: number };\n}\n\n/**\n * Structural view of the host-attached physics body. The host materializes\n * bodies in the WASM simulation and may expose this shape on entities for\n * velocity/pose access; no Rapier types are involved.\n */\ninterface PhysicsBodyLike {\n\ttranslation(): { x: number; y: number; z: number };\n\trotation(): { x: number; y: number; z: number; w: number };\n\tlinvel(): { x: number; y: number; z: number };\n\tangvel(): { x: number; y: number; z: number };\n\tsetTranslation(value: { x: number; y: number; z: number }, wakeUp?: boolean): void;\n\tsetRotation(value: { x: number; y: number; z: number; w: number }, wakeUp?: boolean): void;\n\tsetLinvel(value: { x: number; y: number; z: number }, wakeUp?: boolean): void;\n\tsetAngvel(value: { x: number; y: number; z: number }, wakeUp?: boolean): void;\n}\n\nfunction getBodyLike(entity: GameEntity<any>): PhysicsBodyLike | null {\n\treturn (entity.body as PhysicsBodyLike | null | undefined) ?? null;\n}\n\ntype BehaviorWorld = {\n\tinterpolationAlpha?: number;\n\tdestroyEntity(entity: GameEntity<any>): void;\n\taddEntity(entity: GameEntity<any>): void;\n};\n\ntype BehaviorScene = {\n\tscene: {\n\t\tadd(object: Object3D): void;\n\t\tremove(object: Object3D): void;\n\t};\n};\n\nconst DESTRUCTIBLE_3D_BEHAVIOR_KEY = Symbol.for(\n\t'zylem:behavior:destructible-3d',\n);\n\nconst DEFAULT_FRACTURE_OPTIONS: FractureOptionsInput = {\n\tfractureMethod: 'voronoi',\n\tfragmentCount: 12,\n\tvoronoiOptions: {\n\t\tmode: '3D',\n\t},\n\tfracturePlanes: {\n\t\tx: true,\n\t\ty: true,\n\t\tz: true,\n\t},\n\ttextureScale: new Vector2(1, 1),\n\ttextureOffset: new Vector2(0, 0),\n};\n\nconst DEFAULT_FRAGMENT_PHYSICS: Required<Destructible3DFragmentPhysicsOptions> = {\n\tmode: 'compound',\n\tinheritSourceVelocity: true,\n\toutwardVelocity: 3,\n\tangularVelocity: 1.5,\n};\n\nconst defaultOptions: Destructible3DBehaviorOptions = {\n\tfractureOptions: DEFAULT_FRACTURE_OPTIONS,\n\tinnerMaterial: null,\n\tcollider: {\n\t\tshape: 'convexHull',\n\t\tsensor: false,\n\t},\n\tfragmentPhysics: DEFAULT_FRAGMENT_PHYSICS,\n};\n\nconst runtimeStates = new WeakMap<\n\tBehaviorRef<Destructible3DBehaviorOptions>,\n\tRuntimeState\n>();\n\nfunction getRuntimeState(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): RuntimeState {\n\tconst existing = runtimeStates.get(ref);\n\tif (existing) {\n\t\treturn existing;\n\t}\n\n\tconst state: RuntimeState = {\n\t\tfragmentContainer: null,\n\t\tfragmentEntities: [],\n\t\tfragments: [],\n\t\tprebakedFragments: [],\n\t\tprebakedFractureKey: null,\n\t\tcreatedRootGroup: false,\n\t\tfractureMode: null,\n\t\tisFractured: false,\n\t\toriginalMeshParent: null,\n\t\toriginalColliderDesc: undefined,\n\t\toriginalColliderDescs: [],\n\t\toriginalMeshVisible: true,\n\t\toriginalGroupVisible: true,\n\t\tsourceBodySnapshot: null,\n\t\tsourcePhysicsAttached: false,\n\t};\n\truntimeStates.set(ref, state);\n\treturn state;\n}\n\nconst prebakeWorkerApis = new Map<\n\tstring,\n\tComlink.Remote<DestructiblePrebakeWorkerAPI>\n>();\n\n/** One in-flight worker prebake per behavior ref (dedupes duplicate bind calls). */\nconst prebakeAsyncInFlight = new WeakMap<\n\tBehaviorRef<Destructible3DBehaviorOptions>,\n\tPromise<void>\n>();\n\nfunction resolvePrebakeWorkerHref(url: URL | string): string {\n\treturn typeof url === 'string' ? url : url.href;\n}\n\nfunction getPrebakeWorkerApi(\n\turl: URL | string,\n): Comlink.Remote<DestructiblePrebakeWorkerAPI> {\n\tif (typeof Worker === 'undefined') {\n\t\tthrow new Error(\n\t\t\t'Destructible3D prebakeAsync requires a Web Worker-capable environment.',\n\t\t);\n\t}\n\tconst key = resolvePrebakeWorkerHref(url);\n\tlet api = prebakeWorkerApis.get(key);\n\tif (api) {\n\t\treturn api;\n\t}\n\tconst worker = new Worker(key, { type: 'module' });\n\tapi = Comlink.wrap(worker);\n\tprebakeWorkerApis.set(key, api);\n\treturn api;\n}\n\nfunction requireEntity(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): GameEntity<any> {\n\tconst entity = (ref as any).__entity as GameEntity<any> | undefined;\n\tif (!entity) {\n\t\tthrow new Error(\n\t\t\t'Destructible3DBehavior requires the entity to be registered on a stage before calling fracture() or repair().',\n\t\t);\n\t}\n\n\treturn entity;\n}\n\nfunction getBehaviorWorld(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): BehaviorWorld | null {\n\treturn ((ref as any).__world ?? null) as BehaviorWorld | null;\n}\n\nfunction getBehaviorScene(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): BehaviorScene | null {\n\treturn ((ref as any).__scene ?? null) as BehaviorScene | null;\n}\n\nfunction getBehaviorCreateEntity(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): CreateEntityFn | null {\n\treturn ((ref as any).__createEntity ?? null) as CreateEntityFn | null;\n}\n\nfunction getBehaviorGlobals(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): (() => any) | null {\n\treturn ((ref as any).__getGlobals ?? null) as (() => any) | null;\n}\n\nfunction cloneFractureOptionsInput(\n\tvalue?: FractureOptionsInput | PinataFractureOptions,\n): FractureOptionsInput {\n\tif (!value) {\n\t\treturn {};\n\t}\n\n\tif (value instanceof PinataFractureOptions) {\n\t\treturn {\n\t\t\tfractureMethod: value.fractureMethod,\n\t\t\tfragmentCount: value.fragmentCount,\n\t\t\tvoronoiOptions: value.voronoiOptions\n\t\t\t\t? {\n\t\t\t\t\tmode: value.voronoiOptions.mode,\n\t\t\t\t\tseedPoints: value.voronoiOptions.seedPoints?.map((point) =>\n\t\t\t\t\t\tpoint.clone()),\n\t\t\t\t\timpactPoint: value.voronoiOptions.impactPoint?.clone(),\n\t\t\t\t\timpactRadius: value.voronoiOptions.impactRadius,\n\t\t\t\t\tprojectionAxis: value.voronoiOptions.projectionAxis,\n\t\t\t\t\tprojectionNormal: value.voronoiOptions.projectionNormal?.clone(),\n\t\t\t\t\tuseApproximation: value.voronoiOptions.useApproximation,\n\t\t\t\t\tapproximationNeighborCount:\n\t\t\t\t\t\tvalue.voronoiOptions.approximationNeighborCount,\n\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t\tfracturePlanes: value.fracturePlanes\n\t\t\t\t? { ...value.fracturePlanes }\n\t\t\t\t: undefined,\n\t\t\ttextureScale: value.textureScale?.clone(),\n\t\t\ttextureOffset: value.textureOffset?.clone(),\n\t\t\tseed: value.seed,\n\t\t};\n\t}\n\n\treturn {\n\t\t...value,\n\t\tvoronoiOptions: value.voronoiOptions\n\t\t\t? {\n\t\t\t\t...value.voronoiOptions,\n\t\t\t\tseedPoints: value.voronoiOptions.seedPoints?.map((point) =>\n\t\t\t\t\tpoint.clone()),\n\t\t\t\timpactPoint: value.voronoiOptions.impactPoint?.clone(),\n\t\t\t\tprojectionNormal: value.voronoiOptions.projectionNormal?.clone(),\n\t\t\t}\n\t\t\t: undefined,\n\t\tfracturePlanes: value.fracturePlanes\n\t\t\t? { ...value.fracturePlanes }\n\t\t\t: undefined,\n\t\ttextureScale: value.textureScale?.clone(),\n\t\ttextureOffset: value.textureOffset?.clone(),\n\t};\n}\n\nfunction resolveFractureOptions(\n\tbaseValue?: FractureOptionsInput | PinataFractureOptions,\n\toverrideValue?: FractureOptionsInput | PinataFractureOptions,\n): PinataFractureOptions {\n\tconst base = cloneFractureOptionsInput(baseValue);\n\tconst override = cloneFractureOptionsInput(overrideValue);\n\n\tconst fractureMethod =\n\t\toverride.fractureMethod\n\t\t?? base.fractureMethod\n\t\t?? DEFAULT_FRACTURE_OPTIONS.fractureMethod\n\t\t?? 'voronoi';\n\n\tconst voronoiOptions = fractureMethod === 'voronoi'\n\t\t? {\n\t\t\tmode:\n\t\t\t\toverride.voronoiOptions?.mode\n\t\t\t\t?? base.voronoiOptions?.mode\n\t\t\t\t?? DEFAULT_FRACTURE_OPTIONS.voronoiOptions?.mode\n\t\t\t\t?? '3D',\n\t\t\tseedPoints:\n\t\t\t\toverride.voronoiOptions?.seedPoints\n\t\t\t\t?? base.voronoiOptions?.seedPoints,\n\t\t\timpactPoint:\n\t\t\t\toverride.voronoiOptions?.impactPoint\n\t\t\t\t?? base.voronoiOptions?.impactPoint,\n\t\t\timpactRadius:\n\t\t\t\toverride.voronoiOptions?.impactRadius\n\t\t\t\t?? base.voronoiOptions?.impactRadius,\n\t\t\tprojectionAxis:\n\t\t\t\toverride.voronoiOptions?.projectionAxis\n\t\t\t\t?? base.voronoiOptions?.projectionAxis,\n\t\t\tprojectionNormal:\n\t\t\t\toverride.voronoiOptions?.projectionNormal\n\t\t\t\t?? base.voronoiOptions?.projectionNormal,\n\t\t\tuseApproximation:\n\t\t\t\toverride.voronoiOptions?.useApproximation\n\t\t\t\t?? base.voronoiOptions?.useApproximation,\n\t\t\tapproximationNeighborCount:\n\t\t\t\toverride.voronoiOptions?.approximationNeighborCount\n\t\t\t\t?? base.voronoiOptions?.approximationNeighborCount,\n\t\t}\n\t\t: undefined;\n\n\treturn new PinataFractureOptions({\n\t\tfractureMethod,\n\t\tfragmentCount:\n\t\t\toverride.fragmentCount\n\t\t\t?? base.fragmentCount\n\t\t\t?? DEFAULT_FRACTURE_OPTIONS.fragmentCount\n\t\t\t?? 12,\n\t\tvoronoiOptions,\n\t\tfracturePlanes: {\n\t\t\tx:\n\t\t\t\toverride.fracturePlanes?.x\n\t\t\t\t?? base.fracturePlanes?.x\n\t\t\t\t?? DEFAULT_FRACTURE_OPTIONS.fracturePlanes?.x\n\t\t\t\t?? true,\n\t\t\ty:\n\t\t\t\toverride.fracturePlanes?.y\n\t\t\t\t?? base.fracturePlanes?.y\n\t\t\t\t?? DEFAULT_FRACTURE_OPTIONS.fracturePlanes?.y\n\t\t\t\t?? true,\n\t\t\tz:\n\t\t\t\toverride.fracturePlanes?.z\n\t\t\t\t?? base.fracturePlanes?.z\n\t\t\t\t?? DEFAULT_FRACTURE_OPTIONS.fracturePlanes?.z\n\t\t\t\t?? true,\n\t\t},\n\t\ttextureScale:\n\t\t\toverride.textureScale?.clone()\n\t\t\t?? base.textureScale?.clone()\n\t\t\t?? DEFAULT_FRACTURE_OPTIONS.textureScale?.clone()\n\t\t\t?? new Vector2(1, 1),\n\t\ttextureOffset:\n\t\t\toverride.textureOffset?.clone()\n\t\t\t?? base.textureOffset?.clone()\n\t\t\t?? DEFAULT_FRACTURE_OPTIONS.textureOffset?.clone()\n\t\t\t?? new Vector2(0, 0),\n\t\tseed: override.seed ?? base.seed,\n\t});\n}\n\nfunction resolveColliderOptions(\n\tinput?: Destructible3DColliderOptions,\n): Required<\n\tPick<Destructible3DColliderOptions, 'shape' | 'sensor'>\n> & Omit<Destructible3DColliderOptions, 'shape' | 'sensor'> {\n\treturn {\n\t\tshape: input?.shape ?? defaultOptions.collider?.shape ?? 'convexHull',\n\t\tsensor: input?.sensor ?? defaultOptions.collider?.sensor ?? false,\n\t\tcollisionGroups: input?.collisionGroups,\n\t};\n}\n\nfunction resolveFragmentPhysicsOptions(\n\tinput?: Destructible3DFragmentPhysicsOptions,\n): Required<Destructible3DFragmentPhysicsOptions> {\n\treturn {\n\t\tmode: input?.mode ?? DEFAULT_FRAGMENT_PHYSICS.mode,\n\t\tinheritSourceVelocity:\n\t\t\tinput?.inheritSourceVelocity\n\t\t\t?? DEFAULT_FRAGMENT_PHYSICS.inheritSourceVelocity,\n\t\toutwardVelocity:\n\t\t\tinput?.outwardVelocity\n\t\t\t?? DEFAULT_FRAGMENT_PHYSICS.outwardVelocity,\n\t\tangularVelocity:\n\t\t\tinput?.angularVelocity\n\t\t\t?? DEFAULT_FRAGMENT_PHYSICS.angularVelocity,\n\t};\n}\n\nfunction findFirstMesh(root: Object3D | null | undefined): Mesh | null {\n\tlet resolved: Mesh | null = null;\n\troot?.traverse((child) => {\n\t\tif (resolved) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ((child as { isMesh?: boolean }).isMesh) {\n\t\t\tresolved = child as Mesh;\n\t\t}\n\t});\n\treturn resolved;\n}\n\nfunction requireEntityMesh(entity: GameEntity<any>): Mesh {\n\tif (entity.mesh?.geometry) {\n\t\treturn entity.mesh;\n\t}\n\n\tconst mesh = findFirstMesh(entity.group);\n\tif (!mesh?.geometry) {\n\t\tthrow new Error(\n\t\t\t'Destructible3DBehavior requires the entity to have a primary mesh geometry.',\n\t\t);\n\t}\n\n\tentity.mesh = mesh;\n\tif (!entity.materials?.length) {\n\t\tif (Array.isArray(mesh.material)) {\n\t\t\tentity.materials = [...mesh.material];\n\t\t} else if (mesh.material) {\n\t\t\tentity.materials = [mesh.material];\n\t\t}\n\t}\n\n\treturn mesh;\n}\n\nfunction getPrimaryMaterial(mesh: Mesh): Material {\n\tif (Array.isArray(mesh.material)) {\n\t\tconst material = mesh.material[0];\n\t\tif (material) {\n\t\t\treturn material;\n\t\t}\n\t} else if (mesh.material) {\n\t\treturn mesh.material;\n\t}\n\n\tthrow new Error(\n\t\t'Destructible3DBehavior requires the entity mesh to have a material.',\n\t);\n}\n\nfunction ensureRootGroup(\n\tentity: GameEntity<any>,\n\tstate: RuntimeState,\n): Group {\n\tif (entity.group) {\n\t\tstate.createdRootGroup = false;\n\t\treturn entity.group;\n\t}\n\n\tconst originalMesh = requireEntityMesh(entity);\n\tconst parent = originalMesh.parent;\n\tconst root = new Group();\n\troot.name = `${entity.name ?? entity.uuid}-destructible-root`;\n\troot.position.copy(originalMesh.position);\n\troot.quaternion.copy(originalMesh.quaternion);\n\troot.scale.copy(originalMesh.scale);\n\n\toriginalMesh.position.set(0, 0, 0);\n\toriginalMesh.quaternion.identity();\n\toriginalMesh.scale.set(1, 1, 1);\n\n\tif (parent) {\n\t\tparent.remove(originalMesh);\n\t\tparent.add(root);\n\t}\n\n\troot.add(originalMesh);\n\tentity.group = root;\n\tstate.createdRootGroup = true;\n\treturn root;\n}\n\nfunction createFractureSourceMesh(\n\tmesh: Mesh,\n\troot: Group,\n\tinnerMaterial: Material | null | undefined,\n): DestructibleMesh {\n\tconst geometry = buildNormalizedFractureSourceGeometry(mesh, root);\n\tconst outerMaterial = getPrimaryMaterial(mesh);\n\treturn new DestructibleMesh(\n\t\tgeometry,\n\t\touterMaterial,\n\t\tinnerMaterial ?? outerMaterial,\n\t);\n}\n\nfunction createPrebakedFragmentTemplates(\n\tfragments: readonly DestructibleMesh[],\n): PrebakedFragmentTemplate[] {\n\treturn fragments.map((fragment) => {\n\t\tconst geometry = fragment.geometry.clone();\n\t\tgeometry.computeBoundingBox();\n\t\tgeometry.computeBoundingSphere();\n\t\treturn {\n\t\t\tgeometry,\n\t\t\tposition: fragment.position.clone(),\n\t\t\tquaternion: fragment.quaternion.clone(),\n\t\t\tscale: fragment.scale.clone(),\n\t\t};\n\t});\n}\n\nfunction disposePrebakedFragmentTemplates(\n\ttemplates: readonly PrebakedFragmentTemplate[],\n): void {\n\tfor (const template of templates) {\n\t\ttemplate.geometry.dispose();\n\t}\n}\n\nfunction cachePrebakedFragments(\n\tstate: RuntimeState,\n\tcacheKey: string,\n\tfragments: readonly DestructibleMesh[],\n): void {\n\tif (\n\t\tstate.prebakedFractureKey === cacheKey\n\t\t&& state.prebakedFragments.length > 0\n\t) {\n\t\treturn;\n\t}\n\n\tdisposePrebakedFragmentTemplates(state.prebakedFragments);\n\tstate.prebakedFragments = createPrebakedFragmentTemplates(fragments);\n\tstate.prebakedFractureKey = cacheKey;\n}\n\nfunction installPrebakedTemplateParts(\n\tstate: RuntimeState,\n\tcacheKey: string,\n\tparts: Array<{\n\t\tgeometry: BufferGeometry;\n\t\tposition: Vector3;\n\t\tquaternion: Quaternion;\n\t\tscale: Vector3;\n\t}>,\n): void {\n\tif (\n\t\tstate.prebakedFractureKey === cacheKey\n\t\t&& state.prebakedFragments.length > 0\n\t) {\n\t\tfor (const part of parts) {\n\t\t\tpart.geometry.dispose();\n\t\t}\n\t\treturn;\n\t}\n\n\tdisposePrebakedFragmentTemplates(state.prebakedFragments);\n\tstate.prebakedFragments = parts.map((part) => ({\n\t\tgeometry: part.geometry,\n\t\tposition: part.position.clone(),\n\t\tquaternion: part.quaternion.clone(),\n\t\tscale: part.scale.clone(),\n\t}));\n\tstate.prebakedFractureKey = cacheKey;\n}\n\nfunction instantiatePrebakedFragments(\n\tmesh: Mesh,\n\tinnerMaterial: Material | null | undefined,\n\ttemplates: readonly PrebakedFragmentTemplate[],\n): readonly DestructibleMesh[] {\n\tconst outerMaterial = getPrimaryMaterial(mesh);\n\treturn templates.map((template) => {\n\t\tconst fragment = new DestructibleMesh(\n\t\t\ttemplate.geometry.clone(),\n\t\t\touterMaterial,\n\t\t\tinnerMaterial ?? outerMaterial,\n\t\t);\n\t\tfragment.position.copy(template.position);\n\t\tfragment.quaternion.copy(template.quaternion);\n\t\tfragment.scale.copy(template.scale);\n\t\treturn fragment;\n\t});\n}\n\nfunction getFragmentVertices(fragment: DestructibleMesh): Float32Array {\n\tconst position = fragment.geometry.getAttribute('position');\n\tif (!(position instanceof BufferAttribute)) {\n\t\tthrow new Error('Fragment geometry is missing a position attribute.');\n\t}\n\n\treturn new Float32Array(position.array as ArrayLike<number>);\n}\n\nfunction getFragmentIndices(fragment: DestructibleMesh): Uint32Array {\n\tconst geometryIndex = fragment.geometry.getIndex();\n\tif (geometryIndex) {\n\t\treturn new Uint32Array(geometryIndex.array as ArrayLike<number>);\n\t}\n\n\tconst position = fragment.geometry.getAttribute('position');\n\tif (!(position instanceof BufferAttribute)) {\n\t\treturn new Uint32Array();\n\t}\n\n\treturn Uint32Array.from({ length: position.count }, (_value, index) => index);\n}\n\nfunction createCuboidColliderShape(\n\tfragment: DestructibleMesh,\n): { type: 'box'; halfExtents: [number, number, number] } {\n\tconst bounds = fragment.geometry.boundingBox ?? new Box3();\n\tif (!fragment.geometry.boundingBox) {\n\t\tfragment.geometry.computeBoundingBox();\n\t}\n\tbounds.copy(fragment.geometry.boundingBox ?? bounds);\n\tconst size = bounds.getSize(new Vector3());\n\treturn {\n\t\ttype: 'box',\n\t\thalfExtents: [\n\t\t\tMath.max(size.x / 2, 0.001),\n\t\t\tMath.max(size.y / 2, 0.001),\n\t\t\tMath.max(size.z / 2, 0.001),\n\t\t],\n\t};\n}\n\nfunction createFragmentColliderDefinition(\n\tfragment: DestructibleMesh,\n\toptions: Destructible3DColliderOptions | undefined,\n\ttranslation?: Vector3 | null,\n): Destructible3DFragmentColliderDefinition {\n\tconst resolved = resolveColliderOptions(options);\n\tconst vertices = getFragmentVertices(fragment);\n\n\tlet shape: Destructible3DFragmentColliderDefinition['shape'] | null = null;\n\n\tif (resolved.shape === 'convexHull' && vertices.length >= 12) {\n\t\tshape = { type: 'convexHull', vertices };\n\t}\n\n\tif (!shape && resolved.shape === 'trimesh') {\n\t\tshape = { type: 'trimesh', vertices, indices: getFragmentIndices(fragment) };\n\t}\n\n\tif (!shape) {\n\t\tshape = createCuboidColliderShape(fragment);\n\t}\n\n\tconst definition: Destructible3DFragmentColliderDefinition = {\n\t\tshape,\n\t\tsensor: resolved.sensor,\n\t};\n\tif (translation) {\n\t\tdefinition.offset = [translation.x, translation.y, translation.z];\n\t}\n\tif (resolved.collisionGroups !== undefined) {\n\t\tdefinition.collisionGroups = resolved.collisionGroups;\n\t}\n\treturn definition;\n}\n\nfunction snapshotBody(entity: GameEntity<any>): PhysicsSnapshot | null {\n\tconst body = getBodyLike(entity);\n\tif (!body) {\n\t\treturn null;\n\t}\n\n\tconst translation = body.translation();\n\tconst rotation = body.rotation();\n\tconst linearVelocity = body.linvel();\n\tconst angularVelocity = body.angvel();\n\n\treturn {\n\t\ttranslation: { ...translation },\n\t\trotation: { ...rotation },\n\t\tlinearVelocity: { ...linearVelocity },\n\t\tangularVelocity: { ...angularVelocity },\n\t};\n}\n\nfunction restoreBodySnapshot(\n\tentity: GameEntity<any>,\n\tsnapshot: PhysicsSnapshot | null,\n): void {\n\tconst body = getBodyLike(entity);\n\tif (!snapshot || !body) {\n\t\treturn;\n\t}\n\n\tbody.setTranslation(snapshot.translation, true);\n\tbody.setRotation(snapshot.rotation, true);\n\tbody.setLinvel(snapshot.linearVelocity, true);\n\tbody.setAngvel(snapshot.angularVelocity, true);\n}\n\nfunction attachEntityPhysics(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\tentity: GameEntity<any>,\n\tsnapshot: PhysicsSnapshot | null,\n): void {\n\tconst world = getBehaviorWorld(ref);\n\tif (!world || !entity.colliderDesc) {\n\t\treturn;\n\t}\n\n\tif (entity.physicsAttached) {\n\t\tworld.destroyEntity(entity);\n\t}\n\n\tworld.addEntity(entity);\n\trestoreBodySnapshot(entity, snapshot);\n}\n\nfunction detachEntityPhysics(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\tentity: GameEntity<any>,\n): void {\n\tconst world = getBehaviorWorld(ref);\n\tif (!world || !entity.physicsAttached) {\n\t\treturn;\n\t}\n\n\tworld.destroyEntity(entity);\n}\n\nfunction disposeFragments(fragments: readonly DestructibleMesh[]): void {\n\tfor (const fragment of fragments) {\n\t\tfragment.removeFromParent();\n\t\tfragment.geometry.dispose();\n\t}\n}\n\nfunction syncRuntimeFragmentEntityTransform(\n\tentity: GameEntity<any>,\n\t_interpolationAlpha: number,\n): void {\n\tconst target = entity.group ?? entity.mesh;\n\tif (!target) {\n\t\treturn;\n\t}\n\n\tconst wasmPose = (entity as any).getPose?.();\n\tif (wasmPose && (entity as any).runtimeHandle >= 0) {\n\t\ttarget.position.set(wasmPose.position.x, wasmPose.position.y, wasmPose.position.z);\n\t\ttarget.quaternion.set(wasmPose.rotation.x, wasmPose.rotation.y, wasmPose.rotation.z, wasmPose.rotation.w);\n\t}\n}\n\nfunction bakeScaleIntoFragmentGeometry(\n\tfragment: DestructibleMesh,\n\tscale: Vector3,\n): void {\n\tif (\n\t\tMath.abs(scale.x - 1) < 1e-6\n\t\t&& Math.abs(scale.y - 1) < 1e-6\n\t\t&& Math.abs(scale.z - 1) < 1e-6\n\t) {\n\t\treturn;\n\t}\n\n\tfragment.geometry.applyMatrix4(\n\t\tnew Matrix4().makeScale(scale.x, scale.y, scale.z),\n\t);\n\tfragment.geometry.computeBoundingBox();\n\tfragment.geometry.computeBoundingSphere();\n}\n\nfunction getRootWorldPosition(root: Group): Vector3 {\n\troot.updateMatrixWorld(true);\n\treturn root.getWorldPosition(new Vector3());\n}\n\nfunction getImpactPointWorld(\n\troot: Group,\n\tfractureOptions: PinataFractureOptions,\n): Vector3 | null {\n\tconst localImpactPoint = fractureOptions.voronoiOptions?.impactPoint;\n\tif (!localImpactPoint) {\n\t\treturn null;\n\t}\n\n\troot.updateMatrixWorld(true);\n\treturn localImpactPoint.clone().applyMatrix4(root.matrixWorld);\n}\n\nfunction computeFragmentWorldPose(\n\troot: Group,\n\tfragment: DestructibleMesh,\n): {\n\tposition: Vector3;\n\trotation: Quaternion;\n\tscale: Vector3;\n} {\n\troot.updateMatrixWorld(true);\n\tfragment.updateMatrix();\n\n\tconst worldMatrix = new Matrix4()\n\t\t.copy(root.matrixWorld)\n\t\t.multiply(fragment.matrix);\n\tconst position = new Vector3();\n\tconst rotation = new Quaternion();\n\tconst scale = new Vector3();\n\n\tworldMatrix.decompose(position, rotation, scale);\n\treturn {\n\t\tposition,\n\t\trotation,\n\t\tscale,\n\t};\n}\n\nfunction pseudoRandomSigned(index: number, salt: number): number {\n\tconst value = Math.sin((index + 1) * 12.9898 + salt * 78.233) * 43758.5453;\n\treturn (value - Math.floor(value)) * 2 - 1;\n}\n\nfunction computeFragmentAngularVelocity(\n\tindex: number,\n\tmagnitude: number,\n): { x: number; y: number; z: number } {\n\tif (magnitude <= 0) {\n\t\treturn { x: 0, y: 0, z: 0 };\n\t}\n\n\tconst axis = new Vector3(\n\t\tpseudoRandomSigned(index, 0.13),\n\t\tpseudoRandomSigned(index, 0.47),\n\t\tpseudoRandomSigned(index, 0.91),\n\t);\n\tif (axis.lengthSq() <= 1e-6) {\n\t\taxis.set(0.35, 1, 0.2);\n\t}\n\taxis.normalize().multiplyScalar(magnitude);\n\treturn {\n\t\tx: axis.x,\n\t\ty: axis.y,\n\t\tz: axis.z,\n\t};\n}\n\nfunction computeFragmentLinearVelocity(\n\tfragmentWorldPosition: Vector3,\n\trootWorldPosition: Vector3,\n\timpactPointWorld: Vector3 | null,\n\tphysicsOptions: Required<Destructible3DFragmentPhysicsOptions>,\n\tsourceVelocity: { x: number; y: number; z: number } | null,\n): { x: number; y: number; z: number } {\n\tconst velocity = new Vector3();\n\n\tif (physicsOptions.inheritSourceVelocity && sourceVelocity) {\n\t\tvelocity.set(\n\t\t\tsourceVelocity.x,\n\t\t\tsourceVelocity.y,\n\t\t\tsourceVelocity.z,\n\t\t);\n\t}\n\n\tif (physicsOptions.outwardVelocity <= 0) {\n\t\treturn {\n\t\t\tx: velocity.x,\n\t\t\ty: velocity.y,\n\t\t\tz: velocity.z,\n\t\t};\n\t}\n\n\tconst direction = fragmentWorldPosition.clone().sub(\n\t\timpactPointWorld ?? rootWorldPosition,\n\t);\n\tif (direction.lengthSq() <= 1e-6) {\n\t\tdirection.copy(fragmentWorldPosition).sub(rootWorldPosition);\n\t}\n\tif (direction.lengthSq() <= 1e-6) {\n\t\tdirection.set(0, 1, 0);\n\t}\n\tdirection.normalize().multiplyScalar(physicsOptions.outwardVelocity);\n\tvelocity.add(direction);\n\n\treturn {\n\t\tx: velocity.x,\n\t\ty: velocity.y,\n\t\tz: velocity.z,\n\t};\n}\n\nfunction createRuntimeFragmentEntity(\n\tcreateEntity: CreateEntityFn,\n\tparentEntity: GameEntity<any>,\n\tfragment: DestructibleMesh,\n\tindex: number,\n\tcolliderOptions: Destructible3DColliderOptions | undefined,\n\tposition: Vector3,\n\trotation: Quaternion,\n): GameEntity<any> {\n\tconst entity = createEntity({\n\t\tname: `${parentEntity.name ?? parentEntity.uuid}-fragment-${index}`,\n\t});\n\n\tentity.onCleanup(() => {\n\t\tfragment.removeFromParent();\n\t\tfragment.geometry.dispose();\n\t});\n\tentity.create();\n\n\tentity.mesh = fragment;\n\tif (Array.isArray(fragment.material)) {\n\t\tentity.materials = [...fragment.material];\n\t} else if (fragment.material) {\n\t\tentity.materials = [fragment.material];\n\t}\n\n\tentity.colliderDesc = createFragmentColliderDefinition(fragment, colliderOptions);\n\tentity.colliderDescs = [entity.colliderDesc];\n\tconst bodyDefinition: Destructible3DFragmentBodyDefinition = {\n\t\tkind: 'dynamic',\n\t\tposition: [position.x, position.y, position.z],\n\t\trotation: [rotation.x, rotation.y, rotation.z, rotation.w],\n\t\tcanSleep: false,\n\t\tccdEnabled: true,\n\t};\n\tentity.bodyDesc = bodyDefinition;\n\n\tfragment.position.set(0, 0, 0);\n\tfragment.quaternion.identity();\n\tfragment.scale.set(1, 1, 1);\n\n\treturn entity;\n}\n\n/**\n * {@link ZylemWorld} locks translations and rotations on every new rigid body\n * when world gravity is `(0,0,0)`, so entities do not drift in zero‑G scenes.\n * Independent destructible fragments are still meant to move via\n * `setLinvel` / `setAngvel`, so they must opt out of that lock after spawn.\n */\nfunction unlockIndependentFragmentPhysicsBody(entity: GameEntity<any>): void {\n\tconst body = entity.body as\n\t\t| {\n\t\t\tlockTranslations?(locked: boolean, wakeUp?: boolean): void;\n\t\t\tlockRotations?(locked: boolean, wakeUp?: boolean): void;\n\t\t}\n\t\t| null\n\t\t| undefined;\n\tif (!body?.lockTranslations || !body.lockRotations) {\n\t\treturn;\n\t}\n\tbody.lockTranslations(false, true);\n\tbody.lockRotations(false, true);\n}\n\nfunction destroyRuntimeFragmentEntities(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\tstate: RuntimeState,\n): void {\n\tconst world = getBehaviorWorld(ref);\n\tconst scene = getBehaviorScene(ref);\n\tconst handledFragments = new Set<DestructibleMesh>();\n\n\tfor (const fragmentEntity of state.fragmentEntities) {\n\t\tconst fragmentMesh = fragmentEntity.mesh as DestructibleMesh | undefined;\n\t\tif (fragmentMesh) {\n\t\t\thandledFragments.add(fragmentMesh);\n\t\t}\n\n\t\ttry {\n\t\t\tfragmentEntity.nodeDestroy({\n\t\t\t\tme: fragmentEntity,\n\t\t\t\tglobals: getBehaviorGlobals(ref)?.() ?? {},\n\t\t\t} as any);\n\t\t} catch {\n\t\t\t// Cleanup is best-effort for behavior-managed runtime fragments.\n\t\t}\n\n\t\tif (world && fragmentEntity.physicsAttached) {\n\t\t\tworld.destroyEntity(fragmentEntity);\n\t\t}\n\n\t\tconst target = fragmentEntity.group ?? fragmentEntity.mesh;\n\t\tif (target) {\n\t\t\ttarget.removeFromParent();\n\t\t\tscene?.scene.remove(target);\n\t\t}\n\t}\n\n\tfor (const fragment of state.fragments) {\n\t\tif (handledFragments.has(fragment)) {\n\t\t\tcontinue;\n\t\t}\n\t\tfragment.removeFromParent();\n\t\tfragment.geometry.dispose();\n\t}\n\n\tstate.fragmentEntities = [];\n}\n\nfunction restoreOriginalMesh(\n\tentity: GameEntity<any>,\n\tstate: RuntimeState,\n): void {\n\tif (!entity.mesh) {\n\t\treturn;\n\t}\n\n\tif (state.createdRootGroup && entity.group) {\n\t\tconst root = entity.group;\n\t\tconst parent = root.parent;\n\t\tentity.mesh.position.copy(root.position);\n\t\tentity.mesh.quaternion.copy(root.quaternion);\n\t\tentity.mesh.scale.copy(root.scale);\n\t\tentity.mesh.removeFromParent();\n\n\t\tif (parent) {\n\t\t\tparent.remove(root);\n\t\t\tparent.add(entity.mesh);\n\t\t}\n\n\t\tentity.group = undefined;\n\t\treturn;\n\t}\n\n\tconst parent = state.originalMeshParent ?? entity.group;\n\tif (parent && entity.mesh.parent !== parent) {\n\t\tparent.add(entity.mesh);\n\t}\n}\n\nfunction restoreRuntimeState(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\trefreshPhysics: boolean,\n): void {\n\tconst state = getRuntimeState(ref);\n\tif (!state.isFractured) {\n\t\treturn;\n\t}\n\n\tconst entity = requireEntity(ref);\n\n\tif (state.fractureMode === 'independent') {\n\t\tdestroyRuntimeFragmentEntities(ref, state);\n\t} else {\n\t\tstate.fragmentContainer?.removeFromParent();\n\t\tstate.fragmentContainer?.clear();\n\t\tdisposeFragments(state.fragments);\n\t}\n\n\tstate.fragmentContainer = null;\n\tstate.fragments = [];\n\n\trestoreOriginalMesh(entity, state);\n\tif (entity.mesh) {\n\t\tentity.mesh.visible = state.originalMeshVisible;\n\t}\n\tif (entity.group) {\n\t\tentity.group.visible = state.originalGroupVisible;\n\t}\n\n\tentity.colliderDesc = state.originalColliderDesc;\n\tentity.colliderDescs = [...state.originalColliderDescs];\n\tif (!entity.colliderDesc && entity.colliderDescs.length > 0) {\n\t\tentity.colliderDesc = entity.colliderDescs[0];\n\t}\n\n\tif (refreshPhysics && state.sourcePhysicsAttached) {\n\t\tattachEntityPhysics(ref, entity, state.sourceBodySnapshot);\n\t}\n\n\tstate.createdRootGroup = false;\n\tstate.fractureMode = null;\n\tstate.originalMeshParent = null;\n\tstate.originalColliderDesc = undefined;\n\tstate.originalColliderDescs = [];\n\tstate.originalMeshVisible = true;\n\tstate.originalGroupVisible = true;\n\tstate.sourceBodySnapshot = null;\n\tstate.sourcePhysicsAttached = false;\n\tstate.isFractured = false;\n}\n\nfunction disposeRuntimeState(state: RuntimeState): void {\n\tdisposePrebakedFragmentTemplates(state.prebakedFragments);\n\tstate.prebakedFragments = [];\n\tstate.prebakedFractureKey = null;\n}\n\nfunction fractureCompoundEntity(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\tentity: GameEntity<any>,\n\troot: Group,\n\tfragments: readonly DestructibleMesh[],\n\tstate: RuntimeState,\n): void {\n\tconst fragmentContainer = new Group();\n\tfragmentContainer.name = `${entity.name ?? entity.uuid}-fracture-fragments`;\n\tfor (const fragment of fragments) {\n\t\tfragmentContainer.add(fragment);\n\t}\n\n\tentity.mesh?.removeFromParent();\n\troot.add(fragmentContainer);\n\n\tstate.fragmentContainer = fragmentContainer;\n\tstate.fractureMode = 'compound';\n\n\tconst colliderDescs = fragments.map((fragment) =>\n\t\tcreateFragmentColliderDefinition(\n\t\t\tfragment,\n\t\t\tref.options.collider,\n\t\t\tfragment.position,\n\t\t));\n\tif (colliderDescs.length > 0) {\n\t\tentity.colliderDescs = colliderDescs;\n\t\tentity.colliderDesc = colliderDescs[0];\n\t\tif (state.sourcePhysicsAttached) {\n\t\t\tattachEntityPhysics(ref, entity, state.sourceBodySnapshot);\n\t\t}\n\t}\n}\n\nfunction fractureIndependentEntity(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\tentity: GameEntity<any>,\n\troot: Group,\n\tfractureOptions: PinataFractureOptions,\n\tfragments: readonly DestructibleMesh[],\n\tstate: RuntimeState,\n): void {\n\tconst world = getBehaviorWorld(ref);\n\tconst scene = getBehaviorScene(ref);\n\tif (!world || !scene) {\n\t\tthrow new Error(\n\t\t\t'Destructible3DBehavior independent fragments require an active scene and physics world.',\n\t\t);\n\t}\n\n\tconst createEntity = getBehaviorCreateEntity(ref);\n\tif (!createEntity) {\n\t\tthrow new Error(\n\t\t\t'Destructible3DBehavior independent fragments require a host entity factory (BehaviorSystemContext.createEntity).',\n\t\t);\n\t}\n\n\tconst physicsOptions = resolveFragmentPhysicsOptions(ref.options.fragmentPhysics);\n\tconst rootWorldPosition = getRootWorldPosition(root);\n\tconst impactPointWorld = getImpactPointWorld(root, fractureOptions);\n\tconst sourceVelocity = state.sourceBodySnapshot?.linearVelocity ?? null;\n\n\tif (entity.mesh) {\n\t\tentity.mesh.visible = false;\n\t}\n\tif (state.sourcePhysicsAttached) {\n\t\tdetachEntityPhysics(ref, entity);\n\t}\n\n\tconst fragmentEntities: GameEntity<any>[] = [];\n\n\tfor (const [index, fragment] of fragments.entries()) {\n\t\tconst fragmentWorldPose = computeFragmentWorldPose(root, fragment);\n\t\tbakeScaleIntoFragmentGeometry(fragment, fragmentWorldPose.scale);\n\n\t\tconst fragmentEntity = createRuntimeFragmentEntity(\n\t\t\tcreateEntity,\n\t\t\tentity,\n\t\t\tfragment,\n\t\t\tindex,\n\t\t\tref.options.collider,\n\t\t\tfragmentWorldPose.position,\n\t\t\tfragmentWorldPose.rotation,\n\t\t);\n\n\t\tworld.addEntity(fragmentEntity);\n\t\tunlockIndependentFragmentPhysicsBody(fragmentEntity);\n\t\tconst linearVelocity = computeFragmentLinearVelocity(\n\t\t\tfragmentWorldPose.position,\n\t\t\trootWorldPosition,\n\t\t\timpactPointWorld,\n\t\t\tphysicsOptions,\n\t\t\tsourceVelocity,\n\t\t);\n\t\tconst fragmentBody = getBodyLike(fragmentEntity);\n\t\tfragmentBody?.setLinvel(linearVelocity, true);\n\t\tfragmentBody?.setAngvel(\n\t\t\tcomputeFragmentAngularVelocity(\n\t\t\t\tindex,\n\t\t\t\tphysicsOptions.angularVelocity,\n\t\t\t),\n\t\t\ttrue,\n\t\t);\n\n\t\tsyncRuntimeFragmentEntityTransform(\n\t\t\tfragmentEntity,\n\t\t\tworld.interpolationAlpha ?? 0,\n\t\t);\n\n\t\tconst target = fragmentEntity.group ?? fragmentEntity.mesh;\n\t\tif (target) {\n\t\t\ttarget.removeFromParent();\n\t\t\tscene.scene.add(target);\n\t\t}\n\n\t\tfragmentEntities.push(fragmentEntity);\n\t}\n\n\tstate.fragmentEntities = fragmentEntities;\n\tstate.fractureMode = 'independent';\n}\n\nfunction fractureEntity(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n): readonly DestructibleMesh[] {\n\tconst entity = requireEntity(ref);\n\tif (entity.isInstanced) {\n\t\tthrow new Error(\n\t\t\t'Destructible3DBehavior does not support entities using instanced rendering.',\n\t\t);\n\t}\n\n\tconst state = getRuntimeState(ref);\n\tif (state.isFractured) {\n\t\trestoreRuntimeState(ref, true);\n\t}\n\n\tconst sourceMesh = requireEntityMesh(entity);\n\tconst fractureOptions = resolveFractureOptions(\n\t\tref.options.fractureOptions,\n\t\toverrideOptions,\n\t);\n\tconst cacheKey = buildFractureGeometryCacheKey(fractureOptions);\n\n\tconst root = ensureRootGroup(entity, state);\n\tstate.originalMeshParent = sourceMesh.parent;\n\tstate.originalColliderDesc = entity.colliderDesc;\n\tstate.originalColliderDescs = entity.colliderDescs.length > 0\n\t\t? [...entity.colliderDescs]\n\t\t: entity.colliderDesc\n\t\t\t? [entity.colliderDesc]\n\t\t\t: [];\n\tstate.originalMeshVisible = sourceMesh.visible;\n\tstate.originalGroupVisible = entity.group?.visible ?? true;\n\tstate.sourceBodySnapshot = snapshotBody(entity);\n\tstate.sourcePhysicsAttached = entity.physicsAttached;\n\n\tconst usePrebakedFragments =\n\t\tstate.prebakedFractureKey === cacheKey\n\t\t&& state.prebakedFragments.length > 0;\n\tconst source = usePrebakedFragments\n\t\t? null\n\t\t: createFractureSourceMesh(\n\t\t\tsourceMesh,\n\t\t\troot,\n\t\t\tref.options.innerMaterial,\n\t\t);\n\n\ttry {\n\t\tconst fragmentPhysics = resolveFragmentPhysicsOptions(\n\t\t\tref.options.fragmentPhysics,\n\t\t);\n\t\tconst fragments = usePrebakedFragments\n\t\t\t? instantiatePrebakedFragments(\n\t\t\t\tsourceMesh,\n\t\t\t\tref.options.innerMaterial,\n\t\t\t\tstate.prebakedFragments,\n\t\t\t)\n\t\t\t: source!.fracture(fractureOptions);\n\t\tcachePrebakedFragments(state, cacheKey, fragments);\n\n\t\tstate.fragments = [...fragments];\n\t\tstate.isFractured = true;\n\n\t\tif (fragmentPhysics.mode === 'independent') {\n\t\t\tfractureIndependentEntity(\n\t\t\t\tref,\n\t\t\t\tentity,\n\t\t\t\troot,\n\t\t\t\tfractureOptions,\n\t\t\t\tfragments,\n\t\t\t\tstate,\n\t\t\t);\n\t\t} else {\n\t\t\tfractureCompoundEntity(\n\t\t\t\tref,\n\t\t\t\tentity,\n\t\t\t\troot,\n\t\t\t\tfragments,\n\t\t\t\tstate,\n\t\t\t);\n\t\t}\n\n\t\treturn fragments;\n\t} catch (error) {\n\t\trestoreRuntimeState(ref, true);\n\t\tthrow error;\n\t} finally {\n\t\tsource?.geometry.dispose();\n\t}\n}\n\nfunction prebakeEntityGeometryOnly(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n): void {\n\tconst entity = requireEntity(ref);\n\tif (entity.isInstanced) {\n\t\tthrow new Error(\n\t\t\t'Destructible3DBehavior does not support entities using instanced rendering.',\n\t\t);\n\t}\n\n\tconst state = getRuntimeState(ref);\n\tif (state.isFractured) {\n\t\treturn;\n\t}\n\n\tconst fractureOptions = resolveFractureOptions(\n\t\tref.options.fractureOptions,\n\t\toverrideOptions,\n\t);\n\tconst cacheKey = buildFractureGeometryCacheKey(fractureOptions);\n\tif (\n\t\tstate.prebakedFractureKey === cacheKey\n\t\t&& state.prebakedFragments.length > 0\n\t) {\n\t\treturn;\n\t}\n\n\tconst sourceMesh = requireEntityMesh(entity);\n\tconst root = ensureRootGroup(entity, state);\n\tconst createdRootGroup = state.createdRootGroup;\n\n\tconst source = createFractureSourceMesh(\n\t\tsourceMesh,\n\t\troot,\n\t\tref.options.innerMaterial,\n\t);\n\ttry {\n\t\tconst fragments = source.fracture(fractureOptions) as DestructibleMesh[];\n\t\tcachePrebakedFragments(state, cacheKey, fragments);\n\t\tfor (const fragment of fragments) {\n\t\t\tfragment.geometry.dispose();\n\t\t}\n\t} finally {\n\t\tsource.geometry.dispose();\n\t}\n\n\tif (createdRootGroup) {\n\t\trestoreOriginalMesh(entity, state);\n\t\tstate.createdRootGroup = false;\n\t}\n}\n\nasync function prebakeEntityAsync(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n): Promise<void> {\n\tconst workerUrl = ref.options.prebakeWorkerUrl;\n\tif (!workerUrl) {\n\t\tprebakeEntityGeometryOnly(ref, overrideOptions);\n\t\treturn;\n\t}\n\n\tconst existing = prebakeAsyncInFlight.get(ref);\n\tif (existing) {\n\t\tawait existing;\n\t\treturn;\n\t}\n\n\tconst job = (async () => {\n\t\tconst entity = requireEntity(ref);\n\t\tif (entity.isInstanced) {\n\t\t\tthrow new Error(\n\t\t\t\t'Destructible3DBehavior does not support entities using instanced rendering.',\n\t\t\t);\n\t\t}\n\n\t\tconst state = getRuntimeState(ref);\n\t\tif (state.isFractured) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst fractureOptions = resolveFractureOptions(\n\t\t\tref.options.fractureOptions,\n\t\t\toverrideOptions,\n\t\t);\n\t\tconst cacheKey = buildFractureGeometryCacheKey(fractureOptions);\n\t\tif (\n\t\t\tstate.prebakedFractureKey === cacheKey\n\t\t\t&& state.prebakedFragments.length > 0\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst sourceMesh = requireEntityMesh(entity);\n\t\tconst root = ensureRootGroup(entity, state);\n\t\tconst createdRootGroup = state.createdRootGroup;\n\n\t\tconst normalizedGeometry = buildNormalizedFractureSourceGeometry(\n\t\t\tsourceMesh,\n\t\t\troot,\n\t\t);\n\n\t\tif (createdRootGroup) {\n\t\t\trestoreOriginalMesh(entity, state);\n\t\t\tstate.createdRootGroup = false;\n\t\t}\n\n\t\tconst { payload, transferables } = bufferGeometryToPlain(normalizedGeometry);\n\t\tnormalizedGeometry.dispose();\n\n\t\tconst plainOptions = pinataFractureOptionsToPlain(fractureOptions);\n\t\tconst api = getPrebakeWorkerApi(workerUrl);\n\t\tconst request = Comlink.transfer(\n\t\t\t{ geometry: payload, options: plainOptions },\n\t\t\ttransferables,\n\t\t);\n\n\t\tconst response = await api.prebake(request);\n\t\tconst parts = plainWorkerResultToTemplateParts(response);\n\t\tinstallPrebakedTemplateParts(state, cacheKey, parts);\n\t})();\n\n\tprebakeAsyncInFlight.set(ref, job);\n\ttry {\n\t\tawait job;\n\t} finally {\n\t\tif (prebakeAsyncInFlight.get(ref) === job) {\n\t\t\tprebakeAsyncInFlight.delete(ref);\n\t\t}\n\t}\n}\n\nfunction prebakeEntity(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n): void {\n\tprebakeEntityGeometryOnly(ref, overrideOptions);\n}\n\nfunction createDestructible3DHandle(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): Destructible3DHandle {\n\treturn {\n\t\tfracture: (overrideOptions) => fractureEntity(ref, overrideOptions),\n\t\tprebake: (overrideOptions) => {\n\t\t\tprebakeEntity(ref, overrideOptions);\n\t\t},\n\t\tprebakeAsync: (overrideOptions) => prebakeEntityAsync(ref, overrideOptions),\n\t\trepair: () => restoreRuntimeState(ref, true),\n\t\tisFractured: () => getRuntimeState(ref).isFractured,\n\t\tgetFragments: () => getRuntimeState(ref).fragments,\n\t};\n}\n\nclass Destructible3DSystem implements BehaviorSystem {\n\tconstructor(\n\t\tprivate world: unknown,\n\t\tprivate scene: unknown,\n\t\tprivate getBehaviorLinks?: (key: symbol) => Iterable<BehaviorEntityLink>,\n\t\tprivate createEntity?: CreateEntityFn,\n\t\tprivate getGlobals?: () => any,\n\t) {\n\t\tthis.primeLinks();\n\t}\n\n\tattach(link: BehaviorEntityLink): void {\n\t\tif (link.ref?.descriptor?.key !== DESTRUCTIBLE_3D_BEHAVIOR_KEY) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.primeLink(link);\n\t}\n\n\tupdate(_ecs: unknown, _delta: number): void {\n\t\tthis.primeLinks();\n\t\tconst links = this.getBehaviorLinks?.(DESTRUCTIBLE_3D_BEHAVIOR_KEY);\n\t\tif (!links) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst interpolationAlpha =\n\t\t\t(this.world as { interpolationAlpha?: number } | null)?.interpolationAlpha\n\t\t\t?? 0;\n\t\tfor (const link of links) {\n\t\t\tconst state = getRuntimeState(\n\t\t\t\tlink.ref as BehaviorRef<Destructible3DBehaviorOptions>,\n\t\t\t);\n\t\t\tfor (const fragmentEntity of state.fragmentEntities) {\n\t\t\t\tsyncRuntimeFragmentEntityTransform(\n\t\t\t\t\tfragmentEntity,\n\t\t\t\t\tinterpolationAlpha,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tdestroy(_ecs: unknown): void {\n\t\tconst links = this.getBehaviorLinks?.(DESTRUCTIBLE_3D_BEHAVIOR_KEY);\n\t\tif (!links) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const link of links) {\n\t\t\tconst ref = link.ref as BehaviorRef<Destructible3DBehaviorOptions>;\n\t\t\trestoreRuntimeState(ref, false);\n\t\t\tdisposeRuntimeState(getRuntimeState(ref));\n\t\t}\n\t}\n\n\tprivate primeLinks(): void {\n\t\tconst links = this.getBehaviorLinks?.(DESTRUCTIBLE_3D_BEHAVIOR_KEY);\n\t\tif (!links) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const link of links) {\n\t\t\tthis.primeLink(link);\n\t\t}\n\t}\n\n\tprivate primeLink(link: BehaviorEntityLink): void {\n\t\tconst ref = link.ref as BehaviorRef<Destructible3DBehaviorOptions> & {\n\t\t\t__cleanupRegistered?: boolean;\n\t\t};\n\t\tconst entity = link.entity as GameEntity<any>;\n\t\t(ref as any).__entity = entity;\n\t\t(ref as any).__world = this.world;\n\t\t(ref as any).__scene = this.scene;\n\t\t(ref as any).__createEntity = this.createEntity;\n\t\t(ref as any).__getGlobals = this.getGlobals;\n\n\t\tif (!ref.__cleanupRegistered) {\n\t\t\tentity.onCleanup(() => {\n\t\t\t\trestoreRuntimeState(ref, false);\n\t\t\t\tdisposeRuntimeState(getRuntimeState(ref));\n\t\t\t});\n\t\t\tref.__cleanupRegistered = true;\n\t\t}\n\t}\n}\n\nexport const Destructible3DBehavior = defineBehavior<\n\tDestructible3DBehaviorOptions,\n\tDestructible3DHandle\n>({\n\tname: 'destructible-3d',\n\tdefaultOptions,\n\tsystemFactory: (ctx) =>\n\t\tnew Destructible3DSystem(\n\t\t\tctx.world,\n\t\t\tctx.scene,\n\t\t\tctx.getBehaviorLinks,\n\t\t\tctx.createEntity,\n\t\t\tctx.getGlobals,\n\t\t),\n\tcreateHandle: createDestructible3DHandle,\n});\n","export * from './destructible-3d.descriptor';\nexport type {\n\tDestructiblePrebakeWorkerAPI,\n\tPlainBufferGeometryPayload,\n\tPlainFractureOptions,\n\tPrebakeWorkerRequest,\n\tPrebakeWorkerResponse,\n} from '../../destructible-prebake';\nexport {\n\tDestructibleMesh,\n\tFractureOptions,\n\ttype VoronoiOptions,\n} from '@dgreenheck/three-pinata';\n"],"mappings":"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","names":["parent","DestructibleMesh"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/coordinators/boundary-ricochet-3d.coordinator.ts"],"sourcesContent":["import type { MoveableEntity } from '../capabilities/moveable';\nimport type { BaseEntityInterface } from '../types/entity-types';\nimport type { Ricochet3DHandle } from '../behaviors/ricochet-3d/ricochet-3d.descriptor';\nimport type { WorldBoundary3DHandle } from '../behaviors/world-boundary-3d/world-boundary-3d.descriptor';\nimport { getBounds3DNormalFromHits } from '../behaviors/shared/bounds-3d';\nimport { updateBoundaryRicochet } from './shared/boundary-ricochet';\n\n/** Entity shape required by the 3D boundary-ricochet coordinator. */\nexport type BoundaryRicochet3DEntity = BaseEntityInterface & MoveableEntity;\n\n/**\n * Coordinator that bridges WorldBoundary3DBehavior and Ricochet3DBehavior.\n * Snaps the body back to the boundary's clamped position before reflecting,\n * so fast entities can't tunnel outside the box between frames.\n */\nexport class BoundaryRicochet3DCoordinator {\n\tconstructor(\n\t\tprivate entity: BoundaryRicochet3DEntity,\n\t\tprivate boundary: WorldBoundary3DHandle,\n\t\tprivate ricochet: Ricochet3DHandle,\n\t) {}\n\n\tpublic update(): boolean {\n\t\treturn updateBoundaryRicochet({\n\t\t\tgetLastHits: () => this.boundary.getLastHits(),\n\t\t\thasAnyHit: (hits) =>\n\t\t\t\thits.left || hits.right || hits.top || hits.bottom || hits.back || hits.front,\n\t\t\tgetNormal: (hits) => getBounds3DNormalFromHits(hits),\n\t\t\tsnapToClamped: () => {\n\t\t\t\tconst clamped = this.boundary.getLastClampedPosition();\n\t\t\t\tif (clamped && this.entity.body) {\n\t\t\t\t\tthis.entity.body.setTranslation(clamped, true);\n\t\t\t\t}\n\t\t\t},\n\t\t\tapplyRicochet: (normal) =>\n\t\t\t\tthis.ricochet.applyRicochet({\n\t\t\t\t\tentity: this.entity,\n\t\t\t\t\tcontact: { normal },\n\t\t\t\t}),\n\t\t});\n\t}\n}\n"],"mappings":";;;;;;;;AAeO,IAAM,gCAAN,MAAoC;AAAA,EAC1C,YACS,QACA,UACA,UACP;AAHO;AACA;AACA;AAAA,EACN;AAAA,EAHM;AAAA,EACA;AAAA,EACA;AAAA,EAGF,SAAkB;AACxB,WAAO,uBAAuB;AAAA,MAC7B,aAAa,MAAM,KAAK,SAAS,YAAY;AAAA,MAC7C,WAAW,CAAC,SACX,KAAK,QAAQ,KAAK,SAAS,KAAK,OAAO,KAAK,UAAU,KAAK,QAAQ,KAAK;AAAA,MACzE,WAAW,CAAC,SAAS,0BAA0B,IAAI;AAAA,MACnD,eAAe,MAAM;AACpB,cAAM,UAAU,KAAK,SAAS,uBAAuB;AACrD,YAAI,WAAW,KAAK,OAAO,MAAM;AAChC,eAAK,OAAO,KAAK,eAAe,SAAS,IAAI;AAAA,QAC9C;AAAA,MACD;AAAA,MACA,eAAe,CAAC,WACf,KAAK,SAAS,cAAc;AAAA,QAC3B,QAAQ,KAAK;AAAA,QACb,SAAS,EAAE,OAAO;AAAA,MACnB,CAAC;AAAA,IACH,CAAC;AAAA,EACF;AACD;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/coordinators/top-down-shooter.coordinator.ts"],"sourcesContent":["import {\n\tcreateTopDownMovementInputComponent,\n\ttype TopDownMovementInputComponent,\n} from '../behaviors/top-down-movement/components';\nimport type {\n\tShooter2DHandle,\n\tShooter2DSourceEntity,\n\tShooter2DStageLike,\n} from '../behaviors/shooter-2d/shooter-2d.descriptor';\nimport {\n\tfireShooter2DIfRequested,\n\ttype Shooter2DAimFireInput,\n} from './shared/shooter-fire';\n\nexport interface TopDownShooterInput extends Shooter2DAimFireInput {\n\tmoveX: number;\n\tmoveY: number;\n}\n\nexport type TopDownShooterEntity = Shooter2DSourceEntity & {\n\t$topDownMovement?: TopDownMovementInputComponent;\n};\n\n/**\n * Coordinator that fans a single input snapshot out to the top-down movement\n * behavior (move + face axes) and the Shooter2D behavior (fire requests).\n */\nexport class TopDownShooterCoordinator {\n\tconstructor(\n\t\tprivate entity: TopDownShooterEntity,\n\t\tprivate shooter: Shooter2DHandle,\n\t\tprivate stage: Shooter2DStageLike,\n\t) {}\n\n\tpublic update(input: TopDownShooterInput): void {\n\t\tif (!this.entity.$topDownMovement) {\n\t\t\tthis.entity.$topDownMovement = createTopDownMovementInputComponent();\n\t\t}\n\n\t\tthis.entity.$topDownMovement.moveX = input.moveX;\n\t\tthis.entity.$topDownMovement.moveY = input.moveY;\n\t\tthis.entity.$topDownMovement.faceX = input.aimX;\n\t\tthis.entity.$topDownMovement.faceY = input.aimY;\n\n\t\tfireShooter2DIfRequested(this.entity, this.shooter, this.stage, input);\n\t}\n}\n"],"mappings":";;;;;;;;AA2BO,IAAM,4BAAN,MAAgC;AAAA,EACtC,YACS,QACA,SACA,OACP;AAHO;AACA;AACA;AAAA,EACN;AAAA,EAHM;AAAA,EACA;AAAA,EACA;AAAA,EAGF,OAAO,OAAkC;AAC/C,QAAI,CAAC,KAAK,OAAO,kBAAkB;AAClC,WAAK,OAAO,mBAAmB,oCAAoC;AAAA,IACpE;AAEA,SAAK,OAAO,iBAAiB,QAAQ,MAAM;AAC3C,SAAK,OAAO,iBAAiB,QAAQ,MAAM;AAC3C,SAAK,OAAO,iBAAiB,QAAQ,MAAM;AAC3C,SAAK,OAAO,iBAAiB,QAAQ,MAAM;AAE3C,6BAAyB,KAAK,QAAQ,KAAK,SAAS,KAAK,OAAO,KAAK;AAAA,EACtE;AACD;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/coordinators/shared/boundary-ricochet.ts"],"sourcesContent":["/**\n * Shared boundary→ricochet glue used by the 2D and 3D boundary-ricochet\n * coordinators. Reads the boundary behavior's last hits, optionally snaps the\n * body back inside the bounds, and applies the ricochet reflection.\n */\nexport interface BoundaryRicochetUpdate<THits, TNormal> {\n\t/** Boundary behavior handle (or any source of last-frame hits). */\n\tgetLastHits(): THits | null;\n\t/** Whether any boundary face was hit this frame. */\n\thasAnyHit(hits: THits): boolean;\n\t/** Convert hits into a reflection normal. */\n\tgetNormal(hits: THits): TNormal;\n\t/** Optional pre-reflection snap (e.g. clamp the body back inside bounds). */\n\tsnapToClamped?(): void;\n\t/** Apply the reflection; returns true when a ricochet occurred. */\n\tapplyRicochet(normal: TNormal): boolean;\n}\n\nexport function updateBoundaryRicochet<THits, TNormal>(\n\tupdate: BoundaryRicochetUpdate<THits, TNormal>,\n): boolean {\n\tconst hits = update.getLastHits();\n\tif (!hits || !update.hasAnyHit(hits)) return false;\n\n\tupdate.snapToClamped?.();\n\treturn update.applyRicochet(update.getNormal(hits));\n}\n"],"mappings":";AAkBO,SAAS,uBACf,QACU;AACV,QAAM,OAAO,OAAO,YAAY;AAChC,MAAI,CAAC,QAAQ,CAAC,OAAO,UAAU,IAAI,EAAG,QAAO;AAE7C,SAAO,gBAAgB;AACvB,SAAO,OAAO,cAAc,OAAO,UAAU,IAAI,CAAC;AACnD;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/behaviors/jumper-3d/jumper-3d-fsm.ts","../src/lib/behaviors/jumper-3d/jumper-3d.descriptor.ts"],"sourcesContent":["/**\n * Jumper 3D Finite State Machine\n *\n * Three high-level states driven by events emitted from the behavior tick:\n * Grounded ──Jump──▶ Jumping\n * Grounded ──Fall──▶ Falling (walked off a ledge)\n * Jumping ──Fall──▶ Falling (apex / descending)\n * Jumping ──Jump──▶ Jumping (multi-jump)\n * Jumping ──Land──▶ Grounded (rare — very short hop)\n * Falling ──Land──▶ Grounded\n * Falling ──Jump──▶ Jumping (air-jump while falling)\n */\n\nimport { SyncStateMachine, t } from '../../core/utility/sync-state-machine';\nimport type { JumpState3D } from './components';\n\nexport enum Jumper3DState {\n\tGrounded = 'grounded',\n\tJumping = 'jumping',\n\tFalling = 'falling',\n}\n\nexport enum Jumper3DEvent {\n\tJump = 'jump',\n\tFall = 'fall',\n\tLand = 'land',\n}\n\nexport interface Jumper3DFSMContext {\n\tstate: JumpState3D;\n}\n\nexport class Jumper3DFSM {\n\tmachine: SyncStateMachine<Jumper3DState, Jumper3DEvent, never>;\n\n\tconstructor(private ctx: Jumper3DFSMContext) {\n\t\tthis.machine = new SyncStateMachine<Jumper3DState, Jumper3DEvent, never>(\n\t\t\tJumper3DState.Grounded,\n\t\t\t[\n\t\t\t\t// Grounded\n\t\t\t\tt(Jumper3DState.Grounded, Jumper3DEvent.Jump, Jumper3DState.Jumping),\n\t\t\t\tt(Jumper3DState.Grounded, Jumper3DEvent.Fall, Jumper3DState.Falling),\n\t\t\t\tt(Jumper3DState.Grounded, Jumper3DEvent.Land, Jumper3DState.Grounded),\n\n\t\t\t\t// Jumping\n\t\t\t\tt(Jumper3DState.Jumping, Jumper3DEvent.Fall, Jumper3DState.Falling),\n\t\t\t\tt(Jumper3DState.Jumping, Jumper3DEvent.Land, Jumper3DState.Grounded),\n\t\t\t\tt(Jumper3DState.Jumping, Jumper3DEvent.Jump, Jumper3DState.Jumping),\n\n\t\t\t\t// Falling\n\t\t\t\tt(Jumper3DState.Falling, Jumper3DEvent.Land, Jumper3DState.Grounded),\n\t\t\t\tt(Jumper3DState.Falling, Jumper3DEvent.Jump, Jumper3DState.Jumping),\n\t\t\t\tt(Jumper3DState.Falling, Jumper3DEvent.Fall, Jumper3DState.Falling),\n\t\t\t],\n\t\t);\n\t}\n\n\tgetState(): Jumper3DState {\n\t\treturn this.machine.getState();\n\t}\n\n\tdispatch(event: Jumper3DEvent): void {\n\t\tif (this.machine.can(event)) {\n\t\t\tthis.machine.syncDispatch(event);\n\t\t}\n\t}\n\n\tisJumping(): boolean {\n\t\treturn this.getState() === Jumper3DState.Jumping;\n\t}\n\n\tisFalling(): boolean {\n\t\treturn this.getState() === Jumper3DState.Falling;\n\t}\n\n\tisGrounded(): boolean {\n\t\treturn this.getState() === Jumper3DState.Grounded;\n\t}\n\n\tgetJumpsUsed(): number {\n\t\treturn this.ctx.state.jumpsUsed;\n\t}\n\n\t/**\n\t * Translate a tick event into an FSM dispatch.\n\t * Also handles the implicit Grounded→Falling transition when the entity\n\t * is no longer grounded but no explicit event was emitted (e.g. walked\n\t * off a ledge without jumping).\n\t */\n\tapplyTickEvent(tickEvent: string, isGrounded: boolean): void {\n\t\tswitch (tickEvent) {\n\t\t\tcase 'jump':\n\t\t\t\tthis.dispatch(Jumper3DEvent.Jump);\n\t\t\t\tbreak;\n\t\t\tcase 'fall':\n\t\t\t\tthis.dispatch(Jumper3DEvent.Fall);\n\t\t\t\tbreak;\n\t\t\tcase 'land':\n\t\t\t\tthis.dispatch(Jumper3DEvent.Land);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t// No explicit event — detect implicit fall\n\t\t\t\tif (!isGrounded && this.getState() === Jumper3DState.Grounded) {\n\t\t\t\t\tthis.dispatch(Jumper3DEvent.Fall);\n\t\t\t\t}\n\t\t\t\tif (isGrounded && this.getState() !== Jumper3DState.Grounded) {\n\t\t\t\t\tthis.dispatch(Jumper3DEvent.Land);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t}\n}\n","/**\n * Jumper 3D Behavior Descriptor\n *\n * Type-safe descriptor for the jumper-3d behavior system.\n * Provides `entity.use()` API for composable 3D jumping.\n */\n\nimport { defineBehavior } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport { Jumper3DState } from './jumper-3d-fsm';\nimport {\n\tcreateJumpInput3D,\n\ttype JumpConfig3D,\n\ttype JumpInput3D,\n\ttype JumpState3D,\n} from './components';\nimport {\n\tSTAGE_INPUT_BUTTON_JUMP,\n\treadBehaviorSnapshot,\n\ttype BehaviorRuntime,\n} from '../../runtime/wasm-stage-runtime';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Options exposed through entity.use()\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface Jumper3DBehaviorOptions {\n\t/** Desired peak height in world units (default: 2.5) */\n\tjumpHeight?: number;\n\t/** Gravity magnitude applied by the behavior (default: 20) */\n\tgravity?: number;\n\t/** Terminal fall speed (optional) */\n\tmaxFallSpeed?: number;\n\t/** Max concurrent jumps, 1 = single, 2 = double, etc. (default: 1) */\n\tmaxJumps?: number;\n\t/** Reset jump counter on ground (default: true) */\n\tresetJumpsOnGround?: boolean;\n\t/** Reset jump counter on wall contact (default: undefined) */\n\tresetJumpsOnWall?: boolean;\n\t/** Coyote time in ms (default: 100) */\n\tcoyoteTimeMs?: number;\n\t/** Jump buffer in ms (default: 80) */\n\tjumpBufferMs?: number;\n\t/** Min cooldown between jumps in ms (optional) */\n\tminTimeBetweenJumpsMs?: number;\n\t/** Variable jump height config (optional) */\n\tvariableJump?: JumpConfig3D['variableJump'];\n\t/** Planar control config (optional) */\n\tplanar?: JumpConfig3D['planar'];\n\t/** Fall tuning (optional) */\n\tfall?: JumpConfig3D['fall'];\n\t/** Ground-detection ray length (default: 1.0) */\n\tgroundRayLength?: number;\n\t/** Max support distance that counts as grounded and can snap to ground */\n\tsnapToGroundDistance?: number;\n\t/** Enable debug visualization for ground probe rays (default: false) */\n\tdebugGroundProbe?: boolean;\n}\n\nconst defaultOptions: Jumper3DBehaviorOptions = {\n\tjumpHeight: 2.5,\n\tgravity: 20,\n\tmaxJumps: 1,\n\tresetJumpsOnGround: true,\n\tcoyoteTimeMs: 100,\n\tjumpBufferMs: 80,\n\tgroundRayLength: 1.0,\n\tdebugGroundProbe: false,\n};\n\nconst JUMPER_BEHAVIOR_KEY = Symbol.for('zylem:behavior:jumper-3d');\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Entity shape expected by the system\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface Jumper3DEntity {\n\tuuid: string;\n\ttransformStore: import('../../capabilities/transform-store').TransformState;\n\tjumper: JumpConfig3D;\n\t$jumper: JumpInput3D;\n\tjumperState: JumpState3D;\n}\n\nexport function isJumper3DGrounded(params: {\n\tsupportToi?: number | null;\n\tvelocityY: number;\n\tsnapToGroundDistance?: number;\n}): boolean {\n\tif (params.snapToGroundDistance != null) {\n\t\treturn (\n\t\t\tparams.supportToi != null &&\n\t\t\tparams.supportToi <= params.snapToGroundDistance &&\n\t\t\tparams.velocityY <= 0.25\n\t\t);\n\t}\n\n\treturn (\n\t\tparams.supportToi != null &&\n\t\tparams.velocityY > -2.0 &&\n\t\tparams.velocityY < 2.0\n\t);\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Behavior System adapter\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Forwards jump input into the wasm runtime. The Rust `jumper_3d` Stage\n * behavior (ground probe + jump core) is the single simulation path; handles\n * read its state back via the snapshot buffer.\n */\nclass Jumper3DBehaviorSystem implements BehaviorSystem {\n\tprivate attachedRuntimeSlots = new Set<number>();\n\n\tconstructor(\n\t\tprivate wasmStage: BehaviorRuntime | null,\n\t\tprivate getBehaviorLinks?: (key: symbol) => Iterable<BehaviorEntityLink>,\n\t) {}\n\n\tupdate(_ecs: unknown, _delta: number): void {\n\t\tconst links = this.getBehaviorLinks?.(JUMPER_BEHAVIOR_KEY);\n\t\tif (!links) return;\n\n\t\tfor (const link of links) {\n\t\t\tconst gameEntity = link.entity as any;\n\t\t\tconst jumperRef = link.ref as any;\n\n\t\t\tconst options = jumperRef.options as Jumper3DBehaviorOptions;\n\t\t\tconst handle = (gameEntity.runtimeHandle ?? -1) as number;\n\t\t\tif (!this.wasmStage || handle < 0) continue;\n\n\t\t\tif (!gameEntity.$jumper) {\n\t\t\t\tgameEntity.$jumper = createJumpInput3D();\n\t\t\t}\n\n\t\t\tthis.ensureWasmAttached(handle, options);\n\t\t\tjumperRef.__wasmStage = this.wasmStage;\n\t\t\tjumperRef.__entity = gameEntity;\n\t\t\tconst input = gameEntity.$jumper as JumpInput3D;\n\t\t\tconst jumpPressed = !!(input.jumpPressed || input.jumpHeld);\n\t\t\tthis.wasmStage.writeInputButton(handle, STAGE_INPUT_BUTTON_JUMP, jumpPressed);\n\t\t}\n\t}\n\n\tprivate ensureWasmAttached(handle: number, options: Jumper3DBehaviorOptions): void {\n\t\tif (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;\n\t\tconst jumpForce = Math.sqrt(2 * (options.gravity ?? 20) * (options.jumpHeight ?? 2.5));\n\t\tthis.wasmStage.attachJumper3D(handle, {\n\t\t\tjumpForce,\n\t\t\tmaxJumps: options.maxJumps ?? 1,\n\t\t\tgravity: options.gravity ?? 20,\n\t\t\tcoyoteTime: (options.coyoteTimeMs ?? 100) / 1000,\n\t\t\tjumpBufferTime: (options.jumpBufferMs ?? 80) / 1000,\n\t\t});\n\t\tthis.attachedRuntimeSlots.add(handle);\n\t}\n\n\tdestroy(_ecs: unknown): void {\n\t\tthis.attachedRuntimeSlots.clear();\n\t}\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Public descriptor\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Jumper3DBehavior — composable 3D jump behavior.\n *\n * Provides height-based jumping, multi-jump, coyote time, jump buffering,\n * variable jump height, configurable fall gravity, and optional air control.\n *\n * Designed to compose with any movement controller (e.g. FirstPersonBehavior)\n * — the controller writes X/Z velocity and Jumper3DBehavior writes Y velocity.\n *\n * @example\n * ```typescript\n * import { Jumper3DBehavior } from \"@zylem/game-lib/behavior\";\n *\n * const jumper = player.use(Jumper3DBehavior, {\n * jumpHeight: 2.5,\n * gravity: 20,\n * maxJumps: 2,\n * coyoteTimeMs: 100,\n * jumpBufferMs: 80,\n * variableJump: { enabled: true, cutGravityMultiplier: 3 },\n * fall: { fallGravityMultiplier: 1.5 },\n * });\n *\n * player.onUpdate(({ inputs }) => {\n * player.$jumper.jumpPressed = inputs.p1.buttons.A.pressed;\n * player.$jumper.jumpHeld = inputs.p1.buttons.A.held > 0;\n * player.$jumper.jumpReleased = inputs.p1.buttons.A.released;\n *\n * const state = jumper.getState(); // Grounded | Jumping | Falling\n * });\n * ```\n */\nexport const Jumper3DBehavior = defineBehavior<\n\tJumper3DBehaviorOptions,\n\t{\n\t\tgetState: () => Jumper3DState;\n\t\tisJumping: () => boolean;\n\t\tgetJumpsUsed: () => number;\n\t\tgetJumpsRemaining: () => number;\n\t},\n\tJumper3DEntity\n>({\n\tname: 'jumper-3d',\n\tdefaultOptions,\n\tsystemFactory: (ctx) =>\n\t\tnew Jumper3DBehaviorSystem(\n\t\t\tctx.wasmStage ?? null,\n\t\t\tctx.getBehaviorLinks,\n\t\t),\n\t// Handles read the runtime snapshot buffer (previous-step values). The\n\t// Rust behavior is the single source of truth.\n\tcreateHandle: (ref) => {\n\t\tconst jumpsUsed = () => readBehaviorSnapshot(ref)?.jumpCount ?? 0;\n\t\treturn {\n\t\t\tgetState: () => {\n\t\t\t\tconst snapshot = readBehaviorSnapshot(ref);\n\t\t\t\tif (!snapshot) return Jumper3DState.Grounded;\n\t\t\t\tif (snapshot.grounded) return Jumper3DState.Grounded;\n\t\t\t\treturn snapshot.verticalVelocity > 0\n\t\t\t\t\t? Jumper3DState.Jumping\n\t\t\t\t\t: Jumper3DState.Falling;\n\t\t\t},\n\t\t\tisJumping: () => {\n\t\t\t\tconst snapshot = readBehaviorSnapshot(ref);\n\t\t\t\treturn snapshot ? !snapshot.grounded && snapshot.verticalVelocity > 0 : false;\n\t\t\t},\n\t\t\tgetJumpsUsed: jumpsUsed,\n\t\t\tgetJumpsRemaining: () => (ref.options.maxJumps ?? 1) - jumpsUsed(),\n\t\t};\n\t},\n});\n"],"mappings":"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","names":["Jumper3DState","Jumper3DEvent"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/core/vector.ts"],"sourcesContent":["import { Vector2 as ThreeVector2, Vector3 as ThreeVector3 } from 'three';\n\nexport type Vec2 = ThreeVector2;\nexport type Vec3 = ThreeVector3 | Vec3Components;\n\nexport type Vec2Components = { x: number; y: number };\nexport type Vec3Components = { x: number; y: number; z: number };\n\ntype Vec2Tuple = readonly [number?, number?] & { x?: number; y?: number };\ntype Vec3Tuple = readonly [number?, number?, number?] & {\n x?: number;\n y?: number;\n z?: number;\n};\n\nexport type Vec2Input = Vec2 | { x?: number; y?: number } | Vec2Tuple;\nexport type Vec3Input =\n | Vec3\n | { x?: number; y?: number; z?: number }\n | Vec3Tuple;\n\nexport const VEC2_ZERO: Readonly<Vec2Components> = Object.freeze({\n x: 0,\n y: 0,\n});\nexport const VEC2_ONE: Readonly<Vec2Components> = Object.freeze({ x: 1, y: 1 });\nexport const VEC3_ZERO: Readonly<Vec3Components> = Object.freeze({\n x: 0,\n y: 0,\n z: 0,\n});\nexport const VEC3_ONE: Readonly<Vec3Components> = Object.freeze({\n x: 1,\n y: 1,\n z: 1,\n});\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value);\n}\n\nfunction hasVec2Shape(value: unknown): value is { x?: unknown; y?: unknown } {\n return (\n value != null && typeof value === 'object' && ('x' in value || 'y' in value)\n );\n}\n\nfunction hasVec3Shape(\n value: unknown,\n): value is { x?: unknown; y?: unknown; z?: unknown } {\n return (\n value != null &&\n typeof value === 'object' &&\n ('x' in value || 'y' in value || 'z' in value)\n );\n}\n\nfunction getArrayAxis(\n value: readonly unknown[] | undefined,\n index: number,\n fallback: number,\n): number {\n if (!value) {\n return fallback;\n }\n const axis = value[index];\n return isFiniteNumber(axis) ? axis : fallback;\n}\n\nfunction getObjectAxis(\n value: { [key: string]: unknown } | undefined,\n key: 'x' | 'y' | 'z',\n fallback: number,\n): number {\n if (!value) {\n return fallback;\n }\n const axis = value[key];\n return isFiniteNumber(axis) ? axis : fallback;\n}\n\nfunction getVec2Axis(\n value: Vec2Input | Partial<Vec2Components> | null | undefined,\n key: 'x' | 'y',\n index: 0 | 1,\n fallback: number,\n): number {\n if (!value) {\n return fallback;\n }\n if (Array.isArray(value)) {\n return getArrayAxis(value, index, fallback);\n }\n return getObjectAxis(value as { [key: string]: unknown }, key, fallback);\n}\n\nfunction getVec3Axis(\n value: Vec3Input | Partial<Vec3Components> | null | undefined,\n key: 'x' | 'y' | 'z',\n index: 0 | 1 | 2,\n fallback: number,\n): number {\n if (!value) {\n return fallback;\n }\n if (Array.isArray(value)) {\n return getArrayAxis(value, index, fallback);\n }\n return getObjectAxis(value as { [key: string]: unknown }, key, fallback);\n}\n\nfunction normalizeVec2Defaults(\n defaults: Vec2Input | Partial<Vec2Components> | null | undefined,\n): Vec2Components {\n return {\n x: getVec2Axis(defaults, 'x', 0, 0),\n y: getVec2Axis(defaults, 'y', 1, 0),\n };\n}\n\nfunction normalizeVec3Defaults(\n defaults: Vec3Input | Partial<Vec3Components> | null | undefined,\n): Vec3Components {\n return {\n x: getVec3Axis(defaults, 'x', 0, 0),\n y: getVec3Axis(defaults, 'y', 1, 0),\n z: getVec3Axis(defaults, 'z', 2, 0),\n };\n}\n\nexport function isVec2Input(value: unknown): value is Vec2Input {\n return Array.isArray(value) || hasVec2Shape(value);\n}\n\nexport function isVec3Input(value: unknown): value is Vec3Input {\n return Array.isArray(value) || hasVec3Shape(value);\n}\n\nexport function normalizeVec2(\n input?: Vec2Input | null,\n defaults: Vec2Input | Partial<Vec2Components> = VEC2_ZERO,\n): Vec2Components {\n const fallback = normalizeVec2Defaults(defaults);\n return {\n x: getVec2Axis(input, 'x', 0, fallback.x),\n y: getVec2Axis(input, 'y', 1, fallback.y),\n };\n}\n\nexport function normalizeVec3(\n input?: Vec3Input | null,\n defaults: Vec3Input | Partial<Vec3Components> = VEC3_ZERO,\n): Vec3Components {\n const fallback = normalizeVec3Defaults(defaults);\n return {\n x: getVec3Axis(input, 'x', 0, fallback.x),\n y: getVec3Axis(input, 'y', 1, fallback.y),\n z: getVec3Axis(input, 'z', 2, fallback.z),\n };\n}\n\nexport function toThreeVector2(\n input?: Vec2Input | null,\n defaults: Vec2Input | Partial<Vec2Components> = VEC2_ZERO,\n): ThreeVector2 {\n const { x, y } = normalizeVec2(input, defaults);\n return new ThreeVector2(x, y);\n}\n\nexport function toThreeVector3(\n input?: Vec3Input | null,\n defaults: Vec3Input | Partial<Vec3Components> = VEC3_ZERO,\n): ThreeVector3 {\n const { x, y, z } = normalizeVec3(input, defaults);\n return new ThreeVector3(x, y, z);\n}\n\n"],"mappings":";AAAA,SAAS,WAAW,cAAc,WAAW,oBAAoB;AAqB1D,IAAM,YAAsC,OAAO,OAAO;AAAA,EAC/D,GAAG;AAAA,EACH,GAAG;AACL,CAAC;AACM,IAAM,WAAqC,OAAO,OAAO,EAAE,GAAG,GAAG,GAAG,EAAE,CAAC;AACvE,IAAM,YAAsC,OAAO,OAAO;AAAA,EAC/D,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AACL,CAAC;AACM,IAAM,WAAqC,OAAO,OAAO;AAAA,EAC9D,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AACL,CAAC;AAED,SAAS,eAAe,OAAiC;AACvD,SAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK;AAC3D;AAEA,SAAS,aAAa,OAAuD;AAC3E,SACE,SAAS,QAAQ,OAAO,UAAU,aAAa,OAAO,SAAS,OAAO;AAE1E;AAEA,SAAS,aACP,OACoD;AACpD,SACE,SAAS,QACT,OAAO,UAAU,aAChB,OAAO,SAAS,OAAO,SAAS,OAAO;AAE5C;AAEA,SAAS,aACP,OACA,OACA,UACQ;AACR,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AACA,QAAM,OAAO,MAAM,KAAK;AACxB,SAAO,eAAe,IAAI,IAAI,OAAO;AACvC;AAEA,SAAS,cACP,OACA,KACA,UACQ;AACR,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AACA,QAAM,OAAO,MAAM,GAAG;AACtB,SAAO,eAAe,IAAI,IAAI,OAAO;AACvC;AAEA,SAAS,YACP,OACA,KACA,OACA,UACQ;AACR,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AACA,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,WAAO,aAAa,OAAO,OAAO,QAAQ;AAAA,EAC5C;AACA,SAAO,cAAc,OAAqC,KAAK,QAAQ;AACzE;AAEA,SAAS,YACP,OACA,KACA,OACA,UACQ;AACR,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AACA,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,WAAO,aAAa,OAAO,OAAO,QAAQ;AAAA,EAC5C;AACA,SAAO,cAAc,OAAqC,KAAK,QAAQ;AACzE;AAEA,SAAS,sBACP,UACgB;AAChB,SAAO;AAAA,IACL,GAAG,YAAY,UAAU,KAAK,GAAG,CAAC;AAAA,IAClC,GAAG,YAAY,UAAU,KAAK,GAAG,CAAC;AAAA,EACpC;AACF;AAEA,SAAS,sBACP,UACgB;AAChB,SAAO;AAAA,IACL,GAAG,YAAY,UAAU,KAAK,GAAG,CAAC;AAAA,IAClC,GAAG,YAAY,UAAU,KAAK,GAAG,CAAC;AAAA,IAClC,GAAG,YAAY,UAAU,KAAK,GAAG,CAAC;AAAA,EACpC;AACF;AAEO,SAAS,YAAY,OAAoC;AAC9D,SAAO,MAAM,QAAQ,KAAK,KAAK,aAAa,KAAK;AACnD;AAEO,SAAS,YAAY,OAAoC;AAC9D,SAAO,MAAM,QAAQ,KAAK,KAAK,aAAa,KAAK;AACnD;AAEO,SAAS,cACd,OACA,WAAgD,WAChC;AAChB,QAAM,WAAW,sBAAsB,QAAQ;AAC/C,SAAO;AAAA,IACL,GAAG,YAAY,OAAO,KAAK,GAAG,SAAS,CAAC;AAAA,IACxC,GAAG,YAAY,OAAO,KAAK,GAAG,SAAS,CAAC;AAAA,EAC1C;AACF;AAEO,SAAS,cACd,OACA,WAAgD,WAChC;AAChB,QAAM,WAAW,sBAAsB,QAAQ;AAC/C,SAAO;AAAA,IACL,GAAG,YAAY,OAAO,KAAK,GAAG,SAAS,CAAC;AAAA,IACxC,GAAG,YAAY,OAAO,KAAK,GAAG,SAAS,CAAC;AAAA,IACxC,GAAG,YAAY,OAAO,KAAK,GAAG,SAAS,CAAC;AAAA,EAC1C;AACF;AAEO,SAAS,eACd,OACA,WAAgD,WAClC;AACd,QAAM,EAAE,GAAG,EAAE,IAAI,cAAc,OAAO,QAAQ;AAC9C,SAAO,IAAI,aAAa,GAAG,CAAC;AAC9B;AAEO,SAAS,eACd,OACA,WAAgD,WAClC;AACd,QAAM,EAAE,GAAG,GAAG,EAAE,IAAI,cAAc,OAAO,QAAQ;AACjD,SAAO,IAAI,aAAa,GAAG,GAAG,CAAC;AACjC;","names":[]}
|