ecspresso 0.13.0 → 0.13.1

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 (79) hide show
  1. package/dist/index.js +2 -2
  2. package/dist/index.js.map +1 -1
  3. package/dist/plugins/ai/detection.d.ts +118 -0
  4. package/dist/plugins/ai/detection.js +4 -0
  5. package/dist/plugins/ai/detection.js.map +10 -0
  6. package/dist/plugins/{audio.js → audio/audio.js} +1 -1
  7. package/dist/plugins/{audio.js.map → audio/audio.js.map} +2 -2
  8. package/dist/plugins/combat/health.d.ts +98 -0
  9. package/dist/plugins/combat/health.js +4 -0
  10. package/dist/plugins/combat/health.js.map +10 -0
  11. package/dist/plugins/combat/projectile.d.ts +115 -0
  12. package/dist/plugins/combat/projectile.js +4 -0
  13. package/dist/plugins/combat/projectile.js.map +10 -0
  14. package/dist/plugins/{diagnostics.js → debug/diagnostics.js} +1 -1
  15. package/dist/plugins/{diagnostics.js.map → debug/diagnostics.js.map} +2 -2
  16. package/dist/plugins/{input.js → input/input.js} +1 -1
  17. package/dist/plugins/{input.js.map → input/input.js.map} +2 -2
  18. package/dist/plugins/input/selection.d.ts +114 -0
  19. package/dist/plugins/input/selection.js +4 -0
  20. package/dist/plugins/input/selection.js.map +11 -0
  21. package/dist/plugins/isometric/depth-sort.d.ts +44 -0
  22. package/dist/plugins/isometric/depth-sort.js +4 -0
  23. package/dist/plugins/isometric/depth-sort.js.map +10 -0
  24. package/dist/plugins/isometric/projection.d.ts +83 -0
  25. package/dist/plugins/isometric/projection.js +4 -0
  26. package/dist/plugins/isometric/projection.js.map +10 -0
  27. package/dist/plugins/{collision.d.ts → physics/collision.d.ts} +1 -1
  28. package/dist/plugins/{collision.js → physics/collision.js} +1 -1
  29. package/dist/plugins/{collision.js.map → physics/collision.js.map} +3 -3
  30. package/dist/plugins/{physics2D.d.ts → physics/physics2D.d.ts} +1 -1
  31. package/dist/plugins/{physics2D.js → physics/physics2D.js} +1 -1
  32. package/dist/plugins/{physics2D.js.map → physics/physics2D.js.map} +3 -3
  33. package/dist/plugins/physics/steering.d.ts +102 -0
  34. package/dist/plugins/physics/steering.js +4 -0
  35. package/dist/plugins/physics/steering.js.map +10 -0
  36. package/dist/plugins/{particles.d.ts → rendering/particles.d.ts} +2 -2
  37. package/dist/plugins/{particles.js → rendering/particles.js} +1 -1
  38. package/dist/plugins/rendering/particles.js.map +10 -0
  39. package/dist/plugins/{renderers → rendering}/renderer2D.d.ts +9 -5
  40. package/dist/plugins/rendering/renderer2D.js +4 -0
  41. package/dist/plugins/rendering/renderer2D.js.map +10 -0
  42. package/dist/plugins/{sprite-animation.js → rendering/sprite-animation.js} +1 -1
  43. package/dist/plugins/{sprite-animation.js.map → rendering/sprite-animation.js.map} +2 -2
  44. package/dist/plugins/{coroutine.js → scripting/coroutine.js} +1 -1
  45. package/dist/plugins/{coroutine.js.map → scripting/coroutine.js.map} +2 -2
  46. package/dist/plugins/{state-machine.js → scripting/state-machine.js} +1 -1
  47. package/dist/plugins/{state-machine.js.map → scripting/state-machine.js.map} +2 -2
  48. package/dist/plugins/{timers.js → scripting/timers.js} +1 -1
  49. package/dist/plugins/{timers.js.map → scripting/timers.js.map} +2 -2
  50. package/dist/plugins/{tween.d.ts → scripting/tween.d.ts} +1 -1
  51. package/dist/plugins/{tween.js → scripting/tween.js} +1 -1
  52. package/dist/plugins/scripting/tween.js.map +11 -0
  53. package/dist/plugins/{bounds.js → spatial/bounds.js} +1 -1
  54. package/dist/plugins/{bounds.js.map → spatial/bounds.js.map} +2 -2
  55. package/dist/plugins/{camera.d.ts → spatial/camera.d.ts} +43 -12
  56. package/dist/plugins/spatial/camera.js +4 -0
  57. package/dist/plugins/spatial/camera.js.map +10 -0
  58. package/dist/plugins/{spatial-index.d.ts → spatial/spatial-index.d.ts} +2 -2
  59. package/dist/plugins/{spatial-index.js → spatial/spatial-index.js} +1 -1
  60. package/dist/plugins/{spatial-index.js.map → spatial/spatial-index.js.map} +3 -3
  61. package/dist/plugins/{transform.d.ts → spatial/transform.d.ts} +1 -1
  62. package/dist/plugins/{transform.js → spatial/transform.js} +1 -1
  63. package/dist/plugins/spatial/transform.js.map +10 -0
  64. package/package.json +77 -49
  65. package/dist/plugins/camera.js +0 -4
  66. package/dist/plugins/camera.js.map +0 -10
  67. package/dist/plugins/particles.js.map +0 -10
  68. package/dist/plugins/renderers/renderer2D.js +0 -4
  69. package/dist/plugins/renderers/renderer2D.js.map +0 -10
  70. package/dist/plugins/transform.js.map +0 -10
  71. package/dist/plugins/tween.js.map +0 -11
  72. /package/dist/plugins/{audio.d.ts → audio/audio.d.ts} +0 -0
  73. /package/dist/plugins/{diagnostics.d.ts → debug/diagnostics.d.ts} +0 -0
  74. /package/dist/plugins/{input.d.ts → input/input.d.ts} +0 -0
  75. /package/dist/plugins/{sprite-animation.d.ts → rendering/sprite-animation.d.ts} +0 -0
  76. /package/dist/plugins/{coroutine.d.ts → scripting/coroutine.d.ts} +0 -0
  77. /package/dist/plugins/{state-machine.d.ts → scripting/state-machine.d.ts} +0 -0
  78. /package/dist/plugins/{timers.d.ts → scripting/timers.d.ts} +0 -0
  79. /package/dist/plugins/{bounds.d.ts → spatial/bounds.d.ts} +0 -0
@@ -1,10 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/plugins/renderers/renderer2D.ts"],
4
- "sourcesContent": [
5
- "/**\n * 2D Renderer Plugin for ECSpresso\n *\n * An opt-in PixiJS-based 2D rendering plugin that automates scene graph wiring.\n * Import from 'ecspresso/plugins/renderers/renderer2D'\n *\n * This plugin includes transform propagation automatically.\n */\n\nimport type { Application, ApplicationOptions, Container, Sprite, Graphics } from 'pixi.js';\nimport { definePlugin, type Plugin } from 'ecspresso';\nimport type { WorldConfigFrom, EmptyConfig } from '../../type-utils';\nimport type ECSpresso from 'ecspresso';\nimport {\n\tcreateTransformPlugin,\n\ttype LocalTransform,\n\ttype WorldTransform,\n\ttype TransformComponentTypes,\n\ttype TransformPluginOptions,\n} from 'ecspresso/plugins/transform';\nimport { createBounds, type BoundsRect } from 'ecspresso/plugins/bounds';\nimport type { CameraResourceTypes, CameraState } from 'ecspresso/plugins/camera';\n\n// Re-export transform and bounds types for convenience\nexport type { LocalTransform, WorldTransform, TransformComponentTypes };\nexport type { BoundsRect };\nexport { createTransform, createLocalTransform, createWorldTransform, DEFAULT_LOCAL_TRANSFORM, DEFAULT_WORLD_TRANSFORM } from 'ecspresso/plugins/transform';\n\n// Dynamic import for Application to avoid requiring pixi.js at plugin creation time\n// when using managed mode (pixiInit options instead of pre-initialized app)\nasync function createPixiApplication(options: Partial<ApplicationOptions>): Promise<Application> {\n\tconst { Application } = await import('pixi.js');\n\tconst app = new Application();\n\tawait app.init(options);\n\treturn app;\n}\n\n// ==================== Component Types ====================\n\n/**\n * Visibility and alpha component\n */\nexport interface Visible {\n\tvisible: boolean;\n\talpha?: number;\n}\n\n/**\n * Aggregate component types for the 2D renderer plugin.\n * Included automatically via `.withPlugin(createRenderer2DPlugin({ ... }))`.\n *\n * @example\n * ```typescript\n * const ecs = ECSpresso.create()\n * .withPlugin(createRenderer2DPlugin({ ... }))\n * .withComponentTypes<{ velocity: { x: number; y: number }; player: true }>()\n * .build();\n * ```\n */\nexport interface Renderer2DComponentTypes extends TransformComponentTypes {\n\tsprite: Sprite;\n\tgraphics: Graphics;\n\tcontainer: Container;\n\tvisible: Visible;\n\t/** Assigns the entity to a named render layer for z-ordering */\n\trenderLayer: string;\n}\n\n// ==================== Event Types ====================\n\n/**\n * Events emitted by the 2D renderer plugin\n */\nexport interface Renderer2DEventTypes {\n\thierarchyChanged: {\n\t\tentityId: number;\n\t\toldParent: number | null;\n\t\tnewParent: number | null;\n\t};\n}\n\n// ==================== Resource Types ====================\n\n/**\n * Resources provided by the 2D renderer plugin\n */\nexport interface Renderer2DResourceTypes {\n\tpixiApp: Application;\n\trootContainer: Container;\n\t/** Screen bounds derived from PixiJS screen dimensions, updated on resize */\n\tbounds: BoundsRect;\n}\n\n// ==================== Scale Mode Types ====================\n\nexport type ScaleMode = 'fit' | 'cover' | 'stretch';\n\nexport interface ScreenScaleOptions {\n\treadonly width: number;\n\treadonly height: number;\n\treadonly mode?: ScaleMode;\n}\n\nexport interface ViewportScale {\n\tscaleX: number;\n\tscaleY: number;\n\toffsetX: number;\n\toffsetY: number;\n\tphysicalWidth: number;\n\tphysicalHeight: number;\n\t/** Current scale mode. Mutable — call `reapplyViewportScale(pixiApp)` after changing to re-apply immediately. */\n\tmode: ScaleMode;\n\treadonly designWidth: number;\n\treadonly designHeight: number;\n}\n\nexport interface ViewportScaleResourceTypes {\n\tviewportScale: ViewportScale;\n}\n\n// ==================== Plugin Options ====================\n\n/**\n * Common options shared between both initialization modes\n */\ninterface Renderer2DPluginCommonOptions<G extends string = 'renderer2d'> {\n\t/** Optional custom root container (defaults to app.stage) */\n\trootContainer?: Container;\n\t/** System group name (default: 'renderer2d') */\n\tsystemGroup?: G;\n\t/** Priority for render sync system (default: 500) */\n\trenderSyncPriority?: number;\n\t/** Options for the included transform plugin */\n\ttransform?: TransformPluginOptions;\n\t/** When true, wires up pixiApp.ticker to drive ecs.update() automatically (default: true) */\n\tstartLoop?: boolean;\n\t/** Ordered render layer names (back-to-front). Entities with a renderLayer component are placed in the corresponding container. */\n\trenderLayers?: string[];\n\t/** Automatically apply cameraState resource to rootContainer each frame.\n\t * Requires the camera plugin to be installed. (default: false) */\n\tcamera?: boolean;\n\t/** Enforce a logical design resolution with automatic aspect-ratio-aware scaling.\n\t * When set, systems work in design-resolution coordinate space. */\n\tscreenScale?: ScreenScaleOptions;\n}\n\n/**\n * Options when providing a pre-initialized PixiJS Application\n */\nexport interface Renderer2DPluginAppOptions<G extends string = 'renderer2d'> extends Renderer2DPluginCommonOptions<G> {\n\t/** The PixiJS Application instance (already initialized) */\n\tapp: Application;\n\tpixiInit?: never;\n\tcontainer?: never;\n\tbackground?: never;\n\twidth?: never;\n\theight?: never;\n}\n\n/**\n * Options when letting the plugin create and manage the PixiJS Application\n */\nexport interface Renderer2DPluginManagedOptions<G extends string = 'renderer2d'> extends Renderer2DPluginCommonOptions<G> {\n\tapp?: never;\n\t/** Container element to append the canvas to (or CSS selector string). Defaults to `document.body`.\n\t * The canvas also auto-resizes to this element unless `width`/`height` are set or `pixiInit.resizeTo` is set explicitly. */\n\tcontainer?: HTMLElement | string;\n\t/** Canvas background color. */\n\tbackground?: ApplicationOptions['background'];\n\t/** Fixed canvas width. When set (with `height`), the canvas is fixed-size and the auto-resize default is suppressed. */\n\twidth?: ApplicationOptions['width'];\n\t/** Fixed canvas height. When set (with `width`), the canvas is fixed-size and the auto-resize default is suppressed. */\n\theight?: ApplicationOptions['height'];\n\t/** Escape hatch for raw PixiJS ApplicationOptions not otherwise exposed at the top level.\n\t * Top-level fields (`background`, `width`, `height`) take precedence when both are set. */\n\tpixiInit?: Partial<ApplicationOptions>;\n}\n\n/**\n * Configuration options for the 2D renderer plugin.\n *\n * Supports two modes:\n * 1. **Pre-initialized**: Pass an already-initialized Application via `app`\n * 2. **Managed**: Omit `app` and the plugin creates the Application during `ecs.initialize()`.\n * The canvas is appended to `container` (defaults to `document.body`) and auto-resizes to\n * match it. Pass `pixiInit: { width, height }` for a fixed-size canvas instead.\n *\n * This plugin includes transform propagation automatically - no need to add createTransformPlugin() separately.\n *\n * @example Pre-initialized mode (full control)\n * ```typescript\n * const app = new Application();\n * await app.init({ resizeTo: window });\n * const ecs = ECSpresso.create()\n * .withPlugin(createRenderer2DPlugin({ app }))\n * .withComponentTypes<{ player: true }>()\n * .build();\n * ```\n *\n * @example Managed mode (convenience)\n * ```typescript\n * const ecs = ECSpresso.create()\n * .withPlugin(createRenderer2DPlugin({\n * background: '#1099bb',\n * }))\n * .withComponentTypes<{ player: true }>()\n * .build();\n * await ecs.initialize(); // Application created here\n * ```\n */\nexport type Renderer2DPluginOptions<G extends string = 'renderer2d'> = Renderer2DPluginAppOptions<G> | Renderer2DPluginManagedOptions<G>;\n\n// ==================== Helper Utilities ====================\n\ninterface PositionOption {\n\tx?: number;\n\ty?: number;\n}\n\ninterface TransformOptions {\n\trotation?: number;\n\tscale?: number | { x: number; y: number };\n\tvisible?: boolean;\n\talpha?: number;\n}\n\nfunction createLocalTransformInternal(\n\tposition?: PositionOption,\n\toptions?: TransformOptions\n): LocalTransform {\n\tconst scaleValue = options?.scale;\n\tconst scaleX = typeof scaleValue === 'number'\n\t\t? scaleValue\n\t\t: scaleValue?.x ?? 1;\n\tconst scaleY = typeof scaleValue === 'number'\n\t\t? scaleValue\n\t\t: scaleValue?.y ?? 1;\n\n\treturn {\n\t\tx: position?.x ?? 0,\n\t\ty: position?.y ?? 0,\n\t\trotation: options?.rotation ?? 0,\n\t\tscaleX,\n\t\tscaleY,\n\t};\n}\n\nfunction createWorldTransformInternal(\n\tposition?: PositionOption,\n\toptions?: TransformOptions\n): WorldTransform {\n\tconst scaleValue = options?.scale;\n\tconst scaleX = typeof scaleValue === 'number'\n\t\t? scaleValue\n\t\t: scaleValue?.x ?? 1;\n\tconst scaleY = typeof scaleValue === 'number'\n\t\t? scaleValue\n\t\t: scaleValue?.y ?? 1;\n\n\treturn {\n\t\tx: position?.x ?? 0,\n\t\ty: position?.y ?? 0,\n\t\trotation: options?.rotation ?? 0,\n\t\tscaleX,\n\t\tscaleY,\n\t};\n}\n\nfunction createVisibleComponent(options?: TransformOptions): Visible {\n\treturn {\n\t\tvisible: options?.visible ?? true,\n\t\talpha: options?.alpha,\n\t};\n}\n\n/**\n * Create components for a sprite entity.\n * Returns an object suitable for spreading into spawn().\n *\n * @example\n * ```typescript\n * const player = ecs.spawn({\n * ...createSpriteComponents(new Sprite(texture), { x: 100, y: 100 }),\n * velocity: { x: 0, y: 0 },\n * });\n * ```\n */\nexport function createSpriteComponents(\n\tsprite: Sprite,\n\tposition?: PositionOption,\n\toptions?: TransformOptions & { anchor?: { x: number; y: number } }\n): Pick<Renderer2DComponentTypes, 'sprite' | 'localTransform' | 'worldTransform' | 'visible'> {\n\tif (options?.anchor) {\n\t\tsprite.anchor.set(options.anchor.x, options.anchor.y);\n\t}\n\treturn {\n\t\tsprite,\n\t\tlocalTransform: createLocalTransformInternal(position, options),\n\t\tworldTransform: createWorldTransformInternal(position, options),\n\t\tvisible: createVisibleComponent(options),\n\t};\n}\n\n/**\n * Create components for a graphics entity.\n * Returns an object suitable for spreading into spawn().\n *\n * @example\n * ```typescript\n * const rect = ecs.spawn({\n * ...createGraphicsComponents(graphics, { x: 50, y: 50 }),\n * });\n * ```\n */\nexport function createGraphicsComponents(\n\tgraphics: Graphics,\n\tposition?: PositionOption,\n\toptions?: TransformOptions\n): Pick<Renderer2DComponentTypes, 'graphics' | 'localTransform' | 'worldTransform' | 'visible'> {\n\treturn {\n\t\tgraphics,\n\t\tlocalTransform: createLocalTransformInternal(position, options),\n\t\tworldTransform: createWorldTransformInternal(position, options),\n\t\tvisible: createVisibleComponent(options),\n\t};\n}\n\n/**\n * Create components for a container entity.\n * Returns an object suitable for spreading into spawn().\n *\n * @example\n * ```typescript\n * const group = ecs.spawn({\n * ...createContainerComponents(new Container(), { x: 0, y: 0 }),\n * });\n * ```\n */\nexport function createContainerComponents(\n\tcontainer: Container,\n\tposition?: PositionOption,\n\toptions?: TransformOptions\n): Pick<Renderer2DComponentTypes, 'container' | 'localTransform' | 'worldTransform' | 'visible'> {\n\treturn {\n\t\tcontainer,\n\t\tlocalTransform: createLocalTransformInternal(position, options),\n\t\tworldTransform: createWorldTransformInternal(position, options),\n\t\tvisible: createVisibleComponent(options),\n\t};\n}\n\n// ==================== Viewport Scale Utilities ====================\n\nconst scaleModeStrategy: Record<ScaleMode, (ratioX: number, ratioY: number) => { scaleX: number; scaleY: number }> = {\n\tfit: (ratioX, ratioY) => {\n\t\tconst s = Math.min(ratioX, ratioY);\n\t\treturn { scaleX: s, scaleY: s };\n\t},\n\tcover: (ratioX, ratioY) => {\n\t\tconst s = Math.max(ratioX, ratioY);\n\t\treturn { scaleX: s, scaleY: s };\n\t},\n\tstretch: (ratioX, ratioY) => ({ scaleX: ratioX, scaleY: ratioY }),\n};\n\nexport function computeViewportScale(\n\tphysicalW: number,\n\tphysicalH: number,\n\tdesignW: number,\n\tdesignH: number,\n\tmode: ScaleMode,\n): ViewportScale {\n\tconst ratioX = physicalW / designW;\n\tconst ratioY = physicalH / designH;\n\tconst { scaleX, scaleY } = scaleModeStrategy[mode](ratioX, ratioY);\n\n\treturn {\n\t\tscaleX,\n\t\tscaleY,\n\t\toffsetX: (physicalW - designW * scaleX) / 2,\n\t\toffsetY: (physicalH - designH * scaleY) / 2,\n\t\tphysicalWidth: physicalW,\n\t\tphysicalHeight: physicalH,\n\t\tmode,\n\t\tdesignWidth: designW,\n\t\tdesignHeight: designH,\n\t};\n}\n\n/**\n * Convert physical canvas pixel coordinates to design-resolution (logical) coordinates.\n * Compose with camera `screenToWorld()` for full physical→world conversion.\n */\nexport function physicalToLogical(\n\tphysicalX: number,\n\tphysicalY: number,\n\tviewport: ViewportScale,\n): { x: number; y: number } {\n\treturn {\n\t\tx: (physicalX - viewport.offsetX) / viewport.scaleX,\n\t\ty: (physicalY - viewport.offsetY) / viewport.scaleY,\n\t};\n}\n\n/**\n * Convert a DOM pointer event's client coordinates to design-resolution (logical) coordinates.\n * Handles canvas offset, CSS-pixel to physical-pixel scaling, and viewport letterbox/crop offsets.\n * Suitable for wiring into the input plugin's `coordinateTransform` option.\n */\nexport function clientToLogical(\n\tclientX: number,\n\tclientY: number,\n\tcanvas: HTMLCanvasElement,\n\tviewport: ViewportScale,\n): { x: number; y: number } {\n\tconst rect = canvas.getBoundingClientRect();\n\tconst physicalX = (clientX - rect.left) * (viewport.physicalWidth / rect.width);\n\tconst physicalY = (clientY - rect.top) * (viewport.physicalHeight / rect.height);\n\treturn physicalToLogical(physicalX, physicalY, viewport);\n}\n\n/**\n * Re-apply the current viewport scale using the latest `mode` from the `viewportScale` resource.\n * Call after mutating `viewportScale.mode` to take effect immediately without waiting for a window resize.\n */\nexport function reapplyViewportScale(pixiApp: Application): void {\n\tpixiApp.renderer.emit('resize', pixiApp.screen.width, pixiApp.screen.height, pixiApp.renderer.resolution);\n}\n\n// ==================== Plugin Factory ====================\n\n/**\n * Create a 2D rendering plugin for ECSpresso.\n *\n * This plugin provides:\n * - Transform propagation (localTransform -> worldTransform)\n * - Render sync system (updates PixiJS objects from ECS components)\n * - Scene graph management (mirrors ECS hierarchy in PixiJS scene graph)\n *\n * @example Pre-initialized mode\n * ```typescript\n * const app = new Application();\n * await app.init({ resizeTo: window });\n *\n * const ecs = ECSpresso.create<GameComponents, {}, {}>()\n * .withPlugin(createRenderer2DPlugin({ app }))\n * .build();\n * ```\n *\n * @example Managed mode\n * ```typescript\n * const ecs = ECSpresso.create<GameComponents, {}, {}>()\n * .withPlugin(createRenderer2DPlugin({\n * background: '#1099bb',\n * }))\n * .build();\n * await ecs.initialize();\n * ```\n */\ntype Renderer2DLabels = 'renderer2d-sync' | 'renderer2d-scene-graph' | 'renderer2d-camera-sync' | 'transform-propagation';\ntype Renderer2DReactiveQueryNames = 'renderer2d-sprites' | 'renderer2d-graphics' | 'renderer2d-containers';\n\nexport function createRenderer2DPlugin<G extends string = 'renderer2d'>(\n\toptions: Renderer2DPluginOptions<G> & { screenScale: ScreenScaleOptions; camera: true }\n): Plugin<WorldConfigFrom<Renderer2DComponentTypes, Renderer2DEventTypes, Renderer2DResourceTypes & ViewportScaleResourceTypes & CameraResourceTypes>, EmptyConfig, Renderer2DLabels, G, never, Renderer2DReactiveQueryNames>;\nexport function createRenderer2DPlugin<G extends string = 'renderer2d'>(\n\toptions: Renderer2DPluginOptions<G> & { screenScale: ScreenScaleOptions }\n): Plugin<WorldConfigFrom<Renderer2DComponentTypes, Renderer2DEventTypes, Renderer2DResourceTypes & ViewportScaleResourceTypes>, EmptyConfig, Renderer2DLabels, G, never, Renderer2DReactiveQueryNames>;\nexport function createRenderer2DPlugin<G extends string = 'renderer2d'>(\n\toptions: Renderer2DPluginOptions<G> & { camera: true }\n): Plugin<WorldConfigFrom<Renderer2DComponentTypes, Renderer2DEventTypes, Renderer2DResourceTypes & CameraResourceTypes>, EmptyConfig, Renderer2DLabels, G, never, Renderer2DReactiveQueryNames>;\nexport function createRenderer2DPlugin<G extends string = 'renderer2d'>(\n\toptions: Renderer2DPluginOptions<G>\n): Plugin<WorldConfigFrom<Renderer2DComponentTypes, Renderer2DEventTypes, Renderer2DResourceTypes>, EmptyConfig, Renderer2DLabels, G, never, Renderer2DReactiveQueryNames>;\nexport function createRenderer2DPlugin<G extends string = 'renderer2d'>(\n\toptions: Renderer2DPluginOptions<G> & { camera?: boolean; screenScale?: ScreenScaleOptions }\n): Plugin<WorldConfigFrom<Renderer2DComponentTypes, Renderer2DEventTypes, Renderer2DResourceTypes>, EmptyConfig, Renderer2DLabels, G, never, Renderer2DReactiveQueryNames>\n| Plugin<WorldConfigFrom<Renderer2DComponentTypes, Renderer2DEventTypes, Renderer2DResourceTypes & CameraResourceTypes>, EmptyConfig, Renderer2DLabels, G, never, Renderer2DReactiveQueryNames>\n| Plugin<WorldConfigFrom<Renderer2DComponentTypes, Renderer2DEventTypes, Renderer2DResourceTypes & ViewportScaleResourceTypes>, EmptyConfig, Renderer2DLabels, G, never, Renderer2DReactiveQueryNames>\n| Plugin<WorldConfigFrom<Renderer2DComponentTypes, Renderer2DEventTypes, Renderer2DResourceTypes & ViewportScaleResourceTypes & CameraResourceTypes>, EmptyConfig, Renderer2DLabels, G, never, Renderer2DReactiveQueryNames> {\n\tconst {\n\t\trootContainer: customRootContainer,\n\t\tsystemGroup = 'renderer2d',\n\t\trenderSyncPriority = 500,\n\t\ttransform: transformOptions,\n\t\tstartLoop = true,\n\t\trenderLayers = [],\n\t\tcamera = false,\n\t\tscreenScale,\n\t} = options;\n\n\tconst hasScreenScale = screenScale !== undefined;\n\tconst designWidth = screenScale?.width ?? 0;\n\tconst designHeight = screenScale?.height ?? 0;\n\tconst screenScaleMode: ScaleMode = screenScale?.mode ?? 'fit';\n\n\t// Entity ID -> PixiJS Container mapping for scene graph management\n\tconst entityToPixiObject = new Map<number, Container>();\n\n\t// Render layer name -> PixiJS Container mapping\n\tconst layerContainers = new Map<string, Container>();\n\n\t// Container constructor captured during initialization via dynamic import\n\t// Used by getOrCreateLayerContainer for lazy layer creation\n\tlet createLayerContainer: (label: string) => Container = () => {\n\t\tthrow new Error('renderer2D: createLayerContainer called before initialization');\n\t};\n\n\t// Helper to get or create a render layer container\n\tfunction getOrCreateLayerContainer(\n\t\tlayerName: string,\n\t\trootCont: Container\n\t): Container {\n\t\tconst existing = layerContainers.get(layerName);\n\t\tif (existing) return existing;\n\n\t\t// Lazy-create for undeclared layers, appended to end\n\t\tconst cont = createLayerContainer(`layer:${layerName}`);\n\t\tlayerContainers.set(layerName, cont);\n\t\trootCont.addChild(cont);\n\t\treturn cont;\n\t}\n\n\t// Helper to resolve the target container for an entity.\n\t// Scene graph stays flat (rootContainer or render layer) because the render\n\t// sync positions objects using absolute worldTransform. Nesting under a\n\t// parent's display object would double-apply the parent's transform.\n\ttype PluginResourceTypes = Renderer2DResourceTypes & ViewportScaleResourceTypes;\n\ttype PluginECS = ECSpresso<WorldConfigFrom<Renderer2DComponentTypes, Renderer2DEventTypes, PluginResourceTypes>>;\n\n\tfunction resolveTargetContainer(\n\t\tentityId: number,\n\t\tecs: PluginECS\n\t): Container {\n\t\tconst rootCont = ecs.getResource('rootContainer');\n\n\t\t// 1. Check render layer component\n\t\tconst layerName = ecs.getComponent(entityId, 'renderLayer');\n\t\tif (layerName) return getOrCreateLayerContainer(layerName, rootCont);\n\n\t\t// 2. Fall back to root container\n\t\treturn rootCont;\n\t}\n\n\t// Helper to add a PixiJS object to the scene graph\n\tfunction addToSceneGraph(\n\t\tentityId: number,\n\t\tpixiObject: Container,\n\t\tecs: PluginECS\n\t): void {\n\t\tconst targetContainer = resolveTargetContainer(entityId, ecs);\n\n\t\t// Only add if not already a child\n\t\tif (pixiObject.parent !== targetContainer) {\n\t\t\ttargetContainer.addChild(pixiObject);\n\t\t}\n\t}\n\n\t// Helper to update parent in scene graph\n\tfunction updateSceneGraphParent(\n\t\tentityId: number,\n\t\tecs: PluginECS\n\t): void {\n\t\tconst pixiObject = entityToPixiObject.get(entityId);\n\t\tif (!pixiObject) return;\n\n\t\tconst targetContainer = resolveTargetContainer(entityId, ecs);\n\n\t\tif (pixiObject.parent !== targetContainer) {\n\t\t\tpixiObject.removeFromParent();\n\t\t\ttargetContainer.addChild(pixiObject);\n\t\t}\n\t}\n\n\t// Determine mode: pre-initialized if an Application instance was provided, otherwise managed\n\tconst isManaged = !('app' in options && options.app !== undefined);\n\n\treturn definePlugin('renderer2d')\n\t\t.withComponentTypes<Renderer2DComponentTypes>()\n\t\t.withEventTypes<Renderer2DEventTypes>()\n\t\t.withResourceTypes<PluginResourceTypes>()\n\t\t.withLabels<Renderer2DLabels>()\n\t\t.withGroups<G>()\n\t\t.withReactiveQueryNames<Renderer2DReactiveQueryNames>()\n\t\t.install((world) => {\n\t\t\t// Install transform plugin (deduplicates if already installed)\n\t\t\tworld.installPlugin(createTransformPlugin(transformOptions));\n\n\t\t\t// Register resources based on mode\n\t\t\tif (isManaged) {\n\t\t\t\tconst managedOptions = options as Renderer2DPluginManagedOptions<G>;\n\t\t\t\tconst { pixiInit, background, width, height } = managedOptions;\n\t\t\t\tconst containerOption = managedOptions.container ?? document.body;\n\n\t\t\t\tconst containerEl: HTMLElement | null = typeof containerOption === 'string'\n\t\t\t\t\t? document.querySelector<HTMLElement>(containerOption)\n\t\t\t\t\t: containerOption;\n\n\t\t\t\t// Top-level background/width/height override pixiInit equivalents.\n\t\t\t\tconst mergedPixiInit: Partial<ApplicationOptions> = {\n\t\t\t\t\t...pixiInit,\n\t\t\t\t\t...(background !== undefined && { background }),\n\t\t\t\t\t...(width !== undefined && { width }),\n\t\t\t\t\t...(height !== undefined && { height }),\n\t\t\t\t};\n\n\t\t\t\t// Default resizeTo to the resolved container unless the caller opted into a\n\t\t\t\t// fixed-size canvas via width/height, or set pixiInit.resizeTo directly.\n\t\t\t\tconst shouldDefaultResizeTo = containerEl !== null\n\t\t\t\t\t&& mergedPixiInit.resizeTo === undefined\n\t\t\t\t\t&& mergedPixiInit.width === undefined\n\t\t\t\t\t&& mergedPixiInit.height === undefined;\n\n\t\t\t\tconst finalInitOptions: Partial<ApplicationOptions> = {\n\t\t\t\t\t...mergedPixiInit,\n\t\t\t\t\t...(shouldDefaultResizeTo && { resizeTo: containerEl }),\n\t\t\t\t};\n\n\t\t\t\tworld.addResource('pixiApp', async () => {\n\t\t\t\t\tconst app = await createPixiApplication(finalInitOptions);\n\n\t\t\t\t\tif (containerEl) {\n\t\t\t\t\t\tcontainerEl.appendChild(app.canvas);\n\t\t\t\t\t} else if (typeof containerOption === 'string') {\n\t\t\t\t\t\tconsole.warn(`Renderer2D plugin: container selector \"${containerOption}\" not found`);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn app;\n\t\t\t\t});\n\n\t\t\t\tworld.addResource('rootContainer', {\n\t\t\t\t\tdependsOn: ['pixiApp'],\n\t\t\t\t\tfactory: (ecs) => customRootContainer ?? ecs.getResource('pixiApp').stage,\n\t\t\t\t});\n\n\t\t\t\tworld.addResource('bounds', {\n\t\t\t\t\tdependsOn: ['pixiApp'],\n\t\t\t\t\tfactory: (ecs) => {\n\t\t\t\t\t\tif (hasScreenScale) return createBounds(designWidth, designHeight);\n\t\t\t\t\t\tconst pixiApp = ecs.getResource('pixiApp');\n\t\t\t\t\t\treturn createBounds(pixiApp.screen.width, pixiApp.screen.height);\n\t\t\t\t\t},\n\t\t\t\t});\n\n\t\t\t\tif (hasScreenScale) {\n\t\t\t\t\tworld.addResource('viewportScale', {\n\t\t\t\t\t\tdependsOn: ['pixiApp'],\n\t\t\t\t\t\tfactory: (ecs) => {\n\t\t\t\t\t\t\tconst pixiApp = ecs.getResource('pixiApp');\n\t\t\t\t\t\t\treturn computeViewportScale(pixiApp.screen.width, pixiApp.screen.height, designWidth, designHeight, screenScaleMode);\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst app = (options as Renderer2DPluginAppOptions<G>).app;\n\t\t\t\tworld.addResource('pixiApp', app);\n\t\t\t\tworld.addResource('rootContainer', customRootContainer ?? app.stage);\n\t\t\t\tworld.addResource('bounds', hasScreenScale\n\t\t\t\t\t? createBounds(designWidth, designHeight)\n\t\t\t\t\t: createBounds(app.screen.width, app.screen.height));\n\n\t\t\t\tif (hasScreenScale) {\n\t\t\t\t\tworld.addResource('viewportScale',\n\t\t\t\t\t\tcomputeViewportScale(app.screen.width, app.screen.height, designWidth, designHeight, screenScaleMode));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Register dispose callbacks for display object components\n\t\t\tworld.registerDispose('sprite', ({ value: sprite }) => {\n\t\t\t\tsprite.removeFromParent();\n\t\t\t});\n\t\t\tworld.registerDispose('graphics', ({ value: graphics }) => {\n\t\t\t\tgraphics.removeFromParent();\n\t\t\t});\n\t\t\tworld.registerDispose('container', ({ value: container }) => {\n\t\t\t\tcontainer.removeFromParent();\n\t\t\t});\n\n\t\t\t// Display objects require localTransform and visible\n\t\t\tworld.registerRequired('sprite', 'localTransform', () => createLocalTransformInternal());\n\t\t\tworld.registerRequired('sprite', 'visible', () => createVisibleComponent());\n\t\t\tworld.registerRequired('graphics', 'localTransform', () => createLocalTransformInternal());\n\t\t\tworld.registerRequired('graphics', 'visible', () => createVisibleComponent());\n\t\t\tworld.registerRequired('container', 'localTransform', () => createLocalTransformInternal());\n\t\t\tworld.registerRequired('container', 'visible', () => createVisibleComponent());\n\n\t\t\t// ==================== Render Sync System ====================\n\t\t\tworld\n\t\t\t\t.addSystem('renderer2d-sync')\n\t\t\t\t.setPriority(renderSyncPriority)\n\t\t\t\t.inPhase('render')\n\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t.addQuery('sprites', {\n\t\t\t\t\twith: ['sprite', 'worldTransform'],\n\t\t\t\t\tchanged: ['worldTransform'],\n\t\t\t\t})\n\t\t\t\t.addQuery('graphics', {\n\t\t\t\t\twith: ['graphics', 'worldTransform'],\n\t\t\t\t\tchanged: ['worldTransform'],\n\t\t\t\t})\n\t\t\t\t.addQuery('containers', {\n\t\t\t\t\twith: ['container', 'worldTransform'],\n\t\t\t\t\tchanged: ['worldTransform'],\n\t\t\t\t})\n\t\t\t\t.setProcess(({ queries, ecs }) => {\n\t\t\t\t\tfor (const entity of queries.sprites) {\n\t\t\t\t\t\tconst { sprite, worldTransform } = entity.components;\n\n\t\t\t\t\t\tsprite.position.set(worldTransform.x, worldTransform.y);\n\t\t\t\t\t\tsprite.rotation = worldTransform.rotation;\n\t\t\t\t\t\tsprite.scale.set(worldTransform.scaleX, worldTransform.scaleY);\n\n\t\t\t\t\t\tconst visibleComp = ecs.getComponent(entity.id, 'visible');\n\t\t\t\t\t\tif (visibleComp) {\n\t\t\t\t\t\t\tsprite.visible = visibleComp.visible;\n\t\t\t\t\t\t\tif (visibleComp.alpha !== undefined) {\n\t\t\t\t\t\t\t\tsprite.alpha = visibleComp.alpha;\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\tfor (const entity of queries.graphics) {\n\t\t\t\t\t\tconst { graphics, worldTransform } = entity.components;\n\n\t\t\t\t\t\tgraphics.position.set(worldTransform.x, worldTransform.y);\n\t\t\t\t\t\tgraphics.rotation = worldTransform.rotation;\n\t\t\t\t\t\tgraphics.scale.set(worldTransform.scaleX, worldTransform.scaleY);\n\n\t\t\t\t\t\tconst visibleComp = ecs.getComponent(entity.id, 'visible');\n\t\t\t\t\t\tif (visibleComp) {\n\t\t\t\t\t\t\tgraphics.visible = visibleComp.visible;\n\t\t\t\t\t\t\tif (visibleComp.alpha !== undefined) {\n\t\t\t\t\t\t\t\tgraphics.alpha = visibleComp.alpha;\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\tfor (const entity of queries.containers) {\n\t\t\t\t\t\tconst { container, worldTransform } = entity.components;\n\n\t\t\t\t\t\tcontainer.position.set(worldTransform.x, worldTransform.y);\n\t\t\t\t\t\tcontainer.rotation = worldTransform.rotation;\n\t\t\t\t\t\tcontainer.scale.set(worldTransform.scaleX, worldTransform.scaleY);\n\n\t\t\t\t\t\tconst visibleComp = ecs.getComponent(entity.id, 'visible');\n\t\t\t\t\t\tif (visibleComp) {\n\t\t\t\t\t\t\tcontainer.visible = visibleComp.visible;\n\t\t\t\t\t\t\tif (visibleComp.alpha !== undefined) {\n\t\t\t\t\t\t\t\tcontainer.alpha = visibleComp.alpha;\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// ==================== Scene Graph Manager System ====================\n\t\t\tworld\n\t\t\t\t.addSystem('renderer2d-scene-graph')\n\t\t\t\t.setPriority(9999)\n\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t.setOnInitialize(async (ecs) => {\n\t\t\t\t\tconst pixiApp = ecs.getResource('pixiApp');\n\t\t\t\t\tlet rootCont = ecs.getResource('rootContainer');\n\n\t\t\t\t\tconst { Container: ContainerClass } = await import('pixi.js');\n\t\t\t\t\tcreateLayerContainer = (label: string) => {\n\t\t\t\t\t\tconst cont = new ContainerClass();\n\t\t\t\t\t\tcont.label = label;\n\t\t\t\t\t\treturn cont;\n\t\t\t\t\t};\n\n\t\t\t\t\tlet viewportContainer: Container | undefined;\n\t\t\t\t\tif (hasScreenScale) {\n\t\t\t\t\t\tviewportContainer = new ContainerClass();\n\t\t\t\t\t\tviewportContainer.label = 'viewportContainer';\n\n\t\t\t\t\t\tconst vs = ecs.tryGetResource('viewportScale');\n\t\t\t\t\t\tif (!vs) throw new Error('renderer2D: viewportScale resource not found');\n\t\t\t\t\t\tviewportContainer.position.set(vs.offsetX, vs.offsetY);\n\t\t\t\t\t\tviewportContainer.scale.set(vs.scaleX, vs.scaleY);\n\n\t\t\t\t\t\tconst newRoot = new ContainerClass();\n\t\t\t\t\t\tnewRoot.label = 'rootContainer';\n\n\t\t\t\t\t\tpixiApp.stage.addChild(viewportContainer);\n\t\t\t\t\t\tviewportContainer.addChild(newRoot);\n\n\t\t\t\t\t\tecs.updateResource('rootContainer', () => newRoot);\n\t\t\t\t\t\trootCont = newRoot;\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (const layerName of renderLayers) {\n\t\t\t\t\t\tconst cont = createLayerContainer(`layer:${layerName}`);\n\t\t\t\t\t\tlayerContainers.set(layerName, cont);\n\t\t\t\t\t\trootCont.addChild(cont);\n\t\t\t\t\t}\n\n\t\t\t\t\tecs.addReactiveQuery('renderer2d-sprites', {\n\t\t\t\t\t\twith: ['sprite'],\n\t\t\t\t\t\tonEnter: (entity) => {\n\t\t\t\t\t\t\tconst pixiObject = entity.components.sprite;\n\t\t\t\t\t\t\tentityToPixiObject.set(entity.id, pixiObject);\n\t\t\t\t\t\t\taddToSceneGraph(entity.id, pixiObject, ecs);\n\t\t\t\t\t\t},\n\t\t\t\t\t\tonExit: (entityId) => {\n\t\t\t\t\t\t\tentityToPixiObject.delete(entityId);\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\n\t\t\t\t\tecs.addReactiveQuery('renderer2d-graphics', {\n\t\t\t\t\t\twith: ['graphics'],\n\t\t\t\t\t\tonEnter: (entity) => {\n\t\t\t\t\t\t\tconst pixiObject = entity.components.graphics;\n\t\t\t\t\t\t\tentityToPixiObject.set(entity.id, pixiObject);\n\t\t\t\t\t\t\taddToSceneGraph(entity.id, pixiObject, ecs);\n\t\t\t\t\t\t},\n\t\t\t\t\t\tonExit: (entityId) => {\n\t\t\t\t\t\t\tentityToPixiObject.delete(entityId);\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\n\t\t\t\t\tecs.addReactiveQuery('renderer2d-containers', {\n\t\t\t\t\t\twith: ['container'],\n\t\t\t\t\t\tonEnter: (entity) => {\n\t\t\t\t\t\t\tconst pixiObject = entity.components.container;\n\t\t\t\t\t\t\tentityToPixiObject.set(entity.id, pixiObject);\n\t\t\t\t\t\t\taddToSceneGraph(entity.id, pixiObject, ecs);\n\t\t\t\t\t\t},\n\t\t\t\t\t\tonExit: (entityId) => {\n\t\t\t\t\t\t\tentityToPixiObject.delete(entityId);\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\n\t\t\t\t\tecs.on('hierarchyChanged', ({ entityId }) => {\n\t\t\t\t\t\tupdateSceneGraphParent(entityId, ecs);\n\t\t\t\t\t});\n\n\t\t\t\t\tecs.onComponentAdded('renderLayer', ({ entity }) => {\n\t\t\t\t\t\tupdateSceneGraphParent(entity.id, ecs);\n\t\t\t\t\t});\n\n\t\t\t\t\tecs.onComponentRemoved('renderLayer', ({ entity }) => {\n\t\t\t\t\t\tupdateSceneGraphParent(entity.id, ecs);\n\t\t\t\t\t});\n\n\t\t\t\t\tif (camera) {\n\t\t\t\t\t\tconst cameraState = ecs.tryGetResource<CameraState>('cameraState');\n\t\t\t\t\t\tif (!cameraState) throw new Error('renderer2D: cameraState resource not found');\n\t\t\t\t\t\tcameraState.viewportWidth = hasScreenScale ? designWidth : pixiApp.screen.width;\n\t\t\t\t\t\tcameraState.viewportHeight = hasScreenScale ? designHeight : pixiApp.screen.height;\n\t\t\t\t\t}\n\n\t\t\t\t\tpixiApp.renderer.on('resize', (width: number, height: number) => {\n\t\t\t\t\t\tif (hasScreenScale) {\n\t\t\t\t\t\t\tconst vpResource = ecs.tryGetResource('viewportScale');\n\t\t\t\t\t\t\tif (!vpResource) throw new Error('renderer2D: viewportScale resource not found');\n\t\t\t\t\t\t\tconst vs = computeViewportScale(width, height, designWidth, designHeight, vpResource.mode);\n\t\t\t\t\t\t\tvpResource.scaleX = vs.scaleX;\n\t\t\t\t\t\t\tvpResource.scaleY = vs.scaleY;\n\t\t\t\t\t\t\tvpResource.offsetX = vs.offsetX;\n\t\t\t\t\t\t\tvpResource.offsetY = vs.offsetY;\n\t\t\t\t\t\t\tvpResource.physicalWidth = width;\n\t\t\t\t\t\t\tvpResource.physicalHeight = height;\n\n\t\t\t\t\t\t\tif (viewportContainer) {\n\t\t\t\t\t\t\t\tviewportContainer.position.set(vs.offsetX, vs.offsetY);\n\t\t\t\t\t\t\t\tviewportContainer.scale.set(vs.scaleX, vs.scaleY);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconst bounds = ecs.getResource('bounds');\n\t\t\t\t\t\t\tbounds.width = width;\n\t\t\t\t\t\t\tbounds.height = height;\n\n\t\t\t\t\t\t\tif (camera) {\n\t\t\t\t\t\t\t\tconst cameraState = ecs.tryGetResource<CameraState>('cameraState');\n\t\t\t\t\t\t\t\tif (!cameraState) throw new Error('renderer2D: cameraState resource not found');\n\t\t\t\t\t\t\t\tcameraState.viewportWidth = width;\n\t\t\t\t\t\t\t\tcameraState.viewportHeight = height;\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\tif (startLoop) {\n\t\t\t\t\t\tpixiApp.ticker.add((ticker) => {\n\t\t\t\t\t\t\tecs.update(ticker.deltaMS / 1_000);\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t// ==================== Camera Sync System (opt-in) ====================\n\t\t\tif (camera) {\n\t\t\t\tworld\n\t\t\t\t\t.addSystem('renderer2d-camera-sync')\n\t\t\t\t\t.setPriority(900)\n\t\t\t\t\t.inPhase('render')\n\t\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t\t.setProcess(({ ecs }) => {\n\t\t\t\t\t\tconst state = ecs.tryGetResource<CameraState>('cameraState');\n\t\t\t\t\t\tif (!state) throw new Error('renderer2D: cameraState resource not found');\n\t\t\t\t\t\tconst root = ecs.getResource('rootContainer');\n\t\t\t\t\t\tconst [centerW, centerH] = hasScreenScale\n\t\t\t\t\t\t\t? [designWidth, designHeight]\n\t\t\t\t\t\t\t: [ecs.getResource('pixiApp').screen.width, ecs.getResource('pixiApp').screen.height];\n\n\t\t\t\t\t\troot.position.set(\n\t\t\t\t\t\t\tcenterW / 2 - (state.x + state.shakeOffsetX) * state.zoom,\n\t\t\t\t\t\t\tcenterH / 2 - (state.y + state.shakeOffsetY) * state.zoom,\n\t\t\t\t\t\t);\n\t\t\t\t\t\troot.scale.set(state.zoom);\n\t\t\t\t\t\troot.rotation = -(state.rotation + state.shakeRotation);\n\t\t\t\t\t});\n\t\t\t}\n\t\t});\n}\n"
6
- ],
7
- "mappings": "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",
8
- "debugId": "7DB3035D86BB48ED64756E2164756E21",
9
- "names": []
10
- }
@@ -1,10 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/plugins/transform.ts"],
4
- "sourcesContent": [
5
- "/**\n * Transform Plugin for ECSpresso\n *\n * Provides hierarchical transform propagation following Bevy's Transform/GlobalTransform pattern.\n * LocalTransform is modified by user code; WorldTransform is computed automatically.\n *\n * @see https://docs.rs/bevy/latest/bevy/transform/components/struct.GlobalTransform.html\n */\n\nimport { definePlugin, type BasePluginOptions } from 'ecspresso';\nimport type ECSpresso from 'ecspresso';\nimport type { WorldConfigFrom } from '../type-utils';\n\n// ==================== Component Types ====================\n\n/**\n * Local transform relative to parent (or world if no parent).\n * This is the transform you modify directly.\n */\nexport interface LocalTransform {\n\tx: number;\n\ty: number;\n\trotation: number;\n\tscaleX: number;\n\tscaleY: number;\n}\n\n/**\n * Computed world transform (accumulated from parent chain).\n * Read-only - managed by the transform propagation system.\n */\nexport interface WorldTransform {\n\tx: number;\n\ty: number;\n\trotation: number;\n\tscaleX: number;\n\tscaleY: number;\n}\n\n/**\n * Component types provided by the transform plugin.\n * Included automatically via `.withPlugin(createTransformPlugin())`.\n *\n * @example\n * ```typescript\n * const ecs = ECSpresso.create()\n * .withPlugin(createTransformPlugin())\n * .withComponentTypes<{ sprite: Sprite; velocity: { x: number; y: number } }>()\n * .build();\n * ```\n */\nexport interface TransformComponentTypes {\n\tlocalTransform: LocalTransform;\n\tworldTransform: WorldTransform;\n}\n\n/**\n * WorldConfig representing the transform plugin's provided components.\n * Used as the `Requires` type parameter by plugins that depend on transform.\n */\nexport type TransformWorldConfig = WorldConfigFrom<TransformComponentTypes>;\n\n// ==================== Plugin Options ====================\n\n/**\n * Configuration options for the transform plugin.\n */\nexport interface TransformPluginOptions<G extends string = 'transform'> extends BasePluginOptions<G> {}\n\n// ==================== Default Values ====================\n\n/**\n * Default local transform values.\n */\nexport const DEFAULT_LOCAL_TRANSFORM: Readonly<LocalTransform> = {\n\tx: 0,\n\ty: 0,\n\trotation: 0,\n\tscaleX: 1,\n\tscaleY: 1,\n};\n\n/**\n * Default world transform values.\n */\nexport const DEFAULT_WORLD_TRANSFORM: Readonly<WorldTransform> = {\n\tx: 0,\n\ty: 0,\n\trotation: 0,\n\tscaleX: 1,\n\tscaleY: 1,\n};\n\n// ==================== Helper Functions ====================\n\n/**\n * Create a local transform component with position only.\n * Uses default rotation (0) and scale (1, 1).\n *\n * @param x The x coordinate\n * @param y The y coordinate\n * @returns Component object suitable for spreading into spawn()\n *\n * @example\n * ```typescript\n * ecs.spawn({\n * ...createLocalTransform(100, 200),\n * sprite,\n * });\n * ```\n */\nexport function createLocalTransform(x: number, y: number): Pick<TransformComponentTypes, 'localTransform'> {\n\treturn {\n\t\tlocalTransform: {\n\t\t\tx,\n\t\t\ty,\n\t\t\trotation: 0,\n\t\t\tscaleX: 1,\n\t\t\tscaleY: 1,\n\t\t},\n\t};\n}\n\n/**\n * Create a world transform component with position only.\n * Typically used alongside createLocalTransform for initial state.\n *\n * @param x The x coordinate\n * @param y The y coordinate\n * @returns Component object suitable for spreading into spawn()\n */\nexport function createWorldTransform(x: number, y: number): Pick<TransformComponentTypes, 'worldTransform'> {\n\treturn {\n\t\tworldTransform: {\n\t\t\tx,\n\t\t\ty,\n\t\t\trotation: 0,\n\t\t\tscaleX: 1,\n\t\t\tscaleY: 1,\n\t\t},\n\t};\n}\n\n/**\n * Options for creating a full transform.\n */\nexport interface TransformOptions {\n\trotation?: number;\n\tscaleX?: number;\n\tscaleY?: number;\n\t/** Uniform scale (overrides scaleX/scaleY if provided) */\n\tscale?: number;\n}\n\n/**\n * Create both local and world transform components.\n * World transform is initialized to match local transform.\n *\n * @param x The x coordinate\n * @param y The y coordinate\n * @param options Optional rotation and scale\n * @returns Component object suitable for spreading into spawn()\n *\n * @example\n * ```typescript\n * ecs.spawn({\n * ...createTransform(100, 200),\n * sprite,\n * });\n *\n * // With rotation and scale\n * ecs.spawn({\n * ...createTransform(100, 200, { rotation: Math.PI / 4, scale: 2 }),\n * sprite,\n * });\n * ```\n */\nexport function createTransform(\n\tx: number,\n\ty: number,\n\toptions?: TransformOptions\n): TransformComponentTypes {\n\tconst scaleX = options?.scale ?? options?.scaleX ?? 1;\n\tconst scaleY = options?.scale ?? options?.scaleY ?? 1;\n\tconst rotation = options?.rotation ?? 0;\n\n\tconst transform = {\n\t\tx,\n\t\ty,\n\t\trotation,\n\t\tscaleX,\n\t\tscaleY,\n\t};\n\n\treturn {\n\t\tlocalTransform: { ...transform },\n\t\tworldTransform: { ...transform },\n\t};\n}\n\n// ==================== Plugin Factory ====================\n\n/**\n * Create a transform plugin for ECSpresso.\n *\n * This plugin provides:\n * - Transform propagation system that computes world transforms from local transforms\n * - Parent-first traversal ensures parents are processed before children\n * - Supports full transform hierarchy (position, rotation, scale)\n *\n * @example\n * ```typescript\n * const ecs = ECSpresso\n * .create<Components, Events, Resources>()\n * .withPlugin(createTransformPlugin())\n * .withPlugin(createPhysics2DPlugin())\n * .build();\n *\n * // Spawn entity with transform\n * ecs.spawn({\n * ...createTransform(100, 200),\n * velocity: { x: 50, y: 0 },\n * });\n * ```\n */\nexport function createTransformPlugin<G extends string = 'transform'>(\n\toptions?: TransformPluginOptions<G>\n) {\n\tconst {\n\t\tsystemGroup = 'transform',\n\t\tpriority = 500,\n\t\tphase = 'postUpdate',\n\t} = options ?? {};\n\n\treturn definePlugin('transform')\n\t\t.withComponentTypes<TransformComponentTypes>()\n\t\t.withLabels<'transform-propagation'>()\n\t\t.withGroups<G>()\n\t\t.install((world) => {\n\t\t\t// localTransform requires worldTransform — initialize from localTransform values\n\t\t\tworld.registerRequired('localTransform', 'worldTransform', (lt) => ({\n\t\t\t\tx: lt.x, y: lt.y, rotation: lt.rotation, scaleX: lt.scaleX, scaleY: lt.scaleY,\n\t\t\t}));\n\n\t\t\tconst orphanBuffer: Array<import('../types').FilteredEntity<TransformComponentTypes, 'localTransform' | 'worldTransform'>> = [];\n\n\t\t\tworld\n\t\t\t\t.addSystem('transform-propagation')\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.setProcess(({ ecs }) => {\n\t\t\t\t\tpropagateTransforms(ecs, orphanBuffer);\n\t\t\t\t});\n\t\t});\n}\n\n/**\n * Propagate transforms through the hierarchy.\n * Parent-first traversal ensures parents are computed before children.\n *\n * Runs unconditionally for all entities with transforms — user code can\n * freely mutate localTransform without needing to call markChanged.\n * Marks worldTransform as changed so downstream systems (e.g. renderer\n * sync) pick up the updated values.\n */\nfunction propagateTransforms(\n\tecs: ECSpresso<WorldConfigFrom<TransformComponentTypes>>,\n\torphanBuffer: Array<import('../types').FilteredEntity<TransformComponentTypes, 'localTransform' | 'worldTransform'>>,\n): void {\n\tconst em = ecs.entityManager;\n\n\t// Use parent-first traversal for entities in hierarchy\n\tecs.forEachInHierarchy((entityId, parentId) => {\n\t\tconst localTransform = em.getComponent(entityId, 'localTransform');\n\t\tconst worldTransform = em.getComponent(entityId, 'worldTransform');\n\n\t\tif (!localTransform || !worldTransform) return;\n\n\t\tif (parentId === null) {\n\t\t\t// Root entity: world transform equals local transform\n\t\t\tcopyTransform(localTransform, worldTransform);\n\t\t} else {\n\t\t\t// Child entity: combine with parent's world transform\n\t\t\tconst parentWorld = em.getComponent(parentId, 'worldTransform');\n\t\t\tif (parentWorld) {\n\t\t\t\tcombineTransforms(parentWorld, localTransform, worldTransform);\n\t\t\t} else {\n\t\t\t\t// Parent has no world transform, treat as root\n\t\t\t\tcopyTransform(localTransform, worldTransform);\n\t\t\t}\n\t\t}\n\n\t\tecs.markChanged(entityId, 'worldTransform');\n\t});\n\n\t// Process orphaned entities (not in hierarchy but have transforms)\n\tem.getEntitiesWithQueryInto(orphanBuffer, ['localTransform', 'worldTransform']);\n\tfor (const entity of orphanBuffer) {\n\t\tconst parentId = ecs.getParent(entity.id);\n\t\t// Only process if truly orphaned (no parent and not a root with children)\n\t\tif (parentId === null && ecs.getChildren(entity.id).length === 0) {\n\t\t\tconst { localTransform, worldTransform } = entity.components;\n\t\t\tcopyTransform(localTransform, worldTransform);\n\t\t\tecs.markChanged(entity.id, 'worldTransform');\n\t\t}\n\t}\n}\n\n/**\n * Copy transform values from source to destination.\n */\nfunction copyTransform(src: LocalTransform, dest: WorldTransform): void {\n\tdest.x = src.x;\n\tdest.y = src.y;\n\tdest.rotation = src.rotation;\n\tdest.scaleX = src.scaleX;\n\tdest.scaleY = src.scaleY;\n}\n\n/**\n * Combine parent world transform with child local transform into child world transform.\n */\nfunction combineTransforms(\n\tparent: WorldTransform,\n\tlocal: LocalTransform,\n\tworld: WorldTransform\n): void {\n\t// Apply parent's scale to local position\n\tconst scaledLocalX = local.x * parent.scaleX;\n\tconst scaledLocalY = local.y * parent.scaleY;\n\n\t// Rotate local position by parent's rotation\n\tconst cos = Math.cos(parent.rotation);\n\tconst sin = Math.sin(parent.rotation);\n\tconst rotatedX = scaledLocalX * cos - scaledLocalY * sin;\n\tconst rotatedY = scaledLocalX * sin + scaledLocalY * cos;\n\n\t// Add to parent's position\n\tworld.x = parent.x + rotatedX;\n\tworld.y = parent.y + rotatedY;\n\tworld.rotation = parent.rotation + local.rotation;\n\tworld.scaleX = parent.scaleX * local.scaleX;\n\tworld.scaleY = parent.scaleY * local.scaleY;\n}\n"
6
- ],
7
- "mappings": "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",
8
- "debugId": "7C2E80F6F657F59964756E2164756E21",
9
- "names": []
10
- }
@@ -1,11 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/plugins/tween.ts", "../src/utils/easing.ts"],
4
- "sourcesContent": [
5
- "/**\n * Tween Plugin for ECSpresso\n *\n * Declarative property animation within the ECS. Tween any numeric component\n * field over time with standard easing functions, sequences, and completion events.\n */\n\nimport { definePlugin, type BasePluginOptions } from 'ecspresso';\nimport type { ComponentsOfWorld, AnyECSpresso } from 'ecspresso';\nimport { linear, type EasingFn } from '../utils/easing';\n\n// ==================== Event Types ====================\n\n/**\n * Data structure published when a tween completes.\n * Use this type when defining tween completion events in your EventTypes interface.\n */\nexport interface TweenEventData {\n\t/** The entity ID the tween belongs to */\n\tentityId: number;\n\t/** Number of steps in the tween */\n\tstepCount: number;\n}\n\n\n// ==================== Component Types ====================\n\nexport interface TweenTarget {\n\t/** Component name on the entity */\n\tcomponent: string;\n\t/** Pre-split field path (e.g., ['position', 'x']) */\n\tpath: readonly string[];\n\t/** Starting value. null = resolve from current value on first tick */\n\tfrom: number | null;\n\t/** Target value */\n\tto: number;\n}\n\nexport interface TweenStep {\n\ttargets: TweenTarget[];\n\tduration: number;\n\teasing: EasingFn;\n}\n\nexport interface Tween {\n\tsteps: TweenStep[];\n\tcurrentStep: number;\n\telapsed: number;\n\tloop: LoopMode;\n\ttotalLoops: number;\n\tcompletedLoops: number;\n\tdirection: 1 | -1;\n\tstate: 'pending' | 'active' | 'complete';\n\tonComplete?: (data: TweenEventData) => void;\n\tjustFinished: boolean;\n}\n\nexport type LoopMode = 'once' | 'loop' | 'yoyo';\n\n/**\n * Component types provided by the tween plugin.\n */\nexport interface TweenComponentTypes {\n\ttween: Tween;\n}\n\n// ==================== Plugin Options ====================\n\nexport interface TweenPluginOptions<G extends string = 'tweens'> extends BasePluginOptions<G> {}\n\n// ==================== Helper Functions ====================\n\nexport interface TweenOptions {\n\t/** Explicit starting value (default: captures current value on first tick) */\n\tfrom?: number;\n\t/** Easing function (default: linear) */\n\teasing?: EasingFn;\n\t/** Loop mode (default: 'once') */\n\tloop?: LoopMode;\n\t/** Number of loops. -1 = infinite (default: 1) */\n\tloops?: number;\n\t/** Callback invoked when tween completes */\n\tonComplete?: (data: TweenEventData) => void;\n}\n\n/**\n * Create a single-target tween component.\n *\n * @param component Component name on the entity\n * @param field Field path (dot-separated for nested, e.g. 'position.x')\n * @param to Target value\n * @param duration Duration in seconds\n * @param options Optional configuration\n * @returns Component object suitable for spreading into spawn()\n */\nexport function createTween(\n\tcomponent: string,\n\tfield: string,\n\tto: number,\n\tduration: number,\n\toptions?: TweenOptions,\n): Pick<TweenComponentTypes, 'tween'> {\n\tconst {\n\t\tfrom,\n\t\teasing = linear,\n\t\tloop = 'once',\n\t\tloops = 1,\n\t\tonComplete,\n\t} = options ?? {};\n\n\treturn {\n\t\ttween: {\n\t\t\tsteps: [{\n\t\t\t\ttargets: [{\n\t\t\t\t\tcomponent,\n\t\t\t\t\tpath: field.split('.'),\n\t\t\t\t\tfrom: from ?? null,\n\t\t\t\t\tto,\n\t\t\t\t}],\n\t\t\t\tduration,\n\t\t\t\teasing,\n\t\t\t}],\n\t\t\tcurrentStep: 0,\n\t\t\telapsed: 0,\n\t\t\tloop,\n\t\t\ttotalLoops: loops,\n\t\t\tcompletedLoops: 0,\n\t\t\tdirection: 1,\n\t\t\tstate: 'pending',\n\t\t\tonComplete,\n\t\t\tjustFinished: false,\n\t\t},\n\t};\n}\n\nexport interface TweenSequenceStepInput {\n\ttargets: ReadonlyArray<{\n\t\tcomponent: string;\n\t\tfield: string;\n\t\tto: number;\n\t\tfrom?: number;\n\t}>;\n\tduration: number;\n\teasing?: EasingFn;\n}\n\nexport interface TweenSequenceOptions {\n\t/** Loop mode (default: 'once') */\n\tloop?: LoopMode;\n\t/** Number of loops. -1 = infinite (default: 1) */\n\tloops?: number;\n\t/** Callback invoked when tween completes */\n\tonComplete?: (data: TweenEventData) => void;\n}\n\n/**\n * Create a multi-step tween sequence. Each step can have parallel targets.\n *\n * @param steps Array of step definitions\n * @param options Optional configuration\n * @returns Component object suitable for spreading into spawn()\n */\nexport function createTweenSequence(\n\tsteps: ReadonlyArray<TweenSequenceStepInput>,\n\toptions?: TweenSequenceOptions,\n): Pick<TweenComponentTypes, 'tween'> {\n\tconst {\n\t\tloop = 'once',\n\t\tloops = 1,\n\t\tonComplete,\n\t} = options ?? {};\n\n\treturn {\n\t\ttween: {\n\t\t\tsteps: steps.map((step) => ({\n\t\t\t\ttargets: step.targets.map((target) => ({\n\t\t\t\t\tcomponent: target.component,\n\t\t\t\t\tpath: target.field.split('.'),\n\t\t\t\t\tfrom: target.from ?? null,\n\t\t\t\t\tto: target.to,\n\t\t\t\t})),\n\t\t\t\tduration: step.duration,\n\t\t\t\teasing: step.easing ?? linear,\n\t\t\t})),\n\t\t\tcurrentStep: 0,\n\t\t\telapsed: 0,\n\t\t\tloop,\n\t\t\ttotalLoops: loops,\n\t\t\tcompletedLoops: 0,\n\t\t\tdirection: 1,\n\t\t\tstate: 'pending',\n\t\t\tonComplete,\n\t\t\tjustFinished: false,\n\t\t},\n\t};\n}\n\n// ==================== Kit Types ====================\n\n/**\n * Recursively produce a union of dot-separated paths that resolve to `number`\n * within type T. Depth-limited to 4 levels to prevent TS recursion errors.\n *\n * @example\n * NumericPaths<{ x: number; y: number }> // 'x' | 'y'\n * NumericPaths<{ position: { x: number }; rotation: number }> // 'position.x' | 'rotation'\n */\nexport type NumericPaths<T, Depth extends readonly unknown[] = []> =\n\tDepth['length'] extends 4 ? never :\n\tT extends readonly unknown[] ? never :\n\tT extends Record<string, unknown>\n\t\t? { [K in keyof T & string]:\n\t\t\tNonNullable<T[K]> extends number\n\t\t\t\t? K\n\t\t\t\t: NonNullable<T[K]> extends readonly unknown[]\n\t\t\t\t\t? never\n\t\t\t\t\t: NonNullable<T[K]> extends Record<string, unknown>\n\t\t\t\t\t\t? `${K}.${NumericPaths<NonNullable<T[K]>, [...Depth, unknown]>}`\n\t\t\t\t\t\t: never\n\t\t}[keyof T & string]\n\t\t: never;\n\n/**\n * Discriminated union over component names: each variant constrains `field`\n * to the numeric paths of that component. TS narrows inline object literals\n * by `component` discriminant — zero runtime overhead.\n */\nexport type TypedTweenTargetInput<C extends Record<string, any>> = {\n\t[K in keyof C & string]: {\n\t\tcomponent: K;\n\t\tfield: NumericPaths<C[K]>;\n\t\tto: number;\n\t\tfrom?: number;\n\t}\n}[keyof C & string];\n\nexport interface TypedTweenSequenceStepInput<C extends Record<string, any>> {\n\ttargets: ReadonlyArray<TypedTweenTargetInput<C>>;\n\tduration: number;\n\teasing?: EasingFn;\n}\n\nexport interface TweenHelpers<W extends AnyECSpresso> {\n\tcreateTween: <K extends keyof ComponentsOfWorld<W> & string>(\n\t\tcomponent: K,\n\t\tfield: NumericPaths<ComponentsOfWorld<W>[K]>,\n\t\tto: number,\n\t\tduration: number,\n\t\toptions?: {\n\t\t\tfrom?: number;\n\t\t\teasing?: EasingFn;\n\t\t\tloop?: LoopMode;\n\t\t\tloops?: number;\n\t\t\tonComplete?: (data: TweenEventData) => void;\n\t\t},\n\t) => Pick<TweenComponentTypes, 'tween'>;\n\tcreateTweenSequence: (\n\t\tsteps: ReadonlyArray<TypedTweenSequenceStepInput<ComponentsOfWorld<W>>>,\n\t\toptions?: {\n\t\t\tloop?: LoopMode;\n\t\t\tloops?: number;\n\t\t\tonComplete?: (data: TweenEventData) => void;\n\t\t},\n\t) => Pick<TweenComponentTypes, 'tween'>;\n}\n\nexport function createTweenHelpers<W extends AnyECSpresso>(_world?: W): TweenHelpers<W> {\n\treturn {\n\t\tcreateTween: createTween as TweenHelpers<W>['createTween'],\n\t\tcreateTweenSequence: createTweenSequence as TweenHelpers<W>['createTweenSequence'],\n\t};\n}\n\n// ==================== Field Path Resolution ====================\n\n/**\n * Module-scoped mutable result to avoid per-call allocation in hot path.\n */\nconst _fieldRef: { parent: Record<string, unknown>; key: string } = { parent: {} as Record<string, unknown>, key: '' };\n\n/**\n * Traverse an object by path segments. Returns the parent object and final key\n * for read/write, or null if any segment is missing.\n */\nfunction resolveField(obj: Record<string, unknown>, path: readonly string[]): typeof _fieldRef | null {\n\tconst lastIdx = path.length - 1;\n\tlet current: Record<string, unknown> = obj;\n\n\tfor (let i = 0; i < lastIdx; i++) {\n\t\tconst segment = path[i];\n\t\tif (segment === undefined) return null;\n\t\tconst next = current[segment];\n\t\tif (next === null || next === undefined || typeof next !== 'object') return null;\n\t\tcurrent = next as Record<string, unknown>;\n\t}\n\n\tconst finalKey = path[lastIdx];\n\tif (finalKey === undefined) return null;\n\tif (!(finalKey in current)) return null;\n\n\t_fieldRef.parent = current;\n\t_fieldRef.key = finalKey;\n\treturn _fieldRef;\n}\n\nfunction readField(obj: Record<string, unknown>, path: readonly string[]): number | null {\n\tconst ref = resolveField(obj, path);\n\tif (!ref) return null;\n\tconst val = ref.parent[ref.key];\n\treturn typeof val === 'number' ? val : null;\n}\n\nfunction writeField(obj: Record<string, unknown>, path: readonly string[], value: number): boolean {\n\tconst ref = resolveField(obj, path);\n\tif (!ref) return false;\n\tref.parent[ref.key] = value;\n\treturn true;\n}\n\n// ==================== System Logic ====================\n\nfunction clamp(value: number, min: number, max: number): number {\n\treturn value < min ? min : value > max ? max : value;\n}\n\n/**\n * Resolve all null `from` values by reading current component field values.\n */\nfunction resolveFromValues(\n\ttween: Tween,\n\tentityComponents: Record<string, unknown>,\n): void {\n\tfor (const step of tween.steps) {\n\t\tfor (const target of step.targets) {\n\t\t\tif (target.from !== null) continue;\n\t\t\tconst comp = entityComponents[target.component];\n\t\t\tif (!comp || typeof comp !== 'object') continue;\n\t\t\tconst val = readField(comp as Record<string, unknown>, target.path);\n\t\t\tif (val !== null) {\n\t\t\t\ttarget.from = val;\n\t\t\t} else {\n\t\t\t\ttarget.from = 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Apply interpolation for a step's targets at a given progress.\n */\nfunction applyStep(\n\tstep: TweenStep,\n\tprogress: number,\n\tentityComponents: Record<string, unknown>,\n\tentityId: number,\n\tecs: { markChanged: (entityId: number, componentName: any) => void },\n): void {\n\tconst easedT = step.easing(progress);\n\n\tfor (const target of step.targets) {\n\t\tconst comp = entityComponents[target.component];\n\t\tif (!comp || typeof comp !== 'object') continue;\n\t\tconst from = target.from ?? 0;\n\t\tconst value = from + (target.to - from) * easedT;\n\t\tconst written = writeField(comp as Record<string, unknown>, target.path, value);\n\t\tif (written) {\n\t\t\tecs.markChanged(entityId, target.component);\n\t\t}\n\t}\n}\n\n/**\n * Snap all targets in a step to their final values (from or to depending on direction).\n */\nfunction snapStepToEnd(\n\tstep: TweenStep,\n\tentityComponents: Record<string, unknown>,\n\tentityId: number,\n\tecs: { markChanged: (entityId: number, componentName: any) => void },\n): void {\n\tfor (const target of step.targets) {\n\t\tconst comp = entityComponents[target.component];\n\t\tif (!comp || typeof comp !== 'object') continue;\n\t\tconst written = writeField(comp as Record<string, unknown>, target.path, target.to);\n\t\tif (written) {\n\t\t\tecs.markChanged(entityId, target.component);\n\t\t}\n\t}\n}\n\n/**\n * Reverse all from/to values in every step (for yoyo).\n */\nfunction reverseAllTargets(tween: Tween): void {\n\tfor (const step of tween.steps) {\n\t\tfor (const target of step.targets) {\n\t\t\tconst tmp = target.from ?? 0;\n\t\t\ttarget.from = target.to;\n\t\t\ttarget.to = tmp;\n\t\t}\n\t}\n}\n\n// ==================== Tween Processing Helpers ====================\n\ntype TweenEcs = { markChanged: (entityId: number, componentName: any) => void; commands: { removeComponent: (entityId: number, componentName: any) => void } };\n\nfunction completeTween(\n\ttween: Tween,\n\tentityId: number,\n\tecs: { commands: { removeComponent: (entityId: number, componentName: any) => void } },\n): void {\n\ttween.state = 'complete';\n\ttween.justFinished = true;\n\n\ttween.onComplete?.({ entityId, stepCount: tween.steps.length });\n\tecs.commands.removeComponent(entityId, 'tween');\n}\n\nfunction handleTweenEnd(\n\ttween: Tween,\n\tentityId: number,\n\tecs: TweenEcs,\n): boolean {\n\ttween.completedLoops++;\n\n\tif (tween.loop === 'once') {\n\t\tcompleteTween(tween, entityId, ecs);\n\t\treturn false;\n\t}\n\n\t// Check if finite loops exhausted\n\tif (tween.totalLoops > 0 && tween.completedLoops >= tween.totalLoops) {\n\t\tcompleteTween(tween, entityId, ecs);\n\t\treturn false;\n\t}\n\n\t// Loop continues\n\tif (tween.loop === 'yoyo') {\n\t\ttween.direction = tween.direction === 1 ? -1 : 1;\n\t\treverseAllTargets(tween);\n\t}\n\n\ttween.currentStep = 0;\n\n\t// For 'loop' mode, from values stay as-is so the animation replays identically.\n\t// For 'yoyo' mode, reverseAllTargets already swapped from/to.\n\n\treturn tween.elapsed > 0;\n}\n\n/**\n * Advance to next step. Returns true if there's more work to process,\n * false if the tween has completed or looped.\n */\nfunction advanceStep(\n\ttween: Tween,\n\tentityComponents: Record<string, unknown>,\n\tentityId: number,\n\tecs: TweenEcs,\n): boolean {\n\tconst nextStep = tween.currentStep + 1;\n\n\tif (nextStep < tween.steps.length) {\n\t\t// More steps — resolve from values for next step and continue\n\t\ttween.currentStep = nextStep;\n\t\tconst step = tween.steps[nextStep];\n\t\tif (step) {\n\t\t\tfor (const target of step.targets) {\n\t\t\t\tif (target.from !== null) continue;\n\t\t\t\tconst comp = entityComponents[target.component];\n\t\t\t\tif (!comp || typeof comp !== 'object') continue;\n\t\t\t\tconst val = readField(comp as Record<string, unknown>, target.path);\n\t\t\t\ttarget.from = val ?? 0;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t// All steps done — handle loop/complete\n\treturn handleTweenEnd(tween, entityId, ecs);\n}\n\nfunction processTweenProgress(\n\ttween: Tween,\n\tentityComponents: Record<string, unknown>,\n\tentityId: number,\n\tecs: TweenEcs,\n): void {\n\t// eslint-disable-next-line no-constant-condition\n\twhile (true) {\n\t\tconst currentStep = tween.steps[tween.currentStep];\n\t\tif (!currentStep) return;\n\n\t\t// Zero-duration steps complete immediately\n\t\tif (currentStep.duration <= 0) {\n\t\t\tsnapStepToEnd(currentStep, entityComponents, entityId, ecs);\n\t\t\ttween.elapsed = 0;\n\n\t\t\tif (!advanceStep(tween, entityComponents, entityId, ecs)) return;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (tween.elapsed >= currentStep.duration) {\n\t\t\t// Step complete — snap to end and carry overflow\n\t\t\tsnapStepToEnd(currentStep, entityComponents, entityId, ecs);\n\t\t\tconst overflow = tween.elapsed - currentStep.duration;\n\t\t\ttween.elapsed = overflow;\n\n\t\t\tif (!advanceStep(tween, entityComponents, entityId, ecs)) return;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Step in progress — interpolate\n\t\tconst progress = clamp(tween.elapsed / currentStep.duration, 0, 1);\n\t\tapplyStep(currentStep, progress, entityComponents, entityId, ecs);\n\t\treturn;\n\t}\n}\n\n// ==================== Plugin Factory ====================\n\n/**\n * Create a tween plugin for ECSpresso.\n *\n * This plugin provides:\n * - Tween system that processes all tween components each frame\n * - Support for single-field, multi-target, and multi-step sequences\n * - 31 standard easing functions\n * - Loop modes: once, loop, yoyo\n * - `justFinished` flag for one-frame completion detection\n * - `onComplete` callback on completion\n * - Change detection via markChanged\n */\nexport function createTweenPlugin<G extends string = 'tweens'>(\n\toptions?: TweenPluginOptions<G>\n) {\n\tconst {\n\t\tsystemGroup = 'tweens',\n\t\tpriority = 0,\n\t\tphase = 'update',\n\t} = options ?? {};\n\n\treturn definePlugin('tweens')\n\t\t.withComponentTypes<TweenComponentTypes>()\n\t\t.withLabels<'tween-update'>()\n\t\t.withGroups<G>()\n\t\t.install((world) => {\n\t\t\tworld\n\t\t\t\t.addSystem('tween-update')\n\t\t\t\t.setPriority(priority)\n\t\t\t\t.inPhase(phase)\n\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t.addQuery('tweens', {\n\t\t\t\t\twith: ['tween'],\n\t\t\t\t})\n\t\t\t\t.setProcess(({ queries, dt, ecs }) => {\n\t\t\t\t\tfor (const entity of queries.tweens) {\n\t\t\t\t\t\tconst tween = entity.components.tween as Tween;\n\t\t\t\t\t\tconst entityComponents = entity.components as Record<string, unknown>;\n\n\t\t\t\t\t\t// Reset justFinished flag from previous frame\n\t\t\t\t\t\tif (tween.justFinished) {\n\t\t\t\t\t\t\ttween.justFinished = false;\n\t\t\t\t\t\t\t// Component removal was queued, skip processing\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Skip completed tweens\n\t\t\t\t\t\tif (tween.state === 'complete') continue;\n\n\t\t\t\t\t\t// Resolve pending state: capture null from values\n\t\t\t\t\t\tif (tween.state === 'pending') {\n\t\t\t\t\t\t\tresolveFromValues(tween, entityComponents);\n\t\t\t\t\t\t\ttween.state = 'active';\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Process active tween\n\t\t\t\t\t\tconst currentStep = tween.steps[tween.currentStep];\n\t\t\t\t\t\tif (!currentStep) continue;\n\n\t\t\t\t\t\ttween.elapsed += dt;\n\n\t\t\t\t\t\tprocessTweenProgress(tween, entityComponents, entity.id, ecs);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t});\n}\n",
6
- "/**\n * Easing Functions\n *\n * 31 standard easing functions for animation. Pure math, no dependencies.\n */\n\nexport type EasingFn = (t: number) => number;\n\nexport function linear(t: number): number {\n\treturn t;\n}\n\n// Quad\nexport function easeInQuad(t: number): number {\n\treturn t * t;\n}\n\nexport function easeOutQuad(t: number): number {\n\treturn t * (2 - t);\n}\n\nexport function easeInOutQuad(t: number): number {\n\treturn t < 0.5\n\t\t? 2 * t * t\n\t\t: -1 + (4 - 2 * t) * t;\n}\n\n// Cubic\nexport function easeInCubic(t: number): number {\n\treturn t * t * t;\n}\n\nexport function easeOutCubic(t: number): number {\n\tconst t1 = t - 1;\n\treturn t1 * t1 * t1 + 1;\n}\n\nexport function easeInOutCubic(t: number): number {\n\treturn t < 0.5\n\t\t? 4 * t * t * t\n\t\t: 1 + (t - 1) * (2 * t - 2) * (2 * t - 2);\n}\n\n// Quart\nexport function easeInQuart(t: number): number {\n\treturn t * t * t * t;\n}\n\nexport function easeOutQuart(t: number): number {\n\tconst t1 = t - 1;\n\treturn 1 - t1 * t1 * t1 * t1;\n}\n\nexport function easeInOutQuart(t: number): number {\n\treturn t < 0.5\n\t\t? 8 * t * t * t * t\n\t\t: 1 - 8 * (t - 1) * (t - 1) * (t - 1) * (t - 1);\n}\n\n// Quint\nexport function easeInQuint(t: number): number {\n\treturn t * t * t * t * t;\n}\n\nexport function easeOutQuint(t: number): number {\n\tconst t1 = t - 1;\n\treturn 1 + t1 * t1 * t1 * t1 * t1;\n}\n\nexport function easeInOutQuint(t: number): number {\n\treturn t < 0.5\n\t\t? 16 * t * t * t * t * t\n\t\t: 1 + 16 * (t - 1) * (t - 1) * (t - 1) * (t - 1) * (t - 1);\n}\n\n// Sine\nexport function easeInSine(t: number): number {\n\treturn 1 - Math.cos((t * Math.PI) / 2);\n}\n\nexport function easeOutSine(t: number): number {\n\treturn Math.sin((t * Math.PI) / 2);\n}\n\nexport function easeInOutSine(t: number): number {\n\treturn -(Math.cos(Math.PI * t) - 1) / 2;\n}\n\n// Expo\nexport function easeInExpo(t: number): number {\n\treturn t === 0 ? 0 : Math.pow(2, 10 * (t - 1));\n}\n\nexport function easeOutExpo(t: number): number {\n\treturn t === 1 ? 1 : 1 - Math.pow(2, -10 * t);\n}\n\nexport function easeInOutExpo(t: number): number {\n\tif (t === 0) return 0;\n\tif (t === 1) return 1;\n\treturn t < 0.5\n\t\t? Math.pow(2, 20 * t - 10) / 2\n\t\t: (2 - Math.pow(2, -20 * t + 10)) / 2;\n}\n\n// Circ\nexport function easeInCirc(t: number): number {\n\treturn 1 - Math.sqrt(1 - t * t);\n}\n\nexport function easeOutCirc(t: number): number {\n\tconst t1 = t - 1;\n\treturn Math.sqrt(1 - t1 * t1);\n}\n\nexport function easeInOutCirc(t: number): number {\n\treturn t < 0.5\n\t\t? (1 - Math.sqrt(1 - 4 * t * t)) / 2\n\t\t: (Math.sqrt(1 - (-2 * t + 2) * (-2 * t + 2)) + 1) / 2;\n}\n\n// Back\nconst BACK_C1 = 1.70158;\nconst BACK_C2 = BACK_C1 * 1.525;\nconst BACK_C3 = BACK_C1 + 1;\n\nexport function easeInBack(t: number): number {\n\treturn BACK_C3 * t * t * t - BACK_C1 * t * t;\n}\n\nexport function easeOutBack(t: number): number {\n\tconst t1 = t - 1;\n\treturn 1 + BACK_C3 * t1 * t1 * t1 + BACK_C1 * t1 * t1;\n}\n\nexport function easeInOutBack(t: number): number {\n\treturn t < 0.5\n\t\t? ((2 * t) * (2 * t) * ((BACK_C2 + 1) * 2 * t - BACK_C2)) / 2\n\t\t: ((2 * t - 2) * (2 * t - 2) * ((BACK_C2 + 1) * (t * 2 - 2) + BACK_C2) + 2) / 2;\n}\n\n// Elastic\nconst ELASTIC_C4 = (2 * Math.PI) / 3;\nconst ELASTIC_C5 = (2 * Math.PI) / 4.5;\n\nexport function easeInElastic(t: number): number {\n\tif (t === 0) return 0;\n\tif (t === 1) return 1;\n\treturn -Math.pow(2, 10 * t - 10) * Math.sin((10 * t - 10.75) * ELASTIC_C4);\n}\n\nexport function easeOutElastic(t: number): number {\n\tif (t === 0) return 0;\n\tif (t === 1) return 1;\n\treturn Math.pow(2, -10 * t) * Math.sin((10 * t - 0.75) * ELASTIC_C4) + 1;\n}\n\nexport function easeInOutElastic(t: number): number {\n\tif (t === 0) return 0;\n\tif (t === 1) return 1;\n\treturn t < 0.5\n\t\t? -(Math.pow(2, 20 * t - 10) * Math.sin((20 * t - 11.125) * ELASTIC_C5)) / 2\n\t\t: (Math.pow(2, -20 * t + 10) * Math.sin((20 * t - 11.125) * ELASTIC_C5)) / 2 + 1;\n}\n\n// Bounce\nexport function easeOutBounce(t: number): number {\n\tconst n1 = 7.5625;\n\tconst d1 = 2.75;\n\n\tif (t < 1 / d1) {\n\t\treturn n1 * t * t;\n\t} else if (t < 2 / d1) {\n\t\tconst t1 = t - 1.5 / d1;\n\t\treturn n1 * t1 * t1 + 0.75;\n\t} else if (t < 2.5 / d1) {\n\t\tconst t1 = t - 2.25 / d1;\n\t\treturn n1 * t1 * t1 + 0.9375;\n\t} else {\n\t\tconst t1 = t - 2.625 / d1;\n\t\treturn n1 * t1 * t1 + 0.984375;\n\t}\n}\n\nexport function easeInBounce(t: number): number {\n\treturn 1 - easeOutBounce(1 - t);\n}\n\nexport function easeInOutBounce(t: number): number {\n\treturn t < 0.5\n\t\t? (1 - easeOutBounce(1 - 2 * t)) / 2\n\t\t: (1 + easeOutBounce(2 * t - 1)) / 2;\n}\n\n/** Runtime lookup of all easing functions by name */\nexport const easings = {\n\tlinear,\n\teaseInQuad,\n\teaseOutQuad,\n\teaseInOutQuad,\n\teaseInCubic,\n\teaseOutCubic,\n\teaseInOutCubic,\n\teaseInQuart,\n\teaseOutQuart,\n\teaseInOutQuart,\n\teaseInQuint,\n\teaseOutQuint,\n\teaseInOutQuint,\n\teaseInSine,\n\teaseOutSine,\n\teaseInOutSine,\n\teaseInExpo,\n\teaseOutExpo,\n\teaseInOutExpo,\n\teaseInCirc,\n\teaseOutCirc,\n\teaseInOutCirc,\n\teaseInBack,\n\teaseOutBack,\n\teaseInOutBack,\n\teaseInElastic,\n\teaseOutElastic,\n\teaseInOutElastic,\n\teaseInBounce,\n\teaseOutBounce,\n\teaseInOutBounce,\n} as const;\n"
7
- ],
8
- "mappings": "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",
9
- "debugId": "5CFFC226CB1D9DD164756E2164756E21",
10
- "names": []
11
- }
File without changes
File without changes