ecspresso 0.17.1 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/CHANGELOG.md +44 -1
  2. package/dist/asset-manager.d.ts +8 -8
  3. package/dist/asset-types.d.ts +9 -5
  4. package/dist/ecspresso-builder.d.ts +5 -5
  5. package/dist/ecspresso.d.ts +13 -1
  6. package/dist/index.d.ts +3 -3
  7. package/dist/index.js +2 -2
  8. package/dist/index.js.map +10 -10
  9. package/dist/plugins/ai/behavior-tree.d.ts +2 -2
  10. package/dist/plugins/ai/behavior-tree.js.map +2 -2
  11. package/dist/plugins/ai/detection.d.ts +3 -3
  12. package/dist/plugins/ai/detection.js.map +2 -2
  13. package/dist/plugins/ai/flocking.d.ts +3 -3
  14. package/dist/plugins/ai/flocking.js.map +1 -1
  15. package/dist/plugins/ai/pathfinding.d.ts +3 -4
  16. package/dist/plugins/ai/pathfinding.js.map +2 -2
  17. package/dist/plugins/audio/audio.js +2 -2
  18. package/dist/plugins/audio/audio.js.map +3 -3
  19. package/dist/plugins/combat/health.d.ts +2 -2
  20. package/dist/plugins/combat/health.js.map +2 -2
  21. package/dist/plugins/combat/projectile.d.ts +3 -3
  22. package/dist/plugins/combat/projectile.js.map +2 -2
  23. package/dist/plugins/input/selection.d.ts +3 -3
  24. package/dist/plugins/input/selection.js.map +3 -3
  25. package/dist/plugins/isometric/depth-sort.d.ts +2 -2
  26. package/dist/plugins/isometric/depth-sort.js.map +2 -2
  27. package/dist/plugins/isometric/projection.d.ts +2 -2
  28. package/dist/plugins/isometric/projection.js.map +2 -2
  29. package/dist/plugins/physics/steering.d.ts +2 -2
  30. package/dist/plugins/physics/steering.js.map +2 -2
  31. package/dist/plugins/rendering/particles.d.ts +2 -2
  32. package/dist/plugins/rendering/particles.js +2 -2
  33. package/dist/plugins/rendering/particles.js.map +3 -3
  34. package/dist/plugins/rendering/renderer2D.d.ts +6 -5
  35. package/dist/plugins/rendering/renderer2D.js +2 -2
  36. package/dist/plugins/rendering/renderer2D.js.map +3 -3
  37. package/dist/plugins/rendering/renderer3D.d.ts +3 -2
  38. package/dist/plugins/rendering/renderer3D.js +2 -2
  39. package/dist/plugins/rendering/renderer3D.js.map +3 -3
  40. package/dist/plugins/rendering/tilemap.d.ts +3 -3
  41. package/dist/plugins/rendering/tilemap.js.map +3 -3
  42. package/dist/plugins/spatial/camera.js.map +2 -2
  43. package/dist/plugins/spatial/camera3D.d.ts +3 -3
  44. package/dist/plugins/spatial/camera3D.js.map +2 -2
  45. package/dist/plugins/spatial/transform.d.ts +2 -2
  46. package/dist/plugins/spatial/transform.js.map +1 -1
  47. package/dist/plugins/spatial/transform3D.d.ts +2 -2
  48. package/dist/plugins/spatial/transform3D.js.map +1 -1
  49. package/dist/plugins/ui/ui.d.ts +2 -2
  50. package/dist/plugins/ui/ui.js +2 -2
  51. package/dist/plugins/ui/ui.js.map +4 -4
  52. package/dist/reactive-query-manager.d.ts +26 -11
  53. package/dist/screen-types.d.ts +21 -3
  54. package/dist/system-builder.d.ts +5 -5
  55. package/dist/type-utils.d.ts +20 -0
  56. package/dist/types.d.ts +1 -1
  57. package/package.json +2 -2
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/plugins/rendering/renderer3D.ts"],
4
4
  "sourcesContent": [
5
- "/**\n * 3D Renderer Plugin for ECSpresso\n *\n * An opt-in Three.js-based 3D rendering plugin that automates scene graph wiring.\n * Import from 'ecspresso/plugins/rendering/renderer3D'\n *\n * This plugin includes 3D transform propagation automatically.\n */\n\nimport type {\n\tWebGLRenderer,\n\tWebGLRendererParameters,\n\tScene,\n\tCamera,\n\tPerspectiveCamera,\n\tOrthographicCamera,\n\tObject3D,\n\tMesh,\n\tGroup,\n\tColorRepresentation,\n\tVector3,\n\tEuler,\n\tQuaternion,\n} from 'three';\nimport { definePlugin, type Plugin } from 'ecspresso';\nimport type { WorldConfigFrom, EmptyConfig } from '../../type-utils';\nimport type ECSpresso from 'ecspresso';\nimport {\n\tcreateTransform3DPlugin,\n\tcreateTransform3D,\n\ttype LocalTransform3D,\n\ttype WorldTransform3D,\n\ttype Transform3DComponentTypes,\n\ttype Transform3DPluginOptions,\n\tDEFAULT_LOCAL_TRANSFORM_3D,\n} from 'ecspresso/plugins/spatial/transform3D';\n\n// Re-export transform types for convenience\nexport type { LocalTransform3D, WorldTransform3D, Transform3DComponentTypes };\nexport {\n\tcreateTransform3D,\n\tcreateLocalTransform3D,\n\tcreateWorldTransform3D,\n\tDEFAULT_LOCAL_TRANSFORM_3D,\n\tDEFAULT_WORLD_TRANSFORM_3D,\n} from 'ecspresso/plugins/spatial/transform3D';\n\n// ==================== Component Types ====================\n\n/**\n * Visibility component for 3D entities.\n */\nexport interface Visible3D {\n\tvisible: boolean;\n}\n\n/**\n * Aggregate component types for the 3D renderer plugin.\n * Included automatically via `.withPlugin(createRenderer3DPlugin({ ... }))`.\n */\nexport interface Renderer3DComponentTypes extends Transform3DComponentTypes {\n\tmesh: Mesh;\n\tgroup: Group;\n\tobject3d: Object3D;\n\tvisible3d: Visible3D;\n\t/** Controls Three.js Object3D.renderOrder for manual z-ordering */\n\trenderOrder: number;\n}\n\n// ==================== Event Types ====================\n\n/**\n * Events emitted by the 3D renderer plugin.\n */\nexport interface Renderer3DEventTypes {\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 3D renderer plugin.\n */\nexport interface Renderer3DResourceTypes {\n\tthreeRenderer: WebGLRenderer;\n\tscene: Scene;\n\tcamera: Camera;\n}\n\n// ==================== Plugin Options ====================\n\n/**\n * Common options shared between both initialization modes.\n */\ninterface Renderer3DPluginCommonOptions<G extends string = 'renderer3d'> {\n\t/** System group name (default: 'renderer3d') */\n\tsystemGroup?: G;\n\t/** Priority for render sync system (default: 500) */\n\trenderSyncPriority?: number;\n\t/** Options for the included 3D transform plugin */\n\ttransform?: Transform3DPluginOptions;\n\t/** When true, starts a requestAnimationFrame loop to drive ecs.update() automatically (default: true) */\n\tstartLoop?: boolean;\n}\n\n/**\n * Options when providing pre-initialized Three.js objects.\n */\nexport interface Renderer3DPluginPreInitOptions<G extends string = 'renderer3d'> extends Renderer3DPluginCommonOptions<G> {\n\t/** Pre-initialized WebGLRenderer */\n\trenderer: WebGLRenderer;\n\t/** Pre-initialized Scene */\n\tscene: Scene;\n\t/** Pre-initialized Camera */\n\tcamera: Camera;\n\tcontainer?: never;\n\tbackground?: never;\n\twidth?: never;\n\theight?: never;\n\tantialias?: never;\n\tshadows?: never;\n\tcameraOptions?: never;\n\tthreeInit?: never;\n}\n\n/**\n * Camera configuration for managed mode.\n *\n * Discriminated on `projection`. Defaults to `'perspective'` when omitted.\n * Orthographic cameras use `viewSize` (world-unit height at zoom=1) to define\n * the base frustum; `zoom` maps directly to Three.js's `OrthographicCamera.zoom`.\n */\nexport type CameraOptions =\n\t| {\n\t\tprojection?: 'perspective';\n\t\tfov?: number;\n\t\tnear?: number;\n\t\tfar?: number;\n\t\tposition?: { x: number; y: number; z: number };\n\t\tlookAt?: { x: number; y: number; z: number };\n\t}\n\t| {\n\t\tprojection: 'orthographic';\n\t\tviewSize?: number;\n\t\tzoom?: number;\n\t\tnear?: number;\n\t\tfar?: number;\n\t\tposition?: { x: number; y: number; z: number };\n\t\tlookAt?: { x: number; y: number; z: number };\n\t};\n\n/**\n * Options when letting the plugin create and manage Three.js objects.\n */\nexport interface Renderer3DPluginManagedOptions<G extends string = 'renderer3d'> extends Renderer3DPluginCommonOptions<G> {\n\trenderer?: never;\n\tscene?: never;\n\tcamera?: never;\n\t/** Container element to append the canvas to (or CSS selector string). Defaults to `document.body`. */\n\tcontainer?: HTMLElement | string;\n\t/** Scene background color. */\n\tbackground?: ColorRepresentation;\n\t/** Canvas width. When omitted, auto-sizes to container. */\n\twidth?: number;\n\t/** Canvas height. When omitted, auto-sizes to container. */\n\theight?: number;\n\t/** Enable antialiasing (default: true) */\n\tantialias?: boolean;\n\t/** Enable shadow mapping (default: false) */\n\tshadows?: boolean;\n\t/** Camera configuration */\n\tcameraOptions?: CameraOptions;\n\t/** Escape hatch for raw WebGLRendererParameters not otherwise exposed. */\n\tthreeInit?: Partial<WebGLRendererParameters>;\n}\n\n/**\n * Configuration options for the 3D renderer plugin.\n *\n * Supports two modes:\n * 1. **Pre-initialized**: Pass already-initialized renderer, scene, camera\n * 2. **Managed**: Omit them and the plugin creates everything during `ecs.initialize()`\n *\n * This plugin includes 3D transform propagation automatically.\n *\n * @example Pre-initialized mode\n * ```typescript\n * const renderer = new WebGLRenderer({ antialias: true });\n * const scene = new Scene();\n * const camera = new PerspectiveCamera(75, w / h, 0.1, 1000);\n *\n * const ecs = ECSpresso.create()\n * .withPlugin(createRenderer3DPlugin({ renderer, scene, camera }))\n * .build();\n * ```\n *\n * @example Managed mode\n * ```typescript\n * const ecs = ECSpresso.create()\n * .withPlugin(createRenderer3DPlugin({\n * container: '#game',\n * background: 0x1099bb,\n * antialias: true,\n * cameraOptions: { fov: 75, position: { x: 0, y: 5, z: 10 } },\n * }))\n * .build();\n * await ecs.initialize();\n * ```\n */\nexport type Renderer3DPluginOptions<G extends string = 'renderer3d'> =\n\tRenderer3DPluginPreInitOptions<G> | Renderer3DPluginManagedOptions<G>;\n\n// ==================== Helper Utilities ====================\n\ninterface PositionOption3D {\n\tx?: number;\n\ty?: number;\n\tz?: number;\n}\n\ninterface TransformOptions3D {\n\trotation?: { x?: number; y?: number; z?: number };\n\tscale?: number | { x: number; y: number; z: number };\n\tvisible?: boolean;\n}\n\nfunction buildTransformComponents(\n\tposition?: PositionOption3D,\n\toptions?: TransformOptions3D,\n): Transform3DComponentTypes {\n\tconst scaleValue = options?.scale;\n\tconst scaleOpts = typeof scaleValue === 'number'\n\t\t? { scale: scaleValue }\n\t\t: scaleValue\n\t\t\t? { scaleX: scaleValue.x, scaleY: scaleValue.y, scaleZ: scaleValue.z }\n\t\t\t: undefined;\n\n\treturn createTransform3D(\n\t\tposition?.x ?? 0,\n\t\tposition?.y ?? 0,\n\t\tposition?.z ?? 0,\n\t\t{ rotation: options?.rotation, ...scaleOpts },\n\t);\n}\n\n/**\n * Create components for a mesh entity.\n * Returns an object suitable for spreading into spawn().\n *\n * @example\n * ```typescript\n * const player = ecs.spawn({\n * ...createMeshComponents(myMesh, { x: 10, y: 0, z: -5 }),\n * velocity: { x: 0, y: 0, z: 0 },\n * });\n * ```\n */\nexport function createMeshComponents(\n\tmesh: Mesh,\n\tposition?: PositionOption3D,\n\toptions?: TransformOptions3D,\n): Pick<Renderer3DComponentTypes, 'mesh' | 'localTransform3D' | 'worldTransform3D' | 'visible3d'> {\n\treturn {\n\t\tmesh,\n\t\t...buildTransformComponents(position, options),\n\t\tvisible3d: { visible: options?.visible ?? true },\n\t};\n}\n\n/**\n * Create components for a group entity.\n * Returns an object suitable for spreading into spawn().\n *\n * @example\n * ```typescript\n * const enemies = ecs.spawn({\n * ...createGroupComponents(enemyGroup, { x: 50, y: 0, z: -30 }),\n * });\n * ```\n */\nexport function createGroupComponents(\n\tgroup: Group,\n\tposition?: PositionOption3D,\n\toptions?: TransformOptions3D,\n): Pick<Renderer3DComponentTypes, 'group' | 'localTransform3D' | 'worldTransform3D' | 'visible3d'> {\n\treturn {\n\t\tgroup,\n\t\t...buildTransformComponents(position, options),\n\t\tvisible3d: { visible: options?.visible ?? true },\n\t};\n}\n\n/**\n * Create components for a generic Object3D entity.\n * Returns an object suitable for spreading into spawn().\n *\n * @example\n * ```typescript\n * const obj = ecs.spawn({\n * ...createObject3DComponents(myObject, { x: 0, y: 0, z: 0 }),\n * });\n * ```\n */\nexport function createObject3DComponents(\n\tobject3d: Object3D,\n\tposition?: PositionOption3D,\n\toptions?: TransformOptions3D,\n): Pick<Renderer3DComponentTypes, 'object3d' | 'localTransform3D' | 'worldTransform3D' | 'visible3d'> {\n\treturn {\n\t\tobject3d,\n\t\t...buildTransformComponents(position, options),\n\t\tvisible3d: { visible: options?.visible ?? true },\n\t};\n}\n\n// ==================== Sync Helper ====================\n\n/**\n * Apply worldTransform3D and visible3d to a Three.js Object3D.\n *\n * Managed objects have matrixAutoUpdate / matrixWorldAutoUpdate disabled\n * (see addToScene), so we recompose obj.matrix and refresh obj.matrixWorld\n * ourselves. Because the plugin keeps a flat scene graph AND assumes the scene\n * root stays at identity, world = local — so we skip a 4x4 matmul and copy.\n *\n * Note: obj.position / obj.rotation / obj.scale are NOT kept in sync — read\n * worldTransform3D from the ECS component if you need current values.\n */\nfunction syncObject3D(\n\tobj: Object3D,\n\twt: WorldTransform3D,\n\tvis: Visible3D,\n\tpos: Vector3,\n\teuler: Euler,\n\tquat: Quaternion,\n\tscale: Vector3,\n): void {\n\tpos.set(wt.x, wt.y, wt.z);\n\teuler.set(wt.rx, wt.ry, wt.rz, 'XYZ');\n\tquat.setFromEuler(euler);\n\tscale.set(wt.sx, wt.sy, wt.sz);\n\tobj.matrix.compose(pos, quat, scale);\n\tobj.matrixWorld.copy(obj.matrix);\n\tobj.visible = vis.visible;\n}\n\n// ==================== Plugin Factory ====================\n\ntype Renderer3DLabels = 'renderer3d-sync' | 'renderer3d-scene-graph' | 'renderer3d-render' | 'transform3d-propagation';\ntype Renderer3DReactiveQueryNames = 'renderer3d-meshes' | 'renderer3d-groups' | 'renderer3d-objects';\n\n/**\n * Create a 3D rendering plugin for ECSpresso.\n *\n * This plugin provides:\n * - 3D transform propagation (localTransform3D -> worldTransform3D)\n * - Render sync system (updates Three.js objects from ECS components)\n * - Scene graph management (auto-adds/removes Three.js objects)\n * - Render call (renderer.render(scene, camera) each frame)\n * - Optional requestAnimationFrame loop\n */\nexport function createRenderer3DPlugin<G extends string = 'renderer3d'>(\n\toptions: Renderer3DPluginOptions<G>,\n): Plugin<WorldConfigFrom<Renderer3DComponentTypes, Renderer3DEventTypes, Renderer3DResourceTypes>, EmptyConfig, Renderer3DLabels, G, never, Renderer3DReactiveQueryNames> {\n\tconst {\n\t\tsystemGroup = 'renderer3d',\n\t\trenderSyncPriority = 500,\n\t\ttransform: transformOptions,\n\t\tstartLoop = true,\n\t} = options;\n\n\t// Entity ID -> Three.js Object3D mapping for scene graph management\n\tconst entityToThreeObject = new Map<number, Object3D>();\n\n\t// Cached resource references, set during scene-graph init for hot-path access\n\tlet cachedRenderer: WebGLRenderer | null = null;\n\tlet cachedScene: Scene | null = null;\n\tlet cachedCamera: Camera | null = null;\n\n\t// Preallocated math temporaries for syncObject3D, allocated during scene-graph init.\n\tlet tmpPos: Vector3 | null = null;\n\tlet tmpEuler: Euler | null = null;\n\tlet tmpQuat: Quaternion | null = null;\n\tlet tmpScale: Vector3 | null = null;\n\n\t// Determine mode: pre-initialized if renderer was provided\n\tconst isManaged = !('renderer' in options && options.renderer !== undefined);\n\n\ttype PluginECS = ECSpresso<WorldConfigFrom<Renderer3DComponentTypes, Renderer3DEventTypes, Renderer3DResourceTypes>>;\n\n\treturn definePlugin('renderer3d')\n\t\t.withComponentTypes<Renderer3DComponentTypes>()\n\t\t.withEventTypes<Renderer3DEventTypes>()\n\t\t.withResourceTypes<Renderer3DResourceTypes>()\n\t\t.withLabels<Renderer3DLabels>()\n\t\t.withGroups<G>()\n\t\t.withReactiveQueryNames<Renderer3DReactiveQueryNames>()\n\t\t.install((world) => {\n\t\t\t// Install 3D transform plugin (deduplicates if already installed)\n\t\t\tworld.installPlugin(createTransform3DPlugin(transformOptions));\n\n\t\t\t// Register resources based on mode\n\t\t\tif (isManaged) {\n\t\t\t\tconst managedOptions = options as Renderer3DPluginManagedOptions<G>;\n\t\t\t\tconst {\n\t\t\t\t\tbackground,\n\t\t\t\t\twidth,\n\t\t\t\t\theight,\n\t\t\t\t\tantialias = true,\n\t\t\t\t\tshadows = false,\n\t\t\t\t\tcameraOptions,\n\t\t\t\t\tthreeInit,\n\t\t\t\t} = managedOptions;\n\t\t\t\tconst containerOption = managedOptions.container ?? document.body;\n\n\t\t\t\tworld.addResource('threeRenderer', async () => {\n\t\t\t\t\tconst { WebGLRenderer: WebGLRendererClass } = await import('three');\n\n\t\t\t\t\tconst containerEl: HTMLElement | null = typeof containerOption === 'string'\n\t\t\t\t\t\t? document.querySelector<HTMLElement>(containerOption)\n\t\t\t\t\t\t: containerOption;\n\n\t\t\t\t\tconst rendererParams: WebGLRendererParameters = {\n\t\t\t\t\t\tantialias,\n\t\t\t\t\t\tpowerPreference: 'high-performance',\n\t\t\t\t\t\t...threeInit,\n\t\t\t\t\t};\n\n\t\t\t\t\tconst renderer = new WebGLRendererClass(rendererParams);\n\n\t\t\t\t\tif (shadows) {\n\t\t\t\t\t\trenderer.shadowMap.enabled = true;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst w = width ?? containerEl?.clientWidth ?? window.innerWidth;\n\t\t\t\t\tconst h = height ?? containerEl?.clientHeight ?? window.innerHeight;\n\t\t\t\t\trenderer.setSize(w, h);\n\n\t\t\t\t\tif (containerEl) {\n\t\t\t\t\t\tcontainerEl.appendChild(renderer.domElement);\n\t\t\t\t\t} else if (typeof containerOption === 'string') {\n\t\t\t\t\t\tconsole.warn(`Renderer3D plugin: container selector \"${containerOption}\" not found`);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn renderer;\n\t\t\t\t});\n\n\t\t\t\tworld.addResource('scene', {\n\t\t\t\t\tdependsOn: ['threeRenderer'],\n\t\t\t\t\tfactory: async () => {\n\t\t\t\t\t\tconst { Scene: SceneClass, Color } = await import('three');\n\t\t\t\t\t\tconst scene = new SceneClass();\n\t\t\t\t\t\tif (background !== undefined) {\n\t\t\t\t\t\t\tscene.background = new Color(background);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn scene;\n\t\t\t\t\t},\n\t\t\t\t});\n\n\t\t\t\tworld.addResource('camera', {\n\t\t\t\t\tdependsOn: ['threeRenderer'],\n\t\t\t\t\tfactory: async (ecs) => {\n\t\t\t\t\t\tconst renderer = ecs.getResource('threeRenderer');\n\t\t\t\t\t\tconst aspect = renderer.domElement.width / renderer.domElement.height;\n\t\t\t\t\t\tconst near = cameraOptions?.near ?? 0.1;\n\t\t\t\t\t\tconst far = cameraOptions?.far ?? 1000;\n\n\t\t\t\t\t\tlet cam: Camera;\n\t\t\t\t\t\tif (cameraOptions?.projection === 'orthographic') {\n\t\t\t\t\t\t\tconst { OrthographicCamera: OrthographicCameraClass } = await import('three');\n\t\t\t\t\t\t\tconst viewSize = cameraOptions.viewSize ?? 10;\n\t\t\t\t\t\t\tconst halfH = viewSize / 2;\n\t\t\t\t\t\t\tconst halfW = halfH * aspect;\n\t\t\t\t\t\t\tconst ortho = new OrthographicCameraClass(-halfW, halfW, halfH, -halfH, near, far);\n\t\t\t\t\t\t\tortho.zoom = cameraOptions.zoom ?? 1;\n\t\t\t\t\t\t\tortho.updateProjectionMatrix();\n\t\t\t\t\t\t\tcam = ortho;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconst { PerspectiveCamera: PerspectiveCameraClass } = await import('three');\n\t\t\t\t\t\t\tconst fov = cameraOptions?.fov ?? 75;\n\t\t\t\t\t\t\tcam = new PerspectiveCameraClass(fov, aspect, near, far);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (cameraOptions?.position) {\n\t\t\t\t\t\t\tcam.position.set(\n\t\t\t\t\t\t\t\tcameraOptions.position.x,\n\t\t\t\t\t\t\t\tcameraOptions.position.y,\n\t\t\t\t\t\t\t\tcameraOptions.position.z,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (cameraOptions?.lookAt) {\n\t\t\t\t\t\t\tcam.lookAt(\n\t\t\t\t\t\t\t\tcameraOptions.lookAt.x,\n\t\t\t\t\t\t\t\tcameraOptions.lookAt.y,\n\t\t\t\t\t\t\t\tcameraOptions.lookAt.z,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn cam;\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconst preInit = options as Renderer3DPluginPreInitOptions<G>;\n\t\t\t\tworld.addResource('threeRenderer', preInit.renderer);\n\t\t\t\tworld.addResource('scene', preInit.scene);\n\t\t\t\tworld.addResource('camera', preInit.camera);\n\t\t\t}\n\n\t\t\t// Register dispose callbacks for 3D object components\n\t\t\tworld.registerDispose('mesh', ({ value }) => {\n\t\t\t\tif (value.parent) value.parent.remove(value);\n\t\t\t});\n\t\t\tworld.registerDispose('group', ({ value }) => {\n\t\t\t\tif (value.parent) value.parent.remove(value);\n\t\t\t});\n\t\t\tworld.registerDispose('object3d', ({ value }) => {\n\t\t\t\tif (value.parent) value.parent.remove(value);\n\t\t\t});\n\n\t\t\t// 3D objects require localTransform3D and visible3d\n\t\t\tworld.registerRequired('mesh', 'localTransform3D', () => ({ ...DEFAULT_LOCAL_TRANSFORM_3D }));\n\t\t\tworld.registerRequired('mesh', 'visible3d', () => ({ visible: true }));\n\t\t\tworld.registerRequired('group', 'localTransform3D', () => ({ ...DEFAULT_LOCAL_TRANSFORM_3D }));\n\t\t\tworld.registerRequired('group', 'visible3d', () => ({ visible: true }));\n\t\t\tworld.registerRequired('object3d', 'localTransform3D', () => ({ ...DEFAULT_LOCAL_TRANSFORM_3D }));\n\t\t\tworld.registerRequired('object3d', 'visible3d', () => ({ visible: true }));\n\n\t\t\t// ==================== Render Sync System ====================\n\t\t\tworld\n\t\t\t\t.addSystem('renderer3d-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('meshes', {\n\t\t\t\t\twith: ['mesh', 'worldTransform3D', 'visible3d'],\n\t\t\t\t\tchanged: ['worldTransform3D'],\n\t\t\t\t})\n\t\t\t\t.addQuery('groups', {\n\t\t\t\t\twith: ['group', 'worldTransform3D', 'visible3d'],\n\t\t\t\t\tchanged: ['worldTransform3D'],\n\t\t\t\t})\n\t\t\t\t.addQuery('objects', {\n\t\t\t\t\twith: ['object3d', 'worldTransform3D', 'visible3d'],\n\t\t\t\t\tchanged: ['worldTransform3D'],\n\t\t\t\t})\n\t\t\t\t.setProcess(({ queries }) => {\n\t\t\t\t\tconst pos = tmpPos;\n\t\t\t\t\tconst euler = tmpEuler;\n\t\t\t\t\tconst quat = tmpQuat;\n\t\t\t\t\tconst scale = tmpScale;\n\t\t\t\t\tif (!pos || !euler || !quat || !scale) return;\n\n\t\t\t\t\tfor (const entity of queries.meshes) {\n\t\t\t\t\t\tconst { mesh, worldTransform3D, visible3d } = entity.components;\n\t\t\t\t\t\tsyncObject3D(mesh, worldTransform3D, visible3d, pos, euler, quat, scale);\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (const entity of queries.groups) {\n\t\t\t\t\t\tconst { group, worldTransform3D, visible3d } = entity.components;\n\t\t\t\t\t\tsyncObject3D(group, worldTransform3D, visible3d, pos, euler, quat, scale);\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (const entity of queries.objects) {\n\t\t\t\t\t\tconst { object3d, worldTransform3D, visible3d } = entity.components;\n\t\t\t\t\t\tsyncObject3D(object3d, worldTransform3D, visible3d, pos, euler, quat, scale);\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('renderer3d-scene-graph')\n\t\t\t\t.setPriority(9999)\n\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t.setOnInitialize(async (ecs: PluginECS) => {\n\t\t\t\t\tconst { Vector3: Vector3Class, Euler: EulerClass, Quaternion: QuaternionClass } = await import('three');\n\t\t\t\t\ttmpPos = new Vector3Class();\n\t\t\t\t\ttmpEuler = new EulerClass();\n\t\t\t\t\ttmpQuat = new QuaternionClass();\n\t\t\t\t\ttmpScale = new Vector3Class();\n\n\t\t\t\t\tconst scene = ecs.getResource('scene');\n\t\t\t\t\tconst threeRenderer = ecs.getResource('threeRenderer');\n\t\t\t\t\tconst camera = ecs.getResource('camera');\n\n\t\t\t\t\t// Cache for hot-path render system\n\t\t\t\t\tcachedRenderer = threeRenderer;\n\t\t\t\t\tcachedScene = scene;\n\t\t\t\t\tcachedCamera = camera;\n\n\t\t\t\t\t// Helper to add a Three.js object to the scene.\n\t\t\t\t\t// Disable Three.js's per-frame matrix bookkeeping for managed objects:\n\t\t\t\t\t// the sync system writes obj.matrix and obj.matrixWorld manually only when\n\t\t\t\t\t// worldTransform3D actually changes, skipping the work for static frames.\n\t\t\t\t\tfunction addToScene(entityId: number, obj: Object3D): void {\n\t\t\t\t\t\tobj.matrixAutoUpdate = false;\n\t\t\t\t\t\tobj.matrixWorldAutoUpdate = false;\n\t\t\t\t\t\tentityToThreeObject.set(entityId, obj);\n\t\t\t\t\t\tscene.add(obj);\n\t\t\t\t\t}\n\n\t\t\t\t\tecs.addReactiveQuery('renderer3d-meshes', {\n\t\t\t\t\t\twith: ['mesh'],\n\t\t\t\t\t\tonEnter: (entity) => {\n\t\t\t\t\t\t\taddToScene(entity.id, entity.components.mesh);\n\t\t\t\t\t\t},\n\t\t\t\t\t\tonExit: (entityId) => {\n\t\t\t\t\t\t\tentityToThreeObject.delete(entityId);\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\n\t\t\t\t\tecs.addReactiveQuery('renderer3d-groups', {\n\t\t\t\t\t\twith: ['group'],\n\t\t\t\t\t\tonEnter: (entity) => {\n\t\t\t\t\t\t\taddToScene(entity.id, entity.components.group);\n\t\t\t\t\t\t},\n\t\t\t\t\t\tonExit: (entityId) => {\n\t\t\t\t\t\t\tentityToThreeObject.delete(entityId);\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\n\t\t\t\t\tecs.addReactiveQuery('renderer3d-objects', {\n\t\t\t\t\t\twith: ['object3d'],\n\t\t\t\t\t\tonEnter: (entity) => {\n\t\t\t\t\t\t\taddToScene(entity.id, entity.components.object3d);\n\t\t\t\t\t\t},\n\t\t\t\t\t\tonExit: (entityId) => {\n\t\t\t\t\t\t\tentityToThreeObject.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\tconst obj = entityToThreeObject.get(entityId);\n\t\t\t\t\t\tif (!obj) return;\n\t\t\t\t\t\t// Scene graph stays flat — all objects are children of scene directly.\n\t\t\t\t\t\t// Re-add to scene if somehow removed.\n\t\t\t\t\t\tif (obj.parent !== scene) {\n\t\t\t\t\t\t\tscene.add(obj);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\t// Resize handler\n\t\t\t\t\tconst resizeHandler = () => {\n\t\t\t\t\t\tconst w = threeRenderer.domElement.parentElement?.clientWidth ?? window.innerWidth;\n\t\t\t\t\t\tconst h = threeRenderer.domElement.parentElement?.clientHeight ?? window.innerHeight;\n\t\t\t\t\t\tthreeRenderer.setSize(w, h);\n\t\t\t\t\t\tif ((camera as PerspectiveCamera).isPerspectiveCamera) {\n\t\t\t\t\t\t\tconst perspCam = camera as PerspectiveCamera;\n\t\t\t\t\t\t\tperspCam.aspect = w / h;\n\t\t\t\t\t\t\tperspCam.updateProjectionMatrix();\n\t\t\t\t\t\t} else if ((camera as OrthographicCamera).isOrthographicCamera) {\n\t\t\t\t\t\t\tconst orthoCam = camera as OrthographicCamera;\n\t\t\t\t\t\t\tconst halfH = (orthoCam.top - orthoCam.bottom) / 2;\n\t\t\t\t\t\t\tconst halfW = halfH * (w / h);\n\t\t\t\t\t\t\torthoCam.left = -halfW;\n\t\t\t\t\t\t\torthoCam.right = halfW;\n\t\t\t\t\t\t\torthoCam.top = halfH;\n\t\t\t\t\t\t\torthoCam.bottom = -halfH;\n\t\t\t\t\t\t\torthoCam.updateProjectionMatrix();\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t\twindow.addEventListener('resize', resizeHandler);\n\n\t\t\t\t\t// Animation loop\n\t\t\t\t\tif (startLoop) {\n\t\t\t\t\t\tlet lastTime = 0;\n\t\t\t\t\t\tconst animate = (time: number) => {\n\t\t\t\t\t\t\trequestAnimationFrame(animate);\n\t\t\t\t\t\t\tconst dt = lastTime === 0 ? 0 : (time - lastTime) / 1000;\n\t\t\t\t\t\t\tlastTime = time;\n\t\t\t\t\t\t\tecs.update(dt);\n\t\t\t\t\t\t};\n\t\t\t\t\t\trequestAnimationFrame(animate);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t// ==================== Render System ====================\n\t\t\tworld\n\t\t\t\t.addSystem('renderer3d-render')\n\t\t\t\t.setPriority(0)\n\t\t\t\t.inPhase('render')\n\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t.setProcess(() => {\n\t\t\t\t\tif (cachedRenderer && cachedScene && cachedCamera) {\n\t\t\t\t\t\tcachedRenderer.render(cachedScene, cachedCamera);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t});\n}\n"
5
+ "/**\n * 3D Renderer Plugin for ECSpresso\n *\n * An opt-in Three.js-based 3D rendering plugin that automates scene graph wiring.\n * Import from 'ecspresso/plugins/rendering/renderer3D'\n *\n * This plugin includes 3D transform propagation automatically.\n */\n\nimport type {\n\tWebGLRenderer,\n\tWebGLRendererParameters,\n\tScene,\n\tCamera,\n\tPerspectiveCamera,\n\tOrthographicCamera,\n\tObject3D,\n\tMesh,\n\tGroup,\n\tColorRepresentation,\n\tVector3,\n\tEuler,\n\tQuaternion,\n} from 'three';\nimport { definePlugin, type Plugin } from 'ecspresso';\nimport type { ComponentsConfig, EmptyConfig, EventsConfig, ResourcesConfig } from '../../type-utils';\nimport type ECSpresso from 'ecspresso';\nimport {\n\tcreateTransform3DPlugin,\n\tcreateTransform3D,\n\ttype LocalTransform3D,\n\ttype WorldTransform3D,\n\ttype Transform3DComponentTypes,\n\ttype Transform3DPluginOptions,\n\tDEFAULT_LOCAL_TRANSFORM_3D,\n} from 'ecspresso/plugins/spatial/transform3D';\n\n// Re-export transform types for convenience\nexport type { LocalTransform3D, WorldTransform3D, Transform3DComponentTypes };\nexport {\n\tcreateTransform3D,\n\tcreateLocalTransform3D,\n\tcreateWorldTransform3D,\n\tDEFAULT_LOCAL_TRANSFORM_3D,\n\tDEFAULT_WORLD_TRANSFORM_3D,\n} from 'ecspresso/plugins/spatial/transform3D';\n\n// ==================== Component Types ====================\n\n/**\n * Visibility component for 3D entities.\n */\nexport interface Visible3D {\n\tvisible: boolean;\n}\n\n/**\n * Aggregate component types for the 3D renderer plugin.\n * Included automatically via `.withPlugin(createRenderer3DPlugin({ ... }))`.\n */\nexport interface Renderer3DComponentTypes extends Transform3DComponentTypes {\n\tmesh: Mesh;\n\tgroup: Group;\n\tobject3d: Object3D;\n\tvisible3d: Visible3D;\n\t/** Controls Three.js Object3D.renderOrder for manual z-ordering */\n\trenderOrder: number;\n}\n\n// ==================== Event Types ====================\n\n/**\n * Events emitted by the 3D renderer plugin.\n */\nexport interface Renderer3DEventTypes {\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 3D renderer plugin.\n */\nexport interface Renderer3DResourceTypes {\n\tthreeRenderer: WebGLRenderer;\n\tscene: Scene;\n\tcamera: Camera;\n}\n\n// ==================== Plugin Options ====================\n\n/**\n * Common options shared between both initialization modes.\n */\ninterface Renderer3DPluginCommonOptions<G extends string = 'renderer3d'> {\n\t/** System group name (default: 'renderer3d') */\n\tsystemGroup?: G;\n\t/** Priority for render sync system (default: 500) */\n\trenderSyncPriority?: number;\n\t/** Options for the included 3D transform plugin */\n\ttransform?: Transform3DPluginOptions;\n\t/** When true, starts a requestAnimationFrame loop to drive ecs.update() automatically (default: true) */\n\tstartLoop?: boolean;\n}\n\n/**\n * Options when providing pre-initialized Three.js objects.\n */\nexport interface Renderer3DPluginPreInitOptions<G extends string = 'renderer3d'> extends Renderer3DPluginCommonOptions<G> {\n\t/** Pre-initialized WebGLRenderer */\n\trenderer: WebGLRenderer;\n\t/** Pre-initialized Scene */\n\tscene: Scene;\n\t/** Pre-initialized Camera */\n\tcamera: Camera;\n\tcontainer?: never;\n\tbackground?: never;\n\twidth?: never;\n\theight?: never;\n\tantialias?: never;\n\tshadows?: never;\n\tcameraOptions?: never;\n\tthreeInit?: never;\n}\n\n/**\n * Camera configuration for managed mode.\n *\n * Discriminated on `projection`. Defaults to `'perspective'` when omitted.\n * Orthographic cameras use `viewSize` (world-unit height at zoom=1) to define\n * the base frustum; `zoom` maps directly to Three.js's `OrthographicCamera.zoom`.\n */\nexport type CameraOptions =\n\t| {\n\t\tprojection?: 'perspective';\n\t\tfov?: number;\n\t\tnear?: number;\n\t\tfar?: number;\n\t\tposition?: { x: number; y: number; z: number };\n\t\tlookAt?: { x: number; y: number; z: number };\n\t}\n\t| {\n\t\tprojection: 'orthographic';\n\t\tviewSize?: number;\n\t\tzoom?: number;\n\t\tnear?: number;\n\t\tfar?: number;\n\t\tposition?: { x: number; y: number; z: number };\n\t\tlookAt?: { x: number; y: number; z: number };\n\t};\n\n/**\n * Options when letting the plugin create and manage Three.js objects.\n */\nexport interface Renderer3DPluginManagedOptions<G extends string = 'renderer3d'> extends Renderer3DPluginCommonOptions<G> {\n\trenderer?: never;\n\tscene?: never;\n\tcamera?: never;\n\t/** Container element to append the canvas to (or CSS selector string). Defaults to `document.body`. */\n\tcontainer?: HTMLElement | string;\n\t/** Scene background color. */\n\tbackground?: ColorRepresentation;\n\t/** Canvas width. When omitted, auto-sizes to container. */\n\twidth?: number;\n\t/** Canvas height. When omitted, auto-sizes to container. */\n\theight?: number;\n\t/** Enable antialiasing (default: true) */\n\tantialias?: boolean;\n\t/** Enable shadow mapping (default: false) */\n\tshadows?: boolean;\n\t/** Camera configuration */\n\tcameraOptions?: CameraOptions;\n\t/** Escape hatch for raw WebGLRendererParameters not otherwise exposed. */\n\tthreeInit?: Partial<WebGLRendererParameters>;\n}\n\n/**\n * Configuration options for the 3D renderer plugin.\n *\n * Supports two modes:\n * 1. **Pre-initialized**: Pass already-initialized renderer, scene, camera\n * 2. **Managed**: Omit them and the plugin creates everything during `ecs.initialize()`\n *\n * This plugin includes 3D transform propagation automatically.\n *\n * @example Pre-initialized mode\n * ```typescript\n * const renderer = new WebGLRenderer({ antialias: true });\n * const scene = new Scene();\n * const camera = new PerspectiveCamera(75, w / h, 0.1, 1000);\n *\n * const ecs = ECSpresso.create()\n * .withPlugin(createRenderer3DPlugin({ renderer, scene, camera }))\n * .build();\n * ```\n *\n * @example Managed mode\n * ```typescript\n * const ecs = ECSpresso.create()\n * .withPlugin(createRenderer3DPlugin({\n * container: '#game',\n * background: 0x1099bb,\n * antialias: true,\n * cameraOptions: { fov: 75, position: { x: 0, y: 5, z: 10 } },\n * }))\n * .build();\n * await ecs.initialize();\n * ```\n */\nexport type Renderer3DPluginOptions<G extends string = 'renderer3d'> =\n\tRenderer3DPluginPreInitOptions<G> | Renderer3DPluginManagedOptions<G>;\n\n// ==================== Helper Utilities ====================\n\ninterface PositionOption3D {\n\tx?: number;\n\ty?: number;\n\tz?: number;\n}\n\ninterface TransformOptions3D {\n\trotation?: { x?: number; y?: number; z?: number };\n\tscale?: number | { x: number; y: number; z: number };\n\tvisible?: boolean;\n}\n\nfunction buildTransformComponents(\n\tposition?: PositionOption3D,\n\toptions?: TransformOptions3D,\n): Transform3DComponentTypes {\n\tconst scaleValue = options?.scale;\n\tconst scaleOpts = typeof scaleValue === 'number'\n\t\t? { scale: scaleValue }\n\t\t: scaleValue\n\t\t\t? { scaleX: scaleValue.x, scaleY: scaleValue.y, scaleZ: scaleValue.z }\n\t\t\t: undefined;\n\n\treturn createTransform3D(\n\t\tposition?.x ?? 0,\n\t\tposition?.y ?? 0,\n\t\tposition?.z ?? 0,\n\t\t{ rotation: options?.rotation, ...scaleOpts },\n\t);\n}\n\n/**\n * Create components for a mesh entity.\n * Returns an object suitable for spreading into spawn().\n *\n * @example\n * ```typescript\n * const player = ecs.spawn({\n * ...createMeshComponents(myMesh, { x: 10, y: 0, z: -5 }),\n * velocity: { x: 0, y: 0, z: 0 },\n * });\n * ```\n */\nexport function createMeshComponents(\n\tmesh: Mesh,\n\tposition?: PositionOption3D,\n\toptions?: TransformOptions3D,\n): Pick<Renderer3DComponentTypes, 'mesh' | 'localTransform3D' | 'worldTransform3D' | 'visible3d'> {\n\treturn {\n\t\tmesh,\n\t\t...buildTransformComponents(position, options),\n\t\tvisible3d: { visible: options?.visible ?? true },\n\t};\n}\n\n/**\n * Create components for a group entity.\n * Returns an object suitable for spreading into spawn().\n *\n * @example\n * ```typescript\n * const enemies = ecs.spawn({\n * ...createGroupComponents(enemyGroup, { x: 50, y: 0, z: -30 }),\n * });\n * ```\n */\nexport function createGroupComponents(\n\tgroup: Group,\n\tposition?: PositionOption3D,\n\toptions?: TransformOptions3D,\n): Pick<Renderer3DComponentTypes, 'group' | 'localTransform3D' | 'worldTransform3D' | 'visible3d'> {\n\treturn {\n\t\tgroup,\n\t\t...buildTransformComponents(position, options),\n\t\tvisible3d: { visible: options?.visible ?? true },\n\t};\n}\n\n/**\n * Create components for a generic Object3D entity.\n * Returns an object suitable for spreading into spawn().\n *\n * @example\n * ```typescript\n * const obj = ecs.spawn({\n * ...createObject3DComponents(myObject, { x: 0, y: 0, z: 0 }),\n * });\n * ```\n */\nexport function createObject3DComponents(\n\tobject3d: Object3D,\n\tposition?: PositionOption3D,\n\toptions?: TransformOptions3D,\n): Pick<Renderer3DComponentTypes, 'object3d' | 'localTransform3D' | 'worldTransform3D' | 'visible3d'> {\n\treturn {\n\t\tobject3d,\n\t\t...buildTransformComponents(position, options),\n\t\tvisible3d: { visible: options?.visible ?? true },\n\t};\n}\n\n// ==================== Sync Helper ====================\n\n/**\n * Apply worldTransform3D and visible3d to a Three.js Object3D.\n *\n * Managed objects have matrixAutoUpdate / matrixWorldAutoUpdate disabled\n * (see addToScene), so we recompose obj.matrix and refresh obj.matrixWorld\n * ourselves. Because the plugin keeps a flat scene graph AND assumes the scene\n * root stays at identity, world = local — so we skip a 4x4 matmul and copy.\n *\n * Note: obj.position / obj.rotation / obj.scale are NOT kept in sync — read\n * worldTransform3D from the ECS component if you need current values.\n */\nfunction syncObject3D(\n\tobj: Object3D,\n\twt: WorldTransform3D,\n\tvis: Visible3D,\n\tpos: Vector3,\n\teuler: Euler,\n\tquat: Quaternion,\n\tscale: Vector3,\n): void {\n\tpos.set(wt.x, wt.y, wt.z);\n\teuler.set(wt.rx, wt.ry, wt.rz, 'XYZ');\n\tquat.setFromEuler(euler);\n\tscale.set(wt.sx, wt.sy, wt.sz);\n\tobj.matrix.compose(pos, quat, scale);\n\tobj.matrixWorld.copy(obj.matrix);\n\tobj.visible = vis.visible;\n}\n\n// ==================== Plugin Factory ====================\n\ntype Renderer3DLabels = 'renderer3d-sync' | 'renderer3d-scene-graph' | 'renderer3d-render' | 'transform3d-propagation';\ntype Renderer3DReactiveQueryNames = 'renderer3d-meshes' | 'renderer3d-groups' | 'renderer3d-objects';\ntype Renderer3DWorldConfig =\n\tComponentsConfig<Renderer3DComponentTypes>\n\t& EventsConfig<Renderer3DEventTypes>\n\t& ResourcesConfig<Renderer3DResourceTypes>;\n\n/**\n * Create a 3D rendering plugin for ECSpresso.\n *\n * This plugin provides:\n * - 3D transform propagation (localTransform3D -> worldTransform3D)\n * - Render sync system (updates Three.js objects from ECS components)\n * - Scene graph management (auto-adds/removes Three.js objects)\n * - Render call (renderer.render(scene, camera) each frame)\n * - Optional requestAnimationFrame loop\n */\nexport function createRenderer3DPlugin<G extends string = 'renderer3d'>(\n\toptions: Renderer3DPluginOptions<G>,\n): Plugin<Renderer3DWorldConfig, EmptyConfig, Renderer3DLabels, G, never, Renderer3DReactiveQueryNames> {\n\tconst {\n\t\tsystemGroup = 'renderer3d',\n\t\trenderSyncPriority = 500,\n\t\ttransform: transformOptions,\n\t\tstartLoop = true,\n\t} = options;\n\n\t// Entity ID -> Three.js Object3D mapping for scene graph management\n\tconst entityToThreeObject = new Map<number, Object3D>();\n\n\t// Cached resource references, set during scene-graph init for hot-path access\n\tlet cachedRenderer: WebGLRenderer | null = null;\n\tlet cachedScene: Scene | null = null;\n\tlet cachedCamera: Camera | null = null;\n\n\t// Preallocated math temporaries for syncObject3D, allocated during scene-graph init.\n\tlet tmpPos: Vector3 | null = null;\n\tlet tmpEuler: Euler | null = null;\n\tlet tmpQuat: Quaternion | null = null;\n\tlet tmpScale: Vector3 | null = null;\n\n\t// Determine mode: pre-initialized if renderer was provided\n\tconst isManaged = !('renderer' in options && options.renderer !== undefined);\n\n\ttype PluginECS = ECSpresso<Renderer3DWorldConfig>;\n\n\treturn definePlugin('renderer3d')\n\t\t.withComponentTypes<Renderer3DComponentTypes>()\n\t\t.withEventTypes<Renderer3DEventTypes>()\n\t\t.withResourceTypes<Renderer3DResourceTypes>()\n\t\t.withLabels<Renderer3DLabels>()\n\t\t.withGroups<G>()\n\t\t.withReactiveQueryNames<Renderer3DReactiveQueryNames>()\n\t\t.install((world) => {\n\t\t\t// Install 3D transform plugin (deduplicates if already installed)\n\t\t\tworld.installPlugin(createTransform3DPlugin(transformOptions));\n\n\t\t\t// Register resources based on mode\n\t\t\tif (isManaged) {\n\t\t\t\tconst managedOptions = options as Renderer3DPluginManagedOptions<G>;\n\t\t\t\tconst {\n\t\t\t\t\tbackground,\n\t\t\t\t\twidth,\n\t\t\t\t\theight,\n\t\t\t\t\tantialias = true,\n\t\t\t\t\tshadows = false,\n\t\t\t\t\tcameraOptions,\n\t\t\t\t\tthreeInit,\n\t\t\t\t} = managedOptions;\n\t\t\t\tconst containerOption = managedOptions.container ?? document.body;\n\n\t\t\t\tworld.addResource('threeRenderer', async () => {\n\t\t\t\t\tconst { WebGLRenderer: WebGLRendererClass } = await import('three');\n\n\t\t\t\t\tconst containerEl: HTMLElement | null = typeof containerOption === 'string'\n\t\t\t\t\t\t? document.querySelector<HTMLElement>(containerOption)\n\t\t\t\t\t\t: containerOption;\n\n\t\t\t\t\tconst rendererParams: WebGLRendererParameters = {\n\t\t\t\t\t\tantialias,\n\t\t\t\t\t\tpowerPreference: 'high-performance',\n\t\t\t\t\t\t...threeInit,\n\t\t\t\t\t};\n\n\t\t\t\t\tconst renderer = new WebGLRendererClass(rendererParams);\n\n\t\t\t\t\tif (shadows) {\n\t\t\t\t\t\trenderer.shadowMap.enabled = true;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst w = width ?? containerEl?.clientWidth ?? window.innerWidth;\n\t\t\t\t\tconst h = height ?? containerEl?.clientHeight ?? window.innerHeight;\n\t\t\t\t\trenderer.setSize(w, h);\n\n\t\t\t\t\tif (containerEl) {\n\t\t\t\t\t\tcontainerEl.appendChild(renderer.domElement);\n\t\t\t\t\t} else if (typeof containerOption === 'string') {\n\t\t\t\t\t\tconsole.warn(`Renderer3D plugin: container selector \"${containerOption}\" not found`);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn renderer;\n\t\t\t\t});\n\n\t\t\t\tworld.addResource('scene', {\n\t\t\t\t\tdependsOn: ['threeRenderer'],\n\t\t\t\t\tfactory: async () => {\n\t\t\t\t\t\tconst { Scene: SceneClass, Color } = await import('three');\n\t\t\t\t\t\tconst scene = new SceneClass();\n\t\t\t\t\t\tif (background !== undefined) {\n\t\t\t\t\t\t\tscene.background = new Color(background);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn scene;\n\t\t\t\t\t},\n\t\t\t\t});\n\n\t\t\t\tworld.addResource('camera', {\n\t\t\t\t\tdependsOn: ['threeRenderer'],\n\t\t\t\t\tfactory: async (ecs) => {\n\t\t\t\t\t\tconst renderer = ecs.getResource('threeRenderer');\n\t\t\t\t\t\tconst aspect = renderer.domElement.width / renderer.domElement.height;\n\t\t\t\t\t\tconst near = cameraOptions?.near ?? 0.1;\n\t\t\t\t\t\tconst far = cameraOptions?.far ?? 1000;\n\n\t\t\t\t\t\tlet cam: Camera;\n\t\t\t\t\t\tif (cameraOptions?.projection === 'orthographic') {\n\t\t\t\t\t\t\tconst { OrthographicCamera: OrthographicCameraClass } = await import('three');\n\t\t\t\t\t\t\tconst viewSize = cameraOptions.viewSize ?? 10;\n\t\t\t\t\t\t\tconst halfH = viewSize / 2;\n\t\t\t\t\t\t\tconst halfW = halfH * aspect;\n\t\t\t\t\t\t\tconst ortho = new OrthographicCameraClass(-halfW, halfW, halfH, -halfH, near, far);\n\t\t\t\t\t\t\tortho.zoom = cameraOptions.zoom ?? 1;\n\t\t\t\t\t\t\tortho.updateProjectionMatrix();\n\t\t\t\t\t\t\tcam = ortho;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconst { PerspectiveCamera: PerspectiveCameraClass } = await import('three');\n\t\t\t\t\t\t\tconst fov = cameraOptions?.fov ?? 75;\n\t\t\t\t\t\t\tcam = new PerspectiveCameraClass(fov, aspect, near, far);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (cameraOptions?.position) {\n\t\t\t\t\t\t\tcam.position.set(\n\t\t\t\t\t\t\t\tcameraOptions.position.x,\n\t\t\t\t\t\t\t\tcameraOptions.position.y,\n\t\t\t\t\t\t\t\tcameraOptions.position.z,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (cameraOptions?.lookAt) {\n\t\t\t\t\t\t\tcam.lookAt(\n\t\t\t\t\t\t\t\tcameraOptions.lookAt.x,\n\t\t\t\t\t\t\t\tcameraOptions.lookAt.y,\n\t\t\t\t\t\t\t\tcameraOptions.lookAt.z,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn cam;\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconst preInit = options as Renderer3DPluginPreInitOptions<G>;\n\t\t\t\tworld.addResource('threeRenderer', preInit.renderer);\n\t\t\t\tworld.addResource('scene', preInit.scene);\n\t\t\t\tworld.addResource('camera', preInit.camera);\n\t\t\t}\n\n\t\t\t// Register dispose callbacks for 3D object components\n\t\t\tworld.registerDispose('mesh', ({ value }) => {\n\t\t\t\tif (value.parent) value.parent.remove(value);\n\t\t\t});\n\t\t\tworld.registerDispose('group', ({ value }) => {\n\t\t\t\tif (value.parent) value.parent.remove(value);\n\t\t\t});\n\t\t\tworld.registerDispose('object3d', ({ value }) => {\n\t\t\t\tif (value.parent) value.parent.remove(value);\n\t\t\t});\n\n\t\t\t// 3D objects require localTransform3D and visible3d\n\t\t\tworld.registerRequired('mesh', 'localTransform3D', () => ({ ...DEFAULT_LOCAL_TRANSFORM_3D }));\n\t\t\tworld.registerRequired('mesh', 'visible3d', () => ({ visible: true }));\n\t\t\tworld.registerRequired('group', 'localTransform3D', () => ({ ...DEFAULT_LOCAL_TRANSFORM_3D }));\n\t\t\tworld.registerRequired('group', 'visible3d', () => ({ visible: true }));\n\t\t\tworld.registerRequired('object3d', 'localTransform3D', () => ({ ...DEFAULT_LOCAL_TRANSFORM_3D }));\n\t\t\tworld.registerRequired('object3d', 'visible3d', () => ({ visible: true }));\n\n\t\t\t// ==================== Render Sync System ====================\n\t\t\tworld\n\t\t\t\t.addSystem('renderer3d-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('meshes', {\n\t\t\t\t\twith: ['mesh', 'worldTransform3D', 'visible3d'],\n\t\t\t\t\tchanged: ['worldTransform3D'],\n\t\t\t\t})\n\t\t\t\t.addQuery('groups', {\n\t\t\t\t\twith: ['group', 'worldTransform3D', 'visible3d'],\n\t\t\t\t\tchanged: ['worldTransform3D'],\n\t\t\t\t})\n\t\t\t\t.addQuery('objects', {\n\t\t\t\t\twith: ['object3d', 'worldTransform3D', 'visible3d'],\n\t\t\t\t\tchanged: ['worldTransform3D'],\n\t\t\t\t})\n\t\t\t\t.setProcess(({ queries }) => {\n\t\t\t\t\tconst pos = tmpPos;\n\t\t\t\t\tconst euler = tmpEuler;\n\t\t\t\t\tconst quat = tmpQuat;\n\t\t\t\t\tconst scale = tmpScale;\n\t\t\t\t\tif (!pos || !euler || !quat || !scale) return;\n\n\t\t\t\t\tfor (const entity of queries.meshes) {\n\t\t\t\t\t\tconst { mesh, worldTransform3D, visible3d } = entity.components;\n\t\t\t\t\t\tsyncObject3D(mesh, worldTransform3D, visible3d, pos, euler, quat, scale);\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (const entity of queries.groups) {\n\t\t\t\t\t\tconst { group, worldTransform3D, visible3d } = entity.components;\n\t\t\t\t\t\tsyncObject3D(group, worldTransform3D, visible3d, pos, euler, quat, scale);\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (const entity of queries.objects) {\n\t\t\t\t\t\tconst { object3d, worldTransform3D, visible3d } = entity.components;\n\t\t\t\t\t\tsyncObject3D(object3d, worldTransform3D, visible3d, pos, euler, quat, scale);\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('renderer3d-scene-graph')\n\t\t\t\t.setPriority(9999)\n\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t.setOnInitialize(async (ecs: PluginECS) => {\n\t\t\t\t\tconst { Vector3: Vector3Class, Euler: EulerClass, Quaternion: QuaternionClass } = await import('three');\n\t\t\t\t\ttmpPos = new Vector3Class();\n\t\t\t\t\ttmpEuler = new EulerClass();\n\t\t\t\t\ttmpQuat = new QuaternionClass();\n\t\t\t\t\ttmpScale = new Vector3Class();\n\n\t\t\t\t\tconst scene = ecs.getResource('scene');\n\t\t\t\t\tconst threeRenderer = ecs.getResource('threeRenderer');\n\t\t\t\t\tconst camera = ecs.getResource('camera');\n\n\t\t\t\t\t// Cache for hot-path render system\n\t\t\t\t\tcachedRenderer = threeRenderer;\n\t\t\t\t\tcachedScene = scene;\n\t\t\t\t\tcachedCamera = camera;\n\n\t\t\t\t\t// Helper to add a Three.js object to the scene.\n\t\t\t\t\t// Disable Three.js's per-frame matrix bookkeeping for managed objects:\n\t\t\t\t\t// the sync system writes obj.matrix and obj.matrixWorld manually only when\n\t\t\t\t\t// worldTransform3D actually changes, skipping the work for static frames.\n\t\t\t\t\tfunction addToScene(entityId: number, obj: Object3D): void {\n\t\t\t\t\t\tobj.matrixAutoUpdate = false;\n\t\t\t\t\t\tobj.matrixWorldAutoUpdate = false;\n\t\t\t\t\t\tentityToThreeObject.set(entityId, obj);\n\t\t\t\t\t\tscene.add(obj);\n\t\t\t\t\t}\n\n\t\t\t\t\tecs.addReactiveQuery('renderer3d-meshes', {\n\t\t\t\t\t\twith: ['mesh'],\n\t\t\t\t\t\tonEnter: ({ entity }) => {\n\t\t\t\t\t\t\taddToScene(entity.id, entity.components.mesh);\n\t\t\t\t\t\t},\n\t\t\t\t\t\tonExit: ({ entityId }) => {\n\t\t\t\t\t\t\tentityToThreeObject.delete(entityId);\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\n\t\t\t\t\tecs.addReactiveQuery('renderer3d-groups', {\n\t\t\t\t\t\twith: ['group'],\n\t\t\t\t\t\tonEnter: ({ entity }) => {\n\t\t\t\t\t\t\taddToScene(entity.id, entity.components.group);\n\t\t\t\t\t\t},\n\t\t\t\t\t\tonExit: ({ entityId }) => {\n\t\t\t\t\t\t\tentityToThreeObject.delete(entityId);\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\n\t\t\t\t\tecs.addReactiveQuery('renderer3d-objects', {\n\t\t\t\t\t\twith: ['object3d'],\n\t\t\t\t\t\tonEnter: ({ entity }) => {\n\t\t\t\t\t\t\taddToScene(entity.id, entity.components.object3d);\n\t\t\t\t\t\t},\n\t\t\t\t\t\tonExit: ({ entityId }) => {\n\t\t\t\t\t\t\tentityToThreeObject.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\tconst obj = entityToThreeObject.get(entityId);\n\t\t\t\t\t\tif (!obj) return;\n\t\t\t\t\t\t// Scene graph stays flat — all objects are children of scene directly.\n\t\t\t\t\t\t// Re-add to scene if somehow removed.\n\t\t\t\t\t\tif (obj.parent !== scene) {\n\t\t\t\t\t\t\tscene.add(obj);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\t// Resize handler\n\t\t\t\t\tconst resizeHandler = () => {\n\t\t\t\t\t\tconst w = threeRenderer.domElement.parentElement?.clientWidth ?? window.innerWidth;\n\t\t\t\t\t\tconst h = threeRenderer.domElement.parentElement?.clientHeight ?? window.innerHeight;\n\t\t\t\t\t\tthreeRenderer.setSize(w, h);\n\t\t\t\t\t\tif ((camera as PerspectiveCamera).isPerspectiveCamera) {\n\t\t\t\t\t\t\tconst perspCam = camera as PerspectiveCamera;\n\t\t\t\t\t\t\tperspCam.aspect = w / h;\n\t\t\t\t\t\t\tperspCam.updateProjectionMatrix();\n\t\t\t\t\t\t} else if ((camera as OrthographicCamera).isOrthographicCamera) {\n\t\t\t\t\t\t\tconst orthoCam = camera as OrthographicCamera;\n\t\t\t\t\t\t\tconst halfH = (orthoCam.top - orthoCam.bottom) / 2;\n\t\t\t\t\t\t\tconst halfW = halfH * (w / h);\n\t\t\t\t\t\t\torthoCam.left = -halfW;\n\t\t\t\t\t\t\torthoCam.right = halfW;\n\t\t\t\t\t\t\torthoCam.top = halfH;\n\t\t\t\t\t\t\torthoCam.bottom = -halfH;\n\t\t\t\t\t\t\torthoCam.updateProjectionMatrix();\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t\twindow.addEventListener('resize', resizeHandler);\n\n\t\t\t\t\t// Animation loop\n\t\t\t\t\tif (startLoop) {\n\t\t\t\t\t\tlet lastTime = 0;\n\t\t\t\t\t\tconst animate = (time: number) => {\n\t\t\t\t\t\t\trequestAnimationFrame(animate);\n\t\t\t\t\t\t\tconst dt = lastTime === 0 ? 0 : (time - lastTime) / 1000;\n\t\t\t\t\t\t\tlastTime = time;\n\t\t\t\t\t\t\tecs.update(dt);\n\t\t\t\t\t\t};\n\t\t\t\t\t\trequestAnimationFrame(animate);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t// ==================== Render System ====================\n\t\t\tworld\n\t\t\t\t.addSystem('renderer3d-render')\n\t\t\t\t.setPriority(0)\n\t\t\t\t.inPhase('render')\n\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t.setProcess(() => {\n\t\t\t\t\tif (cachedRenderer && cachedScene && cachedCamera) {\n\t\t\t\t\t\tcachedRenderer.render(cachedScene, cachedCamera);\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": "4D8B1BD0246DFAAD64756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "AE1D48ECD13E603A64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -9,7 +9,7 @@
9
9
  * regardless of source.
10
10
  */
11
11
  import { type BasePluginOptions } from 'ecspresso';
12
- import type { WorldConfigFrom, EmptyConfig } from '../../type-utils';
12
+ import type { ComponentsConfig, ResourcesConfig } from '../../type-utils';
13
13
  import { type NavGrid } from '../ai/pathfinding';
14
14
  import type { Vector2D } from '../../utils/math';
15
15
  export declare const TILE_FLIP_HORIZONTAL = 2147483648;
@@ -199,7 +199,7 @@ export interface TilemapRegistry {
199
199
  export interface TilemapResourceTypes {
200
200
  tilemaps: TilemapRegistry;
201
201
  }
202
- export type TilemapWorldConfig = WorldConfigFrom<TilemapComponentTypes, EmptyConfig['events'], TilemapResourceTypes>;
202
+ export type TilemapWorldConfig = ComponentsConfig<TilemapComponentTypes> & ResourcesConfig<TilemapResourceTypes>;
203
203
  export interface TilemapPluginOptions<G extends string = 'rendering'> extends BasePluginOptions<G> {
204
204
  /** Optional collision layer name. When set, solid tiles auto-spawn `aabbCollider` strips. */
205
205
  collisionLayer?: string;
@@ -208,7 +208,7 @@ export interface TilemapPluginOptions<G extends string = 'rendering'> extends Ba
208
208
  }
209
209
  export declare function createLoadedTilemap(data: TilemapRuntimeData): LoadedTilemap;
210
210
  export declare function parseTiledJSON(map: TiledMap, options: ParseTiledOptions): LoadedTilemap;
211
- export declare function createTilemapPlugin<G extends string = 'rendering'>(options?: TilemapPluginOptions<G>): import("ecspresso").Plugin<import("ecspresso").WithResources<import("ecspresso").WithComponents<EmptyConfig, TilemapComponentTypes>, TilemapResourceTypes>, EmptyConfig, never, G, never, never>;
211
+ export declare function createTilemapPlugin<G extends string = 'rendering'>(options?: TilemapPluginOptions<G>): import("ecspresso").Plugin<import("ecspresso").WithResources<import("ecspresso").WithComponents<import("ecspresso").EmptyConfig, TilemapComponentTypes>, TilemapResourceTypes>, import("ecspresso").EmptyConfig, never, G, never, never>;
212
212
  /**
213
213
  * Create a `tilemap` layer component for spreading into `spawn()`.
214
214
  *
@@ -2,10 +2,10 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/plugins/ai/pathfinding.ts", "../src/plugins/rendering/tilemap.ts"],
4
4
  "sourcesContent": [
5
- "/**\n * Pathfinding Plugin for ECSpresso\n *\n * A* pathfinding on a weighted grid. Produces waypoint lists consumed by the\n * steering plugin — the pathfinding system writes the `path` component and\n * sets `moveTarget` to the first waypoint; the waypoint advancement handler\n * listens for `arriveAtTarget` and advances to the next waypoint.\n *\n * Exports the pure `findPath(grid, start, goal, options?)` function for\n * turn-based / non-realtime consumers that don't need the component dance.\n */\n\nimport { definePlugin, type BasePluginOptions } from 'ecspresso';\nimport type { WorldConfigFrom } from 'ecspresso';\nimport type { Vector2D } from '../../utils/math';\nimport type { TransformWorldConfig } from '../spatial/transform';\nimport type { SteeringWorldConfig } from '../physics/steering';\n\n// ==================== Topology / Grid Types ====================\n\n/** Flat-indexed cell position in a `NavGrid`. Transparent alias, not branded. */\nexport type CellIndex = number;\n\n/**\n * Grid topology. v1 ships `square4`; other values are accepted at construction\n * but throw at `findPath` time.\n */\nexport type NavGridTopology = 'square4' | 'square8' | 'hex-pointy' | 'hex-flat';\n\n/**\n * Weighted navigation grid. Row-major storage (`idx = row * width + col`).\n * Cell value `0` = impassable, `1`–`255` = traversal cost into that cell.\n */\nexport interface NavGrid {\n\treadonly topology: NavGridTopology;\n\treadonly width: number;\n\treadonly height: number;\n\treadonly cellSize: number;\n\treadonly originX: number;\n\treadonly originY: number;\n\treadonly cells: Uint8Array;\n\tworldToCell(wx: number, wy: number): CellIndex;\n\tcellToWorld(idx: CellIndex): Vector2D;\n\tcellFromXY(x: number, y: number): CellIndex;\n\tcellToXY(idx: CellIndex): { x: number; y: number };\n}\n\n/** Options accepted by `createNavGrid`. */\nexport interface CreateNavGridOptions {\n\ttopology?: NavGridTopology;\n\twidth: number;\n\theight: number;\n\tcellSize?: number;\n\toriginX?: number;\n\toriginY?: number;\n\tcells?: Uint8Array;\n\tdefaultCost?: number;\n}\n\n// ==================== Component Types ====================\n\n/** Signals the pathfinding system to compute a route to `target`. */\nexport interface PathRequest {\n\ttarget: Vector2D;\n}\n\n/** Active route; waypoints are in world-space, advanced by `currentIndex`. */\nexport interface Path {\n\twaypoints: Vector2D[];\n\tcurrentIndex: number;\n}\n\n/** Component types provided by the pathfinding plugin. */\nexport interface PathfindingComponentTypes {\n\tpathRequest: PathRequest;\n\tpath: Path;\n}\n\n// ==================== Event Types ====================\n\n/** Fired when A* produces a route. `path` is empty when start is already at the goal. */\nexport interface PathFoundEvent {\n\tentityId: number;\n\tpath: Vector2D[];\n}\n\n/** Fired when no path exists to the target. */\nexport interface PathBlockedEvent {\n\tentityId: number;\n}\n\n/** Event types provided by the pathfinding plugin. */\nexport interface PathfindingEventTypes {\n\tpathFound: PathFoundEvent;\n\tpathBlocked: PathBlockedEvent;\n}\n\n// ==================== Resource Types ====================\n\n/** Resource types provided by the pathfinding plugin. */\nexport interface PathfindingResourceTypes {\n\tnavGrid: NavGrid;\n}\n\n// ==================== WorldConfig ====================\n\n/** WorldConfig representing the pathfinding plugin's provided types. */\nexport type PathfindingWorldConfig = WorldConfigFrom<\n\tPathfindingComponentTypes,\n\tPathfindingEventTypes,\n\tPathfindingResourceTypes\n>;\n\n// ==================== Plugin Options ====================\n\nexport interface PathfindingPluginOptions<G extends string = 'ai'> extends BasePluginOptions<G> {\n\t/** The navigation grid. Construct via `createNavGrid`. */\n\tgrid: NavGrid;\n\t/** Max path requests processed per frame (default 4). */\n\tmaxRequestsPerFrame?: number;\n\t/** Default `maxNodesExpanded` passed to A* per request (default 10_000). */\n\tmaxNodesExpanded?: number;\n}\n\n// ==================== NavGrid Construction ====================\n\ninterface TopologyOps {\n\tneighbors(grid: NavGrid, idx: CellIndex, out: number[]): number;\n\tstepCost(grid: NavGrid, from: CellIndex, to: CellIndex): number;\n\theuristic(grid: NavGrid, a: CellIndex, b: CellIndex): number;\n}\n\nconst square4Ops: TopologyOps = {\n\tneighbors(grid, idx, out) {\n\t\tconst col = idx % grid.width;\n\t\tconst row = (idx - col) / grid.width;\n\t\tlet count = 0;\n\t\tif (col > 0) out[count++] = idx - 1;\n\t\tif (col < grid.width - 1) out[count++] = idx + 1;\n\t\tif (row > 0) out[count++] = idx - grid.width;\n\t\tif (row < grid.height - 1) out[count++] = idx + grid.width;\n\t\treturn count;\n\t},\n\tstepCost(grid, _from, to) {\n\t\treturn grid.cells[to] ?? 0;\n\t},\n\theuristic(grid, a, b) {\n\t\tconst ax = a % grid.width;\n\t\tconst ay = (a - ax) / grid.width;\n\t\tconst bx = b % grid.width;\n\t\tconst by = (b - bx) / grid.width;\n\t\treturn Math.abs(ax - bx) + Math.abs(ay - by);\n\t},\n};\n\nconst unimplementedOps = (topology: NavGridTopology): TopologyOps => {\n\tconst err = (): never => {\n\t\tthrow new Error(`pathfinding: topology '${topology}' is not implemented in v1`);\n\t};\n\treturn {\n\t\tneighbors: err,\n\t\tstepCost: err,\n\t\theuristic: err,\n\t};\n};\n\nconst topologyOps: Readonly<Record<NavGridTopology, TopologyOps>> = Object.freeze({\n\t'square4': square4Ops,\n\t'square8': unimplementedOps('square8'),\n\t'hex-pointy': unimplementedOps('hex-pointy'),\n\t'hex-flat': unimplementedOps('hex-flat'),\n});\n\n/**\n * Create a weighted navigation grid.\n *\n * @example\n * ```typescript\n * const grid = createNavGrid({ width: 32, height: 32, cellSize: 16 });\n * grid.cells[grid.cellFromXY(5, 5)] = 0; // block a cell\n * ```\n */\nexport function createNavGrid(options: CreateNavGridOptions): NavGrid {\n\tconst topology = options.topology ?? 'square4';\n\tconst cellSize = options.cellSize ?? 32;\n\tconst originX = options.originX ?? 0;\n\tconst originY = options.originY ?? 0;\n\tconst { width, height } = options;\n\tconst defaultCost = options.defaultCost ?? 1;\n\n\tif (!Number.isInteger(width) || width <= 0) {\n\t\tthrow new Error(`pathfinding: width must be a positive integer, got ${width}`);\n\t}\n\tif (!Number.isInteger(height) || height <= 0) {\n\t\tthrow new Error(`pathfinding: height must be a positive integer, got ${height}`);\n\t}\n\tif (cellSize <= 0) {\n\t\tthrow new Error(`pathfinding: cellSize must be > 0, got ${cellSize}`);\n\t}\n\tif (defaultCost < 0 || defaultCost > 255) {\n\t\tthrow new Error(`pathfinding: defaultCost must be in 0–255, got ${defaultCost}`);\n\t}\n\n\tconst expectedLen = width * height;\n\tconst cells = options.cells ?? new Uint8Array(expectedLen).fill(defaultCost);\n\tif (cells.length !== expectedLen) {\n\t\tthrow new Error(\n\t\t\t`pathfinding: cells length ${cells.length} does not match width*height ${expectedLen}`,\n\t\t);\n\t}\n\n\tconst invCellSize = 1 / cellSize;\n\n\tconst worldToCell = (wx: number, wy: number): CellIndex => {\n\t\tconst col = Math.floor((wx - originX) * invCellSize);\n\t\tconst row = Math.floor((wy - originY) * invCellSize);\n\t\tconst cCol = col < 0 ? 0 : col >= width ? width - 1 : col;\n\t\tconst cRow = row < 0 ? 0 : row >= height ? height - 1 : row;\n\t\treturn cRow * width + cCol;\n\t};\n\n\tconst cellToWorld = (idx: CellIndex): Vector2D => {\n\t\tconst col = idx % width;\n\t\tconst row = (idx - col) / width;\n\t\treturn {\n\t\t\tx: originX + (col + 0.5) * cellSize,\n\t\t\ty: originY + (row + 0.5) * cellSize,\n\t\t};\n\t};\n\n\tconst cellFromXY = (x: number, y: number): CellIndex => y * width + x;\n\n\tconst cellToXY = (idx: CellIndex): { x: number; y: number } => {\n\t\tconst x = idx % width;\n\t\treturn { x, y: (idx - x) / width };\n\t};\n\n\treturn {\n\t\ttopology, width, height, cellSize, originX, originY, cells,\n\t\tworldToCell, cellToWorld, cellFromXY, cellToXY,\n\t};\n}\n\n// ==================== Helper Functions ====================\n\n/**\n * Create a `pathRequest` component for spreading into `spawn()` / `addComponent()`.\n *\n * @example\n * ```typescript\n * ecs.spawn({\n * ...createTransform(0, 0),\n * ...createMoveSpeed(100),\n * ...createPathRequest({ x: 200, y: 300 }),\n * });\n * ```\n */\nexport function createPathRequest(target: Vector2D): Pick<PathfindingComponentTypes, 'pathRequest'> {\n\treturn { pathRequest: { target: { x: target.x, y: target.y } } };\n}\n\n// ==================== Pure A* API ====================\n\nexport interface FindPathOptions {\n\t/** Cap on A* node expansions; returns `null` if exceeded. Default 10_000. */\n\tmaxNodesExpanded?: number;\n\t/** Dynamic per-call obstacles layered on top of the static grid. */\n\tblockedCells?: Set<CellIndex>;\n\t/** Accept arrival within N cells of goal (topology-aware distance). Default 0. */\n\tgoalTolerance?: number;\n}\n\ninterface PathHeap {\n\tids: Int32Array;\n\tpriorities: Float32Array;\n\tsize: number;\n}\n\n// Why: parallel-typed-array heap keeps cells & priorities in cache without per-node allocations.\nfunction heapPush(heap: PathHeap, id: number, priority: number): void {\n\tlet i = heap.size;\n\theap.size = i + 1;\n\twhile (i > 0) {\n\t\tconst parent = (i - 1) >> 1;\n\t\tif ((heap.priorities[parent] ?? 0) <= priority) break;\n\t\theap.ids[i] = heap.ids[parent] ?? 0;\n\t\theap.priorities[i] = heap.priorities[parent] ?? 0;\n\t\ti = parent;\n\t}\n\theap.ids[i] = id;\n\theap.priorities[i] = priority;\n}\n\nfunction heapPop(heap: PathHeap): number {\n\tconst top = heap.ids[0] ?? -1;\n\tconst last = heap.size - 1;\n\theap.size = last;\n\tif (last <= 0) return top;\n\tconst movedId = heap.ids[last] ?? 0;\n\tconst movedPri = heap.priorities[last] ?? 0;\n\tlet i = 0;\n\tconst half = last >> 1;\n\twhile (i < half) {\n\t\tlet child = (i << 1) + 1;\n\t\tconst right = child + 1;\n\t\tif (right < last && (heap.priorities[right] ?? 0) < (heap.priorities[child] ?? 0)) child = right;\n\t\tif ((heap.priorities[child] ?? 0) >= movedPri) break;\n\t\theap.ids[i] = heap.ids[child] ?? 0;\n\t\theap.priorities[i] = heap.priorities[child] ?? 0;\n\t\ti = child;\n\t}\n\theap.ids[i] = movedId;\n\theap.priorities[i] = movedPri;\n\treturn top;\n}\n\nfunction reconstructPath(cameFrom: Int32Array, end: CellIndex): CellIndex[] {\n\t// Why: two-pass (count then fill) avoids unshift/reverse allocation.\n\tlet count = 1;\n\tlet cur = end;\n\twhile ((cameFrom[cur] ?? -1) !== -1) {\n\t\tcount++;\n\t\tcur = cameFrom[cur] ?? -1;\n\t}\n\tconst path = new Array<CellIndex>(count);\n\tcur = end;\n\tfor (let i = count - 1; i >= 0; i--) {\n\t\tpath[i] = cur;\n\t\tif (i > 0) cur = cameFrom[cur] ?? -1;\n\t}\n\treturn path;\n}\n\n/**\n * Compute a path through `grid` from `start` to `goal`.\n *\n * Returns a list of cell indices starting with `start` and ending at a cell\n * within `goalTolerance` of `goal`, or `null` if no such path exists within\n * `maxNodesExpanded` expansions.\n *\n * `start` is always treated as passable (even if its grid cell is 0 or the\n * cell is in `blockedCells`) — actors physics-pushed onto a wall still get a\n * valid origin.\n */\nexport function findPath(\n\tgrid: NavGrid,\n\tstart: CellIndex,\n\tgoal: CellIndex,\n\toptions?: FindPathOptions,\n): CellIndex[] | null {\n\tconst n = grid.cells.length;\n\tif (start < 0 || start >= n) return null;\n\tif (goal < 0 || goal >= n) return null;\n\n\tconst maxNodesExpanded = options?.maxNodesExpanded ?? 10_000;\n\tconst blockedCells = options?.blockedCells;\n\tconst goalTolerance = options?.goalTolerance ?? 0;\n\tconst ops = topologyOps[grid.topology];\n\n\t// Per-call allocations: ~n bytes × 5 (gScore, cameFrom, closed, heap ids, heap priorities).\n\t// For a 100×100 grid that's ~120 KB per search. Acceptable for v1 game-grid scales.\n\t// Deferred optimization: closure-scoped reusable pool keyed by `n`, reset per call.\n\tconst gScore = new Float32Array(n);\n\tgScore.fill(Number.POSITIVE_INFINITY);\n\tconst cameFrom = new Int32Array(n);\n\tcameFrom.fill(-1);\n\tconst closed = new Uint8Array(n);\n\tconst heap: PathHeap = {\n\t\tids: new Int32Array(n),\n\t\tpriorities: new Float32Array(n),\n\t\tsize: 0,\n\t};\n\tconst neighborBuf: number[] = [];\n\n\tgScore[start] = 0;\n\theapPush(heap, start, ops.heuristic(grid, start, goal));\n\n\tlet expanded = 0;\n\twhile (heap.size > 0) {\n\t\tif (expanded >= maxNodesExpanded) return null;\n\t\tconst current = heapPop(heap);\n\t\tif (closed[current]) continue;\n\t\tclosed[current] = 1;\n\t\texpanded++;\n\n\t\tif (ops.heuristic(grid, current, goal) <= goalTolerance) {\n\t\t\treturn reconstructPath(cameFrom, current);\n\t\t}\n\n\t\tneighborBuf.length = 0;\n\t\tconst count = ops.neighbors(grid, current, neighborBuf);\n\t\tfor (let k = 0; k < count; k++) {\n\t\t\tconst next = neighborBuf[k] ?? -1;\n\t\t\tif (next < 0 || closed[next]) continue;\n\t\t\tconst cellCost = grid.cells[next] ?? 0;\n\t\t\tif (cellCost === 0) continue;\n\t\t\tif (blockedCells && blockedCells.has(next)) continue;\n\n\t\t\tconst tentative = (gScore[current] ?? Number.POSITIVE_INFINITY) + ops.stepCost(grid, current, next);\n\t\t\tif (tentative < (gScore[next] ?? Number.POSITIVE_INFINITY)) {\n\t\t\t\tgScore[next] = tentative;\n\t\t\t\tcameFrom[next] = current;\n\t\t\t\theapPush(heap, next, tentative + ops.heuristic(grid, next, goal));\n\t\t\t}\n\t\t}\n\t}\n\treturn null;\n}\n\n// ==================== Plugin Factory ====================\n\n/**\n * Create a pathfinding plugin for ECSpresso.\n *\n * Requires the transform and steering plugins to be installed (entities need\n * `worldTransform` for start-cell detection and `moveTarget`/`moveSpeed` for\n * waypoint traversal).\n *\n * @example\n * ```typescript\n * const grid = createNavGrid({ width: 32, height: 32, cellSize: 16 });\n * const ecs = ECSpresso.create()\n * .withPlugin(createTransformPlugin())\n * .withPlugin(createSteeringPlugin())\n * .withPlugin(createPathfindingPlugin({ grid }))\n * .build();\n *\n * ecs.spawn({\n * ...createTransform(0, 0),\n * ...createMoveSpeed(100),\n * ...createPathRequest({ x: 500, y: 300 }),\n * });\n * ```\n */\nexport function createPathfindingPlugin<G extends string = 'ai'>(\n\toptions: PathfindingPluginOptions<G>,\n) {\n\tconst {\n\t\tgrid,\n\t\tsystemGroup = 'ai' as G,\n\t\tpriority = 150,\n\t\tphase = 'update',\n\t\tmaxRequestsPerFrame = 4,\n\t\tmaxNodesExpanded = 10_000,\n\t} = options;\n\n\treturn definePlugin('pathfinding')\n\t\t.withComponentTypes<PathfindingComponentTypes>()\n\t\t.withEventTypes<PathfindingEventTypes>()\n\t\t.withResourceTypes<PathfindingResourceTypes>()\n\t\t.withLabels<'pathfinding-request' | 'pathfinding-waypoint-advance'>()\n\t\t.withGroups<G>()\n\t\t.requires<TransformWorldConfig & SteeringWorldConfig>()\n\t\t.install((world) => {\n\t\t\tworld.addResource('navGrid', grid);\n\n\t\t\tworld\n\t\t\t\t.addSystem('pathfinding-request')\n\t\t\t\t.setPriority(priority)\n\t\t\t\t.inPhase(phase)\n\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t.addQuery('requests', {\n\t\t\t\t\twith: ['pathRequest', 'worldTransform'],\n\t\t\t\t})\n\t\t\t\t.setProcess(({ queries, ecs }) => {\n\t\t\t\t\tconst navGrid = ecs.getResource('navGrid');\n\t\t\t\t\tlet processed = 0;\n\t\t\t\t\tfor (const entity of queries.requests) {\n\t\t\t\t\t\tif (processed >= maxRequestsPerFrame) break;\n\t\t\t\t\t\tprocessed++;\n\t\t\t\t\t\tconst { pathRequest, worldTransform } = entity.components;\n\t\t\t\t\t\tconst startIdx = navGrid.worldToCell(worldTransform.x, worldTransform.y);\n\t\t\t\t\t\tconst goalIdx = navGrid.worldToCell(pathRequest.target.x, pathRequest.target.y);\n\t\t\t\t\t\tconst result = findPath(navGrid, startIdx, goalIdx, { maxNodesExpanded });\n\t\t\t\t\t\tecs.commands.removeComponent(entity.id, 'pathRequest');\n\n\t\t\t\t\t\tif (result === null) {\n\t\t\t\t\t\t\tecs.eventBus.publish('pathBlocked', { entityId: entity.id });\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst waypoints = result.slice(1).map(idx => navGrid.cellToWorld(idx));\n\t\t\t\t\t\tecs.eventBus.publish('pathFound', { entityId: entity.id, path: waypoints });\n\t\t\t\t\t\tif (waypoints.length === 0) continue;\n\n\t\t\t\t\t\tconst existingPath = ecs.getComponent(entity.id, 'path');\n\t\t\t\t\t\tif (existingPath) {\n\t\t\t\t\t\t\texistingPath.waypoints = waypoints;\n\t\t\t\t\t\t\texistingPath.currentIndex = 0;\n\t\t\t\t\t\t\tecs.markChanged(entity.id, 'path');\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tecs.addComponent(entity.id, 'path', { waypoints, currentIndex: 0 });\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst first = waypoints[0];\n\t\t\t\t\t\tif (!first) continue;\n\t\t\t\t\t\tconst existingMT = ecs.getComponent(entity.id, 'moveTarget');\n\t\t\t\t\t\tif (existingMT) {\n\t\t\t\t\t\t\texistingMT.x = first.x;\n\t\t\t\t\t\t\texistingMT.y = first.y;\n\t\t\t\t\t\t\tecs.markChanged(entity.id, 'moveTarget');\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tecs.addComponent(entity.id, 'moveTarget', { x: first.x, y: first.y });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\tworld\n\t\t\t\t.addSystem('pathfinding-waypoint-advance')\n\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t.setEventHandlers({\n\t\t\t\t\tarriveAtTarget({ data, ecs }) {\n\t\t\t\t\t\tconst path = ecs.getComponent(data.entityId, 'path');\n\t\t\t\t\t\tif (!path) return;\n\t\t\t\t\t\tconst next = path.currentIndex + 1;\n\t\t\t\t\t\tif (next >= path.waypoints.length) {\n\t\t\t\t\t\t\tecs.commands.removeComponent(data.entityId, 'path');\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tpath.currentIndex = next;\n\t\t\t\t\t\tecs.markChanged(data.entityId, 'path');\n\t\t\t\t\t\tconst wp = path.waypoints[next];\n\t\t\t\t\t\tif (!wp) return;\n\t\t\t\t\t\t// Why: use command buffer so the add is queued AFTER steering's\n\t\t\t\t\t\t// queued `removeComponent('moveTarget')` in the same phase.\n\t\t\t\t\t\tecs.commands.addComponent(data.entityId, 'moveTarget', { x: wp.x, y: wp.y });\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t});\n}\n",
6
- "/**\n * Tilemap plugin for ECSpresso.\n *\n * Two ingestion paths share a common `LoadedTilemap` shape:\n * - `registerAsset` — load a Tiled `.tmj` file via the asset manager\n * - `registerRuntime` — pass a pre-built tile-id array (procedural)\n *\n * Query methods (`isSolid`, `isOpaque`, `isWalkable`) read from `tileMetadata`\n * regardless of source.\n */\n\nimport { definePlugin, type BasePluginOptions } from 'ecspresso';\nimport type ECSpresso from 'ecspresso';\nimport type { WorldConfigFrom, EmptyConfig } from '../../type-utils';\nimport { createNavGrid, type NavGrid } from '../ai/pathfinding';\nimport type { Vector2D } from '../../utils/math';\nimport type { LocalTransform, WorldTransform } from '../spatial/transform';\nimport type { AABBCollider, CollisionLayer } from '../physics/collision';\n\nexport const TILE_FLIP_HORIZONTAL = 0x80000000;\nexport const TILE_FLIP_VERTICAL = 0x40000000;\nexport const TILE_FLIP_DIAGONAL = 0x20000000;\nexport const TILE_GID_MASK = 0x1fffffff;\n\nexport interface DecodedGid {\n\tid: number;\n\tflipH: boolean;\n\tflipV: boolean;\n\tflipD: boolean;\n}\n\nexport function decodeGid(gid: number): DecodedGid {\n\treturn {\n\t\tid: (gid & TILE_GID_MASK) >>> 0,\n\t\tflipH: (gid & TILE_FLIP_HORIZONTAL) !== 0,\n\t\tflipV: (gid & TILE_FLIP_VERTICAL) !== 0,\n\t\tflipD: (gid & TILE_FLIP_DIAGONAL) !== 0,\n\t};\n}\n\n/** The three tile flag keys the query API understands. Custom keys flow through unchanged. */\nexport type TileFlag = 'solid' | 'blocksSight' | 'walkable';\n\n/** Tile metadata. Known flag keys drive query methods; arbitrary custom keys are preserved. */\nexport interface TileMetadata {\n\tsolid?: boolean;\n\tblocksSight?: boolean;\n\twalkable?: boolean;\n\t[key: string]: unknown;\n}\n\nexport interface ObjectDef {\n\tname: string;\n\ttype: string;\n\tx: number;\n\ty: number;\n\twidth: number;\n\theight: number;\n\trotation: number;\n\tproperties: Record<string, string | number | boolean>;\n}\n\nexport interface RuntimeTileset {\n\ttextureKey: string;\n\tcolumns: number;\n\ttileWidth: number;\n\ttileHeight: number;\n\tfirstgid?: number;\n}\n\nexport interface RuntimeLayer {\n\tname: string;\n\ttiles: Uint32Array | Uint8Array | readonly number[];\n\tparallax?: Vector2D;\n\topacity?: number;\n\tvisible?: boolean;\n}\n\nexport interface TilemapRuntimeData {\n\twidth: number;\n\theight: number;\n\ttileSize: number;\n\tlayers: readonly RuntimeLayer[];\n\ttilesets: readonly RuntimeTileset[];\n\ttileMetadata?: Record<number, TileMetadata>;\n\tobjectLayers?: readonly { name: string; objects: readonly ObjectDef[] }[];\n}\n\nexport interface LoadedLayer {\n\tname: string;\n\ttiles: Uint32Array;\n\tparallax: Vector2D;\n\topacity: number;\n\tvisible: boolean;\n}\n\nexport interface LoadedTileset {\n\ttextureKey: string;\n\tcolumns: number;\n\ttileWidth: number;\n\ttileHeight: number;\n\tfirstgid: number;\n}\n\nexport interface LoadedObjectLayer {\n\tname: string;\n\tobjects: readonly ObjectDef[];\n}\n\nexport interface LoadedTilemap {\n\treadonly width: number;\n\treadonly height: number;\n\treadonly tileWidth: number;\n\treadonly tileHeight: number;\n\treadonly layers: readonly LoadedLayer[];\n\treadonly tilesets: readonly LoadedTileset[];\n\treadonly tileMetadata: ReadonlyMap<number, TileMetadata>;\n\treadonly objectLayers: readonly LoadedObjectLayer[];\n\n\ttileToWorld(tx: number, ty: number): Vector2D;\n\tworldToTile(wx: number, wy: number): { tx: number; ty: number };\n\tgetTile(layerIndex: number, tx: number, ty: number): number;\n\tisSolid(tx: number, ty: number): boolean;\n\tisOpaque(tx: number, ty: number): boolean;\n\tisWalkable(tx: number, ty: number): boolean;\n\tbuildNavGrid(layerIndex: number, costFn?: (tileId: number) => number): NavGrid;\n\tgetObjectLayer(name: string): readonly ObjectDef[];\n\tgetObjects(type: string): readonly ObjectDef[];\n}\n\n/** Subset of a Tiled `.tmj` (JSON) document we consume in v1. */\nexport interface TiledMap {\n\twidth: number;\n\theight: number;\n\ttilewidth: number;\n\ttileheight: number;\n\ttilesets: readonly TiledTileset[];\n\tlayers: readonly TiledLayer[];\n}\n\nexport interface TiledTileset {\n\tfirstgid: number;\n\tcolumns: number;\n\ttilewidth: number;\n\ttileheight: number;\n\timage: string;\n\timagewidth: number;\n\timageheight: number;\n\ttiles?: readonly TiledTileDef[];\n}\n\nexport interface TiledTileDef {\n\tid: number;\n\tproperties?: readonly TiledProperty[];\n\tanimation?: readonly { tileid: number; duration: number }[];\n}\n\nexport interface TiledProperty {\n\tname: string;\n\ttype: 'bool' | 'int' | 'float' | 'string' | 'color' | 'file' | 'object';\n\tvalue: string | number | boolean;\n}\n\nexport type TiledLayer = TiledTileLayer | TiledObjectLayer;\n\nexport interface TiledTileLayer {\n\ttype: 'tilelayer';\n\tname: string;\n\twidth: number;\n\theight: number;\n\tdata: readonly number[];\n\topacity: number;\n\tvisible: boolean;\n\tparallaxx?: number;\n\tparallaxy?: number;\n}\n\nexport interface TiledObjectLayer {\n\ttype: 'objectgroup';\n\tname: string;\n\tobjects: readonly TiledObject[];\n}\n\nexport interface TiledObject {\n\tid: number;\n\tname?: string;\n\ttype?: string;\n\tx: number;\n\ty: number;\n\twidth?: number;\n\theight?: number;\n\trotation?: number;\n\tproperties?: readonly TiledProperty[];\n}\n\nexport interface ParseTiledOptions {\n\ttilesetTextures: Record<string, string>;\n}\n\nexport type TilemapCullingMode = 'viewport' | 'none';\n\nexport interface TilemapLayerComponent {\n\tdataKey: string;\n\ttilesetKey?: string;\n\tlayerIndex: number;\n\topacity: number;\n\tparallax: Vector2D;\n\tcullingMode: TilemapCullingMode;\n\tcameraRef?: number;\n\ttintFn?: (tx: number, ty: number) => number | null;\n}\n\nexport interface TilemapColliderTag {\n\tdataKey: string;\n}\n\nexport interface TilemapComponentTypes {\n\ttilemap: TilemapLayerComponent;\n\ttilemapCollider: TilemapColliderTag;\n}\n\nexport interface TilemapRegistry {\n\tregisterRuntime(dataKey: string, data: TilemapRuntimeData): LoadedTilemap;\n\tregisterAsset(dataKey: string, assetKey: string, options?: ParseTiledOptions): Promise<LoadedTilemap>;\n\tget(dataKey: string): LoadedTilemap | undefined;\n\thas(dataKey: string): boolean;\n\treadonly entries: ReadonlyMap<string, LoadedTilemap>;\n}\n\nexport interface TilemapResourceTypes {\n\ttilemaps: TilemapRegistry;\n}\n\nexport type TilemapWorldConfig = WorldConfigFrom<TilemapComponentTypes, EmptyConfig['events'], TilemapResourceTypes>;\n\nexport interface TilemapPluginOptions<G extends string = 'rendering'> extends BasePluginOptions<G> {\n\t/** Optional collision layer name. When set, solid tiles auto-spawn `aabbCollider` strips. */\n\tcollisionLayer?: string;\n\t/** Layers the auto-generated tile bodies collide with. */\n\tcollidesWith?: readonly string[];\n}\n\nfunction toTilesArray(input: RuntimeLayer['tiles']): Uint32Array {\n\treturn Uint32Array.from(input);\n}\n\nfunction tiledPropsToRecord(props?: readonly TiledProperty[]): Record<string, string | number | boolean> {\n\tif (!props) return {};\n\tconst out: Record<string, string | number | boolean> = {};\n\tfor (const p of props) out[p.name] = p.value;\n\treturn out;\n}\n\nexport function createLoadedTilemap(data: TilemapRuntimeData): LoadedTilemap {\n\tconst { width, height, tileSize, layers, tilesets } = data;\n\n\tif (!Number.isFinite(width) || width <= 0) {\n\t\tthrow new Error(`tilemap: width must be > 0, got ${width}`);\n\t}\n\tif (!Number.isFinite(height) || height <= 0) {\n\t\tthrow new Error(`tilemap: height must be > 0, got ${height}`);\n\t}\n\tif (!Number.isFinite(tileSize) || tileSize <= 0) {\n\t\tthrow new Error(`tilemap: tileSize must be > 0, got ${tileSize}`);\n\t}\n\tif (tilesets.length === 0) {\n\t\tthrow new Error('tilemap: at least one tileset is required');\n\t}\n\n\tconst expectedLen = width * height;\n\n\tconst loadedLayers: LoadedLayer[] = layers.map((l) => {\n\t\tconst tiles = toTilesArray(l.tiles);\n\t\tif (tiles.length !== expectedLen) {\n\t\t\tthrow new Error(\n\t\t\t\t`tilemap: layer \"${l.name}\" tile count ${tiles.length} does not match width*height ${expectedLen}`,\n\t\t\t);\n\t\t}\n\t\treturn {\n\t\t\tname: l.name,\n\t\t\ttiles,\n\t\t\tparallax: l.parallax ? { x: l.parallax.x, y: l.parallax.y } : { x: 1, y: 1 },\n\t\t\topacity: l.opacity ?? 1,\n\t\t\tvisible: l.visible ?? true,\n\t\t};\n\t});\n\n\tconst loadedTilesets: LoadedTileset[] = tilesets.map((t, i) => {\n\t\tif (t.firstgid === undefined && i > 0) {\n\t\t\tthrow new Error(`tilemap: runtime tileset at index ${i} (\"${t.textureKey}\") must specify an explicit firstgid`);\n\t\t}\n\t\treturn {\n\t\t\ttextureKey: t.textureKey,\n\t\t\tcolumns: t.columns,\n\t\t\ttileWidth: t.tileWidth,\n\t\t\ttileHeight: t.tileHeight,\n\t\t\tfirstgid: t.firstgid ?? 1,\n\t\t};\n\t});\n\n\tconst metadataMap = new Map<number, TileMetadata>();\n\tif (data.tileMetadata) {\n\t\tfor (const [k, v] of Object.entries(data.tileMetadata)) {\n\t\t\tmetadataMap.set(Number(k), { ...v });\n\t\t}\n\t}\n\n\tconst objectLayers: LoadedObjectLayer[] = (data.objectLayers ?? []).map(l => ({\n\t\tname: l.name,\n\t\tobjects: l.objects.map(o => ({ ...o, properties: { ...o.properties } })),\n\t}));\n\n\treturn buildLoadedTilemap({\n\t\twidth,\n\t\theight,\n\t\ttileWidth: tileSize,\n\t\ttileHeight: tileSize,\n\t\tlayers: loadedLayers,\n\t\ttilesets: loadedTilesets,\n\t\ttileMetadata: metadataMap,\n\t\tobjectLayers,\n\t});\n}\n\nexport function parseTiledJSON(map: TiledMap, options: ParseTiledOptions): LoadedTilemap {\n\tconst { width, height, tilewidth, tileheight } = map;\n\tconst expectedLen = width * height;\n\n\tconst loadedTilesets: LoadedTileset[] = map.tilesets.map((t) => {\n\t\tconst textureKey = options.tilesetTextures[t.image];\n\t\tif (!textureKey) {\n\t\t\tthrow new Error(`tilemap: no texture key registered for tileset image \"${t.image}\"`);\n\t\t}\n\t\treturn {\n\t\t\ttextureKey,\n\t\t\tcolumns: t.columns,\n\t\t\ttileWidth: t.tilewidth,\n\t\t\ttileHeight: t.tileheight,\n\t\t\tfirstgid: t.firstgid,\n\t\t};\n\t});\n\n\tconst metadataMap = new Map<number, TileMetadata>();\n\tfor (const ts of map.tilesets) {\n\t\tif (!ts.tiles) continue;\n\t\tfor (const td of ts.tiles) {\n\t\t\tmetadataMap.set(ts.firstgid + td.id, tiledPropsToRecord(td.properties) as TileMetadata);\n\t\t}\n\t}\n\n\tconst loadedLayers: LoadedLayer[] = [];\n\tconst loadedObjectLayers: LoadedObjectLayer[] = [];\n\tfor (const l of map.layers) {\n\t\tif (l.type === 'tilelayer') {\n\t\t\tif (l.data.length !== expectedLen) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`tilemap: layer \"${l.name}\" data length ${l.data.length} does not match map ${expectedLen}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tloadedLayers.push({\n\t\t\t\tname: l.name,\n\t\t\t\ttiles: Uint32Array.from(l.data),\n\t\t\t\tparallax: { x: l.parallaxx ?? 1, y: l.parallaxy ?? 1 },\n\t\t\t\topacity: l.opacity,\n\t\t\t\tvisible: l.visible,\n\t\t\t});\n\t\t} else {\n\t\t\tloadedObjectLayers.push({\n\t\t\t\tname: l.name,\n\t\t\t\tobjects: l.objects.map(o => ({\n\t\t\t\t\tname: o.name ?? '',\n\t\t\t\t\ttype: o.type ?? '',\n\t\t\t\t\tx: o.x,\n\t\t\t\t\ty: o.y,\n\t\t\t\t\twidth: o.width ?? 0,\n\t\t\t\t\theight: o.height ?? 0,\n\t\t\t\t\trotation: o.rotation ?? 0,\n\t\t\t\t\tproperties: tiledPropsToRecord(o.properties),\n\t\t\t\t})),\n\t\t\t});\n\t\t}\n\t}\n\n\treturn buildLoadedTilemap({\n\t\twidth,\n\t\theight,\n\t\ttileWidth: tilewidth,\n\t\ttileHeight: tileheight,\n\t\tlayers: loadedLayers,\n\t\ttilesets: loadedTilesets,\n\t\ttileMetadata: metadataMap,\n\t\tobjectLayers: loadedObjectLayers,\n\t});\n}\n\ninterface LoadedTilemapState {\n\twidth: number;\n\theight: number;\n\ttileWidth: number;\n\ttileHeight: number;\n\tlayers: LoadedLayer[];\n\ttilesets: LoadedTileset[];\n\ttileMetadata: Map<number, TileMetadata>;\n\tobjectLayers: LoadedObjectLayer[];\n}\n\nfunction buildLoadedTilemap(state: LoadedTilemapState): LoadedTilemap {\n\tconst { width, height, tileWidth, tileHeight, layers, tilesets, tileMetadata, objectLayers } = state;\n\n\t// Why: hot path. Inlining the bounds + cellIndex math here avoids\n\t// per-layer recomputation in the loop below (called by FOV / pathfinding consumers).\n\tconst flagAtAnyLayer = (tx: number, ty: number, key: TileFlag): boolean => {\n\t\tif (tx < 0 || ty < 0 || tx >= width || ty >= height) return false;\n\t\tconst idx = ty * width + tx;\n\t\tfor (let i = 0; i < layers.length; i++) {\n\t\t\tconst gid = (layers[i]!.tiles[idx] ?? 0) & TILE_GID_MASK;\n\t\t\tif (gid === 0) continue;\n\t\t\tconst meta = tileMetadata.get(gid);\n\t\t\tif (meta && meta[key] === true) return true;\n\t\t}\n\t\treturn false;\n\t};\n\n\tconst defaultCostFromMetadata = (gid: number): number => {\n\t\tconst meta = tileMetadata.get(gid);\n\t\treturn meta?.walkable === true ? 1 : 0;\n\t};\n\n\treturn {\n\t\twidth,\n\t\theight,\n\t\ttileWidth,\n\t\ttileHeight,\n\t\tlayers,\n\t\ttilesets,\n\t\ttileMetadata,\n\t\tobjectLayers,\n\n\t\ttileToWorld(tx, ty) {\n\t\t\treturn { x: (tx + 0.5) * tileWidth, y: (ty + 0.5) * tileHeight };\n\t\t},\n\n\t\tworldToTile(wx, wy) {\n\t\t\treturn { tx: Math.floor(wx / tileWidth), ty: Math.floor(wy / tileHeight) };\n\t\t},\n\n\t\tgetTile(layerIndex, tx, ty) {\n\t\t\tconst layer = layers[layerIndex];\n\t\t\tif (!layer) return 0;\n\t\t\tif (tx < 0 || ty < 0 || tx >= width || ty >= height) return 0;\n\t\t\treturn (layer.tiles[ty * width + tx] ?? 0) & TILE_GID_MASK;\n\t\t},\n\n\t\tisSolid: (tx, ty) => flagAtAnyLayer(tx, ty, 'solid'),\n\t\tisOpaque: (tx, ty) => flagAtAnyLayer(tx, ty, 'blocksSight'),\n\t\tisWalkable: (tx, ty) => flagAtAnyLayer(tx, ty, 'walkable'),\n\n\t\tbuildNavGrid(layerIndex, costFn) {\n\t\t\tconst layer = layers[layerIndex];\n\t\t\tif (!layer) {\n\t\t\t\tthrow new Error(`tilemap: buildNavGrid — no layer at index ${layerIndex}`);\n\t\t\t}\n\t\t\tconst cells = new Uint8Array(width * height);\n\t\t\tconst cost = costFn ?? defaultCostFromMetadata;\n\t\t\tfor (let i = 0; i < cells.length; i++) {\n\t\t\t\tconst gid = (layer.tiles[i] ?? 0) & TILE_GID_MASK;\n\t\t\t\tconst c = cost(gid) | 0;\n\t\t\t\tcells[i] = c < 0 ? 0 : c > 255 ? 255 : c;\n\t\t\t}\n\t\t\treturn createNavGrid({ width, height, cellSize: tileWidth, cells });\n\t\t},\n\n\t\tgetObjectLayer(name) {\n\t\t\treturn objectLayers.find(l => l.name === name)?.objects ?? [];\n\t\t},\n\n\t\tgetObjects(type) {\n\t\t\tconst out: ObjectDef[] = [];\n\t\t\tfor (const layer of objectLayers) {\n\t\t\t\tfor (const o of layer.objects) {\n\t\t\t\t\tif (o.type === type) out.push(o);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn out;\n\t\t},\n\t};\n}\n\ninterface CollisionStrip {\n\ttx: number;\n\tty: number;\n\ttw: number;\n\tth: number;\n}\n\n/** Greedy row-first scan: each row produces N horizontal strips. No vertical merge in v1. */\nfunction buildCollisionStrips(map: LoadedTilemap): CollisionStrip[] {\n\tconst strips: CollisionStrip[] = [];\n\tfor (let ty = 0; ty < map.height; ty++) {\n\t\tlet runStart = -1;\n\t\tfor (let tx = 0; tx <= map.width; tx++) {\n\t\t\tconst solid = tx < map.width && map.isSolid(tx, ty);\n\t\t\tif (solid && runStart === -1) {\n\t\t\t\trunStart = tx;\n\t\t\t} else if (!solid && runStart !== -1) {\n\t\t\t\tstrips.push({ tx: runStart, ty, tw: tx - runStart, th: 1 });\n\t\t\t\trunStart = -1;\n\t\t\t}\n\t\t}\n\t}\n\treturn strips;\n}\n\n// Component shape for the optional collision-strip spawn. The plugin doesn't\n// declare a hard requirement on the collision/transform plugins so users who\n// don't enable `collisionLayer` aren't forced to install them; the cast at the\n// spawn site is the bridge. When `collisionLayer` is set the user has installed\n// both plugins by definition (otherwise the layer name would be meaningless).\ninterface CollisionSpawnShape {\n\ttilemapCollider: TilemapColliderTag;\n\taabbCollider: AABBCollider;\n\tcollisionLayer: CollisionLayer<string>;\n\tlocalTransform: LocalTransform;\n\tworldTransform: WorldTransform;\n}\n\ntype TilemapWorld = ECSpresso<TilemapWorldConfig>;\n\ntype TilemapLabels = never;\n\nexport function createTilemapPlugin<G extends string = 'rendering'>(\n\toptions: TilemapPluginOptions<G> = {},\n) {\n\tconst { collisionLayer, collidesWith } = options;\n\n\treturn definePlugin('tilemap')\n\t\t.withComponentTypes<TilemapComponentTypes>()\n\t\t.withResourceTypes<TilemapResourceTypes>()\n\t\t.withLabels<TilemapLabels>()\n\t\t.withGroups<G>()\n\t\t.install((world: TilemapWorld) => {\n\t\t\tconst entries = new Map<string, LoadedTilemap>();\n\t\t\tconst colliderEntitiesByKey = new Map<string, number[]>();\n\n\t\t\tconst despawnCollidersFor = (dataKey: string): void => {\n\t\t\t\tconst ids = colliderEntitiesByKey.get(dataKey);\n\t\t\t\tif (!ids) return;\n\t\t\t\tfor (const id of ids) world.removeEntity(id);\n\t\t\t\tcolliderEntitiesByKey.delete(dataKey);\n\t\t\t};\n\n\t\t\tconst spawnCollisionStripsFor = (dataKey: string, lt: LoadedTilemap): void => {\n\t\t\t\tif (!collisionLayer) return;\n\t\t\t\tconst ids: number[] = [];\n\t\t\t\tfor (const s of buildCollisionStrips(lt)) {\n\t\t\t\t\tconst cx = (s.tx + s.tw / 2) * lt.tileWidth;\n\t\t\t\t\tconst cy = (s.ty + s.th / 2) * lt.tileHeight;\n\t\t\t\t\tconst components: CollisionSpawnShape = {\n\t\t\t\t\t\ttilemapCollider: { dataKey },\n\t\t\t\t\t\taabbCollider: { width: s.tw * lt.tileWidth, height: s.th * lt.tileHeight },\n\t\t\t\t\t\tcollisionLayer: { layer: collisionLayer, collidesWith: collidesWith ?? [] },\n\t\t\t\t\t\tlocalTransform: { x: cx, y: cy, rotation: 0, scaleX: 1, scaleY: 1 },\n\t\t\t\t\t\tworldTransform: { x: cx, y: cy, rotation: 0, scaleX: 1, scaleY: 1 },\n\t\t\t\t\t};\n\t\t\t\t\tconst entity = (world as unknown as ECSpresso<WorldConfigFrom<CollisionSpawnShape>>).spawn(components);\n\t\t\t\t\tids.push(entity.id);\n\t\t\t\t}\n\t\t\t\tif (ids.length > 0) colliderEntitiesByKey.set(dataKey, ids);\n\t\t\t};\n\n\t\t\tconst ingest = (dataKey: string, lt: LoadedTilemap): LoadedTilemap => {\n\t\t\t\tdespawnCollidersFor(dataKey);\n\t\t\t\tentries.set(dataKey, lt);\n\t\t\t\tspawnCollisionStripsFor(dataKey, lt);\n\t\t\t\treturn lt;\n\t\t\t};\n\n\t\t\tconst registry: TilemapRegistry = {\n\t\t\t\tentries,\n\t\t\t\tregisterRuntime(dataKey, data) {\n\t\t\t\t\treturn ingest(dataKey, createLoadedTilemap(data));\n\t\t\t\t},\n\t\t\t\tasync registerAsset(dataKey, assetKey, parseOptions) {\n\t\t\t\t\tconst raw = await (world as unknown as ECSpresso<WorldConfigFrom<EmptyConfig['components'], EmptyConfig['events'], EmptyConfig['resources'], { [k: string]: TiledMap }>>).loadAsset(assetKey) as TiledMap;\n\t\t\t\t\treturn ingest(dataKey, parseTiledJSON(raw, parseOptions ?? { tilesetTextures: {} }));\n\t\t\t\t},\n\t\t\t\tget: (dataKey) => entries.get(dataKey),\n\t\t\t\thas: (dataKey) => entries.has(dataKey),\n\t\t\t};\n\n\t\t\tworld.addResource('tilemaps', registry);\n\t\t});\n}\n\n/**\n * Create a `tilemap` layer component for spreading into `spawn()`.\n *\n * @example\n * ```typescript\n * ecs.spawn({\n * ...createTilemapLayer('dungeon', 0),\n * ...createLocalTransform(0, 0),\n * });\n * ```\n */\nexport function createTilemapLayer(\n\tdataKey: string,\n\tlayerIndex: number,\n\toptions?: {\n\t\ttilesetKey?: string;\n\t\topacity?: number;\n\t\tparallax?: Vector2D;\n\t\tcullingMode?: TilemapCullingMode;\n\t\tcameraRef?: number;\n\t\ttintFn?: (tx: number, ty: number) => number | null;\n\t},\n): Pick<TilemapComponentTypes, 'tilemap'> {\n\treturn {\n\t\ttilemap: {\n\t\t\tdataKey,\n\t\t\tlayerIndex,\n\t\t\ttilesetKey: options?.tilesetKey,\n\t\t\topacity: options?.opacity ?? 1,\n\t\t\tparallax: options?.parallax ?? { x: 1, y: 1 },\n\t\t\tcullingMode: options?.cullingMode ?? 'viewport',\n\t\t\tcameraRef: options?.cameraRef,\n\t\t\ttintFn: options?.tintFn,\n\t\t},\n\t};\n}\n"
5
+ "/**\n * Pathfinding Plugin for ECSpresso\n *\n * A* pathfinding on a weighted grid. Produces waypoint lists consumed by the\n * steering plugin — the pathfinding system writes the `path` component and\n * sets `moveTarget` to the first waypoint; the waypoint advancement handler\n * listens for `arriveAtTarget` and advances to the next waypoint.\n *\n * Exports the pure `findPath(grid, start, goal, options?)` function for\n * turn-based / non-realtime consumers that don't need the component dance.\n */\n\nimport { definePlugin, type BasePluginOptions } from 'ecspresso';\nimport type { ComponentsConfig, EventsConfig, ResourcesConfig } from 'ecspresso';\nimport type { Vector2D } from '../../utils/math';\nimport type { TransformWorldConfig } from '../spatial/transform';\nimport type { SteeringWorldConfig } from '../physics/steering';\n\n// ==================== Topology / Grid Types ====================\n\n/** Flat-indexed cell position in a `NavGrid`. Transparent alias, not branded. */\nexport type CellIndex = number;\n\n/**\n * Grid topology. v1 ships `square4`; other values are accepted at construction\n * but throw at `findPath` time.\n */\nexport type NavGridTopology = 'square4' | 'square8' | 'hex-pointy' | 'hex-flat';\n\n/**\n * Weighted navigation grid. Row-major storage (`idx = row * width + col`).\n * Cell value `0` = impassable, `1`–`255` = traversal cost into that cell.\n */\nexport interface NavGrid {\n\treadonly topology: NavGridTopology;\n\treadonly width: number;\n\treadonly height: number;\n\treadonly cellSize: number;\n\treadonly originX: number;\n\treadonly originY: number;\n\treadonly cells: Uint8Array;\n\tworldToCell(wx: number, wy: number): CellIndex;\n\tcellToWorld(idx: CellIndex): Vector2D;\n\tcellFromXY(x: number, y: number): CellIndex;\n\tcellToXY(idx: CellIndex): { x: number; y: number };\n}\n\n/** Options accepted by `createNavGrid`. */\nexport interface CreateNavGridOptions {\n\ttopology?: NavGridTopology;\n\twidth: number;\n\theight: number;\n\tcellSize?: number;\n\toriginX?: number;\n\toriginY?: number;\n\tcells?: Uint8Array;\n\tdefaultCost?: number;\n}\n\n// ==================== Component Types ====================\n\n/** Signals the pathfinding system to compute a route to `target`. */\nexport interface PathRequest {\n\ttarget: Vector2D;\n}\n\n/** Active route; waypoints are in world-space, advanced by `currentIndex`. */\nexport interface Path {\n\twaypoints: Vector2D[];\n\tcurrentIndex: number;\n}\n\n/** Component types provided by the pathfinding plugin. */\nexport interface PathfindingComponentTypes {\n\tpathRequest: PathRequest;\n\tpath: Path;\n}\n\n// ==================== Event Types ====================\n\n/** Fired when A* produces a route. `path` is empty when start is already at the goal. */\nexport interface PathFoundEvent {\n\tentityId: number;\n\tpath: Vector2D[];\n}\n\n/** Fired when no path exists to the target. */\nexport interface PathBlockedEvent {\n\tentityId: number;\n}\n\n/** Event types provided by the pathfinding plugin. */\nexport interface PathfindingEventTypes {\n\tpathFound: PathFoundEvent;\n\tpathBlocked: PathBlockedEvent;\n}\n\n// ==================== Resource Types ====================\n\n/** Resource types provided by the pathfinding plugin. */\nexport interface PathfindingResourceTypes {\n\tnavGrid: NavGrid;\n}\n\n// ==================== WorldConfig ====================\n\n/** WorldConfig representing the pathfinding plugin's provided types. */\nexport type PathfindingWorldConfig =\n\tComponentsConfig<PathfindingComponentTypes>\n\t& EventsConfig<PathfindingEventTypes>\n\t& ResourcesConfig<PathfindingResourceTypes>;\n\n// ==================== Plugin Options ====================\n\nexport interface PathfindingPluginOptions<G extends string = 'ai'> extends BasePluginOptions<G> {\n\t/** The navigation grid. Construct via `createNavGrid`. */\n\tgrid: NavGrid;\n\t/** Max path requests processed per frame (default 4). */\n\tmaxRequestsPerFrame?: number;\n\t/** Default `maxNodesExpanded` passed to A* per request (default 10_000). */\n\tmaxNodesExpanded?: number;\n}\n\n// ==================== NavGrid Construction ====================\n\ninterface TopologyOps {\n\tneighbors(grid: NavGrid, idx: CellIndex, out: number[]): number;\n\tstepCost(grid: NavGrid, from: CellIndex, to: CellIndex): number;\n\theuristic(grid: NavGrid, a: CellIndex, b: CellIndex): number;\n}\n\nconst square4Ops: TopologyOps = {\n\tneighbors(grid, idx, out) {\n\t\tconst col = idx % grid.width;\n\t\tconst row = (idx - col) / grid.width;\n\t\tlet count = 0;\n\t\tif (col > 0) out[count++] = idx - 1;\n\t\tif (col < grid.width - 1) out[count++] = idx + 1;\n\t\tif (row > 0) out[count++] = idx - grid.width;\n\t\tif (row < grid.height - 1) out[count++] = idx + grid.width;\n\t\treturn count;\n\t},\n\tstepCost(grid, _from, to) {\n\t\treturn grid.cells[to] ?? 0;\n\t},\n\theuristic(grid, a, b) {\n\t\tconst ax = a % grid.width;\n\t\tconst ay = (a - ax) / grid.width;\n\t\tconst bx = b % grid.width;\n\t\tconst by = (b - bx) / grid.width;\n\t\treturn Math.abs(ax - bx) + Math.abs(ay - by);\n\t},\n};\n\nconst unimplementedOps = (topology: NavGridTopology): TopologyOps => {\n\tconst err = (): never => {\n\t\tthrow new Error(`pathfinding: topology '${topology}' is not implemented in v1`);\n\t};\n\treturn {\n\t\tneighbors: err,\n\t\tstepCost: err,\n\t\theuristic: err,\n\t};\n};\n\nconst topologyOps: Readonly<Record<NavGridTopology, TopologyOps>> = Object.freeze({\n\t'square4': square4Ops,\n\t'square8': unimplementedOps('square8'),\n\t'hex-pointy': unimplementedOps('hex-pointy'),\n\t'hex-flat': unimplementedOps('hex-flat'),\n});\n\n/**\n * Create a weighted navigation grid.\n *\n * @example\n * ```typescript\n * const grid = createNavGrid({ width: 32, height: 32, cellSize: 16 });\n * grid.cells[grid.cellFromXY(5, 5)] = 0; // block a cell\n * ```\n */\nexport function createNavGrid(options: CreateNavGridOptions): NavGrid {\n\tconst topology = options.topology ?? 'square4';\n\tconst cellSize = options.cellSize ?? 32;\n\tconst originX = options.originX ?? 0;\n\tconst originY = options.originY ?? 0;\n\tconst { width, height } = options;\n\tconst defaultCost = options.defaultCost ?? 1;\n\n\tif (!Number.isInteger(width) || width <= 0) {\n\t\tthrow new Error(`pathfinding: width must be a positive integer, got ${width}`);\n\t}\n\tif (!Number.isInteger(height) || height <= 0) {\n\t\tthrow new Error(`pathfinding: height must be a positive integer, got ${height}`);\n\t}\n\tif (cellSize <= 0) {\n\t\tthrow new Error(`pathfinding: cellSize must be > 0, got ${cellSize}`);\n\t}\n\tif (defaultCost < 0 || defaultCost > 255) {\n\t\tthrow new Error(`pathfinding: defaultCost must be in 0–255, got ${defaultCost}`);\n\t}\n\n\tconst expectedLen = width * height;\n\tconst cells = options.cells ?? new Uint8Array(expectedLen).fill(defaultCost);\n\tif (cells.length !== expectedLen) {\n\t\tthrow new Error(\n\t\t\t`pathfinding: cells length ${cells.length} does not match width*height ${expectedLen}`,\n\t\t);\n\t}\n\n\tconst invCellSize = 1 / cellSize;\n\n\tconst worldToCell = (wx: number, wy: number): CellIndex => {\n\t\tconst col = Math.floor((wx - originX) * invCellSize);\n\t\tconst row = Math.floor((wy - originY) * invCellSize);\n\t\tconst cCol = col < 0 ? 0 : col >= width ? width - 1 : col;\n\t\tconst cRow = row < 0 ? 0 : row >= height ? height - 1 : row;\n\t\treturn cRow * width + cCol;\n\t};\n\n\tconst cellToWorld = (idx: CellIndex): Vector2D => {\n\t\tconst col = idx % width;\n\t\tconst row = (idx - col) / width;\n\t\treturn {\n\t\t\tx: originX + (col + 0.5) * cellSize,\n\t\t\ty: originY + (row + 0.5) * cellSize,\n\t\t};\n\t};\n\n\tconst cellFromXY = (x: number, y: number): CellIndex => y * width + x;\n\n\tconst cellToXY = (idx: CellIndex): { x: number; y: number } => {\n\t\tconst x = idx % width;\n\t\treturn { x, y: (idx - x) / width };\n\t};\n\n\treturn {\n\t\ttopology, width, height, cellSize, originX, originY, cells,\n\t\tworldToCell, cellToWorld, cellFromXY, cellToXY,\n\t};\n}\n\n// ==================== Helper Functions ====================\n\n/**\n * Create a `pathRequest` component for spreading into `spawn()` / `addComponent()`.\n *\n * @example\n * ```typescript\n * ecs.spawn({\n * ...createTransform(0, 0),\n * ...createMoveSpeed(100),\n * ...createPathRequest({ x: 200, y: 300 }),\n * });\n * ```\n */\nexport function createPathRequest(target: Vector2D): Pick<PathfindingComponentTypes, 'pathRequest'> {\n\treturn { pathRequest: { target: { x: target.x, y: target.y } } };\n}\n\n// ==================== Pure A* API ====================\n\nexport interface FindPathOptions {\n\t/** Cap on A* node expansions; returns `null` if exceeded. Default 10_000. */\n\tmaxNodesExpanded?: number;\n\t/** Dynamic per-call obstacles layered on top of the static grid. */\n\tblockedCells?: Set<CellIndex>;\n\t/** Accept arrival within N cells of goal (topology-aware distance). Default 0. */\n\tgoalTolerance?: number;\n}\n\ninterface PathHeap {\n\tids: Int32Array;\n\tpriorities: Float32Array;\n\tsize: number;\n}\n\n// Why: parallel-typed-array heap keeps cells & priorities in cache without per-node allocations.\nfunction heapPush(heap: PathHeap, id: number, priority: number): void {\n\tlet i = heap.size;\n\theap.size = i + 1;\n\twhile (i > 0) {\n\t\tconst parent = (i - 1) >> 1;\n\t\tif ((heap.priorities[parent] ?? 0) <= priority) break;\n\t\theap.ids[i] = heap.ids[parent] ?? 0;\n\t\theap.priorities[i] = heap.priorities[parent] ?? 0;\n\t\ti = parent;\n\t}\n\theap.ids[i] = id;\n\theap.priorities[i] = priority;\n}\n\nfunction heapPop(heap: PathHeap): number {\n\tconst top = heap.ids[0] ?? -1;\n\tconst last = heap.size - 1;\n\theap.size = last;\n\tif (last <= 0) return top;\n\tconst movedId = heap.ids[last] ?? 0;\n\tconst movedPri = heap.priorities[last] ?? 0;\n\tlet i = 0;\n\tconst half = last >> 1;\n\twhile (i < half) {\n\t\tlet child = (i << 1) + 1;\n\t\tconst right = child + 1;\n\t\tif (right < last && (heap.priorities[right] ?? 0) < (heap.priorities[child] ?? 0)) child = right;\n\t\tif ((heap.priorities[child] ?? 0) >= movedPri) break;\n\t\theap.ids[i] = heap.ids[child] ?? 0;\n\t\theap.priorities[i] = heap.priorities[child] ?? 0;\n\t\ti = child;\n\t}\n\theap.ids[i] = movedId;\n\theap.priorities[i] = movedPri;\n\treturn top;\n}\n\nfunction reconstructPath(cameFrom: Int32Array, end: CellIndex): CellIndex[] {\n\t// Why: two-pass (count then fill) avoids unshift/reverse allocation.\n\tlet count = 1;\n\tlet cur = end;\n\twhile ((cameFrom[cur] ?? -1) !== -1) {\n\t\tcount++;\n\t\tcur = cameFrom[cur] ?? -1;\n\t}\n\tconst path = new Array<CellIndex>(count);\n\tcur = end;\n\tfor (let i = count - 1; i >= 0; i--) {\n\t\tpath[i] = cur;\n\t\tif (i > 0) cur = cameFrom[cur] ?? -1;\n\t}\n\treturn path;\n}\n\n/**\n * Compute a path through `grid` from `start` to `goal`.\n *\n * Returns a list of cell indices starting with `start` and ending at a cell\n * within `goalTolerance` of `goal`, or `null` if no such path exists within\n * `maxNodesExpanded` expansions.\n *\n * `start` is always treated as passable (even if its grid cell is 0 or the\n * cell is in `blockedCells`) — actors physics-pushed onto a wall still get a\n * valid origin.\n */\nexport function findPath(\n\tgrid: NavGrid,\n\tstart: CellIndex,\n\tgoal: CellIndex,\n\toptions?: FindPathOptions,\n): CellIndex[] | null {\n\tconst n = grid.cells.length;\n\tif (start < 0 || start >= n) return null;\n\tif (goal < 0 || goal >= n) return null;\n\n\tconst maxNodesExpanded = options?.maxNodesExpanded ?? 10_000;\n\tconst blockedCells = options?.blockedCells;\n\tconst goalTolerance = options?.goalTolerance ?? 0;\n\tconst ops = topologyOps[grid.topology];\n\n\t// Per-call allocations: ~n bytes × 5 (gScore, cameFrom, closed, heap ids, heap priorities).\n\t// For a 100×100 grid that's ~120 KB per search. Acceptable for v1 game-grid scales.\n\t// Deferred optimization: closure-scoped reusable pool keyed by `n`, reset per call.\n\tconst gScore = new Float32Array(n);\n\tgScore.fill(Number.POSITIVE_INFINITY);\n\tconst cameFrom = new Int32Array(n);\n\tcameFrom.fill(-1);\n\tconst closed = new Uint8Array(n);\n\tconst heap: PathHeap = {\n\t\tids: new Int32Array(n),\n\t\tpriorities: new Float32Array(n),\n\t\tsize: 0,\n\t};\n\tconst neighborBuf: number[] = [];\n\n\tgScore[start] = 0;\n\theapPush(heap, start, ops.heuristic(grid, start, goal));\n\n\tlet expanded = 0;\n\twhile (heap.size > 0) {\n\t\tif (expanded >= maxNodesExpanded) return null;\n\t\tconst current = heapPop(heap);\n\t\tif (closed[current]) continue;\n\t\tclosed[current] = 1;\n\t\texpanded++;\n\n\t\tif (ops.heuristic(grid, current, goal) <= goalTolerance) {\n\t\t\treturn reconstructPath(cameFrom, current);\n\t\t}\n\n\t\tneighborBuf.length = 0;\n\t\tconst count = ops.neighbors(grid, current, neighborBuf);\n\t\tfor (let k = 0; k < count; k++) {\n\t\t\tconst next = neighborBuf[k] ?? -1;\n\t\t\tif (next < 0 || closed[next]) continue;\n\t\t\tconst cellCost = grid.cells[next] ?? 0;\n\t\t\tif (cellCost === 0) continue;\n\t\t\tif (blockedCells && blockedCells.has(next)) continue;\n\n\t\t\tconst tentative = (gScore[current] ?? Number.POSITIVE_INFINITY) + ops.stepCost(grid, current, next);\n\t\t\tif (tentative < (gScore[next] ?? Number.POSITIVE_INFINITY)) {\n\t\t\t\tgScore[next] = tentative;\n\t\t\t\tcameFrom[next] = current;\n\t\t\t\theapPush(heap, next, tentative + ops.heuristic(grid, next, goal));\n\t\t\t}\n\t\t}\n\t}\n\treturn null;\n}\n\n// ==================== Plugin Factory ====================\n\n/**\n * Create a pathfinding plugin for ECSpresso.\n *\n * Requires the transform and steering plugins to be installed (entities need\n * `worldTransform` for start-cell detection and `moveTarget`/`moveSpeed` for\n * waypoint traversal).\n *\n * @example\n * ```typescript\n * const grid = createNavGrid({ width: 32, height: 32, cellSize: 16 });\n * const ecs = ECSpresso.create()\n * .withPlugin(createTransformPlugin())\n * .withPlugin(createSteeringPlugin())\n * .withPlugin(createPathfindingPlugin({ grid }))\n * .build();\n *\n * ecs.spawn({\n * ...createTransform(0, 0),\n * ...createMoveSpeed(100),\n * ...createPathRequest({ x: 500, y: 300 }),\n * });\n * ```\n */\nexport function createPathfindingPlugin<G extends string = 'ai'>(\n\toptions: PathfindingPluginOptions<G>,\n) {\n\tconst {\n\t\tgrid,\n\t\tsystemGroup = 'ai' as G,\n\t\tpriority = 150,\n\t\tphase = 'update',\n\t\tmaxRequestsPerFrame = 4,\n\t\tmaxNodesExpanded = 10_000,\n\t} = options;\n\n\treturn definePlugin('pathfinding')\n\t\t.withComponentTypes<PathfindingComponentTypes>()\n\t\t.withEventTypes<PathfindingEventTypes>()\n\t\t.withResourceTypes<PathfindingResourceTypes>()\n\t\t.withLabels<'pathfinding-request' | 'pathfinding-waypoint-advance'>()\n\t\t.withGroups<G>()\n\t\t.requires<TransformWorldConfig & SteeringWorldConfig>()\n\t\t.install((world) => {\n\t\t\tworld.addResource('navGrid', grid);\n\n\t\t\tworld\n\t\t\t\t.addSystem('pathfinding-request')\n\t\t\t\t.setPriority(priority)\n\t\t\t\t.inPhase(phase)\n\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t.addQuery('requests', {\n\t\t\t\t\twith: ['pathRequest', 'worldTransform'],\n\t\t\t\t})\n\t\t\t\t.setProcess(({ queries, ecs }) => {\n\t\t\t\t\tconst navGrid = ecs.getResource('navGrid');\n\t\t\t\t\tlet processed = 0;\n\t\t\t\t\tfor (const entity of queries.requests) {\n\t\t\t\t\t\tif (processed >= maxRequestsPerFrame) break;\n\t\t\t\t\t\tprocessed++;\n\t\t\t\t\t\tconst { pathRequest, worldTransform } = entity.components;\n\t\t\t\t\t\tconst startIdx = navGrid.worldToCell(worldTransform.x, worldTransform.y);\n\t\t\t\t\t\tconst goalIdx = navGrid.worldToCell(pathRequest.target.x, pathRequest.target.y);\n\t\t\t\t\t\tconst result = findPath(navGrid, startIdx, goalIdx, { maxNodesExpanded });\n\t\t\t\t\t\tecs.commands.removeComponent(entity.id, 'pathRequest');\n\n\t\t\t\t\t\tif (result === null) {\n\t\t\t\t\t\t\tecs.eventBus.publish('pathBlocked', { entityId: entity.id });\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst waypoints = result.slice(1).map(idx => navGrid.cellToWorld(idx));\n\t\t\t\t\t\tecs.eventBus.publish('pathFound', { entityId: entity.id, path: waypoints });\n\t\t\t\t\t\tif (waypoints.length === 0) continue;\n\n\t\t\t\t\t\tconst existingPath = ecs.getComponent(entity.id, 'path');\n\t\t\t\t\t\tif (existingPath) {\n\t\t\t\t\t\t\texistingPath.waypoints = waypoints;\n\t\t\t\t\t\t\texistingPath.currentIndex = 0;\n\t\t\t\t\t\t\tecs.markChanged(entity.id, 'path');\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tecs.addComponent(entity.id, 'path', { waypoints, currentIndex: 0 });\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst first = waypoints[0];\n\t\t\t\t\t\tif (!first) continue;\n\t\t\t\t\t\tconst existingMT = ecs.getComponent(entity.id, 'moveTarget');\n\t\t\t\t\t\tif (existingMT) {\n\t\t\t\t\t\t\texistingMT.x = first.x;\n\t\t\t\t\t\t\texistingMT.y = first.y;\n\t\t\t\t\t\t\tecs.markChanged(entity.id, 'moveTarget');\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tecs.addComponent(entity.id, 'moveTarget', { x: first.x, y: first.y });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\tworld\n\t\t\t\t.addSystem('pathfinding-waypoint-advance')\n\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t.setEventHandlers({\n\t\t\t\t\tarriveAtTarget({ data, ecs }) {\n\t\t\t\t\t\tconst path = ecs.getComponent(data.entityId, 'path');\n\t\t\t\t\t\tif (!path) return;\n\t\t\t\t\t\tconst next = path.currentIndex + 1;\n\t\t\t\t\t\tif (next >= path.waypoints.length) {\n\t\t\t\t\t\t\tecs.commands.removeComponent(data.entityId, 'path');\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tpath.currentIndex = next;\n\t\t\t\t\t\tecs.markChanged(data.entityId, 'path');\n\t\t\t\t\t\tconst wp = path.waypoints[next];\n\t\t\t\t\t\tif (!wp) return;\n\t\t\t\t\t\t// Why: use command buffer so the add is queued AFTER steering's\n\t\t\t\t\t\t// queued `removeComponent('moveTarget')` in the same phase.\n\t\t\t\t\t\tecs.commands.addComponent(data.entityId, 'moveTarget', { x: wp.x, y: wp.y });\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t});\n}\n",
6
+ "/**\n * Tilemap plugin for ECSpresso.\n *\n * Two ingestion paths share a common `LoadedTilemap` shape:\n * - `registerAsset` — load a Tiled `.tmj` file via the asset manager\n * - `registerRuntime` — pass a pre-built tile-id array (procedural)\n *\n * Query methods (`isSolid`, `isOpaque`, `isWalkable`) read from `tileMetadata`\n * regardless of source.\n */\n\nimport { definePlugin, type BasePluginOptions } from 'ecspresso';\nimport type ECSpresso from 'ecspresso';\nimport type { AssetsConfig, ComponentsConfig, ResourcesConfig } from '../../type-utils';\nimport { createNavGrid, type NavGrid } from '../ai/pathfinding';\nimport type { Vector2D } from '../../utils/math';\nimport type { LocalTransform, WorldTransform } from '../spatial/transform';\nimport type { AABBCollider, CollisionLayer } from '../physics/collision';\n\nexport const TILE_FLIP_HORIZONTAL = 0x80000000;\nexport const TILE_FLIP_VERTICAL = 0x40000000;\nexport const TILE_FLIP_DIAGONAL = 0x20000000;\nexport const TILE_GID_MASK = 0x1fffffff;\n\nexport interface DecodedGid {\n\tid: number;\n\tflipH: boolean;\n\tflipV: boolean;\n\tflipD: boolean;\n}\n\nexport function decodeGid(gid: number): DecodedGid {\n\treturn {\n\t\tid: (gid & TILE_GID_MASK) >>> 0,\n\t\tflipH: (gid & TILE_FLIP_HORIZONTAL) !== 0,\n\t\tflipV: (gid & TILE_FLIP_VERTICAL) !== 0,\n\t\tflipD: (gid & TILE_FLIP_DIAGONAL) !== 0,\n\t};\n}\n\n/** The three tile flag keys the query API understands. Custom keys flow through unchanged. */\nexport type TileFlag = 'solid' | 'blocksSight' | 'walkable';\n\n/** Tile metadata. Known flag keys drive query methods; arbitrary custom keys are preserved. */\nexport interface TileMetadata {\n\tsolid?: boolean;\n\tblocksSight?: boolean;\n\twalkable?: boolean;\n\t[key: string]: unknown;\n}\n\nexport interface ObjectDef {\n\tname: string;\n\ttype: string;\n\tx: number;\n\ty: number;\n\twidth: number;\n\theight: number;\n\trotation: number;\n\tproperties: Record<string, string | number | boolean>;\n}\n\nexport interface RuntimeTileset {\n\ttextureKey: string;\n\tcolumns: number;\n\ttileWidth: number;\n\ttileHeight: number;\n\tfirstgid?: number;\n}\n\nexport interface RuntimeLayer {\n\tname: string;\n\ttiles: Uint32Array | Uint8Array | readonly number[];\n\tparallax?: Vector2D;\n\topacity?: number;\n\tvisible?: boolean;\n}\n\nexport interface TilemapRuntimeData {\n\twidth: number;\n\theight: number;\n\ttileSize: number;\n\tlayers: readonly RuntimeLayer[];\n\ttilesets: readonly RuntimeTileset[];\n\ttileMetadata?: Record<number, TileMetadata>;\n\tobjectLayers?: readonly { name: string; objects: readonly ObjectDef[] }[];\n}\n\nexport interface LoadedLayer {\n\tname: string;\n\ttiles: Uint32Array;\n\tparallax: Vector2D;\n\topacity: number;\n\tvisible: boolean;\n}\n\nexport interface LoadedTileset {\n\ttextureKey: string;\n\tcolumns: number;\n\ttileWidth: number;\n\ttileHeight: number;\n\tfirstgid: number;\n}\n\nexport interface LoadedObjectLayer {\n\tname: string;\n\tobjects: readonly ObjectDef[];\n}\n\nexport interface LoadedTilemap {\n\treadonly width: number;\n\treadonly height: number;\n\treadonly tileWidth: number;\n\treadonly tileHeight: number;\n\treadonly layers: readonly LoadedLayer[];\n\treadonly tilesets: readonly LoadedTileset[];\n\treadonly tileMetadata: ReadonlyMap<number, TileMetadata>;\n\treadonly objectLayers: readonly LoadedObjectLayer[];\n\n\ttileToWorld(tx: number, ty: number): Vector2D;\n\tworldToTile(wx: number, wy: number): { tx: number; ty: number };\n\tgetTile(layerIndex: number, tx: number, ty: number): number;\n\tisSolid(tx: number, ty: number): boolean;\n\tisOpaque(tx: number, ty: number): boolean;\n\tisWalkable(tx: number, ty: number): boolean;\n\tbuildNavGrid(layerIndex: number, costFn?: (tileId: number) => number): NavGrid;\n\tgetObjectLayer(name: string): readonly ObjectDef[];\n\tgetObjects(type: string): readonly ObjectDef[];\n}\n\n/** Subset of a Tiled `.tmj` (JSON) document we consume in v1. */\nexport interface TiledMap {\n\twidth: number;\n\theight: number;\n\ttilewidth: number;\n\ttileheight: number;\n\ttilesets: readonly TiledTileset[];\n\tlayers: readonly TiledLayer[];\n}\n\nexport interface TiledTileset {\n\tfirstgid: number;\n\tcolumns: number;\n\ttilewidth: number;\n\ttileheight: number;\n\timage: string;\n\timagewidth: number;\n\timageheight: number;\n\ttiles?: readonly TiledTileDef[];\n}\n\nexport interface TiledTileDef {\n\tid: number;\n\tproperties?: readonly TiledProperty[];\n\tanimation?: readonly { tileid: number; duration: number }[];\n}\n\nexport interface TiledProperty {\n\tname: string;\n\ttype: 'bool' | 'int' | 'float' | 'string' | 'color' | 'file' | 'object';\n\tvalue: string | number | boolean;\n}\n\nexport type TiledLayer = TiledTileLayer | TiledObjectLayer;\n\nexport interface TiledTileLayer {\n\ttype: 'tilelayer';\n\tname: string;\n\twidth: number;\n\theight: number;\n\tdata: readonly number[];\n\topacity: number;\n\tvisible: boolean;\n\tparallaxx?: number;\n\tparallaxy?: number;\n}\n\nexport interface TiledObjectLayer {\n\ttype: 'objectgroup';\n\tname: string;\n\tobjects: readonly TiledObject[];\n}\n\nexport interface TiledObject {\n\tid: number;\n\tname?: string;\n\ttype?: string;\n\tx: number;\n\ty: number;\n\twidth?: number;\n\theight?: number;\n\trotation?: number;\n\tproperties?: readonly TiledProperty[];\n}\n\nexport interface ParseTiledOptions {\n\ttilesetTextures: Record<string, string>;\n}\n\nexport type TilemapCullingMode = 'viewport' | 'none';\n\nexport interface TilemapLayerComponent {\n\tdataKey: string;\n\ttilesetKey?: string;\n\tlayerIndex: number;\n\topacity: number;\n\tparallax: Vector2D;\n\tcullingMode: TilemapCullingMode;\n\tcameraRef?: number;\n\ttintFn?: (tx: number, ty: number) => number | null;\n}\n\nexport interface TilemapColliderTag {\n\tdataKey: string;\n}\n\nexport interface TilemapComponentTypes {\n\ttilemap: TilemapLayerComponent;\n\ttilemapCollider: TilemapColliderTag;\n}\n\nexport interface TilemapRegistry {\n\tregisterRuntime(dataKey: string, data: TilemapRuntimeData): LoadedTilemap;\n\tregisterAsset(dataKey: string, assetKey: string, options?: ParseTiledOptions): Promise<LoadedTilemap>;\n\tget(dataKey: string): LoadedTilemap | undefined;\n\thas(dataKey: string): boolean;\n\treadonly entries: ReadonlyMap<string, LoadedTilemap>;\n}\n\nexport interface TilemapResourceTypes {\n\ttilemaps: TilemapRegistry;\n}\n\nexport type TilemapWorldConfig =\n\tComponentsConfig<TilemapComponentTypes>\n\t& ResourcesConfig<TilemapResourceTypes>;\n\nexport interface TilemapPluginOptions<G extends string = 'rendering'> extends BasePluginOptions<G> {\n\t/** Optional collision layer name. When set, solid tiles auto-spawn `aabbCollider` strips. */\n\tcollisionLayer?: string;\n\t/** Layers the auto-generated tile bodies collide with. */\n\tcollidesWith?: readonly string[];\n}\n\nfunction toTilesArray(input: RuntimeLayer['tiles']): Uint32Array {\n\treturn Uint32Array.from(input);\n}\n\nfunction tiledPropsToRecord(props?: readonly TiledProperty[]): Record<string, string | number | boolean> {\n\tif (!props) return {};\n\tconst out: Record<string, string | number | boolean> = {};\n\tfor (const p of props) out[p.name] = p.value;\n\treturn out;\n}\n\nexport function createLoadedTilemap(data: TilemapRuntimeData): LoadedTilemap {\n\tconst { width, height, tileSize, layers, tilesets } = data;\n\n\tif (!Number.isFinite(width) || width <= 0) {\n\t\tthrow new Error(`tilemap: width must be > 0, got ${width}`);\n\t}\n\tif (!Number.isFinite(height) || height <= 0) {\n\t\tthrow new Error(`tilemap: height must be > 0, got ${height}`);\n\t}\n\tif (!Number.isFinite(tileSize) || tileSize <= 0) {\n\t\tthrow new Error(`tilemap: tileSize must be > 0, got ${tileSize}`);\n\t}\n\tif (tilesets.length === 0) {\n\t\tthrow new Error('tilemap: at least one tileset is required');\n\t}\n\n\tconst expectedLen = width * height;\n\n\tconst loadedLayers: LoadedLayer[] = layers.map((l) => {\n\t\tconst tiles = toTilesArray(l.tiles);\n\t\tif (tiles.length !== expectedLen) {\n\t\t\tthrow new Error(\n\t\t\t\t`tilemap: layer \"${l.name}\" tile count ${tiles.length} does not match width*height ${expectedLen}`,\n\t\t\t);\n\t\t}\n\t\treturn {\n\t\t\tname: l.name,\n\t\t\ttiles,\n\t\t\tparallax: l.parallax ? { x: l.parallax.x, y: l.parallax.y } : { x: 1, y: 1 },\n\t\t\topacity: l.opacity ?? 1,\n\t\t\tvisible: l.visible ?? true,\n\t\t};\n\t});\n\n\tconst loadedTilesets: LoadedTileset[] = tilesets.map((t, i) => {\n\t\tif (t.firstgid === undefined && i > 0) {\n\t\t\tthrow new Error(`tilemap: runtime tileset at index ${i} (\"${t.textureKey}\") must specify an explicit firstgid`);\n\t\t}\n\t\treturn {\n\t\t\ttextureKey: t.textureKey,\n\t\t\tcolumns: t.columns,\n\t\t\ttileWidth: t.tileWidth,\n\t\t\ttileHeight: t.tileHeight,\n\t\t\tfirstgid: t.firstgid ?? 1,\n\t\t};\n\t});\n\n\tconst metadataMap = new Map<number, TileMetadata>();\n\tif (data.tileMetadata) {\n\t\tfor (const [k, v] of Object.entries(data.tileMetadata)) {\n\t\t\tmetadataMap.set(Number(k), { ...v });\n\t\t}\n\t}\n\n\tconst objectLayers: LoadedObjectLayer[] = (data.objectLayers ?? []).map(l => ({\n\t\tname: l.name,\n\t\tobjects: l.objects.map(o => ({ ...o, properties: { ...o.properties } })),\n\t}));\n\n\treturn buildLoadedTilemap({\n\t\twidth,\n\t\theight,\n\t\ttileWidth: tileSize,\n\t\ttileHeight: tileSize,\n\t\tlayers: loadedLayers,\n\t\ttilesets: loadedTilesets,\n\t\ttileMetadata: metadataMap,\n\t\tobjectLayers,\n\t});\n}\n\nexport function parseTiledJSON(map: TiledMap, options: ParseTiledOptions): LoadedTilemap {\n\tconst { width, height, tilewidth, tileheight } = map;\n\tconst expectedLen = width * height;\n\n\tconst loadedTilesets: LoadedTileset[] = map.tilesets.map((t) => {\n\t\tconst textureKey = options.tilesetTextures[t.image];\n\t\tif (!textureKey) {\n\t\t\tthrow new Error(`tilemap: no texture key registered for tileset image \"${t.image}\"`);\n\t\t}\n\t\treturn {\n\t\t\ttextureKey,\n\t\t\tcolumns: t.columns,\n\t\t\ttileWidth: t.tilewidth,\n\t\t\ttileHeight: t.tileheight,\n\t\t\tfirstgid: t.firstgid,\n\t\t};\n\t});\n\n\tconst metadataMap = new Map<number, TileMetadata>();\n\tfor (const ts of map.tilesets) {\n\t\tif (!ts.tiles) continue;\n\t\tfor (const td of ts.tiles) {\n\t\t\tmetadataMap.set(ts.firstgid + td.id, tiledPropsToRecord(td.properties) as TileMetadata);\n\t\t}\n\t}\n\n\tconst loadedLayers: LoadedLayer[] = [];\n\tconst loadedObjectLayers: LoadedObjectLayer[] = [];\n\tfor (const l of map.layers) {\n\t\tif (l.type === 'tilelayer') {\n\t\t\tif (l.data.length !== expectedLen) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`tilemap: layer \"${l.name}\" data length ${l.data.length} does not match map ${expectedLen}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tloadedLayers.push({\n\t\t\t\tname: l.name,\n\t\t\t\ttiles: Uint32Array.from(l.data),\n\t\t\t\tparallax: { x: l.parallaxx ?? 1, y: l.parallaxy ?? 1 },\n\t\t\t\topacity: l.opacity,\n\t\t\t\tvisible: l.visible,\n\t\t\t});\n\t\t} else {\n\t\t\tloadedObjectLayers.push({\n\t\t\t\tname: l.name,\n\t\t\t\tobjects: l.objects.map(o => ({\n\t\t\t\t\tname: o.name ?? '',\n\t\t\t\t\ttype: o.type ?? '',\n\t\t\t\t\tx: o.x,\n\t\t\t\t\ty: o.y,\n\t\t\t\t\twidth: o.width ?? 0,\n\t\t\t\t\theight: o.height ?? 0,\n\t\t\t\t\trotation: o.rotation ?? 0,\n\t\t\t\t\tproperties: tiledPropsToRecord(o.properties),\n\t\t\t\t})),\n\t\t\t});\n\t\t}\n\t}\n\n\treturn buildLoadedTilemap({\n\t\twidth,\n\t\theight,\n\t\ttileWidth: tilewidth,\n\t\ttileHeight: tileheight,\n\t\tlayers: loadedLayers,\n\t\ttilesets: loadedTilesets,\n\t\ttileMetadata: metadataMap,\n\t\tobjectLayers: loadedObjectLayers,\n\t});\n}\n\ninterface LoadedTilemapState {\n\twidth: number;\n\theight: number;\n\ttileWidth: number;\n\ttileHeight: number;\n\tlayers: LoadedLayer[];\n\ttilesets: LoadedTileset[];\n\ttileMetadata: Map<number, TileMetadata>;\n\tobjectLayers: LoadedObjectLayer[];\n}\n\nfunction buildLoadedTilemap(state: LoadedTilemapState): LoadedTilemap {\n\tconst { width, height, tileWidth, tileHeight, layers, tilesets, tileMetadata, objectLayers } = state;\n\n\t// Why: hot path. Inlining the bounds + cellIndex math here avoids\n\t// per-layer recomputation in the loop below (called by FOV / pathfinding consumers).\n\tconst flagAtAnyLayer = (tx: number, ty: number, key: TileFlag): boolean => {\n\t\tif (tx < 0 || ty < 0 || tx >= width || ty >= height) return false;\n\t\tconst idx = ty * width + tx;\n\t\tfor (let i = 0; i < layers.length; i++) {\n\t\t\tconst gid = (layers[i]!.tiles[idx] ?? 0) & TILE_GID_MASK;\n\t\t\tif (gid === 0) continue;\n\t\t\tconst meta = tileMetadata.get(gid);\n\t\t\tif (meta && meta[key] === true) return true;\n\t\t}\n\t\treturn false;\n\t};\n\n\tconst defaultCostFromMetadata = (gid: number): number => {\n\t\tconst meta = tileMetadata.get(gid);\n\t\treturn meta?.walkable === true ? 1 : 0;\n\t};\n\n\treturn {\n\t\twidth,\n\t\theight,\n\t\ttileWidth,\n\t\ttileHeight,\n\t\tlayers,\n\t\ttilesets,\n\t\ttileMetadata,\n\t\tobjectLayers,\n\n\t\ttileToWorld(tx, ty) {\n\t\t\treturn { x: (tx + 0.5) * tileWidth, y: (ty + 0.5) * tileHeight };\n\t\t},\n\n\t\tworldToTile(wx, wy) {\n\t\t\treturn { tx: Math.floor(wx / tileWidth), ty: Math.floor(wy / tileHeight) };\n\t\t},\n\n\t\tgetTile(layerIndex, tx, ty) {\n\t\t\tconst layer = layers[layerIndex];\n\t\t\tif (!layer) return 0;\n\t\t\tif (tx < 0 || ty < 0 || tx >= width || ty >= height) return 0;\n\t\t\treturn (layer.tiles[ty * width + tx] ?? 0) & TILE_GID_MASK;\n\t\t},\n\n\t\tisSolid: (tx, ty) => flagAtAnyLayer(tx, ty, 'solid'),\n\t\tisOpaque: (tx, ty) => flagAtAnyLayer(tx, ty, 'blocksSight'),\n\t\tisWalkable: (tx, ty) => flagAtAnyLayer(tx, ty, 'walkable'),\n\n\t\tbuildNavGrid(layerIndex, costFn) {\n\t\t\tconst layer = layers[layerIndex];\n\t\t\tif (!layer) {\n\t\t\t\tthrow new Error(`tilemap: buildNavGrid — no layer at index ${layerIndex}`);\n\t\t\t}\n\t\t\tconst cells = new Uint8Array(width * height);\n\t\t\tconst cost = costFn ?? defaultCostFromMetadata;\n\t\t\tfor (let i = 0; i < cells.length; i++) {\n\t\t\t\tconst gid = (layer.tiles[i] ?? 0) & TILE_GID_MASK;\n\t\t\t\tconst c = cost(gid) | 0;\n\t\t\t\tcells[i] = c < 0 ? 0 : c > 255 ? 255 : c;\n\t\t\t}\n\t\t\treturn createNavGrid({ width, height, cellSize: tileWidth, cells });\n\t\t},\n\n\t\tgetObjectLayer(name) {\n\t\t\treturn objectLayers.find(l => l.name === name)?.objects ?? [];\n\t\t},\n\n\t\tgetObjects(type) {\n\t\t\tconst out: ObjectDef[] = [];\n\t\t\tfor (const layer of objectLayers) {\n\t\t\t\tfor (const o of layer.objects) {\n\t\t\t\t\tif (o.type === type) out.push(o);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn out;\n\t\t},\n\t};\n}\n\ninterface CollisionStrip {\n\ttx: number;\n\tty: number;\n\ttw: number;\n\tth: number;\n}\n\n/** Greedy row-first scan: each row produces N horizontal strips. No vertical merge in v1. */\nfunction buildCollisionStrips(map: LoadedTilemap): CollisionStrip[] {\n\tconst strips: CollisionStrip[] = [];\n\tfor (let ty = 0; ty < map.height; ty++) {\n\t\tlet runStart = -1;\n\t\tfor (let tx = 0; tx <= map.width; tx++) {\n\t\t\tconst solid = tx < map.width && map.isSolid(tx, ty);\n\t\t\tif (solid && runStart === -1) {\n\t\t\t\trunStart = tx;\n\t\t\t} else if (!solid && runStart !== -1) {\n\t\t\t\tstrips.push({ tx: runStart, ty, tw: tx - runStart, th: 1 });\n\t\t\t\trunStart = -1;\n\t\t\t}\n\t\t}\n\t}\n\treturn strips;\n}\n\n// Component shape for the optional collision-strip spawn. The plugin doesn't\n// declare a hard requirement on the collision/transform plugins so users who\n// don't enable `collisionLayer` aren't forced to install them; the cast at the\n// spawn site is the bridge. When `collisionLayer` is set the user has installed\n// both plugins by definition (otherwise the layer name would be meaningless).\ninterface CollisionSpawnShape {\n\ttilemapCollider: TilemapColliderTag;\n\taabbCollider: AABBCollider;\n\tcollisionLayer: CollisionLayer<string>;\n\tlocalTransform: LocalTransform;\n\tworldTransform: WorldTransform;\n}\n\ntype TilemapWorld = ECSpresso<TilemapWorldConfig>;\n\ntype TilemapLabels = never;\n\nexport function createTilemapPlugin<G extends string = 'rendering'>(\n\toptions: TilemapPluginOptions<G> = {},\n) {\n\tconst { collisionLayer, collidesWith } = options;\n\n\treturn definePlugin('tilemap')\n\t\t.withComponentTypes<TilemapComponentTypes>()\n\t\t.withResourceTypes<TilemapResourceTypes>()\n\t\t.withLabels<TilemapLabels>()\n\t\t.withGroups<G>()\n\t\t.install((world: TilemapWorld) => {\n\t\t\tconst entries = new Map<string, LoadedTilemap>();\n\t\t\tconst colliderEntitiesByKey = new Map<string, number[]>();\n\n\t\t\tconst despawnCollidersFor = (dataKey: string): void => {\n\t\t\t\tconst ids = colliderEntitiesByKey.get(dataKey);\n\t\t\t\tif (!ids) return;\n\t\t\t\tfor (const id of ids) world.removeEntity(id);\n\t\t\t\tcolliderEntitiesByKey.delete(dataKey);\n\t\t\t};\n\n\t\t\tconst spawnCollisionStripsFor = (dataKey: string, lt: LoadedTilemap): void => {\n\t\t\t\tif (!collisionLayer) return;\n\t\t\t\tconst ids: number[] = [];\n\t\t\t\tfor (const s of buildCollisionStrips(lt)) {\n\t\t\t\t\tconst cx = (s.tx + s.tw / 2) * lt.tileWidth;\n\t\t\t\t\tconst cy = (s.ty + s.th / 2) * lt.tileHeight;\n\t\t\t\t\tconst components: CollisionSpawnShape = {\n\t\t\t\t\t\ttilemapCollider: { dataKey },\n\t\t\t\t\t\taabbCollider: { width: s.tw * lt.tileWidth, height: s.th * lt.tileHeight },\n\t\t\t\t\t\tcollisionLayer: { layer: collisionLayer, collidesWith: collidesWith ?? [] },\n\t\t\t\t\t\tlocalTransform: { x: cx, y: cy, rotation: 0, scaleX: 1, scaleY: 1 },\n\t\t\t\t\t\tworldTransform: { x: cx, y: cy, rotation: 0, scaleX: 1, scaleY: 1 },\n\t\t\t\t\t};\n\t\t\t\t\tconst entity = (world as unknown as ECSpresso<ComponentsConfig<CollisionSpawnShape>>).spawn(components);\n\t\t\t\t\tids.push(entity.id);\n\t\t\t\t}\n\t\t\t\tif (ids.length > 0) colliderEntitiesByKey.set(dataKey, ids);\n\t\t\t};\n\n\t\t\tconst ingest = (dataKey: string, lt: LoadedTilemap): LoadedTilemap => {\n\t\t\t\tdespawnCollidersFor(dataKey);\n\t\t\t\tentries.set(dataKey, lt);\n\t\t\t\tspawnCollisionStripsFor(dataKey, lt);\n\t\t\t\treturn lt;\n\t\t\t};\n\n\t\t\tconst registry: TilemapRegistry = {\n\t\t\t\tentries,\n\t\t\t\tregisterRuntime(dataKey, data) {\n\t\t\t\t\treturn ingest(dataKey, createLoadedTilemap(data));\n\t\t\t\t},\n\t\t\t\tasync registerAsset(dataKey, assetKey, parseOptions) {\n\t\t\t\t\tconst raw = await (world as unknown as ECSpresso<AssetsConfig<{ [k: string]: TiledMap }>>).loadAsset(assetKey) as TiledMap;\n\t\t\t\t\treturn ingest(dataKey, parseTiledJSON(raw, parseOptions ?? { tilesetTextures: {} }));\n\t\t\t\t},\n\t\t\t\tget: (dataKey) => entries.get(dataKey),\n\t\t\t\thas: (dataKey) => entries.has(dataKey),\n\t\t\t};\n\n\t\t\tworld.addResource('tilemaps', registry);\n\t\t});\n}\n\n/**\n * Create a `tilemap` layer component for spreading into `spawn()`.\n *\n * @example\n * ```typescript\n * ecs.spawn({\n * ...createTilemapLayer('dungeon', 0),\n * ...createLocalTransform(0, 0),\n * });\n * ```\n */\nexport function createTilemapLayer(\n\tdataKey: string,\n\tlayerIndex: number,\n\toptions?: {\n\t\ttilesetKey?: string;\n\t\topacity?: number;\n\t\tparallax?: Vector2D;\n\t\tcullingMode?: TilemapCullingMode;\n\t\tcameraRef?: number;\n\t\ttintFn?: (tx: number, ty: number) => number | null;\n\t},\n): Pick<TilemapComponentTypes, 'tilemap'> {\n\treturn {\n\t\ttilemap: {\n\t\t\tdataKey,\n\t\t\tlayerIndex,\n\t\t\ttilesetKey: options?.tilesetKey,\n\t\t\topacity: options?.opacity ?? 1,\n\t\t\tparallax: options?.parallax ?? { x: 1, y: 1 },\n\t\t\tcullingMode: options?.cullingMode ?? 'viewport',\n\t\t\tcameraRef: options?.cameraRef,\n\t\t\ttintFn: options?.tintFn,\n\t\t},\n\t};\n}\n"
7
7
  ],
8
- "mappings": "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",
8
+ "mappings": "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",
9
9
  "debugId": "2E25150012F8083364756E2164756E21",
10
10
  "names": []
11
11
  }