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
@@ -1,4 +1,4 @@
1
- var J=Object.defineProperty;var K=(j)=>j;function L(j,k){this[j]=K.bind(null,k)}var N=(j,k)=>{for(var q in k)J(j,q,{get:k[q],enumerable:!0,configurable:!0,set:L.bind(k,q)})};var O=(j,k)=>()=>(j&&(k=j(j=0)),k);var Q=((j)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(j,{get:(k,q)=>(typeof require<"u"?require:k)[q]}):j)(function(j){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+j+'" is not supported')});import{definePlugin as M}from"ecspresso";function V(j){return{health:{current:j,max:j}}}function W(j,k){return{health:{current:j,max:k}}}function X(j){let{systemGroup:k="combat"}=j??{};return M("health").withComponentTypes().withEventTypes().withLabels().withGroups().install((q)=>{q.addSystem("health-damage").inGroup(k).setEventHandlers({damage({data:z,ecs:F}){let A=F.getComponent(z.entityId,"health");if(!A)return;if(A.current<=0)return;if(A.current=Math.max(0,A.current-z.amount),F.markChanged(z.entityId,"health"),A.current<=0)F.eventBus.publish("entityDied",{entityId:z.entityId,killerId:z.sourceId})}})})}export{W as createHealthWith,X as createHealthPlugin,V as createHealth};
1
+ var K=((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 J}from"ecspresso";function N(j){return{health:{current:j,max:j}}}function O(j,k){return{health:{current:j,max:k}}}function Q(j){let{systemGroup:k="combat"}=j??{};return J("health").withComponentTypes().withEventTypes().withLabels().withGroups().install((A)=>{A.addSystem("health-damage").inGroup(k).setEventHandlers({damage({data:q,ecs:F}){let z=F.getComponent(q.entityId,"health");if(!z)return;if(z.current<=0)return;if(z.current=Math.max(0,z.current-q.amount),F.markChanged(q.entityId,"health"),z.current<=0)F.eventBus.publish("entityDied",{entityId:q.entityId,killerId:q.sourceId})}})})}export{O as createHealthWith,Q as createHealthPlugin,N as createHealth};
2
2
 
3
- //# debugId=B2A67A4C6953F66664756E2164756E21
3
+ //# debugId=F64127187EB3461D64756E2164756E21
4
4
  //# sourceMappingURL=health.js.map
@@ -4,7 +4,7 @@
4
4
  "sourcesContent": [
5
5
  "/**\n * Health Plugin for ECSpresso\n *\n * Provides a standard health/damage/death lifecycle.\n * Entities with a `health` component can receive `damage` events.\n * When health reaches zero, an `entityDied` event is published.\n * The plugin does NOT remove dead entities — game-specific logic\n * decides when and how to handle death (animations, loot, etc).\n */\n\nimport { definePlugin, type BasePluginOptions } from 'ecspresso';\nimport type { WorldConfigFrom } from 'ecspresso';\n\n// ==================== Component Types ====================\n\n/**\n * Health state for an entity.\n */\nexport interface Health {\n\tcurrent: number;\n\tmax: number;\n}\n\n/**\n * Component types provided by the health plugin.\n */\nexport interface HealthComponentTypes {\n\thealth: Health;\n}\n\n// ==================== Event Types ====================\n\n/**\n * Event requesting damage to an entity.\n */\nexport interface DamageEvent {\n\tentityId: number;\n\tamount: number;\n\tsourceId?: number;\n}\n\n/**\n * Event fired when an entity's health reaches zero.\n */\nexport interface EntityDiedEvent {\n\tentityId: number;\n\tkillerId?: number;\n}\n\n/**\n * Event types provided by the health plugin.\n */\nexport interface HealthEventTypes {\n\tdamage: DamageEvent;\n\tentityDied: EntityDiedEvent;\n}\n\n// ==================== WorldConfig ====================\n\n/**\n * WorldConfig representing the health plugin's provided types.\n * Used as the `Requires` type parameter by plugins that depend on health.\n */\nexport type HealthWorldConfig = WorldConfigFrom<HealthComponentTypes, HealthEventTypes>;\n\n// ==================== Plugin Options ====================\n\nexport interface HealthPluginOptions<G extends string = 'combat'> extends BasePluginOptions<G> {}\n\n// ==================== Helper Functions ====================\n\n/**\n * Create a health component at full HP.\n *\n * @param max Maximum (and initial) health\n * @returns Component object suitable for spreading into spawn()\n *\n * @example\n * ```typescript\n * ecs.spawn({\n * ...createHealth(100),\n * ...createLocalTransform(200, 300),\n * });\n * ```\n */\nexport function createHealth(max: number): Pick<HealthComponentTypes, 'health'> {\n\treturn { health: { current: max, max } };\n}\n\n/**\n * Create a health component with a specific current value.\n *\n * @param current Current health\n * @param max Maximum health\n * @returns Component object suitable for spreading into spawn()\n */\nexport function createHealthWith(current: number, max: number): Pick<HealthComponentTypes, 'health'> {\n\treturn { health: { current, max } };\n}\n\n// ==================== Plugin Factory ====================\n\n/**\n * Create a health plugin for ECSpresso.\n *\n * Provides event-driven damage processing. Subscribe to `damage` events\n * to deal damage, and listen to `entityDied` events to react to deaths.\n *\n * @example\n * ```typescript\n * const ecs = ECSpresso.create()\n * .withPlugin(createHealthPlugin())\n * .build();\n *\n * // Deal damage:\n * ecs.eventBus.publish('damage', { entityId: targetId, amount: 25 });\n *\n * // React to death:\n * ecs.on('entityDied', ({ entityId }) => {\n * ecs.commands.removeEntity(entityId);\n * });\n * ```\n */\nexport function createHealthPlugin<G extends string = 'combat'>(\n\toptions?: HealthPluginOptions<G>,\n) {\n\tconst {\n\t\tsystemGroup = 'combat',\n\t} = options ?? {};\n\n\treturn definePlugin('health')\n\t\t.withComponentTypes<HealthComponentTypes>()\n\t\t.withEventTypes<HealthEventTypes>()\n\t\t.withLabels<'health-damage'>()\n\t\t.withGroups<G>()\n\t\t.install((world) => {\n\t\t\tworld\n\t\t\t\t.addSystem('health-damage')\n\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t.setEventHandlers({\n\t\t\t\t\tdamage({ data, ecs }) {\n\t\t\t\t\t\tconst health = ecs.getComponent(data.entityId, 'health');\n\t\t\t\t\t\tif (!health) return;\n\t\t\t\t\t\tif (health.current <= 0) return;\n\n\t\t\t\t\t\thealth.current = Math.max(0, health.current - data.amount);\n\t\t\t\t\t\tecs.markChanged(data.entityId, 'health');\n\n\t\t\t\t\t\tif (health.current <= 0) {\n\t\t\t\t\t\t\tecs.eventBus.publish('entityDied', {\n\t\t\t\t\t\t\t\tentityId: data.entityId,\n\t\t\t\t\t\t\t\tkillerId: data.sourceId,\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"
6
6
  ],
7
- "mappings": "4cAUA,uBAAS,kBA2EF,SAAS,CAAY,CAAC,EAAmD,CAC/E,MAAO,CAAE,OAAQ,CAAE,QAAS,EAAK,KAAI,CAAE,EAUjC,SAAS,CAAgB,CAAC,EAAiB,EAAmD,CACpG,MAAO,CAAE,OAAQ,CAAE,UAAS,KAAI,CAAE,EA0B5B,SAAS,CAA+C,CAC9D,EACC,CACD,IACC,cAAc,UACX,GAAW,CAAC,EAEhB,OAAO,EAAa,QAAQ,EAC1B,mBAAyC,EACzC,eAAiC,EACjC,WAA4B,EAC5B,WAAc,EACd,QAAQ,CAAC,IAAU,CACnB,EACE,UAAU,eAAe,EACzB,QAAQ,CAAW,EACnB,iBAAiB,CACjB,MAAM,EAAG,OAAM,OAAO,CACrB,IAAM,EAAS,EAAI,aAAa,EAAK,SAAU,QAAQ,EACvD,GAAI,CAAC,EAAQ,OACb,GAAI,EAAO,SAAW,EAAG,OAKzB,GAHA,EAAO,QAAU,KAAK,IAAI,EAAG,EAAO,QAAU,EAAK,MAAM,EACzD,EAAI,YAAY,EAAK,SAAU,QAAQ,EAEnC,EAAO,SAAW,EACrB,EAAI,SAAS,QAAQ,aAAc,CAClC,SAAU,EAAK,SACf,SAAU,EAAK,QAChB,CAAC,EAGJ,CAAC,EACF",
8
- "debugId": "B2A67A4C6953F66664756E2164756E21",
7
+ "mappings": "2PAUA,uBAAS,kBA2EF,SAAS,CAAY,CAAC,EAAmD,CAC/E,MAAO,CAAE,OAAQ,CAAE,QAAS,EAAK,KAAI,CAAE,EAUjC,SAAS,CAAgB,CAAC,EAAiB,EAAmD,CACpG,MAAO,CAAE,OAAQ,CAAE,UAAS,KAAI,CAAE,EA0B5B,SAAS,CAA+C,CAC9D,EACC,CACD,IACC,cAAc,UACX,GAAW,CAAC,EAEhB,OAAO,EAAa,QAAQ,EAC1B,mBAAyC,EACzC,eAAiC,EACjC,WAA4B,EAC5B,WAAc,EACd,QAAQ,CAAC,IAAU,CACnB,EACE,UAAU,eAAe,EACzB,QAAQ,CAAW,EACnB,iBAAiB,CACjB,MAAM,EAAG,OAAM,OAAO,CACrB,IAAM,EAAS,EAAI,aAAa,EAAK,SAAU,QAAQ,EACvD,GAAI,CAAC,EAAQ,OACb,GAAI,EAAO,SAAW,EAAG,OAKzB,GAHA,EAAO,QAAU,KAAK,IAAI,EAAG,EAAO,QAAU,EAAK,MAAM,EACzD,EAAI,YAAY,EAAK,SAAU,QAAQ,EAEnC,EAAO,SAAW,EACrB,EAAI,SAAS,QAAQ,aAAc,CAClC,SAAU,EAAK,SACf,SAAU,EAAK,QAChB,CAAC,EAGJ,CAAC,EACF",
8
+ "debugId": "F64127187EB3461D64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,4 +1,4 @@
1
- var Y=Object.defineProperty;var Z=(k)=>k;function _(k,v){this[k]=Z.bind(null,v)}var b=(k,v)=>{for(var C in v)Y(k,C,{get:v[C],enumerable:!0,configurable:!0,set:_.bind(v,C)})};var B=(k,v)=>()=>(k&&(v=k(k=0)),v);var S=((k)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(k,{get:(v,C)=>(typeof require<"u"?require:v)[C]}):k)(function(k){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+k+'" is not supported')});import{definePlugin as $}from"ecspresso";function A(k,v,C){return{projectile:{damage:k,speed:v,sourceId:C}}}function q(k){return{projectileTarget:{entityId:k}}}function w(k,v){let C=Math.sqrt(k*k+v*v);if(C===0)return{projectileDirection:{x:0,y:-1}};return{projectileDirection:{x:k/C,y:v/C}}}function h(k){let{systemGroup:v="combat",priority:C=300,phase:U="update",publishDamage:X=!0}=k??{};return $("projectile").withComponentTypes().withEventTypes().withLabels().withGroups().requires().install((R)=>{R.addSystem("projectile-homing").setPriority(C).inPhase(U).inGroup(v).addQuery("homing",{with:["projectile","projectileTarget","localTransform"]}).setProcess(({queries:F,ecs:z,dt:M})=>{for(let K of F.homing){let{projectile:L,projectileTarget:H,localTransform:E}=K.components;if(!z.getEntity(H.entityId)){z.commands.removeEntity(K.id);continue}let J=z.getComponent(H.entityId,"worldTransform");if(!J){z.commands.removeEntity(K.id);continue}let N=J.x-E.x,O=J.y-E.y,V=N*N+O*O,Q=L.speed*M;if(V<=Q*Q)E.x=J.x,E.y=J.y;else{let W=Math.sqrt(V);E.x+=N/W*Q,E.y+=O/W*Q,E.rotation=Math.atan2(O,N)}z.markChanged(K.id,"localTransform")}}),R.addSystem("projectile-linear").setPriority(C).inPhase(U).inGroup(v).addQuery("linear",{with:["projectile","projectileDirection","localTransform"]}).setProcess(({queries:F,dt:z})=>{for(let M of F.linear){let{projectile:K,projectileDirection:L,localTransform:H}=M.components,E=K.speed*z;H.x+=L.x*E,H.y+=L.y*E}}),R.addSystem("projectile-collision").inGroup(v).setEventHandlers({collision({data:F,ecs:z}){if(!z.getEntity(F.entityA)||!z.getEntity(F.entityB))return;let M=z.getComponent(F.entityA,"projectile"),K=z.getComponent(F.entityB,"projectile"),L=M!==void 0,H=L?M:K;if(!H)return;let E=L?F.entityA:F.entityB,J=L?F.entityB:F.entityA;if(J===H.sourceId)return;if(z.eventBus.publish("projectileHit",{projectileId:E,targetId:J,damage:H.damage}),X)z.eventBus.publish("damage",{entityId:J,amount:H.damage,sourceId:H.sourceId});z.commands.removeEntity(E)}})})}export{q as createProjectileTarget,h as createProjectilePlugin,w as createProjectileDirection,A as createProjectile};
1
+ var Z=((v)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(v,{get:(E,H)=>(typeof require<"u"?require:E)[H]}):v)(function(v){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+v+'" is not supported')});import{definePlugin as Y}from"ecspresso";function b(v,E,H){return{projectile:{damage:v,speed:E,sourceId:H}}}function B(v){return{projectileTarget:{entityId:v}}}function S(v,E){let H=Math.sqrt(v*v+E*E);if(H===0)return{projectileDirection:{x:0,y:-1}};return{projectileDirection:{x:v/H,y:E/H}}}function G(v){let{systemGroup:E="combat",priority:H=300,phase:U="update",publishDamage:X=!0}=v??{};return Y("projectile").withComponentTypes().withEventTypes().withLabels().withGroups().requires().install((R)=>{R.addSystem("projectile-homing").setPriority(H).inPhase(U).inGroup(E).addQuery("homing",{with:["projectile","projectileTarget","localTransform"]}).setProcess(({queries:C,ecs:k,dt:M})=>{for(let K of C.homing){let{projectile:L,projectileTarget:F,localTransform:z}=K.components;if(!k.getEntity(F.entityId)){k.commands.removeEntity(K.id);continue}let J=k.getComponent(F.entityId,"worldTransform");if(!J){k.commands.removeEntity(K.id);continue}let N=J.x-z.x,O=J.y-z.y,V=N*N+O*O,Q=L.speed*M;if(V<=Q*Q)z.x=J.x,z.y=J.y;else{let W=Math.sqrt(V);z.x+=N/W*Q,z.y+=O/W*Q,z.rotation=Math.atan2(O,N)}k.markChanged(K.id,"localTransform")}}),R.addSystem("projectile-linear").setPriority(H).inPhase(U).inGroup(E).addQuery("linear",{with:["projectile","projectileDirection","localTransform"]}).setProcess(({queries:C,dt:k})=>{for(let M of C.linear){let{projectile:K,projectileDirection:L,localTransform:F}=M.components,z=K.speed*k;F.x+=L.x*z,F.y+=L.y*z}}),R.addSystem("projectile-collision").inGroup(E).setEventHandlers({collision({data:C,ecs:k}){if(!k.getEntity(C.entityA)||!k.getEntity(C.entityB))return;let M=k.getComponent(C.entityA,"projectile"),K=k.getComponent(C.entityB,"projectile"),L=M!==void 0,F=L?M:K;if(!F)return;let z=L?C.entityA:C.entityB,J=L?C.entityB:C.entityA;if(J===F.sourceId)return;if(k.eventBus.publish("projectileHit",{projectileId:z,targetId:J,damage:F.damage}),X)k.eventBus.publish("damage",{entityId:J,amount:F.damage,sourceId:F.sourceId});k.commands.removeEntity(z)}})})}export{B as createProjectileTarget,G as createProjectilePlugin,S as createProjectileDirection,b as createProjectile};
2
2
 
3
- //# debugId=2FD63C0EC856D97064756E2164756E21
3
+ //# debugId=D0756C0A27AA8CAC64756E2164756E21
4
4
  //# sourceMappingURL=projectile.js.map
@@ -4,7 +4,7 @@
4
4
  "sourcesContent": [
5
5
  "/**\n * Projectile Plugin for ECSpresso\n *\n * Provides projectile movement (homing and linear) and collision integration.\n * Homing projectiles track a target entity's position each frame.\n * Linear projectiles move in a fixed direction.\n * When a collision involves a projectile, a `projectileHit` event is published\n * and a `damage` event is forwarded to the target (if the health plugin is present).\n */\n\nimport { definePlugin, type BasePluginOptions } from 'ecspresso';\nimport type { WorldConfigFrom } from 'ecspresso';\nimport type { TransformWorldConfig } from '../spatial/transform';\nimport type { CollisionEventTypes } from '../physics/collision';\nimport type { DamageEvent } from './health';\n\n// ==================== Component Types ====================\n\n/**\n * Core projectile data.\n */\nexport interface Projectile {\n\tdamage: number;\n\tspeed: number;\n\t/** Entity that fired this projectile */\n\tsourceId: number;\n}\n\n/**\n * Homing target — projectile tracks this entity's position each frame.\n */\nexport interface ProjectileTarget {\n\tentityId: number;\n}\n\n/**\n * Fixed direction for non-homing projectiles (normalized).\n */\nexport interface ProjectileDirection {\n\tx: number;\n\ty: number;\n}\n\n/**\n * Component types provided by the projectile plugin.\n */\nexport interface ProjectileComponentTypes {\n\tprojectile: Projectile;\n\tprojectileTarget: ProjectileTarget;\n\tprojectileDirection: ProjectileDirection;\n}\n\n// ==================== Event Types ====================\n\n/**\n * Event fired when a projectile hits a target via collision.\n */\nexport interface ProjectileHitEvent {\n\tprojectileId: number;\n\ttargetId: number;\n\tdamage: number;\n}\n\n/**\n * Event types provided by the projectile plugin.\n */\nexport interface ProjectileEventTypes {\n\tprojectileHit: ProjectileHitEvent;\n\tdamage: DamageEvent;\n}\n\n// ==================== WorldConfig ====================\n\n/**\n * WorldConfig representing the projectile plugin's provided types.\n */\nexport type ProjectileWorldConfig = WorldConfigFrom<ProjectileComponentTypes, ProjectileEventTypes>;\n\n// ==================== Plugin Options ====================\n\nexport interface ProjectilePluginOptions<G extends string = 'combat'> extends BasePluginOptions<G> {\n\t/**\n\t * Whether to auto-publish `damage` events on hit.\n\t * Requires the health plugin to be installed. (default: true)\n\t */\n\tpublishDamage?: boolean;\n}\n\n// ==================== Helper Functions ====================\n\n/**\n * Create a projectile component.\n *\n * @param damage Damage dealt on hit\n * @param speed Movement speed in pixels per second\n * @param sourceId Entity that fired this projectile\n * @returns Component object suitable for spreading into spawn()\n */\nexport function createProjectile(\n\tdamage: number,\n\tspeed: number,\n\tsourceId: number,\n): Pick<ProjectileComponentTypes, 'projectile'> {\n\treturn { projectile: { damage, speed, sourceId } };\n}\n\n/**\n * Create a homing projectile target component.\n *\n * @param entityId Target entity to track\n * @returns Component object suitable for spreading into spawn()\n */\nexport function createProjectileTarget(entityId: number): Pick<ProjectileComponentTypes, 'projectileTarget'> {\n\treturn { projectileTarget: { entityId } };\n}\n\n/**\n * Create a fixed-direction projectile component (auto-normalizes).\n *\n * @param x Direction x\n * @param y Direction y\n * @returns Component object suitable for spreading into spawn()\n */\nexport function createProjectileDirection(x: number, y: number): Pick<ProjectileComponentTypes, 'projectileDirection'> {\n\tconst len = Math.sqrt(x * x + y * y);\n\tif (len === 0) return { projectileDirection: { x: 0, y: -1 } };\n\treturn { projectileDirection: { x: x / len, y: y / len } };\n}\n\n// ==================== Plugin Factory ====================\n\n/**\n * Create a projectile plugin for ECSpresso.\n *\n * Provides homing and linear projectile movement systems, plus\n * automatic collision-to-damage integration.\n *\n * @example\n * ```typescript\n * // Spawn a homing projectile:\n * ecs.spawn({\n * ...createProjectile(10, 400, turretId),\n * ...createProjectileTarget(enemyId),\n * ...createLocalTransform(x, y),\n * ...createCircleCollider(4),\n * ...collisionLayers.turretProjectile(),\n * sprite: bulletSprite,\n * renderLayer: 'projectiles',\n * });\n * ```\n */\nexport function createProjectilePlugin<G extends string = 'combat'>(\n\toptions?: ProjectilePluginOptions<G>,\n) {\n\tconst {\n\t\tsystemGroup = 'combat',\n\t\tpriority = 300,\n\t\tphase = 'update',\n\t\tpublishDamage = true,\n\t} = options ?? {};\n\n\treturn definePlugin('projectile')\n\t\t.withComponentTypes<ProjectileComponentTypes>()\n\t\t.withEventTypes<ProjectileEventTypes>()\n\t\t.withLabels<'projectile-homing' | 'projectile-linear' | 'projectile-collision'>()\n\t\t.withGroups<G>()\n\t\t.requires<\n\t\t\tTransformWorldConfig &\n\t\t\tWorldConfigFrom<{}, CollisionEventTypes<string>>\n\t\t>()\n\t\t.install((world) => {\n\t\t\t// Homing projectiles — track target position each frame\n\t\t\tworld\n\t\t\t\t.addSystem('projectile-homing')\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('homing', {\n\t\t\t\t\twith: ['projectile', 'projectileTarget', 'localTransform'],\n\t\t\t\t})\n\t\t\t\t.setProcess(({ queries, ecs, dt }) => {\n\t\t\t\t\tfor (const entity of queries.homing) {\n\t\t\t\t\t\tconst { projectile, projectileTarget, localTransform } = entity.components;\n\n\t\t\t\t\t\t// Target no longer exists — remove projectile\n\t\t\t\t\t\tif (!ecs.getEntity(projectileTarget.entityId)) {\n\t\t\t\t\t\t\tecs.commands.removeEntity(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 targetTransform = ecs.getComponent(projectileTarget.entityId, 'worldTransform');\n\t\t\t\t\t\tif (!targetTransform) {\n\t\t\t\t\t\t\tecs.commands.removeEntity(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 dx = targetTransform.x - localTransform.x;\n\t\t\t\t\t\tconst dy = targetTransform.y - localTransform.y;\n\t\t\t\t\t\tconst distSq = dx * dx + dy * dy;\n\t\t\t\t\t\tconst step = projectile.speed * dt;\n\n\t\t\t\t\t\tif (distSq <= step * step) {\n\t\t\t\t\t\t\tlocalTransform.x = targetTransform.x;\n\t\t\t\t\t\t\tlocalTransform.y = targetTransform.y;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconst dist = Math.sqrt(distSq);\n\t\t\t\t\t\t\tlocalTransform.x += (dx / dist) * step;\n\t\t\t\t\t\t\tlocalTransform.y += (dy / dist) * step;\n\t\t\t\t\t\t\tlocalTransform.rotation = Math.atan2(dy, dx);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tecs.markChanged(entity.id, 'localTransform');\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t// Linear projectiles — move in fixed direction\n\t\t\tworld\n\t\t\t\t.addSystem('projectile-linear')\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('linear', {\n\t\t\t\t\twith: ['projectile', 'projectileDirection', 'localTransform'],\n\t\t\t\t})\n\t\t\t\t.setProcess(({ queries, dt }) => {\n\t\t\t\t\tfor (const entity of queries.linear) {\n\t\t\t\t\t\tconst { projectile, projectileDirection, localTransform } = entity.components;\n\t\t\t\t\t\tconst step = projectile.speed * dt;\n\t\t\t\t\t\tlocalTransform.x += projectileDirection.x * step;\n\t\t\t\t\t\tlocalTransform.y += projectileDirection.y * step;\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t// Collision integration — route collision events to projectileHit + damage\n\t\t\tworld\n\t\t\t\t.addSystem('projectile-collision')\n\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t.setEventHandlers({\n\t\t\t\t\tcollision({ data, ecs }) {\n\t\t\t\t\t\tif (!ecs.getEntity(data.entityA) || !ecs.getEntity(data.entityB)) return;\n\n\t\t\t\t\t\tconst projectileA = ecs.getComponent(data.entityA, 'projectile');\n\t\t\t\t\t\tconst projectileB = ecs.getComponent(data.entityB, 'projectile');\n\n\t\t\t\t\t\tconst isAProjectile = projectileA !== undefined;\n\t\t\t\t\t\tconst projectileData = isAProjectile ? projectileA : projectileB;\n\t\t\t\t\t\tif (!projectileData) return;\n\n\t\t\t\t\t\tconst projectileId = isAProjectile ? data.entityA : data.entityB;\n\t\t\t\t\t\tconst targetId = isAProjectile ? data.entityB : data.entityA;\n\n\t\t\t\t\t\t// Don't hit the entity that fired this projectile\n\t\t\t\t\t\tif (targetId === projectileData.sourceId) return;\n\n\t\t\t\t\t\tecs.eventBus.publish('projectileHit', {\n\t\t\t\t\t\t\tprojectileId,\n\t\t\t\t\t\t\ttargetId,\n\t\t\t\t\t\t\tdamage: projectileData.damage,\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tif (publishDamage) {\n\t\t\t\t\t\t\tecs.eventBus.publish('damage', {\n\t\t\t\t\t\t\t\tentityId: targetId,\n\t\t\t\t\t\t\t\tamount: projectileData.damage,\n\t\t\t\t\t\t\t\tsourceId: projectileData.sourceId,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tecs.commands.removeEntity(projectileId);\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": "2FD63C0EC856D97064756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "D0756C0A27AA8CAC64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,5 +1,5 @@
1
- var $=Object.defineProperty;var A=(j)=>j;function G(j,k){this[j]=A.bind(null,k)}var Y=(j,k)=>{for(var q in k)$(j,q,{get:k[q],enumerable:!0,configurable:!0,set:G.bind(k,q)})};var _=(j,k)=>()=>(j&&(k=j(j=0)),k);var D=((j)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(j,{get:(k,q)=>(typeof require<"u"?require:k)[q]}):j)(function(j){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+j+'" is not supported')});import{definePlugin as L}from"ecspresso";function M(j){let k=new Float64Array(j),q=0,z=0;return{push(Q){if(k[q]=Q,q=(q+1)%j,z<j)z++},computeFps(){if(z<2)return 0;let Q=k[(q-1+j)%j]??0,U=k[(q-z+j)%j]??0,F=Q-U;if(F<=0)return 0;return(z-1)/F*1000},computeAverageFrameTime(){if(z<2)return 0;let Q=k[(q-1+j)%j]??0,U=k[(q-z+j)%j]??0,F=Q-U;if(F<=0)return 0;return F/(z-1)},get size(){return z}}}function R(j){let{systemGroup:k="diagnostics",enableTimingOnInit:q=!0,fpsSampleCount:z=60}=j??{},Q={fps:0,entityCount:0,systemTimings:new Map,phaseTimings:{preUpdate:0,fixedUpdate:0,update:0,postUpdate:0,render:0},averageFrameTime:0},U=M(z);return L("diagnostics").withResourceTypes().withLabels().withGroups().install((F)=>{F.addResource("diagnostics",Q),F.addSystem("diagnostics-collect").setPriority(-999999).inPhase("render").inGroup(k).setOnInitialize((J)=>{if(q)J.enableDiagnostics(!0)}).setOnDetach((J)=>{J.enableDiagnostics(!1)}).setProcess(({ecs:J})=>{let V=performance.now();U.push(V);let K=J.getResource("diagnostics"),H={fps:U.computeFps(),entityCount:J.entityCount,systemTimings:J.systemTimings,phaseTimings:J.phaseTimings,averageFrameTime:U.computeAverageFrameTime()};K.fps=H.fps,K.entityCount=H.entityCount,K.systemTimings=H.systemTimings,K.phaseTimings=H.phaseTimings,K.averageFrameTime=H.averageFrameTime})})}var N={"top-left":"top:8px;left:8px","top-right":"top:8px;right:8px","bottom-left":"bottom:8px;left:8px","bottom-right":"bottom:8px;right:8px"};function B(j,k){let{position:q="top-left",updateInterval:z=200,showSystemTimings:Q=!0,maxSystemsShown:U=10}=k??{},F=document.createElement("div");F.style.cssText=`position:fixed;${N[q]};z-index:999999;background:rgba(0,0,0,0.8);color:#0f0;font:12px/1.4 monospace;padding:8px 12px;border-radius:4px;pointer-events:none;white-space:pre`,document.body.appendChild(F);let J=setInterval(()=>{let V=j.getResource("diagnostics"),K=[`FPS: ${V.fps.toFixed(0)}`,`Frame: ${V.averageFrameTime.toFixed(2)}ms`,`Entities: ${V.entityCount}`],H=V.phaseTimings;if(K.push(`Phases: pre=${H.preUpdate.toFixed(2)} fix=${H.fixedUpdate.toFixed(2)} upd=${H.update.toFixed(2)} post=${H.postUpdate.toFixed(2)} ren=${H.render.toFixed(2)}`),Q&&V.systemTimings.size>0){K.push("--- Systems ---");let Z=[...V.systemTimings.entries()].sort((W,X)=>X[1]-W[1]).slice(0,U);for(let[W,X]of Z)K.push(` ${W}: ${X.toFixed(3)}ms`)}F.textContent=K.join(`
2
- `)},z);return()=>{clearInterval(J),F.remove()}}export{R as createDiagnosticsPlugin,B as createDiagnosticsOverlay};
1
+ var L=((j)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(j,{get:(F,k)=>(typeof require<"u"?require:F)[k]}):j)(function(j){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+j+'" is not supported')});import{definePlugin as $}from"ecspresso";function A(j){let F=new Float64Array(j),k=0,q=0;return{push(Q){if(F[k]=Q,k=(k+1)%j,q<j)q++},computeFps(){if(q<2)return 0;let Q=F[(k-1+j)%j]??0,U=F[(k-q+j)%j]??0,z=Q-U;if(z<=0)return 0;return(q-1)/z*1000},computeAverageFrameTime(){if(q<2)return 0;let Q=F[(k-1+j)%j]??0,U=F[(k-q+j)%j]??0,z=Q-U;if(z<=0)return 0;return z/(q-1)},get size(){return q}}}function Y(j){let{systemGroup:F="diagnostics",enableTimingOnInit:k=!0,fpsSampleCount:q=60}=j??{},Q={fps:0,entityCount:0,systemTimings:new Map,phaseTimings:{preUpdate:0,fixedUpdate:0,update:0,postUpdate:0,render:0},averageFrameTime:0},U=A(q);return $("diagnostics").withResourceTypes().withLabels().withGroups().install((z)=>{z.addResource("diagnostics",Q),z.addSystem("diagnostics-collect").setPriority(-999999).inPhase("render").inGroup(F).setOnInitialize((J)=>{if(k)J.enableDiagnostics(!0)}).setOnDetach((J)=>{J.enableDiagnostics(!1)}).setProcess(({ecs:J})=>{let V=performance.now();U.push(V);let K=J.getResource("diagnostics"),H={fps:U.computeFps(),entityCount:J.entityCount,systemTimings:J.systemTimings,phaseTimings:J.phaseTimings,averageFrameTime:U.computeAverageFrameTime()};K.fps=H.fps,K.entityCount=H.entityCount,K.systemTimings=H.systemTimings,K.phaseTimings=H.phaseTimings,K.averageFrameTime=H.averageFrameTime})})}var G={"top-left":"top:8px;left:8px","top-right":"top:8px;right:8px","bottom-left":"bottom:8px;left:8px","bottom-right":"bottom:8px;right:8px"};function _(j,F){let{position:k="top-left",updateInterval:q=200,showSystemTimings:Q=!0,maxSystemsShown:U=10}=F??{},z=document.createElement("div");z.style.cssText=`position:fixed;${G[k]};z-index:999999;background:rgba(0,0,0,0.8);color:#0f0;font:12px/1.4 monospace;padding:8px 12px;border-radius:4px;pointer-events:none;white-space:pre`,document.body.appendChild(z);let J=setInterval(()=>{let V=j.getResource("diagnostics"),K=[`FPS: ${V.fps.toFixed(0)}`,`Frame: ${V.averageFrameTime.toFixed(2)}ms`,`Entities: ${V.entityCount}`],H=V.phaseTimings;if(K.push(`Phases: pre=${H.preUpdate.toFixed(2)} fix=${H.fixedUpdate.toFixed(2)} upd=${H.update.toFixed(2)} post=${H.postUpdate.toFixed(2)} ren=${H.render.toFixed(2)}`),Q&&V.systemTimings.size>0){K.push("--- Systems ---");let Z=[...V.systemTimings.entries()].sort((W,X)=>X[1]-W[1]).slice(0,U);for(let[W,X]of Z)K.push(` ${W}: ${X.toFixed(3)}ms`)}z.textContent=K.join(`
2
+ `)},q);return()=>{clearInterval(J),z.remove()}}export{Y as createDiagnosticsPlugin,_ as createDiagnosticsOverlay};
3
3
 
4
- //# debugId=2396ABCE6E466B2664756E2164756E21
4
+ //# debugId=D7FE41862EA92B5B64756E2164756E21
5
5
  //# sourceMappingURL=diagnostics.js.map
@@ -4,7 +4,7 @@
4
4
  "sourcesContent": [
5
5
  "/**\n * Diagnostics Plugin for ECSpresso\n *\n * Runtime diagnostics: FPS, entity count, per-system timing, per-phase timing,\n * and an optional DOM overlay for visual debugging.\n */\n\nimport { definePlugin } from 'ecspresso';\nimport type { SystemPhase } from 'ecspresso';\n\n// ==================== Types ====================\n\nexport interface DiagnosticsData {\n\tfps: number;\n\tentityCount: number;\n\tsystemTimings: ReadonlyMap<string, number>;\n\tphaseTimings: Readonly<Record<SystemPhase, number>>;\n\taverageFrameTime: number;\n}\n\nexport interface DiagnosticsResourceTypes {\n\tdiagnostics: DiagnosticsData;\n}\n\nexport interface DiagnosticsPluginOptions<G extends string = 'diagnostics'> {\n\t/** System group name (default: 'diagnostics') */\n\tsystemGroup?: G;\n\t/** Enable timing collection on initialize (default: true) */\n\tenableTimingOnInit?: boolean;\n\t/** Number of frames to sample for FPS average (default: 60) */\n\tfpsSampleCount?: number;\n}\n\nexport interface DiagnosticsOverlayOptions {\n\t/** Corner position (default: 'top-left') */\n\tposition?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';\n\t/** Milliseconds between DOM updates (default: 200) */\n\tupdateInterval?: number;\n\t/** Show per-system timings (default: true) */\n\tshowSystemTimings?: boolean;\n\t/** Maximum systems to show in overlay (default: 10) */\n\tmaxSystemsShown?: number;\n}\n\n// ==================== Ring Buffer ====================\n\n/**\n * Fixed-size circular buffer for frame timestamps.\n * Avoids Array.shift() allocation on every frame.\n */\nfunction createRingBuffer(capacity: number) {\n\tconst buffer = new Float64Array(capacity);\n\tlet writeIndex = 0;\n\tlet count = 0;\n\n\treturn {\n\t\tpush(value: number): void {\n\t\t\tbuffer[writeIndex] = value;\n\t\t\twriteIndex = (writeIndex + 1) % capacity;\n\t\t\tif (count < capacity) count++;\n\t\t},\n\n\t\t/** Compute FPS from stored timestamps */\n\t\tcomputeFps(): number {\n\t\t\tif (count < 2) return 0;\n\t\t\tconst newest = buffer[(writeIndex - 1 + capacity) % capacity] ?? 0;\n\t\t\tconst oldest = buffer[(writeIndex - count + capacity) % capacity] ?? 0;\n\t\t\tconst elapsed = newest - oldest;\n\t\t\tif (elapsed <= 0) return 0;\n\t\t\treturn ((count - 1) / elapsed) * 1000;\n\t\t},\n\n\t\t/** Compute average frame time in ms */\n\t\tcomputeAverageFrameTime(): number {\n\t\t\tif (count < 2) return 0;\n\t\t\tconst newest = buffer[(writeIndex - 1 + capacity) % capacity] ?? 0;\n\t\t\tconst oldest = buffer[(writeIndex - count + capacity) % capacity] ?? 0;\n\t\t\tconst elapsed = newest - oldest;\n\t\t\tif (elapsed <= 0) return 0;\n\t\t\treturn elapsed / (count - 1);\n\t\t},\n\n\t\tget size(): number {\n\t\t\treturn count;\n\t\t},\n\t};\n}\n\n// ==================== Plugin Factory ====================\n\nexport function createDiagnosticsPlugin<G extends string = 'diagnostics'>(\n\toptions?: DiagnosticsPluginOptions<G>,\n) {\n\tconst {\n\t\tsystemGroup = 'diagnostics',\n\t\tenableTimingOnInit = true,\n\t\tfpsSampleCount = 60,\n\t} = options ?? {};\n\n\tconst initialData: DiagnosticsData = {\n\t\tfps: 0,\n\t\tentityCount: 0,\n\t\tsystemTimings: new Map(),\n\t\tphaseTimings: { preUpdate: 0, fixedUpdate: 0, update: 0, postUpdate: 0, render: 0 },\n\t\taverageFrameTime: 0,\n\t};\n\n\tconst ringBuffer = createRingBuffer(fpsSampleCount);\n\n\treturn definePlugin('diagnostics')\n\t\t.withResourceTypes<DiagnosticsResourceTypes>()\n\t\t.withLabels<'diagnostics-collect'>()\n\t\t.withGroups<G>()\n\t\t.install((world) => {\n\t\t\tworld.addResource('diagnostics', initialData);\n\n\t\t\tworld\n\t\t\t\t.addSystem('diagnostics-collect')\n\t\t\t\t.setPriority(-999999)\n\t\t\t\t.inPhase('render')\n\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t.setOnInitialize((ecs) => {\n\t\t\t\t\tif (enableTimingOnInit) {\n\t\t\t\t\t\tecs.enableDiagnostics(true);\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.setOnDetach((ecs) => {\n\t\t\t\t\tecs.enableDiagnostics(false);\n\t\t\t\t})\n\t\t\t\t.setProcess(({ ecs }) => {\n\t\t\t\t\tconst now = performance.now();\n\t\t\t\t\tringBuffer.push(now);\n\n\t\t\t\t\tconst resource = ecs.getResource('diagnostics');\n\t\t\t\t\tconst updated: DiagnosticsData = {\n\t\t\t\t\t\tfps: ringBuffer.computeFps(),\n\t\t\t\t\t\tentityCount: ecs.entityCount,\n\t\t\t\t\t\tsystemTimings: ecs.systemTimings,\n\t\t\t\t\t\tphaseTimings: ecs.phaseTimings,\n\t\t\t\t\t\taverageFrameTime: ringBuffer.computeAverageFrameTime(),\n\t\t\t\t\t};\n\n\t\t\t\t\t// Mutate fields on the existing resource object to avoid allocation\n\t\t\t\t\t(resource as { -readonly [K in keyof DiagnosticsData]: DiagnosticsData[K] }).fps = updated.fps;\n\t\t\t\t\t(resource as { -readonly [K in keyof DiagnosticsData]: DiagnosticsData[K] }).entityCount = updated.entityCount;\n\t\t\t\t\t(resource as { -readonly [K in keyof DiagnosticsData]: DiagnosticsData[K] }).systemTimings = updated.systemTimings;\n\t\t\t\t\t(resource as { -readonly [K in keyof DiagnosticsData]: DiagnosticsData[K] }).phaseTimings = updated.phaseTimings;\n\t\t\t\t\t(resource as { -readonly [K in keyof DiagnosticsData]: DiagnosticsData[K] }).averageFrameTime = updated.averageFrameTime;\n\t\t\t\t});\n\t\t});\n}\n\n// ==================== Overlay Helper ====================\n\nconst POSITION_STYLES: Record<NonNullable<DiagnosticsOverlayOptions['position']>, string> = {\n\t'top-left': 'top:8px;left:8px',\n\t'top-right': 'top:8px;right:8px',\n\t'bottom-left': 'bottom:8px;left:8px',\n\t'bottom-right': 'bottom:8px;right:8px',\n} as const;\n\n/**\n * Create a DOM overlay that displays diagnostics data.\n * Returns a cleanup function that removes the element and clears the interval.\n *\n * @param ecs An ECSpresso instance with the diagnostics resource\n * @param options Overlay configuration\n * @returns Cleanup function\n */\nexport function createDiagnosticsOverlay<\n\tR extends DiagnosticsResourceTypes,\n>(\n\tecs: { getResource<K extends keyof R>(key: K): R[K] },\n\toptions?: DiagnosticsOverlayOptions,\n): () => void {\n\tconst {\n\t\tposition = 'top-left',\n\t\tupdateInterval = 200,\n\t\tshowSystemTimings = true,\n\t\tmaxSystemsShown = 10,\n\t} = options ?? {};\n\n\tconst el = document.createElement('div');\n\tel.style.cssText = `position:fixed;${POSITION_STYLES[position]};z-index:999999;background:rgba(0,0,0,0.8);color:#0f0;font:12px/1.4 monospace;padding:8px 12px;border-radius:4px;pointer-events:none;white-space:pre`;\n\tdocument.body.appendChild(el);\n\n\tconst intervalId = setInterval(() => {\n\t\tconst d = ecs.getResource('diagnostics' as keyof R) as DiagnosticsData;\n\n\t\tconst lines: string[] = [\n\t\t\t`FPS: ${d.fps.toFixed(0)}`,\n\t\t\t`Frame: ${d.averageFrameTime.toFixed(2)}ms`,\n\t\t\t`Entities: ${d.entityCount}`,\n\t\t];\n\n\t\tconst phases = d.phaseTimings;\n\t\tlines.push(\n\t\t\t`Phases: pre=${phases.preUpdate.toFixed(2)} fix=${phases.fixedUpdate.toFixed(2)} upd=${phases.update.toFixed(2)} post=${phases.postUpdate.toFixed(2)} ren=${phases.render.toFixed(2)}`,\n\t\t);\n\n\t\tif (showSystemTimings && d.systemTimings.size > 0) {\n\t\t\tlines.push('--- Systems ---');\n\t\t\tconst sorted = [...d.systemTimings.entries()]\n\t\t\t\t.sort((a, b) => b[1] - a[1])\n\t\t\t\t.slice(0, maxSystemsShown);\n\t\t\tfor (const [label, ms] of sorted) {\n\t\t\t\tlines.push(` ${label}: ${ms.toFixed(3)}ms`);\n\t\t\t}\n\t\t}\n\n\t\tel.textContent = lines.join('\\n');\n\t}, updateInterval);\n\n\treturn () => {\n\t\tclearInterval(intervalId);\n\t\tel.remove();\n\t};\n}\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "2396ABCE6E466B2664756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "D7FE41862EA92B5B64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,4 +1,4 @@
1
- var i=Object.defineProperty;var s=(j)=>j;function o(j,q){this[j]=s.bind(null,q)}var Wj=(j,q)=>{for(var W in q)i(j,W,{get:q[W],enumerable:!0,configurable:!0,set:o.bind(q,W)})};var Yj=(j,q)=>()=>(j&&(q=j(j=0)),q);var $j=((j)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(j,{get:(q,W)=>(typeof require<"u"?require:q)[W]}):j)(function(j){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+j+'" is not supported')});import{definePlugin as n}from"ecspresso";function Gj(j){return j}function Kj(j,...q){return q.map((W)=>({pad:j,button:W}))}function Cj(j,q,W,G){return G===void 0?{pad:j,axis:q,direction:W}:{pad:j,axis:q,direction:W,threshold:G}}var d=0.5,r=0.15,H=4;function t(){return{keysDown:new Set,keysPressed:[],keysReleased:[],pointerButtonsDown:new Set,pointerButtonsPressed:[],pointerButtonsReleased:[],pointerX:0,pointerY:0,lastPointerX:0,lastPointerY:0,pointerMoved:!1}}function a(){return{keysDown:new Set,keysPressed:new Set,keysReleased:new Set,pointerButtonsDown:new Set,pointerButtonsPressed:new Set,pointerButtonsReleased:new Set,pointerX:0,pointerY:0,pointerDeltaX:0,pointerDeltaY:0}}function e(){return{connected:!1,id:null,buttonsDown:new Set,buttonsPrev:new Set,buttonsPressed:new Set,buttonsReleased:new Set,buttonValues:[],axes:[],rawAxes:[]}}function h(){return{active:new Set,prev:new Set}}function B(j,q){j.clear();for(let W of q)j.add(W)}function jj(j,q){B(j.keysDown,q.keysDown),B(j.keysPressed,q.keysPressed),B(j.keysReleased,q.keysReleased),B(j.pointerButtonsDown,q.pointerButtonsDown),B(j.pointerButtonsPressed,q.pointerButtonsPressed),B(j.pointerButtonsReleased,q.pointerButtonsReleased),j.pointerDeltaX=q.pointerMoved?q.pointerX-q.lastPointerX:0,j.pointerDeltaY=q.pointerMoved?q.pointerY-q.lastPointerY:0,j.pointerX=q.pointerX,j.pointerY=q.pointerY,q.keysPressed.length=0,q.keysReleased.length=0,q.pointerButtonsPressed.length=0,q.pointerButtonsReleased.length=0,q.lastPointerX=q.pointerX,q.lastPointerY=q.pointerY,q.pointerMoved=!1}function qj(j){return()=>{if(typeof navigator>"u"||typeof navigator.getGamepads!=="function"){for(let W=0;W<j.length;W++)j[W]=null;return j}let q=navigator.getGamepads();for(let W=0;W<j.length;W++)j[W]=q[W]??null;return j}}function D(j,q,W,G,Z){let $=Math.sqrt(j*j+q*q);if($<W){G[Z]=0,G[Z+1]=0;return}let V=Math.min(($-W)/(1-W),1);G[Z]=j/$*V,G[Z+1]=q/$*V}function Jj(j,q,W){if(q.length=j.length,j.length>=2)D(j[0]??0,j[1]??0,W,q,0);if(j.length>=4)D(j[2]??0,j[3]??0,W,q,2);for(let G=4;G<j.length;G++)q[G]=j[G]??0}function Qj(j,q,W){let G=q();for(let Z=0;Z<H;Z++){let $=G[Z]??null,V=j[Z];if(!V)continue;let R=V.buttonsPrev;if(B(R,V.buttonsDown),V.buttonsDown.clear(),V.buttonsPressed.clear(),V.buttonsReleased.clear(),!$||!$.connected){if(V.connected){for(let Y of R)V.buttonsReleased.add(Y);V.connected=!1,V.id=null,V.buttonValues.length=0,V.axes.length=0,V.rawAxes.length=0}continue}V.connected=!0,V.id=$.id,V.buttonValues.length=$.buttons.length;for(let Y=0;Y<$.buttons.length;Y++){let E=$.buttons[Y];if(!E){V.buttonValues[Y]=0;continue}if(V.buttonValues[Y]=E.value,E.pressed)V.buttonsDown.add(Y)}for(let Y of V.buttonsDown)if(!R.has(Y))V.buttonsPressed.add(Y);for(let Y of R)if(!V.buttonsDown.has(Y))V.buttonsReleased.add(Y);V.rawAxes.length=$.axes.length;for(let Y=0;Y<$.axes.length;Y++)V.rawAxes[Y]=$.axes[Y]??0;Jj(V.rawAxes,V.axes,W)}}function Vj(j,q,W,G){if(j.keys?.some((Z)=>q.has(Z)))return!0;if(j.pointerButtons?.some((Z)=>W.has(Z)))return!0;if(j.gamepadButtons?.some(({pad:Z,button:$})=>G[Z]?.buttonsDown.has($)??!1))return!0;if(j.gamepadAxes?.some(({pad:Z,axis:$,direction:V,threshold:R=d})=>{let Y=G[Z]?.axes[$]??0;return V>0?Y>R:Y<-R}))return!0;return!1}function k(j,q,W,G,Z){let $=j.prev;j.prev=j.active,j.active=$,$.clear();for(let[V,R]of Object.entries(q))if(Vj(R,W,G,Z))$.add(V)}function g(j){return{isActive:(q)=>j.active.has(q),justActivated:(q)=>j.active.has(q)&&!j.prev.has(q),justDeactivated:(q)=>!j.active.has(q)&&j.prev.has(q)}}function Rj(j){let{systemGroup:q="input",priority:W=100,phase:G="preUpdate",target:Z=globalThis,gamepad:$={},coordinateTransform:V}=j??{},R={...j?.actions??{}},Y=new Map(Object.entries(j?.players??{})),E=$.deadzone??r,S=$.poll??qj(Array(H).fill(null)),C=t(),K=a(),L=Array.from({length:H},e),z=h(),O=new Map,N=new Map,T=[],I={x:0,y:0},F={x:0,y:0},U=R,A={isDown:(J)=>K.keysDown.has(J),justPressed:(J)=>K.keysPressed.has(J),justReleased:(J)=>K.keysReleased.has(J)},y={position:I,delta:F,isDown:(J)=>K.pointerButtonsDown.has(J),justPressed:(J)=>K.pointerButtonsPressed.has(J),justReleased:(J)=>K.pointerButtonsReleased.has(J)};function b(J){let Q=L[J];if(!Q)throw Error(`Invalid gamepad index: ${J}`);return{get connected(){return Q.connected},get id(){return Q.id},isDown:(X)=>Q.buttonsDown.has(X),justPressed:(X)=>Q.buttonsPressed.has(X),justReleased:(X)=>Q.buttonsReleased.has(X),buttonValue:(X)=>Q.buttonValues[X]??0,axis:(X)=>Q.axes[X]??0,rawAxis:(X)=>Q.rawAxes[X]??0}}let c=Array.from({length:H},(J,Q)=>b(Q)),f=g(z);function M(J){let Q=O.get(J);if(Q)return Q;let X=h();return O.set(J,X),X}function P(J){let Q=M(J);return{actions:g(Q),setActionMap:(X)=>{if(!Y.has(J))throw Error(`Player '${J}' was removed`);Y.set(J,{...X})},getActionMap:()=>{let X=Y.get(J);if(!X)throw Error(`Player '${J}' was removed`);return{...X}}}}for(let J of Y.keys())N.set(J,P(J));let x={keyboard:A,pointer:y,gamepads:c,actions:f,setActionMap(J){U={...J}},getActionMap(){return{...U}},definePlayer(J,Q){if(Y.set(J,{...Q}),!N.has(J))N.set(J,P(J))},removePlayer(J){let Q=Y.delete(J);return N.delete(J),O.delete(J),Q},player(J){return N.get(J)},playerIds(){return Array.from(Y.keys())}};function m(J){let Q=J;if(Q.repeat)return;C.keysDown.add(Q.key),C.keysPressed.push(Q.key)}function u(J){let Q=J;C.keysDown.delete(Q.key),C.keysReleased.push(Q.key)}function w(J){let Q=J;C.pointerButtonsDown.add(Q.button),C.pointerButtonsPressed.push(Q.button)}function l(J){let Q=J;if(V){let{x:X,y:v}=V(Q.clientX,Q.clientY);C.pointerX=X,C.pointerY=v}else C.pointerX=Q.clientX,C.pointerY=Q.clientY;C.pointerMoved=!0}function p(J){let Q=J;C.pointerButtonsDown.delete(Q.button),C.pointerButtonsReleased.push(Q.button)}function _(J,Q){Z.addEventListener(J,Q),T.push(()=>{Z.removeEventListener(J,Q)})}return n("input").withResourceTypes().withLabels().withGroups().install((J)=>{J.addResource("inputState",x),J.addSystem("input-state").setPriority(W).inPhase(G).inGroup(q).setOnInitialize(()=>{_("keydown",m),_("keyup",u),_("pointerdown",w),_("pointermove",l),_("pointerup",p)}).setOnDetach(()=>{for(let Q of T)Q();T.length=0}).setProcess(()=>{Qj(L,S,E),jj(K,C),I.x=K.pointerX,I.y=K.pointerY,F.x=K.pointerDeltaX,F.y=K.pointerDeltaY,k(z,U,K.keysDown,K.pointerButtonsDown,L);for(let[Q,X]of Y){let v=M(Q);k(v,X,K.keysDown,K.pointerButtonsDown,L)}})})}export{Kj as gamepadButtonsOn,Cj as gamepadAxisOn,Rj as createInputPlugin,Gj as createActionBinding};
1
+ var Jj=((j)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(j,{get:(q,W)=>(typeof require<"u"?require:q)[W]}):j)(function(j){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+j+'" is not supported')});import{definePlugin as i}from"ecspresso";function Wj(j){return j}function Yj(j,...q){return q.map((W)=>({pad:j,button:W}))}function $j(j,q,W,G){return G===void 0?{pad:j,axis:q,direction:W}:{pad:j,axis:q,direction:W,threshold:G}}var s=0.5,o=0.15,H=4;function n(){return{keysDown:new Set,keysPressed:[],keysReleased:[],pointerButtonsDown:new Set,pointerButtonsPressed:[],pointerButtonsReleased:[],pointerX:0,pointerY:0,lastPointerX:0,lastPointerY:0,pointerMoved:!1}}function d(){return{keysDown:new Set,keysPressed:new Set,keysReleased:new Set,pointerButtonsDown:new Set,pointerButtonsPressed:new Set,pointerButtonsReleased:new Set,pointerX:0,pointerY:0,pointerDeltaX:0,pointerDeltaY:0}}function r(){return{connected:!1,id:null,buttonsDown:new Set,buttonsPrev:new Set,buttonsPressed:new Set,buttonsReleased:new Set,buttonValues:[],axes:[],rawAxes:[]}}function h(){return{active:new Set,prev:new Set}}function B(j,q){j.clear();for(let W of q)j.add(W)}function t(j,q){B(j.keysDown,q.keysDown),B(j.keysPressed,q.keysPressed),B(j.keysReleased,q.keysReleased),B(j.pointerButtonsDown,q.pointerButtonsDown),B(j.pointerButtonsPressed,q.pointerButtonsPressed),B(j.pointerButtonsReleased,q.pointerButtonsReleased),j.pointerDeltaX=q.pointerMoved?q.pointerX-q.lastPointerX:0,j.pointerDeltaY=q.pointerMoved?q.pointerY-q.lastPointerY:0,j.pointerX=q.pointerX,j.pointerY=q.pointerY,q.keysPressed.length=0,q.keysReleased.length=0,q.pointerButtonsPressed.length=0,q.pointerButtonsReleased.length=0,q.lastPointerX=q.pointerX,q.lastPointerY=q.pointerY,q.pointerMoved=!1}function a(j){return()=>{if(typeof navigator>"u"||typeof navigator.getGamepads!=="function"){for(let W=0;W<j.length;W++)j[W]=null;return j}let q=navigator.getGamepads();for(let W=0;W<j.length;W++)j[W]=q[W]??null;return j}}function D(j,q,W,G,Z){let $=Math.sqrt(j*j+q*q);if($<W){G[Z]=0,G[Z+1]=0;return}let V=Math.min(($-W)/(1-W),1);G[Z]=j/$*V,G[Z+1]=q/$*V}function e(j,q,W){if(q.length=j.length,j.length>=2)D(j[0]??0,j[1]??0,W,q,0);if(j.length>=4)D(j[2]??0,j[3]??0,W,q,2);for(let G=4;G<j.length;G++)q[G]=j[G]??0}function jj(j,q,W){let G=q();for(let Z=0;Z<H;Z++){let $=G[Z]??null,V=j[Z];if(!V)continue;let R=V.buttonsPrev;if(B(R,V.buttonsDown),V.buttonsDown.clear(),V.buttonsPressed.clear(),V.buttonsReleased.clear(),!$||!$.connected){if(V.connected){for(let Y of R)V.buttonsReleased.add(Y);V.connected=!1,V.id=null,V.buttonValues.length=0,V.axes.length=0,V.rawAxes.length=0}continue}V.connected=!0,V.id=$.id,V.buttonValues.length=$.buttons.length;for(let Y=0;Y<$.buttons.length;Y++){let E=$.buttons[Y];if(!E){V.buttonValues[Y]=0;continue}if(V.buttonValues[Y]=E.value,E.pressed)V.buttonsDown.add(Y)}for(let Y of V.buttonsDown)if(!R.has(Y))V.buttonsPressed.add(Y);for(let Y of R)if(!V.buttonsDown.has(Y))V.buttonsReleased.add(Y);V.rawAxes.length=$.axes.length;for(let Y=0;Y<$.axes.length;Y++)V.rawAxes[Y]=$.axes[Y]??0;e(V.rawAxes,V.axes,W)}}function qj(j,q,W,G){if(j.keys?.some((Z)=>q.has(Z)))return!0;if(j.pointerButtons?.some((Z)=>W.has(Z)))return!0;if(j.gamepadButtons?.some(({pad:Z,button:$})=>G[Z]?.buttonsDown.has($)??!1))return!0;if(j.gamepadAxes?.some(({pad:Z,axis:$,direction:V,threshold:R=s})=>{let Y=G[Z]?.axes[$]??0;return V>0?Y>R:Y<-R}))return!0;return!1}function k(j,q,W,G,Z){let $=j.prev;j.prev=j.active,j.active=$,$.clear();for(let[V,R]of Object.entries(q))if(qj(R,W,G,Z))$.add(V)}function g(j){return{isActive:(q)=>j.active.has(q),justActivated:(q)=>j.active.has(q)&&!j.prev.has(q),justDeactivated:(q)=>!j.active.has(q)&&j.prev.has(q)}}function Xj(j){let{systemGroup:q="input",priority:W=100,phase:G="preUpdate",target:Z=globalThis,gamepad:$={},coordinateTransform:V}=j??{},R={...j?.actions??{}},Y=new Map(Object.entries(j?.players??{})),E=$.deadzone??o,S=$.poll??a(Array(H).fill(null)),C=n(),K=d(),L=Array.from({length:H},r),z=h(),O=new Map,N=new Map,T=[],I={x:0,y:0},F={x:0,y:0},U=R,A={isDown:(J)=>K.keysDown.has(J),justPressed:(J)=>K.keysPressed.has(J),justReleased:(J)=>K.keysReleased.has(J)},y={position:I,delta:F,isDown:(J)=>K.pointerButtonsDown.has(J),justPressed:(J)=>K.pointerButtonsPressed.has(J),justReleased:(J)=>K.pointerButtonsReleased.has(J)};function b(J){let Q=L[J];if(!Q)throw Error(`Invalid gamepad index: ${J}`);return{get connected(){return Q.connected},get id(){return Q.id},isDown:(X)=>Q.buttonsDown.has(X),justPressed:(X)=>Q.buttonsPressed.has(X),justReleased:(X)=>Q.buttonsReleased.has(X),buttonValue:(X)=>Q.buttonValues[X]??0,axis:(X)=>Q.axes[X]??0,rawAxis:(X)=>Q.rawAxes[X]??0}}let c=Array.from({length:H},(J,Q)=>b(Q)),f=g(z);function M(J){let Q=O.get(J);if(Q)return Q;let X=h();return O.set(J,X),X}function P(J){let Q=M(J);return{actions:g(Q),setActionMap:(X)=>{if(!Y.has(J))throw Error(`Player '${J}' was removed`);Y.set(J,{...X})},getActionMap:()=>{let X=Y.get(J);if(!X)throw Error(`Player '${J}' was removed`);return{...X}}}}for(let J of Y.keys())N.set(J,P(J));let x={keyboard:A,pointer:y,gamepads:c,actions:f,setActionMap(J){U={...J}},getActionMap(){return{...U}},definePlayer(J,Q){if(Y.set(J,{...Q}),!N.has(J))N.set(J,P(J))},removePlayer(J){let Q=Y.delete(J);return N.delete(J),O.delete(J),Q},player(J){return N.get(J)},playerIds(){return Array.from(Y.keys())}};function m(J){let Q=J;if(Q.repeat)return;C.keysDown.add(Q.key),C.keysPressed.push(Q.key)}function u(J){let Q=J;C.keysDown.delete(Q.key),C.keysReleased.push(Q.key)}function w(J){let Q=J;C.pointerButtonsDown.add(Q.button),C.pointerButtonsPressed.push(Q.button)}function l(J){let Q=J;if(V){let{x:X,y:v}=V(Q.clientX,Q.clientY);C.pointerX=X,C.pointerY=v}else C.pointerX=Q.clientX,C.pointerY=Q.clientY;C.pointerMoved=!0}function p(J){let Q=J;C.pointerButtonsDown.delete(Q.button),C.pointerButtonsReleased.push(Q.button)}function _(J,Q){Z.addEventListener(J,Q),T.push(()=>{Z.removeEventListener(J,Q)})}return i("input").withResourceTypes().withLabels().withGroups().install((J)=>{J.addResource("inputState",x),J.addSystem("input-state").setPriority(W).inPhase(G).inGroup(q).setOnInitialize(()=>{_("keydown",m),_("keyup",u),_("pointerdown",w),_("pointermove",l),_("pointerup",p)}).setOnDetach(()=>{for(let Q of T)Q();T.length=0}).setProcess(()=>{jj(L,S,E),t(K,C),I.x=K.pointerX,I.y=K.pointerY,F.x=K.pointerDeltaX,F.y=K.pointerDeltaY,k(z,U,K.keysDown,K.pointerButtonsDown,L);for(let[Q,X]of Y){let v=M(Q);k(v,X,K.keysDown,K.pointerButtonsDown,L)}})})}export{Yj as gamepadButtonsOn,$j as gamepadAxisOn,Xj as createInputPlugin,Wj as createActionBinding};
2
2
 
3
- //# debugId=A22CC6420E47F29C64756E2164756E21
3
+ //# debugId=A6B7FF490EDEEA4864756E2164756E21
4
4
  //# sourceMappingURL=input.js.map
@@ -4,7 +4,7 @@
4
4
  "sourcesContent": [
5
5
  "/**\n * Input Plugin for ECSpresso\n *\n * Resource-only plugin — input is polled via the `inputState` resource. Provides\n * frame-accurate keyboard, pointer (mouse + touch via PointerEvent), up to 4\n * gamepads, and unified + per-player action maps.\n *\n * Mutation model: DOM events accumulate into `raw` between frames and are\n * flattened once per frame into a stable `frame` object whose Sets are cleared\n * and refilled in place (no per-frame allocations). Gamepads are polled once\n * per frame via `navigator.getGamepads()` (or an injected poll function).\n * Unified and per-player action states ping-pong two Sets (`active` / `prev`)\n * so edge detection costs nothing beyond one `.add()` per active action.\n */\n\nimport { definePlugin, type BasePluginOptions, type Vector2D } from 'ecspresso';\n\n// ==================== Public Types ====================\n\n// Key codes per the UI Events spec (KeyboardEvent.key values)\n// https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values\n\ntype LowercaseLetter =\n\t| 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm'\n\t| 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z';\n\ntype Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';\n\ntype Punctuation =\n\t| '`' | '~' | '!' | '@' | '#' | '$' | '%' | '^' | '&' | '*' | '(' | ')'\n\t| '-' | '_' | '=' | '+' | '[' | '{' | ']' | '}' | '\\\\' | '|'\n\t| ';' | ':' | \"'\" | '\"' | ',' | '<' | '.' | '>' | '/' | '?';\n\ntype ModifierKey =\n\t| 'Alt' | 'AltGraph' | 'CapsLock' | 'Control' | 'Fn' | 'FnLock'\n\t| 'Hyper' | 'Meta' | 'NumLock' | 'ScrollLock' | 'Shift'\n\t| 'Super' | 'Symbol' | 'SymbolLock';\n\ntype WhitespaceKey = 'Enter' | 'Tab' | ' ';\n\ntype NavigationKey =\n\t| `Arrow${'Down' | 'Left' | 'Right' | 'Up'}`\n\t| 'End' | 'Home' | 'PageDown' | 'PageUp';\n\ntype EditingKey =\n\t| 'Backspace' | 'Clear' | 'Copy' | 'CrSel' | 'Cut' | 'Delete'\n\t| 'EraseEof' | 'ExSel' | 'Insert' | 'Paste' | 'Redo' | 'Undo';\n\ntype UIKey =\n\t| 'Accept' | 'Again' | 'Attn' | 'Cancel' | 'ContextMenu' | 'Escape'\n\t| 'Execute' | 'Find' | 'Finish' | 'Help' | 'Pause' | 'Play'\n\t| 'Props' | 'Select' | 'ZoomIn' | 'ZoomOut';\n\ntype DeviceKey =\n\t| 'BrightnessDown' | 'BrightnessUp' | 'Eject' | 'Hibernate'\n\t| 'LogOff' | 'Power' | 'PowerOff' | 'PrintScreen' | 'Standby' | 'WakeUp';\n\ntype IMEKey =\n\t| 'AllCandidates' | 'Alphanumeric' | 'CodeInput' | 'Compose' | 'Convert'\n\t| 'FinalMode' | 'GroupFirst' | 'GroupLast' | 'GroupNext' | 'GroupPrevious'\n\t| 'ModeChange' | 'NextCandidate' | 'NonConvert' | 'PreviousCandidate'\n\t| 'Process' | 'SingleCandidate'\n\t| 'HangulMode' | 'HanjaMode' | 'JunjaMode'\n\t| 'Eisu' | 'Hankaku' | 'Hiragana' | 'HiraganaKatakana' | 'KanaMode'\n\t| 'KanjiMode' | 'Katakana' | 'Romaji' | 'Zenkaku' | 'ZenkakuHankaku';\n\ntype FunctionKey =\n\t| `F${1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24}`\n\t| 'Soft1' | 'Soft2' | 'Soft3' | 'Soft4';\n\ntype PhoneKey =\n\t| 'AppSwitch' | 'Call' | 'Camera' | 'CameraFocus' | 'EndCall'\n\t| 'GoBack' | 'GoHome' | 'HeadsetHook' | 'LastNumberRedial'\n\t| 'Notification' | 'MannerMode' | 'VoiceDial';\n\ntype MultimediaKey =\n\t| 'ChannelDown' | 'ChannelUp'\n\t| `Media${\n\t\t'FastForward' | 'Pause' | 'Play' | 'PlayPause'\n\t\t| 'Record' | 'Rewind' | 'Stop' | 'TrackNext' | 'TrackPrevious'\n\t}`;\n\ntype AudioKey =\n\t| `Audio${\n\t\t'BalanceLeft' | 'BalanceRight' | 'BassDown' | 'BassBoostDown'\n\t\t| 'BassBoostToggle' | 'BassBoostUp' | 'BassUp' | 'FaderFront' | 'FaderRear'\n\t\t| 'SurroundModeNext' | 'TrebleDown' | 'TrebleUp'\n\t\t| 'VolumeDown' | 'VolumeMute' | 'VolumeUp'\n\t}`\n\t| `Microphone${'Toggle' | 'VolumeDown' | 'VolumeMute' | 'VolumeUp'}`;\n\ntype TVKey =\n\t| 'TV'\n\t| `TV${\n\t\t'3DMode' | 'AntennaCable' | 'AudioDescription' | 'AudioDescriptionMixDown'\n\t\t| 'AudioDescriptionMixUp' | 'ContentsMenu' | 'DataService' | 'Input'\n\t\t| 'InputComponent1' | 'InputComponent2' | 'InputComposite1' | 'InputComposite2'\n\t\t| 'InputHDMI1' | 'InputHDMI2' | 'InputHDMI3' | 'InputHDMI4' | 'InputVGA1'\n\t\t| 'MediaContext' | 'Network' | 'NumberEntry' | 'Power' | 'RadioService'\n\t\t| 'Satellite' | 'SatelliteBS' | 'SatelliteCS' | 'SatelliteToggle'\n\t\t| 'TerrestrialAnalog' | 'TerrestrialDigital' | 'Timer'\n\t}`;\n\ntype MediaControllerKey =\n\t| 'AVRInput' | 'AVRPower'\n\t| `Color${'F0Red' | 'F1Green' | 'F2Yellow' | 'F3Blue' | 'F4Grey' | 'F5Brown'}`\n\t| 'ClosedCaptionToggle' | 'Dimmer' | 'DisplaySwap' | 'DVR' | 'Exit'\n\t| `Favorite${'Clear' | 'Recall' | 'Store'}${0 | 1 | 2 | 3}`\n\t| 'Guide' | 'GuideNextDay' | 'GuidePreviousDay' | 'Info' | 'InstantReplay'\n\t| 'Link' | 'ListProgram' | 'LiveContent' | 'Lock'\n\t| `Media${\n\t\t'Apps' | 'AudioTrack' | 'Last' | 'SkipBackward'\n\t\t| 'SkipForward' | 'StepBackward' | 'StepForward' | 'TopMenu'\n\t}`\n\t| `Navigate${'In' | 'Next' | 'Out' | 'Previous'}`\n\t| 'NextFavoriteChannel' | 'NextUserProfile' | 'OnDemand' | 'Pairing'\n\t| `PinP${'Down' | 'Move' | 'Toggle' | 'Up'}`\n\t| `PlaySpeed${'Down' | 'Reset' | 'Up'}`\n\t| 'RandomToggle' | 'RcLowBattery' | 'RecordSpeedNext' | 'RfBypass'\n\t| 'ScanChannelsToggle' | 'ScreenModeNext' | 'Settings' | 'SplitScreenToggle'\n\t| 'STBInput' | 'STBPower' | 'Subtitle' | 'Teletext'\n\t| 'VideoModeNext' | 'Wink' | 'ZoomToggle';\n\ntype SpeechKey = 'SpeechCorrectionList' | 'SpeechInputToggle';\n\ntype DocumentKey =\n\t| 'Close' | 'New' | 'Open' | 'Print' | 'Save' | 'SpellCheck'\n\t| 'MailForward' | 'MailReply' | 'MailSend';\n\ntype LaunchKey = `Launch${\n\t| 'Calculator' | 'Calendar' | 'Contacts' | 'Mail' | 'MediaPlayer'\n\t| 'MusicPlayer' | 'MyComputer' | 'Phone' | 'ScreenSaver' | 'Spreadsheet'\n\t| 'WebBrowser' | 'WebCam' | 'WordProcessor'\n\t| `Application${1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16}`\n}`;\n\ntype BrowserKey = `Browser${'Back' | 'Favorites' | 'Forward' | 'Home' | 'Refresh' | 'Search' | 'Stop'}`;\n\ntype NumpadKey = 'Decimal' | 'Key11' | 'Key12' | 'Multiply' | 'Add' | 'Divide' | 'Subtract' | 'Separator';\n\nexport type KeyCode =\n\t| LowercaseLetter | Uppercase<LowercaseLetter> | Digit | Punctuation\n\t| ModifierKey | WhitespaceKey | NavigationKey | EditingKey | UIKey | DeviceKey\n\t| IMEKey | FunctionKey | PhoneKey | MultimediaKey | AudioKey | TVKey\n\t| MediaControllerKey | SpeechKey | DocumentKey | LaunchKey | BrowserKey | NumpadKey\n\t| 'Unidentified' | 'Dead';\n\nexport interface KeyboardState {\n\tisDown(key: KeyCode): boolean;\n\tjustPressed(key: KeyCode): boolean;\n\tjustReleased(key: KeyCode): boolean;\n}\n\nexport interface PointerState {\n\treadonly position: Readonly<Vector2D>;\n\treadonly delta: Readonly<Vector2D>;\n\tisDown(button: number): boolean;\n\tjustPressed(button: number): boolean;\n\tjustReleased(button: number): boolean;\n}\n\nexport interface GamepadState {\n\treadonly connected: boolean;\n\treadonly id: string | null;\n\tisDown(button: number): boolean;\n\tjustPressed(button: number): boolean;\n\tjustReleased(button: number): boolean;\n\t/** Analog button value in [0, 1]. Useful for triggers. Returns 0 when disconnected or out of range. */\n\tbuttonValue(button: number): number;\n\t/** Deadzone-applied axis value in [-1, 1]. Sticks use radial deadzone on axis pairs (0,1) and (2,3). */\n\taxis(index: number): number;\n\t/** Raw axis value in [-1, 1] with no deadzone applied. */\n\trawAxis(index: number): number;\n}\n\nexport interface ActionState<A extends string = string> {\n\tisActive(action: A): boolean;\n\tjustActivated(action: A): boolean;\n\tjustDeactivated(action: A): boolean;\n}\n\nexport interface PlayerInput<A extends string = string> {\n\treadonly actions: ActionState<A>;\n\tsetActionMap(map: ActionMap<A>): void;\n\tgetActionMap(): Readonly<ActionMap<A>>;\n}\n\nexport interface InputState<A extends string = string> {\n\treadonly keyboard: KeyboardState;\n\treadonly pointer: PointerState;\n\t/** Always length 4 (standard web gamepad slot count). Disconnected slots return `connected: false`. */\n\treadonly gamepads: ReadonlyArray<GamepadState>;\n\t/** Unified action state — fires when any bound input (keyboard, pointer, any pad) is active. Intended for menu/shared input. */\n\treadonly actions: ActionState<A>;\n\tsetActionMap(actions: ActionMap<A>): void;\n\tgetActionMap(): Readonly<ActionMap<A>>;\n\t/** Register or replace a player's action map. Per-player states are isolated from the unified `actions`. */\n\tdefinePlayer(id: string, map: ActionMap<A>): void;\n\t/** Returns true if the player existed and was removed. */\n\tremovePlayer(id: string): boolean;\n\t/** Returns a handle to a registered player's input, or undefined if no such player. */\n\tplayer(id: string): PlayerInput<A> | undefined;\n\tplayerIds(): readonly string[];\n}\n\nexport interface GamepadButtonRef {\n\tpad: number;\n\tbutton: number;\n}\n\nexport interface GamepadAxisRef {\n\tpad: number;\n\taxis: number;\n\t/** Which half of the axis counts as \"active\". */\n\tdirection: 1 | -1;\n\t/** Magnitude at which the axis triggers the action. Applied to the deadzone-adjusted axis value. Default: 0.5. */\n\tthreshold?: number;\n}\n\nexport interface ActionBinding {\n\tkeys?: KeyCode[];\n\t/** Pointer (mouse/touch) button indices — 0 = primary, 1 = auxiliary, 2 = secondary, etc. */\n\tpointerButtons?: number[];\n\tgamepadButtons?: GamepadButtonRef[];\n\tgamepadAxes?: GamepadAxisRef[];\n}\n\nexport type ActionMap<A extends string = string> = Record<A, ActionBinding>;\n\nexport interface InputResourceTypes<A extends string = string> {\n\tinputState: InputState<A>;\n}\n\n/**\n * Minimal gamepad shape required by the injectable poll function. A structural\n * subset of the browser `Gamepad` interface — `navigator.getGamepads()` satisfies\n * it directly, and test doubles can supply just these fields.\n */\nexport interface GamepadLike {\n\tid: string;\n\tconnected: boolean;\n\tbuttons: ReadonlyArray<{ pressed: boolean; value: number }>;\n\taxes: ReadonlyArray<number>;\n}\n\nexport interface GamepadOptions {\n\t/** Radial deadzone applied to stick pairs (axes 0,1 and 2,3). Value in [0, 1]. Default: 0.15. */\n\tdeadzone?: number;\n\t/**\n\t * Custom poll function returning up to 4 gamepad slots. Defaults to `navigator.getGamepads()`.\n\t * Primarily an injection point for tests; in the browser the default is correct.\n\t */\n\tpoll?: () => ReadonlyArray<GamepadLike | null>;\n}\n\nexport interface InputPluginOptions<A extends string = string, G extends string = 'input'> extends BasePluginOptions<G> {\n\t/** Initial unified action map. */\n\tactions?: ActionMap<A>;\n\t/** Initial per-player action maps, keyed by player id. */\n\tplayers?: Record<string, ActionMap<A>>;\n\t/** EventTarget to attach listeners to (default: globalThis). Pass a custom target for testability. */\n\ttarget?: EventTarget;\n\t/** Gamepad polling and deadzone configuration. */\n\tgamepad?: GamepadOptions;\n\t/**\n\t * Optional conversion from raw DOM client coordinates to the space `inputState.pointer.position` should report.\n\t * Renderer-agnostic: wire to `clientToLogical(...)` from renderer2D when using `screenScale`, or to a renderer-specific helper.\n\t * When omitted, pointer coords remain raw `clientX`/`clientY` (not canvas-relative).\n\t */\n\tcoordinateTransform?: (clientX: number, clientY: number) => { x: number; y: number };\n}\n\n// ==================== Helper Functions ====================\n\n/** Create a single action binding. Identity function that provides type inference for inline literals. */\nexport function createActionBinding(binding: ActionBinding): ActionBinding {\n\treturn binding;\n}\n\n/** Build an array of gamepad button refs scoped to one pad — `gamepadButtonsOn(0, 0, 1, 9)` = pad 0's buttons 0, 1, 9. */\nexport function gamepadButtonsOn(pad: number, ...buttons: number[]): GamepadButtonRef[] {\n\treturn buttons.map((button) => ({ pad, button }));\n}\n\n/** Build a gamepad axis ref. `threshold` defaults to 0.5 at activation time. */\nexport function gamepadAxisOn(pad: number, axis: number, direction: 1 | -1, threshold?: number): GamepadAxisRef {\n\treturn threshold === undefined ? { pad, axis, direction } : { pad, axis, direction, threshold };\n}\n\n// ==================== Internal Types ====================\n\ninterface RawKeyPointerState {\n\tkeysDown: Set<string>;\n\tkeysPressed: string[];\n\tkeysReleased: string[];\n\tpointerButtonsDown: Set<number>;\n\tpointerButtonsPressed: number[];\n\tpointerButtonsReleased: number[];\n\tpointerX: number;\n\tpointerY: number;\n\tlastPointerX: number;\n\tlastPointerY: number;\n\tpointerMoved: boolean;\n}\n\n/**\n * Stable per-frame view of keyboard + pointer input. Sets are mutated in place\n * each frame (cleared and refilled from raw), so closures over this object see\n * consistent state throughout a frame without per-frame Set allocation.\n */\ninterface FrameState {\n\tkeysDown: Set<string>;\n\tkeysPressed: Set<string>;\n\tkeysReleased: Set<string>;\n\tpointerButtonsDown: Set<number>;\n\tpointerButtonsPressed: Set<number>;\n\tpointerButtonsReleased: Set<number>;\n\tpointerX: number;\n\tpointerY: number;\n\tpointerDeltaX: number;\n\tpointerDeltaY: number;\n}\n\ninterface PadRuntime {\n\tconnected: boolean;\n\tid: string | null;\n\tbuttonsDown: Set<number>;\n\tbuttonsPrev: Set<number>;\n\tbuttonsPressed: Set<number>;\n\tbuttonsReleased: Set<number>;\n\tbuttonValues: number[];\n\taxes: number[];\n\trawAxes: number[];\n}\n\n/** Two ping-ponged Sets backing an ActionState. Each frame we swap `active` ↔ `prev`, clear the new `active`, and refill. */\ninterface ActionSlot {\n\tactive: Set<string>;\n\tprev: Set<string>;\n}\n\n// ==================== Helpers ====================\n\nconst DEFAULT_AXIS_THRESHOLD = 0.5;\nconst DEFAULT_DEADZONE = 0.15;\nconst PAD_COUNT = 4;\n\nfunction createRawKeyPointerState(): RawKeyPointerState {\n\treturn {\n\t\tkeysDown: new Set(),\n\t\tkeysPressed: [],\n\t\tkeysReleased: [],\n\t\tpointerButtonsDown: new Set(),\n\t\tpointerButtonsPressed: [],\n\t\tpointerButtonsReleased: [],\n\t\tpointerX: 0,\n\t\tpointerY: 0,\n\t\tlastPointerX: 0,\n\t\tlastPointerY: 0,\n\t\tpointerMoved: false,\n\t};\n}\n\nfunction createFrameState(): FrameState {\n\treturn {\n\t\tkeysDown: new Set(),\n\t\tkeysPressed: new Set(),\n\t\tkeysReleased: new Set(),\n\t\tpointerButtonsDown: new Set(),\n\t\tpointerButtonsPressed: new Set(),\n\t\tpointerButtonsReleased: new Set(),\n\t\tpointerX: 0,\n\t\tpointerY: 0,\n\t\tpointerDeltaX: 0,\n\t\tpointerDeltaY: 0,\n\t};\n}\n\nfunction createPadRuntime(): PadRuntime {\n\treturn {\n\t\tconnected: false,\n\t\tid: null,\n\t\tbuttonsDown: new Set(),\n\t\tbuttonsPrev: new Set(),\n\t\tbuttonsPressed: new Set(),\n\t\tbuttonsReleased: new Set(),\n\t\tbuttonValues: [],\n\t\taxes: [],\n\t\trawAxes: [],\n\t};\n}\n\nfunction createActionSlot(): ActionSlot {\n\treturn { active: new Set(), prev: new Set() };\n}\n\nfunction refillSet<T>(dest: Set<T>, source: Iterable<T>): void {\n\tdest.clear();\n\tfor (const item of source) dest.add(item);\n}\n\nfunction updateFrameStateFromRaw(frame: FrameState, raw: RawKeyPointerState): void {\n\trefillSet(frame.keysDown, raw.keysDown);\n\trefillSet(frame.keysPressed, raw.keysPressed);\n\trefillSet(frame.keysReleased, raw.keysReleased);\n\trefillSet(frame.pointerButtonsDown, raw.pointerButtonsDown);\n\trefillSet(frame.pointerButtonsPressed, raw.pointerButtonsPressed);\n\trefillSet(frame.pointerButtonsReleased, raw.pointerButtonsReleased);\n\n\tframe.pointerDeltaX = raw.pointerMoved ? raw.pointerX - raw.lastPointerX : 0;\n\tframe.pointerDeltaY = raw.pointerMoved ? raw.pointerY - raw.lastPointerY : 0;\n\tframe.pointerX = raw.pointerX;\n\tframe.pointerY = raw.pointerY;\n\n\traw.keysPressed.length = 0;\n\traw.keysReleased.length = 0;\n\traw.pointerButtonsPressed.length = 0;\n\traw.pointerButtonsReleased.length = 0;\n\traw.lastPointerX = raw.pointerX;\n\traw.lastPointerY = raw.pointerY;\n\traw.pointerMoved = false;\n}\n\nfunction defaultPoll(out: Array<GamepadLike | null>): () => ReadonlyArray<GamepadLike | null> {\n\treturn () => {\n\t\tif (typeof navigator === 'undefined' || typeof navigator.getGamepads !== 'function') {\n\t\t\tfor (let i = 0; i < out.length; i++) out[i] = null;\n\t\t\treturn out;\n\t\t}\n\t\tconst pads = navigator.getGamepads();\n\t\tfor (let i = 0; i < out.length; i++) out[i] = pads[i] ?? null;\n\t\treturn out;\n\t};\n}\n\nfunction applyStickDeadzone(x: number, y: number, deadzone: number, out: number[], baseIndex: number): void {\n\tconst mag = Math.sqrt(x * x + y * y);\n\tif (mag < deadzone) {\n\t\tout[baseIndex] = 0;\n\t\tout[baseIndex + 1] = 0;\n\t\treturn;\n\t}\n\tconst scaled = Math.min((mag - deadzone) / (1 - deadzone), 1);\n\tout[baseIndex] = (x / mag) * scaled;\n\tout[baseIndex + 1] = (y / mag) * scaled;\n}\n\nfunction applyAxisDeadzoning(rawAxes: number[], axes: number[], deadzone: number): void {\n\taxes.length = rawAxes.length;\n\tif (rawAxes.length >= 2) {\n\t\tapplyStickDeadzone(rawAxes[0] ?? 0, rawAxes[1] ?? 0, deadzone, axes, 0);\n\t}\n\tif (rawAxes.length >= 4) {\n\t\tapplyStickDeadzone(rawAxes[2] ?? 0, rawAxes[3] ?? 0, deadzone, axes, 2);\n\t}\n\t// Axes beyond the two standard sticks pass through with no deadzone (triggers, dpad-as-axis, etc.)\n\tfor (let i = 4; i < rawAxes.length; i++) {\n\t\taxes[i] = rawAxes[i] ?? 0;\n\t}\n}\n\nfunction pollGamepadsInto(pads: PadRuntime[], pollFn: () => ReadonlyArray<GamepadLike | null>, deadzone: number): void {\n\tconst polled = pollFn();\n\tfor (let i = 0; i < PAD_COUNT; i++) {\n\t\tconst pad = polled[i] ?? null;\n\t\tconst state = pads[i];\n\t\tif (!state) continue;\n\n\t\t// Rotate button sets using the existing `prev` set as scratch, then clear what we'll refill.\n\t\tconst reusedPrev = state.buttonsPrev;\n\t\trefillSet(reusedPrev, state.buttonsDown);\n\t\tstate.buttonsDown.clear();\n\t\tstate.buttonsPressed.clear();\n\t\tstate.buttonsReleased.clear();\n\n\t\tif (!pad || !pad.connected) {\n\t\t\tif (state.connected) {\n\t\t\t\t// Newly disconnected: synthesize justReleased for anything that was held, then clear values.\n\t\t\t\tfor (const b of reusedPrev) state.buttonsReleased.add(b);\n\t\t\t\tstate.connected = false;\n\t\t\t\tstate.id = null;\n\t\t\t\tstate.buttonValues.length = 0;\n\t\t\t\tstate.axes.length = 0;\n\t\t\t\tstate.rawAxes.length = 0;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tstate.connected = true;\n\t\tstate.id = pad.id;\n\n\t\tstate.buttonValues.length = pad.buttons.length;\n\t\tfor (let b = 0; b < pad.buttons.length; b++) {\n\t\t\tconst info = pad.buttons[b];\n\t\t\tif (!info) {\n\t\t\t\tstate.buttonValues[b] = 0;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tstate.buttonValues[b] = info.value;\n\t\t\tif (info.pressed) state.buttonsDown.add(b);\n\t\t}\n\n\t\tfor (const b of state.buttonsDown) {\n\t\t\tif (!reusedPrev.has(b)) state.buttonsPressed.add(b);\n\t\t}\n\t\tfor (const b of reusedPrev) {\n\t\t\tif (!state.buttonsDown.has(b)) state.buttonsReleased.add(b);\n\t\t}\n\n\t\tstate.rawAxes.length = pad.axes.length;\n\t\tfor (let a = 0; a < pad.axes.length; a++) {\n\t\t\tstate.rawAxes[a] = pad.axes[a] ?? 0;\n\t\t}\n\t\tapplyAxisDeadzoning(state.rawAxes, state.axes, deadzone);\n\t}\n}\n\nfunction isBindingActive(\n\tbinding: ActionBinding,\n\tkeysDown: ReadonlySet<string>,\n\tpointerButtonsDown: ReadonlySet<number>,\n\tpads: ReadonlyArray<PadRuntime>,\n): boolean {\n\tif (binding.keys?.some((k) => keysDown.has(k))) return true;\n\tif (binding.pointerButtons?.some((b) => pointerButtonsDown.has(b))) return true;\n\tif (binding.gamepadButtons?.some(({ pad, button }) => pads[pad]?.buttonsDown.has(button) ?? false)) return true;\n\tif (binding.gamepadAxes?.some(({ pad, axis, direction, threshold = DEFAULT_AXIS_THRESHOLD }) => {\n\t\tconst value = pads[pad]?.axes[axis] ?? 0;\n\t\treturn direction > 0 ? value > threshold : value < -threshold;\n\t})) return true;\n\treturn false;\n}\n\n/**\n * Recompute the slot's `active` set in place from `map` against current input sources.\n * Rotates `active` ↔ `prev` (reusing Set instances) so edge detection works with no allocations.\n */\nfunction advanceActionSlot(\n\tslot: ActionSlot,\n\tmap: ActionMap,\n\tkeysDown: ReadonlySet<string>,\n\tpointerButtonsDown: ReadonlySet<number>,\n\tpads: ReadonlyArray<PadRuntime>,\n): void {\n\tconst nextActive = slot.prev;\n\tslot.prev = slot.active;\n\tslot.active = nextActive;\n\tnextActive.clear();\n\n\tfor (const [name, binding] of Object.entries(map)) {\n\t\tif (isBindingActive(binding, keysDown, pointerButtonsDown, pads)) nextActive.add(name);\n\t}\n}\n\nfunction makeActionState<A extends string>(slot: ActionSlot): ActionState<A> {\n\treturn {\n\t\tisActive: (action) => slot.active.has(action),\n\t\tjustActivated: (action) => slot.active.has(action) && !slot.prev.has(action),\n\t\tjustDeactivated: (action) => !slot.active.has(action) && slot.prev.has(action),\n\t};\n}\n\n// ==================== Plugin Factory ====================\n\n/**\n * Create an input plugin for ECSpresso.\n *\n * Provides:\n * - Frame-accurate keyboard state (isDown, justPressed, justReleased)\n * - Pointer position/delta and button state (mouse + touch via PointerEvent)\n * - Up to 4 gamepads polled per frame, with radial deadzone on sticks and analog button values\n * - Unified action mapping (keyboard + pointer + any pad)\n * - Per-player action maps for local co-op (`definePlayer`, `player(id)`)\n * - Automatic listener cleanup on detach\n *\n * @example\n * ```typescript\n * const ecs = ECSpresso.create()\n * .withPlugin(createInputPlugin({\n * actions: {\n * jump: { keys: [' ', 'ArrowUp'], gamepadButtons: [{ pad: 0, button: 0 }] },\n * shoot: { keys: ['z'], pointerButtons: [0] },\n * },\n * players: {\n * p1: { jump: { keys: [' '] }, shoot: { keys: ['z'] } },\n * p2: {\n * jump: { gamepadButtons: gamepadButtonsOn(0, 0) },\n * shoot: { gamepadButtons: gamepadButtonsOn(0, 2) },\n * },\n * },\n * }))\n * .build();\n *\n * const input = ecs.getResource('inputState');\n * if (input.actions.justActivated('jump')) { ... } // any source\n * if (input.player('p1')?.actions.isActive('jump')) { ... } // just player 1\n * if (input.gamepads[0].isDown(0)) { ... } // raw pad 0 A-button\n * ```\n */\nexport function createInputPlugin<A extends string = string, G extends string = 'input'>(\n\toptions?: InputPluginOptions<A, G>\n) {\n\tconst {\n\t\tsystemGroup = 'input',\n\t\tpriority = 100,\n\t\tphase = 'preUpdate',\n\t\ttarget = globalThis,\n\t\tgamepad: gamepadOpts = {},\n\t\tcoordinateTransform,\n\t} = options ?? {};\n\n\t// Construction-time casts: option defaults of `{}` don't structurally satisfy a narrow `ActionMap<A>`,\n\t// but at this boundary we know the user either supplied a valid map or is using A = string.\n\tconst unifiedActionMap = { ...(options?.actions ?? {}) } as ActionMap<A>;\n\tconst playerMaps = new Map<string, ActionMap<A>>(\n\t\tObject.entries(options?.players ?? {}) as Array<[string, ActionMap<A>]>,\n\t);\n\n\tconst deadzone = gamepadOpts.deadzone ?? DEFAULT_DEADZONE;\n\tconst pollFn = gamepadOpts.poll ?? defaultPoll(new Array<GamepadLike | null>(PAD_COUNT).fill(null));\n\n\tconst raw = createRawKeyPointerState();\n\tconst frame = createFrameState();\n\tconst pads: PadRuntime[] = Array.from({ length: PAD_COUNT }, createPadRuntime);\n\tconst unifiedSlot = createActionSlot();\n\tconst playerSlots = new Map<string, ActionSlot>();\n\tconst playerHandles = new Map<string, PlayerInput<A>>();\n\tconst cleanupFns: Array<() => void> = [];\n\n\t// Vector2Ds exposed via the resource — updated in place each frame.\n\tconst position: Vector2D = { x: 0, y: 0 };\n\tconst delta: Vector2D = { x: 0, y: 0 };\n\n\tlet currentUnifiedMap = unifiedActionMap;\n\n\tconst keyboard: KeyboardState = {\n\t\tisDown: (key) => frame.keysDown.has(key),\n\t\tjustPressed: (key) => frame.keysPressed.has(key),\n\t\tjustReleased: (key) => frame.keysReleased.has(key),\n\t};\n\n\tconst pointer: PointerState = {\n\t\tposition,\n\t\tdelta,\n\t\tisDown: (button) => frame.pointerButtonsDown.has(button),\n\t\tjustPressed: (button) => frame.pointerButtonsPressed.has(button),\n\t\tjustReleased: (button) => frame.pointerButtonsReleased.has(button),\n\t};\n\n\tfunction makeGamepadState(index: number): GamepadState {\n\t\tconst state = pads[index];\n\t\tif (!state) throw new Error(`Invalid gamepad index: ${index}`);\n\t\treturn {\n\t\t\tget connected() { return state.connected; },\n\t\t\tget id() { return state.id; },\n\t\t\tisDown: (button) => state.buttonsDown.has(button),\n\t\t\tjustPressed: (button) => state.buttonsPressed.has(button),\n\t\t\tjustReleased: (button) => state.buttonsReleased.has(button),\n\t\t\tbuttonValue: (button) => state.buttonValues[button] ?? 0,\n\t\t\taxis: (index) => state.axes[index] ?? 0,\n\t\t\trawAxis: (index) => state.rawAxes[index] ?? 0,\n\t\t};\n\t}\n\n\tconst gamepadStates: ReadonlyArray<GamepadState> = Array.from({ length: PAD_COUNT }, (_, i) => makeGamepadState(i));\n\n\tconst unifiedActions = makeActionState<A>(unifiedSlot);\n\n\tfunction ensurePlayerSlot(id: string): ActionSlot {\n\t\tconst existing = playerSlots.get(id);\n\t\tif (existing) return existing;\n\t\tconst slot = createActionSlot();\n\t\tplayerSlots.set(id, slot);\n\t\treturn slot;\n\t}\n\n\tfunction createPlayerHandle(id: string): PlayerInput<A> {\n\t\tconst slot = ensurePlayerSlot(id);\n\t\treturn {\n\t\t\tactions: makeActionState<A>(slot),\n\t\t\tsetActionMap: (map) => {\n\t\t\t\tif (!playerMaps.has(id)) throw new Error(`Player '${id}' was removed`);\n\t\t\t\tplayerMaps.set(id, { ...map });\n\t\t\t},\n\t\t\tgetActionMap: () => {\n\t\t\t\tconst map = playerMaps.get(id);\n\t\t\t\tif (!map) throw new Error(`Player '${id}' was removed`);\n\t\t\t\treturn { ...map };\n\t\t\t},\n\t\t};\n\t}\n\n\tfor (const id of playerMaps.keys()) {\n\t\tplayerHandles.set(id, createPlayerHandle(id));\n\t}\n\n\tconst inputState: InputState<A> = {\n\t\tkeyboard,\n\t\tpointer,\n\t\tgamepads: gamepadStates,\n\t\tactions: unifiedActions,\n\t\tsetActionMap(newMap) {\n\t\t\tcurrentUnifiedMap = { ...newMap };\n\t\t},\n\t\tgetActionMap() {\n\t\t\treturn { ...currentUnifiedMap };\n\t\t},\n\t\tdefinePlayer(id, map) {\n\t\t\tplayerMaps.set(id, { ...map });\n\t\t\tif (!playerHandles.has(id)) playerHandles.set(id, createPlayerHandle(id));\n\t\t},\n\t\tremovePlayer(id) {\n\t\t\tconst existed = playerMaps.delete(id);\n\t\t\tplayerHandles.delete(id);\n\t\t\tplayerSlots.delete(id);\n\t\t\treturn existed;\n\t\t},\n\t\tplayer(id) {\n\t\t\treturn playerHandles.get(id);\n\t\t},\n\t\tplayerIds() {\n\t\t\treturn Array.from(playerMaps.keys());\n\t\t},\n\t};\n\n\tfunction onKeyDown(e: Event) {\n\t\tconst ke = e as KeyboardEvent;\n\t\tif (ke.repeat) return;\n\t\traw.keysDown.add(ke.key);\n\t\traw.keysPressed.push(ke.key);\n\t}\n\n\tfunction onKeyUp(e: Event) {\n\t\tconst ke = e as KeyboardEvent;\n\t\traw.keysDown.delete(ke.key);\n\t\traw.keysReleased.push(ke.key);\n\t}\n\n\tfunction onPointerDown(e: Event) {\n\t\tconst pe = e as PointerEvent;\n\t\traw.pointerButtonsDown.add(pe.button);\n\t\traw.pointerButtonsPressed.push(pe.button);\n\t}\n\n\tfunction onPointerMove(e: Event) {\n\t\tconst pe = e as PointerEvent;\n\t\tif (coordinateTransform) {\n\t\t\tconst { x, y } = coordinateTransform(pe.clientX, pe.clientY);\n\t\t\traw.pointerX = x;\n\t\t\traw.pointerY = y;\n\t\t} else {\n\t\t\traw.pointerX = pe.clientX;\n\t\t\traw.pointerY = pe.clientY;\n\t\t}\n\t\traw.pointerMoved = true;\n\t}\n\n\tfunction onPointerUp(e: Event) {\n\t\tconst pe = e as PointerEvent;\n\t\traw.pointerButtonsDown.delete(pe.button);\n\t\traw.pointerButtonsReleased.push(pe.button);\n\t}\n\n\tfunction addListener(type: string, handler: (e: Event) => void) {\n\t\ttarget.addEventListener(type, handler);\n\t\tcleanupFns.push(() => { target.removeEventListener(type, handler); });\n\t}\n\n\treturn definePlugin('input')\n\t\t.withResourceTypes<InputResourceTypes<A>>()\n\t\t.withLabels<'input-state'>()\n\t\t.withGroups<G>()\n\t\t.install((world) => {\n\t\t\tworld.addResource('inputState', inputState);\n\n\t\t\tworld\n\t\t\t\t.addSystem('input-state')\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(() => {\n\t\t\t\t\taddListener('keydown', onKeyDown);\n\t\t\t\t\taddListener('keyup', onKeyUp);\n\t\t\t\t\taddListener('pointerdown', onPointerDown);\n\t\t\t\t\taddListener('pointermove', onPointerMove);\n\t\t\t\t\taddListener('pointerup', onPointerUp);\n\t\t\t\t})\n\t\t\t\t.setOnDetach(() => {\n\t\t\t\t\tfor (const cleanup of cleanupFns) cleanup();\n\t\t\t\t\tcleanupFns.length = 0;\n\t\t\t\t})\n\t\t\t\t.setProcess(() => {\n\t\t\t\t\t// Pads must be polled before action computation so a single frame reflects\n\t\t\t\t\t// both DOM-driven (keyboard/pointer) and polled (gamepad) sources consistently.\n\t\t\t\t\tpollGamepadsInto(pads, pollFn, deadzone);\n\t\t\t\t\tupdateFrameStateFromRaw(frame, raw);\n\n\t\t\t\t\tposition.x = frame.pointerX;\n\t\t\t\t\tposition.y = frame.pointerY;\n\t\t\t\t\tdelta.x = frame.pointerDeltaX;\n\t\t\t\t\tdelta.y = frame.pointerDeltaY;\n\n\t\t\t\t\tadvanceActionSlot(unifiedSlot, currentUnifiedMap, frame.keysDown, frame.pointerButtonsDown, pads);\n\t\t\t\t\tfor (const [id, map] of playerMaps) {\n\t\t\t\t\t\tconst slot = ensurePlayerSlot(id);\n\t\t\t\t\t\tadvanceActionSlot(slot, map, frame.keysDown, frame.pointerButtonsDown, pads);\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": "A22CC6420E47F29C64756E2164756E21",
7
+ "mappings": "4PAeA,uBAAS,kBAoQF,SAAS,EAAmB,CAAC,EAAuC,CAC1E,OAAO,EAID,SAAS,EAAgB,CAAC,KAAgB,EAAuC,CACvF,OAAO,EAAQ,IAAI,CAAC,KAAY,CAAE,MAAK,QAAO,EAAE,EAI1C,SAAS,EAAa,CAAC,EAAa,EAAc,EAAmB,EAAoC,CAC/G,OAAO,IAAc,OAAY,CAAE,MAAK,OAAM,WAAU,EAAI,CAAE,MAAK,OAAM,YAAW,WAAU,EAyD/F,IAAM,EAAyB,IACzB,EAAmB,KACnB,EAAY,EAElB,SAAS,CAAwB,EAAuB,CACvD,MAAO,CACN,SAAU,IAAI,IACd,YAAa,CAAC,EACd,aAAc,CAAC,EACf,mBAAoB,IAAI,IACxB,sBAAuB,CAAC,EACxB,uBAAwB,CAAC,EACzB,SAAU,EACV,SAAU,EACV,aAAc,EACd,aAAc,EACd,aAAc,EACf,EAGD,SAAS,CAAgB,EAAe,CACvC,MAAO,CACN,SAAU,IAAI,IACd,YAAa,IAAI,IACjB,aAAc,IAAI,IAClB,mBAAoB,IAAI,IACxB,sBAAuB,IAAI,IAC3B,uBAAwB,IAAI,IAC5B,SAAU,EACV,SAAU,EACV,cAAe,EACf,cAAe,CAChB,EAGD,SAAS,CAAgB,EAAe,CACvC,MAAO,CACN,UAAW,GACX,GAAI,KACJ,YAAa,IAAI,IACjB,YAAa,IAAI,IACjB,eAAgB,IAAI,IACpB,gBAAiB,IAAI,IACrB,aAAc,CAAC,EACf,KAAM,CAAC,EACP,QAAS,CAAC,CACX,EAGD,SAAS,CAAgB,EAAe,CACvC,MAAO,CAAE,OAAQ,IAAI,IAAO,KAAM,IAAI,GAAM,EAG7C,SAAS,CAAY,CAAC,EAAc,EAA2B,CAC9D,EAAK,MAAM,EACX,QAAW,KAAQ,EAAQ,EAAK,IAAI,CAAI,EAGzC,SAAS,CAAuB,CAAC,EAAmB,EAA+B,CAClF,EAAU,EAAM,SAAU,EAAI,QAAQ,EACtC,EAAU,EAAM,YAAa,EAAI,WAAW,EAC5C,EAAU,EAAM,aAAc,EAAI,YAAY,EAC9C,EAAU,EAAM,mBAAoB,EAAI,kBAAkB,EAC1D,EAAU,EAAM,sBAAuB,EAAI,qBAAqB,EAChE,EAAU,EAAM,uBAAwB,EAAI,sBAAsB,EAElE,EAAM,cAAgB,EAAI,aAAe,EAAI,SAAW,EAAI,aAAe,EAC3E,EAAM,cAAgB,EAAI,aAAe,EAAI,SAAW,EAAI,aAAe,EAC3E,EAAM,SAAW,EAAI,SACrB,EAAM,SAAW,EAAI,SAErB,EAAI,YAAY,OAAS,EACzB,EAAI,aAAa,OAAS,EAC1B,EAAI,sBAAsB,OAAS,EACnC,EAAI,uBAAuB,OAAS,EACpC,EAAI,aAAe,EAAI,SACvB,EAAI,aAAe,EAAI,SACvB,EAAI,aAAe,GAGpB,SAAS,CAAW,CAAC,EAAyE,CAC7F,MAAO,IAAM,CACZ,GAAI,OAAO,UAAc,KAAe,OAAO,UAAU,cAAgB,WAAY,CACpF,QAAS,EAAI,EAAG,EAAI,EAAI,OAAQ,IAAK,EAAI,GAAK,KAC9C,OAAO,EAER,IAAM,EAAO,UAAU,YAAY,EACnC,QAAS,EAAI,EAAG,EAAI,EAAI,OAAQ,IAAK,EAAI,GAAK,EAAK,IAAM,KACzD,OAAO,GAIT,SAAS,CAAkB,CAAC,EAAW,EAAW,EAAkB,EAAe,EAAyB,CAC3G,IAAM,EAAM,KAAK,KAAK,EAAI,EAAI,EAAI,CAAC,EACnC,GAAI,EAAM,EAAU,CACnB,EAAI,GAAa,EACjB,EAAI,EAAY,GAAK,EACrB,OAED,IAAM,EAAS,KAAK,KAAK,EAAM,IAAa,EAAI,GAAW,CAAC,EAC5D,EAAI,GAAc,EAAI,EAAO,EAC7B,EAAI,EAAY,GAAM,EAAI,EAAO,EAGlC,SAAS,CAAmB,CAAC,EAAmB,EAAgB,EAAwB,CAEvF,GADA,EAAK,OAAS,EAAQ,OAClB,EAAQ,QAAU,EACrB,EAAmB,EAAQ,IAAM,EAAG,EAAQ,IAAM,EAAG,EAAU,EAAM,CAAC,EAEvE,GAAI,EAAQ,QAAU,EACrB,EAAmB,EAAQ,IAAM,EAAG,EAAQ,IAAM,EAAG,EAAU,EAAM,CAAC,EAGvE,QAAS,EAAI,EAAG,EAAI,EAAQ,OAAQ,IACnC,EAAK,GAAK,EAAQ,IAAM,EAI1B,SAAS,EAAgB,CAAC,EAAoB,EAAiD,EAAwB,CACtH,IAAM,EAAS,EAAO,EACtB,QAAS,EAAI,EAAG,EAAI,EAAW,IAAK,CACnC,IAAM,EAAM,EAAO,IAAM,KACnB,EAAQ,EAAK,GACnB,GAAI,CAAC,EAAO,SAGZ,IAAM,EAAa,EAAM,YAMzB,GALA,EAAU,EAAY,EAAM,WAAW,EACvC,EAAM,YAAY,MAAM,EACxB,EAAM,eAAe,MAAM,EAC3B,EAAM,gBAAgB,MAAM,EAExB,CAAC,GAAO,CAAC,EAAI,UAAW,CAC3B,GAAI,EAAM,UAAW,CAEpB,QAAW,KAAK,EAAY,EAAM,gBAAgB,IAAI,CAAC,EACvD,EAAM,UAAY,GAClB,EAAM,GAAK,KACX,EAAM,aAAa,OAAS,EAC5B,EAAM,KAAK,OAAS,EACpB,EAAM,QAAQ,OAAS,EAExB,SAGD,EAAM,UAAY,GAClB,EAAM,GAAK,EAAI,GAEf,EAAM,aAAa,OAAS,EAAI,QAAQ,OACxC,QAAS,EAAI,EAAG,EAAI,EAAI,QAAQ,OAAQ,IAAK,CAC5C,IAAM,EAAO,EAAI,QAAQ,GACzB,GAAI,CAAC,EAAM,CACV,EAAM,aAAa,GAAK,EACxB,SAGD,GADA,EAAM,aAAa,GAAK,EAAK,MACzB,EAAK,QAAS,EAAM,YAAY,IAAI,CAAC,EAG1C,QAAW,KAAK,EAAM,YACrB,GAAI,CAAC,EAAW,IAAI,CAAC,EAAG,EAAM,eAAe,IAAI,CAAC,EAEnD,QAAW,KAAK,EACf,GAAI,CAAC,EAAM,YAAY,IAAI,CAAC,EAAG,EAAM,gBAAgB,IAAI,CAAC,EAG3D,EAAM,QAAQ,OAAS,EAAI,KAAK,OAChC,QAAS,EAAI,EAAG,EAAI,EAAI,KAAK,OAAQ,IACpC,EAAM,QAAQ,GAAK,EAAI,KAAK,IAAM,EAEnC,EAAoB,EAAM,QAAS,EAAM,KAAM,CAAQ,GAIzD,SAAS,EAAe,CACvB,EACA,EACA,EACA,EACU,CACV,GAAI,EAAQ,MAAM,KAAK,CAAC,IAAM,EAAS,IAAI,CAAC,CAAC,EAAG,MAAO,GACvD,GAAI,EAAQ,gBAAgB,KAAK,CAAC,IAAM,EAAmB,IAAI,CAAC,CAAC,EAAG,MAAO,GAC3E,GAAI,EAAQ,gBAAgB,KAAK,EAAG,MAAK,YAAa,EAAK,IAAM,YAAY,IAAI,CAAM,GAAK,EAAK,EAAG,MAAO,GAC3G,GAAI,EAAQ,aAAa,KAAK,EAAG,MAAK,OAAM,YAAW,YAAY,KAA6B,CAC/F,IAAM,EAAQ,EAAK,IAAM,KAAK,IAAS,EACvC,OAAO,EAAY,EAAI,EAAQ,EAAY,EAAQ,CAAC,EACpD,EAAG,MAAO,GACX,MAAO,GAOR,SAAS,CAAiB,CACzB,EACA,EACA,EACA,EACA,EACO,CACP,IAAM,EAAa,EAAK,KACxB,EAAK,KAAO,EAAK,OACjB,EAAK,OAAS,EACd,EAAW,MAAM,EAEjB,QAAY,EAAM,KAAY,OAAO,QAAQ,CAAG,EAC/C,GAAI,GAAgB,EAAS,EAAU,EAAoB,CAAI,EAAG,EAAW,IAAI,CAAI,EAIvF,SAAS,CAAiC,CAAC,EAAkC,CAC5E,MAAO,CACN,SAAU,CAAC,IAAW,EAAK,OAAO,IAAI,CAAM,EAC5C,cAAe,CAAC,IAAW,EAAK,OAAO,IAAI,CAAM,GAAK,CAAC,EAAK,KAAK,IAAI,CAAM,EAC3E,gBAAiB,CAAC,IAAW,CAAC,EAAK,OAAO,IAAI,CAAM,GAAK,EAAK,KAAK,IAAI,CAAM,CAC9E,EAwCM,SAAS,EAAwE,CACvF,EACC,CACD,IACC,cAAc,QACd,WAAW,IACX,QAAQ,YACR,SAAS,WACT,QAAS,EAAc,CAAC,EACxB,uBACG,GAAW,CAAC,EAIV,EAAmB,IAAM,GAAS,SAAW,CAAC,CAAG,EACjD,EAAa,IAAI,IACtB,OAAO,QAAQ,GAAS,SAAW,CAAC,CAAC,CACtC,EAEM,EAAW,EAAY,UAAY,EACnC,EAAS,EAAY,MAAQ,EAAgB,MAA0B,CAAS,EAAE,KAAK,IAAI,CAAC,EAE5F,EAAM,EAAyB,EAC/B,EAAQ,EAAiB,EACzB,EAAqB,MAAM,KAAK,CAAE,OAAQ,CAAU,EAAG,CAAgB,EACvE,EAAc,EAAiB,EAC/B,EAAc,IAAI,IAClB,EAAgB,IAAI,IACpB,EAAgC,CAAC,EAGjC,EAAqB,CAAE,EAAG,EAAG,EAAG,CAAE,EAClC,EAAkB,CAAE,EAAG,EAAG,EAAG,CAAE,EAEjC,EAAoB,EAElB,EAA0B,CAC/B,OAAQ,CAAC,IAAQ,EAAM,SAAS,IAAI,CAAG,EACvC,YAAa,CAAC,IAAQ,EAAM,YAAY,IAAI,CAAG,EAC/C,aAAc,CAAC,IAAQ,EAAM,aAAa,IAAI,CAAG,CAClD,EAEM,EAAwB,CAC7B,WACA,QACA,OAAQ,CAAC,IAAW,EAAM,mBAAmB,IAAI,CAAM,EACvD,YAAa,CAAC,IAAW,EAAM,sBAAsB,IAAI,CAAM,EAC/D,aAAc,CAAC,IAAW,EAAM,uBAAuB,IAAI,CAAM,CAClE,EAEA,SAAS,CAAgB,CAAC,EAA6B,CACtD,IAAM,EAAQ,EAAK,GACnB,GAAI,CAAC,EAAO,MAAU,MAAM,0BAA0B,GAAO,EAC7D,MAAO,IACF,UAAS,EAAG,CAAE,OAAO,EAAM,cAC3B,GAAE,EAAG,CAAE,OAAO,EAAM,IACxB,OAAQ,CAAC,IAAW,EAAM,YAAY,IAAI,CAAM,EAChD,YAAa,CAAC,IAAW,EAAM,eAAe,IAAI,CAAM,EACxD,aAAc,CAAC,IAAW,EAAM,gBAAgB,IAAI,CAAM,EAC1D,YAAa,CAAC,IAAW,EAAM,aAAa,IAAW,EACvD,KAAM,CAAC,IAAU,EAAM,KAAK,IAAU,EACtC,QAAS,CAAC,IAAU,EAAM,QAAQ,IAAU,CAC7C,EAGD,IAAM,EAA6C,MAAM,KAAK,CAAE,OAAQ,CAAU,EAAG,CAAC,EAAG,IAAM,EAAiB,CAAC,CAAC,EAE5G,EAAiB,EAAmB,CAAW,EAErD,SAAS,CAAgB,CAAC,EAAwB,CACjD,IAAM,EAAW,EAAY,IAAI,CAAE,EACnC,GAAI,EAAU,OAAO,EACrB,IAAM,EAAO,EAAiB,EAE9B,OADA,EAAY,IAAI,EAAI,CAAI,EACjB,EAGR,SAAS,CAAkB,CAAC,EAA4B,CACvD,IAAM,EAAO,EAAiB,CAAE,EAChC,MAAO,CACN,QAAS,EAAmB,CAAI,EAChC,aAAc,CAAC,IAAQ,CACtB,GAAI,CAAC,EAAW,IAAI,CAAE,EAAG,MAAU,MAAM,WAAW,gBAAiB,EACrE,EAAW,IAAI,EAAI,IAAK,CAAI,CAAC,GAE9B,aAAc,IAAM,CACnB,IAAM,EAAM,EAAW,IAAI,CAAE,EAC7B,GAAI,CAAC,EAAK,MAAU,MAAM,WAAW,gBAAiB,EACtD,MAAO,IAAK,CAAI,EAElB,EAGD,QAAW,KAAM,EAAW,KAAK,EAChC,EAAc,IAAI,EAAI,EAAmB,CAAE,CAAC,EAG7C,IAAM,EAA4B,CACjC,WACA,UACA,SAAU,EACV,QAAS,EACT,YAAY,CAAC,EAAQ,CACpB,EAAoB,IAAK,CAAO,GAEjC,YAAY,EAAG,CACd,MAAO,IAAK,CAAkB,GAE/B,YAAY,CAAC,EAAI,EAAK,CAErB,GADA,EAAW,IAAI,EAAI,IAAK,CAAI,CAAC,EACzB,CAAC,EAAc,IAAI,CAAE,EAAG,EAAc,IAAI,EAAI,EAAmB,CAAE,CAAC,GAEzE,YAAY,CAAC,EAAI,CAChB,IAAM,EAAU,EAAW,OAAO,CAAE,EAGpC,OAFA,EAAc,OAAO,CAAE,EACvB,EAAY,OAAO,CAAE,EACd,GAER,MAAM,CAAC,EAAI,CACV,OAAO,EAAc,IAAI,CAAE,GAE5B,SAAS,EAAG,CACX,OAAO,MAAM,KAAK,EAAW,KAAK,CAAC,EAErC,EAEA,SAAS,CAAS,CAAC,EAAU,CAC5B,IAAM,EAAK,EACX,GAAI,EAAG,OAAQ,OACf,EAAI,SAAS,IAAI,EAAG,GAAG,EACvB,EAAI,YAAY,KAAK,EAAG,GAAG,EAG5B,SAAS,CAAO,CAAC,EAAU,CAC1B,IAAM,EAAK,EACX,EAAI,SAAS,OAAO,EAAG,GAAG,EAC1B,EAAI,aAAa,KAAK,EAAG,GAAG,EAG7B,SAAS,CAAa,CAAC,EAAU,CAChC,IAAM,EAAK,EACX,EAAI,mBAAmB,IAAI,EAAG,MAAM,EACpC,EAAI,sBAAsB,KAAK,EAAG,MAAM,EAGzC,SAAS,CAAa,CAAC,EAAU,CAChC,IAAM,EAAK,EACX,GAAI,EAAqB,CACxB,IAAQ,IAAG,KAAM,EAAoB,EAAG,QAAS,EAAG,OAAO,EAC3D,EAAI,SAAW,EACf,EAAI,SAAW,EAEf,OAAI,SAAW,EAAG,QAClB,EAAI,SAAW,EAAG,QAEnB,EAAI,aAAe,GAGpB,SAAS,CAAW,CAAC,EAAU,CAC9B,IAAM,EAAK,EACX,EAAI,mBAAmB,OAAO,EAAG,MAAM,EACvC,EAAI,uBAAuB,KAAK,EAAG,MAAM,EAG1C,SAAS,CAAW,CAAC,EAAc,EAA6B,CAC/D,EAAO,iBAAiB,EAAM,CAAO,EACrC,EAAW,KAAK,IAAM,CAAE,EAAO,oBAAoB,EAAM,CAAO,EAAI,EAGrE,OAAO,EAAa,OAAO,EACzB,kBAAyC,EACzC,WAA0B,EAC1B,WAAc,EACd,QAAQ,CAAC,IAAU,CACnB,EAAM,YAAY,aAAc,CAAU,EAE1C,EACE,UAAU,aAAa,EACvB,YAAY,CAAQ,EACpB,QAAQ,CAAK,EACb,QAAQ,CAAW,EACnB,gBAAgB,IAAM,CACtB,EAAY,UAAW,CAAS,EAChC,EAAY,QAAS,CAAO,EAC5B,EAAY,cAAe,CAAa,EACxC,EAAY,cAAe,CAAa,EACxC,EAAY,YAAa,CAAW,EACpC,EACA,YAAY,IAAM,CAClB,QAAW,KAAW,EAAY,EAAQ,EAC1C,EAAW,OAAS,EACpB,EACA,WAAW,IAAM,CAGjB,GAAiB,EAAM,EAAQ,CAAQ,EACvC,EAAwB,EAAO,CAAG,EAElC,EAAS,EAAI,EAAM,SACnB,EAAS,EAAI,EAAM,SACnB,EAAM,EAAI,EAAM,cAChB,EAAM,EAAI,EAAM,cAEhB,EAAkB,EAAa,EAAmB,EAAM,SAAU,EAAM,mBAAoB,CAAI,EAChG,QAAY,EAAI,KAAQ,EAAY,CACnC,IAAM,EAAO,EAAiB,CAAE,EAChC,EAAkB,EAAM,EAAK,EAAM,SAAU,EAAM,mBAAoB,CAAI,GAE5E,EACF",
8
+ "debugId": "A6B7FF490EDEEA4864756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,4 +1,4 @@
1
- var r=Object.defineProperty;var o=(j)=>j;function s(j,I){this[j]=o.bind(null,I)}var QJ=(j,I)=>{for(var K in I)r(j,K,{get:I[K],enumerable:!0,configurable:!0,set:s.bind(I,K)})};var $J=(j,I)=>()=>(j&&(I=j(j=0)),I);var jJ=((j)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(j,{get:(I,K)=>(typeof require<"u"?require:I)[K]}):j)(function(j){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+j+'" is not supported')});import{definePlugin as a}from"ecspresso";var w={traumaDecay:1,maxOffsetX:10,maxOffsetY:10,maxRotation:0.05},u={smoothing:5,deadzoneX:0,deadzoneY:0,offsetX:0,offsetY:0};function PJ(j,I,K){let B=j-(K.x+K.shakeOffsetX),O=I-(K.y+K.shakeOffsetY),T=-(K.rotation+K.shakeRotation),E=Math.cos(T),A=Math.sin(T),y=B*E-O*A,q=B*A+O*E;return{x:y*K.zoom+K.viewportWidth/2,y:q*K.zoom+K.viewportHeight/2}}function p(j,I,K){let B=(j-K.viewportWidth/2)/K.zoom,O=(I-K.viewportHeight/2)/K.zoom,T=K.rotation+K.shakeRotation,E=Math.cos(T),A=Math.sin(T),y=B*E-O*A,q=B*A+O*E;return{x:y+K.x+K.shakeOffsetX,y:q+K.y+K.shakeOffsetY}}function t(j){return typeof j==="number"?j:j.id}function m(j){let I=j===!0?{}:j;return{trauma:0,traumaDecay:I.traumaDecay??w.traumaDecay,maxOffsetX:I.maxOffsetX??w.maxOffsetX,maxOffsetY:I.maxOffsetY??w.maxOffsetY,maxRotation:I.maxRotation??w.maxRotation}}function e(j){if(Array.isArray(j))return{minX:j[0],minY:j[1],maxX:j[2],maxY:j[3]};return{...j}}function i(j){return{smoothing:j?.smoothing??u.smoothing,deadzoneX:j?.deadzoneX??u.deadzoneX,deadzoneY:j?.deadzoneY??u.deadzoneY,offsetX:j?.offsetX??u.offsetX,offsetY:j?.offsetY??u.offsetY}}function KJ(j){let{viewportWidth:I=800,viewportHeight:K=600,initial:B,follow:O,shake:T,bounds:E,zoom:A,pan:y,systemGroup:q="camera",phase:g="postUpdate",randomFn:f=Math.random}=j??{};return a("camera").withComponentTypes().withResourceTypes().withLabels().withGroups().requires().install((k)=>{let J={x:B?.x??0,y:B?.y??0,zoom:B?.zoom??1,rotation:B?.rotation??0,shakeOffsetX:0,shakeOffsetY:0,shakeRotation:0,viewportWidth:I,viewportHeight:K,entityId:-1,follow:()=>{},unfollow:()=>{},setPosition:()=>{},setZoom:()=>{},setRotation:()=>{},setBounds:()=>{},clearBounds:()=>{},addTrauma:()=>{}};if(k.addResource("cameraState",J),k.addSystem("camera-init").inGroup(q).setOnInitialize((V)=>{let P=V.spawn({camera:{x:B?.x??0,y:B?.y??0,zoom:B?.zoom??1,rotation:B?.rotation??0}});if(O)V.addComponent(P.id,"cameraFollow",{target:-1,...i(O)});if(T)V.addComponent(P.id,"cameraShake",m(T));if(E)V.addComponent(P.id,"cameraBounds",e(E));J.entityId=P.id,J.follow=(N,$)=>{let R={target:t(N),...i($)},Q=V.getComponent(J.entityId,"cameraFollow");if(Q)Q.target=R.target,Q.smoothing=R.smoothing,Q.deadzoneX=R.deadzoneX,Q.deadzoneY=R.deadzoneY,Q.offsetX=R.offsetX,Q.offsetY=R.offsetY;else V.addComponent(J.entityId,"cameraFollow",R)},J.unfollow=()=>{if(V.getComponent(J.entityId,"cameraFollow"))V.removeComponent(J.entityId,"cameraFollow")},J.setPosition=(N,$)=>{let z=V.getComponent(J.entityId,"camera");if(!z)return;z.x=N,z.y=$},J.setZoom=(N)=>{let $=V.getComponent(J.entityId,"camera");if(!$)return;$.zoom=N},J.setRotation=(N)=>{let $=V.getComponent(J.entityId,"camera");if(!$)return;$.rotation=N},J.setBounds=(N,$,z,R)=>{let Q=V.getComponent(J.entityId,"cameraBounds");if(Q)Q.minX=N,Q.minY=$,Q.maxX=z,Q.maxY=R;else V.addComponent(J.entityId,"cameraBounds",{minX:N,minY:$,maxX:z,maxY:R})},J.clearBounds=()=>{if(V.getComponent(J.entityId,"cameraBounds"))V.removeComponent(J.entityId,"cameraBounds")},J.addTrauma=(N)=>{let $=V.getComponent(J.entityId,"cameraShake");if($)$.trauma=Math.min(1,Math.max(0,$.trauma+N));else V.addComponent(J.entityId,"cameraShake",{...m(!0),trauma:Math.min(1,Math.max(0,N))})}}),k.addSystem("camera-follow").setPriority(400).inPhase(g).inGroup(q).addQuery("cameras",{with:["camera","cameraFollow"]}).setProcess(({queries:V,dt:P,ecs:N})=>{let $=Math.min(1,P);for(let z of V.cameras){let{camera:R,cameraFollow:Q}=z.components;if(Q.target<0)continue;let U=N.getComponent(Q.target,"worldTransform");if(!U)continue;let _=U.x+Q.offsetX,G=U.y+Q.offsetY,M=_-R.x,W=G-R.y;if(Math.abs(M)>Q.deadzoneX){let Z=M>0?1:-1,D=M-Z*Q.deadzoneX,F=Math.min(1,Q.smoothing*$);R.x+=D*F}if(Math.abs(W)>Q.deadzoneY){let Z=W>0?1:-1,D=W-Z*Q.deadzoneY,F=Math.min(1,Q.smoothing*$);R.y+=D*F}}}),k.addSystem("camera-shake-update").setPriority(390).inPhase(g).inGroup(q).addQuery("shakeCameras",{with:["camera","cameraShake"]}).setProcess(({queries:V,dt:P})=>{for(let N of V.shakeCameras){let{cameraShake:$}=N.components;$.trauma=Math.max(0,$.trauma-$.traumaDecay*P)}}),k.addSystem("camera-bounds").setPriority(380).inPhase(g).inGroup(q).addQuery("boundedCameras",{with:["camera","cameraBounds"]}).setProcess(({queries:V})=>{for(let P of V.boundedCameras){let{camera:N,cameraBounds:$}=P.components,z=J.viewportWidth/(2*N.zoom),R=J.viewportHeight/(2*N.zoom),Q=$.minX+z,U=$.maxX-z,_=$.minY+R,G=$.maxY-R;if(Q>U)N.x=($.minX+$.maxX)/2;else N.x=Math.max(Q,Math.min(U,N.x));if(_>G)N.y=($.minY+$.maxY)/2;else N.y=Math.max(_,Math.min(G,N.y))}}),k.addSystem("camera-state-sync").setPriority(370).inPhase(g).inGroup(q).setProcess(({ecs:V})=>{let P=V.getComponent(J.entityId,"camera");if(!P){J.x=0,J.y=0,J.zoom=1,J.rotation=0,J.shakeOffsetX=0,J.shakeOffsetY=0,J.shakeRotation=0;return}J.x=P.x,J.y=P.y,J.zoom=P.zoom,J.rotation=P.rotation;let N=V.getComponent(J.entityId,"cameraShake");if(N&&N.trauma>0){let $=N.trauma*N.trauma;J.shakeOffsetX=N.maxOffsetX*$*(f()*2-1),J.shakeOffsetY=N.maxOffsetY*$*(f()*2-1),J.shakeRotation=N.maxRotation*$*(f()*2-1)}else J.shakeOffsetX=0,J.shakeOffsetY=0,J.shakeRotation=0}),A){let U=function(_){_.preventDefault(),$+=Math.sign(_.deltaY)},{zoomStep:V=0.1,minZoom:P=0.1,maxZoom:N=10}=A,$=0,z=!1,R,Q;k.addSystem("camera-zoom").setPriority(410).inPhase("preUpdate").inGroup(q).addQuery("cameras",{with:["camera"]}).setOnInitialize((_)=>{let G=_.tryGetResource("inputState"),M=_.tryGetResource("pixiApp");if(!G||!M){console.error("[camera] zoom requires the input plugin and renderer2D plugin. Zoom will be disabled.");return}R=M.canvas,R.addEventListener("wheel",U,{passive:!1}),Q=_.tryGetResource("isoProjection"),z=!0}).setOnDetach(()=>{if(!z||!R)return;R.removeEventListener("wheel",U)}).setProcess(({queries:_,ecs:G})=>{if(!z||$===0)return;let M=$;$=0;let[W]=_.cameras;if(!W)return;let Z=W.components.camera,D=G.tryGetResource("inputState");if(!D)return;let F=M>0?1-V:1+V,C=Math.max(P,Math.min(N,Z.zoom*Math.pow(F,Math.abs(M))));if(Q&&R){let H=R.getBoundingClientRect(),b=D.pointer.position.x-(H.left+H.width/2),v=D.pointer.position.y-(H.top+H.height/2),X=Q.tileWidth/2,Y=Q.tileHeight/2,h=(Z.x-Z.y)*X+Q.originX,L=(Z.x+Z.y)*Y+Q.originY,x=h+b/Z.zoom,S=L+v/Z.zoom;Z.zoom=C;let c=x-b/C,n=S-v/C,d=c-Q.originX,l=n-Q.originY;Z.x=d/Q.tileWidth+l/Q.tileHeight,Z.y=-d/Q.tileWidth+l/Q.tileHeight}else{let H=p(D.pointer.position.x,D.pointer.position.y,J);Z.zoom=C,Z.x=H.x-(D.pointer.position.x-J.viewportWidth/2)/C,Z.y=H.y-(D.pointer.position.y-J.viewportHeight/2)/C}})}if(y){let{speed:V,actions:P}=y,N=P?.up??"panUp",$=P?.down??"panDown",z=P?.left??"panLeft",R=P?.right??"panRight",Q=!1;k.addSystem("camera-pan").setPriority(420).inPhase("preUpdate").inGroup(q).setOnInitialize((U)=>{if(!U.tryGetResource("inputState")){console.error("[camera] pan requires the input plugin. Pan will be disabled.");return}Q=!0}).setProcess(({ecs:U,dt:_})=>{if(!Q)return;let G=U.tryGetResource("inputState");if(!G)return;let M=V/J.zoom*_,W=(G.actions.isActive(R)?1:0)-(G.actions.isActive(z)?1:0),Z=(G.actions.isActive($)?1:0)-(G.actions.isActive(N)?1:0);if(W!==0||Z!==0)J.setPosition(J.x+W*M,J.y+Z*M)})}})}import{Graphics as JJ}from"pixi.js";import{definePlugin as NJ}from"ecspresso";function _J(){return{selectable:!0}}function GJ(j){let{systemGroup:I="selection",priority:K=100,phase:B="preUpdate",clickThreshold:O=5,boxFillColor:T=65280,boxFillAlpha:E=0.15,boxStrokeColor:A=65280,boxStrokeAlpha:y=0.8,selectedTint:q=4521796,renderLayer:g}=j??{},f={color:T,alpha:E},k={color:A,width:1.5,alpha:y};return NJ("selection").withComponentTypes().withResourceTypes().withLabels().withGroups().requires().install((J)=>{J.addResource("selectionState",{dragStart:{x:0,y:0},boxEntityId:null});let V=null;J.addSystem("selection-input").setPriority(K).inPhase(B).inGroup(I).addQuery("selectables",{with:["selectable","worldTransform"]}).addQuery("currentlySelected",{with:["selected"]}).withResources(["inputState","selectionState","pixiApp"]).setOnInitialize((P)=>{let N=P.getResource("pixiApp");V=($)=>$.preventDefault(),N.canvas.addEventListener("contextmenu",V)}).setOnDetach((P)=>{if(!V)return;P.getResource("pixiApp").canvas.removeEventListener("contextmenu",V),V=null}).setProcess(({queries:P,ecs:N,resources:$})=>{let{inputState:z,selectionState:R}=$,Q=z.pointer;if(Q.justPressed(0)){if(R.boxEntityId!==null)N.commands.removeEntity(R.boxEntityId);R.dragStart.x=Q.position.x,R.dragStart.y=Q.position.y;let H=N.spawn({graphics:new JJ});if(g)N.addComponent(H.id,"renderLayer",g);R.boxEntityId=H.id}if(Q.isDown(0)&&R.boxEntityId!==null){let H=N.getComponent(R.boxEntityId,"graphics");if(!H)return;let b=R.dragStart.x,v=R.dragStart.y,X=Q.position.x,Y=Q.position.y,h=Math.min(b,X),L=Math.min(v,Y),x=Math.abs(X-b),S=Math.abs(Y-v);H.clear(),H.rect(h,L,x,S),H.fill(f),H.stroke(k)}if(!Q.justReleased(0)||R.boxEntityId===null)return;let U=R.dragStart.x,_=R.dragStart.y,G=Q.position.x,M=Q.position.y,W=Math.abs(G-U),Z=Math.abs(M-_);for(let H of P.currentlySelected)N.removeComponent(H.id,"selected");let D=W<O&&Z<O,F=N.tryGetResource("cameraState"),C=F?p(G,M,F):{x:G,y:M};if(D){let b=null,v=1/0;for(let X of P.selectables){let{worldTransform:Y}=X.components,h=Y.x-C.x,L=Y.y-C.y,x=h*h+L*L;if(x<400&&x<v)v=x,b=X.id}if(b!==null)N.addComponent(b,"selected",!0)}else{let H=F?p(U,_,F):{x:U,y:_},b=Math.min(H.x,C.x),v=Math.max(H.x,C.x),X=Math.min(H.y,C.y),Y=Math.max(H.y,C.y);for(let h of P.selectables){let{worldTransform:L}=h.components;if(L.x>=b&&L.x<=v&&L.y>=X&&L.y<=Y)N.addComponent(h.id,"selected",!0)}}N.commands.removeEntity(R.boxEntityId),R.boxEntityId=null}),J.addSystem("selection-visual").setPriority(K).inPhase("render").inGroup(I).addQuery("selectedUnits",{with:["selected","sprite"]}).setOnEntityEnter("selectedUnits",({entity:P})=>{P.components.sprite.tint=q}).addQuery("deselectedUnits",{with:["selectable","sprite"],without:["selected"]}).setOnEntityEnter("deselectedUnits",({entity:P})=>{P.components.sprite.tint=16777215})})}export{GJ as createSelectionPlugin,_J as createSelectable};
1
+ var e=((P)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(P,{get:(M,K)=>(typeof require<"u"?require:M)[K]}):P)(function(P){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+P+'" is not supported')});import{definePlugin as r}from"ecspresso";var w={traumaDecay:1,maxOffsetX:10,maxOffsetY:10,maxRotation:0.05},u={smoothing:5,deadzoneX:0,deadzoneY:0,offsetX:0,offsetY:0};function QJ(P,M,K){let U=P-(K.x+K.shakeOffsetX),O=M-(K.y+K.shakeOffsetY),T=-(K.rotation+K.shakeRotation),E=Math.cos(T),A=Math.sin(T),y=U*E-O*A,q=U*A+O*E;return{x:y*K.zoom+K.viewportWidth/2,y:q*K.zoom+K.viewportHeight/2}}function p(P,M,K){let U=(P-K.viewportWidth/2)/K.zoom,O=(M-K.viewportHeight/2)/K.zoom,T=K.rotation+K.shakeRotation,E=Math.cos(T),A=Math.sin(T),y=U*E-O*A,q=U*A+O*E;return{x:y+K.x+K.shakeOffsetX,y:q+K.y+K.shakeOffsetY}}function o(P){return typeof P==="number"?P:P.id}function m(P){let M=P===!0?{}:P;return{trauma:0,traumaDecay:M.traumaDecay??w.traumaDecay,maxOffsetX:M.maxOffsetX??w.maxOffsetX,maxOffsetY:M.maxOffsetY??w.maxOffsetY,maxRotation:M.maxRotation??w.maxRotation}}function s(P){if(Array.isArray(P))return{minX:P[0],minY:P[1],maxX:P[2],maxY:P[3]};return{...P}}function i(P){return{smoothing:P?.smoothing??u.smoothing,deadzoneX:P?.deadzoneX??u.deadzoneX,deadzoneY:P?.deadzoneY??u.deadzoneY,offsetX:P?.offsetX??u.offsetX,offsetY:P?.offsetY??u.offsetY}}function $J(P){let{viewportWidth:M=800,viewportHeight:K=600,initial:U,follow:O,shake:T,bounds:E,zoom:A,pan:y,systemGroup:q="camera",phase:g="postUpdate",randomFn:f=Math.random}=P??{};return r("camera").withComponentTypes().withResourceTypes().withLabels().withGroups().requires().install((k)=>{let J={x:U?.x??0,y:U?.y??0,zoom:U?.zoom??1,rotation:U?.rotation??0,shakeOffsetX:0,shakeOffsetY:0,shakeRotation:0,viewportWidth:M,viewportHeight:K,entityId:-1,follow:()=>{},unfollow:()=>{},setPosition:()=>{},setZoom:()=>{},setRotation:()=>{},setBounds:()=>{},clearBounds:()=>{},addTrauma:()=>{}};if(k.addResource("cameraState",J),k.addSystem("camera-init").inGroup(q).setOnInitialize((R)=>{let V=R.spawn({camera:{x:U?.x??0,y:U?.y??0,zoom:U?.zoom??1,rotation:U?.rotation??0}});if(O)R.addComponent(V.id,"cameraFollow",{target:-1,...i(O)});if(T)R.addComponent(V.id,"cameraShake",m(T));if(E)R.addComponent(V.id,"cameraBounds",s(E));J.entityId=V.id,J.follow=(N,$)=>{let j={target:o(N),...i($)},Q=R.getComponent(J.entityId,"cameraFollow");if(Q)Q.target=j.target,Q.smoothing=j.smoothing,Q.deadzoneX=j.deadzoneX,Q.deadzoneY=j.deadzoneY,Q.offsetX=j.offsetX,Q.offsetY=j.offsetY;else R.addComponent(J.entityId,"cameraFollow",j)},J.unfollow=()=>{if(R.getComponent(J.entityId,"cameraFollow"))R.removeComponent(J.entityId,"cameraFollow")},J.setPosition=(N,$)=>{let Z=R.getComponent(J.entityId,"camera");if(!Z)return;Z.x=N,Z.y=$},J.setZoom=(N)=>{let $=R.getComponent(J.entityId,"camera");if(!$)return;$.zoom=N},J.setRotation=(N)=>{let $=R.getComponent(J.entityId,"camera");if(!$)return;$.rotation=N},J.setBounds=(N,$,Z,j)=>{let Q=R.getComponent(J.entityId,"cameraBounds");if(Q)Q.minX=N,Q.minY=$,Q.maxX=Z,Q.maxY=j;else R.addComponent(J.entityId,"cameraBounds",{minX:N,minY:$,maxX:Z,maxY:j})},J.clearBounds=()=>{if(R.getComponent(J.entityId,"cameraBounds"))R.removeComponent(J.entityId,"cameraBounds")},J.addTrauma=(N)=>{let $=R.getComponent(J.entityId,"cameraShake");if($)$.trauma=Math.min(1,Math.max(0,$.trauma+N));else R.addComponent(J.entityId,"cameraShake",{...m(!0),trauma:Math.min(1,Math.max(0,N))})}}),k.addSystem("camera-follow").setPriority(400).inPhase(g).inGroup(q).addQuery("cameras",{with:["camera","cameraFollow"]}).setProcess(({queries:R,dt:V,ecs:N})=>{let $=Math.min(1,V);for(let Z of R.cameras){let{camera:j,cameraFollow:Q}=Z.components;if(Q.target<0)continue;let G=N.getComponent(Q.target,"worldTransform");if(!G)continue;let z=G.x+Q.offsetX,_=G.y+Q.offsetY,B=z-j.x,W=_-j.y;if(Math.abs(B)>Q.deadzoneX){let H=B>0?1:-1,D=B-H*Q.deadzoneX,F=Math.min(1,Q.smoothing*$);j.x+=D*F}if(Math.abs(W)>Q.deadzoneY){let H=W>0?1:-1,D=W-H*Q.deadzoneY,F=Math.min(1,Q.smoothing*$);j.y+=D*F}}}),k.addSystem("camera-shake-update").setPriority(390).inPhase(g).inGroup(q).addQuery("shakeCameras",{with:["camera","cameraShake"]}).setProcess(({queries:R,dt:V})=>{for(let N of R.shakeCameras){let{cameraShake:$}=N.components;$.trauma=Math.max(0,$.trauma-$.traumaDecay*V)}}),k.addSystem("camera-bounds").setPriority(380).inPhase(g).inGroup(q).addQuery("boundedCameras",{with:["camera","cameraBounds"]}).setProcess(({queries:R})=>{for(let V of R.boundedCameras){let{camera:N,cameraBounds:$}=V.components,Z=J.viewportWidth/(2*N.zoom),j=J.viewportHeight/(2*N.zoom),Q=$.minX+Z,G=$.maxX-Z,z=$.minY+j,_=$.maxY-j;if(Q>G)N.x=($.minX+$.maxX)/2;else N.x=Math.max(Q,Math.min(G,N.x));if(z>_)N.y=($.minY+$.maxY)/2;else N.y=Math.max(z,Math.min(_,N.y))}}),k.addSystem("camera-state-sync").setPriority(370).inPhase(g).inGroup(q).setProcess(({ecs:R})=>{let V=R.getComponent(J.entityId,"camera");if(!V){J.x=0,J.y=0,J.zoom=1,J.rotation=0,J.shakeOffsetX=0,J.shakeOffsetY=0,J.shakeRotation=0;return}J.x=V.x,J.y=V.y,J.zoom=V.zoom,J.rotation=V.rotation;let N=R.getComponent(J.entityId,"cameraShake");if(N&&N.trauma>0){let $=N.trauma*N.trauma;J.shakeOffsetX=N.maxOffsetX*$*(f()*2-1),J.shakeOffsetY=N.maxOffsetY*$*(f()*2-1),J.shakeRotation=N.maxRotation*$*(f()*2-1)}else J.shakeOffsetX=0,J.shakeOffsetY=0,J.shakeRotation=0}),A){let G=function(z){z.preventDefault(),$+=Math.sign(z.deltaY)},{zoomStep:R=0.1,minZoom:V=0.1,maxZoom:N=10}=A,$=0,Z=!1,j,Q;k.addSystem("camera-zoom").setPriority(410).inPhase("preUpdate").inGroup(q).addQuery("cameras",{with:["camera"]}).setOnInitialize((z)=>{let _=z.tryGetResource("inputState"),B=z.tryGetResource("pixiApp");if(!_||!B){console.error("[camera] zoom requires the input plugin and renderer2D plugin. Zoom will be disabled.");return}j=B.canvas,j.addEventListener("wheel",G,{passive:!1}),Q=z.tryGetResource("isoProjection"),Z=!0}).setOnDetach(()=>{if(!Z||!j)return;j.removeEventListener("wheel",G)}).setProcess(({queries:z,ecs:_})=>{if(!Z||$===0)return;let B=$;$=0;let[W]=z.cameras;if(!W)return;let H=W.components.camera,D=_.tryGetResource("inputState");if(!D)return;let F=B>0?1-R:1+R,C=Math.max(V,Math.min(N,H.zoom*Math.pow(F,Math.abs(B))));if(Q&&j){let I=j.getBoundingClientRect(),b=D.pointer.position.x-(I.left+I.width/2),v=D.pointer.position.y-(I.top+I.height/2),X=Q.tileWidth/2,Y=Q.tileHeight/2,h=(H.x-H.y)*X+Q.originX,L=(H.x+H.y)*Y+Q.originY,x=h+b/H.zoom,S=L+v/H.zoom;H.zoom=C;let c=x-b/C,n=S-v/C,d=c-Q.originX,l=n-Q.originY;H.x=d/Q.tileWidth+l/Q.tileHeight,H.y=-d/Q.tileWidth+l/Q.tileHeight}else{let I=p(D.pointer.position.x,D.pointer.position.y,J);H.zoom=C,H.x=I.x-(D.pointer.position.x-J.viewportWidth/2)/C,H.y=I.y-(D.pointer.position.y-J.viewportHeight/2)/C}})}if(y){let{speed:R,actions:V}=y,N=V?.up??"panUp",$=V?.down??"panDown",Z=V?.left??"panLeft",j=V?.right??"panRight",Q=!1;k.addSystem("camera-pan").setPriority(420).inPhase("preUpdate").inGroup(q).setOnInitialize((G)=>{if(!G.tryGetResource("inputState")){console.error("[camera] pan requires the input plugin. Pan will be disabled.");return}Q=!0}).setProcess(({ecs:G,dt:z})=>{if(!Q)return;let _=G.tryGetResource("inputState");if(!_)return;let B=R/J.zoom*z,W=(_.actions.isActive(j)?1:0)-(_.actions.isActive(Z)?1:0),H=(_.actions.isActive($)?1:0)-(_.actions.isActive(N)?1:0);if(W!==0||H!==0)J.setPosition(J.x+W*B,J.y+H*B)})}})}import{Graphics as a}from"pixi.js";import{definePlugin as t}from"ecspresso";function KJ(){return{selectable:!0}}function IJ(P){let{systemGroup:M="selection",priority:K=100,phase:U="preUpdate",clickThreshold:O=5,boxFillColor:T=65280,boxFillAlpha:E=0.15,boxStrokeColor:A=65280,boxStrokeAlpha:y=0.8,selectedTint:q=4521796,renderLayer:g}=P??{},f={color:T,alpha:E},k={color:A,width:1.5,alpha:y};return t("selection").withComponentTypes().withResourceTypes().withLabels().withGroups().requires().install((J)=>{J.addResource("selectionState",{dragStart:{x:0,y:0},boxEntityId:null});let R=null;J.addSystem("selection-input").setPriority(K).inPhase(U).inGroup(M).addQuery("selectables",{with:["selectable","worldTransform"]}).addQuery("currentlySelected",{with:["selected"]}).withResources(["inputState","selectionState","pixiApp"]).setOnInitialize((V)=>{let N=V.getResource("pixiApp");R=($)=>$.preventDefault(),N.canvas.addEventListener("contextmenu",R)}).setOnDetach((V)=>{if(!R)return;V.getResource("pixiApp").canvas.removeEventListener("contextmenu",R),R=null}).setProcess(({queries:V,ecs:N,resources:$})=>{let{inputState:Z,selectionState:j}=$,Q=Z.pointer;if(Q.justPressed(0)){if(j.boxEntityId!==null)N.commands.removeEntity(j.boxEntityId);j.dragStart.x=Q.position.x,j.dragStart.y=Q.position.y;let I=N.spawn({graphics:new a});if(g)N.addComponent(I.id,"renderLayer",g);j.boxEntityId=I.id}if(Q.isDown(0)&&j.boxEntityId!==null){let I=N.getComponent(j.boxEntityId,"graphics");if(!I)return;let b=j.dragStart.x,v=j.dragStart.y,X=Q.position.x,Y=Q.position.y,h=Math.min(b,X),L=Math.min(v,Y),x=Math.abs(X-b),S=Math.abs(Y-v);I.clear(),I.rect(h,L,x,S),I.fill(f),I.stroke(k)}if(!Q.justReleased(0)||j.boxEntityId===null)return;let G=j.dragStart.x,z=j.dragStart.y,_=Q.position.x,B=Q.position.y,W=Math.abs(_-G),H=Math.abs(B-z);for(let I of V.currentlySelected)N.removeComponent(I.id,"selected");let D=W<O&&H<O,F=N.tryGetResource("cameraState"),C=F?p(_,B,F):{x:_,y:B};if(D){let b=null,v=1/0;for(let X of V.selectables){let{worldTransform:Y}=X.components,h=Y.x-C.x,L=Y.y-C.y,x=h*h+L*L;if(x<400&&x<v)v=x,b=X.id}if(b!==null)N.addComponent(b,"selected",!0)}else{let I=F?p(G,z,F):{x:G,y:z},b=Math.min(I.x,C.x),v=Math.max(I.x,C.x),X=Math.min(I.y,C.y),Y=Math.max(I.y,C.y);for(let h of V.selectables){let{worldTransform:L}=h.components;if(L.x>=b&&L.x<=v&&L.y>=X&&L.y<=Y)N.addComponent(h.id,"selected",!0)}}N.commands.removeEntity(j.boxEntityId),j.boxEntityId=null}),J.addSystem("selection-visual").setPriority(K).inPhase("render").inGroup(M).addQuery("selectedUnits",{with:["selected","sprite"]}).setOnEntityEnter("selectedUnits",({entity:V})=>{V.components.sprite.tint=q}).addQuery("deselectedUnits",{with:["selectable","sprite"],without:["selected"]}).setOnEntityEnter("deselectedUnits",({entity:V})=>{V.components.sprite.tint=16777215})})}export{IJ as createSelectionPlugin,KJ as createSelectable};
2
2
 
3
- //# debugId=2CBA75EEC12DB4DB64756E2164756E21
3
+ //# debugId=A100A9606EA8CF3164756E2164756E21
4
4
  //# sourceMappingURL=selection.js.map
@@ -5,7 +5,7 @@
5
5
  "/**\n * Camera / Viewport Plugin for ECSpresso\n *\n * Provides a declarative camera with world/screen coordinate conversion, smooth follow,\n * trauma-based shake, bounds clamping, cursor-centered zoom, and logical viewport dimensions.\n *\n * This plugin is renderer-agnostic. PixiJS or other renderer integration (applying\n * cameraState to a container/stage transform) is the consumer's responsibility.\n *\n * Camera uses its own x/y/zoom/rotation rather than localTransform/worldTransform.\n * It reads the target entity's worldTransform for follow, but doesn't participate\n * in the transform hierarchy itself.\n */\n\nimport { definePlugin } from 'ecspresso';\nimport type { SystemPhase } from 'ecspresso';\nimport type ECSpresso from 'ecspresso';\nimport type { WorldConfigFrom } from '../../type-utils';\nimport type { TransformWorldConfig } from './transform';\n\n// ==================== Component Types ====================\n\nexport interface Camera {\n\tx: number;\n\ty: number;\n\tzoom: number;\n\trotation: number;\n}\n\nexport interface CameraFollow {\n\ttarget: number;\n\tsmoothing: number;\n\tdeadzoneX: number;\n\tdeadzoneY: number;\n\toffsetX: number;\n\toffsetY: number;\n}\n\nexport interface CameraShake {\n\ttrauma: number;\n\ttraumaDecay: number;\n\tmaxOffsetX: number;\n\tmaxOffsetY: number;\n\tmaxRotation: number;\n}\n\nexport interface CameraBounds {\n\tminX: number;\n\tminY: number;\n\tmaxX: number;\n\tmaxY: number;\n}\n\nexport interface CameraComponentTypes {\n\tcamera: Camera;\n\tcameraFollow: CameraFollow;\n\tcameraShake: CameraShake;\n\tcameraBounds: CameraBounds;\n}\n\n// ==================== Resource Types ====================\n\nexport interface FollowOptions {\n\tsmoothing?: number;\n\tdeadzoneX?: number;\n\tdeadzoneY?: number;\n\toffsetX?: number;\n\toffsetY?: number;\n}\n\nexport type EntityHandle = { id: number };\n\nexport interface CameraState {\n\t// Read-only data (synced from camera entity each frame)\n\tx: number;\n\ty: number;\n\tzoom: number;\n\trotation: number;\n\tshakeOffsetX: number;\n\tshakeOffsetY: number;\n\tshakeRotation: number;\n\tviewportWidth: number;\n\tviewportHeight: number;\n\tentityId: number;\n\n\t// Mutation methods\n\tfollow(target: number | EntityHandle, options?: FollowOptions): void;\n\tunfollow(): void;\n\tsetPosition(x: number, y: number): void;\n\tsetZoom(zoom: number): void;\n\tsetRotation(rotation: number): void;\n\tsetBounds(minX: number, minY: number, maxX: number, maxY: number): void;\n\tclearBounds(): void;\n\taddTrauma(amount: number): void;\n}\n\nexport interface CameraResourceTypes {\n\tcameraState: CameraState;\n}\n\n// ==================== Plugin Options ====================\n\nexport interface CameraPluginOptions<G extends string = 'camera'> {\n\tviewportWidth?: number;\n\tviewportHeight?: number;\n\tinitial?: {\n\t\tx?: number;\n\t\ty?: number;\n\t\tzoom?: number;\n\t\trotation?: number;\n\t};\n\tfollow?: FollowOptions;\n\tshake?: boolean | Partial<Omit<CameraShake, 'trauma'>>;\n\tbounds?:\n\t\t| { minX: number; minY: number; maxX: number; maxY: number }\n\t\t| [number, number, number, number];\n\tzoom?: {\n\t\tzoomStep?: number;\n\t\tminZoom?: number;\n\t\tmaxZoom?: number;\n\t};\n\tpan?: {\n\t\tspeed: number;\n\t\tactions?: {\n\t\t\tup?: string;\n\t\t\tdown?: string;\n\t\t\tleft?: string;\n\t\t\tright?: string;\n\t\t};\n\t};\n\tsystemGroup?: G;\n\tphase?: SystemPhase;\n\trandomFn?: () => number;\n}\n\n// ==================== Default Values ====================\n\nconst DEFAULT_SHAKE: Readonly<Omit<CameraShake, 'trauma'>> = {\n\ttraumaDecay: 1,\n\tmaxOffsetX: 10,\n\tmaxOffsetY: 10,\n\tmaxRotation: 0.05,\n};\n\nconst DEFAULT_FOLLOW: Readonly<Omit<CameraFollow, 'target'>> = {\n\tsmoothing: 5,\n\tdeadzoneX: 0,\n\tdeadzoneY: 0,\n\toffsetX: 0,\n\toffsetY: 0,\n};\n\n// ==================== Coordinate Conversion ====================\n\nexport function worldToScreen(\n\tworldX: number,\n\tworldY: number,\n\tstate: CameraState,\n): { x: number; y: number } {\n\tconst dx = worldX - (state.x + state.shakeOffsetX);\n\tconst dy = worldY - (state.y + state.shakeOffsetY);\n\n\tconst angle = -(state.rotation + state.shakeRotation);\n\tconst cos = Math.cos(angle);\n\tconst sin = Math.sin(angle);\n\tconst rx = dx * cos - dy * sin;\n\tconst ry = dx * sin + dy * cos;\n\n\treturn {\n\t\tx: rx * state.zoom + state.viewportWidth / 2,\n\t\ty: ry * state.zoom + state.viewportHeight / 2,\n\t};\n}\n\nexport function screenToWorld(\n\tscreenX: number,\n\tscreenY: number,\n\tstate: CameraState,\n): { x: number; y: number } {\n\tconst cx = (screenX - state.viewportWidth / 2) / state.zoom;\n\tconst cy = (screenY - state.viewportHeight / 2) / state.zoom;\n\n\tconst angle = state.rotation + state.shakeRotation;\n\tconst cos = Math.cos(angle);\n\tconst sin = Math.sin(angle);\n\tconst rx = cx * cos - cy * sin;\n\tconst ry = cx * sin + cy * cos;\n\n\treturn {\n\t\tx: rx + state.x + state.shakeOffsetX,\n\t\ty: ry + state.y + state.shakeOffsetY,\n\t};\n}\n\n// ==================== Internal Helpers ====================\n\nfunction resolveTarget(target: number | EntityHandle): number {\n\treturn typeof target === 'number' ? target : target.id;\n}\n\nfunction resolveShakeOptions(shake: true | Partial<Omit<CameraShake, 'trauma'>>): CameraShake {\n\tconst opts = shake === true ? {} : shake;\n\treturn {\n\t\ttrauma: 0,\n\t\ttraumaDecay: opts.traumaDecay ?? DEFAULT_SHAKE.traumaDecay,\n\t\tmaxOffsetX: opts.maxOffsetX ?? DEFAULT_SHAKE.maxOffsetX,\n\t\tmaxOffsetY: opts.maxOffsetY ?? DEFAULT_SHAKE.maxOffsetY,\n\t\tmaxRotation: opts.maxRotation ?? DEFAULT_SHAKE.maxRotation,\n\t};\n}\n\nfunction resolveBounds(\n\tbounds: { minX: number; minY: number; maxX: number; maxY: number } | [number, number, number, number],\n): CameraBounds {\n\tif (Array.isArray(bounds)) {\n\t\treturn { minX: bounds[0], minY: bounds[1], maxX: bounds[2], maxY: bounds[3] };\n\t}\n\treturn { ...bounds };\n}\n\nfunction resolveFollowOptions(options?: FollowOptions): Omit<CameraFollow, 'target'> {\n\treturn {\n\t\tsmoothing: options?.smoothing ?? DEFAULT_FOLLOW.smoothing,\n\t\tdeadzoneX: options?.deadzoneX ?? DEFAULT_FOLLOW.deadzoneX,\n\t\tdeadzoneY: options?.deadzoneY ?? DEFAULT_FOLLOW.deadzoneY,\n\t\toffsetX: options?.offsetX ?? DEFAULT_FOLLOW.offsetX,\n\t\toffsetY: options?.offsetY ?? DEFAULT_FOLLOW.offsetY,\n\t};\n}\n\n// ==================== Plugin Factory ====================\n\ntype CameraWorldConfig = WorldConfigFrom<CameraComponentTypes, {}, CameraResourceTypes>;\n\ntype CameraLabels =\n\t| 'camera-init'\n\t| 'camera-follow'\n\t| 'camera-shake-update'\n\t| 'camera-bounds'\n\t| 'camera-state-sync'\n\t| 'camera-zoom'\n\t| 'camera-pan';\n\nexport function createCameraPlugin<G extends string = 'camera'>(\n\toptions?: CameraPluginOptions<G>,\n) {\n\tconst {\n\t\tviewportWidth = 800,\n\t\tviewportHeight = 600,\n\t\tinitial,\n\t\tfollow: followConfig,\n\t\tshake: shakeConfig,\n\t\tbounds: boundsConfig,\n\t\tzoom: zoomConfig,\n\t\tpan: panConfig,\n\t\tsystemGroup = 'camera',\n\t\tphase = 'postUpdate',\n\t\trandomFn = Math.random,\n\t} = options ?? {};\n\n\treturn definePlugin('camera')\n\t\t.withComponentTypes<CameraComponentTypes>()\n\t\t.withResourceTypes<CameraResourceTypes>()\n\t\t.withLabels<CameraLabels>()\n\t\t.withGroups<G>()\n\t\t.requires<TransformWorldConfig>()\n\t\t.install((world) => {\n\t\t\t// Build mutation methods as closures over the world reference.\n\t\t\t// The cameraState resource is created immediately with placeholder methods,\n\t\t\t// then the init system populates entityId and wires up real methods.\n\n\t\t\tconst cameraState: CameraState = {\n\t\t\t\tx: initial?.x ?? 0,\n\t\t\t\ty: initial?.y ?? 0,\n\t\t\t\tzoom: initial?.zoom ?? 1,\n\t\t\t\trotation: initial?.rotation ?? 0,\n\t\t\t\tshakeOffsetX: 0,\n\t\t\t\tshakeOffsetY: 0,\n\t\t\t\tshakeRotation: 0,\n\t\t\t\tviewportWidth,\n\t\t\t\tviewportHeight,\n\t\t\t\tentityId: -1,\n\n\t\t\t\t// Mutation methods — wired up after camera entity is spawned\n\t\t\t\tfollow: () => {},\n\t\t\t\tunfollow: () => {},\n\t\t\t\tsetPosition: () => {},\n\t\t\t\tsetZoom: () => {},\n\t\t\t\tsetRotation: () => {},\n\t\t\t\tsetBounds: () => {},\n\t\t\t\tclearBounds: () => {},\n\t\t\t\taddTrauma: () => {},\n\t\t\t};\n\n\t\t\tworld.addResource('cameraState', cameraState);\n\n\t\t\t// camera-init: spawns camera entity and wires up mutation closures\n\t\t\tworld\n\t\t\t\t.addSystem('camera-init')\n\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t.setOnInitialize((ecs: ECSpresso<CameraWorldConfig & TransformWorldConfig>) => {\n\t\t\t\t\t// Spawn with required camera component\n\t\t\t\t\tconst entity = ecs.spawn({\n\t\t\t\t\t\tcamera: {\n\t\t\t\t\t\t\tx: initial?.x ?? 0,\n\t\t\t\t\t\t\ty: initial?.y ?? 0,\n\t\t\t\t\t\t\tzoom: initial?.zoom ?? 1,\n\t\t\t\t\t\t\trotation: initial?.rotation ?? 0,\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\n\t\t\t\t\t// Conditionally add optional components\n\t\t\t\t\tif (followConfig) {\n\t\t\t\t\t\tecs.addComponent(entity.id, 'cameraFollow', {\n\t\t\t\t\t\t\ttarget: -1,\n\t\t\t\t\t\t\t...resolveFollowOptions(followConfig),\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tif (shakeConfig) {\n\t\t\t\t\t\tecs.addComponent(entity.id, 'cameraShake', resolveShakeOptions(shakeConfig));\n\t\t\t\t\t}\n\n\t\t\t\t\tif (boundsConfig) {\n\t\t\t\t\t\tecs.addComponent(entity.id, 'cameraBounds', resolveBounds(boundsConfig));\n\t\t\t\t\t}\n\t\t\t\t\tcameraState.entityId = entity.id;\n\n\t\t\t\t\t// Wire up mutation methods\n\t\t\t\t\tcameraState.follow = (target: number | EntityHandle, opts?: FollowOptions) => {\n\t\t\t\t\t\tconst targetId = resolveTarget(target);\n\t\t\t\t\t\tconst followData: CameraFollow = {\n\t\t\t\t\t\t\ttarget: targetId,\n\t\t\t\t\t\t\t...resolveFollowOptions(opts),\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst existing = ecs.getComponent(cameraState.entityId, 'cameraFollow');\n\t\t\t\t\t\tif (existing) {\n\t\t\t\t\t\t\texisting.target = followData.target;\n\t\t\t\t\t\t\texisting.smoothing = followData.smoothing;\n\t\t\t\t\t\t\texisting.deadzoneX = followData.deadzoneX;\n\t\t\t\t\t\t\texisting.deadzoneY = followData.deadzoneY;\n\t\t\t\t\t\t\texisting.offsetX = followData.offsetX;\n\t\t\t\t\t\t\texisting.offsetY = followData.offsetY;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tecs.addComponent(cameraState.entityId, 'cameraFollow', followData);\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\n\t\t\t\t\tcameraState.unfollow = () => {\n\t\t\t\t\t\tconst existing = ecs.getComponent(cameraState.entityId, 'cameraFollow');\n\t\t\t\t\t\tif (existing) {\n\t\t\t\t\t\t\tecs.removeComponent(cameraState.entityId, 'cameraFollow');\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\n\t\t\t\t\tcameraState.setPosition = (x: number, y: number) => {\n\t\t\t\t\t\tconst camera = ecs.getComponent(cameraState.entityId, 'camera');\n\t\t\t\t\t\tif (!camera) return;\n\t\t\t\t\t\tcamera.x = x;\n\t\t\t\t\t\tcamera.y = y;\n\t\t\t\t\t};\n\n\t\t\t\t\tcameraState.setZoom = (zoom: number) => {\n\t\t\t\t\t\tconst camera = ecs.getComponent(cameraState.entityId, 'camera');\n\t\t\t\t\t\tif (!camera) return;\n\t\t\t\t\t\tcamera.zoom = zoom;\n\t\t\t\t\t};\n\n\t\t\t\t\tcameraState.setRotation = (rotation: number) => {\n\t\t\t\t\t\tconst camera = ecs.getComponent(cameraState.entityId, 'camera');\n\t\t\t\t\t\tif (!camera) return;\n\t\t\t\t\t\tcamera.rotation = rotation;\n\t\t\t\t\t};\n\n\t\t\t\t\tcameraState.setBounds = (minX: number, minY: number, maxX: number, maxY: number) => {\n\t\t\t\t\t\tconst existing = ecs.getComponent(cameraState.entityId, 'cameraBounds');\n\t\t\t\t\t\tif (existing) {\n\t\t\t\t\t\t\texisting.minX = minX;\n\t\t\t\t\t\t\texisting.minY = minY;\n\t\t\t\t\t\t\texisting.maxX = maxX;\n\t\t\t\t\t\t\texisting.maxY = maxY;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tecs.addComponent(cameraState.entityId, 'cameraBounds', { minX, minY, maxX, maxY });\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\n\t\t\t\t\tcameraState.clearBounds = () => {\n\t\t\t\t\t\tconst existing = ecs.getComponent(cameraState.entityId, 'cameraBounds');\n\t\t\t\t\t\tif (existing) {\n\t\t\t\t\t\t\tecs.removeComponent(cameraState.entityId, 'cameraBounds');\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\n\t\t\t\t\tcameraState.addTrauma = (amount: number) => {\n\t\t\t\t\t\tconst shake = ecs.getComponent(cameraState.entityId, 'cameraShake');\n\t\t\t\t\t\tif (shake) {\n\t\t\t\t\t\t\tshake.trauma = Math.min(1, Math.max(0, shake.trauma + amount));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tecs.addComponent(cameraState.entityId, 'cameraShake', {\n\t\t\t\t\t\t\t\t...resolveShakeOptions(true),\n\t\t\t\t\t\t\t\ttrauma: Math.min(1, Math.max(0, amount)),\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\n\t\t\t// camera-follow: priority 400 (after transform propagation at 500)\n\t\t\tworld\n\t\t\t\t.addSystem('camera-follow')\n\t\t\t\t.setPriority(400)\n\t\t\t\t.inPhase(phase)\n\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t.addQuery('cameras', {\n\t\t\t\t\twith: ['camera', 'cameraFollow'],\n\t\t\t\t})\n\t\t\t\t.setProcess(({ queries, dt, ecs }) => {\n\t\t\t\t\tconst t = Math.min(1, dt);\n\t\t\t\t\tfor (const entity of queries.cameras) {\n\t\t\t\t\t\tconst { camera, cameraFollow } = entity.components;\n\t\t\t\t\t\tif (cameraFollow.target < 0) continue;\n\n\t\t\t\t\t\tconst targetWorld = ecs.getComponent(cameraFollow.target, 'worldTransform');\n\t\t\t\t\t\tif (!targetWorld) continue;\n\n\t\t\t\t\t\tconst goalX = targetWorld.x + cameraFollow.offsetX;\n\t\t\t\t\t\tconst goalY = targetWorld.y + cameraFollow.offsetY;\n\t\t\t\t\t\tconst dx = goalX - camera.x;\n\t\t\t\t\t\tconst dy = goalY - camera.y;\n\n\t\t\t\t\t\tif (Math.abs(dx) > cameraFollow.deadzoneX) {\n\t\t\t\t\t\t\tconst sign = dx > 0 ? 1 : -1;\n\t\t\t\t\t\t\tconst excessX = dx - sign * cameraFollow.deadzoneX;\n\t\t\t\t\t\t\tconst factor = Math.min(1, cameraFollow.smoothing * t);\n\t\t\t\t\t\t\tcamera.x += excessX * factor;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (Math.abs(dy) > cameraFollow.deadzoneY) {\n\t\t\t\t\t\t\tconst sign = dy > 0 ? 1 : -1;\n\t\t\t\t\t\t\tconst excessY = dy - sign * cameraFollow.deadzoneY;\n\t\t\t\t\t\t\tconst factor = Math.min(1, cameraFollow.smoothing * t);\n\t\t\t\t\t\t\tcamera.y += excessY * factor;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t// camera-shake-update: priority 390\n\t\t\tworld\n\t\t\t\t.addSystem('camera-shake-update')\n\t\t\t\t.setPriority(390)\n\t\t\t\t.inPhase(phase)\n\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t.addQuery('shakeCameras', {\n\t\t\t\t\twith: ['camera', 'cameraShake'],\n\t\t\t\t})\n\t\t\t\t.setProcess(({ queries, dt }) => {\n\t\t\t\t\tfor (const entity of queries.shakeCameras) {\n\t\t\t\t\t\tconst { cameraShake } = entity.components;\n\t\t\t\t\t\tcameraShake.trauma = Math.max(0, cameraShake.trauma - cameraShake.traumaDecay * dt);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t// camera-bounds: priority 380\n\t\t\tworld\n\t\t\t\t.addSystem('camera-bounds')\n\t\t\t\t.setPriority(380)\n\t\t\t\t.inPhase(phase)\n\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t.addQuery('boundedCameras', {\n\t\t\t\t\twith: ['camera', 'cameraBounds'],\n\t\t\t\t})\n\t\t\t\t.setProcess(({ queries }) => {\n\t\t\t\t\tfor (const entity of queries.boundedCameras) {\n\t\t\t\t\t\tconst { camera, cameraBounds } = entity.components;\n\t\t\t\t\t\tconst halfW = cameraState.viewportWidth / (2 * camera.zoom);\n\t\t\t\t\t\tconst halfH = cameraState.viewportHeight / (2 * camera.zoom);\n\n\t\t\t\t\t\tconst effectiveMinX = cameraBounds.minX + halfW;\n\t\t\t\t\t\tconst effectiveMaxX = cameraBounds.maxX - halfW;\n\t\t\t\t\t\tconst effectiveMinY = cameraBounds.minY + halfH;\n\t\t\t\t\t\tconst effectiveMaxY = cameraBounds.maxY - halfH;\n\n\t\t\t\t\t\tif (effectiveMinX > effectiveMaxX) {\n\t\t\t\t\t\t\tcamera.x = (cameraBounds.minX + cameraBounds.maxX) / 2;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcamera.x = Math.max(effectiveMinX, Math.min(effectiveMaxX, camera.x));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (effectiveMinY > effectiveMaxY) {\n\t\t\t\t\t\t\tcamera.y = (cameraBounds.minY + cameraBounds.maxY) / 2;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcamera.y = Math.max(effectiveMinY, Math.min(effectiveMaxY, camera.y));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t// camera-state-sync: priority 370\n\t\t\tworld\n\t\t\t\t.addSystem('camera-state-sync')\n\t\t\t\t.setPriority(370)\n\t\t\t\t.inPhase(phase)\n\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t.setProcess(({ ecs }) => {\n\t\t\t\t\tconst camera = ecs.getComponent(cameraState.entityId, 'camera');\n\t\t\t\t\tif (!camera) {\n\t\t\t\t\t\tcameraState.x = 0;\n\t\t\t\t\t\tcameraState.y = 0;\n\t\t\t\t\t\tcameraState.zoom = 1;\n\t\t\t\t\t\tcameraState.rotation = 0;\n\t\t\t\t\t\tcameraState.shakeOffsetX = 0;\n\t\t\t\t\t\tcameraState.shakeOffsetY = 0;\n\t\t\t\t\t\tcameraState.shakeRotation = 0;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tcameraState.x = camera.x;\n\t\t\t\t\tcameraState.y = camera.y;\n\t\t\t\t\tcameraState.zoom = camera.zoom;\n\t\t\t\t\tcameraState.rotation = camera.rotation;\n\n\t\t\t\t\tconst shake = ecs.getComponent(cameraState.entityId, 'cameraShake');\n\t\t\t\t\tif (shake && shake.trauma > 0) {\n\t\t\t\t\t\tconst intensity = shake.trauma * shake.trauma;\n\t\t\t\t\t\tcameraState.shakeOffsetX = shake.maxOffsetX * intensity * (randomFn() * 2 - 1);\n\t\t\t\t\t\tcameraState.shakeOffsetY = shake.maxOffsetY * intensity * (randomFn() * 2 - 1);\n\t\t\t\t\t\tcameraState.shakeRotation = shake.maxRotation * intensity * (randomFn() * 2 - 1);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcameraState.shakeOffsetX = 0;\n\t\t\t\t\t\tcameraState.shakeOffsetY = 0;\n\t\t\t\t\t\tcameraState.shakeRotation = 0;\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t// camera-zoom: conditionally registered when zoom option is provided\n\t\t\tif (zoomConfig) {\n\t\t\t\tconst {\n\t\t\t\t\tzoomStep = 0.1,\n\t\t\t\t\tminZoom = 0.1,\n\t\t\t\t\tmaxZoom = 10,\n\t\t\t\t} = zoomConfig;\n\n\t\t\t\ttype ZoomInputState = { pointer: { position: { x: number; y: number } } };\n\n\t\t\t\tlet pendingSteps = 0;\n\t\t\t\tlet zoomActive = false;\n\t\t\t\tlet canvas: HTMLCanvasElement | undefined;\n\t\t\t\tlet isoState: { tileWidth: number; tileHeight: number; originX: number; originY: number } | undefined;\n\n\t\t\t\tfunction onWheel(e: WheelEvent) {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\tpendingSteps += Math.sign(e.deltaY);\n\t\t\t\t}\n\n\t\t\t\tworld\n\t\t\t\t\t.addSystem('camera-zoom')\n\t\t\t\t\t.setPriority(410)\n\t\t\t\t\t.inPhase('preUpdate')\n\t\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t\t.addQuery('cameras', {\n\t\t\t\t\t\twith: ['camera'],\n\t\t\t\t\t})\n\t\t\t\t\t.setOnInitialize((ecs) => {\n\t\t\t\t\t\t// Check for required dependencies\n\t\t\t\t\t\tconst inputState = ecs.tryGetResource<ZoomInputState>('inputState');\n\t\t\t\t\t\tconst pixiApp = ecs.tryGetResource<{ canvas: HTMLCanvasElement }>('pixiApp');\n\n\t\t\t\t\t\tif (!inputState || !pixiApp) {\n\t\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t\t'[camera] zoom requires the input plugin and renderer2D plugin. ' +\n\t\t\t\t\t\t\t\t'Zoom will be disabled.',\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcanvas = pixiApp.canvas;\n\t\t\t\t\t\tcanvas.addEventListener('wheel', onWheel as EventListener, { passive: false });\n\n\t\t\t\t\t\t// Detect isometric projection for iso-aware cursor-centered zoom\n\t\t\t\t\t\tisoState = ecs.tryGetResource<{\n\t\t\t\t\t\t\ttileWidth: number; tileHeight: number;\n\t\t\t\t\t\t\toriginX: number; originY: number;\n\t\t\t\t\t\t}>('isoProjection');\n\n\t\t\t\t\t\tzoomActive = true;\n\t\t\t\t\t})\n\t\t\t\t\t.setOnDetach(() => {\n\t\t\t\t\t\tif (!zoomActive || !canvas) return;\n\t\t\t\t\t\tcanvas.removeEventListener('wheel', onWheel as EventListener);\n\t\t\t\t\t})\n\t\t\t\t\t.setProcess(({ queries, ecs }) => {\n\t\t\t\t\t\tif (!zoomActive || pendingSteps === 0) return;\n\n\t\t\t\t\t\tconst steps = pendingSteps;\n\t\t\t\t\t\tpendingSteps = 0;\n\n\t\t\t\t\t\tconst [cameraEntity] = queries.cameras;\n\t\t\t\t\t\tif (!cameraEntity) return;\n\n\t\t\t\t\t\tconst cam = cameraEntity.components.camera;\n\t\t\t\t\t\tconst inputState = ecs.tryGetResource<ZoomInputState>('inputState');\n\t\t\t\t\t\tif (!inputState) return;\n\n\t\t\t\t\t\t// Apply zoom — proportional to number of wheel steps\n\t\t\t\t\t\tconst direction = steps > 0 ? (1 - zoomStep) : (1 + zoomStep);\n\t\t\t\t\t\tconst newZoom = Math.max(minZoom, Math.min(maxZoom, cam.zoom * Math.pow(direction, Math.abs(steps))));\n\n\t\t\t\t\t\tif (isoState && canvas) {\n\t\t\t\t\t\t\t// Iso-aware cursor-centered zoom: work in iso-screen space\n\t\t\t\t\t\t\tconst rect = canvas.getBoundingClientRect();\n\t\t\t\t\t\t\tconst screenOffX = inputState.pointer.position.x - (rect.left + rect.width / 2);\n\t\t\t\t\t\t\tconst screenOffY = inputState.pointer.position.y - (rect.top + rect.height / 2);\n\n\t\t\t\t\t\t\t// Inlined worldToIso — avoids cross-plugin import\n\t\t\t\t\t\t\tconst halfW = isoState.tileWidth / 2;\n\t\t\t\t\t\t\tconst halfH = isoState.tileHeight / 2;\n\t\t\t\t\t\t\tconst camIsoX = (cam.x - cam.y) * halfW + isoState.originX;\n\t\t\t\t\t\t\tconst camIsoY = (cam.x + cam.y) * halfH + isoState.originY;\n\t\t\t\t\t\t\tconst isoBeforeX = camIsoX + screenOffX / cam.zoom;\n\t\t\t\t\t\t\tconst isoBeforeY = camIsoY + screenOffY / cam.zoom;\n\n\t\t\t\t\t\t\tcam.zoom = newZoom;\n\n\t\t\t\t\t\t\t// New camera iso position so the same point stays under cursor\n\t\t\t\t\t\t\tconst newCamIsoX = isoBeforeX - screenOffX / newZoom;\n\t\t\t\t\t\t\tconst newCamIsoY = isoBeforeY - screenOffY / newZoom;\n\n\t\t\t\t\t\t\t// Inlined isoToWorld\n\t\t\t\t\t\t\tconst relX = newCamIsoX - isoState.originX;\n\t\t\t\t\t\t\tconst relY = newCamIsoY - isoState.originY;\n\t\t\t\t\t\t\tcam.x = relX / isoState.tileWidth + relY / isoState.tileHeight;\n\t\t\t\t\t\t\tcam.y = -relX / isoState.tileWidth + relY / isoState.tileHeight;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Pixel-space cursor-centered zoom\n\t\t\t\t\t\t\tconst worldBefore = screenToWorld(\n\t\t\t\t\t\t\t\tinputState.pointer.position.x,\n\t\t\t\t\t\t\t\tinputState.pointer.position.y,\n\t\t\t\t\t\t\t\tcameraState,\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tcam.zoom = newZoom;\n\n\t\t\t\t\t\t\tcam.x = worldBefore.x - (inputState.pointer.position.x - cameraState.viewportWidth / 2) / newZoom;\n\t\t\t\t\t\t\tcam.y = worldBefore.y - (inputState.pointer.position.y - cameraState.viewportHeight / 2) / newZoom;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t}\n\n\t\t\t// camera-pan: conditionally registered when pan option is provided\n\t\t\tif (panConfig) {\n\t\t\t\ttype PanInputState = { actions: { isActive(action: string): boolean } };\n\n\t\t\t\tconst {\n\t\t\t\t\tspeed,\n\t\t\t\t\tactions: panActions,\n\t\t\t\t} = panConfig;\n\n\t\t\t\tconst actionUp = panActions?.up ?? 'panUp';\n\t\t\t\tconst actionDown = panActions?.down ?? 'panDown';\n\t\t\t\tconst actionLeft = panActions?.left ?? 'panLeft';\n\t\t\t\tconst actionRight = panActions?.right ?? 'panRight';\n\n\t\t\t\tlet panActive = false;\n\n\t\t\t\tworld\n\t\t\t\t\t.addSystem('camera-pan')\n\t\t\t\t\t.setPriority(420)\n\t\t\t\t\t.inPhase('preUpdate')\n\t\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t\t.setOnInitialize((ecs) => {\n\t\t\t\t\t\tconst inputState = ecs.tryGetResource<PanInputState>('inputState');\n\t\t\t\t\t\tif (!inputState) {\n\t\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t\t'[camera] pan requires the input plugin. Pan will be disabled.',\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tpanActive = true;\n\t\t\t\t\t})\n\t\t\t\t\t.setProcess(({ ecs, dt }) => {\n\t\t\t\t\t\tif (!panActive) return;\n\n\t\t\t\t\t\tconst inputState = ecs.tryGetResource<PanInputState>('inputState');\n\t\t\t\t\t\tif (!inputState) return;\n\n\t\t\t\t\t\tconst delta = (speed / cameraState.zoom) * dt;\n\t\t\t\t\t\tconst dx = (inputState.actions.isActive(actionRight) ? 1 : 0)\n\t\t\t\t\t\t\t- (inputState.actions.isActive(actionLeft) ? 1 : 0);\n\t\t\t\t\t\tconst dy = (inputState.actions.isActive(actionDown) ? 1 : 0)\n\t\t\t\t\t\t\t- (inputState.actions.isActive(actionUp) ? 1 : 0);\n\n\t\t\t\t\t\tif (dx !== 0 || dy !== 0) {\n\t\t\t\t\t\t\tcameraState.setPosition(\n\t\t\t\t\t\t\t\tcameraState.x + dx * delta,\n\t\t\t\t\t\t\t\tcameraState.y + dy * delta,\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}\n\t\t});\n}\n",
6
6
  "/**\n * Selection Plugin for ECSpresso\n *\n * Provides pointer-driven entity selection via box-drag and click.\n * Entities with a `selectable` component can be selected by the user.\n * Selected entities receive a `selected` component that other systems\n * can query for.\n *\n * Requires the input plugin (for pointer state) and the renderer2D plugin\n * (for graphics rendering of the selection box).\n *\n * Camera-aware: when a `cameraState` resource is present (from the camera\n * plugin), pointer coordinates are automatically converted to world space\n * for hit-testing. The selection box overlay remains in screen space.\n */\n\nimport { Graphics } from 'pixi.js';\nimport { definePlugin, type BasePluginOptions } from 'ecspresso';\nimport type { WorldConfigFrom } from 'ecspresso';\nimport type { InputResourceTypes } from './input';\nimport type { Renderer2DComponentTypes, Renderer2DResourceTypes } from '../rendering/renderer2D';\nimport type { CameraState } from '../spatial/camera';\nimport { screenToWorld } from '../spatial/camera';\n\n// ==================== Component Types ====================\n\n/**\n * Component types provided by the selection plugin.\n */\nexport interface SelectionComponentTypes {\n\t/** Tag marking an entity as eligible for selection */\n\tselectable: true;\n\t/** Tag marking an entity as currently selected (added/removed dynamically) */\n\tselected: true;\n}\n\n// ==================== Resource Types ====================\n\n/**\n * Internal state tracking the current drag selection.\n */\nexport interface SelectionState {\n\tdragStart: { x: number; y: number };\n\tboxEntityId: number | null;\n}\n\n/**\n * Resource types provided by the selection plugin.\n */\nexport interface SelectionResourceTypes {\n\tselectionState: SelectionState;\n}\n\n// ==================== WorldConfig ====================\n\n/**\n * WorldConfig representing the selection plugin's provided types.\n */\nexport type SelectionWorldConfig = WorldConfigFrom<SelectionComponentTypes, {}, SelectionResourceTypes>;\n\n// ==================== Dependency Types ====================\n\ntype SelectionRequires = WorldConfigFrom<Renderer2DComponentTypes, {}, InputResourceTypes & Renderer2DResourceTypes>;\n\n// ==================== Plugin Options ====================\n\n/**\n * Configuration options for the selection plugin.\n */\nexport interface SelectionPluginOptions<G extends string = 'selection'> extends BasePluginOptions<G> {\n\t/** Minimum drag distance (px) to trigger box select vs click select (default: 5) */\n\tclickThreshold?: number;\n\t/** Selection box fill color (default: 0x00FF00) */\n\tboxFillColor?: number;\n\t/** Selection box fill alpha (default: 0.15) */\n\tboxFillAlpha?: number;\n\t/** Selection box stroke color (default: 0x00FF00) */\n\tboxStrokeColor?: number;\n\t/** Selection box stroke alpha (default: 0.8) */\n\tboxStrokeAlpha?: number;\n\t/** Tint applied to selected entities' sprites (default: 0x44FF44) */\n\tselectedTint?: number;\n\t/** Render layer for the selection box entity (default: undefined) */\n\trenderLayer?: string;\n}\n\n// ==================== Helper Functions ====================\n\n/**\n * Create a selectable component.\n *\n * @returns Component object suitable for spreading into spawn()\n *\n * @example\n * ```typescript\n * ecs.spawn({\n * ...createTransform(100, 200),\n * sprite,\n * ...createSelectable(),\n * });\n * ```\n */\nexport function createSelectable(): Pick<SelectionComponentTypes, 'selectable'> {\n\treturn { selectable: true };\n}\n\n// ==================== Plugin Factory ====================\n\n/**\n * Create a selection plugin for ECSpresso.\n *\n * Provides:\n * - Box-drag selection (left-click drag to select multiple entities)\n * - Click selection (left-click to select a single entity)\n * - Visual feedback (configurable sprite tint for selected entities)\n * - Selection box overlay (rendered as a PixiJS Graphics entity)\n * - Automatic camera-awareness when cameraState resource is present\n *\n * Requires the input plugin and renderer2D plugin to be installed.\n *\n * @example\n * ```typescript\n * const ecs = ECSpresso.create()\n * .withPlugin(createRenderer2DPlugin({ renderLayers: ['game', 'ui'] }))\n * .withPlugin(createInputPlugin())\n * .withPlugin(createSelectionPlugin({ renderLayer: 'ui' }))\n * .build();\n *\n * await ecs.initialize();\n *\n * ecs.spawn({\n * sprite,\n * ...createTransform(100, 200),\n * ...createSelectable(),\n * });\n * ```\n */\nexport function createSelectionPlugin<G extends string = 'selection'>(\n\toptions?: SelectionPluginOptions<G>\n) {\n\tconst {\n\t\tsystemGroup = 'selection',\n\t\tpriority = 100,\n\t\tphase = 'preUpdate',\n\t\tclickThreshold = 5,\n\t\tboxFillColor = 0x00FF00,\n\t\tboxFillAlpha = 0.15,\n\t\tboxStrokeColor = 0x00FF00,\n\t\tboxStrokeAlpha = 0.8,\n\t\tselectedTint = 0x44FF44,\n\t\trenderLayer,\n\t} = options ?? {};\n\n\t// Pre-allocate draw options to avoid per-frame allocations during drag\n\tconst fillOptions = { color: boxFillColor, alpha: boxFillAlpha };\n\tconst strokeOptions = { color: boxStrokeColor, width: 1.5, alpha: boxStrokeAlpha };\n\n\treturn definePlugin('selection')\n\t\t.withComponentTypes<SelectionComponentTypes>()\n\t\t.withResourceTypes<SelectionResourceTypes>()\n\t\t.withLabels<'selection-input' | 'selection-visual'>()\n\t\t.withGroups<G>()\n\t\t.requires<SelectionRequires>()\n\t\t.install((world) => {\n\t\t\tworld.addResource('selectionState', {\n\t\t\t\tdragStart: { x: 0, y: 0 },\n\t\t\t\tboxEntityId: null,\n\t\t\t});\n\n\t\t\tlet preventContextMenu: ((e: Event) => void) | null = null;\n\n\t\t\tworld\n\t\t\t\t.addSystem('selection-input')\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('selectables', {\n\t\t\t\t\twith: ['selectable', 'worldTransform'],\n\t\t\t\t})\n\t\t\t\t.addQuery('currentlySelected', {\n\t\t\t\t\twith: ['selected'],\n\t\t\t\t})\n\t\t\t\t.withResources(['inputState', 'selectionState', 'pixiApp'])\n\t\t\t\t.setOnInitialize((ecs) => {\n\t\t\t\t\tconst pixiApp = ecs.getResource('pixiApp');\n\t\t\t\t\tpreventContextMenu = (e: Event) => e.preventDefault();\n\t\t\t\t\tpixiApp.canvas.addEventListener('contextmenu', preventContextMenu);\n\t\t\t\t})\n\t\t\t\t.setOnDetach((ecs) => {\n\t\t\t\t\tif (!preventContextMenu) return;\n\t\t\t\t\tconst pixiApp = ecs.getResource('pixiApp');\n\t\t\t\t\tpixiApp.canvas.removeEventListener('contextmenu', preventContextMenu);\n\t\t\t\t\tpreventContextMenu = null;\n\t\t\t\t})\n\t\t\t\t.setProcess(({ queries, ecs, resources }) => {\n\t\t\t\t\tconst { inputState: input, selectionState } = resources;\n\t\t\t\t\tconst pointer = input.pointer;\n\n\t\t\t\t\t// Start drag\n\t\t\t\t\tif (pointer.justPressed(0)) {\n\t\t\t\t\t\t// Clean up any orphaned box entity from an interrupted drag\n\t\t\t\t\t\tif (selectionState.boxEntityId !== null) {\n\t\t\t\t\t\t\tecs.commands.removeEntity(selectionState.boxEntityId);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tselectionState.dragStart.x = pointer.position.x;\n\t\t\t\t\t\tselectionState.dragStart.y = pointer.position.y;\n\n\t\t\t\t\t\tconst boxEntity = ecs.spawn({\n\t\t\t\t\t\t\tgraphics: new Graphics(),\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (renderLayer) {\n\t\t\t\t\t\t\tecs.addComponent(boxEntity.id, 'renderLayer', renderLayer);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tselectionState.boxEntityId = boxEntity.id;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Update drag visual (screen-space — no camera conversion)\n\t\t\t\t\tif (pointer.isDown(0) && selectionState.boxEntityId !== null) {\n\t\t\t\t\t\tconst g = ecs.getComponent(selectionState.boxEntityId, 'graphics');\n\t\t\t\t\t\tif (!g) return;\n\n\t\t\t\t\t\tconst startX = selectionState.dragStart.x;\n\t\t\t\t\t\tconst startY = selectionState.dragStart.y;\n\t\t\t\t\t\tconst curX = pointer.position.x;\n\t\t\t\t\t\tconst curY = pointer.position.y;\n\t\t\t\t\t\tconst minX = Math.min(startX, curX);\n\t\t\t\t\t\tconst minY = Math.min(startY, curY);\n\t\t\t\t\t\tconst w = Math.abs(curX - startX);\n\t\t\t\t\t\tconst h = Math.abs(curY - startY);\n\n\t\t\t\t\t\tg.clear();\n\t\t\t\t\t\tg.rect(minX, minY, w, h);\n\t\t\t\t\t\tg.fill(fillOptions);\n\t\t\t\t\t\tg.stroke(strokeOptions);\n\t\t\t\t\t}\n\n\t\t\t\t\t// End drag — perform selection\n\t\t\t\t\tif (!pointer.justReleased(0) || selectionState.boxEntityId === null) return;\n\n\t\t\t\t\tconst startX = selectionState.dragStart.x;\n\t\t\t\t\tconst startY = selectionState.dragStart.y;\n\t\t\t\t\tconst endX = pointer.position.x;\n\t\t\t\t\tconst endY = pointer.position.y;\n\n\t\t\t\t\tconst w = Math.abs(endX - startX);\n\t\t\t\t\tconst h = Math.abs(endY - startY);\n\n\t\t\t\t\t// Clear current selection\n\t\t\t\t\tfor (const entity of queries.currentlySelected) {\n\t\t\t\t\t\tecs.removeComponent(entity.id, 'selected');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst isClick = w < clickThreshold && h < clickThreshold;\n\n\t\t\t\t\t// Convert screen coords to world space for hit-testing\n\t\t\t\t\tconst camState = ecs.tryGetResource('cameraState') as CameraState | undefined;\n\t\t\t\t\tconst worldEnd = camState\n\t\t\t\t\t\t? screenToWorld(endX, endY, camState)\n\t\t\t\t\t\t: { x: endX, y: endY };\n\n\t\t\t\t\tif (isClick) {\n\t\t\t\t\t\tconst clickRadiusSq = 400; // 20px radius in world space\n\t\t\t\t\t\tlet nearestId: number | null = null;\n\t\t\t\t\t\tlet nearestDistSq = Infinity;\n\n\t\t\t\t\t\tfor (const entity of queries.selectables) {\n\t\t\t\t\t\t\tconst { worldTransform } = entity.components;\n\t\t\t\t\t\t\tconst dx = worldTransform.x - worldEnd.x;\n\t\t\t\t\t\t\tconst dy = worldTransform.y - worldEnd.y;\n\t\t\t\t\t\t\tconst distSq = dx * dx + dy * dy;\n\t\t\t\t\t\t\tif (distSq < clickRadiusSq && distSq < nearestDistSq) {\n\t\t\t\t\t\t\t\tnearestDistSq = distSq;\n\t\t\t\t\t\t\t\tnearestId = entity.id;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (nearestId !== null) {\n\t\t\t\t\t\t\tecs.addComponent(nearestId, 'selected', true);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst worldStart = camState\n\t\t\t\t\t\t\t? screenToWorld(startX, startY, camState)\n\t\t\t\t\t\t\t: { x: startX, y: startY };\n\t\t\t\t\t\tconst minWX = Math.min(worldStart.x, worldEnd.x);\n\t\t\t\t\t\tconst maxWX = Math.max(worldStart.x, worldEnd.x);\n\t\t\t\t\t\tconst minWY = Math.min(worldStart.y, worldEnd.y);\n\t\t\t\t\t\tconst maxWY = Math.max(worldStart.y, worldEnd.y);\n\n\t\t\t\t\t\tfor (const entity of queries.selectables) {\n\t\t\t\t\t\t\tconst { worldTransform } = entity.components;\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tworldTransform.x >= minWX &&\n\t\t\t\t\t\t\t\tworldTransform.x <= maxWX &&\n\t\t\t\t\t\t\t\tworldTransform.y >= minWY &&\n\t\t\t\t\t\t\t\tworldTransform.y <= maxWY\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tecs.addComponent(entity.id, 'selected', true);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tecs.commands.removeEntity(selectionState.boxEntityId);\n\t\t\t\t\tselectionState.boxEntityId = null;\n\t\t\t\t});\n\n\t\t\t// Visual feedback via enter/exit callbacks — only fires on selection change\n\t\t\tworld\n\t\t\t\t.addSystem('selection-visual')\n\t\t\t\t.setPriority(priority)\n\t\t\t\t.inPhase('render')\n\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t.addQuery('selectedUnits', {\n\t\t\t\t\twith: ['selected', 'sprite'],\n\t\t\t\t})\n\t\t\t\t.setOnEntityEnter('selectedUnits', ({ entity }) => {\n\t\t\t\t\tentity.components.sprite.tint = selectedTint;\n\t\t\t\t})\n\t\t\t\t.addQuery('deselectedUnits', {\n\t\t\t\t\twith: ['selectable', 'sprite'],\n\t\t\t\t\twithout: ['selected'],\n\t\t\t\t})\n\t\t\t\t.setOnEntityEnter('deselectedUnits', ({ entity }) => {\n\t\t\t\t\tentity.components.sprite.tint = 0xFFFFFF;\n\t\t\t\t});\n\t\t});\n}\n"
7
7
  ],
8
- "mappings": "+cAcA,uBAAS,kBA2HT,IAAM,EAAuD,CAC5D,YAAa,EACb,WAAY,GACZ,WAAY,GACZ,YAAa,IACd,EAEM,EAAyD,CAC9D,UAAW,EACX,UAAW,EACX,UAAW,EACX,QAAS,EACT,QAAS,CACV,EAIO,SAAS,EAAa,CAC5B,EACA,EACA,EAC2B,CAC3B,IAAM,EAAK,GAAU,EAAM,EAAI,EAAM,cAC/B,EAAK,GAAU,EAAM,EAAI,EAAM,cAE/B,EAAQ,EAAE,EAAM,SAAW,EAAM,eACjC,EAAM,KAAK,IAAI,CAAK,EACpB,EAAM,KAAK,IAAI,CAAK,EACpB,EAAK,EAAK,EAAM,EAAK,EACrB,EAAK,EAAK,EAAM,EAAK,EAE3B,MAAO,CACN,EAAG,EAAK,EAAM,KAAO,EAAM,cAAgB,EAC3C,EAAG,EAAK,EAAM,KAAO,EAAM,eAAiB,CAC7C,EAGM,SAAS,CAAa,CAC5B,EACA,EACA,EAC2B,CAC3B,IAAM,GAAM,EAAU,EAAM,cAAgB,GAAK,EAAM,KACjD,GAAM,EAAU,EAAM,eAAiB,GAAK,EAAM,KAElD,EAAQ,EAAM,SAAW,EAAM,cAC/B,EAAM,KAAK,IAAI,CAAK,EACpB,EAAM,KAAK,IAAI,CAAK,EACpB,EAAK,EAAK,EAAM,EAAK,EACrB,EAAK,EAAK,EAAM,EAAK,EAE3B,MAAO,CACN,EAAG,EAAK,EAAM,EAAI,EAAM,aACxB,EAAG,EAAK,EAAM,EAAI,EAAM,YACzB,EAKD,SAAS,CAAa,CAAC,EAAuC,CAC7D,OAAO,OAAO,IAAW,SAAW,EAAS,EAAO,GAGrD,SAAS,CAAmB,CAAC,EAAiE,CAC7F,IAAM,EAAO,IAAU,GAAO,CAAC,EAAI,EACnC,MAAO,CACN,OAAQ,EACR,YAAa,EAAK,aAAe,EAAc,YAC/C,WAAY,EAAK,YAAc,EAAc,WAC7C,WAAY,EAAK,YAAc,EAAc,WAC7C,YAAa,EAAK,aAAe,EAAc,WAChD,EAGD,SAAS,CAAa,CACrB,EACe,CACf,GAAI,MAAM,QAAQ,CAAM,EACvB,MAAO,CAAE,KAAM,EAAO,GAAI,KAAM,EAAO,GAAI,KAAM,EAAO,GAAI,KAAM,EAAO,EAAG,EAE7E,MAAO,IAAK,CAAO,EAGpB,SAAS,CAAoB,CAAC,EAAuD,CACpF,MAAO,CACN,UAAW,GAAS,WAAa,EAAe,UAChD,UAAW,GAAS,WAAa,EAAe,UAChD,UAAW,GAAS,WAAa,EAAe,UAChD,QAAS,GAAS,SAAW,EAAe,QAC5C,QAAS,GAAS,SAAW,EAAe,OAC7C,EAgBM,SAAS,EAA+C,CAC9D,EACC,CACD,IACC,gBAAgB,IAChB,iBAAiB,IACjB,UACA,OAAQ,EACR,MAAO,EACP,OAAQ,EACR,KAAM,EACN,IAAK,EACL,cAAc,SACd,QAAQ,aACR,WAAW,KAAK,QACb,GAAW,CAAC,EAEhB,OAAO,EAAa,QAAQ,EAC1B,mBAAyC,EACzC,kBAAuC,EACvC,WAAyB,EACzB,WAAc,EACd,SAA+B,EAC/B,QAAQ,CAAC,IAAU,CAKnB,IAAM,EAA2B,CAChC,EAAG,GAAS,GAAK,EACjB,EAAG,GAAS,GAAK,EACjB,KAAM,GAAS,MAAQ,EACvB,SAAU,GAAS,UAAY,EAC/B,aAAc,EACd,aAAc,EACd,cAAe,EACf,gBACA,iBACA,SAAU,GAGV,OAAQ,IAAM,GACd,SAAU,IAAM,GAChB,YAAa,IAAM,GACnB,QAAS,IAAM,GACf,YAAa,IAAM,GACnB,UAAW,IAAM,GACjB,YAAa,IAAM,GACnB,UAAW,IAAM,EAClB,EAgPA,GA9OA,EAAM,YAAY,cAAe,CAAW,EAG5C,EACE,UAAU,aAAa,EACvB,QAAQ,CAAW,EACnB,gBAAgB,CAAC,IAA6D,CAE9E,IAAM,EAAS,EAAI,MAAM,CACxB,OAAQ,CACP,EAAG,GAAS,GAAK,EACjB,EAAG,GAAS,GAAK,EACjB,KAAM,GAAS,MAAQ,EACvB,SAAU,GAAS,UAAY,CAChC,CACD,CAAC,EAGD,GAAI,EACH,EAAI,aAAa,EAAO,GAAI,eAAgB,CAC3C,OAAQ,MACL,EAAqB,CAAY,CACrC,CAAC,EAGF,GAAI,EACH,EAAI,aAAa,EAAO,GAAI,cAAe,EAAoB,CAAW,CAAC,EAG5E,GAAI,EACH,EAAI,aAAa,EAAO,GAAI,eAAgB,EAAc,CAAY,CAAC,EAExE,EAAY,SAAW,EAAO,GAG9B,EAAY,OAAS,CAAC,EAA+B,IAAyB,CAE7E,IAAM,EAA2B,CAChC,OAFgB,EAAc,CAAM,KAGjC,EAAqB,CAAI,CAC7B,EACM,EAAW,EAAI,aAAa,EAAY,SAAU,cAAc,EACtE,GAAI,EACH,EAAS,OAAS,EAAW,OAC7B,EAAS,UAAY,EAAW,UAChC,EAAS,UAAY,EAAW,UAChC,EAAS,UAAY,EAAW,UAChC,EAAS,QAAU,EAAW,QAC9B,EAAS,QAAU,EAAW,QAE9B,OAAI,aAAa,EAAY,SAAU,eAAgB,CAAU,GAInE,EAAY,SAAW,IAAM,CAE5B,GADiB,EAAI,aAAa,EAAY,SAAU,cAAc,EAErE,EAAI,gBAAgB,EAAY,SAAU,cAAc,GAI1D,EAAY,YAAc,CAAC,EAAW,IAAc,CACnD,IAAM,EAAS,EAAI,aAAa,EAAY,SAAU,QAAQ,EAC9D,GAAI,CAAC,EAAQ,OACb,EAAO,EAAI,EACX,EAAO,EAAI,GAGZ,EAAY,QAAU,CAAC,IAAiB,CACvC,IAAM,EAAS,EAAI,aAAa,EAAY,SAAU,QAAQ,EAC9D,GAAI,CAAC,EAAQ,OACb,EAAO,KAAO,GAGf,EAAY,YAAc,CAAC,IAAqB,CAC/C,IAAM,EAAS,EAAI,aAAa,EAAY,SAAU,QAAQ,EAC9D,GAAI,CAAC,EAAQ,OACb,EAAO,SAAW,GAGnB,EAAY,UAAY,CAAC,EAAc,EAAc,EAAc,IAAiB,CACnF,IAAM,EAAW,EAAI,aAAa,EAAY,SAAU,cAAc,EACtE,GAAI,EACH,EAAS,KAAO,EAChB,EAAS,KAAO,EAChB,EAAS,KAAO,EAChB,EAAS,KAAO,EAEhB,OAAI,aAAa,EAAY,SAAU,eAAgB,CAAE,OAAM,OAAM,OAAM,MAAK,CAAC,GAInF,EAAY,YAAc,IAAM,CAE/B,GADiB,EAAI,aAAa,EAAY,SAAU,cAAc,EAErE,EAAI,gBAAgB,EAAY,SAAU,cAAc,GAI1D,EAAY,UAAY,CAAC,IAAmB,CAC3C,IAAM,EAAQ,EAAI,aAAa,EAAY,SAAU,aAAa,EAClE,GAAI,EACH,EAAM,OAAS,KAAK,IAAI,EAAG,KAAK,IAAI,EAAG,EAAM,OAAS,CAAM,CAAC,EAE7D,OAAI,aAAa,EAAY,SAAU,cAAe,IAClD,EAAoB,EAAI,EAC3B,OAAQ,KAAK,IAAI,EAAG,KAAK,IAAI,EAAG,CAAM,CAAC,CACxC,CAAC,GAGH,EAGF,EACE,UAAU,eAAe,EACzB,YAAY,GAAG,EACf,QAAQ,CAAK,EACb,QAAQ,CAAW,EACnB,SAAS,UAAW,CACpB,KAAM,CAAC,SAAU,cAAc,CAChC,CAAC,EACA,WAAW,EAAG,UAAS,KAAI,SAAU,CACrC,IAAM,EAAI,KAAK,IAAI,EAAG,CAAE,EACxB,QAAW,KAAU,EAAQ,QAAS,CACrC,IAAQ,SAAQ,gBAAiB,EAAO,WACxC,GAAI,EAAa,OAAS,EAAG,SAE7B,IAAM,EAAc,EAAI,aAAa,EAAa,OAAQ,gBAAgB,EAC1E,GAAI,CAAC,EAAa,SAElB,IAAM,EAAQ,EAAY,EAAI,EAAa,QACrC,EAAQ,EAAY,EAAI,EAAa,QACrC,EAAK,EAAQ,EAAO,EACpB,EAAK,EAAQ,EAAO,EAE1B,GAAI,KAAK,IAAI,CAAE,EAAI,EAAa,UAAW,CAC1C,IAAM,EAAO,EAAK,EAAI,EAAI,GACpB,EAAU,EAAK,EAAO,EAAa,UACnC,EAAS,KAAK,IAAI,EAAG,EAAa,UAAY,CAAC,EACrD,EAAO,GAAK,EAAU,EAEvB,GAAI,KAAK,IAAI,CAAE,EAAI,EAAa,UAAW,CAC1C,IAAM,EAAO,EAAK,EAAI,EAAI,GACpB,EAAU,EAAK,EAAO,EAAa,UACnC,EAAS,KAAK,IAAI,EAAG,EAAa,UAAY,CAAC,EACrD,EAAO,GAAK,EAAU,IAGxB,EAGF,EACE,UAAU,qBAAqB,EAC/B,YAAY,GAAG,EACf,QAAQ,CAAK,EACb,QAAQ,CAAW,EACnB,SAAS,eAAgB,CACzB,KAAM,CAAC,SAAU,aAAa,CAC/B,CAAC,EACA,WAAW,EAAG,UAAS,QAAS,CAChC,QAAW,KAAU,EAAQ,aAAc,CAC1C,IAAQ,eAAgB,EAAO,WAC/B,EAAY,OAAS,KAAK,IAAI,EAAG,EAAY,OAAS,EAAY,YAAc,CAAE,GAEnF,EAGF,EACE,UAAU,eAAe,EACzB,YAAY,GAAG,EACf,QAAQ,CAAK,EACb,QAAQ,CAAW,EACnB,SAAS,iBAAkB,CAC3B,KAAM,CAAC,SAAU,cAAc,CAChC,CAAC,EACA,WAAW,EAAG,aAAc,CAC5B,QAAW,KAAU,EAAQ,eAAgB,CAC5C,IAAQ,SAAQ,gBAAiB,EAAO,WAClC,EAAQ,EAAY,eAAiB,EAAI,EAAO,MAChD,EAAQ,EAAY,gBAAkB,EAAI,EAAO,MAEjD,EAAgB,EAAa,KAAO,EACpC,EAAgB,EAAa,KAAO,EACpC,EAAgB,EAAa,KAAO,EACpC,EAAgB,EAAa,KAAO,EAE1C,GAAI,EAAgB,EACnB,EAAO,GAAK,EAAa,KAAO,EAAa,MAAQ,EAErD,OAAO,EAAI,KAAK,IAAI,EAAe,KAAK,IAAI,EAAe,EAAO,CAAC,CAAC,EAGrE,GAAI,EAAgB,EACnB,EAAO,GAAK,EAAa,KAAO,EAAa,MAAQ,EAErD,OAAO,EAAI,KAAK,IAAI,EAAe,KAAK,IAAI,EAAe,EAAO,CAAC,CAAC,GAGtE,EAGF,EACE,UAAU,mBAAmB,EAC7B,YAAY,GAAG,EACf,QAAQ,CAAK,EACb,QAAQ,CAAW,EACnB,WAAW,EAAG,SAAU,CACxB,IAAM,EAAS,EAAI,aAAa,EAAY,SAAU,QAAQ,EAC9D,GAAI,CAAC,EAAQ,CACZ,EAAY,EAAI,EAChB,EAAY,EAAI,EAChB,EAAY,KAAO,EACnB,EAAY,SAAW,EACvB,EAAY,aAAe,EAC3B,EAAY,aAAe,EAC3B,EAAY,cAAgB,EAC5B,OAGD,EAAY,EAAI,EAAO,EACvB,EAAY,EAAI,EAAO,EACvB,EAAY,KAAO,EAAO,KAC1B,EAAY,SAAW,EAAO,SAE9B,IAAM,EAAQ,EAAI,aAAa,EAAY,SAAU,aAAa,EAClE,GAAI,GAAS,EAAM,OAAS,EAAG,CAC9B,IAAM,EAAY,EAAM,OAAS,EAAM,OACvC,EAAY,aAAe,EAAM,WAAa,GAAa,EAAS,EAAI,EAAI,GAC5E,EAAY,aAAe,EAAM,WAAa,GAAa,EAAS,EAAI,EAAI,GAC5E,EAAY,cAAgB,EAAM,YAAc,GAAa,EAAS,EAAI,EAAI,GAE9E,OAAY,aAAe,EAC3B,EAAY,aAAe,EAC3B,EAAY,cAAgB,EAE7B,EAGE,EAAY,CAcf,IAAS,EAAT,QAAgB,CAAC,EAAe,CAC/B,EAAE,eAAe,EACjB,GAAgB,KAAK,KAAK,EAAE,MAAM,IAdlC,WAAW,IACX,UAAU,IACV,UAAU,IACP,EAIA,EAAe,EACf,EAAa,GACb,EACA,EAOJ,EACE,UAAU,aAAa,EACvB,YAAY,GAAG,EACf,QAAQ,WAAW,EACnB,QAAQ,CAAW,EACnB,SAAS,UAAW,CACpB,KAAM,CAAC,QAAQ,CAChB,CAAC,EACA,gBAAgB,CAAC,IAAQ,CAEzB,IAAM,EAAa,EAAI,eAA+B,YAAY,EAC5D,EAAU,EAAI,eAA8C,SAAS,EAE3E,GAAI,CAAC,GAAc,CAAC,EAAS,CAC5B,QAAQ,MACP,uFAED,EACA,OAGD,EAAS,EAAQ,OACjB,EAAO,iBAAiB,QAAS,EAA0B,CAAE,QAAS,EAAM,CAAC,EAG7E,EAAW,EAAI,eAGZ,eAAe,EAElB,EAAa,GACb,EACA,YAAY,IAAM,CAClB,GAAI,CAAC,GAAc,CAAC,EAAQ,OAC5B,EAAO,oBAAoB,QAAS,CAAwB,EAC5D,EACA,WAAW,EAAG,UAAS,SAAU,CACjC,GAAI,CAAC,GAAc,IAAiB,EAAG,OAEvC,IAAM,EAAQ,EACd,EAAe,EAEf,IAAO,GAAgB,EAAQ,QAC/B,GAAI,CAAC,EAAc,OAEnB,IAAM,EAAM,EAAa,WAAW,OAC9B,EAAa,EAAI,eAA+B,YAAY,EAClE,GAAI,CAAC,EAAY,OAGjB,IAAM,EAAY,EAAQ,EAAK,EAAI,EAAa,EAAI,EAC9C,EAAU,KAAK,IAAI,EAAS,KAAK,IAAI,EAAS,EAAI,KAAO,KAAK,IAAI,EAAW,KAAK,IAAI,CAAK,CAAC,CAAC,CAAC,EAEpG,GAAI,GAAY,EAAQ,CAEvB,IAAM,EAAO,EAAO,sBAAsB,EACpC,EAAa,EAAW,QAAQ,SAAS,GAAK,EAAK,KAAO,EAAK,MAAQ,GACvE,EAAa,EAAW,QAAQ,SAAS,GAAK,EAAK,IAAM,EAAK,OAAS,GAGvE,EAAQ,EAAS,UAAY,EAC7B,EAAQ,EAAS,WAAa,EAC9B,GAAW,EAAI,EAAI,EAAI,GAAK,EAAQ,EAAS,QAC7C,GAAW,EAAI,EAAI,EAAI,GAAK,EAAQ,EAAS,QAC7C,EAAa,EAAU,EAAa,EAAI,KACxC,EAAa,EAAU,EAAa,EAAI,KAE9C,EAAI,KAAO,EAGX,IAAM,EAAa,EAAa,EAAa,EACvC,EAAa,EAAa,EAAa,EAGvC,EAAO,EAAa,EAAS,QAC7B,EAAO,EAAa,EAAS,QACnC,EAAI,EAAI,EAAO,EAAS,UAAY,EAAO,EAAS,WACpD,EAAI,EAAI,CAAC,EAAO,EAAS,UAAY,EAAO,EAAS,WAC/C,KAEN,IAAM,EAAc,EACnB,EAAW,QAAQ,SAAS,EAC5B,EAAW,QAAQ,SAAS,EAC5B,CACD,EAEA,EAAI,KAAO,EAEX,EAAI,EAAI,EAAY,GAAK,EAAW,QAAQ,SAAS,EAAI,EAAY,cAAgB,GAAK,EAC1F,EAAI,EAAI,EAAY,GAAK,EAAW,QAAQ,SAAS,EAAI,EAAY,eAAiB,GAAK,GAE5F,EAIH,GAAI,EAAW,CAGd,IACC,QACA,QAAS,GACN,EAEE,EAAW,GAAY,IAAM,QAC7B,EAAa,GAAY,MAAQ,UACjC,EAAa,GAAY,MAAQ,UACjC,EAAc,GAAY,OAAS,WAErC,EAAY,GAEhB,EACE,UAAU,YAAY,EACtB,YAAY,GAAG,EACf,QAAQ,WAAW,EACnB,QAAQ,CAAW,EACnB,gBAAgB,CAAC,IAAQ,CAEzB,GAAI,CADe,EAAI,eAA8B,YAAY,EAChD,CAChB,QAAQ,MACP,+DACD,EACA,OAED,EAAY,GACZ,EACA,WAAW,EAAG,MAAK,QAAS,CAC5B,GAAI,CAAC,EAAW,OAEhB,IAAM,EAAa,EAAI,eAA8B,YAAY,EACjE,GAAI,CAAC,EAAY,OAEjB,IAAM,EAAS,EAAQ,EAAY,KAAQ,EACrC,GAAM,EAAW,QAAQ,SAAS,CAAW,EAAI,EAAI,IACvD,EAAW,QAAQ,SAAS,CAAU,EAAI,EAAI,GAC5C,GAAM,EAAW,QAAQ,SAAS,CAAU,EAAI,EAAI,IACtD,EAAW,QAAQ,SAAS,CAAQ,EAAI,EAAI,GAEhD,GAAI,IAAO,GAAK,IAAO,EACtB,EAAY,YACX,EAAY,EAAI,EAAK,EACrB,EAAY,EAAI,EAAK,CACtB,EAED,GAEH,ECxqBH,mBAAS,iBACT,uBAAS,mBAqFF,SAAS,EAAgB,EAAgD,CAC/E,MAAO,CAAE,WAAY,EAAK,EAkCpB,SAAS,EAAqD,CACpE,EACC,CACD,IACC,cAAc,YACd,WAAW,IACX,QAAQ,YACR,iBAAiB,EACjB,eAAe,MACf,eAAe,KACf,iBAAiB,MACjB,iBAAiB,IACjB,eAAe,QACf,eACG,GAAW,CAAC,EAGV,EAAc,CAAE,MAAO,EAAc,MAAO,CAAa,EACzD,EAAgB,CAAE,MAAO,EAAgB,MAAO,IAAK,MAAO,CAAe,EAEjF,OAAO,GAAa,WAAW,EAC7B,mBAA4C,EAC5C,kBAA0C,EAC1C,WAAmD,EACnD,WAAc,EACd,SAA4B,EAC5B,QAAQ,CAAC,IAAU,CACnB,EAAM,YAAY,iBAAkB,CACnC,UAAW,CAAE,EAAG,EAAG,EAAG,CAAE,EACxB,YAAa,IACd,CAAC,EAED,IAAI,EAAkD,KAEtD,EACE,UAAU,iBAAiB,EAC3B,YAAY,CAAQ,EACpB,QAAQ,CAAK,EACb,QAAQ,CAAW,EACnB,SAAS,cAAe,CACxB,KAAM,CAAC,aAAc,gBAAgB,CACtC,CAAC,EACA,SAAS,oBAAqB,CAC9B,KAAM,CAAC,UAAU,CAClB,CAAC,EACA,cAAc,CAAC,aAAc,iBAAkB,SAAS,CAAC,EACzD,gBAAgB,CAAC,IAAQ,CACzB,IAAM,EAAU,EAAI,YAAY,SAAS,EACzC,EAAqB,CAAC,IAAa,EAAE,eAAe,EACpD,EAAQ,OAAO,iBAAiB,cAAe,CAAkB,EACjE,EACA,YAAY,CAAC,IAAQ,CACrB,GAAI,CAAC,EAAoB,OACT,EAAI,YAAY,SAAS,EACjC,OAAO,oBAAoB,cAAe,CAAkB,EACpE,EAAqB,KACrB,EACA,WAAW,EAAG,UAAS,MAAK,eAAgB,CAC5C,IAAQ,WAAY,EAAO,kBAAmB,EACxC,EAAU,EAAM,QAGtB,GAAI,EAAQ,YAAY,CAAC,EAAG,CAE3B,GAAI,EAAe,cAAgB,KAClC,EAAI,SAAS,aAAa,EAAe,WAAW,EAGrD,EAAe,UAAU,EAAI,EAAQ,SAAS,EAC9C,EAAe,UAAU,EAAI,EAAQ,SAAS,EAE9C,IAAM,EAAY,EAAI,MAAM,CAC3B,SAAU,IAAI,EACf,CAAC,EACD,GAAI,EACH,EAAI,aAAa,EAAU,GAAI,cAAe,CAAW,EAE1D,EAAe,YAAc,EAAU,GAIxC,GAAI,EAAQ,OAAO,CAAC,GAAK,EAAe,cAAgB,KAAM,CAC7D,IAAM,EAAI,EAAI,aAAa,EAAe,YAAa,UAAU,EACjE,GAAI,CAAC,EAAG,OAER,IAAM,EAAS,EAAe,UAAU,EAClC,EAAS,EAAe,UAAU,EAClC,EAAO,EAAQ,SAAS,EACxB,EAAO,EAAQ,SAAS,EACxB,EAAO,KAAK,IAAI,EAAQ,CAAI,EAC5B,EAAO,KAAK,IAAI,EAAQ,CAAI,EAC5B,EAAI,KAAK,IAAI,EAAO,CAAM,EAC1B,EAAI,KAAK,IAAI,EAAO,CAAM,EAEhC,EAAE,MAAM,EACR,EAAE,KAAK,EAAM,EAAM,EAAG,CAAC,EACvB,EAAE,KAAK,CAAW,EAClB,EAAE,OAAO,CAAa,EAIvB,GAAI,CAAC,EAAQ,aAAa,CAAC,GAAK,EAAe,cAAgB,KAAM,OAErE,IAAM,EAAS,EAAe,UAAU,EAClC,EAAS,EAAe,UAAU,EAClC,EAAO,EAAQ,SAAS,EACxB,EAAO,EAAQ,SAAS,EAExB,EAAI,KAAK,IAAI,EAAO,CAAM,EAC1B,EAAI,KAAK,IAAI,EAAO,CAAM,EAGhC,QAAW,KAAU,EAAQ,kBAC5B,EAAI,gBAAgB,EAAO,GAAI,UAAU,EAG1C,IAAM,EAAU,EAAI,GAAkB,EAAI,EAGpC,EAAW,EAAI,eAAe,aAAa,EAC3C,EAAW,EACd,EAAc,EAAM,EAAM,CAAQ,EAClC,CAAE,EAAG,EAAM,EAAG,CAAK,EAEtB,GAAI,EAAS,CAEZ,IAAI,EAA2B,KAC3B,EAAgB,IAEpB,QAAW,KAAU,EAAQ,YAAa,CACzC,IAAQ,kBAAmB,EAAO,WAC5B,EAAK,EAAe,EAAI,EAAS,EACjC,EAAK,EAAe,EAAI,EAAS,EACjC,EAAS,EAAK,EAAK,EAAK,EAC9B,GAAI,EATiB,KASS,EAAS,EACtC,EAAgB,EAChB,EAAY,EAAO,GAIrB,GAAI,IAAc,KACjB,EAAI,aAAa,EAAW,WAAY,EAAI,EAEvC,KACN,IAAM,EAAa,EAChB,EAAc,EAAQ,EAAQ,CAAQ,EACtC,CAAE,EAAG,EAAQ,EAAG,CAAO,EACpB,EAAQ,KAAK,IAAI,EAAW,EAAG,EAAS,CAAC,EACzC,EAAQ,KAAK,IAAI,EAAW,EAAG,EAAS,CAAC,EACzC,EAAQ,KAAK,IAAI,EAAW,EAAG,EAAS,CAAC,EACzC,EAAQ,KAAK,IAAI,EAAW,EAAG,EAAS,CAAC,EAE/C,QAAW,KAAU,EAAQ,YAAa,CACzC,IAAQ,kBAAmB,EAAO,WAClC,GACC,EAAe,GAAK,GACpB,EAAe,GAAK,GACpB,EAAe,GAAK,GACpB,EAAe,GAAK,EAEpB,EAAI,aAAa,EAAO,GAAI,WAAY,EAAI,GAK/C,EAAI,SAAS,aAAa,EAAe,WAAW,EACpD,EAAe,YAAc,KAC7B,EAGF,EACE,UAAU,kBAAkB,EAC5B,YAAY,CAAQ,EACpB,QAAQ,QAAQ,EAChB,QAAQ,CAAW,EACnB,SAAS,gBAAiB,CAC1B,KAAM,CAAC,WAAY,QAAQ,CAC5B,CAAC,EACA,iBAAiB,gBAAiB,EAAG,YAAa,CAClD,EAAO,WAAW,OAAO,KAAO,EAChC,EACA,SAAS,kBAAmB,CAC5B,KAAM,CAAC,aAAc,QAAQ,EAC7B,QAAS,CAAC,UAAU,CACrB,CAAC,EACA,iBAAiB,kBAAmB,EAAG,YAAa,CACpD,EAAO,WAAW,OAAO,KAAO,SAChC,EACF",
9
- "debugId": "2CBA75EEC12DB4DB64756E2164756E21",
8
+ "mappings": "2PAcA,uBAAS,kBA2HT,IAAM,EAAuD,CAC5D,YAAa,EACb,WAAY,GACZ,WAAY,GACZ,YAAa,IACd,EAEM,EAAyD,CAC9D,UAAW,EACX,UAAW,EACX,UAAW,EACX,QAAS,EACT,QAAS,CACV,EAIO,SAAS,EAAa,CAC5B,EACA,EACA,EAC2B,CAC3B,IAAM,EAAK,GAAU,EAAM,EAAI,EAAM,cAC/B,EAAK,GAAU,EAAM,EAAI,EAAM,cAE/B,EAAQ,EAAE,EAAM,SAAW,EAAM,eACjC,EAAM,KAAK,IAAI,CAAK,EACpB,EAAM,KAAK,IAAI,CAAK,EACpB,EAAK,EAAK,EAAM,EAAK,EACrB,EAAK,EAAK,EAAM,EAAK,EAE3B,MAAO,CACN,EAAG,EAAK,EAAM,KAAO,EAAM,cAAgB,EAC3C,EAAG,EAAK,EAAM,KAAO,EAAM,eAAiB,CAC7C,EAGM,SAAS,CAAa,CAC5B,EACA,EACA,EAC2B,CAC3B,IAAM,GAAM,EAAU,EAAM,cAAgB,GAAK,EAAM,KACjD,GAAM,EAAU,EAAM,eAAiB,GAAK,EAAM,KAElD,EAAQ,EAAM,SAAW,EAAM,cAC/B,EAAM,KAAK,IAAI,CAAK,EACpB,EAAM,KAAK,IAAI,CAAK,EACpB,EAAK,EAAK,EAAM,EAAK,EACrB,EAAK,EAAK,EAAM,EAAK,EAE3B,MAAO,CACN,EAAG,EAAK,EAAM,EAAI,EAAM,aACxB,EAAG,EAAK,EAAM,EAAI,EAAM,YACzB,EAKD,SAAS,CAAa,CAAC,EAAuC,CAC7D,OAAO,OAAO,IAAW,SAAW,EAAS,EAAO,GAGrD,SAAS,CAAmB,CAAC,EAAiE,CAC7F,IAAM,EAAO,IAAU,GAAO,CAAC,EAAI,EACnC,MAAO,CACN,OAAQ,EACR,YAAa,EAAK,aAAe,EAAc,YAC/C,WAAY,EAAK,YAAc,EAAc,WAC7C,WAAY,EAAK,YAAc,EAAc,WAC7C,YAAa,EAAK,aAAe,EAAc,WAChD,EAGD,SAAS,CAAa,CACrB,EACe,CACf,GAAI,MAAM,QAAQ,CAAM,EACvB,MAAO,CAAE,KAAM,EAAO,GAAI,KAAM,EAAO,GAAI,KAAM,EAAO,GAAI,KAAM,EAAO,EAAG,EAE7E,MAAO,IAAK,CAAO,EAGpB,SAAS,CAAoB,CAAC,EAAuD,CACpF,MAAO,CACN,UAAW,GAAS,WAAa,EAAe,UAChD,UAAW,GAAS,WAAa,EAAe,UAChD,UAAW,GAAS,WAAa,EAAe,UAChD,QAAS,GAAS,SAAW,EAAe,QAC5C,QAAS,GAAS,SAAW,EAAe,OAC7C,EAgBM,SAAS,EAA+C,CAC9D,EACC,CACD,IACC,gBAAgB,IAChB,iBAAiB,IACjB,UACA,OAAQ,EACR,MAAO,EACP,OAAQ,EACR,KAAM,EACN,IAAK,EACL,cAAc,SACd,QAAQ,aACR,WAAW,KAAK,QACb,GAAW,CAAC,EAEhB,OAAO,EAAa,QAAQ,EAC1B,mBAAyC,EACzC,kBAAuC,EACvC,WAAyB,EACzB,WAAc,EACd,SAA+B,EAC/B,QAAQ,CAAC,IAAU,CAKnB,IAAM,EAA2B,CAChC,EAAG,GAAS,GAAK,EACjB,EAAG,GAAS,GAAK,EACjB,KAAM,GAAS,MAAQ,EACvB,SAAU,GAAS,UAAY,EAC/B,aAAc,EACd,aAAc,EACd,cAAe,EACf,gBACA,iBACA,SAAU,GAGV,OAAQ,IAAM,GACd,SAAU,IAAM,GAChB,YAAa,IAAM,GACnB,QAAS,IAAM,GACf,YAAa,IAAM,GACnB,UAAW,IAAM,GACjB,YAAa,IAAM,GACnB,UAAW,IAAM,EAClB,EAgPA,GA9OA,EAAM,YAAY,cAAe,CAAW,EAG5C,EACE,UAAU,aAAa,EACvB,QAAQ,CAAW,EACnB,gBAAgB,CAAC,IAA6D,CAE9E,IAAM,EAAS,EAAI,MAAM,CACxB,OAAQ,CACP,EAAG,GAAS,GAAK,EACjB,EAAG,GAAS,GAAK,EACjB,KAAM,GAAS,MAAQ,EACvB,SAAU,GAAS,UAAY,CAChC,CACD,CAAC,EAGD,GAAI,EACH,EAAI,aAAa,EAAO,GAAI,eAAgB,CAC3C,OAAQ,MACL,EAAqB,CAAY,CACrC,CAAC,EAGF,GAAI,EACH,EAAI,aAAa,EAAO,GAAI,cAAe,EAAoB,CAAW,CAAC,EAG5E,GAAI,EACH,EAAI,aAAa,EAAO,GAAI,eAAgB,EAAc,CAAY,CAAC,EAExE,EAAY,SAAW,EAAO,GAG9B,EAAY,OAAS,CAAC,EAA+B,IAAyB,CAE7E,IAAM,EAA2B,CAChC,OAFgB,EAAc,CAAM,KAGjC,EAAqB,CAAI,CAC7B,EACM,EAAW,EAAI,aAAa,EAAY,SAAU,cAAc,EACtE,GAAI,EACH,EAAS,OAAS,EAAW,OAC7B,EAAS,UAAY,EAAW,UAChC,EAAS,UAAY,EAAW,UAChC,EAAS,UAAY,EAAW,UAChC,EAAS,QAAU,EAAW,QAC9B,EAAS,QAAU,EAAW,QAE9B,OAAI,aAAa,EAAY,SAAU,eAAgB,CAAU,GAInE,EAAY,SAAW,IAAM,CAE5B,GADiB,EAAI,aAAa,EAAY,SAAU,cAAc,EAErE,EAAI,gBAAgB,EAAY,SAAU,cAAc,GAI1D,EAAY,YAAc,CAAC,EAAW,IAAc,CACnD,IAAM,EAAS,EAAI,aAAa,EAAY,SAAU,QAAQ,EAC9D,GAAI,CAAC,EAAQ,OACb,EAAO,EAAI,EACX,EAAO,EAAI,GAGZ,EAAY,QAAU,CAAC,IAAiB,CACvC,IAAM,EAAS,EAAI,aAAa,EAAY,SAAU,QAAQ,EAC9D,GAAI,CAAC,EAAQ,OACb,EAAO,KAAO,GAGf,EAAY,YAAc,CAAC,IAAqB,CAC/C,IAAM,EAAS,EAAI,aAAa,EAAY,SAAU,QAAQ,EAC9D,GAAI,CAAC,EAAQ,OACb,EAAO,SAAW,GAGnB,EAAY,UAAY,CAAC,EAAc,EAAc,EAAc,IAAiB,CACnF,IAAM,EAAW,EAAI,aAAa,EAAY,SAAU,cAAc,EACtE,GAAI,EACH,EAAS,KAAO,EAChB,EAAS,KAAO,EAChB,EAAS,KAAO,EAChB,EAAS,KAAO,EAEhB,OAAI,aAAa,EAAY,SAAU,eAAgB,CAAE,OAAM,OAAM,OAAM,MAAK,CAAC,GAInF,EAAY,YAAc,IAAM,CAE/B,GADiB,EAAI,aAAa,EAAY,SAAU,cAAc,EAErE,EAAI,gBAAgB,EAAY,SAAU,cAAc,GAI1D,EAAY,UAAY,CAAC,IAAmB,CAC3C,IAAM,EAAQ,EAAI,aAAa,EAAY,SAAU,aAAa,EAClE,GAAI,EACH,EAAM,OAAS,KAAK,IAAI,EAAG,KAAK,IAAI,EAAG,EAAM,OAAS,CAAM,CAAC,EAE7D,OAAI,aAAa,EAAY,SAAU,cAAe,IAClD,EAAoB,EAAI,EAC3B,OAAQ,KAAK,IAAI,EAAG,KAAK,IAAI,EAAG,CAAM,CAAC,CACxC,CAAC,GAGH,EAGF,EACE,UAAU,eAAe,EACzB,YAAY,GAAG,EACf,QAAQ,CAAK,EACb,QAAQ,CAAW,EACnB,SAAS,UAAW,CACpB,KAAM,CAAC,SAAU,cAAc,CAChC,CAAC,EACA,WAAW,EAAG,UAAS,KAAI,SAAU,CACrC,IAAM,EAAI,KAAK,IAAI,EAAG,CAAE,EACxB,QAAW,KAAU,EAAQ,QAAS,CACrC,IAAQ,SAAQ,gBAAiB,EAAO,WACxC,GAAI,EAAa,OAAS,EAAG,SAE7B,IAAM,EAAc,EAAI,aAAa,EAAa,OAAQ,gBAAgB,EAC1E,GAAI,CAAC,EAAa,SAElB,IAAM,EAAQ,EAAY,EAAI,EAAa,QACrC,EAAQ,EAAY,EAAI,EAAa,QACrC,EAAK,EAAQ,EAAO,EACpB,EAAK,EAAQ,EAAO,EAE1B,GAAI,KAAK,IAAI,CAAE,EAAI,EAAa,UAAW,CAC1C,IAAM,EAAO,EAAK,EAAI,EAAI,GACpB,EAAU,EAAK,EAAO,EAAa,UACnC,EAAS,KAAK,IAAI,EAAG,EAAa,UAAY,CAAC,EACrD,EAAO,GAAK,EAAU,EAEvB,GAAI,KAAK,IAAI,CAAE,EAAI,EAAa,UAAW,CAC1C,IAAM,EAAO,EAAK,EAAI,EAAI,GACpB,EAAU,EAAK,EAAO,EAAa,UACnC,EAAS,KAAK,IAAI,EAAG,EAAa,UAAY,CAAC,EACrD,EAAO,GAAK,EAAU,IAGxB,EAGF,EACE,UAAU,qBAAqB,EAC/B,YAAY,GAAG,EACf,QAAQ,CAAK,EACb,QAAQ,CAAW,EACnB,SAAS,eAAgB,CACzB,KAAM,CAAC,SAAU,aAAa,CAC/B,CAAC,EACA,WAAW,EAAG,UAAS,QAAS,CAChC,QAAW,KAAU,EAAQ,aAAc,CAC1C,IAAQ,eAAgB,EAAO,WAC/B,EAAY,OAAS,KAAK,IAAI,EAAG,EAAY,OAAS,EAAY,YAAc,CAAE,GAEnF,EAGF,EACE,UAAU,eAAe,EACzB,YAAY,GAAG,EACf,QAAQ,CAAK,EACb,QAAQ,CAAW,EACnB,SAAS,iBAAkB,CAC3B,KAAM,CAAC,SAAU,cAAc,CAChC,CAAC,EACA,WAAW,EAAG,aAAc,CAC5B,QAAW,KAAU,EAAQ,eAAgB,CAC5C,IAAQ,SAAQ,gBAAiB,EAAO,WAClC,EAAQ,EAAY,eAAiB,EAAI,EAAO,MAChD,EAAQ,EAAY,gBAAkB,EAAI,EAAO,MAEjD,EAAgB,EAAa,KAAO,EACpC,EAAgB,EAAa,KAAO,EACpC,EAAgB,EAAa,KAAO,EACpC,EAAgB,EAAa,KAAO,EAE1C,GAAI,EAAgB,EACnB,EAAO,GAAK,EAAa,KAAO,EAAa,MAAQ,EAErD,OAAO,EAAI,KAAK,IAAI,EAAe,KAAK,IAAI,EAAe,EAAO,CAAC,CAAC,EAGrE,GAAI,EAAgB,EACnB,EAAO,GAAK,EAAa,KAAO,EAAa,MAAQ,EAErD,OAAO,EAAI,KAAK,IAAI,EAAe,KAAK,IAAI,EAAe,EAAO,CAAC,CAAC,GAGtE,EAGF,EACE,UAAU,mBAAmB,EAC7B,YAAY,GAAG,EACf,QAAQ,CAAK,EACb,QAAQ,CAAW,EACnB,WAAW,EAAG,SAAU,CACxB,IAAM,EAAS,EAAI,aAAa,EAAY,SAAU,QAAQ,EAC9D,GAAI,CAAC,EAAQ,CACZ,EAAY,EAAI,EAChB,EAAY,EAAI,EAChB,EAAY,KAAO,EACnB,EAAY,SAAW,EACvB,EAAY,aAAe,EAC3B,EAAY,aAAe,EAC3B,EAAY,cAAgB,EAC5B,OAGD,EAAY,EAAI,EAAO,EACvB,EAAY,EAAI,EAAO,EACvB,EAAY,KAAO,EAAO,KAC1B,EAAY,SAAW,EAAO,SAE9B,IAAM,EAAQ,EAAI,aAAa,EAAY,SAAU,aAAa,EAClE,GAAI,GAAS,EAAM,OAAS,EAAG,CAC9B,IAAM,EAAY,EAAM,OAAS,EAAM,OACvC,EAAY,aAAe,EAAM,WAAa,GAAa,EAAS,EAAI,EAAI,GAC5E,EAAY,aAAe,EAAM,WAAa,GAAa,EAAS,EAAI,EAAI,GAC5E,EAAY,cAAgB,EAAM,YAAc,GAAa,EAAS,EAAI,EAAI,GAE9E,OAAY,aAAe,EAC3B,EAAY,aAAe,EAC3B,EAAY,cAAgB,EAE7B,EAGE,EAAY,CAcf,IAAS,EAAT,QAAgB,CAAC,EAAe,CAC/B,EAAE,eAAe,EACjB,GAAgB,KAAK,KAAK,EAAE,MAAM,IAdlC,WAAW,IACX,UAAU,IACV,UAAU,IACP,EAIA,EAAe,EACf,EAAa,GACb,EACA,EAOJ,EACE,UAAU,aAAa,EACvB,YAAY,GAAG,EACf,QAAQ,WAAW,EACnB,QAAQ,CAAW,EACnB,SAAS,UAAW,CACpB,KAAM,CAAC,QAAQ,CAChB,CAAC,EACA,gBAAgB,CAAC,IAAQ,CAEzB,IAAM,EAAa,EAAI,eAA+B,YAAY,EAC5D,EAAU,EAAI,eAA8C,SAAS,EAE3E,GAAI,CAAC,GAAc,CAAC,EAAS,CAC5B,QAAQ,MACP,uFAED,EACA,OAGD,EAAS,EAAQ,OACjB,EAAO,iBAAiB,QAAS,EAA0B,CAAE,QAAS,EAAM,CAAC,EAG7E,EAAW,EAAI,eAGZ,eAAe,EAElB,EAAa,GACb,EACA,YAAY,IAAM,CAClB,GAAI,CAAC,GAAc,CAAC,EAAQ,OAC5B,EAAO,oBAAoB,QAAS,CAAwB,EAC5D,EACA,WAAW,EAAG,UAAS,SAAU,CACjC,GAAI,CAAC,GAAc,IAAiB,EAAG,OAEvC,IAAM,EAAQ,EACd,EAAe,EAEf,IAAO,GAAgB,EAAQ,QAC/B,GAAI,CAAC,EAAc,OAEnB,IAAM,EAAM,EAAa,WAAW,OAC9B,EAAa,EAAI,eAA+B,YAAY,EAClE,GAAI,CAAC,EAAY,OAGjB,IAAM,EAAY,EAAQ,EAAK,EAAI,EAAa,EAAI,EAC9C,EAAU,KAAK,IAAI,EAAS,KAAK,IAAI,EAAS,EAAI,KAAO,KAAK,IAAI,EAAW,KAAK,IAAI,CAAK,CAAC,CAAC,CAAC,EAEpG,GAAI,GAAY,EAAQ,CAEvB,IAAM,EAAO,EAAO,sBAAsB,EACpC,EAAa,EAAW,QAAQ,SAAS,GAAK,EAAK,KAAO,EAAK,MAAQ,GACvE,EAAa,EAAW,QAAQ,SAAS,GAAK,EAAK,IAAM,EAAK,OAAS,GAGvE,EAAQ,EAAS,UAAY,EAC7B,EAAQ,EAAS,WAAa,EAC9B,GAAW,EAAI,EAAI,EAAI,GAAK,EAAQ,EAAS,QAC7C,GAAW,EAAI,EAAI,EAAI,GAAK,EAAQ,EAAS,QAC7C,EAAa,EAAU,EAAa,EAAI,KACxC,EAAa,EAAU,EAAa,EAAI,KAE9C,EAAI,KAAO,EAGX,IAAM,EAAa,EAAa,EAAa,EACvC,EAAa,EAAa,EAAa,EAGvC,EAAO,EAAa,EAAS,QAC7B,EAAO,EAAa,EAAS,QACnC,EAAI,EAAI,EAAO,EAAS,UAAY,EAAO,EAAS,WACpD,EAAI,EAAI,CAAC,EAAO,EAAS,UAAY,EAAO,EAAS,WAC/C,KAEN,IAAM,EAAc,EACnB,EAAW,QAAQ,SAAS,EAC5B,EAAW,QAAQ,SAAS,EAC5B,CACD,EAEA,EAAI,KAAO,EAEX,EAAI,EAAI,EAAY,GAAK,EAAW,QAAQ,SAAS,EAAI,EAAY,cAAgB,GAAK,EAC1F,EAAI,EAAI,EAAY,GAAK,EAAW,QAAQ,SAAS,EAAI,EAAY,eAAiB,GAAK,GAE5F,EAIH,GAAI,EAAW,CAGd,IACC,QACA,QAAS,GACN,EAEE,EAAW,GAAY,IAAM,QAC7B,EAAa,GAAY,MAAQ,UACjC,EAAa,GAAY,MAAQ,UACjC,EAAc,GAAY,OAAS,WAErC,EAAY,GAEhB,EACE,UAAU,YAAY,EACtB,YAAY,GAAG,EACf,QAAQ,WAAW,EACnB,QAAQ,CAAW,EACnB,gBAAgB,CAAC,IAAQ,CAEzB,GAAI,CADe,EAAI,eAA8B,YAAY,EAChD,CAChB,QAAQ,MACP,+DACD,EACA,OAED,EAAY,GACZ,EACA,WAAW,EAAG,MAAK,QAAS,CAC5B,GAAI,CAAC,EAAW,OAEhB,IAAM,EAAa,EAAI,eAA8B,YAAY,EACjE,GAAI,CAAC,EAAY,OAEjB,IAAM,EAAS,EAAQ,EAAY,KAAQ,EACrC,GAAM,EAAW,QAAQ,SAAS,CAAW,EAAI,EAAI,IACvD,EAAW,QAAQ,SAAS,CAAU,EAAI,EAAI,GAC5C,GAAM,EAAW,QAAQ,SAAS,CAAU,EAAI,EAAI,IACtD,EAAW,QAAQ,SAAS,CAAQ,EAAI,EAAI,GAEhD,GAAI,IAAO,GAAK,IAAO,EACtB,EAAY,YACX,EAAY,EAAI,EAAK,EACrB,EAAY,EAAI,EAAK,CACtB,EAED,GAEH,ECxqBH,mBAAS,gBACT,uBAAS,kBAqFF,SAAS,EAAgB,EAAgD,CAC/E,MAAO,CAAE,WAAY,EAAK,EAkCpB,SAAS,EAAqD,CACpE,EACC,CACD,IACC,cAAc,YACd,WAAW,IACX,QAAQ,YACR,iBAAiB,EACjB,eAAe,MACf,eAAe,KACf,iBAAiB,MACjB,iBAAiB,IACjB,eAAe,QACf,eACG,GAAW,CAAC,EAGV,EAAc,CAAE,MAAO,EAAc,MAAO,CAAa,EACzD,EAAgB,CAAE,MAAO,EAAgB,MAAO,IAAK,MAAO,CAAe,EAEjF,OAAO,EAAa,WAAW,EAC7B,mBAA4C,EAC5C,kBAA0C,EAC1C,WAAmD,EACnD,WAAc,EACd,SAA4B,EAC5B,QAAQ,CAAC,IAAU,CACnB,EAAM,YAAY,iBAAkB,CACnC,UAAW,CAAE,EAAG,EAAG,EAAG,CAAE,EACxB,YAAa,IACd,CAAC,EAED,IAAI,EAAkD,KAEtD,EACE,UAAU,iBAAiB,EAC3B,YAAY,CAAQ,EACpB,QAAQ,CAAK,EACb,QAAQ,CAAW,EACnB,SAAS,cAAe,CACxB,KAAM,CAAC,aAAc,gBAAgB,CACtC,CAAC,EACA,SAAS,oBAAqB,CAC9B,KAAM,CAAC,UAAU,CAClB,CAAC,EACA,cAAc,CAAC,aAAc,iBAAkB,SAAS,CAAC,EACzD,gBAAgB,CAAC,IAAQ,CACzB,IAAM,EAAU,EAAI,YAAY,SAAS,EACzC,EAAqB,CAAC,IAAa,EAAE,eAAe,EACpD,EAAQ,OAAO,iBAAiB,cAAe,CAAkB,EACjE,EACA,YAAY,CAAC,IAAQ,CACrB,GAAI,CAAC,EAAoB,OACT,EAAI,YAAY,SAAS,EACjC,OAAO,oBAAoB,cAAe,CAAkB,EACpE,EAAqB,KACrB,EACA,WAAW,EAAG,UAAS,MAAK,eAAgB,CAC5C,IAAQ,WAAY,EAAO,kBAAmB,EACxC,EAAU,EAAM,QAGtB,GAAI,EAAQ,YAAY,CAAC,EAAG,CAE3B,GAAI,EAAe,cAAgB,KAClC,EAAI,SAAS,aAAa,EAAe,WAAW,EAGrD,EAAe,UAAU,EAAI,EAAQ,SAAS,EAC9C,EAAe,UAAU,EAAI,EAAQ,SAAS,EAE9C,IAAM,EAAY,EAAI,MAAM,CAC3B,SAAU,IAAI,CACf,CAAC,EACD,GAAI,EACH,EAAI,aAAa,EAAU,GAAI,cAAe,CAAW,EAE1D,EAAe,YAAc,EAAU,GAIxC,GAAI,EAAQ,OAAO,CAAC,GAAK,EAAe,cAAgB,KAAM,CAC7D,IAAM,EAAI,EAAI,aAAa,EAAe,YAAa,UAAU,EACjE,GAAI,CAAC,EAAG,OAER,IAAM,EAAS,EAAe,UAAU,EAClC,EAAS,EAAe,UAAU,EAClC,EAAO,EAAQ,SAAS,EACxB,EAAO,EAAQ,SAAS,EACxB,EAAO,KAAK,IAAI,EAAQ,CAAI,EAC5B,EAAO,KAAK,IAAI,EAAQ,CAAI,EAC5B,EAAI,KAAK,IAAI,EAAO,CAAM,EAC1B,EAAI,KAAK,IAAI,EAAO,CAAM,EAEhC,EAAE,MAAM,EACR,EAAE,KAAK,EAAM,EAAM,EAAG,CAAC,EACvB,EAAE,KAAK,CAAW,EAClB,EAAE,OAAO,CAAa,EAIvB,GAAI,CAAC,EAAQ,aAAa,CAAC,GAAK,EAAe,cAAgB,KAAM,OAErE,IAAM,EAAS,EAAe,UAAU,EAClC,EAAS,EAAe,UAAU,EAClC,EAAO,EAAQ,SAAS,EACxB,EAAO,EAAQ,SAAS,EAExB,EAAI,KAAK,IAAI,EAAO,CAAM,EAC1B,EAAI,KAAK,IAAI,EAAO,CAAM,EAGhC,QAAW,KAAU,EAAQ,kBAC5B,EAAI,gBAAgB,EAAO,GAAI,UAAU,EAG1C,IAAM,EAAU,EAAI,GAAkB,EAAI,EAGpC,EAAW,EAAI,eAAe,aAAa,EAC3C,EAAW,EACd,EAAc,EAAM,EAAM,CAAQ,EAClC,CAAE,EAAG,EAAM,EAAG,CAAK,EAEtB,GAAI,EAAS,CAEZ,IAAI,EAA2B,KAC3B,EAAgB,IAEpB,QAAW,KAAU,EAAQ,YAAa,CACzC,IAAQ,kBAAmB,EAAO,WAC5B,EAAK,EAAe,EAAI,EAAS,EACjC,EAAK,EAAe,EAAI,EAAS,EACjC,EAAS,EAAK,EAAK,EAAK,EAC9B,GAAI,EATiB,KASS,EAAS,EACtC,EAAgB,EAChB,EAAY,EAAO,GAIrB,GAAI,IAAc,KACjB,EAAI,aAAa,EAAW,WAAY,EAAI,EAEvC,KACN,IAAM,EAAa,EAChB,EAAc,EAAQ,EAAQ,CAAQ,EACtC,CAAE,EAAG,EAAQ,EAAG,CAAO,EACpB,EAAQ,KAAK,IAAI,EAAW,EAAG,EAAS,CAAC,EACzC,EAAQ,KAAK,IAAI,EAAW,EAAG,EAAS,CAAC,EACzC,EAAQ,KAAK,IAAI,EAAW,EAAG,EAAS,CAAC,EACzC,EAAQ,KAAK,IAAI,EAAW,EAAG,EAAS,CAAC,EAE/C,QAAW,KAAU,EAAQ,YAAa,CACzC,IAAQ,kBAAmB,EAAO,WAClC,GACC,EAAe,GAAK,GACpB,EAAe,GAAK,GACpB,EAAe,GAAK,GACpB,EAAe,GAAK,EAEpB,EAAI,aAAa,EAAO,GAAI,WAAY,EAAI,GAK/C,EAAI,SAAS,aAAa,EAAe,WAAW,EACpD,EAAe,YAAc,KAC7B,EAGF,EACE,UAAU,kBAAkB,EAC5B,YAAY,CAAQ,EACpB,QAAQ,QAAQ,EAChB,QAAQ,CAAW,EACnB,SAAS,gBAAiB,CAC1B,KAAM,CAAC,WAAY,QAAQ,CAC5B,CAAC,EACA,iBAAiB,gBAAiB,EAAG,YAAa,CAClD,EAAO,WAAW,OAAO,KAAO,EAChC,EACA,SAAS,kBAAmB,CAC5B,KAAM,CAAC,aAAc,QAAQ,EAC7B,QAAS,CAAC,UAAU,CACrB,CAAC,EACA,iBAAiB,kBAAmB,EAAG,YAAa,CACpD,EAAO,WAAW,OAAO,KAAO,SAChC,EACF",
9
+ "debugId": "A100A9606EA8CF3164756E2164756E21",
10
10
  "names": []
11
11
  }
@@ -1,4 +1,4 @@
1
- var E=Object.defineProperty;var H=(b)=>b;function I(b,j){this[b]=H.bind(null,j)}var L=(b,j)=>{for(var k in j)E(b,k,{get:j[k],enumerable:!0,configurable:!0,set:I.bind(j,k)})};var M=(b,j)=>()=>(b&&(j=b(b=0)),j);var N=((b)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(b,{get:(j,k)=>(typeof require<"u"?require:j)[k]}):b)(function(b){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+b+'" is not supported')});import{definePlugin as J}from"ecspresso";function K(b,j){return b+j}function U(b){let{depthFn:j=K,systemGroup:k="isometric"}=b??{};return J("isometric-depth-sort").withComponentTypes().requires().withGroups().install((C)=>{C.addSystem("isometric-depth-sort-init").inGroup(k).setOnInitialize((z)=>{let x=z.getResource("rootContainer");x.sortableChildren=!0}),C.addSystem("isometric-depth-sort").setPriority(350).inPhase("render").inGroup(k).addQuery("sprites",{with:["sprite","worldTransform"],changed:["worldTransform"],optional:["depthOffset"]}).addQuery("graphics",{with:["graphics","worldTransform"],changed:["worldTransform"],optional:["depthOffset"]}).addQuery("containers",{with:["container","worldTransform"],changed:["worldTransform"],optional:["depthOffset"]}).setProcess(({queries:z})=>{for(let x of z.sprites){let{sprite:A,worldTransform:v,depthOffset:B}=x.components;A.zIndex=j(v.x,v.y)+(B??0)}for(let x of z.graphics){let{graphics:A,worldTransform:v,depthOffset:B}=x.components;A.zIndex=j(v.x,v.y)+(B??0)}for(let x of z.containers){let{container:A,worldTransform:v,depthOffset:B}=x.components;A.zIndex=j(v.x,v.y)+(B??0)}})})}export{U as createIsoDepthSortPlugin};
1
+ var I=((b)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(b,{get:(k,B)=>(typeof require<"u"?require:k)[B]}):b)(function(b){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+b+'" is not supported')});import{definePlugin as E}from"ecspresso";function H(b,k){return b+k}function L(b){let{depthFn:k=H,systemGroup:B="isometric"}=b??{};return E("isometric-depth-sort").withComponentTypes().requires().withGroups().install((C)=>{C.addSystem("isometric-depth-sort-init").inGroup(B).setOnInitialize((x)=>{let v=x.getResource("rootContainer");v.sortableChildren=!0}),C.addSystem("isometric-depth-sort").setPriority(350).inPhase("render").inGroup(B).addQuery("sprites",{with:["sprite","worldTransform"],changed:["worldTransform"],optional:["depthOffset"]}).addQuery("graphics",{with:["graphics","worldTransform"],changed:["worldTransform"],optional:["depthOffset"]}).addQuery("containers",{with:["container","worldTransform"],changed:["worldTransform"],optional:["depthOffset"]}).setProcess(({queries:x})=>{for(let v of x.sprites){let{sprite:z,worldTransform:j,depthOffset:A}=v.components;z.zIndex=k(j.x,j.y)+(A??0)}for(let v of x.graphics){let{graphics:z,worldTransform:j,depthOffset:A}=v.components;z.zIndex=k(j.x,j.y)+(A??0)}for(let v of x.containers){let{container:z,worldTransform:j,depthOffset:A}=v.components;z.zIndex=k(j.x,j.y)+(A??0)}})})}export{L as createIsoDepthSortPlugin};
2
2
 
3
- //# debugId=91FD048FD3AF993864756E2164756E21
3
+ //# debugId=E8C9DCC3EA4239A864756E2164756E21
4
4
  //# sourceMappingURL=depth-sort.js.map