ecspresso 0.14.6 → 0.14.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.
Files changed (72) hide show
  1. package/dist/index.js +2 -2
  2. package/dist/index.js.map +2 -2
  3. package/dist/plugins/ai/behavior-tree.js +2 -2
  4. package/dist/plugins/ai/behavior-tree.js.map +2 -2
  5. package/dist/plugins/ai/detection.js +2 -2
  6. package/dist/plugins/ai/detection.js.map +2 -2
  7. package/dist/plugins/ai/flocking.js +2 -2
  8. package/dist/plugins/ai/flocking.js.map +2 -2
  9. package/dist/plugins/ai/pathfinding.js +2 -2
  10. package/dist/plugins/ai/pathfinding.js.map +2 -2
  11. package/dist/plugins/audio/audio.js +2 -2
  12. package/dist/plugins/audio/audio.js.map +2 -2
  13. package/dist/plugins/combat/health.js +2 -2
  14. package/dist/plugins/combat/health.js.map +2 -2
  15. package/dist/plugins/combat/projectile.js +2 -2
  16. package/dist/plugins/combat/projectile.js.map +2 -2
  17. package/dist/plugins/debug/diagnostics.js +3 -3
  18. package/dist/plugins/debug/diagnostics.js.map +2 -2
  19. package/dist/plugins/input/input.js +2 -2
  20. package/dist/plugins/input/input.js.map +2 -2
  21. package/dist/plugins/input/selection.js +2 -2
  22. package/dist/plugins/input/selection.js.map +2 -2
  23. package/dist/plugins/isometric/depth-sort.js +2 -2
  24. package/dist/plugins/isometric/depth-sort.js.map +2 -2
  25. package/dist/plugins/isometric/projection.js +2 -2
  26. package/dist/plugins/isometric/projection.js.map +2 -2
  27. package/dist/plugins/physics/collision.js +2 -2
  28. package/dist/plugins/physics/collision.js.map +2 -2
  29. package/dist/plugins/physics/collision3D.js +2 -2
  30. package/dist/plugins/physics/collision3D.js.map +2 -2
  31. package/dist/plugins/physics/physics2D.js +2 -2
  32. package/dist/plugins/physics/physics2D.js.map +2 -2
  33. package/dist/plugins/physics/physics3D.js +2 -2
  34. package/dist/plugins/physics/physics3D.js.map +2 -2
  35. package/dist/plugins/physics/steering.js +2 -2
  36. package/dist/plugins/physics/steering.js.map +2 -2
  37. package/dist/plugins/rendering/particles.js +2 -2
  38. package/dist/plugins/rendering/particles.js.map +2 -2
  39. package/dist/plugins/rendering/renderer2D.js +2 -2
  40. package/dist/plugins/rendering/renderer2D.js.map +2 -2
  41. package/dist/plugins/rendering/renderer3D.js +2 -4105
  42. package/dist/plugins/rendering/renderer3D.js.map +3 -5
  43. package/dist/plugins/rendering/sprite-animation.js +2 -2
  44. package/dist/plugins/rendering/sprite-animation.js.map +2 -2
  45. package/dist/plugins/rendering/tilemap.js +2 -2
  46. package/dist/plugins/rendering/tilemap.js.map +2 -2
  47. package/dist/plugins/scripting/coroutine.js +2 -2
  48. package/dist/plugins/scripting/coroutine.js.map +2 -2
  49. package/dist/plugins/scripting/state-machine.js +2 -2
  50. package/dist/plugins/scripting/state-machine.js.map +2 -2
  51. package/dist/plugins/scripting/timers.js +2 -2
  52. package/dist/plugins/scripting/timers.js.map +2 -2
  53. package/dist/plugins/scripting/tween.js +2 -2
  54. package/dist/plugins/scripting/tween.js.map +2 -2
  55. package/dist/plugins/spatial/bounds.js +2 -2
  56. package/dist/plugins/spatial/bounds.js.map +2 -2
  57. package/dist/plugins/spatial/camera.js +2 -2
  58. package/dist/plugins/spatial/camera.js.map +2 -2
  59. package/dist/plugins/spatial/camera3D.js +2 -2
  60. package/dist/plugins/spatial/camera3D.js.map +2 -2
  61. package/dist/plugins/spatial/spatial-index.js +2 -2
  62. package/dist/plugins/spatial/spatial-index.js.map +2 -2
  63. package/dist/plugins/spatial/spatial-index3D.js +2 -2
  64. package/dist/plugins/spatial/spatial-index3D.js.map +2 -2
  65. package/dist/plugins/spatial/transform.js +2 -2
  66. package/dist/plugins/spatial/transform.js.map +2 -2
  67. package/dist/plugins/spatial/transform3D.js +2 -2
  68. package/dist/plugins/spatial/transform3D.js.map +2 -2
  69. package/dist/plugins/ui/ui.d.ts +40 -8
  70. package/dist/plugins/ui/ui.js +2 -2
  71. package/dist/plugins/ui/ui.js.map +3 -3
  72. package/package.json +1 -1
@@ -4,7 +4,7 @@
4
4
  "sourcesContent": [
5
5
  "/**\n * Behavior Tree Plugin for ECSpresso\n *\n * Provides composable, priority-driven AI via behavior trees. Shared immutable\n * tree definitions drive per-entity runtime state. Uses hybrid traversal\n * (Approach C): re-evaluate from root each tick to preserve priority, resume\n * running leaves, and abort diverged running nodes via `onAbort`.\n *\n * Each entity gets a `behaviorTree` component referencing a shared definition\n * plus a typed blackboard for per-entity AI memory. One system processes all\n * behavior-tree entities each tick.\n *\n * Node types:\n * Composites — sequence, selector, parallel\n * Decorators — inverter, repeat, cooldown, guard\n * Leaves — action (tick → NodeStatus, optional onAbort), condition (predicate)\n */\n\nimport { definePlugin, type BasePluginOptions, type WorldConfigFrom, type BaseWorld } from 'ecspresso';\n\n// ==================== NodeStatus ====================\n\n/**\n * Return value from behavior tree node ticks.\n *\n * - `Success` (0) — node completed successfully\n * - `Failure` (1) — node failed\n * - `Running` (2) — node still executing, will resume next tick\n */\nexport const NodeStatus = { Success: 0, Failure: 1, Running: 2 } as const;\nexport type NodeStatus = (typeof NodeStatus)[keyof typeof NodeStatus];\n\n// ==================== Callback Context ====================\n\n/** BaseWorld narrowed to behavior-tree components for typed access in helpers. */\ntype BehaviorTreeWorld = BaseWorld<BehaviorTreeComponentTypes>;\n\n/**\n * Context passed to all leaf node callbacks (action tick, condition check,\n * onAbort, guard predicates).\n *\n * @template BB - Blackboard type for per-entity AI memory\n * @template W - World interface type (default: BehaviorTreeWorld)\n */\nexport interface BehaviorTreeContext<\n\tBB extends object = Record<string, unknown>,\n\tW extends BaseWorld<BehaviorTreeComponentTypes> = BehaviorTreeWorld,\n> {\n\treadonly ecs: W;\n\treadonly entityId: number;\n\treadonly dt: number;\n\treadonly blackboard: BB;\n}\n\n// ==================== Node Types ====================\n\n/**\n * Action leaf — executes behavior each tick.\n * Returns `Running` for multi-frame actions. Optional `onAbort` fires\n * when a higher-priority branch preempts this running action.\n */\nexport interface ActionNode<BB extends object = Record<string, unknown>> {\n\treadonly type: 'action';\n\treadonly name: string;\n\treadonly tick: (ctx: BehaviorTreeContext<BB>) => NodeStatus;\n\treadonly onAbort?: (ctx: BehaviorTreeContext<BB>) => void;\n\tnodeIndex: number;\n}\n\n/**\n * Condition leaf — checks a predicate. Returns Success or Failure, never Running.\n */\nexport interface ConditionNode<BB extends object = Record<string, unknown>> {\n\treadonly type: 'condition';\n\treadonly name: string;\n\treadonly check: (ctx: BehaviorTreeContext<BB>) => boolean;\n\tnodeIndex: number;\n}\n\n/**\n * Sequence composite — runs children left-to-right.\n * Fails on first failure, succeeds when all succeed.\n * Resumes from stored child index when a running node exists.\n */\nexport interface SequenceNode<BB extends object = Record<string, unknown>> {\n\treadonly type: 'sequence';\n\treadonly children: readonly BehaviorTreeNode<BB>[];\n\tnodeIndex: number;\n}\n\n/**\n * Selector composite — runs children left-to-right.\n * Succeeds on first success, fails when all fail.\n * Always re-evaluates from child 0 to preserve priority ordering.\n */\nexport interface SelectorNode<BB extends object = Record<string, unknown>> {\n\treadonly type: 'selector';\n\treadonly children: readonly BehaviorTreeNode<BB>[];\n\tnodeIndex: number;\n}\n\n/**\n * Parallel composite — ticks all children each frame.\n * Configurable success/failure thresholds.\n *\n * Limitation (v1): only one running leaf is tracked for abort.\n * Other running children in a parallel stop being ticked if the\n * tree path diverges but do not receive an `onAbort` call.\n */\nexport interface ParallelNode<BB extends object = Record<string, unknown>> {\n\treadonly type: 'parallel';\n\treadonly children: readonly BehaviorTreeNode<BB>[];\n\treadonly successThreshold: number;\n\treadonly failureThreshold: number;\n\tnodeIndex: number;\n}\n\n/** Decorator — inverts child result (Success↔Failure), passes Running through. */\nexport interface InverterNode<BB extends object = Record<string, unknown>> {\n\treadonly type: 'inverter';\n\treadonly child: BehaviorTreeNode<BB>;\n\tnodeIndex: number;\n}\n\n/** Decorator — repeats child `count` times (or forever when count is -1). */\nexport interface RepeatNode<BB extends object = Record<string, unknown>> {\n\treadonly type: 'repeat';\n\treadonly child: BehaviorTreeNode<BB>;\n\treadonly count: number;\n\tnodeIndex: number;\n}\n\n/** Decorator — prevents child re-entry for `duration` seconds after completion. */\nexport interface CooldownNode<BB extends object = Record<string, unknown>> {\n\treadonly type: 'cooldown';\n\treadonly child: BehaviorTreeNode<BB>;\n\treadonly duration: number;\n\tnodeIndex: number;\n}\n\n/** Decorator — conditional gate. Ticks child only when condition passes. */\nexport interface GuardNode<BB extends object = Record<string, unknown>> {\n\treadonly type: 'guard';\n\treadonly child: BehaviorTreeNode<BB>;\n\treadonly condition: (ctx: BehaviorTreeContext<BB>) => boolean;\n\tnodeIndex: number;\n}\n\n/** Union of all behavior tree node types. */\nexport type BehaviorTreeNode<BB extends object = Record<string, unknown>> =\n\t| ActionNode<BB>\n\t| ConditionNode<BB>\n\t| SequenceNode<BB>\n\t| SelectorNode<BB>\n\t| ParallelNode<BB>\n\t| InverterNode<BB>\n\t| RepeatNode<BB>\n\t| CooldownNode<BB>\n\t| GuardNode<BB>;\n\n// ==================== Builder Functions ====================\n\n/**\n * Create an action leaf node.\n *\n * @param name - Human-readable name (used in abort events)\n * @param tick - Called each frame while this node is active; return NodeStatus\n * @param options - Optional `onAbort` callback fired when preempted by a higher-priority branch\n */\nexport function action<BB extends object>(\n\tname: string,\n\ttick: (ctx: BehaviorTreeContext<BB>) => NodeStatus,\n\toptions?: { onAbort?: (ctx: BehaviorTreeContext<BB>) => void },\n): ActionNode<BB> {\n\treturn { type: 'action', name, tick, onAbort: options?.onAbort, nodeIndex: -1 };\n}\n\n/**\n * Create a condition leaf node.\n *\n * @param name - Human-readable name\n * @param check - Predicate returning true (Success) or false (Failure). Never Running.\n */\nexport function condition<BB extends object>(\n\tname: string,\n\tcheck: (ctx: BehaviorTreeContext<BB>) => boolean,\n): ConditionNode<BB> {\n\treturn { type: 'condition', name, check, nodeIndex: -1 };\n}\n\n/**\n * Create a sequence composite. Runs children L→R, fails on first failure.\n */\nexport function sequence<BB extends object>(\n\tchildren: BehaviorTreeNode<BB>[],\n): SequenceNode<BB> {\n\treturn { type: 'sequence', children, nodeIndex: -1 };\n}\n\n/**\n * Create a selector composite. Runs children L→R, succeeds on first success.\n * Always starts from child 0 to re-evaluate priority.\n */\nexport function selector<BB extends object>(\n\tchildren: BehaviorTreeNode<BB>[],\n): SelectorNode<BB> {\n\treturn { type: 'selector', children, nodeIndex: -1 };\n}\n\n/**\n * Create a parallel composite. Ticks all children each frame.\n *\n * @param children - Child nodes to tick in parallel\n * @param options.successThreshold - Successes needed for parallel to succeed (default: all)\n * @param options.failureThreshold - Failures needed for parallel to fail (default: all)\n */\nexport function parallel<BB extends object>(\n\tchildren: BehaviorTreeNode<BB>[],\n\toptions?: { successThreshold?: number; failureThreshold?: number },\n): ParallelNode<BB> {\n\treturn {\n\t\ttype: 'parallel',\n\t\tchildren,\n\t\tsuccessThreshold: options?.successThreshold ?? children.length,\n\t\tfailureThreshold: options?.failureThreshold ?? children.length,\n\t\tnodeIndex: -1,\n\t};\n}\n\n/** Create an inverter decorator. Flips Success↔Failure, passes Running. */\nexport function inverter<BB extends object>(\n\tchild: BehaviorTreeNode<BB>,\n): InverterNode<BB> {\n\treturn { type: 'inverter', child, nodeIndex: -1 };\n}\n\n/**\n * Create a repeat decorator.\n *\n * @param child - Node to repeat\n * @param count - Number of repetitions, or -1 for infinite (default: -1)\n */\nexport function repeat<BB extends object>(\n\tchild: BehaviorTreeNode<BB>,\n\tcount = -1,\n): RepeatNode<BB> {\n\treturn { type: 'repeat', child, count, nodeIndex: -1 };\n}\n\n/**\n * Create a cooldown decorator. Prevents re-entry for `duration` seconds\n * after child completes (Success or Failure).\n */\nexport function cooldown<BB extends object>(\n\tchild: BehaviorTreeNode<BB>,\n\tduration: number,\n): CooldownNode<BB> {\n\treturn { type: 'cooldown', child, duration, nodeIndex: -1 };\n}\n\n/**\n * Create a guard decorator. Ticks child only when condition returns true.\n * Returns Failure when condition is false.\n */\nexport function guard<BB extends object>(\n\tcond: (ctx: BehaviorTreeContext<BB>) => boolean,\n\tchild: BehaviorTreeNode<BB>,\n): GuardNode<BB> {\n\treturn { type: 'guard', condition: cond, child, nodeIndex: -1 };\n}\n\n// ==================== Definition ====================\n\n/**\n * Immutable behavior tree definition. Shared across entities.\n *\n * @template BB - Blackboard type for per-entity AI memory\n */\nexport interface BehaviorTreeDefinition<BB extends object = Record<string, unknown>> {\n\treadonly id: string;\n\treadonly root: BehaviorTreeNode<BB>;\n\treadonly nodeCount: number;\n}\n\n/** Internal storage for definition data not exposed on the public interface. */\nconst defFlatNodes = new WeakMap<BehaviorTreeDefinition<object>, readonly BehaviorTreeNode<object>[]>();\nconst defDefaultBB = new WeakMap<BehaviorTreeDefinition<object>, object>();\n\n/**\n * Define a behavior tree with a typed blackboard.\n *\n * The `blackboard` value serves as both the type source and the default\n * initial state cloned for each entity via `createBehaviorTree`.\n *\n * @param id - Unique identifier for this tree definition\n * @param config - `{ blackboard, root }` — default blackboard + root node\n * @returns Frozen BehaviorTreeDefinition\n *\n * @example\n * ```typescript\n * const tree = defineBehaviorTree('patrol', {\n * blackboard: { targetId: null as number | null, timer: 0 },\n * root: selector([\n * guard(ctx => ctx.blackboard.targetId !== null, action('chase', ...)),\n * action('wander', ...),\n * ]),\n * });\n * ```\n */\nexport function defineBehaviorTree<BB extends object>(\n\tid: string,\n\tconfig: { blackboard: BB; root: BehaviorTreeNode<BB> },\n): BehaviorTreeDefinition<BB> {\n\tlet nextIndex = 0;\n\tconst flatNodes: BehaviorTreeNode<BB>[] = [];\n\n\tfunction indexTree(node: BehaviorTreeNode<BB>): void {\n\t\tnode.nodeIndex = nextIndex;\n\t\tflatNodes[nextIndex] = node;\n\t\tnextIndex++;\n\t\tif ('children' in node) {\n\t\t\tfor (const child of node.children) indexTree(child);\n\t\t}\n\t\tif ('child' in node) {\n\t\t\tindexTree(node.child);\n\t\t}\n\t}\n\tindexTree(config.root);\n\n\tconst def: BehaviorTreeDefinition<BB> = Object.freeze({ id, root: config.root, nodeCount: nextIndex });\n\tdefFlatNodes.set(def as BehaviorTreeDefinition<object>, flatNodes as readonly BehaviorTreeNode<object>[]);\n\tdefDefaultBB.set(def as BehaviorTreeDefinition<object>, config.blackboard);\n\treturn def;\n}\n\n// ==================== Per-Entity Component ====================\n\n/**\n * Runtime behavior tree state stored on each entity.\n *\n * The `blackboard` is typed as `object` at the component level.\n * Inside tree callbacks, the `BehaviorTreeContext<BB>` provides\n * typed access to the blackboard via the tree definition's generic.\n * Outside the tree, cast the blackboard to the specific BB type.\n */\nexport interface BehaviorTreeComponent {\n\treadonly definition: BehaviorTreeDefinition<Record<string, unknown>>;\n\tblackboard: object;\n\t/** Index of the currently running leaf, or -1 if none. */\n\trunningNodeIndex: number;\n\t/**\n\t * Dense per-node state array (sized to `definition.nodeCount`).\n\t * Semantics vary by node type:\n\t * - sequence/selector: child progress index\n\t * - repeat: completed iteration count\n\t * - cooldown: expiry timestamp (elapsedTime when cooldown ends)\n\t */\n\tnodeState: Float64Array;\n\t/** Accumulated time (seconds) for cooldown tracking. */\n\telapsedTime: number;\n}\n\n/**\n * Component types provided by the behavior tree plugin.\n */\nexport interface BehaviorTreeComponentTypes {\n\tbehaviorTree: BehaviorTreeComponent;\n}\n\n// ==================== Event Types ====================\n\n/**\n * Event published when a running action is preempted (aborted) by a\n * higher-priority branch taking over.\n */\nexport interface BehaviorTreeAbortEvent {\n\tentityId: number;\n\t/** nodeIndex of the aborted action */\n\tnodeIndex: number;\n\t/** Human-readable name of the aborted action */\n\tnodeName: string;\n\t/** Definition id of the behavior tree */\n\tdefinitionId: string;\n}\n\n/**\n * Event types provided by the behavior tree plugin.\n */\nexport interface BehaviorTreeEventTypes {\n\tbehaviorTreeAbort: BehaviorTreeAbortEvent;\n}\n\n// ==================== WorldConfig ====================\n\n/**\n * WorldConfig representing the behavior tree plugin's provided types.\n */\nexport type BehaviorTreeWorldConfig = WorldConfigFrom<BehaviorTreeComponentTypes, BehaviorTreeEventTypes>;\n\n// ==================== Helper Functions ====================\n\n/**\n * Create a `behaviorTree` component from a definition.\n *\n * @param definition - Shared tree definition\n * @param blackboard - Optional partial overrides for the default blackboard\n * @returns Component object suitable for spreading into spawn()\n *\n * @example\n * ```typescript\n * ecs.spawn({\n * ...createBehaviorTree(villagerTree, { hunger: 80 }),\n * ...createLocalTransform(100, 200),\n * });\n * ```\n */\nexport function createBehaviorTree<BB extends object>(\n\tdefinition: BehaviorTreeDefinition<BB>,\n\tblackboard?: Partial<BB>,\n): Pick<BehaviorTreeComponentTypes, 'behaviorTree'> {\n\tconst defaultBB = defDefaultBB.get(definition as BehaviorTreeDefinition<object>) as BB;\n\tconst bb = { ...defaultBB, ...blackboard };\n\treturn {\n\t\tbehaviorTree: {\n\t\t\tdefinition: definition as BehaviorTreeDefinition<Record<string, unknown>>,\n\t\t\tblackboard: bb,\n\t\t\trunningNodeIndex: -1,\n\t\t\tnodeState: new Float64Array(definition.nodeCount),\n\t\t\telapsedTime: 0,\n\t\t},\n\t};\n}\n\n/**\n * Check whether an entity's behavior tree has a running action.\n */\nexport function isBehaviorTreeRunning(\n\tecs: { getComponent(entityId: number, name: 'behaviorTree'): BehaviorTreeComponent | undefined },\n\tentityId: number,\n): boolean {\n\tconst bt = ecs.getComponent(entityId, 'behaviorTree');\n\treturn bt !== undefined && bt.runningNodeIndex !== -1;\n}\n\n/**\n * Reset an entity's behavior tree: abort any running action, clear all\n * composite progress, and optionally reset the blackboard.\n */\nexport function resetBehaviorTree(\n\tecs: BehaviorTreeWorld,\n\tentityId: number,\n\tblackboard?: Partial<Record<string, unknown>>,\n): void {\n\tconst bt = ecs.getComponent(entityId, 'behaviorTree');\n\tif (!bt) return;\n\n\tif (bt.runningNodeIndex !== -1) {\n\t\tconst flatNodes = defFlatNodes.get(bt.definition as BehaviorTreeDefinition<object>);\n\t\tconst node = flatNodes?.[bt.runningNodeIndex];\n\t\tif (node && node.type === 'action' && node.onAbort) {\n\t\t\tnode.onAbort({ ecs, entityId, dt: 0, blackboard: bt.blackboard as Record<string, unknown> });\n\t\t}\n\t\tbt.runningNodeIndex = -1;\n\t}\n\tbt.nodeState.fill(0);\n\tbt.elapsedTime = 0;\n\n\tif (blackboard) {\n\t\tObject.assign(bt.blackboard, blackboard);\n\t}\n}\n\n// ==================== Internal: Traversal ====================\n\n/** Internal shorthand — all runtime traversal uses the erased base types. */\ntype AnyNode = BehaviorTreeNode<Record<string, unknown>>;\n\n/** Mutable version of context for pre-allocation in the system loop. */\ninterface MutableCtx {\n\tecs: BehaviorTreeWorld;\n\tentityId: number;\n\tdt: number;\n\tblackboard: Record<string, unknown>;\n}\n\nfunction abortRunningNode(bt: BehaviorTreeComponent, ctx: MutableCtx): void {\n\tconst flatNodes = defFlatNodes.get(bt.definition as BehaviorTreeDefinition<object>);\n\tconst node = flatNodes?.[bt.runningNodeIndex] as AnyNode | undefined;\n\tif (node && node.type === 'action') {\n\t\tnode.onAbort?.(ctx);\n\t\tctx.ecs.eventBus.publish('behaviorTreeAbort', {\n\t\t\tentityId: ctx.entityId,\n\t\t\tnodeIndex: bt.runningNodeIndex,\n\t\t\tnodeName: node.name,\n\t\t\tdefinitionId: bt.definition.id,\n\t\t} satisfies BehaviorTreeAbortEvent);\n\t}\n\tbt.nodeState.fill(0);\n\tbt.runningNodeIndex = -1;\n}\n\nfunction tickNode(node: AnyNode, bt: BehaviorTreeComponent, ctx: MutableCtx): NodeStatus {\n\tswitch (node.type) {\n\t\tcase 'condition':\n\t\t\treturn node.check(ctx) ? NodeStatus.Success : NodeStatus.Failure;\n\n\t\tcase 'action': {\n\t\t\tconst result = node.tick(ctx);\n\t\t\tif (result === NodeStatus.Running) {\n\t\t\t\tif (bt.runningNodeIndex !== -1 && bt.runningNodeIndex !== node.nodeIndex) {\n\t\t\t\t\tabortRunningNode(bt, ctx);\n\t\t\t\t}\n\t\t\t\tbt.runningNodeIndex = node.nodeIndex;\n\t\t\t} else if (bt.runningNodeIndex === node.nodeIndex) {\n\t\t\t\tbt.runningNodeIndex = -1;\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\tcase 'sequence': {\n\t\t\tconst startChild = (bt.runningNodeIndex !== -1)\n\t\t\t\t? (bt.nodeState[node.nodeIndex] ?? 0)\n\t\t\t\t: 0;\n\t\t\tfor (let i = startChild; i < node.children.length; i++) {\n\t\t\t\tconst status = tickNode(node.children[i]!, bt, ctx);\n\t\t\t\tif (status === NodeStatus.Failure) {\n\t\t\t\t\tbt.nodeState[node.nodeIndex] = 0;\n\t\t\t\t\treturn NodeStatus.Failure;\n\t\t\t\t}\n\t\t\t\tif (status === NodeStatus.Running) {\n\t\t\t\t\tbt.nodeState[node.nodeIndex] = i;\n\t\t\t\t\treturn NodeStatus.Running;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbt.nodeState[node.nodeIndex] = 0;\n\t\t\treturn NodeStatus.Success;\n\t\t}\n\n\t\tcase 'selector': {\n\t\t\tfor (let i = 0; i < node.children.length; i++) {\n\t\t\t\tconst status = tickNode(node.children[i]!, bt, ctx);\n\t\t\t\tif (status === NodeStatus.Success) return NodeStatus.Success;\n\t\t\t\tif (status === NodeStatus.Running) return NodeStatus.Running;\n\t\t\t}\n\t\t\treturn NodeStatus.Failure;\n\t\t}\n\n\t\tcase 'parallel': {\n\t\t\tlet successCount = 0;\n\t\t\tlet failureCount = 0;\n\t\t\tlet anyRunning = false;\n\t\t\tfor (let i = 0; i < node.children.length; i++) {\n\t\t\t\tconst status = tickNode(node.children[i]!, bt, ctx);\n\t\t\t\tif (status === NodeStatus.Success) successCount++;\n\t\t\t\telse if (status === NodeStatus.Failure) failureCount++;\n\t\t\t\telse anyRunning = true;\n\t\t\t}\n\t\t\tif (successCount >= node.successThreshold) return NodeStatus.Success;\n\t\t\tif (failureCount >= node.failureThreshold) return NodeStatus.Failure;\n\t\t\tif (anyRunning) return NodeStatus.Running;\n\t\t\treturn NodeStatus.Failure;\n\t\t}\n\n\t\tcase 'inverter': {\n\t\t\tconst status = tickNode(node.child, bt, ctx);\n\t\t\tif (status === NodeStatus.Success) return NodeStatus.Failure;\n\t\t\tif (status === NodeStatus.Failure) return NodeStatus.Success;\n\t\t\treturn NodeStatus.Running;\n\t\t}\n\n\t\tcase 'repeat': {\n\t\t\tconst iteration = bt.nodeState[node.nodeIndex] ?? 0;\n\t\t\tconst status = tickNode(node.child, bt, ctx);\n\t\t\tif (status === NodeStatus.Failure) {\n\t\t\t\tbt.nodeState[node.nodeIndex] = 0;\n\t\t\t\treturn NodeStatus.Failure;\n\t\t\t}\n\t\t\tif (status === NodeStatus.Running) return NodeStatus.Running;\n\t\t\tconst next = iteration + 1;\n\t\t\tif (node.count !== -1 && next >= node.count) {\n\t\t\t\tbt.nodeState[node.nodeIndex] = 0;\n\t\t\t\treturn NodeStatus.Success;\n\t\t\t}\n\t\t\tbt.nodeState[node.nodeIndex] = next;\n\t\t\treturn NodeStatus.Running;\n\t\t}\n\n\t\tcase 'cooldown': {\n\t\t\tconst expiresAt = bt.nodeState[node.nodeIndex] ?? 0;\n\t\t\tif (expiresAt > 0 && bt.elapsedTime < expiresAt) return NodeStatus.Failure;\n\t\t\tconst status = tickNode(node.child, bt, ctx);\n\t\t\tif (status !== NodeStatus.Running) {\n\t\t\t\tbt.nodeState[node.nodeIndex] = bt.elapsedTime + node.duration;\n\t\t\t}\n\t\t\treturn status;\n\t\t}\n\n\t\tcase 'guard': {\n\t\t\tif (!node.condition(ctx)) return NodeStatus.Failure;\n\t\t\treturn tickNode(node.child, bt, ctx);\n\t\t}\n\t}\n}\n\n// ==================== Typed Helpers ====================\n\n/**\n * Typed helpers for the behavior tree plugin.\n * Creates helpers that validate callback parameters against the world type W.\n * Call after `.build()` using `typeof ecs`.\n */\nexport interface BehaviorTreeHelpers<W extends BaseWorld<BehaviorTreeComponentTypes>> {\n\tdefineBehaviorTree: <BB extends object>(\n\t\tid: string,\n\t\tconfig: { blackboard: BB; root: BehaviorTreeNode<BB> },\n\t) => BehaviorTreeDefinition<BB>;\n\taction: <BB extends object>(\n\t\tname: string,\n\t\ttick: (ctx: BehaviorTreeContext<BB, W>) => NodeStatus,\n\t\toptions?: { onAbort?: (ctx: BehaviorTreeContext<BB, W>) => void },\n\t) => ActionNode<BB>;\n\tcondition: <BB extends object>(\n\t\tname: string,\n\t\tcheck: (ctx: BehaviorTreeContext<BB, W>) => boolean,\n\t) => ConditionNode<BB>;\n\tguard: <BB extends object>(\n\t\tcond: (ctx: BehaviorTreeContext<BB, W>) => boolean,\n\t\tchild: BehaviorTreeNode<BB>,\n\t) => GuardNode<BB>;\n}\n\n/**\n * Create typed behavior tree helpers bound to a specific world type.\n *\n * @example\n * ```typescript\n * const ecs = ECSpresso.create()\n * .withPlugin(createBehaviorTreePlugin())\n * .build();\n *\n * const { defineBehaviorTree, action, condition, guard } = ecs.getHelpers(createBehaviorTreeHelpers);\n * ```\n */\nexport function createBehaviorTreeHelpers<\n\tW extends BaseWorld<BehaviorTreeComponentTypes> = BehaviorTreeWorld,\n>(_world?: W): BehaviorTreeHelpers<W> {\n\treturn {\n\t\tdefineBehaviorTree: defineBehaviorTree as BehaviorTreeHelpers<W>['defineBehaviorTree'],\n\t\taction: action as BehaviorTreeHelpers<W>['action'],\n\t\tcondition: condition as BehaviorTreeHelpers<W>['condition'],\n\t\tguard: guard as BehaviorTreeHelpers<W>['guard'],\n\t};\n}\n\n// ==================== Plugin Options ====================\n\n/**\n * Configuration options for the behavior tree plugin.\n */\nexport interface BehaviorTreePluginOptions<G extends string = 'ai'> extends BasePluginOptions<G> {}\n\n// ==================== Plugin Factory ====================\n\n/**\n * Create a behavior tree plugin for ECSpresso.\n *\n * Provides composable, priority-driven AI via behavior trees with:\n * - Hybrid traversal: re-evaluate from root each tick, resume running leaves\n * - Automatic abort with `onAbort` callback when preempted\n * - Typed blackboard for per-entity AI memory\n * - `behaviorTreeAbort` events on preemption\n *\n * @example\n * ```typescript\n * const ecs = ECSpresso.create()\n * .withPlugin(createBehaviorTreePlugin())\n * .build();\n *\n * const { defineBehaviorTree, action, condition, guard } = ecs.getHelpers(createBehaviorTreeHelpers);\n *\n * const tree = defineBehaviorTree('villager', {\n * blackboard: { hunger: 100, targetId: null as number | null },\n * root: selector([\n * guard(ctx => ctx.blackboard.hunger < 30, action('eat', ...)),\n * action('wander', ...),\n * ]),\n * });\n *\n * ecs.spawn({\n * ...createBehaviorTree(tree),\n * ...createLocalTransform(100, 200),\n * });\n * ```\n */\nexport function createBehaviorTreePlugin<G extends string = 'ai'>(\n\toptions?: BehaviorTreePluginOptions<G>,\n) {\n\tconst {\n\t\tsystemGroup = 'ai',\n\t\tpriority = 0,\n\t\tphase = 'update',\n\t} = options ?? {};\n\n\treturn definePlugin('behaviorTree')\n\t\t.withComponentTypes<BehaviorTreeComponentTypes>()\n\t\t.withEventTypes<BehaviorTreeEventTypes>()\n\t\t.withLabels<'behavior-tree-update'>()\n\t\t.withGroups<G>()\n\t\t.install((world) => {\n\t\t\t// Dispose: abort running node on entity removal\n\t\t\tworld.registerDispose('behaviorTree', ({ value, entityId }) => {\n\t\t\t\tif (value.runningNodeIndex !== -1) {\n\t\t\t\t\tconst flatNodes = defFlatNodes.get(value.definition as BehaviorTreeDefinition<object>);\n\t\t\t\t\tconst node = flatNodes?.[value.runningNodeIndex] as AnyNode | undefined;\n\t\t\t\t\tif (node && node.type === 'action' && node.onAbort) {\n\t\t\t\t\t\tnode.onAbort({\n\t\t\t\t\t\t\tecs: world as unknown as BehaviorTreeWorld,\n\t\t\t\t\t\t\tentityId,\n\t\t\t\t\t\t\tdt: 0,\n\t\t\t\t\t\t\tblackboard: value.blackboard as Record<string, unknown>,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tworld\n\t\t\t\t.addSystem('behavior-tree-update')\n\t\t\t\t.setPriority(priority)\n\t\t\t\t.inPhase(phase)\n\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t.addQuery('trees', {\n\t\t\t\t\twith: ['behaviorTree'],\n\t\t\t\t})\n\t\t\t\t.setProcess(({ queries, dt, ecs: ecsWorld }) => {\n\t\t\t\t\tconst ctx: MutableCtx = {\n\t\t\t\t\t\tecs: ecsWorld as unknown as BehaviorTreeWorld,\n\t\t\t\t\t\tentityId: 0,\n\t\t\t\t\t\tdt: 0,\n\t\t\t\t\t\tblackboard: {},\n\t\t\t\t\t};\n\n\t\t\t\t\tfor (const entity of queries.trees) {\n\t\t\t\t\t\tconst bt = entity.components.behaviorTree;\n\t\t\t\t\t\tctx.entityId = entity.id;\n\t\t\t\t\t\tctx.dt = dt;\n\t\t\t\t\t\tctx.blackboard = bt.blackboard as Record<string, unknown>;\n\t\t\t\t\t\tbt.elapsedTime += dt;\n\n\t\t\t\t\t\tconst result = tickNode(bt.definition.root as AnyNode, bt, ctx);\n\n\t\t\t\t\t\tif (result !== NodeStatus.Running && bt.runningNodeIndex !== -1) {\n\t\t\t\t\t\t\tabortRunningNode(bt, ctx);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t});\n}\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "E741AFC03BF2211264756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "71DF25393349415964756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,4 +1,4 @@
1
- var b=Object.defineProperty;var q=(j)=>j;function C(j,k){this[j]=q.bind(null,k)}var F=(j,k)=>{for(var A in k)b(j,A,{get:k[A],enumerable:!0,configurable:!0,set:C.bind(k,A)})};var g=(j,k)=>()=>(j&&(k=j(j=0)),k);var x=((j)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(j,{get:(k,A)=>(typeof require<"u"?require:k)[A]}):j)(function(j){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+j+'" is not supported')});import{definePlugin as R}from"ecspresso";function w(j,k,A=32){return{detector:{range:j,layerFilter:k,maxResults:A}}}function I(j,k){return(j.getComponent(k,"detectedEntities")?.entities.length??0)>0}function h(j,k){return j.distanceSq-k.distanceSq}function m(j){let{systemGroup:k="ai",priority:A=500,phase:G="update"}=j??{},V=new Map,K=new Set,W=new Set,Z=new WeakMap;return R("detection").withComponentTypes().withEventTypes().withLabels().withGroups().requires().install((_)=>{_.registerDispose("detector",({entityId:X})=>{V.delete(X)}),_.addSystem("detection-scan").setPriority(A).inPhase(G).inGroup(k).addQuery("detectors",{with:["detector","worldTransform"]}).setProcess(({queries:X,ecs:E})=>{let P=E.getResource("spatialIndex");for(let H of X.detectors){let{detector:J,worldTransform:O}=H.components;W.clear(),P.queryRadiusInto(O.x,O.y,J.range,W);let L=[],Q=Z.get(J.layerFilter);if(!Q)Q=new Set(J.layerFilter),Z.set(J.layerFilter,Q);for(let z of W){if(z===H.id)continue;if(!E.getEntity(z))continue;let N=E.getComponent(z,"collisionLayer");if(!N)continue;if(!Q.has(N.layer))continue;let Y=E.getComponent(z,"worldTransform");if(!Y)continue;let B=Y.x-O.x,D=Y.y-O.y;L.push({entityId:z,distanceSq:B*B+D*D})}L.sort(h);let U=L.length>J.maxResults?L.slice(0,J.maxResults):L,$=E.getComponent(H.id,"detectedEntities");if($)$.entities=U,E.markChanged(H.id,"detectedEntities");else E.addComponent(H.id,"detectedEntities",{entities:U});let M=V.get(H.id);K.clear();for(let z of U)K.add(z.entityId);if(M){for(let z of K)if(!M.has(z))E.eventBus.publish("detectionGained",{entityId:H.id,detectedId:z});for(let z of M)if(!K.has(z))E.eventBus.publish("detectionLost",{entityId:H.id,lostId:z});M.clear();for(let z of K)M.add(z)}else{let z=new Set;for(let N of U)z.add(N.entityId),E.eventBus.publish("detectionGained",{entityId:H.id,detectedId:N.entityId});V.set(H.id,z)}}})})}export{I as hasDetectedTargets,w as createDetector,m as createDetectionPlugin};
1
+ var C=((k)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(k,{get:(E,H)=>(typeof require<"u"?require:E)[H]}):k)(function(k){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+k+'" is not supported')});import{definePlugin as b}from"ecspresso";function F(k,E,H=32){return{detector:{range:k,layerFilter:E,maxResults:H}}}function g(k,E){return(k.getComponent(E,"detectedEntities")?.entities.length??0)>0}function q(k,E){return k.distanceSq-E.distanceSq}function x(k){let{systemGroup:E="ai",priority:H=500,phase:G="update"}=k??{},V=new Map,K=new Set,W=new Set,Z=new WeakMap;return b("detection").withComponentTypes().withEventTypes().withLabels().withGroups().requires().install((_)=>{_.registerDispose("detector",({entityId:X})=>{V.delete(X)}),_.addSystem("detection-scan").setPriority(H).inPhase(G).inGroup(E).addQuery("detectors",{with:["detector","worldTransform"]}).setProcess(({queries:X,ecs:z})=>{let P=z.getResource("spatialIndex");for(let A of X.detectors){let{detector:J,worldTransform:O}=A.components;W.clear(),P.queryRadiusInto(O.x,O.y,J.range,W);let L=[],Q=Z.get(J.layerFilter);if(!Q)Q=new Set(J.layerFilter),Z.set(J.layerFilter,Q);for(let j of W){if(j===A.id)continue;if(!z.getEntity(j))continue;let N=z.getComponent(j,"collisionLayer");if(!N)continue;if(!Q.has(N.layer))continue;let Y=z.getComponent(j,"worldTransform");if(!Y)continue;let B=Y.x-O.x,D=Y.y-O.y;L.push({entityId:j,distanceSq:B*B+D*D})}L.sort(q);let U=L.length>J.maxResults?L.slice(0,J.maxResults):L,$=z.getComponent(A.id,"detectedEntities");if($)$.entities=U,z.markChanged(A.id,"detectedEntities");else z.addComponent(A.id,"detectedEntities",{entities:U});let M=V.get(A.id);K.clear();for(let j of U)K.add(j.entityId);if(M){for(let j of K)if(!M.has(j))z.eventBus.publish("detectionGained",{entityId:A.id,detectedId:j});for(let j of M)if(!K.has(j))z.eventBus.publish("detectionLost",{entityId:A.id,lostId:j});M.clear();for(let j of K)M.add(j)}else{let j=new Set;for(let N of U)j.add(N.entityId),z.eventBus.publish("detectionGained",{entityId:A.id,detectedId:N.entityId});V.set(A.id,j)}}})})}export{g as hasDetectedTargets,F as createDetector,x as createDetectionPlugin};
2
2
 
3
- //# debugId=A1D4A431370EEBBE64756E2164756E21
3
+ //# debugId=E2B03972F47A4A3E64756E2164756E21
4
4
  //# sourceMappingURL=detection.js.map
@@ -4,7 +4,7 @@
4
4
  "sourcesContent": [
5
5
  "/**\n * Detection Plugin for ECSpresso\n *\n * Provides automatic proximity detection for entities. Entities with a\n * `detector` component get their `detectedEntities` populated each frame\n * with nearby entities that match the configured collision layer filter,\n * sorted by distance ascending (nearest first).\n *\n * Uses the spatial-index plugin for efficient range queries.\n */\n\nimport { definePlugin, type BasePluginOptions } from 'ecspresso';\nimport type { WorldConfigFrom } from 'ecspresso';\nimport type { TransformWorldConfig } from '../spatial/transform';\nimport type { SpatialIndexResourceTypes } from '../spatial/spatial-index';\nimport type { CollisionComponentTypes } from '../physics/collision';\n\n// ==================== Component Types ====================\n\n/**\n * Configures proximity detection for an entity.\n */\nexport interface Detector {\n\t/** Detection radius in world units */\n\trange: number;\n\t/** Only detect entities on these collision layers */\n\tlayerFilter: readonly string[];\n\t/** Maximum number of results to track (default: 32) */\n\tmaxResults: number;\n}\n\n/**\n * A detected entity with its squared distance from the detector.\n */\nexport interface DetectedEntry {\n\tentityId: number;\n\tdistanceSq: number;\n}\n\n/**\n * Auto-populated list of detected entities, sorted by distance ascending.\n */\nexport interface DetectedEntities {\n\tentities: readonly DetectedEntry[];\n}\n\n/**\n * Component types provided by the detection plugin.\n */\nexport interface DetectionComponentTypes {\n\tdetector: Detector;\n\tdetectedEntities: DetectedEntities;\n}\n\n// ==================== Event Types ====================\n\n/**\n * Event fired when a new entity enters detection range.\n */\nexport interface DetectionGainedEvent {\n\t/** The entity doing the detecting */\n\tentityId: number;\n\t/** The entity that was detected */\n\tdetectedId: number;\n}\n\n/**\n * Event fired when an entity leaves detection range.\n */\nexport interface DetectionLostEvent {\n\t/** The entity doing the detecting */\n\tentityId: number;\n\t/** The entity that was lost */\n\tlostId: number;\n}\n\n/**\n * Event types provided by the detection plugin.\n */\nexport interface DetectionEventTypes {\n\tdetectionGained: DetectionGainedEvent;\n\tdetectionLost: DetectionLostEvent;\n}\n\n// ==================== WorldConfig ====================\n\n/**\n * WorldConfig representing the detection plugin's provided types.\n */\nexport type DetectionWorldConfig = WorldConfigFrom<DetectionComponentTypes, DetectionEventTypes>;\n\n// ==================== Plugin Options ====================\n\nexport interface DetectionPluginOptions<G extends string = 'ai'> extends BasePluginOptions<G> {}\n\n// ==================== Helper Functions ====================\n\n/**\n * Create a detector component.\n *\n * @param range Detection radius in world units\n * @param layerFilter Only detect entities on these collision layers\n * @param maxResults Maximum results to track (default: 32)\n * @returns Component object suitable for spreading into spawn()\n *\n * @example\n * ```typescript\n * ecs.spawn({\n * ...createDetector(300, ['enemy']),\n * ...createLocalTransform(400, 400),\n * });\n * ```\n */\nexport function createDetector(\n\trange: number,\n\tlayerFilter: readonly string[],\n\tmaxResults = 32,\n): Pick<DetectionComponentTypes, 'detector'> {\n\treturn { detector: { range, layerFilter, maxResults } };\n}\n\n/**\n * Check whether an entity has any detected targets.\n *\n * @param ecs ECS world instance\n * @param entityId Entity with a detector component\n * @returns true if detectedEntities contains at least one entry\n *\n * @example\n * ```typescript\n * if (hasDetectedTargets(ecs, guardId)) {\n * // transition to chase\n * }\n * ```\n */\nexport function hasDetectedTargets(\n\tecs: { getComponent(entityId: number, name: 'detectedEntities'): DetectedEntities | undefined },\n\tentityId: number,\n): boolean {\n\tconst detected = ecs.getComponent(entityId, 'detectedEntities');\n\treturn (detected?.entities.length ?? 0) > 0;\n}\n\n// ==================== Plugin Factory ====================\n\nfunction compareByDistance(a: DetectedEntry, b: DetectedEntry): number {\n\treturn a.distanceSq - b.distanceSq;\n}\n\n/**\n * Create a detection plugin for ECSpresso.\n *\n * Populates `detectedEntities` each frame with nearby entities matching\n * the detector's layer filter, sorted by distance (nearest first).\n * Publishes `detectionGained`/`detectionLost` events on transitions.\n *\n * Requires the spatial-index and transform plugins to be installed.\n *\n * @example\n * ```typescript\n * const ecs = ECSpresso.create()\n * .withPlugin(createTransformPlugin())\n * .withPlugin(createCollisionPlugin({ layers }))\n * .withPlugin(createSpatialIndexPlugin())\n * .withPlugin(createDetectionPlugin())\n * .build();\n *\n * // Read nearest detected entity:\n * const detected = ecs.getComponent(turretId, 'detectedEntities');\n * const nearest = detected?.entities[0];\n * ```\n */\nexport function createDetectionPlugin<G extends string = 'ai'>(\n\toptions?: DetectionPluginOptions<G>,\n) {\n\tconst {\n\t\tsystemGroup = 'ai',\n\t\tpriority = 500,\n\t\tphase = 'update',\n\t} = options ?? {};\n\n\t// Per-detector tracking of previous frame's detected set for event diffing\n\tconst previousSets = new Map<number, Set<number>>();\n\tconst currentSet = new Set<number>();\n\t// Reusable set for spatial index queries (avoids allocation per frame)\n\tconst candidateSet = new Set<number>();\n\t// Cache: layerFilter array → Set for O(1) lookups\n\tconst layerFilterCache = new WeakMap<readonly string[], Set<string>>();\n\n\treturn definePlugin('detection')\n\t\t.withComponentTypes<DetectionComponentTypes>()\n\t\t.withEventTypes<DetectionEventTypes>()\n\t\t.withLabels<'detection-scan'>()\n\t\t.withGroups<G>()\n\t\t.requires<\n\t\t\tTransformWorldConfig &\n\t\t\tWorldConfigFrom<Pick<CollisionComponentTypes<string>, 'collisionLayer'>> &\n\t\t\tWorldConfigFrom<{}, {}, SpatialIndexResourceTypes>\n\t\t>()\n\t\t.install((world) => {\n\t\t\tworld.registerDispose('detector', ({ entityId }) => {\n\t\t\t\tpreviousSets.delete(entityId);\n\t\t\t});\n\n\t\t\tworld\n\t\t\t\t.addSystem('detection-scan')\n\t\t\t\t.setPriority(priority)\n\t\t\t\t.inPhase(phase)\n\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t.addQuery('detectors', {\n\t\t\t\t\twith: ['detector', 'worldTransform'],\n\t\t\t\t})\n\t\t\t\t.setProcess(({ queries, ecs }) => {\n\t\t\t\t\tconst spatialIndex = ecs.getResource('spatialIndex');\n\n\t\t\t\t\tfor (const entity of queries.detectors) {\n\t\t\t\t\t\tconst { detector, worldTransform } = entity.components;\n\n\t\t\t\t\t\tcandidateSet.clear();\n\t\t\t\t\t\tspatialIndex.queryRadiusInto(worldTransform.x, worldTransform.y, detector.range, candidateSet);\n\n\t\t\t\t\t\t// Build sorted results, filtering by layer and excluding self\n\t\t\t\t\t\tconst entries: DetectedEntry[] = [];\n\n\t\t\t\t\t\tlet filterSet = layerFilterCache.get(detector.layerFilter);\n\t\t\t\t\t\tif (!filterSet) {\n\t\t\t\t\t\t\tfilterSet = new Set(detector.layerFilter);\n\t\t\t\t\t\t\tlayerFilterCache.set(detector.layerFilter, filterSet);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tfor (const candidateId of candidateSet) {\n\t\t\t\t\t\t\tif (candidateId === entity.id) continue;\n\t\t\t\t\t\t\tif (!ecs.getEntity(candidateId)) continue;\n\n\t\t\t\t\t\t\tconst layer = ecs.getComponent(candidateId, 'collisionLayer');\n\t\t\t\t\t\t\tif (!layer) continue;\n\t\t\t\t\t\t\tif (!filterSet.has(layer.layer)) continue;\n\n\t\t\t\t\t\t\tconst candidateTransform = ecs.getComponent(candidateId, 'worldTransform');\n\t\t\t\t\t\t\tif (!candidateTransform) continue;\n\n\t\t\t\t\t\t\tconst dx = candidateTransform.x - worldTransform.x;\n\t\t\t\t\t\t\tconst dy = candidateTransform.y - worldTransform.y;\n\t\t\t\t\t\t\tentries.push({ entityId: candidateId, distanceSq: dx * dx + dy * dy });\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tentries.sort(compareByDistance);\n\t\t\t\t\t\tconst capped = entries.length > detector.maxResults\n\t\t\t\t\t\t\t? entries.slice(0, detector.maxResults)\n\t\t\t\t\t\t\t: entries;\n\n\t\t\t\t\t\t// Update or add the detectedEntities component\n\t\t\t\t\t\tconst existing = ecs.getComponent(entity.id, 'detectedEntities');\n\t\t\t\t\t\tif (existing) {\n\t\t\t\t\t\t\t(existing as { entities: readonly DetectedEntry[] }).entities = capped;\n\t\t\t\t\t\t\tecs.markChanged(entity.id, 'detectedEntities');\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tecs.addComponent(entity.id, 'detectedEntities', { entities: capped });\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Diff against previous frame for events\n\t\t\t\t\t\tconst prev = previousSets.get(entity.id);\n\t\t\t\t\t\tcurrentSet.clear();\n\t\t\t\t\t\tfor (const entry of capped) {\n\t\t\t\t\t\t\tcurrentSet.add(entry.entityId);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (prev) {\n\t\t\t\t\t\t\t// Detect gained\n\t\t\t\t\t\t\tfor (const id of currentSet) {\n\t\t\t\t\t\t\t\tif (!prev.has(id)) {\n\t\t\t\t\t\t\t\t\tecs.eventBus.publish('detectionGained', {\n\t\t\t\t\t\t\t\t\t\tentityId: entity.id,\n\t\t\t\t\t\t\t\t\t\tdetectedId: id,\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// Detect lost\n\t\t\t\t\t\t\tfor (const id of prev) {\n\t\t\t\t\t\t\t\tif (!currentSet.has(id)) {\n\t\t\t\t\t\t\t\t\tecs.eventBus.publish('detectionLost', {\n\t\t\t\t\t\t\t\t\t\tentityId: entity.id,\n\t\t\t\t\t\t\t\t\t\tlostId: id,\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// Update previous set in place\n\t\t\t\t\t\t\tprev.clear();\n\t\t\t\t\t\t\tfor (const id of currentSet) {\n\t\t\t\t\t\t\t\tprev.add(id);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// First frame — all are gained\n\t\t\t\t\t\t\tconst newSet = new Set<number>();\n\t\t\t\t\t\t\tfor (const entry of capped) {\n\t\t\t\t\t\t\t\tnewSet.add(entry.entityId);\n\t\t\t\t\t\t\t\tecs.eventBus.publish('detectionGained', {\n\t\t\t\t\t\t\t\t\tentityId: entity.id,\n\t\t\t\t\t\t\t\t\tdetectedId: entry.entityId,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tpreviousSets.set(entity.id, newSet);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t});\n}\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "A1D4A431370EEBBE64756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "E2B03972F47A4A3E64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,4 +1,4 @@
1
- var o=Object.defineProperty;var zz=(z)=>z;function Jz(z,J){this[z]=zz.bind(null,J)}var Gz=(z,J)=>{for(var Z in J)o(z,Z,{get:J[Z],enumerable:!0,configurable:!0,set:Jz.bind(J,Z)})};var Hz=(z,J)=>()=>(z&&(J=z(z=0)),J);var Lz=((z)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(z,{get:(J,Z)=>(typeof require<"u"?require:J)[Z]}):z)(function(z){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+z+'" is not supported')});import{definePlugin as Uz}from"ecspresso";var m={normalX:0,normalY:0,depth:0},s=0;function c(z,J,Z,k,K,U,$,Q){if(z.entityId=J,z.layer=K,z.collidesWith=U,$)return z.x=Z+($.offsetX??0),z.y=k+($.offsetY??0),z.shape=0,z.halfWidth=$.width/2,z.halfHeight=$.height/2,z.radius=0,!0;if(Q)return z.x=Z+(Q.offsetX??0),z.y=k+(Q.offsetY??0),z.shape=1,z.halfWidth=0,z.halfHeight=0,z.radius=Q.radius,!0;return!1}function Qz(z,J,Z,k,K,U,$,Q,H){let V=K-z,O=U-J,j=Z+$-Math.abs(V),G=k+Q-Math.abs(O);if(j<=0||G<=0)return!1;if(j<G)return H.normalX=V>=0?1:-1,H.normalY=0,H.depth=j,!0;return H.normalX=0,H.normalY=O>=0?1:-1,H.depth=G,!0}function Zz(z,J,Z,k,K,U,$){let Q=k-z,H=K-J,V=Q*Q+H*H,O=Z+U;if(V>=O*O)return!1;let j=Math.sqrt(V);if(j===0)return $.normalX=1,$.normalY=0,$.depth=O,!0;return $.normalX=Q/j,$.normalY=H/j,$.depth=O-j,!0}function r(z,J,Z,k,K,U,$,Q){let H=Math.max(z-Z,Math.min(K,z+Z)),V=Math.max(J-k,Math.min(U,J+k)),O=K-H,j=U-V,G=O*O+j*j;if(G>=$*$)return!1;if(G===0){let L=K-(z-Z),N=z+Z-K,E=U-(J-k),W=J+k-U,_=Math.min(L,N,E,W);if(_===N)return Q.normalX=1,Q.normalY=0,Q.depth=N+$,!0;if(_===L)return Q.normalX=-1,Q.normalY=0,Q.depth=L+$,!0;if(_===W)return Q.normalX=0,Q.normalY=1,Q.depth=W+$,!0;return Q.normalX=0,Q.normalY=-1,Q.depth=E+$,!0}let D=Math.sqrt(G);return Q.normalX=O/D,Q.normalY=j/D,Q.depth=$-D,!0}function n(z,J,Z){if(z.shape===0&&J.shape===0)return Qz(z.x,z.y,z.halfWidth,z.halfHeight,J.x,J.y,J.halfWidth,J.halfHeight,Z);if(z.shape===1&&J.shape===1)return Zz(z.x,z.y,z.radius,J.x,J.y,J.radius,Z);if(z.shape===0&&J.shape===1)return r(z.x,z.y,z.halfWidth,z.halfHeight,J.x,J.y,J.radius,Z);if(!r(J.x,J.y,J.halfWidth,J.halfHeight,z.x,z.y,z.radius,Z))return!1;return Z.normalX=-Z.normalX,Z.normalY=-Z.normalY,!0}var y=new Set,l=!1,$z=50;function i(z,J,Z,k,K,U){if(k)jz(z,J,Z,k,K,U);else Kz(z,J,K,U)}function Kz(z,J,Z,k){if(!l&&J>=$z)l=!0,console.warn(`[ecspresso] Collision detection is using O(n²) brute force with ${J} colliders. For better performance, install createSpatialIndexPlugin() alongside your collision or physics2D plugin.`);for(let K=0;K<J;K++){let U=z[K];if(!U)continue;for(let $=K+1;$<J;$++){let Q=z[$];if(!Q)continue;if(!U.collidesWith.includes(Q.layer)&&!Q.collidesWith.includes(U.layer))continue;if(!n(U,Q,m))continue;Z(U,Q,m,k)}}}function jz(z,J,Z,k,K,U){Z.clear();for(let $=0;$<J;$++){let Q=z[$];if(!Q)continue;Z.set(Q.entityId,Q)}for(let $=0;$<J;$++){let Q=z[$];if(!Q)continue;let H=Q.shape===0?Q.halfWidth:Q.radius,V=Q.shape===0?Q.halfHeight:Q.radius;y.clear(),k.queryRectInto(Q.x-H,Q.y-V,Q.x+H,Q.y+V,y);for(let O of y){if(O<=Q.entityId)continue;let j=Z.get(O);if(!j)continue;if(!Q.collidesWith.includes(j.layer)&&!j.collidesWith.includes(Q.layer))continue;if(!n(Q,j,m))continue;K(Q,j,m,U)}}}function Ez(z,J){return{rigidBody:{type:z,mass:z==="static"?1/0:J?.mass??1,drag:J?.drag??0,restitution:J?.restitution??0,friction:J?.friction??0,gravityScale:J?.gravityScale??1},force:{x:0,y:0}}}function Rz(z,J){return{force:{x:z,y:J}}}function e(z,J,Z,k){let K=z.getComponent(J,"force");if(!K)return;K.x+=Z,K.y+=k}function Pz(z,J,Z,k){let K=z.getComponent(J,"velocity"),U=z.getComponent(J,"rigidBody");if(!K||!U)return;if(U.mass===1/0||U.mass===0)return;K.x+=Z/U.mass,K.y+=k/U.mass}function Tz(z,J,Z,k){let K=z.getComponent(J,"velocity");if(!K)return;K.x=Z,K.y=k}var C={entityA:0,entityB:0,normalX:0,normalY:0,depth:0};function kz(z,J,Z,k){let K=z.rigidBody.type==="dynamic"&&z.rigidBody.mass>0&&z.rigidBody.mass!==1/0?1/z.rigidBody.mass:0,U=J.rigidBody.type==="dynamic"&&J.rigidBody.mass>0&&J.rigidBody.mass!==1/0?1/J.rigidBody.mass:0,$=K+U;if($>0){let Q=Z.depth/$;if(K>0){let j=k.getComponent(z.entityId,"localTransform");if(!j)return;let G=Q*K;j.x-=G*Z.normalX,j.y-=G*Z.normalY,z.x=j.x,z.y=j.y,k.markChanged(z.entityId,"localTransform")}if(U>0){let j=k.getComponent(J.entityId,"localTransform");if(!j)return;let G=Q*U;j.x+=G*Z.normalX,j.y+=G*Z.normalY,J.x=j.x,J.y=j.y,k.markChanged(J.entityId,"localTransform")}let H=J.velocity.x-z.velocity.x,V=J.velocity.y-z.velocity.y,O=H*Z.normalX+V*Z.normalY;if(O<0){let G=-(1+Math.min(z.rigidBody.restitution,J.rigidBody.restitution))*O/$;z.velocity.x-=G*K*Z.normalX,z.velocity.y-=G*K*Z.normalY,J.velocity.x+=G*U*Z.normalX,J.velocity.y+=G*U*Z.normalY;let D=H-O*Z.normalX,L=V-O*Z.normalY,N=Math.sqrt(D*D+L*L);if(N>0.000001){let E=D/N,W=L/N,M=Math.sqrt(z.rigidBody.friction*J.rigidBody.friction)*Math.abs(G),P=Math.min(N/$,M);z.velocity.x+=P*K*E,z.velocity.y+=P*K*W,J.velocity.x-=P*U*E,J.velocity.y-=P*U*W}}k.markChanged(z.entityId,"velocity"),k.markChanged(J.entityId,"velocity")}C.entityA=z.entityId,C.entityB=J.entityId,C.normalX=Z.normalX,C.normalY=Z.normalY,C.depth=Z.depth,k.eventBus.publish("physicsCollision",C)}function qz(z){let{gravity:J={x:0,y:0},systemGroup:Z="physics2D",collisionSystemGroup:k,integrationPriority:K=1000,collisionPriority:U=900,phase:$="fixedUpdate"}=z??{};return Uz("physics2D").withComponentTypes().withEventTypes().withResourceTypes().withLabels().withGroups().requires().install((Q)=>{Q.registerRequired("rigidBody","velocity",()=>({x:0,y:0})),Q.registerRequired("rigidBody","force",()=>({x:0,y:0})),Q.addResource("physicsConfig",{gravity:{x:J.x,y:J.y}}),Q.addSystem("physics2D-integration").setPriority(K).inPhase($).inGroup(Z).addQuery("bodies",{with:["localTransform","velocity","rigidBody","force"]}).setProcess(({queries:D,dt:L,ecs:N})=>{let{gravity:E}=N.getResource("physicsConfig"),W=E.x,_=E.y;for(let M of D.bodies){let{localTransform:P,velocity:R,rigidBody:q,force:T}=M.components;if(q.type==="static")continue;if(q.type==="dynamic"){let B=q.gravityScale*L;R.x+=W*B,R.y+=_*B;let w=q.mass;if(w>0&&w!==1/0){let X=L/w;R.x+=T.x*X,R.y+=T.y*X}if(q.drag>0){let X=Math.max(0,1-q.drag*L);R.x*=X,R.y*=X}}P.x+=R.x*L,P.y+=R.y*L,T.x=0,T.y=0,N.markChanged(M.id,"localTransform")}});let H=Q.addSystem("physics2D-collision").setPriority(U).inPhase($).inGroup(Z);if(k)H.inGroup(k);let V=[],O=new Map,j,G=!1;H.addQuery("collidables",{with:["localTransform","rigidBody","velocity","collisionLayer"]}).setProcess(({queries:D,ecs:L})=>{let N=0;for(let E of D.collidables){let{localTransform:W,rigidBody:_,velocity:M,collisionLayer:P}=E.components,R=L.getComponent(E.id,"aabbCollider"),q=R?void 0:L.getComponent(E.id,"circleCollider");if(!R&&!q)continue;let T=V[N];if(!T)T={entityId:E.id,x:W.x,y:W.y,layer:P.layer,collidesWith:P.collidesWith,shape:s,halfWidth:0,halfHeight:0,radius:0,rigidBody:_,velocity:M},V[N]=T;else T.rigidBody=_,T.velocity=M;if(!c(T,E.id,W.x,W.y,P.layer,P.collidesWith,R,q))continue;N++}if(!G)j=L.tryGetResource("spatialIndex"),G=!0;i(V,N,O,j,kz,L)})})}import{definePlugin as Oz}from"ecspresso";function Xz(z){return{flockingAgent:{perceptionRadius:z?.perceptionRadius??100,separationWeight:z?.separationWeight??1.5,alignmentWeight:z?.alignmentWeight??1,cohesionWeight:z?.cohesionWeight??1,maxForce:z?.maxForce??400,maxSpeed:z?.maxSpeed??200,flockGroup:z?.flockGroup??0}}}var p=new Set,a=0.01;function Yz(z){let{systemGroup:J="ai",priority:Z=500,phase:k="update",headingPriority:K=200}=z??{};return Oz("flocking").withComponentTypes().withLabels().withGroups().requires().install((U)=>{U.addSystem("flocking-forces").setPriority(Z).inPhase(k).inGroup(J).addQuery("boids",{with:["flockingAgent","worldTransform","velocity","force"]}).setProcess(({queries:$,ecs:Q})=>{let H=Q.getResource("spatialIndex");for(let V of $.boids){let{flockingAgent:O,worldTransform:j,velocity:G}=V.components,{perceptionRadius:D,separationWeight:L,alignmentWeight:N,cohesionWeight:E,maxForce:W,flockGroup:_}=O;p.clear(),H.queryRadiusInto(j.x,j.y,D,p);let M=0,P=0,R=0,q=0,T=0,B=0,w=0,X=0,x=0,b=D*0.5,t=b*b;for(let F of p){if(F===V.id)continue;let I=Q.getComponent(F,"flockingAgent");if(!I)continue;if(I.flockGroup!==_)continue;let S=Q.getComponent(F,"worldTransform");if(!S)continue;let f=j.x-S.x,v=j.y-S.y,g=f*f+v*v;if(g>0&&g<t){let d=Math.sqrt(g);M+=f/d,P+=v/d,R++}let h=Q.getComponent(F,"velocity");if(h)q+=h.x,T+=h.y,B++;w+=S.x,X+=S.y,x++}let Y=0,A=0;if(R>0)Y+=M/R*L,A+=P/R*L;if(B>0){let F=q/B,I=T/B;Y+=(F-G.x)*N,A+=(I-G.y)*N}if(x>0){let F=w/x,I=X/x;Y+=(F-j.x-G.x)*E,A+=(I-j.y-G.y)*E}let u=Y*Y+A*A;if(u>W*W){let F=Math.sqrt(u);Y=Y/F*W,A=A/F*W}e(Q,V.id,Y,A)}}),U.addSystem("flocking-heading").setPriority(K).inPhase(k).inGroup(J).addQuery("boids",{with:["flockingAgent","velocity","localTransform"]}).setProcess(({queries:$,ecs:Q})=>{for(let H of $.boids){let{flockingAgent:V,velocity:O,localTransform:j}=H.components,{maxSpeed:G}=V,D=O.x*O.x+O.y*O.y;if(D>G*G){let L=Math.sqrt(D);O.x=O.x/L*G,O.y=O.y/L*G,Q.markChanged(H.id,"velocity")}if(D>a*a){let L=Math.atan2(O.y,O.x);if(L!==j.rotation)j.rotation=L,Q.markChanged(H.id,"localTransform")}}})})}export{Yz as createFlockingPlugin,Xz as createFlockingAgent};
1
+ var Uz=((z)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(z,{get:(J,Z)=>(typeof require<"u"?require:J)[Z]}):z)(function(z){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+z+'" is not supported')});import{definePlugin as $z}from"ecspresso";var m={normalX:0,normalY:0,depth:0},s=0;function c(z,J,Z,k,K,U,$,Q){if(z.entityId=J,z.layer=K,z.collidesWith=U,$)return z.x=Z+($.offsetX??0),z.y=k+($.offsetY??0),z.shape=0,z.halfWidth=$.width/2,z.halfHeight=$.height/2,z.radius=0,!0;if(Q)return z.x=Z+(Q.offsetX??0),z.y=k+(Q.offsetY??0),z.shape=1,z.halfWidth=0,z.halfHeight=0,z.radius=Q.radius,!0;return!1}function o(z,J,Z,k,K,U,$,Q,H){let V=K-z,O=U-J,j=Z+$-Math.abs(V),G=k+Q-Math.abs(O);if(j<=0||G<=0)return!1;if(j<G)return H.normalX=V>=0?1:-1,H.normalY=0,H.depth=j,!0;return H.normalX=0,H.normalY=O>=0?1:-1,H.depth=G,!0}function zz(z,J,Z,k,K,U,$){let Q=k-z,H=K-J,V=Q*Q+H*H,O=Z+U;if(V>=O*O)return!1;let j=Math.sqrt(V);if(j===0)return $.normalX=1,$.normalY=0,$.depth=O,!0;return $.normalX=Q/j,$.normalY=H/j,$.depth=O-j,!0}function r(z,J,Z,k,K,U,$,Q){let H=Math.max(z-Z,Math.min(K,z+Z)),V=Math.max(J-k,Math.min(U,J+k)),O=K-H,j=U-V,G=O*O+j*j;if(G>=$*$)return!1;if(G===0){let L=K-(z-Z),N=z+Z-K,E=U-(J-k),W=J+k-U,_=Math.min(L,N,E,W);if(_===N)return Q.normalX=1,Q.normalY=0,Q.depth=N+$,!0;if(_===L)return Q.normalX=-1,Q.normalY=0,Q.depth=L+$,!0;if(_===W)return Q.normalX=0,Q.normalY=1,Q.depth=W+$,!0;return Q.normalX=0,Q.normalY=-1,Q.depth=E+$,!0}let D=Math.sqrt(G);return Q.normalX=O/D,Q.normalY=j/D,Q.depth=$-D,!0}function n(z,J,Z){if(z.shape===0&&J.shape===0)return o(z.x,z.y,z.halfWidth,z.halfHeight,J.x,J.y,J.halfWidth,J.halfHeight,Z);if(z.shape===1&&J.shape===1)return zz(z.x,z.y,z.radius,J.x,J.y,J.radius,Z);if(z.shape===0&&J.shape===1)return r(z.x,z.y,z.halfWidth,z.halfHeight,J.x,J.y,J.radius,Z);if(!r(J.x,J.y,J.halfWidth,J.halfHeight,z.x,z.y,z.radius,Z))return!1;return Z.normalX=-Z.normalX,Z.normalY=-Z.normalY,!0}var y=new Set,l=!1,Jz=50;function i(z,J,Z,k,K,U){if(k)Zz(z,J,Z,k,K,U);else Qz(z,J,K,U)}function Qz(z,J,Z,k){if(!l&&J>=Jz)l=!0,console.warn(`[ecspresso] Collision detection is using O(n²) brute force with ${J} colliders. For better performance, install createSpatialIndexPlugin() alongside your collision or physics2D plugin.`);for(let K=0;K<J;K++){let U=z[K];if(!U)continue;for(let $=K+1;$<J;$++){let Q=z[$];if(!Q)continue;if(!U.collidesWith.includes(Q.layer)&&!Q.collidesWith.includes(U.layer))continue;if(!n(U,Q,m))continue;Z(U,Q,m,k)}}}function Zz(z,J,Z,k,K,U){Z.clear();for(let $=0;$<J;$++){let Q=z[$];if(!Q)continue;Z.set(Q.entityId,Q)}for(let $=0;$<J;$++){let Q=z[$];if(!Q)continue;let H=Q.shape===0?Q.halfWidth:Q.radius,V=Q.shape===0?Q.halfHeight:Q.radius;y.clear(),k.queryRectInto(Q.x-H,Q.y-V,Q.x+H,Q.y+V,y);for(let O of y){if(O<=Q.entityId)continue;let j=Z.get(O);if(!j)continue;if(!Q.collidesWith.includes(j.layer)&&!j.collidesWith.includes(Q.layer))continue;if(!n(Q,j,m))continue;K(Q,j,m,U)}}}function Lz(z,J){return{rigidBody:{type:z,mass:z==="static"?1/0:J?.mass??1,drag:J?.drag??0,restitution:J?.restitution??0,friction:J?.friction??0,gravityScale:J?.gravityScale??1},force:{x:0,y:0}}}function Vz(z,J){return{force:{x:z,y:J}}}function e(z,J,Z,k){let K=z.getComponent(J,"force");if(!K)return;K.x+=Z,K.y+=k}function Nz(z,J,Z,k){let K=z.getComponent(J,"velocity"),U=z.getComponent(J,"rigidBody");if(!K||!U)return;if(U.mass===1/0||U.mass===0)return;K.x+=Z/U.mass,K.y+=k/U.mass}function Dz(z,J,Z,k){let K=z.getComponent(J,"velocity");if(!K)return;K.x=Z,K.y=k}var C={entityA:0,entityB:0,normalX:0,normalY:0,depth:0};function Kz(z,J,Z,k){let K=z.rigidBody.type==="dynamic"&&z.rigidBody.mass>0&&z.rigidBody.mass!==1/0?1/z.rigidBody.mass:0,U=J.rigidBody.type==="dynamic"&&J.rigidBody.mass>0&&J.rigidBody.mass!==1/0?1/J.rigidBody.mass:0,$=K+U;if($>0){let Q=Z.depth/$;if(K>0){let j=k.getComponent(z.entityId,"localTransform");if(!j)return;let G=Q*K;j.x-=G*Z.normalX,j.y-=G*Z.normalY,z.x=j.x,z.y=j.y,k.markChanged(z.entityId,"localTransform")}if(U>0){let j=k.getComponent(J.entityId,"localTransform");if(!j)return;let G=Q*U;j.x+=G*Z.normalX,j.y+=G*Z.normalY,J.x=j.x,J.y=j.y,k.markChanged(J.entityId,"localTransform")}let H=J.velocity.x-z.velocity.x,V=J.velocity.y-z.velocity.y,O=H*Z.normalX+V*Z.normalY;if(O<0){let G=-(1+Math.min(z.rigidBody.restitution,J.rigidBody.restitution))*O/$;z.velocity.x-=G*K*Z.normalX,z.velocity.y-=G*K*Z.normalY,J.velocity.x+=G*U*Z.normalX,J.velocity.y+=G*U*Z.normalY;let D=H-O*Z.normalX,L=V-O*Z.normalY,N=Math.sqrt(D*D+L*L);if(N>0.000001){let E=D/N,W=L/N,M=Math.sqrt(z.rigidBody.friction*J.rigidBody.friction)*Math.abs(G),P=Math.min(N/$,M);z.velocity.x+=P*K*E,z.velocity.y+=P*K*W,J.velocity.x-=P*U*E,J.velocity.y-=P*U*W}}k.markChanged(z.entityId,"velocity"),k.markChanged(J.entityId,"velocity")}C.entityA=z.entityId,C.entityB=J.entityId,C.normalX=Z.normalX,C.normalY=Z.normalY,C.depth=Z.depth,k.eventBus.publish("physicsCollision",C)}function Wz(z){let{gravity:J={x:0,y:0},systemGroup:Z="physics2D",collisionSystemGroup:k,integrationPriority:K=1000,collisionPriority:U=900,phase:$="fixedUpdate"}=z??{};return $z("physics2D").withComponentTypes().withEventTypes().withResourceTypes().withLabels().withGroups().requires().install((Q)=>{Q.registerRequired("rigidBody","velocity",()=>({x:0,y:0})),Q.registerRequired("rigidBody","force",()=>({x:0,y:0})),Q.addResource("physicsConfig",{gravity:{x:J.x,y:J.y}}),Q.addSystem("physics2D-integration").setPriority(K).inPhase($).inGroup(Z).addQuery("bodies",{with:["localTransform","velocity","rigidBody","force"]}).setProcess(({queries:D,dt:L,ecs:N})=>{let{gravity:E}=N.getResource("physicsConfig"),W=E.x,_=E.y;for(let M of D.bodies){let{localTransform:P,velocity:R,rigidBody:q,force:T}=M.components;if(q.type==="static")continue;if(q.type==="dynamic"){let B=q.gravityScale*L;R.x+=W*B,R.y+=_*B;let w=q.mass;if(w>0&&w!==1/0){let X=L/w;R.x+=T.x*X,R.y+=T.y*X}if(q.drag>0){let X=Math.max(0,1-q.drag*L);R.x*=X,R.y*=X}}P.x+=R.x*L,P.y+=R.y*L,T.x=0,T.y=0,N.markChanged(M.id,"localTransform")}});let H=Q.addSystem("physics2D-collision").setPriority(U).inPhase($).inGroup(Z);if(k)H.inGroup(k);let V=[],O=new Map,j,G=!1;H.addQuery("collidables",{with:["localTransform","rigidBody","velocity","collisionLayer"]}).setProcess(({queries:D,ecs:L})=>{let N=0;for(let E of D.collidables){let{localTransform:W,rigidBody:_,velocity:M,collisionLayer:P}=E.components,R=L.getComponent(E.id,"aabbCollider"),q=R?void 0:L.getComponent(E.id,"circleCollider");if(!R&&!q)continue;let T=V[N];if(!T)T={entityId:E.id,x:W.x,y:W.y,layer:P.layer,collidesWith:P.collidesWith,shape:s,halfWidth:0,halfHeight:0,radius:0,rigidBody:_,velocity:M},V[N]=T;else T.rigidBody=_,T.velocity=M;if(!c(T,E.id,W.x,W.y,P.layer,P.collidesWith,R,q))continue;N++}if(!G)j=L.tryGetResource("spatialIndex"),G=!0;i(V,N,O,j,Kz,L)})})}import{definePlugin as jz}from"ecspresso";function Tz(z){return{flockingAgent:{perceptionRadius:z?.perceptionRadius??100,separationWeight:z?.separationWeight??1.5,alignmentWeight:z?.alignmentWeight??1,cohesionWeight:z?.cohesionWeight??1,maxForce:z?.maxForce??400,maxSpeed:z?.maxSpeed??200,flockGroup:z?.flockGroup??0}}}var p=new Set,a=0.01;function qz(z){let{systemGroup:J="ai",priority:Z=500,phase:k="update",headingPriority:K=200}=z??{};return jz("flocking").withComponentTypes().withLabels().withGroups().requires().install((U)=>{U.addSystem("flocking-forces").setPriority(Z).inPhase(k).inGroup(J).addQuery("boids",{with:["flockingAgent","worldTransform","velocity","force"]}).setProcess(({queries:$,ecs:Q})=>{let H=Q.getResource("spatialIndex");for(let V of $.boids){let{flockingAgent:O,worldTransform:j,velocity:G}=V.components,{perceptionRadius:D,separationWeight:L,alignmentWeight:N,cohesionWeight:E,maxForce:W,flockGroup:_}=O;p.clear(),H.queryRadiusInto(j.x,j.y,D,p);let M=0,P=0,R=0,q=0,T=0,B=0,w=0,X=0,x=0,b=D*0.5,t=b*b;for(let F of p){if(F===V.id)continue;let I=Q.getComponent(F,"flockingAgent");if(!I)continue;if(I.flockGroup!==_)continue;let S=Q.getComponent(F,"worldTransform");if(!S)continue;let f=j.x-S.x,v=j.y-S.y,g=f*f+v*v;if(g>0&&g<t){let d=Math.sqrt(g);M+=f/d,P+=v/d,R++}let h=Q.getComponent(F,"velocity");if(h)q+=h.x,T+=h.y,B++;w+=S.x,X+=S.y,x++}let Y=0,A=0;if(R>0)Y+=M/R*L,A+=P/R*L;if(B>0){let F=q/B,I=T/B;Y+=(F-G.x)*N,A+=(I-G.y)*N}if(x>0){let F=w/x,I=X/x;Y+=(F-j.x-G.x)*E,A+=(I-j.y-G.y)*E}let u=Y*Y+A*A;if(u>W*W){let F=Math.sqrt(u);Y=Y/F*W,A=A/F*W}e(Q,V.id,Y,A)}}),U.addSystem("flocking-heading").setPriority(K).inPhase(k).inGroup(J).addQuery("boids",{with:["flockingAgent","velocity","localTransform"]}).setProcess(({queries:$,ecs:Q})=>{for(let H of $.boids){let{flockingAgent:V,velocity:O,localTransform:j}=H.components,{maxSpeed:G}=V,D=O.x*O.x+O.y*O.y;if(D>G*G){let L=Math.sqrt(D);O.x=O.x/L*G,O.y=O.y/L*G,Q.markChanged(H.id,"velocity")}if(D>a*a){let L=Math.atan2(O.y,O.x);if(L!==j.rotation)j.rotation=L,Q.markChanged(H.id,"localTransform")}}})})}export{qz as createFlockingPlugin,Tz as createFlockingAgent};
2
2
 
3
- //# debugId=86EF73C7B0F16E1564756E2164756E21
3
+ //# debugId=4B6E9CAC48D6266764756E2164756E21
4
4
  //# sourceMappingURL=flocking.js.map
@@ -6,7 +6,7 @@
6
6
  "/**\n * Shared Narrowphase Module\n *\n * Provides contact-computing narrowphase tests and a generic collision\n * iteration pipeline used by both the collision plugin (event-only) and\n * the physics2D plugin (impulse response).\n */\n\nimport type { SpatialIndex } from './spatial-hash';\n\n// ==================== Contact ====================\n\n/**\n * Contact result from a narrowphase test. Normal points from A toward B.\n *\n * Narrowphase functions use this as an out-parameter: the caller owns the\n * struct, the function writes fields in place and returns `true` on hit.\n * The `onContact` callback in `detectCollisions` receives a shared module-\n * level instance — **subscribers must consume it synchronously and must not\n * retain the reference across frames**.\n */\nexport interface Contact {\n\tnormalX: number;\n\tnormalY: number;\n\t/** Penetration depth (positive = overlapping) */\n\tdepth: number;\n}\n\n/**\n * Module-level reusable Contact passed down from `detectCollisions` into\n * narrowphase tests and forwarded to the `onContact` callback. Reused across\n * every pair in every frame — zero allocation in the narrowphase hot path.\n */\nconst _sharedContact: Contact = { normalX: 0, normalY: 0, depth: 0 };\n\n// ==================== BaseColliderInfo ====================\n\n/** Collider shape discriminator for the flattened BaseColliderInfo layout. */\nexport const AABB_SHAPE = 0;\nexport const CIRCLE_SHAPE = 1;\nexport type ColliderShape = typeof AABB_SHAPE | typeof CIRCLE_SHAPE;\n\n/**\n * Minimum collider data shared by collision and physics bundles.\n *\n * Flat layout (no nested `aabb` / `circle` sub-objects): the `shape`\n * discriminator tells you whether to read `halfWidth`/`halfHeight`\n * (AABB) or `radius` (Circle). Unused fields are set to 0.\n *\n * This shape is pool-friendly — all fields are assigned in place each\n * frame without allocating nested objects.\n */\nexport interface BaseColliderInfo<L extends string = string> {\n\tentityId: number;\n\tx: number;\n\ty: number;\n\tlayer: L;\n\tcollidesWith: readonly L[];\n\tshape: ColliderShape;\n\thalfWidth: number;\n\thalfHeight: number;\n\tradius: number;\n}\n\n// ==================== Collider Construction ====================\n\n/**\n * Populate a `BaseColliderInfo` slot in place from raw component data.\n * Returns `true` if the slot was filled, `false` if the entity has no\n * collider (caller should skip it).\n *\n * If an entity has both AABB and circle colliders, AABB wins and only\n * the AABB offset is applied. This matches the dispatch precedence in\n * `computeContact`; the previous implementation stacked both offsets,\n * which was a bug.\n */\nexport function fillBaseColliderInfo<L extends string>(\n\tinfo: BaseColliderInfo<L>,\n\tentityId: number,\n\tx: number,\n\ty: number,\n\tlayer: L,\n\tcollidesWith: readonly L[],\n\taabb: { width: number; height: number; offsetX?: number; offsetY?: number } | undefined,\n\tcircle: { radius: number; offsetX?: number; offsetY?: number } | undefined,\n): boolean {\n\tinfo.entityId = entityId;\n\tinfo.layer = layer;\n\tinfo.collidesWith = collidesWith;\n\n\tif (aabb) {\n\t\tinfo.x = x + (aabb.offsetX ?? 0);\n\t\tinfo.y = y + (aabb.offsetY ?? 0);\n\t\tinfo.shape = AABB_SHAPE;\n\t\tinfo.halfWidth = aabb.width / 2;\n\t\tinfo.halfHeight = aabb.height / 2;\n\t\tinfo.radius = 0;\n\t\treturn true;\n\t}\n\n\tif (circle) {\n\t\tinfo.x = x + (circle.offsetX ?? 0);\n\t\tinfo.y = y + (circle.offsetY ?? 0);\n\t\tinfo.shape = CIRCLE_SHAPE;\n\t\tinfo.halfWidth = 0;\n\t\tinfo.halfHeight = 0;\n\t\tinfo.radius = circle.radius;\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n// ==================== Spatial Index Lookup ====================\n\n/**\n * Retrieve the optional spatialIndex resource, returning undefined when absent.\n * Centralizes the cross-plugin typed lookup so individual plugins don't each\n * need to import SpatialIndex or repeat the tryGetResource pattern.\n */\nexport function tryGetSpatialIndex(\n\ttryGetResource: <T>(key: string) => T | undefined,\n): SpatialIndex | undefined {\n\treturn tryGetResource<SpatialIndex>('spatialIndex');\n}\n\n// ==================== Narrowphase Tests ====================\n\n/**\n * Write an AABB-AABB contact into `out`. Returns `true` if the shapes\n * overlap (out was filled), `false` otherwise.\n */\nexport function computeAABBvsAABB(\n\tax: number, ay: number, ahw: number, ahh: number,\n\tbx: number, by: number, bhw: number, bhh: number,\n\tout: Contact,\n): boolean {\n\tconst dx = bx - ax;\n\tconst dy = by - ay;\n\tconst overlapX = (ahw + bhw) - Math.abs(dx);\n\tconst overlapY = (ahh + bhh) - Math.abs(dy);\n\n\tif (overlapX <= 0 || overlapY <= 0) return false;\n\n\tif (overlapX < overlapY) {\n\t\tout.normalX = dx >= 0 ? 1 : -1;\n\t\tout.normalY = 0;\n\t\tout.depth = overlapX;\n\t\treturn true;\n\t}\n\tout.normalX = 0;\n\tout.normalY = dy >= 0 ? 1 : -1;\n\tout.depth = overlapY;\n\treturn true;\n}\n\nexport function computeCircleVsCircle(\n\tax: number, ay: number, ar: number,\n\tbx: number, by: number, br: number,\n\tout: Contact,\n): boolean {\n\tconst dx = bx - ax;\n\tconst dy = by - ay;\n\tconst distSq = dx * dx + dy * dy;\n\tconst radiusSum = ar + br;\n\n\tif (distSq >= radiusSum * radiusSum) return false;\n\n\tconst dist = Math.sqrt(distSq);\n\tif (dist === 0) {\n\t\tout.normalX = 1;\n\t\tout.normalY = 0;\n\t\tout.depth = radiusSum;\n\t\treturn true;\n\t}\n\tout.normalX = dx / dist;\n\tout.normalY = dy / dist;\n\tout.depth = radiusSum - dist;\n\treturn true;\n}\n\nexport function computeAABBvsCircle(\n\taabbX: number, aabbY: number, ahw: number, ahh: number,\n\tcircleX: number, circleY: number, radius: number,\n\tout: Contact,\n): boolean {\n\tconst closestX = Math.max(aabbX - ahw, Math.min(circleX, aabbX + ahw));\n\tconst closestY = Math.max(aabbY - ahh, Math.min(circleY, aabbY + ahh));\n\n\tconst dx = circleX - closestX;\n\tconst dy = circleY - closestY;\n\tconst distSq = dx * dx + dy * dy;\n\n\tif (distSq >= radius * radius) return false;\n\n\t// Circle center inside AABB\n\tif (distSq === 0) {\n\t\tconst pushLeft = (circleX - (aabbX - ahw));\n\t\tconst pushRight = ((aabbX + ahw) - circleX);\n\t\tconst pushUp = (circleY - (aabbY - ahh));\n\t\tconst pushDown = ((aabbY + ahh) - circleY);\n\t\tconst minPush = Math.min(pushLeft, pushRight, pushUp, pushDown);\n\n\t\tif (minPush === pushRight) {\n\t\t\tout.normalX = 1; out.normalY = 0; out.depth = pushRight + radius;\n\t\t\treturn true;\n\t\t}\n\t\tif (minPush === pushLeft) {\n\t\t\tout.normalX = -1; out.normalY = 0; out.depth = pushLeft + radius;\n\t\t\treturn true;\n\t\t}\n\t\tif (minPush === pushDown) {\n\t\t\tout.normalX = 0; out.normalY = 1; out.depth = pushDown + radius;\n\t\t\treturn true;\n\t\t}\n\t\tout.normalX = 0; out.normalY = -1; out.depth = pushUp + radius;\n\t\treturn true;\n\t}\n\n\tconst dist = Math.sqrt(distSq);\n\tout.normalX = dx / dist;\n\tout.normalY = dy / dist;\n\tout.depth = radius - dist;\n\treturn true;\n}\n\n// ==================== Contact Dispatcher ====================\n\n/**\n * Dispatch to the correct narrowphase function for the given pair and\n * write the contact into `out`. Returns `true` if the pair overlaps.\n */\nexport function computeContact(a: BaseColliderInfo, b: BaseColliderInfo, out: Contact): boolean {\n\tif (a.shape === AABB_SHAPE && b.shape === AABB_SHAPE) {\n\t\treturn computeAABBvsAABB(\n\t\t\ta.x, a.y, a.halfWidth, a.halfHeight,\n\t\t\tb.x, b.y, b.halfWidth, b.halfHeight,\n\t\t\tout,\n\t\t);\n\t}\n\n\tif (a.shape === CIRCLE_SHAPE && b.shape === CIRCLE_SHAPE) {\n\t\treturn computeCircleVsCircle(\n\t\t\ta.x, a.y, a.radius,\n\t\t\tb.x, b.y, b.radius,\n\t\t\tout,\n\t\t);\n\t}\n\n\tif (a.shape === AABB_SHAPE && b.shape === CIRCLE_SHAPE) {\n\t\treturn computeAABBvsCircle(\n\t\t\ta.x, a.y, a.halfWidth, a.halfHeight,\n\t\t\tb.x, b.y, b.radius,\n\t\t\tout,\n\t\t);\n\t}\n\n\t// a is Circle, b is AABB — compute as AABB-vs-Circle, then flip normal in place\n\tif (!computeAABBvsCircle(\n\t\tb.x, b.y, b.halfWidth, b.halfHeight,\n\t\ta.x, a.y, a.radius,\n\t\tout,\n\t)) return false;\n\tout.normalX = -out.normalX;\n\tout.normalY = -out.normalY;\n\treturn true;\n}\n\n// ==================== Collision Iteration ====================\n\n/** Module-level reusable set for broadphase candidates. */\nconst _broadphaseCandidates = new Set<number>();\n\nlet _bruteForceWarned = false;\nconst BRUTE_FORCE_WARN_THRESHOLD = 50;\n\n/**\n * Generic collision detection pipeline: brute-force or broadphase,\n * with layer filtering and contact computation.\n *\n * `count` is the number of live entries at the front of `colliders`.\n * The array itself may be a grow-only pool — only indices `[0, count)`\n * are iterated, so trailing pool slots are ignored.\n *\n * `workingMap` is a caller-owned `Map<number, I>` used by the broadphase\n * path as an entityId → collider lookup. It is cleared and repopulated on\n * each call; callers should allocate it once and pass the same instance\n * every frame. Unused by the brute-force path but still required so that\n * typed reuse is the default, not an opt-in.\n *\n * Uses a context parameter forwarded to the callback to avoid\n * per-frame closure allocation.\n */\nexport function detectCollisions<I extends BaseColliderInfo, C>(\n\tcolliders: I[],\n\tcount: number,\n\tworkingMap: Map<number, I>,\n\tspatialIndex: SpatialIndex | undefined,\n\tonContact: (a: I, b: I, contact: Contact, context: C) => void,\n\tcontext: C,\n): void {\n\tif (spatialIndex) {\n\t\tbroadphaseDetect(colliders, count, workingMap, spatialIndex, onContact, context);\n\t} else {\n\t\tbruteForceDetect(colliders, count, onContact, context);\n\t}\n}\n\nfunction bruteForceDetect<I extends BaseColliderInfo, C>(\n\tcolliders: I[],\n\tcount: number,\n\tonContact: (a: I, b: I, contact: Contact, context: C) => void,\n\tcontext: C,\n): void {\n\tif (!_bruteForceWarned && count >= BRUTE_FORCE_WARN_THRESHOLD) {\n\t\t_bruteForceWarned = true;\n\t\tconsole.warn(\n\t\t\t`[ecspresso] Collision detection is using O(n²) brute force with ${count} colliders. ` +\n\t\t\t`For better performance, install createSpatialIndexPlugin() alongside your collision or physics2D plugin.`,\n\t\t);\n\t}\n\n\tfor (let i = 0; i < count; i++) {\n\t\tconst a = colliders[i];\n\t\tif (!a) continue;\n\n\t\tfor (let j = i + 1; j < count; j++) {\n\t\t\tconst b = colliders[j];\n\t\t\tif (!b) continue;\n\n\t\t\tif (!a.collidesWith.includes(b.layer) && !b.collidesWith.includes(a.layer)) continue;\n\n\t\t\tif (!computeContact(a, b, _sharedContact)) continue;\n\n\t\t\tonContact(a, b, _sharedContact, context);\n\t\t}\n\t}\n}\n\nfunction broadphaseDetect<I extends BaseColliderInfo, C>(\n\tcolliders: I[],\n\tcount: number,\n\tcolliderMap: Map<number, I>,\n\tspatialIndex: SpatialIndex,\n\tonContact: (a: I, b: I, contact: Contact, context: C) => void,\n\tcontext: C,\n): void {\n\tcolliderMap.clear();\n\tfor (let i = 0; i < count; i++) {\n\t\tconst c = colliders[i];\n\t\tif (!c) continue;\n\t\tcolliderMap.set(c.entityId, c);\n\t}\n\n\tfor (let i = 0; i < count; i++) {\n\t\tconst a = colliders[i];\n\t\tif (!a) continue;\n\n\t\tconst aHalfW = a.shape === AABB_SHAPE ? a.halfWidth : a.radius;\n\t\tconst aHalfH = a.shape === AABB_SHAPE ? a.halfHeight : a.radius;\n\n\t\t_broadphaseCandidates.clear();\n\t\tspatialIndex.queryRectInto(\n\t\t\ta.x - aHalfW, a.y - aHalfH,\n\t\t\ta.x + aHalfW, a.y + aHalfH,\n\t\t\t_broadphaseCandidates,\n\t\t);\n\n\t\t// TODO(perf): mirrors narrowphase3D — dense grids add every candidate\n\t\t// (including `a` itself and lower-ID entities) to the set before the\n\t\t// filter below discards ~half of them. Emitting only pairs with larger\n\t\t// IDs at query time would remove the post-hoc filter. Keep in sync with\n\t\t// whatever fix lands in narrowphase3D.\n\t\tfor (const bId of _broadphaseCandidates) {\n\t\t\tif (bId <= a.entityId) continue;\n\n\t\t\tconst b = colliderMap.get(bId);\n\t\t\tif (!b) continue;\n\n\t\t\tif (!a.collidesWith.includes(b.layer) && !b.collidesWith.includes(a.layer)) continue;\n\n\t\t\tif (!computeContact(a, b, _sharedContact)) continue;\n\n\t\t\tonContact(a, b, _sharedContact, context);\n\t\t}\n\t}\n}\n",
7
7
  "/**\n * Flocking Plugin for ECSpresso\n *\n * Classic boid simulation — separation, alignment, cohesion. Produces\n * emergent group movement from simple per-entity steering forces.\n *\n * Composes with the physics2D plugin: flocking computes steering forces\n * and feeds them through `applyForce()`. Physics integration handles\n * velocity and position updates.\n *\n * Requires the spatial-index plugin for efficient neighbor queries.\n * Entities must have a `circleCollider` (or `aabbCollider`) to appear\n * in spatial index queries.\n */\n\nimport { definePlugin, type BasePluginOptions } from 'ecspresso';\nimport type { WorldConfigFrom } from 'ecspresso';\nimport type { TransformWorldConfig } from '../spatial/transform';\nimport type { Physics2DOwnComponentTypes } from '../physics/physics2D';\nimport { applyForce } from '../physics/physics2D';\nimport type { SpatialIndexResourceTypes } from '../spatial/spatial-index';\n\n// ==================== Component Types ====================\n\n/**\n * Configures flocking behavior for a boid entity.\n *\n * Entities with this component must also have:\n * - `localTransform` + `worldTransform` (transform plugin)\n * - `velocity` + `force` + `rigidBody` (physics2D plugin)\n * - `circleCollider` with radius >= perceptionRadius (for spatial index queries)\n */\nexport interface FlockingAgent {\n\t/** Radius within which neighbors are detected */\n\tperceptionRadius: number;\n\t/** Separation weight — steer away from nearby neighbors (default: 1.5) */\n\tseparationWeight: number;\n\t/** Alignment weight — match average heading of neighbors (default: 1.0) */\n\talignmentWeight: number;\n\t/** Cohesion weight — steer toward average position of neighbors (default: 1.0) */\n\tcohesionWeight: number;\n\t/** Maximum steering force magnitude per frame */\n\tmaxForce: number;\n\t/** Maximum velocity magnitude (hard speed cap) */\n\tmaxSpeed: number;\n\t/** Flock group ID for independent flocks (default: 0) */\n\tflockGroup: number;\n}\n\n/**\n * Component types provided by the flocking plugin.\n */\nexport interface FlockingComponentTypes {\n\tflockingAgent: FlockingAgent;\n}\n\n// ==================== WorldConfig ====================\n\n/**\n * WorldConfig representing the flocking plugin's provided types.\n */\nexport type FlockingWorldConfig = WorldConfigFrom<FlockingComponentTypes>;\n\n// ==================== Plugin Options ====================\n\nexport interface FlockingPluginOptions<G extends string = 'ai'> extends BasePluginOptions<G> {\n\t/** Priority for the heading/speed-clamp system (default: 200) */\n\theadingPriority?: number;\n}\n\n// ==================== Helper Functions ====================\n\n/**\n * Create a flockingAgent component with sensible defaults.\n *\n * Entities must also have a `circleCollider` with radius >= perceptionRadius\n * for the spatial index to find them as neighbors.\n *\n * @param options Partial overrides for flocking agent fields\n * @returns Component object suitable for spreading into spawn()\n *\n * @example\n * ```typescript\n * ecs.spawn({\n * ...createFlockingAgent({ perceptionRadius: 80, maxSpeed: 150 }),\n * ...createRigidBody('dynamic', { mass: 1, drag: 1, gravityScale: 0 }),\n * ...createCircleCollider(80),\n * ...createGraphicsComponents(boidGraphics, { x: 100, y: 200 }),\n * });\n * ```\n */\nexport function createFlockingAgent(\n\toptions?: Partial<FlockingAgent>,\n): Pick<FlockingComponentTypes, 'flockingAgent'> {\n\treturn {\n\t\tflockingAgent: {\n\t\t\tperceptionRadius: options?.perceptionRadius ?? 100,\n\t\t\tseparationWeight: options?.separationWeight ?? 1.5,\n\t\t\talignmentWeight: options?.alignmentWeight ?? 1.0,\n\t\t\tcohesionWeight: options?.cohesionWeight ?? 1.0,\n\t\t\tmaxForce: options?.maxForce ?? 400,\n\t\t\tmaxSpeed: options?.maxSpeed ?? 200,\n\t\t\tflockGroup: options?.flockGroup ?? 0,\n\t\t},\n\t};\n}\n\n// ==================== Plugin Factory ====================\n\n// Module-scoped reusable set to reduce GC pressure in neighbor queries\nconst _neighborSet = new Set<number>();\n\nconst SPEED_EPSILON = 0.01;\n\n/**\n * Create a flocking plugin for ECSpresso.\n *\n * Installs two systems:\n * - `flocking-forces` — computes separation/alignment/cohesion and applies via applyForce()\n * - `flocking-heading` — clamps speed to maxSpeed and orients rotation to match velocity\n *\n * Requires the transform, physics2D, and spatial-index plugins to be installed.\n *\n * @example\n * ```typescript\n * const ecs = ECSpresso.create()\n * .withPlugin(createRenderer2DPlugin({ background: '#0a0a2e' }))\n * .withPlugin(createPhysics2DPlugin())\n * .withPlugin(createSpatialIndexPlugin())\n * .withPlugin(createFlockingPlugin())\n * .build();\n * ```\n */\nexport function createFlockingPlugin<G extends string = 'ai'>(\n\toptions?: FlockingPluginOptions<G>,\n) {\n\tconst {\n\t\tsystemGroup = 'ai',\n\t\tpriority = 500,\n\t\tphase = 'update',\n\t\theadingPriority = 200,\n\t} = options ?? {};\n\n\treturn definePlugin('flocking')\n\t\t.withComponentTypes<FlockingComponentTypes>()\n\t\t.withLabels<'flocking-forces' | 'flocking-heading'>()\n\t\t.withGroups<G>()\n\t\t.requires<\n\t\t\tTransformWorldConfig &\n\t\t\tWorldConfigFrom<Pick<Physics2DOwnComponentTypes, 'velocity' | 'force'>> &\n\t\t\tWorldConfigFrom<{}, {}, SpatialIndexResourceTypes>\n\t\t>()\n\t\t.install((world) => {\n\t\t\t// --- System 1: Compute and apply flocking forces ---\n\t\t\tworld\n\t\t\t\t.addSystem('flocking-forces')\n\t\t\t\t.setPriority(priority)\n\t\t\t\t.inPhase(phase)\n\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t.addQuery('boids', {\n\t\t\t\t\twith: ['flockingAgent', 'worldTransform', 'velocity', 'force'],\n\t\t\t\t})\n\t\t\t\t.setProcess(({ queries, ecs }) => {\n\t\t\t\t\tconst spatialIndex = ecs.getResource('spatialIndex');\n\n\t\t\t\t\tfor (const entity of queries.boids) {\n\t\t\t\t\t\tconst { flockingAgent, worldTransform, velocity } = entity.components;\n\t\t\t\t\t\tconst { perceptionRadius, separationWeight, alignmentWeight, cohesionWeight, maxForce, flockGroup } = flockingAgent;\n\n\t\t\t\t\t\t// Query neighbors via spatial index\n\t\t\t\t\t\t_neighborSet.clear();\n\t\t\t\t\t\tspatialIndex.queryRadiusInto(worldTransform.x, worldTransform.y, perceptionRadius, _neighborSet);\n\n\t\t\t\t\t\t// Accumulate steering forces — all inline scalars, no allocations\n\t\t\t\t\t\tlet sepX = 0, sepY = 0, sepCount = 0;\n\t\t\t\t\t\tlet alignX = 0, alignY = 0, alignCount = 0;\n\t\t\t\t\t\tlet cohX = 0, cohY = 0, cohCount = 0;\n\n\t\t\t\t\t\tconst separationRadius = perceptionRadius * 0.5;\n\t\t\t\t\t\tconst separationRadiusSq = separationRadius * separationRadius;\n\n\t\t\t\t\t\tfor (const neighborId of _neighborSet) {\n\t\t\t\t\t\t\tif (neighborId === entity.id) continue;\n\n\t\t\t\t\t\t\tconst neighborAgent = ecs.getComponent(neighborId, 'flockingAgent');\n\t\t\t\t\t\t\tif (!neighborAgent) continue;\n\t\t\t\t\t\t\tif (neighborAgent.flockGroup !== flockGroup) continue;\n\n\t\t\t\t\t\t\tconst neighborTransform = ecs.getComponent(neighborId, 'worldTransform');\n\t\t\t\t\t\t\tif (!neighborTransform) continue;\n\n\t\t\t\t\t\t\tconst dx = worldTransform.x - neighborTransform.x;\n\t\t\t\t\t\t\tconst dy = worldTransform.y - neighborTransform.y;\n\t\t\t\t\t\t\tconst distSq = dx * dx + dy * dy;\n\n\t\t\t\t\t\t\t// Separation — closer neighbors push harder\n\t\t\t\t\t\t\tif (distSq > 0 && distSq < separationRadiusSq) {\n\t\t\t\t\t\t\t\tconst dist = Math.sqrt(distSq);\n\t\t\t\t\t\t\t\tsepX += dx / dist;\n\t\t\t\t\t\t\t\tsepY += dy / dist;\n\t\t\t\t\t\t\t\tsepCount++;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Alignment — average velocity of neighbors\n\t\t\t\t\t\t\tconst neighborVel = ecs.getComponent(neighborId, 'velocity');\n\t\t\t\t\t\t\tif (neighborVel) {\n\t\t\t\t\t\t\t\talignX += neighborVel.x;\n\t\t\t\t\t\t\t\talignY += neighborVel.y;\n\t\t\t\t\t\t\t\talignCount++;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Cohesion — average position of neighbors\n\t\t\t\t\t\t\tcohX += neighborTransform.x;\n\t\t\t\t\t\t\tcohY += neighborTransform.y;\n\t\t\t\t\t\t\tcohCount++;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlet totalFx = 0, totalFy = 0;\n\n\t\t\t\t\t\t// Separation: steer away from crowded neighbors\n\t\t\t\t\t\tif (sepCount > 0) {\n\t\t\t\t\t\t\ttotalFx += (sepX / sepCount) * separationWeight;\n\t\t\t\t\t\t\ttotalFy += (sepY / sepCount) * separationWeight;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Alignment: steer toward average heading\n\t\t\t\t\t\tif (alignCount > 0) {\n\t\t\t\t\t\t\tconst avgVx = alignX / alignCount;\n\t\t\t\t\t\t\tconst avgVy = alignY / alignCount;\n\t\t\t\t\t\t\t// Desired = average velocity - current velocity\n\t\t\t\t\t\t\ttotalFx += (avgVx - velocity.x) * alignmentWeight;\n\t\t\t\t\t\t\ttotalFy += (avgVy - velocity.y) * alignmentWeight;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Cohesion: steer toward average position\n\t\t\t\t\t\tif (cohCount > 0) {\n\t\t\t\t\t\t\tconst avgPx = cohX / cohCount;\n\t\t\t\t\t\t\tconst avgPy = cohY / cohCount;\n\t\t\t\t\t\t\t// Desired = direction to center of mass - current velocity\n\t\t\t\t\t\t\ttotalFx += (avgPx - worldTransform.x - velocity.x) * cohesionWeight;\n\t\t\t\t\t\t\ttotalFy += (avgPy - worldTransform.y - velocity.y) * cohesionWeight;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Clamp total steering force to maxForce\n\t\t\t\t\t\tconst forceMagSq = totalFx * totalFx + totalFy * totalFy;\n\t\t\t\t\t\tif (forceMagSq > maxForce * maxForce) {\n\t\t\t\t\t\t\tconst forceMag = Math.sqrt(forceMagSq);\n\t\t\t\t\t\t\ttotalFx = (totalFx / forceMag) * maxForce;\n\t\t\t\t\t\t\ttotalFy = (totalFy / forceMag) * maxForce;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tapplyForce(ecs, entity.id, totalFx, totalFy);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t// --- System 2: Clamp speed and orient heading from velocity ---\n\t\t\tworld\n\t\t\t\t.addSystem('flocking-heading')\n\t\t\t\t.setPriority(headingPriority)\n\t\t\t\t.inPhase(phase)\n\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t.addQuery('boids', {\n\t\t\t\t\twith: ['flockingAgent', 'velocity', 'localTransform'],\n\t\t\t\t})\n\t\t\t\t.setProcess(({ queries, ecs }) => {\n\t\t\t\t\tfor (const entity of queries.boids) {\n\t\t\t\t\t\tconst { flockingAgent, velocity, localTransform } = entity.components;\n\t\t\t\t\t\tconst { maxSpeed } = flockingAgent;\n\n\t\t\t\t\t\t// Clamp velocity to maxSpeed\n\t\t\t\t\t\tconst speedSq = velocity.x * velocity.x + velocity.y * velocity.y;\n\t\t\t\t\t\tif (speedSq > maxSpeed * maxSpeed) {\n\t\t\t\t\t\t\tconst speed = Math.sqrt(speedSq);\n\t\t\t\t\t\t\tvelocity.x = (velocity.x / speed) * maxSpeed;\n\t\t\t\t\t\t\tvelocity.y = (velocity.y / speed) * maxSpeed;\n\t\t\t\t\t\t\tecs.markChanged(entity.id, 'velocity');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Orient rotation to match velocity heading\n\t\t\t\t\t\tif (speedSq > SPEED_EPSILON * SPEED_EPSILON) {\n\t\t\t\t\t\t\tconst heading = Math.atan2(velocity.y, velocity.x);\n\t\t\t\t\t\t\tif (heading !== localTransform.rotation) {\n\t\t\t\t\t\t\t\tlocalTransform.rotation = heading;\n\t\t\t\t\t\t\t\tecs.markChanged(entity.id, 'localTransform');\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t});\n}\n"
8
8
  ],
9
- "mappings": "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",
10
- "debugId": "86EF73C7B0F16E1564756E2164756E21",
9
+ "mappings": "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",
10
+ "debugId": "4B6E9CAC48D6266764756E2164756E21",
11
11
  "names": []
12
12
  }
@@ -1,4 +1,4 @@
1
- var q=Object.defineProperty;var T=(j)=>j;function z(j,D){this[j]=T.bind(null,D)}var f=(j,D)=>{for(var A in D)q(j,A,{get:D[A],enumerable:!0,configurable:!0,set:z.bind(D,A)})};var y=(j,D)=>()=>(j&&(D=j(j=0)),D);var m=((j)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(j,{get:(D,A)=>(typeof require<"u"?require:D)[A]}):j)(function(j){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+j+'" is not supported')});import{definePlugin as C}from"ecspresso";var F={neighbors(j,D,A){let J=D%j.width,K=(D-J)/j.width,H=0;if(J>0)A[H++]=D-1;if(J<j.width-1)A[H++]=D+1;if(K>0)A[H++]=D-j.width;if(K<j.height-1)A[H++]=D+j.width;return H},stepCost(j,D,A){return j.cells[A]??0},heuristic(j,D,A){let J=D%j.width,K=(D-J)/j.width,H=A%j.width,E=(A-H)/j.width;return Math.abs(J-H)+Math.abs(K-E)}},k=(j)=>{let D=()=>{throw Error(`pathfinding: topology '${j}' is not implemented in v1`)};return{neighbors:D,stepCost:D,heuristic:D}},b=Object.freeze({square4:F,square8:k("square8"),"hex-pointy":k("hex-pointy"),"hex-flat":k("hex-flat")});function x(j){let D=j.topology??"square4",A=j.cellSize??32,J=j.originX??0,K=j.originY??0,{width:H,height:E}=j,_=j.defaultCost??1;if(!Number.isInteger(H)||H<=0)throw Error(`pathfinding: width must be a positive integer, got ${H}`);if(!Number.isInteger(E)||E<=0)throw Error(`pathfinding: height must be a positive integer, got ${E}`);if(A<=0)throw Error(`pathfinding: cellSize must be > 0, got ${A}`);if(_<0||_>255)throw Error(`pathfinding: defaultCost must be in 0–255, got ${_}`);let U=H*E,Q=j.cells??new Uint8Array(U).fill(_);if(Q.length!==U)throw Error(`pathfinding: cells length ${Q.length} does not match width*height ${U}`);let $=1/A;return{topology:D,width:H,height:E,cellSize:A,originX:J,originY:K,cells:Q,worldToCell:(W,N)=>{let B=Math.floor((W-J)*$),Z=Math.floor((N-K)*$),X=B<0?0:B>=H?H-1:B;return(Z<0?0:Z>=E?E-1:Z)*H+X},cellToWorld:(W)=>{let N=W%H,B=(W-N)/H;return{x:J+(N+0.5)*A,y:K+(B+0.5)*A}},cellFromXY:(W,N)=>N*H+W,cellToXY:(W)=>{let N=W%H;return{x:N,y:(W-N)/H}}}}function l(j){return{pathRequest:{target:{x:j.x,y:j.y}}}}function O(j,D,A){let J=j.size;j.size=J+1;while(J>0){let K=J-1>>1;if((j.priorities[K]??0)<=A)break;j.ids[J]=j.ids[K]??0,j.priorities[J]=j.priorities[K]??0,J=K}j.ids[J]=D,j.priorities[J]=A}function P(j){let D=j.ids[0]??-1,A=j.size-1;if(j.size=A,A<=0)return D;let J=j.ids[A]??0,K=j.priorities[A]??0,H=0,E=A>>1;while(H<E){let _=(H<<1)+1,U=_+1;if(U<A&&(j.priorities[U]??0)<(j.priorities[_]??0))_=U;if((j.priorities[_]??0)>=K)break;j.ids[H]=j.ids[_]??0,j.priorities[H]=j.priorities[_]??0,H=_}return j.ids[H]=J,j.priorities[H]=K,D}function S(j,D){let A=1,J=D;while((j[J]??-1)!==-1)A++,J=j[J]??-1;let K=Array(A);J=D;for(let H=A-1;H>=0;H--)if(K[H]=J,H>0)J=j[J]??-1;return K}function v(j,D,A,J){let K=j.cells.length;if(D<0||D>=K)return null;if(A<0||A>=K)return null;let H=J?.maxNodesExpanded??1e4,E=J?.blockedCells,_=J?.goalTolerance??0,U=b[j.topology],Q=new Float32Array(K);Q.fill(Number.POSITIVE_INFINITY);let $=new Int32Array(K);$.fill(-1);let I=new Uint8Array(K),V={ids:new Int32Array(K),priorities:new Float32Array(K),size:0},M=[];Q[D]=0,O(V,D,U.heuristic(j,D,A));let R=0;while(V.size>0){if(R>=H)return null;let W=P(V);if(I[W])continue;if(I[W]=1,R++,U.heuristic(j,W,A)<=_)return S($,W);M.length=0;let N=U.neighbors(j,W,M);for(let B=0;B<N;B++){let Z=M[B]??-1;if(Z<0||I[Z])continue;if((j.cells[Z]??0)===0)continue;if(E&&E.has(Z))continue;let L=(Q[W]??Number.POSITIVE_INFINITY)+U.stepCost(j,W,Z);if(L<(Q[Z]??Number.POSITIVE_INFINITY))Q[Z]=L,$[Z]=W,O(V,Z,L+U.heuristic(j,Z,A))}}return null}function g(j){let{grid:D,systemGroup:A="ai",priority:J=150,phase:K="update",maxRequestsPerFrame:H=4,maxNodesExpanded:E=1e4}=j;return C("pathfinding").withComponentTypes().withEventTypes().withResourceTypes().withLabels().withGroups().requires().install((_)=>{_.addResource("navGrid",D),_.addSystem("pathfinding-request").setPriority(J).inPhase(K).inGroup(A).addQuery("requests",{with:["pathRequest","worldTransform"]}).setProcess(({queries:U,ecs:Q})=>{let $=Q.getResource("navGrid"),I=0;for(let V of U.requests){if(I>=H)break;I++;let{pathRequest:M,worldTransform:R}=V.components,W=$.worldToCell(R.x,R.y),N=$.worldToCell(M.target.x,M.target.y),B=v($,W,N,{maxNodesExpanded:E});if(Q.commands.removeComponent(V.id,"pathRequest"),B===null){Q.eventBus.publish("pathBlocked",{entityId:V.id});continue}let Z=B.slice(1).map((G)=>$.cellToWorld(G));if(Q.eventBus.publish("pathFound",{entityId:V.id,path:Z}),Z.length===0)continue;let X=Q.getComponent(V.id,"path");if(X)X.waypoints=Z,X.currentIndex=0,Q.markChanged(V.id,"path");else Q.addComponent(V.id,"path",{waypoints:Z,currentIndex:0});let L=Z[0];if(!L)continue;let Y=Q.getComponent(V.id,"moveTarget");if(Y)Y.x=L.x,Y.y=L.y,Q.markChanged(V.id,"moveTarget");else Q.addComponent(V.id,"moveTarget",{x:L.x,y:L.y})}}),_.addSystem("pathfinding-waypoint-advance").inGroup(A).setEventHandlers({arriveAtTarget({data:U,ecs:Q}){let $=Q.getComponent(U.entityId,"path");if(!$)return;let I=$.currentIndex+1;if(I>=$.waypoints.length){Q.commands.removeComponent(U.entityId,"path");return}$.currentIndex=I,Q.markChanged(U.entityId,"path");let V=$.waypoints[I];if(!V)return;Q.commands.addComponent(U.entityId,"moveTarget",{x:V.x,y:V.y})}})})}export{v as findPath,g as createPathfindingPlugin,l as createPathRequest,x as createNavGrid};
1
+ var P=((j)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(j,{get:(J,A)=>(typeof require<"u"?require:J)[A]}):j)(function(j){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+j+'" is not supported')});import{definePlugin as q}from"ecspresso";var T={neighbors(j,J,A){let H=J%j.width,K=(J-H)/j.width,D=0;if(H>0)A[D++]=J-1;if(H<j.width-1)A[D++]=J+1;if(K>0)A[D++]=J-j.width;if(K<j.height-1)A[D++]=J+j.width;return D},stepCost(j,J,A){return j.cells[A]??0},heuristic(j,J,A){let H=J%j.width,K=(J-H)/j.width,D=A%j.width,E=(A-D)/j.width;return Math.abs(H-D)+Math.abs(K-E)}},k=(j)=>{let J=()=>{throw Error(`pathfinding: topology '${j}' is not implemented in v1`)};return{neighbors:J,stepCost:J,heuristic:J}},z=Object.freeze({square4:T,square8:k("square8"),"hex-pointy":k("hex-pointy"),"hex-flat":k("hex-flat")});function f(j){let J=j.topology??"square4",A=j.cellSize??32,H=j.originX??0,K=j.originY??0,{width:D,height:E}=j,_=j.defaultCost??1;if(!Number.isInteger(D)||D<=0)throw Error(`pathfinding: width must be a positive integer, got ${D}`);if(!Number.isInteger(E)||E<=0)throw Error(`pathfinding: height must be a positive integer, got ${E}`);if(A<=0)throw Error(`pathfinding: cellSize must be > 0, got ${A}`);if(_<0||_>255)throw Error(`pathfinding: defaultCost must be in 0–255, got ${_}`);let U=D*E,Q=j.cells??new Uint8Array(U).fill(_);if(Q.length!==U)throw Error(`pathfinding: cells length ${Q.length} does not match width*height ${U}`);let $=1/A;return{topology:J,width:D,height:E,cellSize:A,originX:H,originY:K,cells:Q,worldToCell:(W,N)=>{let B=Math.floor((W-H)*$),Z=Math.floor((N-K)*$),X=B<0?0:B>=D?D-1:B;return(Z<0?0:Z>=E?E-1:Z)*D+X},cellToWorld:(W)=>{let N=W%D,B=(W-N)/D;return{x:H+(N+0.5)*A,y:K+(B+0.5)*A}},cellFromXY:(W,N)=>N*D+W,cellToXY:(W)=>{let N=W%D;return{x:N,y:(W-N)/D}}}}function y(j){return{pathRequest:{target:{x:j.x,y:j.y}}}}function O(j,J,A){let H=j.size;j.size=H+1;while(H>0){let K=H-1>>1;if((j.priorities[K]??0)<=A)break;j.ids[H]=j.ids[K]??0,j.priorities[H]=j.priorities[K]??0,H=K}j.ids[H]=J,j.priorities[H]=A}function C(j){let J=j.ids[0]??-1,A=j.size-1;if(j.size=A,A<=0)return J;let H=j.ids[A]??0,K=j.priorities[A]??0,D=0,E=A>>1;while(D<E){let _=(D<<1)+1,U=_+1;if(U<A&&(j.priorities[U]??0)<(j.priorities[_]??0))_=U;if((j.priorities[_]??0)>=K)break;j.ids[D]=j.ids[_]??0,j.priorities[D]=j.priorities[_]??0,D=_}return j.ids[D]=H,j.priorities[D]=K,J}function F(j,J){let A=1,H=J;while((j[H]??-1)!==-1)A++,H=j[H]??-1;let K=Array(A);H=J;for(let D=A-1;D>=0;D--)if(K[D]=H,D>0)H=j[H]??-1;return K}function b(j,J,A,H){let K=j.cells.length;if(J<0||J>=K)return null;if(A<0||A>=K)return null;let D=H?.maxNodesExpanded??1e4,E=H?.blockedCells,_=H?.goalTolerance??0,U=z[j.topology],Q=new Float32Array(K);Q.fill(Number.POSITIVE_INFINITY);let $=new Int32Array(K);$.fill(-1);let I=new Uint8Array(K),V={ids:new Int32Array(K),priorities:new Float32Array(K),size:0},M=[];Q[J]=0,O(V,J,U.heuristic(j,J,A));let R=0;while(V.size>0){if(R>=D)return null;let W=C(V);if(I[W])continue;if(I[W]=1,R++,U.heuristic(j,W,A)<=_)return F($,W);M.length=0;let N=U.neighbors(j,W,M);for(let B=0;B<N;B++){let Z=M[B]??-1;if(Z<0||I[Z])continue;if((j.cells[Z]??0)===0)continue;if(E&&E.has(Z))continue;let L=(Q[W]??Number.POSITIVE_INFINITY)+U.stepCost(j,W,Z);if(L<(Q[Z]??Number.POSITIVE_INFINITY))Q[Z]=L,$[Z]=W,O(V,Z,L+U.heuristic(j,Z,A))}}return null}function m(j){let{grid:J,systemGroup:A="ai",priority:H=150,phase:K="update",maxRequestsPerFrame:D=4,maxNodesExpanded:E=1e4}=j;return q("pathfinding").withComponentTypes().withEventTypes().withResourceTypes().withLabels().withGroups().requires().install((_)=>{_.addResource("navGrid",J),_.addSystem("pathfinding-request").setPriority(H).inPhase(K).inGroup(A).addQuery("requests",{with:["pathRequest","worldTransform"]}).setProcess(({queries:U,ecs:Q})=>{let $=Q.getResource("navGrid"),I=0;for(let V of U.requests){if(I>=D)break;I++;let{pathRequest:M,worldTransform:R}=V.components,W=$.worldToCell(R.x,R.y),N=$.worldToCell(M.target.x,M.target.y),B=b($,W,N,{maxNodesExpanded:E});if(Q.commands.removeComponent(V.id,"pathRequest"),B===null){Q.eventBus.publish("pathBlocked",{entityId:V.id});continue}let Z=B.slice(1).map((G)=>$.cellToWorld(G));if(Q.eventBus.publish("pathFound",{entityId:V.id,path:Z}),Z.length===0)continue;let X=Q.getComponent(V.id,"path");if(X)X.waypoints=Z,X.currentIndex=0,Q.markChanged(V.id,"path");else Q.addComponent(V.id,"path",{waypoints:Z,currentIndex:0});let L=Z[0];if(!L)continue;let Y=Q.getComponent(V.id,"moveTarget");if(Y)Y.x=L.x,Y.y=L.y,Q.markChanged(V.id,"moveTarget");else Q.addComponent(V.id,"moveTarget",{x:L.x,y:L.y})}}),_.addSystem("pathfinding-waypoint-advance").inGroup(A).setEventHandlers({arriveAtTarget({data:U,ecs:Q}){let $=Q.getComponent(U.entityId,"path");if(!$)return;let I=$.currentIndex+1;if(I>=$.waypoints.length){Q.commands.removeComponent(U.entityId,"path");return}$.currentIndex=I,Q.markChanged(U.entityId,"path");let V=$.waypoints[I];if(!V)return;Q.commands.addComponent(U.entityId,"moveTarget",{x:V.x,y:V.y})}})})}export{b as findPath,m as createPathfindingPlugin,y as createPathRequest,f as createNavGrid};
2
2
 
3
- //# debugId=8835265364E0B69F64756E2164756E21
3
+ //# debugId=72F70AA348AB2CF664756E2164756E21
4
4
  //# sourceMappingURL=pathfinding.js.map
@@ -4,7 +4,7 @@
4
4
  "sourcesContent": [
5
5
  "/**\n * Pathfinding Plugin for ECSpresso\n *\n * A* pathfinding on a weighted grid. Produces waypoint lists consumed by the\n * steering plugin — the pathfinding system writes the `path` component and\n * sets `moveTarget` to the first waypoint; the waypoint advancement handler\n * listens for `arriveAtTarget` and advances to the next waypoint.\n *\n * Exports the pure `findPath(grid, start, goal, options?)` function for\n * turn-based / non-realtime consumers that don't need the component dance.\n */\n\nimport { definePlugin, type BasePluginOptions } from 'ecspresso';\nimport type { WorldConfigFrom } from 'ecspresso';\nimport type { Vector2D } from '../../utils/math';\nimport type { TransformWorldConfig } from '../spatial/transform';\nimport type { SteeringWorldConfig } from '../physics/steering';\n\n// ==================== Topology / Grid Types ====================\n\n/** Flat-indexed cell position in a `NavGrid`. Transparent alias, not branded. */\nexport type CellIndex = number;\n\n/**\n * Grid topology. v1 ships `square4`; other values are accepted at construction\n * but throw at `findPath` time.\n */\nexport type NavGridTopology = 'square4' | 'square8' | 'hex-pointy' | 'hex-flat';\n\n/**\n * Weighted navigation grid. Row-major storage (`idx = row * width + col`).\n * Cell value `0` = impassable, `1`–`255` = traversal cost into that cell.\n */\nexport interface NavGrid {\n\treadonly topology: NavGridTopology;\n\treadonly width: number;\n\treadonly height: number;\n\treadonly cellSize: number;\n\treadonly originX: number;\n\treadonly originY: number;\n\treadonly cells: Uint8Array;\n\tworldToCell(wx: number, wy: number): CellIndex;\n\tcellToWorld(idx: CellIndex): Vector2D;\n\tcellFromXY(x: number, y: number): CellIndex;\n\tcellToXY(idx: CellIndex): { x: number; y: number };\n}\n\n/** Options accepted by `createNavGrid`. */\nexport interface CreateNavGridOptions {\n\ttopology?: NavGridTopology;\n\twidth: number;\n\theight: number;\n\tcellSize?: number;\n\toriginX?: number;\n\toriginY?: number;\n\tcells?: Uint8Array;\n\tdefaultCost?: number;\n}\n\n// ==================== Component Types ====================\n\n/** Signals the pathfinding system to compute a route to `target`. */\nexport interface PathRequest {\n\ttarget: Vector2D;\n}\n\n/** Active route; waypoints are in world-space, advanced by `currentIndex`. */\nexport interface Path {\n\twaypoints: Vector2D[];\n\tcurrentIndex: number;\n}\n\n/** Component types provided by the pathfinding plugin. */\nexport interface PathfindingComponentTypes {\n\tpathRequest: PathRequest;\n\tpath: Path;\n}\n\n// ==================== Event Types ====================\n\n/** Fired when A* produces a route. `path` is empty when start is already at the goal. */\nexport interface PathFoundEvent {\n\tentityId: number;\n\tpath: Vector2D[];\n}\n\n/** Fired when no path exists to the target. */\nexport interface PathBlockedEvent {\n\tentityId: number;\n}\n\n/** Event types provided by the pathfinding plugin. */\nexport interface PathfindingEventTypes {\n\tpathFound: PathFoundEvent;\n\tpathBlocked: PathBlockedEvent;\n}\n\n// ==================== Resource Types ====================\n\n/** Resource types provided by the pathfinding plugin. */\nexport interface PathfindingResourceTypes {\n\tnavGrid: NavGrid;\n}\n\n// ==================== WorldConfig ====================\n\n/** WorldConfig representing the pathfinding plugin's provided types. */\nexport type PathfindingWorldConfig = WorldConfigFrom<\n\tPathfindingComponentTypes,\n\tPathfindingEventTypes,\n\tPathfindingResourceTypes\n>;\n\n// ==================== Plugin Options ====================\n\nexport interface PathfindingPluginOptions<G extends string = 'ai'> extends BasePluginOptions<G> {\n\t/** The navigation grid. Construct via `createNavGrid`. */\n\tgrid: NavGrid;\n\t/** Max path requests processed per frame (default 4). */\n\tmaxRequestsPerFrame?: number;\n\t/** Default `maxNodesExpanded` passed to A* per request (default 10_000). */\n\tmaxNodesExpanded?: number;\n}\n\n// ==================== NavGrid Construction ====================\n\ninterface TopologyOps {\n\tneighbors(grid: NavGrid, idx: CellIndex, out: number[]): number;\n\tstepCost(grid: NavGrid, from: CellIndex, to: CellIndex): number;\n\theuristic(grid: NavGrid, a: CellIndex, b: CellIndex): number;\n}\n\nconst square4Ops: TopologyOps = {\n\tneighbors(grid, idx, out) {\n\t\tconst col = idx % grid.width;\n\t\tconst row = (idx - col) / grid.width;\n\t\tlet count = 0;\n\t\tif (col > 0) out[count++] = idx - 1;\n\t\tif (col < grid.width - 1) out[count++] = idx + 1;\n\t\tif (row > 0) out[count++] = idx - grid.width;\n\t\tif (row < grid.height - 1) out[count++] = idx + grid.width;\n\t\treturn count;\n\t},\n\tstepCost(grid, _from, to) {\n\t\treturn grid.cells[to] ?? 0;\n\t},\n\theuristic(grid, a, b) {\n\t\tconst ax = a % grid.width;\n\t\tconst ay = (a - ax) / grid.width;\n\t\tconst bx = b % grid.width;\n\t\tconst by = (b - bx) / grid.width;\n\t\treturn Math.abs(ax - bx) + Math.abs(ay - by);\n\t},\n};\n\nconst unimplementedOps = (topology: NavGridTopology): TopologyOps => {\n\tconst err = (): never => {\n\t\tthrow new Error(`pathfinding: topology '${topology}' is not implemented in v1`);\n\t};\n\treturn {\n\t\tneighbors: err,\n\t\tstepCost: err,\n\t\theuristic: err,\n\t};\n};\n\nconst topologyOps: Readonly<Record<NavGridTopology, TopologyOps>> = Object.freeze({\n\t'square4': square4Ops,\n\t'square8': unimplementedOps('square8'),\n\t'hex-pointy': unimplementedOps('hex-pointy'),\n\t'hex-flat': unimplementedOps('hex-flat'),\n});\n\n/**\n * Create a weighted navigation grid.\n *\n * @example\n * ```typescript\n * const grid = createNavGrid({ width: 32, height: 32, cellSize: 16 });\n * grid.cells[grid.cellFromXY(5, 5)] = 0; // block a cell\n * ```\n */\nexport function createNavGrid(options: CreateNavGridOptions): NavGrid {\n\tconst topology = options.topology ?? 'square4';\n\tconst cellSize = options.cellSize ?? 32;\n\tconst originX = options.originX ?? 0;\n\tconst originY = options.originY ?? 0;\n\tconst { width, height } = options;\n\tconst defaultCost = options.defaultCost ?? 1;\n\n\tif (!Number.isInteger(width) || width <= 0) {\n\t\tthrow new Error(`pathfinding: width must be a positive integer, got ${width}`);\n\t}\n\tif (!Number.isInteger(height) || height <= 0) {\n\t\tthrow new Error(`pathfinding: height must be a positive integer, got ${height}`);\n\t}\n\tif (cellSize <= 0) {\n\t\tthrow new Error(`pathfinding: cellSize must be > 0, got ${cellSize}`);\n\t}\n\tif (defaultCost < 0 || defaultCost > 255) {\n\t\tthrow new Error(`pathfinding: defaultCost must be in 0–255, got ${defaultCost}`);\n\t}\n\n\tconst expectedLen = width * height;\n\tconst cells = options.cells ?? new Uint8Array(expectedLen).fill(defaultCost);\n\tif (cells.length !== expectedLen) {\n\t\tthrow new Error(\n\t\t\t`pathfinding: cells length ${cells.length} does not match width*height ${expectedLen}`,\n\t\t);\n\t}\n\n\tconst invCellSize = 1 / cellSize;\n\n\tconst worldToCell = (wx: number, wy: number): CellIndex => {\n\t\tconst col = Math.floor((wx - originX) * invCellSize);\n\t\tconst row = Math.floor((wy - originY) * invCellSize);\n\t\tconst cCol = col < 0 ? 0 : col >= width ? width - 1 : col;\n\t\tconst cRow = row < 0 ? 0 : row >= height ? height - 1 : row;\n\t\treturn cRow * width + cCol;\n\t};\n\n\tconst cellToWorld = (idx: CellIndex): Vector2D => {\n\t\tconst col = idx % width;\n\t\tconst row = (idx - col) / width;\n\t\treturn {\n\t\t\tx: originX + (col + 0.5) * cellSize,\n\t\t\ty: originY + (row + 0.5) * cellSize,\n\t\t};\n\t};\n\n\tconst cellFromXY = (x: number, y: number): CellIndex => y * width + x;\n\n\tconst cellToXY = (idx: CellIndex): { x: number; y: number } => {\n\t\tconst x = idx % width;\n\t\treturn { x, y: (idx - x) / width };\n\t};\n\n\treturn {\n\t\ttopology, width, height, cellSize, originX, originY, cells,\n\t\tworldToCell, cellToWorld, cellFromXY, cellToXY,\n\t};\n}\n\n// ==================== Helper Functions ====================\n\n/**\n * Create a `pathRequest` component for spreading into `spawn()` / `addComponent()`.\n *\n * @example\n * ```typescript\n * ecs.spawn({\n * ...createTransform(0, 0),\n * ...createMoveSpeed(100),\n * ...createPathRequest({ x: 200, y: 300 }),\n * });\n * ```\n */\nexport function createPathRequest(target: Vector2D): Pick<PathfindingComponentTypes, 'pathRequest'> {\n\treturn { pathRequest: { target: { x: target.x, y: target.y } } };\n}\n\n// ==================== Pure A* API ====================\n\nexport interface FindPathOptions {\n\t/** Cap on A* node expansions; returns `null` if exceeded. Default 10_000. */\n\tmaxNodesExpanded?: number;\n\t/** Dynamic per-call obstacles layered on top of the static grid. */\n\tblockedCells?: Set<CellIndex>;\n\t/** Accept arrival within N cells of goal (topology-aware distance). Default 0. */\n\tgoalTolerance?: number;\n}\n\ninterface PathHeap {\n\tids: Int32Array;\n\tpriorities: Float32Array;\n\tsize: number;\n}\n\n// Why: parallel-typed-array heap keeps cells & priorities in cache without per-node allocations.\nfunction heapPush(heap: PathHeap, id: number, priority: number): void {\n\tlet i = heap.size;\n\theap.size = i + 1;\n\twhile (i > 0) {\n\t\tconst parent = (i - 1) >> 1;\n\t\tif ((heap.priorities[parent] ?? 0) <= priority) break;\n\t\theap.ids[i] = heap.ids[parent] ?? 0;\n\t\theap.priorities[i] = heap.priorities[parent] ?? 0;\n\t\ti = parent;\n\t}\n\theap.ids[i] = id;\n\theap.priorities[i] = priority;\n}\n\nfunction heapPop(heap: PathHeap): number {\n\tconst top = heap.ids[0] ?? -1;\n\tconst last = heap.size - 1;\n\theap.size = last;\n\tif (last <= 0) return top;\n\tconst movedId = heap.ids[last] ?? 0;\n\tconst movedPri = heap.priorities[last] ?? 0;\n\tlet i = 0;\n\tconst half = last >> 1;\n\twhile (i < half) {\n\t\tlet child = (i << 1) + 1;\n\t\tconst right = child + 1;\n\t\tif (right < last && (heap.priorities[right] ?? 0) < (heap.priorities[child] ?? 0)) child = right;\n\t\tif ((heap.priorities[child] ?? 0) >= movedPri) break;\n\t\theap.ids[i] = heap.ids[child] ?? 0;\n\t\theap.priorities[i] = heap.priorities[child] ?? 0;\n\t\ti = child;\n\t}\n\theap.ids[i] = movedId;\n\theap.priorities[i] = movedPri;\n\treturn top;\n}\n\nfunction reconstructPath(cameFrom: Int32Array, end: CellIndex): CellIndex[] {\n\t// Why: two-pass (count then fill) avoids unshift/reverse allocation.\n\tlet count = 1;\n\tlet cur = end;\n\twhile ((cameFrom[cur] ?? -1) !== -1) {\n\t\tcount++;\n\t\tcur = cameFrom[cur] ?? -1;\n\t}\n\tconst path = new Array<CellIndex>(count);\n\tcur = end;\n\tfor (let i = count - 1; i >= 0; i--) {\n\t\tpath[i] = cur;\n\t\tif (i > 0) cur = cameFrom[cur] ?? -1;\n\t}\n\treturn path;\n}\n\n/**\n * Compute a path through `grid` from `start` to `goal`.\n *\n * Returns a list of cell indices starting with `start` and ending at a cell\n * within `goalTolerance` of `goal`, or `null` if no such path exists within\n * `maxNodesExpanded` expansions.\n *\n * `start` is always treated as passable (even if its grid cell is 0 or the\n * cell is in `blockedCells`) — actors physics-pushed onto a wall still get a\n * valid origin.\n */\nexport function findPath(\n\tgrid: NavGrid,\n\tstart: CellIndex,\n\tgoal: CellIndex,\n\toptions?: FindPathOptions,\n): CellIndex[] | null {\n\tconst n = grid.cells.length;\n\tif (start < 0 || start >= n) return null;\n\tif (goal < 0 || goal >= n) return null;\n\n\tconst maxNodesExpanded = options?.maxNodesExpanded ?? 10_000;\n\tconst blockedCells = options?.blockedCells;\n\tconst goalTolerance = options?.goalTolerance ?? 0;\n\tconst ops = topologyOps[grid.topology];\n\n\t// Per-call allocations: ~n bytes × 5 (gScore, cameFrom, closed, heap ids, heap priorities).\n\t// For a 100×100 grid that's ~120 KB per search. Acceptable for v1 game-grid scales.\n\t// Deferred optimization: closure-scoped reusable pool keyed by `n`, reset per call.\n\tconst gScore = new Float32Array(n);\n\tgScore.fill(Number.POSITIVE_INFINITY);\n\tconst cameFrom = new Int32Array(n);\n\tcameFrom.fill(-1);\n\tconst closed = new Uint8Array(n);\n\tconst heap: PathHeap = {\n\t\tids: new Int32Array(n),\n\t\tpriorities: new Float32Array(n),\n\t\tsize: 0,\n\t};\n\tconst neighborBuf: number[] = [];\n\n\tgScore[start] = 0;\n\theapPush(heap, start, ops.heuristic(grid, start, goal));\n\n\tlet expanded = 0;\n\twhile (heap.size > 0) {\n\t\tif (expanded >= maxNodesExpanded) return null;\n\t\tconst current = heapPop(heap);\n\t\tif (closed[current]) continue;\n\t\tclosed[current] = 1;\n\t\texpanded++;\n\n\t\tif (ops.heuristic(grid, current, goal) <= goalTolerance) {\n\t\t\treturn reconstructPath(cameFrom, current);\n\t\t}\n\n\t\tneighborBuf.length = 0;\n\t\tconst count = ops.neighbors(grid, current, neighborBuf);\n\t\tfor (let k = 0; k < count; k++) {\n\t\t\tconst next = neighborBuf[k] ?? -1;\n\t\t\tif (next < 0 || closed[next]) continue;\n\t\t\tconst cellCost = grid.cells[next] ?? 0;\n\t\t\tif (cellCost === 0) continue;\n\t\t\tif (blockedCells && blockedCells.has(next)) continue;\n\n\t\t\tconst tentative = (gScore[current] ?? Number.POSITIVE_INFINITY) + ops.stepCost(grid, current, next);\n\t\t\tif (tentative < (gScore[next] ?? Number.POSITIVE_INFINITY)) {\n\t\t\t\tgScore[next] = tentative;\n\t\t\t\tcameFrom[next] = current;\n\t\t\t\theapPush(heap, next, tentative + ops.heuristic(grid, next, goal));\n\t\t\t}\n\t\t}\n\t}\n\treturn null;\n}\n\n// ==================== Plugin Factory ====================\n\n/**\n * Create a pathfinding plugin for ECSpresso.\n *\n * Requires the transform and steering plugins to be installed (entities need\n * `worldTransform` for start-cell detection and `moveTarget`/`moveSpeed` for\n * waypoint traversal).\n *\n * @example\n * ```typescript\n * const grid = createNavGrid({ width: 32, height: 32, cellSize: 16 });\n * const ecs = ECSpresso.create()\n * .withPlugin(createTransformPlugin())\n * .withPlugin(createSteeringPlugin())\n * .withPlugin(createPathfindingPlugin({ grid }))\n * .build();\n *\n * ecs.spawn({\n * ...createTransform(0, 0),\n * ...createMoveSpeed(100),\n * ...createPathRequest({ x: 500, y: 300 }),\n * });\n * ```\n */\nexport function createPathfindingPlugin<G extends string = 'ai'>(\n\toptions: PathfindingPluginOptions<G>,\n) {\n\tconst {\n\t\tgrid,\n\t\tsystemGroup = 'ai' as G,\n\t\tpriority = 150,\n\t\tphase = 'update',\n\t\tmaxRequestsPerFrame = 4,\n\t\tmaxNodesExpanded = 10_000,\n\t} = options;\n\n\treturn definePlugin('pathfinding')\n\t\t.withComponentTypes<PathfindingComponentTypes>()\n\t\t.withEventTypes<PathfindingEventTypes>()\n\t\t.withResourceTypes<PathfindingResourceTypes>()\n\t\t.withLabels<'pathfinding-request' | 'pathfinding-waypoint-advance'>()\n\t\t.withGroups<G>()\n\t\t.requires<TransformWorldConfig & SteeringWorldConfig>()\n\t\t.install((world) => {\n\t\t\tworld.addResource('navGrid', grid);\n\n\t\t\tworld\n\t\t\t\t.addSystem('pathfinding-request')\n\t\t\t\t.setPriority(priority)\n\t\t\t\t.inPhase(phase)\n\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t.addQuery('requests', {\n\t\t\t\t\twith: ['pathRequest', 'worldTransform'],\n\t\t\t\t})\n\t\t\t\t.setProcess(({ queries, ecs }) => {\n\t\t\t\t\tconst navGrid = ecs.getResource('navGrid');\n\t\t\t\t\tlet processed = 0;\n\t\t\t\t\tfor (const entity of queries.requests) {\n\t\t\t\t\t\tif (processed >= maxRequestsPerFrame) break;\n\t\t\t\t\t\tprocessed++;\n\t\t\t\t\t\tconst { pathRequest, worldTransform } = entity.components;\n\t\t\t\t\t\tconst startIdx = navGrid.worldToCell(worldTransform.x, worldTransform.y);\n\t\t\t\t\t\tconst goalIdx = navGrid.worldToCell(pathRequest.target.x, pathRequest.target.y);\n\t\t\t\t\t\tconst result = findPath(navGrid, startIdx, goalIdx, { maxNodesExpanded });\n\t\t\t\t\t\tecs.commands.removeComponent(entity.id, 'pathRequest');\n\n\t\t\t\t\t\tif (result === null) {\n\t\t\t\t\t\t\tecs.eventBus.publish('pathBlocked', { entityId: entity.id });\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst waypoints = result.slice(1).map(idx => navGrid.cellToWorld(idx));\n\t\t\t\t\t\tecs.eventBus.publish('pathFound', { entityId: entity.id, path: waypoints });\n\t\t\t\t\t\tif (waypoints.length === 0) continue;\n\n\t\t\t\t\t\tconst existingPath = ecs.getComponent(entity.id, 'path');\n\t\t\t\t\t\tif (existingPath) {\n\t\t\t\t\t\t\texistingPath.waypoints = waypoints;\n\t\t\t\t\t\t\texistingPath.currentIndex = 0;\n\t\t\t\t\t\t\tecs.markChanged(entity.id, 'path');\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tecs.addComponent(entity.id, 'path', { waypoints, currentIndex: 0 });\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst first = waypoints[0];\n\t\t\t\t\t\tif (!first) continue;\n\t\t\t\t\t\tconst existingMT = ecs.getComponent(entity.id, 'moveTarget');\n\t\t\t\t\t\tif (existingMT) {\n\t\t\t\t\t\t\texistingMT.x = first.x;\n\t\t\t\t\t\t\texistingMT.y = first.y;\n\t\t\t\t\t\t\tecs.markChanged(entity.id, 'moveTarget');\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tecs.addComponent(entity.id, 'moveTarget', { x: first.x, y: first.y });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\tworld\n\t\t\t\t.addSystem('pathfinding-waypoint-advance')\n\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t.setEventHandlers({\n\t\t\t\t\tarriveAtTarget({ data, ecs }) {\n\t\t\t\t\t\tconst path = ecs.getComponent(data.entityId, 'path');\n\t\t\t\t\t\tif (!path) return;\n\t\t\t\t\t\tconst next = path.currentIndex + 1;\n\t\t\t\t\t\tif (next >= path.waypoints.length) {\n\t\t\t\t\t\t\tecs.commands.removeComponent(data.entityId, 'path');\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tpath.currentIndex = next;\n\t\t\t\t\t\tecs.markChanged(data.entityId, 'path');\n\t\t\t\t\t\tconst wp = path.waypoints[next];\n\t\t\t\t\t\tif (!wp) return;\n\t\t\t\t\t\t// Why: use command buffer so the add is queued AFTER steering's\n\t\t\t\t\t\t// queued `removeComponent('moveTarget')` in the same phase.\n\t\t\t\t\t\tecs.commands.addComponent(data.entityId, 'moveTarget', { x: wp.x, y: wp.y });\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t});\n}\n"
6
6
  ],
7
- "mappings": "4cAYA,uBAAS,kBAwHT,IAAM,EAA0B,CAC/B,SAAS,CAAC,EAAM,EAAK,EAAK,CACzB,IAAM,EAAM,EAAM,EAAK,MACjB,GAAO,EAAM,GAAO,EAAK,MAC3B,EAAQ,EACZ,GAAI,EAAM,EAAG,EAAI,KAAW,EAAM,EAClC,GAAI,EAAM,EAAK,MAAQ,EAAG,EAAI,KAAW,EAAM,EAC/C,GAAI,EAAM,EAAG,EAAI,KAAW,EAAM,EAAK,MACvC,GAAI,EAAM,EAAK,OAAS,EAAG,EAAI,KAAW,EAAM,EAAK,MACrD,OAAO,GAER,QAAQ,CAAC,EAAM,EAAO,EAAI,CACzB,OAAO,EAAK,MAAM,IAAO,GAE1B,SAAS,CAAC,EAAM,EAAG,EAAG,CACrB,IAAM,EAAK,EAAI,EAAK,MACd,GAAM,EAAI,GAAM,EAAK,MACrB,EAAK,EAAI,EAAK,MACd,GAAM,EAAI,GAAM,EAAK,MAC3B,OAAO,KAAK,IAAI,EAAK,CAAE,EAAI,KAAK,IAAI,EAAK,CAAE,EAE7C,EAEM,EAAmB,CAAC,IAA2C,CACpE,IAAM,EAAM,IAAa,CACxB,MAAU,MAAM,0BAA0B,6BAAoC,GAE/E,MAAO,CACN,UAAW,EACX,SAAU,EACV,UAAW,CACZ,GAGK,EAA8D,OAAO,OAAO,CACjF,QAAW,EACX,QAAW,EAAiB,SAAS,EACrC,aAAc,EAAiB,YAAY,EAC3C,WAAY,EAAiB,UAAU,CACxC,CAAC,EAWM,SAAS,CAAa,CAAC,EAAwC,CACrE,IAAM,EAAW,EAAQ,UAAY,UAC/B,EAAW,EAAQ,UAAY,GAC/B,EAAU,EAAQ,SAAW,EAC7B,EAAU,EAAQ,SAAW,GAC3B,QAAO,UAAW,EACpB,EAAc,EAAQ,aAAe,EAE3C,GAAI,CAAC,OAAO,UAAU,CAAK,GAAK,GAAS,EACxC,MAAU,MAAM,sDAAsD,GAAO,EAE9E,GAAI,CAAC,OAAO,UAAU,CAAM,GAAK,GAAU,EAC1C,MAAU,MAAM,uDAAuD,GAAQ,EAEhF,GAAI,GAAY,EACf,MAAU,MAAM,0CAA0C,GAAU,EAErE,GAAI,EAAc,GAAK,EAAc,IACpC,MAAU,MAAM,kDAAiD,GAAa,EAG/E,IAAM,EAAc,EAAQ,EACtB,EAAQ,EAAQ,OAAS,IAAI,WAAW,CAAW,EAAE,KAAK,CAAW,EAC3E,GAAI,EAAM,SAAW,EACpB,MAAU,MACT,6BAA6B,EAAM,sCAAsC,GAC1E,EAGD,IAAM,EAAc,EAAI,EA0BxB,MAAO,CACN,WAAU,QAAO,SAAQ,WAAU,UAAS,UAAS,QACrD,YA1BmB,CAAC,EAAY,IAA0B,CAC1D,IAAM,EAAM,KAAK,OAAO,EAAK,GAAW,CAAW,EAC7C,EAAM,KAAK,OAAO,EAAK,GAAW,CAAW,EAC7C,EAAO,EAAM,EAAI,EAAI,GAAO,EAAQ,EAAQ,EAAI,EAEtD,OADa,EAAM,EAAI,EAAI,GAAO,EAAS,EAAS,EAAI,GAC1C,EAAQ,GAqBT,YAlBM,CAAC,IAA6B,CACjD,IAAM,EAAM,EAAM,EACZ,GAAO,EAAM,GAAO,EAC1B,MAAO,CACN,EAAG,GAAW,EAAM,KAAO,EAC3B,EAAG,GAAW,EAAM,KAAO,CAC5B,GAY0B,WATR,CAAC,EAAW,IAAyB,EAAI,EAAQ,EAS7B,SAPtB,CAAC,IAA6C,CAC9D,IAAM,EAAI,EAAM,EAChB,MAAO,CAAE,IAAG,GAAI,EAAM,GAAK,CAAM,EAMlC,EAiBM,SAAS,CAAiB,CAAC,EAAkE,CACnG,MAAO,CAAE,YAAa,CAAE,OAAQ,CAAE,EAAG,EAAO,EAAG,EAAG,EAAO,CAAE,CAAE,CAAE,EAqBhE,SAAS,CAAQ,CAAC,EAAgB,EAAY,EAAwB,CACrE,IAAI,EAAI,EAAK,KACb,EAAK,KAAO,EAAI,EAChB,MAAO,EAAI,EAAG,CACb,IAAM,EAAU,EAAI,GAAM,EAC1B,IAAK,EAAK,WAAW,IAAW,IAAM,EAAU,MAChD,EAAK,IAAI,GAAK,EAAK,IAAI,IAAW,EAClC,EAAK,WAAW,GAAK,EAAK,WAAW,IAAW,EAChD,EAAI,EAEL,EAAK,IAAI,GAAK,EACd,EAAK,WAAW,GAAK,EAGtB,SAAS,CAAO,CAAC,EAAwB,CACxC,IAAM,EAAM,EAAK,IAAI,IAAM,GACrB,EAAO,EAAK,KAAO,EAEzB,GADA,EAAK,KAAO,EACR,GAAQ,EAAG,OAAO,EACtB,IAAM,EAAU,EAAK,IAAI,IAAS,EAC5B,EAAW,EAAK,WAAW,IAAS,EACtC,EAAI,EACF,EAAO,GAAQ,EACrB,MAAO,EAAI,EAAM,CAChB,IAAI,GAAS,GAAK,GAAK,EACjB,EAAQ,EAAQ,EACtB,GAAI,EAAQ,IAAS,EAAK,WAAW,IAAU,IAAM,EAAK,WAAW,IAAU,GAAI,EAAQ,EAC3F,IAAK,EAAK,WAAW,IAAU,IAAM,EAAU,MAC/C,EAAK,IAAI,GAAK,EAAK,IAAI,IAAU,EACjC,EAAK,WAAW,GAAK,EAAK,WAAW,IAAU,EAC/C,EAAI,EAIL,OAFA,EAAK,IAAI,GAAK,EACd,EAAK,WAAW,GAAK,EACd,EAGR,SAAS,CAAe,CAAC,EAAsB,EAA6B,CAE3E,IAAI,EAAQ,EACR,EAAM,EACV,OAAQ,EAAS,IAAQ,MAAQ,GAChC,IACA,EAAM,EAAS,IAAQ,GAExB,IAAM,EAAW,MAAiB,CAAK,EACvC,EAAM,EACN,QAAS,EAAI,EAAQ,EAAG,GAAK,EAAG,IAE/B,GADA,EAAK,GAAK,EACN,EAAI,EAAG,EAAM,EAAS,IAAQ,GAEnC,OAAO,EAcD,SAAS,CAAQ,CACvB,EACA,EACA,EACA,EACqB,CACrB,IAAM,EAAI,EAAK,MAAM,OACrB,GAAI,EAAQ,GAAK,GAAS,EAAG,OAAO,KACpC,GAAI,EAAO,GAAK,GAAQ,EAAG,OAAO,KAElC,IAAM,EAAmB,GAAS,kBAAoB,IAChD,EAAe,GAAS,aACxB,EAAgB,GAAS,eAAiB,EAC1C,EAAM,EAAY,EAAK,UAKvB,EAAS,IAAI,aAAa,CAAC,EACjC,EAAO,KAAK,OAAO,iBAAiB,EACpC,IAAM,EAAW,IAAI,WAAW,CAAC,EACjC,EAAS,KAAK,EAAE,EAChB,IAAM,EAAS,IAAI,WAAW,CAAC,EACzB,EAAiB,CACtB,IAAK,IAAI,WAAW,CAAC,EACrB,WAAY,IAAI,aAAa,CAAC,EAC9B,KAAM,CACP,EACM,EAAwB,CAAC,EAE/B,EAAO,GAAS,EAChB,EAAS,EAAM,EAAO,EAAI,UAAU,EAAM,EAAO,CAAI,CAAC,EAEtD,IAAI,EAAW,EACf,MAAO,EAAK,KAAO,EAAG,CACrB,GAAI,GAAY,EAAkB,OAAO,KACzC,IAAM,EAAU,EAAQ,CAAI,EAC5B,GAAI,EAAO,GAAU,SAIrB,GAHA,EAAO,GAAW,EAClB,IAEI,EAAI,UAAU,EAAM,EAAS,CAAI,GAAK,EACzC,OAAO,EAAgB,EAAU,CAAO,EAGzC,EAAY,OAAS,EACrB,IAAM,EAAQ,EAAI,UAAU,EAAM,EAAS,CAAW,EACtD,QAAS,EAAI,EAAG,EAAI,EAAO,IAAK,CAC/B,IAAM,EAAO,EAAY,IAAM,GAC/B,GAAI,EAAO,GAAK,EAAO,GAAO,SAE9B,IADiB,EAAK,MAAM,IAAS,KACpB,EAAG,SACpB,GAAI,GAAgB,EAAa,IAAI,CAAI,EAAG,SAE5C,IAAM,GAAa,EAAO,IAAY,OAAO,mBAAqB,EAAI,SAAS,EAAM,EAAS,CAAI,EAClG,GAAI,GAAa,EAAO,IAAS,OAAO,mBACvC,EAAO,GAAQ,EACf,EAAS,GAAQ,EACjB,EAAS,EAAM,EAAM,EAAY,EAAI,UAAU,EAAM,EAAM,CAAI,CAAC,GAInE,OAAO,KA4BD,SAAS,CAAgD,CAC/D,EACC,CACD,IACC,OACA,cAAc,KACd,WAAW,IACX,QAAQ,SACR,sBAAsB,EACtB,mBAAmB,KAChB,EAEJ,OAAO,EAAa,aAAa,EAC/B,mBAA8C,EAC9C,eAAsC,EACtC,kBAA4C,EAC5C,WAAmE,EACnE,WAAc,EACd,SAAqD,EACrD,QAAQ,CAAC,IAAU,CACnB,EAAM,YAAY,UAAW,CAAI,EAEjC,EACE,UAAU,qBAAqB,EAC/B,YAAY,CAAQ,EACpB,QAAQ,CAAK,EACb,QAAQ,CAAW,EACnB,SAAS,WAAY,CACrB,KAAM,CAAC,cAAe,gBAAgB,CACvC,CAAC,EACA,WAAW,EAAG,UAAS,SAAU,CACjC,IAAM,EAAU,EAAI,YAAY,SAAS,EACrC,EAAY,EAChB,QAAW,KAAU,EAAQ,SAAU,CACtC,GAAI,GAAa,EAAqB,MACtC,IACA,IAAQ,cAAa,kBAAmB,EAAO,WACzC,EAAW,EAAQ,YAAY,EAAe,EAAG,EAAe,CAAC,EACjE,EAAU,EAAQ,YAAY,EAAY,OAAO,EAAG,EAAY,OAAO,CAAC,EACxE,EAAS,EAAS,EAAS,EAAU,EAAS,CAAE,kBAAiB,CAAC,EAGxE,GAFA,EAAI,SAAS,gBAAgB,EAAO,GAAI,aAAa,EAEjD,IAAW,KAAM,CACpB,EAAI,SAAS,QAAQ,cAAe,CAAE,SAAU,EAAO,EAAG,CAAC,EAC3D,SAGD,IAAM,EAAY,EAAO,MAAM,CAAC,EAAE,IAAI,KAAO,EAAQ,YAAY,CAAG,CAAC,EAErE,GADA,EAAI,SAAS,QAAQ,YAAa,CAAE,SAAU,EAAO,GAAI,KAAM,CAAU,CAAC,EACtE,EAAU,SAAW,EAAG,SAE5B,IAAM,EAAe,EAAI,aAAa,EAAO,GAAI,MAAM,EACvD,GAAI,EACH,EAAa,UAAY,EACzB,EAAa,aAAe,EAC5B,EAAI,YAAY,EAAO,GAAI,MAAM,EAEjC,OAAI,aAAa,EAAO,GAAI,OAAQ,CAAE,YAAW,aAAc,CAAE,CAAC,EAGnE,IAAM,EAAQ,EAAU,GACxB,GAAI,CAAC,EAAO,SACZ,IAAM,EAAa,EAAI,aAAa,EAAO,GAAI,YAAY,EAC3D,GAAI,EACH,EAAW,EAAI,EAAM,EACrB,EAAW,EAAI,EAAM,EACrB,EAAI,YAAY,EAAO,GAAI,YAAY,EAEvC,OAAI,aAAa,EAAO,GAAI,aAAc,CAAE,EAAG,EAAM,EAAG,EAAG,EAAM,CAAE,CAAC,GAGtE,EAEF,EACE,UAAU,8BAA8B,EACxC,QAAQ,CAAW,EACnB,iBAAiB,CACjB,cAAc,EAAG,OAAM,OAAO,CAC7B,IAAM,EAAO,EAAI,aAAa,EAAK,SAAU,MAAM,EACnD,GAAI,CAAC,EAAM,OACX,IAAM,EAAO,EAAK,aAAe,EACjC,GAAI,GAAQ,EAAK,UAAU,OAAQ,CAClC,EAAI,SAAS,gBAAgB,EAAK,SAAU,MAAM,EAClD,OAED,EAAK,aAAe,EACpB,EAAI,YAAY,EAAK,SAAU,MAAM,EACrC,IAAM,EAAK,EAAK,UAAU,GAC1B,GAAI,CAAC,EAAI,OAGT,EAAI,SAAS,aAAa,EAAK,SAAU,aAAc,CAAE,EAAG,EAAG,EAAG,EAAG,EAAG,CAAE,CAAC,EAE7E,CAAC,EACF",
8
- "debugId": "8835265364E0B69F64756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "72F70AA348AB2CF664756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,4 +1,4 @@
1
- var A=Object.defineProperty;var B=(J)=>J;function S(J,L){this[J]=B.bind(null,L)}var f=(J,L)=>{for(var Z in L)A(J,Z,{get:L[Z],enumerable:!0,configurable:!0,set:S.bind(L,Z)})};var w=(J,L)=>()=>(J&&(L=J(J=0)),L);var C=((J)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(J,{get:(L,Z)=>(typeof require<"u"?require:L)[Z]}):J)(function(J){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+J+'" is not supported')});import{definePlugin as V}from"ecspresso";function y(J){return Object.freeze(J)}function g(J,L,Z){return{audioSource:{sound:J,channel:L,volume:Z?.volume??1,loop:Z?.loop??!1,autoRemove:Z?.autoRemove??!1,playing:!1,_soundId:-1}}}function m(J,L){return()=>import("howler").then(({Howl:Z})=>new Promise((T,H)=>{let _,M=!1;if(_=new Z({src:Array.isArray(J)?J:[J],html5:L?.html5??!1,preload:L?.preload??!0,onload:()=>{M=!0,T(_)},onloaderror:(X,G)=>H(G instanceof Error?G:Error(String(G)))}),!M&&_.state?.()==="loaded")T(_)}))}function h(J){let{channels:L,systemGroup:Z="audio",priority:T=0,phase:H="update"}=J,_=new Map,M=new Map,X=new Map,G=1,j=!1,N=[];for(let[z,q]of Object.entries(L))_.set(z,q.volume),N.push(z);let P=N[0];function E(z,q){if(j)return 0;let F=_.get(q)??1;return z*F*G}function R(z){for(let F of M.values()){if(F.channel!==z)continue;F.howl.volume(E(F.individualVolume,z),F.soundId)}let q=X.get(z);if(q)q.howl.volume(E(q.individualVolume,z),q.soundId)}function W(){for(let z of N)R(z)}function b(z){let q=M.get(z);if(!q)return;q.howl.stop(z),M.delete(z)}let k=null,D=null,O={play(z,q){if(!D)return-1;let F=q?.channel??P,Y=q?.volume??1,Q=q?.loop??!1,U=D(z);U.volume(E(Y,F)),U.loop(Q);let K=U.play(),$={howl:U,soundId:K,channel:F,individualVolume:Y,assetKey:z,entityId:-1};return M.set(K,$),U.once("end",()=>{M.delete(K),k?.publish("soundEnded",{entityId:-1,soundId:K,sound:z})},K),K},stop(z){b(z)},playMusic(z,q){if(!D)return;let F=q?.channel??P,Y=q?.volume??1,Q=q?.loop??!0,U=X.get(F);if(U)U.howl.stop(U.soundId),M.delete(U.soundId);let K=D(z);K.volume(E(Y,F)),K.loop(Q);let $=K.play(),x={howl:K,soundId:$,channel:F,individualVolume:Y,assetKey:z};X.set(F,x),M.set($,{...x,entityId:-1}),K.once("end",()=>{if(M.delete($),X.get(F)?.soundId===$)X.delete(F)},$)},stopMusic(z){if(z!==void 0){let q=X.get(z);if(q)q.howl.stop(q.soundId),M.delete(q.soundId),X.delete(z)}else for(let[q,F]of X)F.howl.stop(F.soundId),M.delete(F.soundId),X.delete(q)},pauseMusic(z){if(z!==void 0){let q=X.get(z);if(q)q.howl.pause(q.soundId)}else for(let q of X.values())q.howl.pause(q.soundId)},resumeMusic(z){if(z!==void 0){let q=X.get(z);if(q)q.howl.play(q.soundId)}else for(let q of X.values())q.howl.play(q.soundId)},setChannelVolume(z,q){_.set(z,q),R(z)},getChannelVolume(z){return _.get(z)??1},setMasterVolume(z){G=z,W()},getMasterVolume(){return G},mute(){j=!0,W()},unmute(){j=!1,W()},toggleMute(){j=!j,W()},isMuted(){return j}};return V("audio").withComponentTypes().withEventTypes().withResourceTypes().withLabels().withGroups().withReactiveQueryNames().install((z)=>{z.addResource("audioState",O),z.registerDispose("audioSource",({value:q})=>{if(q._soundId!==-1)b(q._soundId)}),z.addSystem("audio-sync").setPriority(T).inPhase(H).inGroup(Z).setOnInitialize((q)=>{k=q.eventBus;let F=q.tryGetResource("$assets");if(F)D=(Y)=>F.get(Y);q.addReactiveQuery("audio-sources",{with:["audioSource"],onEnter:(Y)=>{let Q=Y.components.audioSource;if(!D)return;if(Q._soundId!==-1)return;let U=D(Q.sound);U.volume(E(Q.volume,Q.channel)),U.loop(Q.loop);let K=U.play();Q._soundId=K,Q.playing=!0;let $={howl:U,soundId:K,channel:Q.channel,individualVolume:Q.volume,assetKey:Q.sound,entityId:Y.id};M.set(K,$),U.once("end",()=>{if(M.delete(K),Q.playing=!1,k?.publish("soundEnded",{entityId:Y.id,soundId:K,sound:Q.sound}),Q.autoRemove)q.commands.removeEntity(Y.id)},K)},onExit:(Y)=>{}})}).setEventHandlers({playSound({data:q,ecs:F}){F.getResource("audioState").play(q.sound,{channel:q.channel,volume:q.volume,loop:q.loop})},stopMusic({data:q,ecs:F}){F.getResource("audioState").stopMusic(q.channel)}}).setOnDetach(()=>{for(let q of M.values())q.howl.stop(q.soundId);M.clear(),X.clear(),k=null,D=null})})}function r(J){return{createAudioSource:g}}export{m as loadSound,y as defineAudioChannels,g as createAudioSource,h as createAudioPlugin,r as createAudioHelpers};
1
+ var A=((Q)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(Q,{get:($,Y)=>(typeof require<"u"?require:$)[Y]}):Q)(function(Q){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+Q+'" is not supported')});import{definePlugin as B}from"ecspresso";function I(Q){return Object.freeze(Q)}function S(Q,$,Y){return{audioSource:{sound:Q,channel:$,volume:Y?.volume??1,loop:Y?.loop??!1,autoRemove:Y?.autoRemove??!1,playing:!1,_soundId:-1}}}function f(Q,$){return()=>import("howler").then(({Howl:Y})=>new Promise((T,H)=>{let Z,K=!1;if(Z=new Y({src:Array.isArray(Q)?Q:[Q],html5:$?.html5??!1,preload:$?.preload??!0,onload:()=>{K=!0,T(Z)},onloaderror:(U,G)=>H(G instanceof Error?G:Error(String(G)))}),!K&&Z.state?.()==="loaded")T(Z)}))}function w(Q){let{channels:$,systemGroup:Y="audio",priority:T=0,phase:H="update"}=Q,Z=new Map,K=new Map,U=new Map,G=1,j=!1,N=[];for(let[z,q]of Object.entries($))Z.set(z,q.volume),N.push(z);let P=N[0];function E(z,q){if(j)return 0;let F=Z.get(q)??1;return z*F*G}function R(z){for(let F of K.values()){if(F.channel!==z)continue;F.howl.volume(E(F.individualVolume,z),F.soundId)}let q=U.get(z);if(q)q.howl.volume(E(q.individualVolume,z),q.soundId)}function W(){for(let z of N)R(z)}function b(z){let q=K.get(z);if(!q)return;q.howl.stop(z),K.delete(z)}let k=null,D=null,O={play(z,q){if(!D)return-1;let F=q?.channel??P,X=q?.volume??1,L=q?.loop??!1,M=D(z);M.volume(E(X,F)),M.loop(L);let J=M.play(),_={howl:M,soundId:J,channel:F,individualVolume:X,assetKey:z,entityId:-1};return K.set(J,_),M.once("end",()=>{K.delete(J),k?.publish("soundEnded",{entityId:-1,soundId:J,sound:z})},J),J},stop(z){b(z)},playMusic(z,q){if(!D)return;let F=q?.channel??P,X=q?.volume??1,L=q?.loop??!0,M=U.get(F);if(M)M.howl.stop(M.soundId),K.delete(M.soundId);let J=D(z);J.volume(E(X,F)),J.loop(L);let _=J.play(),x={howl:J,soundId:_,channel:F,individualVolume:X,assetKey:z};U.set(F,x),K.set(_,{...x,entityId:-1}),J.once("end",()=>{if(K.delete(_),U.get(F)?.soundId===_)U.delete(F)},_)},stopMusic(z){if(z!==void 0){let q=U.get(z);if(q)q.howl.stop(q.soundId),K.delete(q.soundId),U.delete(z)}else for(let[q,F]of U)F.howl.stop(F.soundId),K.delete(F.soundId),U.delete(q)},pauseMusic(z){if(z!==void 0){let q=U.get(z);if(q)q.howl.pause(q.soundId)}else for(let q of U.values())q.howl.pause(q.soundId)},resumeMusic(z){if(z!==void 0){let q=U.get(z);if(q)q.howl.play(q.soundId)}else for(let q of U.values())q.howl.play(q.soundId)},setChannelVolume(z,q){Z.set(z,q),R(z)},getChannelVolume(z){return Z.get(z)??1},setMasterVolume(z){G=z,W()},getMasterVolume(){return G},mute(){j=!0,W()},unmute(){j=!1,W()},toggleMute(){j=!j,W()},isMuted(){return j}};return B("audio").withComponentTypes().withEventTypes().withResourceTypes().withLabels().withGroups().withReactiveQueryNames().install((z)=>{z.addResource("audioState",O),z.registerDispose("audioSource",({value:q})=>{if(q._soundId!==-1)b(q._soundId)}),z.addSystem("audio-sync").setPriority(T).inPhase(H).inGroup(Y).setOnInitialize((q)=>{k=q.eventBus;let F=q.tryGetResource("$assets");if(F)D=(X)=>F.get(X);q.addReactiveQuery("audio-sources",{with:["audioSource"],onEnter:(X)=>{let L=X.components.audioSource;if(!D)return;if(L._soundId!==-1)return;let M=D(L.sound);M.volume(E(L.volume,L.channel)),M.loop(L.loop);let J=M.play();L._soundId=J,L.playing=!0;let _={howl:M,soundId:J,channel:L.channel,individualVolume:L.volume,assetKey:L.sound,entityId:X.id};K.set(J,_),M.once("end",()=>{if(K.delete(J),L.playing=!1,k?.publish("soundEnded",{entityId:X.id,soundId:J,sound:L.sound}),L.autoRemove)q.commands.removeEntity(X.id)},J)},onExit:(X)=>{}})}).setEventHandlers({playSound({data:q,ecs:F}){F.getResource("audioState").play(q.sound,{channel:q.channel,volume:q.volume,loop:q.loop})},stopMusic({data:q,ecs:F}){F.getResource("audioState").stopMusic(q.channel)}}).setOnDetach(()=>{for(let q of K.values())q.howl.stop(q.soundId);K.clear(),U.clear(),k=null,D=null})})}function v(Q){return{createAudioSource:S}}export{f as loadSound,I as defineAudioChannels,S as createAudioSource,w as createAudioPlugin,v as createAudioHelpers};
2
2
 
3
- //# debugId=E5072AB917D540E664756E2164756E21
3
+ //# debugId=FFF17E90E1B1E9CB64756E2164756E21
4
4
  //# sourceMappingURL=audio.js.map
@@ -4,7 +4,7 @@
4
4
  "sourcesContent": [
5
5
  "/**\n * Audio Plugin for ECSpresso\n *\n * Web Audio API integration via Howler.js for sound effects and music playback.\n * User-defined channels with type-safe volume control, hybrid resource + component API,\n * and asset manager integration.\n */\n\nimport { definePlugin, type BasePluginOptions } from 'ecspresso';\nimport type { AssetsOfWorld, AnyECSpresso, ChannelOfWorld } from 'ecspresso';\nimport type { Howl } from 'howler';\n\n// ==================== Channel Definition ====================\n\n/**\n * Configuration for a single audio channel.\n */\nexport interface AudioChannelConfig {\n\treadonly volume: number;\n}\n\n/**\n * Define audio channels with type-safe names and initial volumes.\n * Mirrors `defineCollisionLayers` pattern.\n *\n * @param channels Object mapping channel names to their configuration\n * @returns Frozen channel configuration with inferred channel name union\n *\n * @example\n * ```typescript\n * const channels = defineAudioChannels({\n * sfx: { volume: 1 },\n * music: { volume: 0.7 },\n * ui: { volume: 0.8 },\n * });\n * type Ch = ChannelsOf<typeof channels>; // 'sfx' | 'music' | 'ui'\n * ```\n */\nexport function defineAudioChannels<const T extends Record<string, AudioChannelConfig>>(\n\tchannels: T\n): Readonly<T> {\n\treturn Object.freeze(channels);\n}\n\n/**\n * Extract channel name union from a `defineAudioChannels` result.\n */\nexport type ChannelsOf<T> = T extends Record<infer K extends string, AudioChannelConfig> ? K : never;\n\n// ==================== Component Types ====================\n\n/**\n * Audio source component attached to entities for positional/entity-bound audio.\n */\nexport interface AudioSource<Ch extends string = string> {\n\t/** Asset key for the sound */\n\treadonly sound: string;\n\t/** Channel this sound plays on */\n\treadonly channel: Ch;\n\t/** Individual volume (0-1) */\n\tvolume: number;\n\t/** Whether sound loops */\n\tloop: boolean;\n\t/** Remove entity when sound ends (like timer autoRemove) */\n\tautoRemove: boolean;\n\t/** Whether sound is currently playing (system-managed) */\n\tplaying: boolean;\n\t/** Howler sound ID (system-managed, -1 = not started) */\n\t_soundId: number;\n}\n\n/**\n * Component types provided by the audio plugin.\n */\nexport interface AudioComponentTypes<Ch extends string = string> {\n\taudioSource: AudioSource<Ch>;\n}\n\n// ==================== Event Types ====================\n\n/**\n * Event to trigger fire-and-forget sound playback from any system.\n */\nexport interface PlaySoundEvent<Ch extends string = string> {\n\t/** Asset key for the sound */\n\tsound: string;\n\t/** Channel to play on */\n\tchannel?: Ch;\n\t/** Individual volume (0-1) */\n\tvolume?: number;\n\t/** Whether sound loops */\n\tloop?: boolean;\n}\n\n/**\n * Event to stop music on a channel.\n */\nexport interface StopMusicEvent<Ch extends string = string> {\n\t/** Channel to stop music on. If omitted, stops all music. */\n\tchannel?: Ch;\n}\n\n/**\n * Event published when a sound finishes playing.\n */\nexport interface SoundEndedEvent {\n\t/** Entity ID if sound was entity-attached, -1 for fire-and-forget */\n\tentityId: number;\n\t/** Howler sound ID */\n\tsoundId: number;\n\t/** Asset key of the sound */\n\tsound: string;\n}\n\n/**\n * Event types provided by the audio plugin.\n */\nexport interface AudioEventTypes<Ch extends string = string> {\n\tplaySound: PlaySoundEvent<Ch>;\n\tstopMusic: StopMusicEvent<Ch>;\n\tsoundEnded: SoundEndedEvent;\n}\n\n// ==================== Resource Types ====================\n\n/**\n * Play options for fire-and-forget sound effects.\n */\nexport interface PlayOptions<Ch extends string = string> {\n\t/** Channel to play on (uses first defined channel if omitted) */\n\tchannel?: Ch;\n\t/** Individual volume (0-1, default: 1) */\n\tvolume?: number;\n\t/** Whether to loop (default: false) */\n\tloop?: boolean;\n}\n\n/**\n * Music playback options.\n */\nexport interface MusicOptions<Ch extends string = string> {\n\t/** Channel to play music on (uses first defined channel if omitted) */\n\tchannel?: Ch;\n\t/** Volume (0-1, default: 1) */\n\tvolume?: number;\n\t/** Whether to loop (default: true) */\n\tloop?: boolean;\n}\n\n/**\n * Audio state resource providing fire-and-forget SFX and music control.\n * Effective volume = individual * channel * master.\n */\nexport interface AudioState<Ch extends string = string> {\n\t/** Play a fire-and-forget sound effect. Returns the Howler sound ID. */\n\tplay(sound: string, options?: PlayOptions<Ch>): number;\n\t/** Stop a specific sound by its Howler sound ID. */\n\tstop(soundId: number): void;\n\n\t/** Play music on a channel. Stops any existing music on that channel first. */\n\tplayMusic(sound: string, options?: MusicOptions<Ch>): void;\n\t/** Stop music on a channel. If omitted, stops all music. */\n\tstopMusic(channel?: Ch): void;\n\t/** Pause music on a channel. If omitted, pauses all music. */\n\tpauseMusic(channel?: Ch): void;\n\t/** Resume music on a channel. If omitted, resumes all music. */\n\tresumeMusic(channel?: Ch): void;\n\n\t/** Set volume for a channel (0-1). */\n\tsetChannelVolume(channel: Ch, volume: number): void;\n\t/** Get current volume for a channel. */\n\tgetChannelVolume(channel: Ch): number;\n\t/** Set master volume (0-1). */\n\tsetMasterVolume(volume: number): void;\n\t/** Get current master volume. */\n\tgetMasterVolume(): number;\n\t/** Mute all audio. */\n\tmute(): void;\n\t/** Unmute all audio. */\n\tunmute(): void;\n\t/** Toggle mute state. */\n\ttoggleMute(): void;\n\t/** Check if audio is muted. */\n\tisMuted(): boolean;\n}\n\n/**\n * Resource types provided by the audio plugin.\n */\nexport interface AudioResourceTypes<Ch extends string = string> {\n\taudioState: AudioState<Ch>;\n}\n\n// ==================== Plugin Options ====================\n\n/**\n * Configuration options for the audio plugin.\n */\nexport interface AudioPluginOptions<Ch extends string, G extends string = 'audio'> extends BasePluginOptions<G> {\n\t/** Channel definitions from defineAudioChannels */\n\tchannels: Readonly<Record<Ch, AudioChannelConfig>>;\n}\n\n// ==================== Helper Functions ====================\n\n/**\n * Create an audioSource component for entity-attached audio.\n *\n * @param sound Asset key for the sound\n * @param channel Channel to play on\n * @param options Optional configuration\n * @returns Component object suitable for spreading into spawn()\n *\n * @example\n * ```typescript\n * ecs.spawn({\n * ...createAudioSource('explosion', 'sfx'),\n * ...createTransform(100, 200),\n * });\n * ```\n */\nexport function createAudioSource<Ch extends string>(\n\tsound: string,\n\tchannel: Ch,\n\toptions?: { volume?: number; loop?: boolean; autoRemove?: boolean }\n): Pick<AudioComponentTypes<Ch>, 'audioSource'> {\n\treturn {\n\t\taudioSource: {\n\t\t\tsound,\n\t\t\tchannel,\n\t\t\tvolume: options?.volume ?? 1,\n\t\t\tloop: options?.loop ?? false,\n\t\t\tautoRemove: options?.autoRemove ?? false,\n\t\t\tplaying: false,\n\t\t\t_soundId: -1,\n\t\t},\n\t};\n}\n\n/**\n * Create a loader function for use with the asset manager.\n * Returns a factory function that loads a Howl when called.\n *\n * @param src URL(s) for the sound file\n * @param options Optional Howl configuration\n * @returns Factory function compatible with asset manager's loader parameter\n *\n * @example\n * ```typescript\n * const ecs = ECSpresso.create()\n * .withAssets(a => a\n * .add('explosion', loadSound('/sounds/explosion.mp3'))\n * .add('bgm', loadSound(['/sounds/bgm.webm', '/sounds/bgm.mp3']))\n * )\n * .build();\n * ```\n */\nexport function loadSound(\n\tsrc: string | string[],\n\toptions?: { html5?: boolean; preload?: boolean }\n): () => Promise<Howl> {\n\treturn () => import('howler').then(({ Howl: HowlClass }) =>\n\t\tnew Promise<Howl>((resolve, reject) => {\n\t\t\tlet howl: Howl;\n\t\t\tlet resolved = false;\n\t\t\thowl = new HowlClass({\n\t\t\t\tsrc: Array.isArray(src) ? src : [src],\n\t\t\t\thtml5: options?.html5 ?? false,\n\t\t\t\tpreload: options?.preload ?? true,\n\t\t\t\tonload: () => {\n\t\t\t\t\tresolved = true;\n\t\t\t\t\tresolve(howl);\n\t\t\t\t},\n\t\t\t\tonloaderror: (_id: number, err: unknown) => reject(\n\t\t\t\t\terr instanceof Error ? err : new Error(String(err))\n\t\t\t\t),\n\t\t\t});\n\t\t\t// If onload fired synchronously during construction (e.g. cached),\n\t\t\t// howl is now assigned and the promise is already resolved.\n\t\t\tif (!resolved && howl.state?.() === 'loaded') {\n\t\t\t\tresolve(howl);\n\t\t\t}\n\t\t})\n\t);\n}\n\n// ==================== Internal Types ====================\n\ninterface ActiveSound<Ch extends string> {\n\thowl: Howl;\n\tsoundId: number;\n\tchannel: Ch;\n\tindividualVolume: number;\n\tassetKey: string;\n\tentityId: number;\n}\n\ninterface MusicEntry<Ch extends string> {\n\thowl: Howl;\n\tsoundId: number;\n\tchannel: Ch;\n\tindividualVolume: number;\n\tassetKey: string;\n}\n\n// ==================== Plugin Factory ====================\n\n/**\n * Create an audio plugin for ECSpresso.\n *\n * Provides:\n * - `audioState` resource for fire-and-forget SFX and music\n * - `audioSource` component for entity-attached sounds\n * - Volume hierarchy: individual * channel * master\n * - `playSound` / `stopMusic` event handlers\n * - `soundEnded` event on completion\n * - Automatic cleanup on entity removal (dispose callback)\n *\n * Sounds must be preloaded through the asset pipeline (`loadSound` helper).\n *\n * @example\n * ```typescript\n * const channels = defineAudioChannels({\n * sfx: { volume: 1 },\n * music: { volume: 0.7 },\n * });\n *\n * const ecs = ECSpresso.create()\n * .withAssets(a => a.add('explosion', loadSound('/sfx/boom.mp3')))\n * .withPlugin(createAudioPlugin({ channels }))\n * .build();\n *\n * await ecs.initialize();\n * const audio = ecs.getResource('audioState');\n * audio.play('explosion', { channel: 'sfx' });\n * ```\n */\nexport function createAudioPlugin<Ch extends string, G extends string = 'audio'>(\n\toptions: AudioPluginOptions<Ch, G>\n) {\n\tconst {\n\t\tchannels: channelDefs,\n\t\tsystemGroup = 'audio',\n\t\tpriority = 0,\n\t\tphase = 'update',\n\t} = options;\n\n\t// Closure state\n\tconst channelVolumes = new Map<Ch, number>();\n\tconst activeSounds = new Map<number, ActiveSound<Ch>>();\n\tconst musicByChannel = new Map<Ch, MusicEntry<Ch>>();\n\tlet masterVolume = 1;\n\tlet muted = false;\n\n\t// Initialize channel volumes from definitions\n\tconst channelNames: Ch[] = [];\n\tfor (const [name, config] of Object.entries(channelDefs) as Array<[Ch, AudioChannelConfig]>) {\n\t\tchannelVolumes.set(name, config.volume);\n\t\tchannelNames.push(name);\n\t}\n\n\tconst defaultChannel = channelNames[0] as Ch;\n\n\t// Volume computation\n\tfunction effectiveVolume(individualVol: number, channel: Ch): number {\n\t\tif (muted) return 0;\n\t\tconst chanVol = channelVolumes.get(channel) ?? 1;\n\t\treturn individualVol * chanVol * masterVolume;\n\t}\n\n\t// Propagate volume changes to all active sounds on a channel\n\tfunction propagateChannelVolume(channel: Ch): void {\n\t\tfor (const sound of activeSounds.values()) {\n\t\t\tif (sound.channel !== channel) continue;\n\t\t\tsound.howl.volume(effectiveVolume(sound.individualVolume, channel), sound.soundId);\n\t\t}\n\t\tconst music = musicByChannel.get(channel);\n\t\tif (music) {\n\t\t\tmusic.howl.volume(effectiveVolume(music.individualVolume, channel), music.soundId);\n\t\t}\n\t}\n\n\t// Propagate volume to all sounds across all channels\n\tfunction propagateAllVolumes(): void {\n\t\tfor (const ch of channelNames) {\n\t\t\tpropagateChannelVolume(ch);\n\t\t}\n\t}\n\n\t// Stop a sound by its Howler sound ID\n\tfunction stopSoundById(soundId: number): void {\n\t\tconst entry = activeSounds.get(soundId);\n\t\tif (!entry) return;\n\t\tentry.howl.stop(soundId);\n\t\tactiveSounds.delete(soundId);\n\t}\n\n\t// Event bus reference, set during initialization\n\tlet eventBusRef: { publish(event: string, data: unknown): void } | null = null;\n\n\t// Resolve Howl from asset key\n\tlet getAsset: ((key: string) => Howl) | null = null;\n\n\t// AudioState resource implementation\n\tconst audioState: AudioState<Ch> = {\n\t\tplay(sound, playOpts) {\n\t\t\tif (!getAsset) return -1;\n\t\t\tconst channel = playOpts?.channel ?? defaultChannel;\n\t\t\tconst individualVol = playOpts?.volume ?? 1;\n\t\t\tconst loop = playOpts?.loop ?? false;\n\n\t\t\tconst howl = getAsset(sound);\n\t\t\thowl.volume(effectiveVolume(individualVol, channel));\n\t\t\thowl.loop(loop);\n\t\t\tconst soundId = howl.play();\n\n\t\t\tconst entry: ActiveSound<Ch> = {\n\t\t\t\thowl,\n\t\t\t\tsoundId,\n\t\t\t\tchannel,\n\t\t\t\tindividualVolume: individualVol,\n\t\t\t\tassetKey: sound,\n\t\t\t\tentityId: -1,\n\t\t\t};\n\t\t\tactiveSounds.set(soundId, entry);\n\n\t\t\thowl.once('end', () => {\n\t\t\t\tactiveSounds.delete(soundId);\n\t\t\t\teventBusRef?.publish('soundEnded', {\n\t\t\t\t\tentityId: -1,\n\t\t\t\t\tsoundId,\n\t\t\t\t\tsound,\n\t\t\t\t} satisfies SoundEndedEvent);\n\t\t\t}, soundId);\n\n\t\t\treturn soundId;\n\t\t},\n\n\t\tstop(soundId) {\n\t\t\tstopSoundById(soundId);\n\t\t},\n\n\t\tplayMusic(sound, musicOpts) {\n\t\t\tif (!getAsset) return;\n\t\t\tconst channel = musicOpts?.channel ?? defaultChannel;\n\t\t\tconst individualVol = musicOpts?.volume ?? 1;\n\t\t\tconst loop = musicOpts?.loop ?? true;\n\n\t\t\t// Stop existing music on this channel\n\t\t\tconst existing = musicByChannel.get(channel);\n\t\t\tif (existing) {\n\t\t\t\texisting.howl.stop(existing.soundId);\n\t\t\t\tactiveSounds.delete(existing.soundId);\n\t\t\t}\n\n\t\t\tconst howl = getAsset(sound);\n\t\t\thowl.volume(effectiveVolume(individualVol, channel));\n\t\t\thowl.loop(loop);\n\t\t\tconst soundId = howl.play();\n\n\t\t\tconst entry: MusicEntry<Ch> = {\n\t\t\t\thowl,\n\t\t\t\tsoundId,\n\t\t\t\tchannel,\n\t\t\t\tindividualVolume: individualVol,\n\t\t\t\tassetKey: sound,\n\t\t\t};\n\t\t\tmusicByChannel.set(channel, entry);\n\t\t\tactiveSounds.set(soundId, {\n\t\t\t\t...entry,\n\t\t\t\tentityId: -1,\n\t\t\t});\n\n\t\t\thowl.once('end', () => {\n\t\t\t\tactiveSounds.delete(soundId);\n\t\t\t\tconst current = musicByChannel.get(channel);\n\t\t\t\tif (current?.soundId === soundId) {\n\t\t\t\t\tmusicByChannel.delete(channel);\n\t\t\t\t}\n\t\t\t}, soundId);\n\t\t},\n\n\t\tstopMusic(channel) {\n\t\t\tif (channel !== undefined) {\n\t\t\t\tconst entry = musicByChannel.get(channel);\n\t\t\t\tif (entry) {\n\t\t\t\t\tentry.howl.stop(entry.soundId);\n\t\t\t\t\tactiveSounds.delete(entry.soundId);\n\t\t\t\t\tmusicByChannel.delete(channel);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor (const [ch, entry] of musicByChannel) {\n\t\t\t\t\tentry.howl.stop(entry.soundId);\n\t\t\t\t\tactiveSounds.delete(entry.soundId);\n\t\t\t\t\tmusicByChannel.delete(ch);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tpauseMusic(channel) {\n\t\t\tif (channel !== undefined) {\n\t\t\t\tconst entry = musicByChannel.get(channel);\n\t\t\t\tif (entry) entry.howl.pause(entry.soundId);\n\t\t\t} else {\n\t\t\t\tfor (const entry of musicByChannel.values()) {\n\t\t\t\t\tentry.howl.pause(entry.soundId);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tresumeMusic(channel) {\n\t\t\tif (channel !== undefined) {\n\t\t\t\tconst entry = musicByChannel.get(channel);\n\t\t\t\tif (entry) entry.howl.play(entry.soundId);\n\t\t\t} else {\n\t\t\t\tfor (const entry of musicByChannel.values()) {\n\t\t\t\t\tentry.howl.play(entry.soundId);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tsetChannelVolume(channel, volume) {\n\t\t\tchannelVolumes.set(channel, volume);\n\t\t\tpropagateChannelVolume(channel);\n\t\t},\n\n\t\tgetChannelVolume(channel) {\n\t\t\treturn channelVolumes.get(channel) ?? 1;\n\t\t},\n\n\t\tsetMasterVolume(volume) {\n\t\t\tmasterVolume = volume;\n\t\t\tpropagateAllVolumes();\n\t\t},\n\n\t\tgetMasterVolume() {\n\t\t\treturn masterVolume;\n\t\t},\n\n\t\tmute() {\n\t\t\tmuted = true;\n\t\t\tpropagateAllVolumes();\n\t\t},\n\n\t\tunmute() {\n\t\t\tmuted = false;\n\t\t\tpropagateAllVolumes();\n\t\t},\n\n\t\ttoggleMute() {\n\t\t\tmuted = !muted;\n\t\t\tpropagateAllVolumes();\n\t\t},\n\n\t\tisMuted() {\n\t\t\treturn muted;\n\t\t},\n\t};\n\n\treturn definePlugin('audio')\n\t\t.withComponentTypes<AudioComponentTypes<Ch>>()\n\t\t.withEventTypes<AudioEventTypes<Ch>>()\n\t\t.withResourceTypes<AudioResourceTypes<Ch>>()\n\t\t.withLabels<'audio-sync'>()\n\t\t.withGroups<G>()\n\t\t.withReactiveQueryNames<'audio-sources'>()\n\t\t.install((world) => {\n\t\t\tworld.addResource('audioState', audioState);\n\n\t\t\t// Dispose callback: stop sounds when audioSource component is removed\n\t\t\tworld.registerDispose('audioSource', ({ value: source }: { value: AudioSource<Ch>; entityId: number }) => {\n\t\t\t\tif (source._soundId !== -1) {\n\t\t\t\t\tstopSoundById(source._soundId);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tworld\n\t\t\t\t.addSystem('audio-sync')\n\t\t\t\t.setPriority(priority)\n\t\t\t\t.inPhase(phase)\n\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t.setOnInitialize((ecs) => {\n\t\t\t\t\teventBusRef = ecs.eventBus;\n\n\t\t\t\t\t// Resolve asset getter - works with $assets resource if available\n\t\t\t\t\tconst assets = ecs.tryGetResource<{ get(k: string): unknown }>('$assets');\n\t\t\t\t\tif (assets) {\n\t\t\t\t\t\tgetAsset = (key: string) => assets.get(key) as Howl;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Register reactive query for audioSource components\n\t\t\t\t\tecs.addReactiveQuery('audio-sources', {\n\t\t\t\t\t\twith: ['audioSource'],\n\t\t\t\t\t\tonEnter: (entity) => {\n\t\t\t\t\t\t\tconst source = entity.components.audioSource;\n\t\t\t\t\t\t\tif (!getAsset) return;\n\t\t\t\t\t\t\tif (source._soundId !== -1) return; // Already started\n\n\t\t\t\t\t\t\tconst howl = getAsset(source.sound);\n\t\t\t\t\t\t\thowl.volume(effectiveVolume(source.volume, source.channel));\n\t\t\t\t\t\t\thowl.loop(source.loop);\n\t\t\t\t\t\t\tconst soundId = howl.play();\n\n\t\t\t\t\t\t\tsource._soundId = soundId;\n\t\t\t\t\t\t\tsource.playing = true;\n\n\t\t\t\t\t\t\tconst entry: ActiveSound<Ch> = {\n\t\t\t\t\t\t\t\thowl,\n\t\t\t\t\t\t\t\tsoundId,\n\t\t\t\t\t\t\t\tchannel: source.channel,\n\t\t\t\t\t\t\t\tindividualVolume: source.volume,\n\t\t\t\t\t\t\t\tassetKey: source.sound,\n\t\t\t\t\t\t\t\tentityId: entity.id,\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tactiveSounds.set(soundId, entry);\n\n\t\t\t\t\t\t\thowl.once('end', () => {\n\t\t\t\t\t\t\t\tactiveSounds.delete(soundId);\n\t\t\t\t\t\t\t\tsource.playing = false;\n\n\t\t\t\t\t\t\t\teventBusRef?.publish('soundEnded', {\n\t\t\t\t\t\t\t\t\tentityId: entity.id,\n\t\t\t\t\t\t\t\t\tsoundId,\n\t\t\t\t\t\t\t\t\tsound: source.sound,\n\t\t\t\t\t\t\t\t} satisfies SoundEndedEvent);\n\n\t\t\t\t\t\t\t\tif (source.autoRemove) {\n\t\t\t\t\t\t\t\t\tecs.commands.removeEntity(entity.id);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}, soundId);\n\t\t\t\t\t\t},\n\t\t\t\t\t\tonExit: (_entityId) => {\n\t\t\t\t\t\t\t// Cleanup handled by dispose callback\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t})\n\t\t\t\t.setEventHandlers({\n\t\t\t\t\tplaySound({ data, ecs }) {\n\t\t\t\t\t\tconst audio = ecs.getResource('audioState');\n\t\t\t\t\t\taudio.play(data.sound, {\n\t\t\t\t\t\t\tchannel: data.channel,\n\t\t\t\t\t\t\tvolume: data.volume,\n\t\t\t\t\t\t\tloop: data.loop,\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t\tstopMusic({ data, ecs }) {\n\t\t\t\t\t\tconst audio = ecs.getResource('audioState');\n\t\t\t\t\t\taudio.stopMusic(data.channel);\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\t.setOnDetach(() => {\n\t\t\t\t\t// Stop all active sounds\n\t\t\t\t\tfor (const entry of activeSounds.values()) {\n\t\t\t\t\t\tentry.howl.stop(entry.soundId);\n\t\t\t\t\t}\n\t\t\t\t\tactiveSounds.clear();\n\t\t\t\t\tmusicByChannel.clear();\n\t\t\t\t\teventBusRef = null;\n\t\t\t\t\tgetAsset = null;\n\t\t\t\t});\n\t\t});\n}\n\n// ==================== Post-Build Helpers ====================\n\n/**\n * Typed helpers for the audio plugin.\n * Creates helpers that validate sound keys and channel names against the world type W.\n * Call after .build() using typeof ecs.\n *\n * @template W - Concrete ECS world type (e.g. `typeof ecs`)\n *\n * @example\n * ```typescript\n * const ecs = ECSpresso.create()\n * .withPlugin(createAudioPlugin({ channels }))\n * .withAssets(a => a.add('boom', loadSound('/sfx/boom.mp3')))\n * .build();\n *\n * const { createAudioSource } = createAudioHelpers<typeof ecs>();\n * // Type-safe: 'boom' must be a registered asset, 'sfx' a valid channel\n * createAudioSource('boom', 'sfx');\n * ```\n */\nexport interface AudioHelpers<W extends AnyECSpresso> {\n\tcreateAudioSource: (\n\t\tsound: keyof AssetsOfWorld<W> & string,\n\t\tchannel: ChannelOfWorld<W>,\n\t\toptions?: { volume?: number; loop?: boolean; autoRemove?: boolean },\n\t) => Pick<AudioComponentTypes<ChannelOfWorld<W>>, 'audioSource'>;\n}\n\nexport function createAudioHelpers<W extends AnyECSpresso>(_world?: W): AudioHelpers<W> {\n\treturn {\n\t\tcreateAudioSource: createAudioSource as AudioHelpers<W>['createAudioSource'],\n\t};\n}\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "E5072AB917D540E664756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "FFF17E90E1B1E9CB64756E2164756E21",
9
9
  "names": []
10
10
  }