{"version":3,"file":"dill-pixel-plugin-crunch-physics.mjs","sources":["../src/types.ts","../src/utils.ts","../src/Entity.ts","../src/Actor.ts","../src/Group.ts","../src/Sensor.ts","../src/Solid.ts","../src/System.ts","../src/CrunchPhysicsPlugin.ts"],"sourcesContent":["import { PointLike, SizeLike } from 'dill-pixel';\nimport { Container } from 'pixi.js';\nimport { Actor } from './Actor';\nimport { Entity } from './Entity';\nimport { Group } from './Group';\nimport { Sensor } from './Sensor';\nimport { Solid } from './Solid';\n\nexport interface Vector2 {\n  x: number;\n  y: number;\n}\n\nexport interface Rectangle {\n  x: number;\n  y: number;\n  width: number;\n  height: number;\n}\n\nexport type CollisionShape = 'rectangle';\nexport type EntityData = {\n  [key: string]: any;\n};\n\nexport type PhysicsEntityClass = new (config?: PhysicsEntityConfig) => Actor | Solid | Sensor;\n\n/**\n * Collision layers using bitwise flags\n * Each entity can belong to multiple layers (using bitwise OR)\n * and can collide with multiple layers (using bitwise AND)\n */\nexport enum CollisionLayer {\n  NONE = 0,\n  DEFAULT = 1 << 0,\n  PLAYER = 1 << 1,\n  ENEMY = 1 << 2,\n  PROJECTILE = 1 << 3,\n  PLATFORM = 1 << 4,\n  TRIGGER = 1 << 5,\n  ITEM = 1 << 6,\n  WALL = 1 << 7,\n  FX = 1 << 8,\n  // Reserve first 16 bits for built-in layers\n  // Bits 16-31 are available for user-defined layers\n  ALL = 0xffffffff, // All bits set to 1\n}\n\n/**\n * Interface for a registered collision layer\n */\nexport interface RegisteredCollisionLayer {\n  /** Name of the collision layer */\n  name: string;\n  /** Numeric value of the collision layer (bitwise) */\n  value: number;\n  /** Description of the collision layer (optional) */\n  description?: string;\n}\n\n/**\n * Registry for tracking custom collision layers\n */\nexport class CollisionLayerRegistry {\n  private static _instance: CollisionLayerRegistry;\n  private _layers: Map<string, RegisteredCollisionLayer> = new Map();\n  private _usedIndices: Set<number> = new Set();\n\n  /**\n   * Get the singleton instance of the registry\n   */\n  public static get instance(): CollisionLayerRegistry {\n    if (!CollisionLayerRegistry._instance) {\n      CollisionLayerRegistry._instance = new CollisionLayerRegistry();\n    }\n    return CollisionLayerRegistry._instance;\n  }\n\n  /**\n   * Register a new collision layer\n   *\n   * @param name Name of the collision layer\n   * @param index Index from 0-15 representing which user bit to use (gets shifted to bits 16-31)\n   * @param description Optional description of the layer\n   * @returns The registered collision layer\n   */\n  public register(name: string, index: number, description?: string): RegisteredCollisionLayer {\n    if (index < 0 || index > 15) {\n      throw new Error('Custom collision layer index must be between 0 and 15');\n    }\n\n    if (this._usedIndices.has(index)) {\n      throw new Error(`Collision layer index ${index} is already in use`);\n    }\n\n    if (this._layers.has(name)) {\n      throw new Error(`Collision layer with name \"${name}\" already exists`);\n    }\n\n    const value = 1 << (index + 16);\n    const layer: RegisteredCollisionLayer = { name, value, description };\n\n    this._layers.set(name, layer);\n    this._usedIndices.add(index);\n\n    return layer;\n  }\n\n  /**\n   * Get a registered collision layer by name\n   *\n   * @param name Name of the collision layer\n   * @returns The registered collision layer or undefined if not found\n   */\n  public get(name: string): RegisteredCollisionLayer | undefined {\n    return this._layers.get(name);\n  }\n\n  /**\n   * Get all registered collision layers\n   *\n   * @returns Array of all registered collision layers\n   */\n  public getAll(): RegisteredCollisionLayer[] {\n    return Array.from(this._layers.values());\n  }\n\n  /**\n   * Check if a collision layer with the given name exists\n   *\n   * @param name Name of the collision layer\n   * @returns True if the layer exists\n   */\n  public has(name: string): boolean {\n    return this._layers.has(name);\n  }\n\n  /**\n   * Remove a registered collision layer\n   *\n   * @param name Name of the collision layer to remove\n   * @returns True if the layer was removed, false if it didn't exist\n   */\n  public remove(name: string): boolean {\n    const layer = this._layers.get(name);\n    if (!layer) return false;\n\n    // Calculate the index from the value\n    const value = layer.value;\n    const index = Math.log2(value) - 16;\n\n    this._usedIndices.delete(index);\n    return this._layers.delete(name);\n  }\n\n  /**\n   * Clear all registered collision layers\n   */\n  public clear(): void {\n    this._layers.clear();\n    this._usedIndices.clear();\n  }\n\n  /**\n   * Get the next available index for a custom collision layer\n   *\n   * @returns The next available index or -1 if all indices are used\n   */\n  public getNextAvailableIndex(): number {\n    for (let i = 0; i < 16; i++) {\n      if (!this._usedIndices.has(i)) {\n        return i;\n      }\n    }\n    return -1;\n  }\n}\n\n/**\n * Utility functions for working with collision layers\n */\nexport const CollisionLayers = {\n  /**\n   * Creates a custom collision layer using bits 16-31 (user space)\n   *\n   * @param index Index from 0-15 representing which user bit to use (gets shifted to bits 16-31)\n   * @returns A unique collision layer value\n   *\n   * @example\n   * ```typescript\n   * // Create custom collision layers\n   * const WATER_LAYER = CollisionLayers.createLayer(0);  // 1 << 16\n   * const LAVA_LAYER = CollisionLayers.createLayer(1);   // 1 << 17\n   * const CLOUD_LAYER = CollisionLayers.createLayer(2);  // 1 << 18\n   *\n   * // Use in entity creation\n   * const waterEntity = physics.createActor({\n   *   type: 'Water',\n   *   position: [100, 400],\n   *   size: [800, 100],\n   *   collisionLayer: WATER_LAYER,\n   *   collisionMask: CollisionLayer.PLAYER | CollisionLayer.ENEMY\n   * });\n   * ```\n   */\n  createLayer(index: number): number {\n    if (index < 0 || index > 15) {\n      throw new Error('Custom collision layer index must be between 0 and 15');\n    }\n    return 1 << (index + 16);\n  },\n\n  /**\n   * Creates a collision mask from multiple layers\n   *\n   * @param layers Array of collision layers to combine\n   * @returns A combined collision mask\n   *\n   * @example\n   * ```typescript\n   * // Create a mask that collides with players, enemies and projectiles\n   * const mask = CollisionLayers.createMask([\n   *   CollisionLayer.PLAYER,\n   *   CollisionLayer.ENEMY,\n   *   CollisionLayer.PROJECTILE\n   * ]);\n   * ```\n   */\n  createMask(layers: number[]): number {\n    return layers.reduce((mask, layer) => mask | layer, 0);\n  },\n\n  /**\n   * Checks if a layer is included in a mask\n   *\n   * @param layer The layer to check\n   * @param mask The mask to check against\n   * @returns True if the layer is included in the mask\n   *\n   * @example\n   * ```typescript\n   * // Check if player layer is in the mask\n   * if (CollisionLayers.isLayerInMask(CollisionLayer.PLAYER, entity.collisionMask)) {\n   *   console.log('Entity can collide with players');\n   * }\n   * ```\n   */\n  isLayerInMask(layer: number, mask: number): boolean {\n    return (layer & mask) !== 0;\n  },\n\n  /**\n   * Get the registry for custom collision layers\n   *\n   * @returns The collision layer registry\n   */\n  getRegistry(): CollisionLayerRegistry {\n    return CollisionLayerRegistry.instance;\n  },\n};\n\nexport interface PhysicsEntityConfig<D extends EntityData = EntityData> {\n  id?: string;\n  class?: PhysicsEntityClass;\n  type?: PhysicsEntityType;\n  position?: PointLike;\n  size?: SizeLike;\n  x?: number;\n  y?: number;\n  width?: number;\n  height?: number;\n  restitution?: number;\n  view?: PhysicsEntityView;\n  data?: Partial<D>;\n  group?: Group;\n  groupOffset?: PointLike;\n  follows?: Entity;\n  followOffset?: PointLike;\n  /** Collision layer this entity belongs to (bitwise) */\n  collisionLayer?: number;\n  /** Collision mask defining which layers this entity collides with (bitwise) */\n  collisionMask?: number;\n  /** Whether to disable actor-to-actor collisions for this entity */\n  disableActorCollisions?: boolean;\n}\n\nexport interface CollisionResult {\n  collided: boolean;\n  normal?: Vector2;\n  penetration?: number;\n  solid: Solid;\n}\n\nexport interface SensorOverlap {\n  type: `${PhysicsEntityType}|${PhysicsEntityType}`;\n  actor: Actor;\n  sensor: Sensor;\n}\n\nexport interface CollisionResult {\n  collided: boolean;\n  normal?: Vector2;\n  penetration?: number;\n  solid: Solid;\n  pushingSolid?: Solid;\n}\n\n/**\n * Result of an actor-to-actor collision\n */\nexport interface ActorCollisionResult {\n  collided: boolean;\n  normal?: Vector2;\n  penetration?: number;\n  actor: Actor;\n}\n\nexport interface Collision {\n  type: `${PhysicsEntityType}|${PhysicsEntityType}`;\n  entity1: Actor | Sensor;\n  entity2: Actor | Solid;\n  result: CollisionResult;\n}\n\n/**\n * Represents a collision between two actors\n */\nexport interface ActorCollision {\n  type: `${PhysicsEntityType}|${PhysicsEntityType}`;\n  actor1: Actor;\n  actor2: Actor;\n  result: ActorCollisionResult;\n}\n\nexport type PhysicsEntityView = Container;\nexport type PhysicsEntityType = 'Actor' | 'Solid' | 'Sensor' | 'Group' | string;\n","import { resolvePointLike, resolveSizeLike } from 'dill-pixel';\nimport { PhysicsEntityConfig } from './types';\n\n/**\n * Utility functions for resolving entity positions and sizes from various input formats.\n * These functions handle the conversion of different coordinate and size specifications\n * into standardized formats used by the physics system.\n */\n\n/**\n * Resolves an entity's position from various input formats.\n * Supports direct x/y values or a position object/array.\n *\n * @param config - Entity configuration containing position information\n * @returns Resolved {x, y} coordinates\n *\n * @example\n * ```typescript\n * // Using direct x/y values\n * resolveEntityPosition({ x: 100, y: 200 })\n * // → { x: 100, y: 200 }\n *\n * // Using position array\n * resolveEntityPosition({ position: [100, 200] })\n * // → { x: 100, y: 200 }\n *\n * // Using position object\n * resolveEntityPosition({ position: { x: 100, y: 200 } })\n * // → { x: 100, y: 200 }\n * ```\n */\nexport function resolveEntityPosition(config: PhysicsEntityConfig): { x: number; y: number } {\n  const { x, y } =\n    config.position !== undefined ? resolvePointLike(config.position) : { x: config?.x ?? 0, y: config?.y ?? 0 };\n\n  return { x, y };\n}\n\n/**\n * Resolves an entity's size from various input formats.\n * Supports direct width/height values or a size object/array.\n *\n * @param config - Entity configuration containing size information\n * @returns Resolved {width, height} dimensions\n *\n * @example\n * ```typescript\n * // Using direct width/height values\n * resolveEntitySize({ width: 100, height: 200 })\n * // → { width: 100, height: 200 }\n *\n * // Using size array\n * resolveEntitySize({ size: [100, 200] })\n * // → { width: 100, height: 200 }\n *\n * // Using size object\n * resolveEntitySize({ size: { width: 100, height: 200 } })\n * // → { width: 100, height: 200 }\n *\n * // Using defaults\n * resolveEntitySize({})\n * // → { width: 32, height: 32 }\n * ```\n */\nexport function resolveEntitySize(config: PhysicsEntityConfig): { width: number; height: number } {\n  const { width, height } =\n    config.size !== undefined\n      ? resolveSizeLike(config.size)\n      : { width: config?.width ?? 32, height: config?.height ?? 32 };\n\n  return { width, height };\n}\n","import {\n  Application,\n  bindAllMethods,\n  defaultFactoryMethods,\n  PointLike,\n  randomUUID,\n  resolvePointLike,\n  SignalConnection,\n  SignalConnections,\n} from 'dill-pixel';\nimport CrunchPhysicsPlugin from './CrunchPhysicsPlugin';\nimport { Group } from './Group';\nimport { System } from './System';\nimport {\n  CollisionLayer,\n  EntityData,\n  PhysicsEntityConfig,\n  PhysicsEntityType,\n  PhysicsEntityView,\n  Rectangle,\n} from './types';\nimport { resolveEntityPosition, resolveEntitySize } from './utils';\n\n/**\n * Base class for all physics entities in the Crunch physics system.\n * Provides common functionality for position, size, view management, and lifecycle.\n *\n * Entity is the foundation for:\n * - Actors (dynamic objects)\n * - Solids (static objects)\n * - Sensors (trigger zones)\n *\n * It handles:\n * - Position and size management\n * - View (sprite) management and updates\n * - Group membership and relative positioning\n * - Culling and lifecycle states\n * - Signal connections for event handling\n *\n * @typeParam A - Application type, defaults to base Application\n * @typeParam D - Entity data type, defaults to base EntityData\n *\n * @example\n * ```typescript\n * // Create a custom entity\n * class CustomEntity extends Entity {\n *   constructor() {\n *     super({\n *       type: 'Custom',\n *       position: [100, 100],\n *       size: [32, 32],\n *       view: sprite\n *     });\n *   }\n *\n *   // Override update for custom behavior\n *   update(dt: number) {\n *     super.update(dt);\n *     // Custom update logic\n *   }\n * }\n * ```\n */\nexport class Entity<A extends Application = Application, D extends EntityData = EntityData> {\n  public readonly entityType: PhysicsEntityType;\n  protected _id: string;\n  /** Unique type identifier for this entity */\n  public type!: string;\n\n  /** Color to use when rendering debug visuals */\n  public debugColor: number;\n\n  /** Whether the entity should be removed when culled (out of bounds) */\n  public shouldRemoveOnCull: boolean;\n\n  /** Entity width in pixels */\n  public width: number;\n\n  /** Entity height in pixels */\n  public height: number;\n\n  /** Visual representation (sprite/graphics) of this entity */\n  public view!: PhysicsEntityView;\n\n  /** Whether this entity is active and should be updated */\n\n  /** Collision layer this entity belongs to (bitwise) */\n  public collisionLayer: number = CollisionLayer.NONE;\n\n  /** Collision mask defining which layers this entity collides with (bitwise) */\n  public collisionMask: number = CollisionLayer.NONE;\n\n  protected _data: Partial<D>;\n  protected _group: Group | null;\n  protected _groupOffset: { x: number; y: number };\n  protected _isCulled: boolean;\n  protected _isDestroyed: boolean;\n  protected _isInitialized: boolean;\n  protected _xRemainder: number;\n  protected _yRemainder: number;\n  protected _x: number;\n  protected _y: number;\n  protected signalConnections: SignalConnections;\n  protected _following: Entity | null;\n  protected _followOffset: { x: number; y: number };\n  protected _config: PhysicsEntityConfig<D> | undefined;\n  protected _active: boolean = true;\n\n  public updatedFollowPosition: boolean = false;\n  public updatedGroupPosition: boolean = false;\n\n  set active(value: boolean) {\n    this._active = value;\n  }\n\n  get active(): boolean {\n    return this._active;\n  }\n\n  set id(value: string) {\n    this._id = value;\n  }\n\n  get id(): string {\n    return this._id || this.type;\n  }\n\n  get make(): typeof defaultFactoryMethods {\n    return this.app.make;\n  }\n\n  /**\n   * Custom data associated with this entity\n   */\n  set data(value: Partial<D>) {\n    this._data = value;\n  }\n\n  get data(): Partial<D> {\n    return this._data;\n  }\n\n  setFollowing(entityToFollow: Entity | null, offset: PointLike = { x: 0, y: 0 }) {\n    this._followOffset = resolvePointLike(offset);\n    if (this._following) {\n      this.system.removeFollower(this);\n    }\n    this._following = entityToFollow;\n    if (entityToFollow) {\n      this.system.addFollower(entityToFollow, this);\n    }\n  }\n\n  get followOffset(): { x: number; y: number } {\n    return this._followOffset || { x: 0, y: 0 };\n  }\n\n  get following(): Entity | null {\n    return this._following;\n  }\n\n  get followers(): Entity[] {\n    return this.system.getFollowersOf(this);\n  }\n\n  /**\n   * The group this entity belongs to, if any.\n   * Groups allow for collective movement and management of entities.\n   */\n  get group(): Group | null {\n    return this._group;\n  }\n\n  set groupOffset(value: { x: number; y: number }) {\n    this._groupOffset = resolvePointLike(value);\n  }\n\n  get groupOffset(): { x: number; y: number } {\n    return this._groupOffset || { x: 0, y: 0 };\n  }\n\n  setGroup(group: Group | null, offset: PointLike = { x: 0, y: 0 }) {\n    this._groupOffset = resolvePointLike(offset);\n    // if we're already in a group, remove ourselves first\n    if (this._group) {\n      this.system.removeFromGroup(this);\n      this.onRemovedFromGroup();\n    }\n    this._group = group;\n    if (group) {\n      this.system.addToGroup(group, this);\n      this.onAddedToGroup();\n    }\n  }\n\n  set position(value: PointLike) {\n    const { x, y } = resolvePointLike(value);\n    this.setPosition(x, y);\n  }\n\n  get position(): PointLike {\n    return { x: this.x, y: this.y };\n  }\n\n  /**\n   * Entity's X position in world space.\n   * If the entity belongs to a group, returns position relative to group.\n   */\n  set x(value: number) {\n    this._x = value;\n  }\n\n  get x(): number {\n    if (this._group) {\n      return Math.round(this._x + this._group.getChildOffset(this).x); // Return world position\n    }\n    return Math.round(this._x);\n  }\n\n  /**\n   * Entity's Y position in world space.\n   * If the entity belongs to a group, returns position relative to group.\n   */\n  set y(value: number) {\n    this._y = value;\n  }\n\n  get y(): number {\n    if (this._group) {\n      return Math.round(this._y + this._group.getChildOffset(this).y); // Return world position\n    }\n    return Math.round(this._y);\n  }\n\n  /** Whether this entity is currently culled (out of bounds) */\n  get isCulled(): boolean {\n    return this._isCulled;\n  }\n\n  /** Whether this entity has been destroyed */\n  get isDestroyed(): boolean {\n    return this._isDestroyed;\n  }\n\n  /** Reference to the main application instance */\n  get app(): A {\n    return Application.getInstance() as A;\n  }\n\n  /** Reference to the physics plugin */\n  get physics(): CrunchPhysicsPlugin {\n    return this.app.getPlugin('crunch-physics') as CrunchPhysicsPlugin;\n  }\n\n  /**\n   * Creates a new Entity instance.\n   *\n   * @param config - Optional configuration for the entity\n   */\n  constructor(config?: PhysicsEntityConfig<D>) {\n    bindAllMethods(this);\n\n    this._config = config;\n\n    this.signalConnections = new SignalConnections();\n    this.shouldRemoveOnCull = false;\n    this.width = 0;\n    this.height = 0;\n\n    this._data = {};\n    this._group = null;\n    this._isCulled = false;\n    this._isDestroyed = false;\n    this._isInitialized = false;\n    this._xRemainder = 0;\n    this._yRemainder = 0;\n\n    this._x = 0;\n    this._y = 0;\n\n    if (config) {\n      this.init(config);\n    }\n\n    this.initialize();\n    this.addView();\n  }\n\n  /**\n   * Called after construction to perform additional initialization.\n   * Override this in subclasses to add custom initialization logic.\n   */\n  protected initialize() {\n    // Override in subclass\n  }\n\n  /**\n   * Called before update to prepare for the next frame.\n   * Override this in subclasses to add pre-update logic.\n   */\n  public preUpdate(): void {\n    // Override in subclass\n  }\n\n  /**\n   * Called every frame to update the entity's state.\n   * Override this in subclasses to add update logic.\n   *\n   * @param dt - Delta time in seconds since last update\n   */\n  public update(dt: number): void {\n    // Override in subclass\n    void dt;\n  }\n\n  /**\n   * Called after update to finalize the frame.\n   * Override this in subclasses to add post-update logic.\n   */\n  public postUpdate(): void {\n    // Override in subclass\n  }\n\n  /**\n   * Excludes collision types for this entity\n   * @deprecated Use setCollisionMask instead\n   */\n  excludeCollisionType() {\n    console.warn('excludeCollisionType is deprecated. Use setCollisionMask instead.');\n    // No-op as we're removing this functionality\n  }\n\n  /**\n   * Includes collision types for this entity\n   * @deprecated Use setCollisionMask instead\n   */\n  includeCollisionType() {\n    console.warn('includeCollisionType is deprecated. Use setCollisionMask instead.');\n    // No-op as we're removing this functionality\n  }\n\n  /**\n   * Removes collision types for this entity\n   * @deprecated Use removeCollisionMask instead\n   */\n  removeCollisionType() {\n    console.warn('removeCollisionType is deprecated. Use removeCollisionMask instead.');\n    // No-op as we're removing this functionality\n  }\n\n  /**\n   * Adds collision types for this entity\n   * @deprecated Use addCollisionMask instead\n   */\n  addCollisionType() {\n    console.warn('addCollisionType is deprecated. Use addCollisionMask instead.');\n    // No-op as we're removing this functionality\n  }\n\n  /**\n   * Checks if this entity can collide with a specific type\n   */\n  canCollideWith(): boolean {\n    // Always return true as we're now using only collision layers/masks\n    return true;\n  }\n\n  /**\n   * Adds the entity's view to the physics container and updates its position.\n   */\n  protected addView() {\n    if (this.view) {\n      this.view.visible = true;\n      this.view.label = this.id || this.type;\n      if (this.system.container) {\n        this.system.container.addChild(this.view);\n        this.updateView();\n      }\n    }\n  }\n\n  /**\n   * Initializes or reinitializes the entity with new configuration.\n   * Used by object pools when recycling entities.\n   *\n   * @param config - New configuration to apply\n   */\n  public init(config: PhysicsEntityConfig<D>): void {\n    if (!config) return;\n    this._config = config as PhysicsEntityConfig<D>;\n\n    if (config.id) {\n      this._id = config.id;\n    } else {\n      this._id = randomUUID();\n    }\n\n    if (config.type) {\n      this.type = config.type;\n    }\n\n    if (config.data) {\n      this._data = config.data as Partial<D>;\n    }\n\n    const position = resolveEntityPosition(config);\n    this._x = position.x;\n    this._y = position.y;\n\n    const size = resolveEntitySize(config);\n    this.width = size.width;\n    this.height = size.height;\n\n    // Initialize collision layers\n    if (config.collisionLayer !== undefined) {\n      this.setCollisionLayer(config.collisionLayer);\n    }\n\n    if (config.collisionMask !== undefined) {\n      this.setCollisionMask(config.collisionMask);\n    }\n\n    // Reset physics properties\n    this._xRemainder = 0;\n    this._yRemainder = 0;\n\n    if (config.view) {\n      this.setView(config.view);\n    }\n\n    if (config.group) {\n      this.setGroup(config.group ?? null, config.groupOffset ? resolvePointLike(config.groupOffset) : { x: 0, y: 0 });\n    }\n\n    if (config.follows) {\n      this.setFollowing(\n        config.follows ?? null,\n        config.followOffset ? resolvePointLike(config.followOffset) : { x: 0, y: 0 },\n      );\n    }\n    // Show and update view if it exists\n    this.addView();\n  }\n\n  /**\n   * Resets the entity to its initial state for reuse in object pools.\n   * Override this to handle custom reset logic.\n   */\n  public reset(): void {\n    // Reset culling state\n    this._isCulled = false;\n    this._isDestroyed = false;\n\n    // Reset remainders\n    this._xRemainder = 0;\n    this._yRemainder = 0;\n\n    this._followOffset = { x: 0, y: 0 };\n    this._following = null;\n\n    this._groupOffset = { x: 0, y: 0 };\n    this._group = null;\n\n    this._data = {};\n\n    this._x = -Number.MAX_SAFE_INTEGER;\n    this._y = -Number.MAX_SAFE_INTEGER;\n\n    if (this.view) {\n      this.view.visible = false;\n    }\n\n    this.system.removeEntity(this);\n  }\n\n  /** Reference to the physics system */\n  get system(): System {\n    return this.physics.system;\n  }\n\n  /**\n   * Called when the entity is added to a group.\n   * Override this to handle custom group addition logic.\n   */\n  public onAddedToGroup(): void {\n    // Override in subclass\n  }\n\n  /**\n   * Called when the entity is removed from a group.\n   * Override this to handle custom group removal logic.\n   */\n  public onRemovedFromGroup(): void {\n    // Override in subclass\n  }\n\n  /**\n   * Updates the entity's position and view.\n   */\n  public updatePosition(): void {\n    this.x = this._x;\n    this.y = this._y;\n    this.updateView();\n  }\n\n  /**\n   * Called when the entity is culled (goes out of bounds).\n   * Override this to handle culling differently.\n   */\n  public onCull(): void {\n    this._isCulled = true;\n    // Default behavior: hide the view\n    if (this.view) {\n      this.view.visible = false;\n    }\n  }\n\n  /**\n   * Called when the entity is brought back after being culled.\n   * Override this to handle unculling differently.\n   */\n  public onUncull(): void {\n    this._isCulled = false;\n    // Default behavior: show the view\n    if (this.view) {\n      this.view.visible = true;\n    }\n  }\n\n  /**\n   * Prepares the entity for removal/recycling.\n   * Override this to handle custom cleanup.\n   */\n  public destroy(): void {\n    if (this._isDestroyed) return;\n\n    this._isDestroyed = true;\n    this._isCulled = false;\n\n    this.signalConnections.disconnectAll();\n\n    // Don't destroy the view - it will be reused\n    if (this.view) {\n      this.view.visible = false;\n      this.view.removeFromParent();\n    }\n\n    this.system.removeFollower(this);\n  }\n\n  /**\n   * Called when the entity is removed from the physics system.\n   * Override this to handle custom removal logic.\n   */\n  public onRemoved(): void {\n    if (!this._isDestroyed) {\n      this.destroy();\n    }\n  }\n\n  /**\n   * Sets a new view for the entity and updates its position.\n   *\n   * @param view - The new view to use\n   */\n  public setView(view: PhysicsEntityView): void {\n    this.view = view;\n    this.updateView();\n  }\n\n  /**\n   * Updates the view's position to match the entity's position.\n   */\n  public updateView(): void {\n    if (this.view && this.view.visible && this.view.position) {\n      this.view.position.set(this.x, this.y);\n    }\n  }\n\n  /**\n   * Gets the entity's bounding rectangle.\n   *\n   * @returns Rectangle representing the entity's bounds\n   */\n  public getBounds(): Rectangle {\n    return {\n      x: this.x,\n      y: this.y,\n      width: this.width,\n      height: this.height,\n    };\n  }\n\n  /**\n   * Sets the entity's position, resetting any movement remainders.\n   *\n   * @param x - New X position\n   * @param y - New Y position\n   */\n  public setPosition(x: number, y: number): void {\n    this._x = x;\n    this._y = y;\n    this._xRemainder = 0;\n    this._yRemainder = 0;\n    this.updateView();\n  }\n\n  /**\n   * Alias for setPosition.\n   *\n   * @param x - New X position\n   * @param y - New Y position\n   */\n  public moveTo(x: number, y: number): void {\n    this.setPosition(x, y);\n  }\n\n  /**\n   * Adds signal connections to the entity.\n   *\n   * @param args - Signal connections to add\n   */\n  public addSignalConnection(...args: SignalConnection[]) {\n    for (const connection of args) {\n      this.signalConnections.add(connection);\n    }\n  }\n\n  /**\n   * Alias for addSignalConnection.\n   *\n   * @param args - Signal connections to add\n   */\n  public connectSignal(...args: SignalConnection[]) {\n    for (const connection of args) {\n      this.signalConnections.add(connection);\n    }\n  }\n\n  /**\n   * Alias for addSignalConnection, specifically for action signals.\n   *\n   * @param args - Action signal connections to add\n   */\n  public connectAction(...args: SignalConnection[]) {\n    for (const connection of args) {\n      this.signalConnections.add(connection);\n    }\n  }\n\n  /**\n   * Checks if this entity can collide with another entity\n   */\n  public canCollideWithEntity(entity: Entity): boolean {\n    // Check if the entities can collide based on their collision layers and masks\n    // A collision occurs when (A.layer & B.mask) !== 0 && (B.layer & A.mask) !== 0\n    return (this.collisionLayer & entity.collisionMask) !== 0 && (entity.collisionLayer & this.collisionMask) !== 0;\n  }\n\n  /**\n   * Sets the collision layer for this entity\n   *\n   * @param layer The collision layer or layers (can be combined with bitwise OR)\n   */\n  public setCollisionLayer(layer: number): void {\n    this.collisionLayer = layer;\n  }\n\n  /**\n   * Adds the specified layers to this entity's collision layer\n   *\n   * @param layers The layers to add (can be combined with bitwise OR)\n   */\n  public addCollisionLayer(layers: number): void {\n    this.collisionLayer |= layers;\n  }\n\n  /**\n   * Removes the specified layers from this entity's collision layer\n   *\n   * @param layers The layers to remove (can be combined with bitwise OR)\n   */\n  public removeCollisionLayer(layers: number): void {\n    this.collisionLayer &= ~layers;\n  }\n\n  /**\n   * Sets the collision mask for this entity\n   *\n   * @param mask The collision mask (can be combined with bitwise OR)\n   */\n  public setCollisionMask(...mask: number[]): void {\n    this.collisionMask = this.physics.createCollisionMask(...mask);\n  }\n\n  /**\n   * Adds the specified layers to this entity's collision mask\n   *\n   * @param layers The layers to add to the mask (can be combined with bitwise OR)\n   */\n  public addCollisionMask(layers: number): void {\n    this.collisionMask |= layers;\n  }\n\n  /**\n   * Removes the specified layers from this entity's collision mask\n   *\n   * @param layers The layers to remove from the mask (can be combined with bitwise OR)\n   */\n  public removeCollisionMask(layers: number): void {\n    this.collisionMask &= ~layers;\n  }\n\n  /**\n   * Checks if this entity belongs to a specific collision layer\n   *\n   * @param layer The layer to check\n   * @returns True if the entity belongs to the specified layer\n   *\n   * @example\n   * ```typescript\n   * // Check if entity is on the PLAYER layer\n   * if (entity.hasCollisionLayer(CollisionLayer.PLAYER)) {\n   *   console.log('Entity is a player');\n   * }\n   *\n   * // Check if entity is on a custom layer\n   * const WATER_LAYER = CollisionLayers.createLayer(0);\n   * if (entity.hasCollisionLayer(WATER_LAYER)) {\n   *   console.log('Entity is water');\n   * }\n   * ```\n   */\n  public hasCollisionLayer(layer: number): boolean {\n    return (this.collisionLayer & layer) !== 0;\n  }\n\n  /**\n   * Checks if this entity can collide with a specific collision layer\n   *\n   * @param layer The layer to check\n   * @returns True if the entity can collide with the specified layer\n   *\n   * @example\n   * ```typescript\n   * // Check if entity can collide with players\n   * if (entity.canCollideWithLayer(CollisionLayer.PLAYER)) {\n   *   console.log('Entity can collide with players');\n   * }\n   *\n   * // Check if entity can collide with a custom layer\n   * const WATER_LAYER = CollisionLayers.createLayer(0);\n   * if (entity.canCollideWithLayer(WATER_LAYER)) {\n   *   console.log('Entity can collide with water');\n   * }\n   * ```\n   */\n  public canCollideWithLayer(layer: number): boolean {\n    return (this.collisionMask & layer) !== 0;\n  }\n}\n","import { Application } from 'dill-pixel';\nimport { Entity } from './Entity';\nimport { Solid } from './Solid';\nimport {\n  ActorCollisionResult,\n  CollisionResult,\n  EntityData,\n  PhysicsEntityConfig,\n  PhysicsEntityType,\n  Vector2,\n} from './types';\n\n/**\n * Dynamic physics entity that can move and collide with other entities.\n * Actors are typically used for players, enemies, projectiles, and other moving game objects.\n *\n * Features:\n * - Velocity-based movement with gravity\n * - Collision detection and response\n * - Solid surface detection (riding)\n * - Automatic culling when out of bounds\n * - Actor-to-actor collision detection\n *\n * @typeParam T - Application type, defaults to base Application\n *\n * @example\n * ```typescript\n * // Create a player actor\n * class Player extends Actor {\n *   constructor() {\n *     super({\n *       type: 'Player',\n *       position: [100, 100],\n *       size: [32, 64],\n *       view: playerSprite\n *     });\n *   }\n *\n *   // Handle collisions\n *   onCollide(result: CollisionResult) {\n *     if (result.solid.type === 'Spike') {\n *       this.die();\n *     }\n *   }\n *\n *   // Handle actor-to-actor collisions\n *   onActorCollide(result: ActorCollisionResult) {\n *     if (result.actor.type === 'Enemy') {\n *       this.takeDamage(10);\n *     }\n *   }\n *\n *   // Custom movement\n *   update(dt: number) {\n *     super.update(dt);\n *\n *     // Move left/right\n *     if (this.app.input.isKeyDown('ArrowLeft')) {\n *       this.velocity.x = -200;\n *     } else if (this.app.input.isKeyDown('ArrowRight')) {\n *       this.velocity.x = 200;\n *     }\n *\n *     // Jump when on ground\n *     if (this.app.input.isKeyPressed('Space') && this.isRidingSolid()) {\n *       this.velocity.y = -400;\n *     }\n *   }\n * }\n * ```\n */\nexport class Actor<T extends Application = Application, D extends EntityData = EntityData> extends Entity<T, D> {\n  public readonly entityType: PhysicsEntityType = 'Actor';\n\n  /** Current velocity in pixels per second */\n  public velocity: Vector2 = { x: 0, y: 0 };\n\n  /** Whether actor-to-actor collisions are disabled for this actor */\n  public disableActorCollisions: boolean = false;\n\n  /** Whether the actor should be removed when culled (out of bounds) */\n  public shouldRemoveOnCull: boolean = true;\n\n  /** List of current frame collisions */\n  public collisions: CollisionResult[] = [];\n\n  /** List of current frame actor-to-actor collisions */\n  public actorCollisions: ActorCollisionResult[] = [];\n\n  /** Cache for isRidingSolid check */\n  private _isRidingSolidCache: boolean | null = null;\n\n  /** Tracks which solid is currently carrying this actor in the current frame */\n  private _carriedBy: Solid | null = null;\n  private _carriedByOverlap: number = 0;\n\n  /** Tracks the grid cells this actor currently occupies */\n  private _currentGridCells: string[] = [];\n\n  /**\n   * Initialize or reinitialize the actor with new configuration.\n   *\n   * @param config - Configuration for the actor\n   */\n  public init(config: PhysicsEntityConfig<D>): void {\n    super.init(config);\n    // Reset velocity and carried state\n    this.velocity = { x: 0, y: 0 };\n    this._isRidingSolidCache = null;\n    this._carriedBy = null;\n    this._carriedByOverlap = 0;\n    this.actorCollisions = [];\n    this._currentGridCells = [];\n\n    if (config.disableActorCollisions !== undefined) {\n      this.disableActorCollisions = config.disableActorCollisions;\n    }\n\n    // Add actor to grid initially if actor collisions are enabled\n    if (this.system.enableActorCollisions && !this.disableActorCollisions) {\n      this.updateGridCells();\n    }\n  }\n\n  /**\n   * Called at the start of each update to prepare for collision checks.\n   */\n  public preUpdate(): void {\n    if (!this.active) return;\n\n    this.collisions = [];\n    this.actorCollisions = [];\n    // Reset the cache at the start of each update\n    this._isRidingSolidCache = null;\n    this._carriedBy = null;\n    this._carriedByOverlap = 0;\n  }\n\n  /**\n   * Updates the actor's position based on velocity and handles collisions.\n   *\n   * @param dt - Delta time in seconds\n   */\n  public update(dt: number): void {\n    if (!this.active) return;\n\n    // Ensure velocity is valid\n    if (!this.isRidingSolid()) {\n      this.velocity.y += this.system.gravity * dt;\n    }\n\n    // Clamp velocity\n    this.velocity.x = Math.min(Math.max(this.velocity.x, -this.system.maxVelocity), this.system.maxVelocity);\n    this.velocity.y = Math.min(Math.max(this.velocity.y, -this.system.maxVelocity), this.system.maxVelocity);\n\n    // Move horizontally\n    if (this.velocity.x !== 0) {\n      this.moveX(this.velocity.x * dt);\n    }\n\n    // Move vertically\n    if (this.velocity.y !== 0) {\n      this.moveY(this.velocity.y * dt);\n    }\n\n    if (this.system.enableActorCollisions) {\n      this.updateGridCells();\n    }\n\n    // Update view\n    this.updateView();\n  }\n\n  /**\n   * Called after update to handle post-movement effects.\n   */\n  public postUpdate(): void {\n    if (!this.active) return;\n\n    if (this.isRidingSolid()) {\n      this.velocity.y = 0;\n    }\n  }\n\n  /**\n   * Resets the actor to its initial state.\n   */\n  public reset(): void {\n    super.reset();\n\n    this._isRidingSolidCache = null;\n    this._carriedBy = null;\n    this._carriedByOverlap = 0;\n    this.velocity = { x: 0, y: 0 };\n\n    this.updatePosition();\n  }\n\n  /**\n   * Called when the actor is culled (goes out of bounds).\n   * Override this to handle culling differently.\n   */\n  public onCull(): void {\n    // Default behavior: destroy the view\n    this.view?.destroy();\n  }\n\n  /**\n   * Called when this actor collides with a solid.\n   * Override this method to implement custom collision response.\n   *\n   * @param result - Information about the collision\n   */\n  public onCollide(result: CollisionResult): void {\n    // Default implementation does nothing\n    // Override this in your actor subclass to handle collisions\n    void result;\n  }\n\n  /**\n   * Called when this actor collides with another actor.\n   * Override this method to implement custom actor-to-actor collision response.\n   *\n   * @param result - Information about the actor collision\n   */\n  public onActorCollide(result: ActorCollisionResult): void {\n    // Default implementation does nothing\n    // Override this in your actor subclass to handle actor-to-actor collisions\n    void result;\n  }\n\n  /**\n   * Checks if this actor is riding the given solid.\n   * An actor is riding if it's directly above the solid.\n   *\n   * @param solid - The solid to check against\n   * @returns True if riding the solid\n   */\n  public isRiding(solid: Solid): boolean {\n    // Skip if solid has no collisions\n    if (!solid.collideable) return false;\n\n    // Check collision layers and masks\n    // An actor can only ride a solid if their collision layers/masks allow interaction\n    if ((this.collisionLayer & solid.collisionMask) === 0 || (solid.collisionLayer & this.collisionMask) === 0) {\n      return false;\n    }\n\n    // If we're already being carried by a different solid this frame,\n    // we can't be riding this one\n    if (this._carriedBy && this._carriedBy !== solid) {\n      return false;\n    }\n\n    // Must be directly above the solid (within 1 pixel)\n    const actorBottom = this.y + this.height;\n    const onTop = Math.abs(actorBottom - solid.y) <= 1;\n\n    // Must be horizontally overlapping\n    const overlap = this.x + this.width > solid.x && this.x < solid.x + solid.width;\n    const overlapWidth = Math.min(this.x + this.width, solid.x + solid.width) - Math.max(this.x, solid.x);\n\n    const isRiding = onTop && overlap;\n\n    if (isRiding && overlapWidth > this._carriedByOverlap) {\n      this._carriedBy = solid;\n      this._carriedByOverlap = overlapWidth;\n    }\n    return isRiding;\n  }\n\n  /**\n   * Checks if this actor is riding any solid in the physics system.\n   * Uses caching to optimize multiple checks per frame.\n   *\n   * @returns True if riding any solid\n   */\n  public isRidingSolid(): boolean {\n    // Return cached value if available\n    if (this._isRidingSolidCache !== null) {\n      return this._isRidingSolidCache;\n    }\n\n    // Calculate and cache the result\n    const solids = this.getSolidsAt(this.x, this.y + 1);\n    this._isRidingSolidCache = solids.some((solid) => this.isRiding(solid));\n    return this._isRidingSolidCache;\n  }\n\n  /**\n   * Called when the actor is squeezed between solids.\n   * Override this to handle squishing differently.\n   */\n  public squish(result: CollisionResult): void {\n    void result;\n    // do something\n  }\n\n  /**\n   * Updates the actor's grid cells in the spatial partitioning system.\n   * This is called when the actor moves or when its size changes.\n   */\n  public updateGridCells(): void {\n    // Skip if actor collisions are disabled system-wide or for this actor specifically\n    if (this.disableActorCollisions) return;\n\n    this.system.updateActorInGrid(this);\n  }\n\n  /**\n   * Gets the current grid cells this actor occupies\n   */\n  public get currentGridCells(): string[] {\n    return this._currentGridCells;\n  }\n\n  /**\n   * Sets the current grid cells this actor occupies\n   */\n  public set currentGridCells(cells: string[]) {\n    this._currentGridCells = cells;\n  }\n\n  /**\n   * Moves the actor horizontally, checking for collisions with solids.\n   *\n   * @param amount - Distance to move in pixels\n   * @param collisionHandler - Optional callback for handling collisions\n   * @returns Array of collision results\n   */\n  public moveX(\n    amount: number,\n    collisionHandler?: (result: CollisionResult) => void,\n    pushingSolid?: Solid,\n  ): CollisionResult[] {\n    // Early return if inactive or zero movement\n    if (!this.active || amount === 0) return [];\n\n    this._xRemainder += amount;\n    const move = Math.round(this._xRemainder);\n\n    // Early return if rounded movement is zero\n    if (move === 0) return [];\n\n    const collisions: CollisionResult[] = [];\n\n    // Cache collision layer and mask for faster access\n    const actorLayer = this.collisionLayer;\n    const actorMask = this.collisionMask;\n\n    // Skip collision checks if no collision mask\n    if (actorMask === 0) {\n      // Just move without checking collisions\n      this._xRemainder -= move;\n      this._x += move;\n      this.updateView();\n\n      return [];\n    }\n\n    this._xRemainder -= move;\n    const sign = Math.sign(move);\n    let remaining = Math.abs(move);\n    const step = sign;\n\n    // If we're being pushed by a solid, temporarily make it non-collidable\n    if (pushingSolid) {\n      pushingSolid.collideable = false;\n    }\n\n    // Move one pixel at a time, checking for collisions\n    while (remaining > 0) {\n      const nextX = this._x + step;\n\n      // Get solids at the next position\n      const solids = this.getSolidsAt(nextX, this._y);\n      let collided = false;\n\n      // Check for collisions with each solid\n      for (const solid of solids) {\n        // Skip if solid can't collide\n        if (!solid.canCollide) continue;\n\n        // Skip if collision layers don't match\n        if ((actorLayer & solid.collisionMask) === 0 || (solid.collisionLayer & actorMask) === 0) {\n          continue;\n        }\n\n        // Calculate collision details\n        const result: CollisionResult = {\n          collided: true,\n          solid,\n          normal: { x: -sign, y: 0 },\n          penetration: step > 0 ? this.x + this.width - solid.x : solid.x + solid.width - this.x,\n          pushingSolid,\n        };\n\n        // Add to collisions array\n        collisions.push(result);\n\n        // Call collision handler if provided\n        if (collisionHandler) {\n          collisionHandler(result);\n        }\n\n        // Call actor's collision handler\n        this.onCollide(result);\n\n        collided = true;\n      }\n\n      if (collided) {\n        // Stop movement on collision\n        break;\n      } else {\n        // Move to next position\n        this._x = nextX;\n        remaining--;\n\n        // Update view every few pixels for better performance\n        // This reduces the number of view updates during movement\n        if (remaining % 4 === 0 || remaining === 0) {\n          this.updateView();\n        }\n      }\n    }\n\n    // Restore solid's collidable state\n    if (pushingSolid) {\n      pushingSolid.collideable = true;\n    }\n\n    // Final view update if we moved\n    if (Math.abs(move) - remaining > 0) {\n      this.updateView();\n    }\n\n    return collisions;\n  }\n\n  /**\n   * Moves the actor vertically, checking for collisions with solids.\n   *\n   * @param amount - Distance to move in pixels\n   * @param collisionHandler - Optional callback for handling collisions\n   * @returns Array of collision results\n   */\n  public moveY(\n    amount: number,\n    collisionHandler?: (result: CollisionResult) => void,\n    pushingSolid?: Solid,\n  ): CollisionResult[] {\n    // Early return if inactive or zero movement\n    if (!this.active || amount === 0) return [];\n\n    this._yRemainder += amount;\n    const move = Math.round(this._yRemainder);\n\n    // Early return if rounded movement is zero\n    if (move === 0) return [];\n\n    const collisions: CollisionResult[] = [];\n\n    // Cache collision layer and mask for faster access\n    const actorLayer = this.collisionLayer;\n    const actorMask = this.collisionMask;\n\n    // Skip collision checks if no collision mask\n    if (actorMask === 0) {\n      // Just move without checking collisions\n      this._yRemainder -= move;\n      this._y += move;\n      this.updateView();\n\n      return [];\n    }\n\n    this._yRemainder -= move;\n    const sign = Math.sign(move);\n    let remaining = Math.abs(move);\n    const step = sign;\n\n    // If we're being pushed by a solid, temporarily make it non-collidable\n    if (pushingSolid) {\n      pushingSolid.collideable = false;\n    }\n\n    // Move one pixel at a time, checking for collisions\n    while (remaining > 0) {\n      const nextY = this._y + step;\n\n      // Get solids at the next position\n      const solids = this.getSolidsAt(this._x, nextY);\n      let collided = false;\n\n      // Check for collisions with each solid\n      for (const solid of solids) {\n        // Skip if solid can't collide\n        if (!solid.canCollide) continue;\n\n        // Skip if collision layers don't match\n        if ((actorLayer & solid.collisionMask) === 0 || (solid.collisionLayer & actorMask) === 0) {\n          continue;\n        }\n\n        // Calculate collision details\n        const result: CollisionResult = {\n          collided: true,\n          solid,\n          normal: { x: 0, y: -sign },\n          penetration: step > 0 ? this.y + this.height - solid.y : solid.y + solid.height - this.y,\n          pushingSolid,\n        };\n\n        // Add to collisions array\n        collisions.push(result);\n\n        // Call collision handler if provided\n        if (collisionHandler) {\n          collisionHandler(result);\n        }\n\n        // Call actor's collision handler\n        this.onCollide(result);\n\n        collided = true;\n      }\n\n      if (collided) {\n        // Stop movement on collision\n        break;\n      } else {\n        // Move to next position\n        this._y = nextY;\n        remaining--;\n\n        // Update view every few pixels for better performance\n        // This reduces the number of view updates during movement\n        if (remaining % 4 === 0 || remaining === 0) {\n          this.updateView();\n        }\n      }\n    }\n\n    // Restore solid's collidable state\n    if (pushingSolid) {\n      pushingSolid.collideable = true;\n    }\n\n    // Final view update if we moved\n    if (Math.abs(move) - remaining > 0) {\n      this.updateView();\n\n      // Update grid cells if actor moved and actor collisions are enabled\n    }\n\n    return collisions;\n  }\n\n  /**\n   * Updates the actor's view position.\n   */\n  public updateView(): void {\n    if (this.view && this.view.visible) {\n      this.view.x = this._x;\n      this.view.y = this._y;\n    }\n  }\n\n  /**\n   * Gets all solids at the specified position that could collide with this actor.\n   *\n   * @param _x - X position to check\n   * @param _y - Y position to check\n   * @returns Array of solids at the position\n   */\n  protected getSolidsAt(_x: number, _y: number): Solid[] {\n    return this.system.getSolidsAt(_x, _y, this);\n  }\n\n  /**\n   * Checks if this actor is colliding with another actor.\n   * The collision will only occur if:\n   * 1. Both actors are active\n   * 2. Neither actor has disabled actor collisions\n   * 3. The collision layers and masks match:\n   *    - (this.collisionLayer & other.collisionMask) !== 0\n   *    - (other.collisionLayer & this.collisionMask) !== 0\n   *\n   * @param actor - The actor to check collision with\n   * @returns Collision result with information about the collision\n   */\n  public checkActorCollision(actor: Actor): ActorCollisionResult {\n    // Skip if either actor is not active\n    if (!this.active || !actor.active) {\n      return { collided: false, actor };\n    }\n\n    // Skip if either actor has disabled actor collisions\n    if (this.disableActorCollisions || actor.disableActorCollisions) {\n      return { collided: false, actor };\n    }\n\n    // Skip if the actors can't collide based on collision layers\n    if ((this.collisionLayer & actor.collisionMask) === 0 || (actor.collisionLayer & this.collisionMask) === 0) {\n      return { collided: false, actor };\n    }\n\n    // Simple AABB collision check\n    const thisLeft = this.x;\n    const thisRight = this.x + this.width;\n    const thisTop = this.y;\n    const thisBottom = this.y + this.height;\n\n    const otherLeft = actor.x;\n    const otherRight = actor.x + actor.width;\n    const otherTop = actor.y;\n    const otherBottom = actor.y + actor.height;\n\n    // Check if the bounding boxes overlap\n    if (thisRight > otherLeft && thisLeft < otherRight && thisBottom > otherTop && thisTop < otherBottom) {\n      // Calculate penetration and normal\n      const overlapX = Math.min(thisRight - otherLeft, otherRight - thisLeft);\n      const overlapY = Math.min(thisBottom - otherTop, otherBottom - thisTop);\n\n      let normal: Vector2;\n      let penetration: number;\n\n      // Determine the collision normal based on the smallest overlap\n      if (overlapX < overlapY) {\n        penetration = overlapX;\n        normal = {\n          x: thisLeft < otherLeft ? -1 : 1,\n          y: 0,\n        };\n      } else {\n        penetration = overlapY;\n        normal = {\n          x: 0,\n          y: thisTop < otherTop ? -1 : 1,\n        };\n      }\n\n      return {\n        collided: true,\n        actor,\n        normal,\n        penetration,\n      };\n    }\n\n    return { collided: false, actor };\n  }\n\n  /**\n   * Resolves a collision with another actor.\n   *\n   * @param result - The collision result to resolve\n   * @param shouldMove - Whether this actor should move to resolve the collision\n   * @returns The updated collision result\n   */\n  public resolveActorCollision(result: ActorCollisionResult): ActorCollisionResult {\n    if (!result.collided || !result.normal || !result.penetration) {\n      return result;\n    }\n\n    // Call the collision handler\n    this.onActorCollide(result);\n\n    // Example:\n    // Move this actor to resolve the collision\n    // this.x += result.normal.x * result.penetration * 0.5;\n    // this.y += result.normal.y * result.penetration * 0.5;\n\n    return result;\n  }\n\n  /**\n   * Sets the actor's size and updates grid cells if needed.\n   *\n   * @param width - New width in pixels\n   * @param height - New height in pixels\n   */\n  public setSize(width: number, height: number): void {\n    const sizeChanged = this.width !== width || this.height !== height;\n\n    this.width = width;\n    this.height = height;\n\n    // Update grid cells if size changed and actor collisions are enabled\n    if (sizeChanged && this.system.enableActorCollisions) {\n      this.updateGridCells();\n    }\n  }\n\n  /**\n   * Sets the actor's width and updates grid cells if needed.\n   *\n   * @param value - New width in pixels\n   */\n  public setWidth(value: number): void {\n    if (this.width !== value) {\n      this.width = value;\n\n      // Update grid cells if size changed and actor collisions are enabled\n      if (this.system.enableActorCollisions) {\n        this.updateGridCells();\n      }\n    }\n  }\n\n  /**\n   * Sets the actor's height and updates grid cells if needed.\n   *\n   * @param value - New height in pixels\n   */\n  public setHeight(value: number): void {\n    if (this.height !== value) {\n      this.height = value;\n\n      // Update grid cells if size changed and actor collisions are enabled\n      if (this.system.enableActorCollisions) {\n        this.updateGridCells();\n      }\n    }\n  }\n}\n","import { Application } from 'dill-pixel';\nimport { Actor } from './Actor';\nimport { Entity } from './Entity';\nimport { Sensor } from './Sensor';\nimport { Solid } from './Solid';\nimport { EntityData, PhysicsEntityType } from './types';\n\n/**\n * A container for managing collections of physics entities that move together.\n * Groups are useful for creating compound objects, moving platforms with riders,\n * and other scenarios where multiple entities need to move as one unit.\n *\n * Features:\n * - Maintains relative positioning of child entities\n * - Supports actors, solids, and sensors as children\n * - Preserves world positions when adding entities\n * - Provides type-safe access to children by entity type\n *\n * @typeParam T - Application type, defaults to base Application\n *\n * @example\n * ```typescript\n * // Create a moving platform with obstacles\n * const platformGroup = physics.createGroup({\n *   type: 'MovingPlatform',\n *   position: [100, 300]\n * });\n *\n * // Add platform and spikes\n * const platform = physics.createSolid({\n *   type: 'Platform',\n *   size: [200, 32]\n * });\n *\n * const spikes = physics.createSensor({\n *   type: 'Spikes',\n *   position: [0, -32],\n *   size: [200, 32]\n * });\n *\n * platformGroup.add(platform);\n * platformGroup.add(spikes);\n *\n * // Move the entire group\n * gsap.to(platformGroup, {\n *   x: 500,\n *   duration: 2,\n *   yoyo: true,\n *   repeat: -1\n * });\n * ```\n */\nexport class Group<T extends Application = Application, D extends EntityData = EntityData> extends Entity<T, D> {\n  public entityType: PhysicsEntityType = 'Group';\n  /** Map of child entities to their relative offsets from the group's position */\n  private childOffsets: Map<Entity, { x: number; y: number }> = new Map();\n  /** Whether this group's position is static (not affected by physics) */\n  public isStatic: boolean = true;\n\n  /**\n   * Gets the relative offset of a child entity from the group's position.\n   * @param entity - The child entity to get the offset for\n   * @returns The relative {x, y} offset of the entity\n   */\n  public getChildOffset(entity: Entity): { x: number; y: number } {\n    return this.childOffsets.get(entity) ?? { x: 0, y: 0 };\n  }\n\n  /**\n   * Sets the group's X position, affecting all child entities.\n   */\n  set x(value: number) {\n    this._x = value;\n  }\n\n  get x(): number {\n    return this._x;\n  }\n\n  /**\n   * Sets the group's Y position, affecting all child entities.\n   */\n  set y(value: number) {\n    this._y = value;\n  }\n\n  get y(): number {\n    return this._y;\n  }\n\n  /**\n   * Add an entity to this container\n   * @param entity The entity to add\n   * @param preserveWorldPosition If true, the entity's world position will be preserved\n   */\n  public add(entity: Entity, offset: { x: number; y: number } = { x: 0, y: 0 }): Group {\n    entity.setGroup(this, offset);\n    return this;\n  }\n\n  /**\n   * Remove an entity from this container\n   */\n  public remove(entity: Entity): Group {\n    entity.setGroup(null);\n    return this;\n  }\n\n  /**\n   * Move the container and all its children\n   */\n  public move(x: number, y: number): void {\n    // Update container position\n    this._x += x;\n    this._y += y;\n\n    this.updateView();\n  }\n\n  /**\n   * Force move the container and all its children to an absolute position\n   */\n  public moveTo(x: number, y: number): void {\n    const dx = x - this.x;\n    const dy = y - this.y;\n    this.move(dx, dy);\n  }\n\n  /**\n   * Get all children of a specific type\n   */\n  public getChildrenByType<E extends Entity>(type: PhysicsEntityType): E[] {\n    return this.system\n      .getEntitiesInGroup(this)\n      .filter((child): child is E => child.entityType === type || child.type === type);\n  }\n\n  /**\n   * Get all actors in this container\n   */\n  public getActors(): Actor[] {\n    return this.getChildrenByType('Actor');\n  }\n\n  /**\n   * Get all solids in this container\n   */\n  public getSolids(): Solid[] {\n    return this.getChildrenByType('Solid');\n  }\n\n  /**\n   * Get all sensors in this container\n   */\n  public getSensors(): Sensor[] {\n    return this.getChildrenByType('Sensor');\n  }\n\n  /**\n   * Get all groups in this container\n   */\n  public getGroups(): Group[] {\n    return this.getChildrenByType('Group');\n  }\n\n  public destroy(): void {\n    super.destroy();\n    this.system.removeGroup(this);\n  }\n}\n","import { Application } from 'dill-pixel';\nimport { Actor } from './Actor';\nimport { Entity } from './Entity';\nimport { Solid } from './Solid';\nimport { EntityData, PhysicsEntityConfig, PhysicsEntityType, SensorOverlap, Vector2 } from './types';\n\n/**\n * A trigger zone that can detect overlaps with actors.\n * Sensors are typically used for collectibles, triggers, and detection zones.\n *\n * Features:\n * - Overlap detection with specific actor types\n * - Optional gravity and movement\n * - Can be static or dynamic\n * - Callbacks for enter/exit events\n *\n * @typeParam T - Application type, defaults to base Application\n *\n * @example\n * ```typescript\n * // Create a coin pickup sensor\n * class Coin extends Sensor {\n *   constructor() {\n *     super({\n *       type: 'Coin',\n *       position: [100, 100],\n *       size: [32, 32],\n *       view: coinSprite\n *     });\n *\n *     // Only detect overlaps with player\n *     this.collidableTypes = ['Player'];\n *   }\n *\n *   // Called when a player enters the coin\n *   onActorEnter(actor: Actor) {\n *     if (actor.type === 'Player') {\n *       increaseScore(10);\n *       this.physics.removeSensor(this);\n *     }\n *   }\n * }\n *\n * // Create a damage zone\n * class Spikes extends Sensor {\n *   constructor() {\n *     super({\n *       type: 'Spikes',\n *       position: [300, 500],\n *       size: [100, 32],\n *       view: spikesSprite\n *     });\n *\n *     this.collidableTypes = ['Player', 'Enemy'];\n *     this.isStatic = true; // Don't move or fall\n *   }\n *\n *   onActorEnter(actor: Actor) {\n *     if (actor.type === 'Player') {\n *       actor.damage(10);\n *     }\n *   }\n * }\n * ```\n */\nexport class Sensor<T extends Application = Application, D extends EntityData = EntityData> extends Entity<T, D> {\n  public readonly entityType: PhysicsEntityType = 'Sensor';\n  /** Whether this sensor should be removed when culled */\n  public shouldRemoveOnCull = false;\n\n  /** List of actor types this sensor can detect */\n  public collidableTypes: string[] = [];\n\n  /** Current velocity in pixels per second */\n  public velocity: Vector2 = { x: 0, y: 0 };\n\n  /** Whether this sensor should stay in place */\n  public isStatic: boolean = false;\n\n  /** Set of actors currently overlapping this sensor */\n  private overlappingActors: Set<Actor> = new Set();\n\n  /** Cache for isRidingSolid check */\n  private _isRidingSolidCache: boolean | null = null;\n\n  private _currentSensorOverlaps = new Set<SensorOverlap>();\n  private _currentOverlaps = new Set<Actor>();\n\n  public setPosition(x: number, y: number): void {\n    if (this.isStatic) {\n      this._x = x;\n      this._y = y;\n      this._xRemainder = 0;\n      this._yRemainder = 0;\n      this.updateView();\n      this.checkActorOverlaps();\n    } else {\n      super.setPosition(x, y);\n    }\n  }\n\n  set x(value: number) {\n    super.x = value;\n    if (this.isStatic) {\n      this._xRemainder = 0;\n      this.updateView();\n      this.checkActorOverlaps();\n    }\n  }\n\n  get x(): number {\n    return super.x;\n  }\n\n  set y(value: number) {\n    super.y = value;\n    if (this.isStatic) {\n      this._yRemainder = 0;\n      this.updateView();\n      this.checkActorOverlaps();\n    }\n  }\n\n  get y(): number {\n    return super.y;\n  }\n\n  /**\n   * Initializes or reinitializes the sensor with new configuration.\n   *\n   * @param config - Configuration for the sensor\n   */\n  public init(config: PhysicsEntityConfig<D>): void {\n    super.init(config);\n    if (!this.velocity) {\n      this.velocity = { x: 0, y: 0 };\n    }\n    this.velocity.x = 0;\n    this.velocity.y = 0;\n    if (!this.overlappingActors) {\n      this.overlappingActors = new Set();\n    }\n    this._isRidingSolidCache = null;\n  }\n\n  /**\n   * Checks if this sensor is riding the given solid.\n   * Takes into account gravity direction for proper riding detection.\n   *\n   * @param solid - The solid to check against\n   * @returns True if riding the solid\n   */\n  public isRiding(solid: Solid): boolean {\n    const gravityDirection = Math.sign(this.system.gravity);\n    if (gravityDirection > 0) {\n      // Normal gravity - check if we're on top of the solid\n      const sensorBottom = this.y + this.height;\n      const onTop = Math.abs(sensorBottom - solid.y) <= 1;\n      const overlap = this.x + this.width > solid.x && this.x < solid.x + solid.width;\n      return onTop && overlap;\n    } else {\n      // Reversed gravity - check if we're on bottom of the solid\n      const sensorTop = this.y;\n      const onBottom = Math.abs(sensorTop - (solid.y + solid.height)) <= 1;\n      const overlap = this.x + this.width > solid.x && this.x < solid.x + solid.width;\n      return onBottom && overlap;\n    }\n  }\n\n  /**\n   * Checks if this sensor is riding any solid.\n   * Uses caching to optimize multiple checks per frame.\n   *\n   * @returns True if riding any solid\n   */\n  public isRidingSolid(): boolean {\n    // Return cached value if available\n    if (this._isRidingSolidCache !== null) {\n      return this._isRidingSolidCache;\n    }\n\n    // Calculate and cache the result\n    const solids = this.getSolidsAt(this.x, this.system.gravity > 0 ? this.y + 1 : this.y - 1);\n    this._isRidingSolidCache = solids.some((solid) => this.isRiding(solid));\n    return this._isRidingSolidCache;\n  }\n\n  /**\n   * Force moves the sensor to a new position, ignoring static state and collisions.\n   *\n   * @param x - New X position\n   * @param y - New Y position\n   */\n  public moveStatic(x: number, y: number): void {\n    this._x = x;\n    this._y = y;\n    this._xRemainder = 0;\n    this._yRemainder = 0;\n    this.updateView();\n    this.checkActorOverlaps();\n  }\n\n  /**\n   * Moves the sensor horizontally, passing through solids.\n   *\n   * @param amount - Distance to move in pixels\n   */\n  public moveX(amount: number): void {\n    if (this.isStatic) {\n      return;\n    }\n\n    this._xRemainder += amount;\n    const move = Math.round(this._xRemainder);\n\n    if (move !== 0) {\n      this._xRemainder -= move;\n      const sign = Math.sign(move);\n      let remaining = Math.abs(move);\n      while (remaining > 0) {\n        const step = sign;\n        const nextX = this.x + step;\n\n        // Check for collision with any solid\n        let collided = false;\n        for (const solid of this.getSolidsAt(nextX, this.y)) {\n          if (solid.canCollide) {\n            collided = true;\n            break;\n          }\n        }\n\n        if (!collided) {\n          this._x = nextX;\n          remaining--;\n          this.updateView();\n          this.checkActorOverlaps();\n        } else {\n          // Stop horizontal movement when hitting a solid\n          this.velocity.x = 0;\n          break;\n        }\n      }\n    }\n  }\n\n  /**\n   * Moves the sensor vertically, colliding with solids for riding.\n   *\n   * @param amount - Distance to move in pixels\n   */\n  public moveY(amount: number): void {\n    if (this.isStatic) {\n      return;\n    }\n\n    this._yRemainder += amount;\n    const move = Math.round(this._yRemainder);\n\n    if (move !== 0) {\n      this._yRemainder -= move;\n      const sign = Math.sign(move);\n\n      let remaining = Math.abs(move);\n      while (remaining > 0) {\n        const step = sign;\n        const nextY = this.y + step;\n\n        // Check for collision with any solid\n        let collided = false;\n        // Only check collisions when moving in the direction of gravity\n        if (Math.sign(this.system.gravity) === sign) {\n          for (const solid of this.getSolidsAt(this.x, nextY)) {\n            if (solid.canCollide) {\n              collided = true;\n              break;\n            }\n          }\n        }\n\n        if (!collided) {\n          this._y = nextY;\n          remaining--;\n          this.updateView();\n          this.checkActorOverlaps();\n        } else {\n          // Stop vertical movement when landing on a solid\n          this.velocity.y = 0;\n          break;\n        }\n      }\n    }\n  }\n\n  /**\n   * Updates the sensor's position and checks for overlapping actors.\n   *\n   * @param deltaTime - Delta time in seconds\n   */\n  public update(deltaTime: number): void {\n    // Reset the cache at the start of each update\n    this._isRidingSolidCache = null;\n\n    if (!this.active) {\n      return;\n    }\n\n    // Only apply gravity if not static and not riding a solid\n    if (!this.isStatic && !this.isRidingSolid()) {\n      this.velocity.y += this.system.gravity * deltaTime;\n    }\n\n    // Move\n    if (this.velocity.x !== 0) {\n      this.moveX(this.velocity.x * deltaTime);\n    }\n    if (this.velocity.y !== 0) {\n      this.moveY(this.velocity.y * deltaTime);\n    }\n  }\n\n  /**\n   * Checks for overlapping actors and triggers callbacks.\n   *\n   * @returns Set of current overlaps\n   */\n  public checkActorOverlaps(): Set<SensorOverlap> {\n    // Skip if sensor has no collision mask or is inactive\n    if (this.collisionMask === 0 || !this.active) {\n      return new Set();\n    }\n\n    this._currentSensorOverlaps.clear();\n    this._currentOverlaps.clear();\n\n    // Get all actors at current position - use spatial filtering first\n    // Only get actors that are potentially in the same grid cells\n\n    // Cache collision layer and mask for faster access\n    const sensorLayer = this.collisionLayer;\n    const sensorMask = this.collisionMask;\n\n    // Get actors by type, but only process those that could be nearby\n    const nearbyActors = this.system.getActorsByType(this.collidableTypes);\n\n    for (const actor of nearbyActors) {\n      // Skip inactive actors\n      if (!actor.active) continue;\n\n      // Fast collision layer check\n      if ((sensorLayer & actor.collisionMask) === 0 || (actor.collisionLayer & sensorMask) === 0) {\n        continue;\n      }\n\n      // Fast AABB check before detailed overlap\n      if (this.system.aabbOverlap(this, actor)) {\n        this._currentOverlaps.add(actor);\n        if (!this.overlappingActors.has(actor)) {\n          // New overlap\n          this._currentSensorOverlaps.add({\n            actor,\n            sensor: this,\n            type: `${actor.type}|${this.type}`,\n          });\n\n          this.onActorEnter(actor);\n        }\n      }\n    }\n\n    // Check for actors that are no longer overlapping\n    for (const actor of this.overlappingActors) {\n      if (!this._currentOverlaps.has(actor)) {\n        this.onActorExit(actor);\n      }\n    }\n\n    // Swap the sets to avoid unnecessary clear and forEach operations\n    const temp = this.overlappingActors;\n    this.overlappingActors = this._currentOverlaps;\n    this._currentOverlaps = temp;\n    this._currentOverlaps.clear();\n\n    return this._currentSensorOverlaps;\n  }\n\n  public reset(): void {\n    super.reset();\n    this._currentSensorOverlaps.clear();\n    this._currentOverlaps.clear();\n    this._isRidingSolidCache = null;\n    this.velocity = { x: 0, y: 0 };\n    this.overlappingActors = new Set();\n  }\n\n  /**\n   * Called when an actor starts overlapping with this sensor.\n   * Override this to handle overlap start events.\n   *\n   * @param actor - The actor that entered\n   */\n  public onActorEnter<A extends Actor = Actor>(actor: A): void {\n    // Override in subclass\n    void actor;\n  }\n\n  /**\n   * Called when an actor stops overlapping with this sensor.\n   * Override this to handle overlap end events.\n   *\n   * @param actor - The actor that exited\n   */\n  public onActorExit<A extends Actor = Actor>(actor: A): void {\n    // Override in subclass\n    void actor;\n  }\n\n  /**\n   * Gets all solids at the specified position.\n   *\n   * @param x - X position to check\n   * @param y - Y position to check\n   * @returns Array of solids at the position\n   */\n  protected getSolidsAt(x: number, y: number): Solid[] {\n    return this.system.getSolidsAt(x, y, this);\n  }\n}\n","import { Application } from 'dill-pixel';\nimport { Actor } from './Actor';\nimport { Entity } from './Entity';\nimport { Sensor } from './Sensor';\nimport { EntityData, PhysicsEntityConfig, PhysicsEntityType } from './types';\n\n/**\n * Static or moving solid object that other entities can collide with.\n * Solids are typically used for platforms, walls, and other obstacles.\n *\n * Features:\n * - Static collision boundaries\n * - Support for moving platforms\n * - Carries actors and sensors that are riding it\n * - Pushes overlapping entities out of the way\n *\n * @typeParam T - Application type, defaults to base Application\n *\n * @example\n * ```typescript\n * // Create a static platform\n * const platform = physics.createSolid({\n *   type: 'Platform',\n *   position: [0, 500],\n *   size: [800, 32],\n *   view: platformSprite\n * });\n *\n * // Create a moving platform\n * const movingPlatform = physics.createSolid({\n *   type: 'Platform',\n *   position: [100, 300],\n *   size: [200, 32],\n *   view: platformSprite\n * });\n *\n * // Move the platform back and forth\n * gsap.to(movingPlatform, {\n *   x: 500,\n *   duration: 2,\n *   yoyo: true,\n *   repeat: -1\n * });\n * ```\n */\nexport class Solid<T extends Application = Application, D extends EntityData = EntityData> extends Entity<T, D> {\n  public readonly entityType: PhysicsEntityType = 'Solid';\n  /** Whether this solid should be removed when culled (typically false) */\n  public shouldRemoveOnCull = false;\n\n  /** Whether this solid can be collided with */\n  private _canCollide: boolean = true;\n\n  get canCollide(): boolean {\n    return this._canCollide;\n  }\n\n  /** Whether this solid has collisions enabled */\n  public collideable: boolean = true;\n\n  /** Whether this solid is currently moving */\n  public moving: boolean = false;\n\n  private _nextX: number;\n  private _nextY: number;\n\n  public setPosition(x: number, y: number): void {\n    this.x = x;\n    this.y = y;\n  }\n\n  /**\n   * Sets the solid's X position.\n   * For moving solids, this queues the movement to be applied on next update.\n   */\n  public set x(value: number) {\n    this._nextX = Math.round(value);\n    this.moving = true;\n  }\n\n  public get x(): number {\n    return this._x;\n  }\n\n  /**\n   * Sets the solid's Y position.\n   * For moving solids, this queues the movement to be applied on next update.\n   */\n  public set y(value: number) {\n    this._nextY = Math.round(value);\n    this.moving = true;\n  }\n\n  public get y(): number {\n    return this._y;\n  }\n\n  /**\n   * Initializes or reinitializes the solid with new configuration.\n   *\n   * @param config - Configuration for the solid\n   */\n  public init(config: PhysicsEntityConfig<D>): void {\n    super.init(config);\n    if (config) {\n      this._nextX = this._x;\n      this._nextY = this._y;\n    }\n  }\n\n  /** Right edge X coordinate */\n  public get right(): number {\n    return this.x + this.width;\n  }\n\n  /** Left edge X coordinate */\n  public get left(): number {\n    return this.x;\n  }\n\n  /** Top edge Y coordinate */\n  public get top(): number {\n    return this.y;\n  }\n\n  /** Bottom edge Y coordinate */\n  public get bottom(): number {\n    return this.y + this.height;\n  }\n\n  /**\n   * Checks if this solid can collide with the given entity type.\n   * This method is kept for backward compatibility.\n   *\n   * @returns Always returns true as we're now using only collision layers/masks\n   */\n  canCollideWith(): boolean {\n    // First check if collisions are enabled at all\n    if (!this.collideable) {\n      return false;\n    }\n\n    // We're now using only collision layers/masks, so this method is simplified\n    return true;\n  }\n\n  /**\n   * Moves the solid by the specified amount, carrying any riding entities.\n   * Also pushes any overlapping entities out of the way.\n   *\n   * @param x - X distance to move\n   * @param y - Y distance to move\n   * @param actors - Set of actors to check for riding/pushing\n   * @param sensors - Set of sensors to check for riding/pushing\n   */\n  public move(\n    x: number,\n    y: number,\n    actors: Set<Actor> = this.system.actors,\n    sensors: Set<Sensor> = this.system.sensors,\n    force: boolean = false,\n  ): void {\n    if (!this.active) {\n      return;\n    }\n\n    // Calculate total movement including remainder\n    const totalX = x + (this._nextX - this._x);\n    const totalY = y + (this._nextY - this._y);\n\n    this._xRemainder += totalX;\n    this._yRemainder += totalY;\n\n    const moveX = Math.round(this._xRemainder);\n    const moveY = Math.round(this._yRemainder);\n\n    if (moveX !== 0 || moveY !== 0 || force) {\n      if (this.collideable) {\n        // Get all riding actors and sensors before movement\n        const ridingActors = new Set<Actor>();\n        const ridingSensors = new Set<Sensor>();\n\n        for (const actor of actors) {\n          // Check if actor can collide with this solid based on collision layers/masks\n          if (\n            (actor.collisionLayer & this.collisionMask) !== 0 &&\n            (this.collisionLayer & actor.collisionMask) !== 0 &&\n            actor.isRiding(this)\n          ) {\n            ridingActors.add(actor);\n          }\n        }\n\n        for (const sensor of sensors) {\n          // Check if sensor can collide with this solid based on collision layers/masks\n          if (\n            (sensor.collisionLayer & this.collisionMask) !== 0 &&\n            (this.collisionLayer & sensor.collisionMask) !== 0 &&\n            sensor.isRiding(this)\n          ) {\n            ridingSensors.add(sensor);\n          }\n        }\n\n        // Make this solid non-collidable so actors don't get stuck\n        this._canCollide = false;\n\n        if (moveX !== 0) {\n          this._xRemainder -= moveX;\n          this._x += moveX;\n\n          if (moveX > 0) {\n            // Moving right\n            for (const actor of actors) {\n              // Check if actor can collide with this solid based on collision layers/masks\n              if (\n                this.overlaps(actor) &&\n                (actor.collisionLayer & this.collisionMask) !== 0 &&\n                (this.collisionLayer & actor.collisionMask) !== 0\n              ) {\n                // Push right\n                actor.moveX(this.right - actor.x, actor.squish, this);\n              } else if (ridingActors.has(actor)) {\n                // Carry right\n                actor.moveX(moveX);\n              }\n            }\n            for (const sensor of sensors) {\n              // Check if sensor can collide with this solid based on collision layers/masks\n              if (\n                this.overlaps(sensor) &&\n                (sensor.collisionLayer & this.collisionMask) !== 0 &&\n                (this.collisionLayer & sensor.collisionMask) !== 0\n              ) {\n                // Push right\n                sensor.moveX(this.right - sensor.x);\n              } else if (ridingSensors.has(sensor)) {\n                // Carry right\n                sensor.moveX(moveX);\n              }\n            }\n          } else {\n            // Moving left\n            for (const actor of actors) {\n              // Check if actor can collide with this solid based on collision layers/masks\n              if (\n                this.overlaps(actor) &&\n                (actor.collisionLayer & this.collisionMask) !== 0 &&\n                (this.collisionLayer & actor.collisionMask) !== 0\n              ) {\n                // Push left\n                actor.moveX(this.left - (actor.x + actor.width), actor.squish, this);\n              } else if (ridingActors.has(actor)) {\n                // Carry left\n                actor.moveX(moveX);\n              }\n            }\n            for (const sensor of sensors) {\n              // Check if sensor can collide with this solid based on collision layers/masks\n              if (\n                this.overlaps(sensor) &&\n                (sensor.collisionLayer & this.collisionMask) !== 0 &&\n                (this.collisionLayer & sensor.collisionMask) !== 0\n              ) {\n                // Push left\n                sensor.moveX(this.left - (sensor.x + sensor.width));\n              } else if (ridingSensors.has(sensor)) {\n                // Carry left\n                sensor.moveX(moveX);\n              }\n            }\n          }\n        }\n\n        if (moveY !== 0) {\n          this._yRemainder -= moveY;\n          this._y += moveY;\n\n          if (moveY > 0) {\n            // Moving down\n            for (const actor of actors) {\n              // Check if actor can collide with this solid based on collision layers/masks\n              if (\n                this.overlaps(actor) &&\n                (actor.collisionLayer & this.collisionMask) !== 0 &&\n                (this.collisionLayer & actor.collisionMask) !== 0\n              ) {\n                // Push down\n                actor.moveY(this.bottom - actor.y, actor.squish, this);\n              } else if (ridingActors.has(actor)) {\n                // Carry down\n                actor.moveY(moveY);\n              }\n            }\n            for (const sensor of sensors) {\n              // Check if sensor can collide with this solid based on collision layers/masks\n              if (\n                this.overlaps(sensor) &&\n                (sensor.collisionLayer & this.collisionMask) !== 0 &&\n                (this.collisionLayer & sensor.collisionMask) !== 0\n              ) {\n                // Push down\n                sensor.moveY(this.bottom - sensor.y);\n              } else if (ridingSensors.has(sensor)) {\n                // Carry down\n                sensor.moveY(moveY);\n              }\n            }\n          } else {\n            // Moving up\n            for (const actor of actors) {\n              // Check if actor can collide with this solid based on collision layers/masks\n              if (\n                this.overlaps(actor) &&\n                (actor.collisionLayer & this.collisionMask) !== 0 &&\n                (this.collisionLayer & actor.collisionMask) !== 0\n              ) {\n                // Push up\n                actor.moveY(this.top - (actor.y + actor.height), actor.squish, this);\n              } else if (ridingActors.has(actor)) {\n                // Carry up\n                actor.moveY(moveY);\n              }\n            }\n            for (const sensor of sensors) {\n              // Check if sensor can collide with this solid based on collision layers/masks\n              if (\n                this.overlaps(sensor) &&\n                (sensor.collisionLayer & this.collisionMask) !== 0 &&\n                (this.collisionLayer & sensor.collisionMask) !== 0\n              ) {\n                // Push up\n                sensor.moveY(this.top - (sensor.y + sensor.height));\n              } else if (ridingSensors.has(sensor)) {\n                // Carry up\n                sensor.moveY(moveY);\n              }\n            }\n          }\n        }\n\n        // Re-enable collisions\n        this._canCollide = true;\n      } else {\n        // When collisions are disabled, just move without affecting other entities\n        if (moveX !== 0) {\n          this._xRemainder -= moveX;\n          this._x += moveX;\n        }\n        if (moveY !== 0) {\n          this._yRemainder -= moveY;\n          this._y += moveY;\n        }\n      }\n\n      // Update next positions to match current\n      this._nextX = this._x;\n      this._nextY = this._y;\n\n      // Update the view position\n      this.updateView();\n    }\n  }\n\n  /**\n   * Checks if this solid overlaps with the given entity.\n   *\n   * @param entity - Entity to check for overlap\n   * @returns True if overlapping\n   */\n  private overlaps(entity: Actor | Sensor): boolean {\n    // Check collision layers and masks\n    // A collision occurs when (A.layer & B.mask) !== 0 && (B.layer & A.mask) !== 0\n    if ((this.collisionLayer & entity.collisionMask) === 0 || (entity.collisionLayer & this.collisionMask) === 0) {\n      return false;\n    }\n\n    // Check for AABB overlap\n    return this.system.aabbOverlap(this, entity);\n  }\n}\n","import { Container, Graphics } from 'pixi.js';\nimport { Actor } from './Actor';\nimport CrunchPhysicsPlugin from './CrunchPhysicsPlugin';\nimport { Entity } from './Entity';\nimport { Group } from './Group';\nimport { AABBLike } from './interfaces';\nimport { Sensor } from './Sensor';\nimport { Solid } from './Solid';\nimport {\n  ActorCollision,\n  ActorCollisionResult,\n  Collision,\n  PhysicsEntityConfig,\n  PhysicsEntityView,\n  Rectangle,\n  SensorOverlap,\n} from './types';\n\n/**\n * Configuration options for the Crunch physics system.\n * These options control the core behavior of the physics simulation.\n *\n * @example\n * ```typescript\n * const options: PhysicsSystemOptions = {\n *   gridSize: 32,\n *   gravity: 980,\n *   maxVelocity: 1000,\n *   debug: true,\n *   boundary: { x: 0, y: 0, width: 800, height: 600 },\n *   culling: true,\n *   collisionResolver: (collisions) => {\n *     for (const collision of collisions) {\n *       handleCollision(collision);\n *     }\n *   }\n * };\n * ```\n */\nexport interface PhysicsSystemOptions {\n  /** Reference to the parent Crunch physics plugin */\n  plugin: CrunchPhysicsPlugin;\n  /** Size of each grid cell for spatial partitioning (in pixels) */\n  gridSize: number;\n  /** Gravity strength in pixels per second squared */\n  gravity: number;\n  /** Maximum velocity for any entity in pixels per second */\n  maxVelocity: number;\n  /** Whether to render debug visualizations */\n  debug?: boolean;\n  /** World boundary for culling entities */\n  boundary?: Rectangle;\n  /** Whether to automatically cull out-of-bounds entities */\n  culling?: boolean;\n  /** Custom handler for resolving collisions */\n  collisionResolver?: (collisions: Collision[]) => void;\n  /** Custom handler for resolving sensor overlaps */\n  overlapResolver?: (overlaps: SensorOverlap[]) => void;\n  /** Custom handler for resolving actor-to-actor collisions */\n  actorCollisionResolver?: (collisions: ActorCollision[]) => void;\n  /** Whether to enable actor-to-actor collisions */\n  enableActorCollisions?: boolean;\n  /** Default collision layer for new entities */\n  defaultCollisionLayer?: number;\n  /** Default collision mask for new entities */\n  defaultCollisionMask?: number;\n}\n\n/**\n * Represents a cell in the spatial partitioning grid that can contain both solids and actors\n */\ninterface GridCell {\n  solids: Set<Solid>;\n  actors: Set<Actor>;\n}\n\n/**\n * Core physics system that manages all physics entities and their interactions.\n * Handles spatial partitioning, collision detection, and entity lifecycle.\n *\n * Features:\n * - Grid-based spatial partitioning for efficient collision checks\n * - Entity management (actors, solids, sensors, groups)\n * - Collision and overlap detection\n * - Debug visualization\n * - Culling system for out-of-bounds entities\n *\n * @example\n * ```typescript\n * // Create the physics system\n * const system = new System({\n *   gridSize: 32,\n *   gravity: 980,\n *   maxVelocity: 1000\n * });\n *\n * // Add entities\n * const player = system.createActor({\n *   type: 'Player',\n *   position: [100, 100]\n * });\n *\n * const platform = system.createSolid({\n *   type: 'Platform',\n *   position: [0, 500],\n *   size: [800, 32]\n * });\n *\n * // Update physics (in game loop)\n * system.update(deltaTime);\n * ```\n */\nexport class System {\n  private readonly options: PhysicsSystemOptions;\n  // Public collections\n  public entities: Set<Entity> = new Set();\n  private _flaggedEntities: Set<Entity> = new Set();\n  // Type-based lookup maps\n  public actors: Set<Actor> = new Set();\n  public solids: Set<Solid> = new Set();\n  public sensors: Set<Sensor> = new Set();\n  public groups: Set<Group> = new Set();\n  // Type-based lookup maps\n  private actorsByType: Map<string, Set<Actor>> = new Map();\n  private solidsByType: Map<string, Set<Solid>> = new Map();\n  private sensorsByType: Map<string, Set<Sensor>> = new Map();\n  private groupsByType: Map<string, Set<Group>> = new Map();\n\n  // Followers tracking\n  private followers: Map<Entity, Set<Entity>> = new Map();\n\n  // groups tracking\n  private groupWithEntities: Map<Group, Set<Entity>> = new Map();\n\n  // Single grid for both solids and actors\n  private grid: Map<string, GridCell> = new Map();\n\n  // Collision tracking\n  private collisions: Collision[] = [];\n  private sensorOverlaps: SensorOverlap[] = [];\n  private actorCollisions: ActorCollision[] = [];\n\n  // Reusable data structures for actor collision detection\n  private _checkedPairs: Set<string> = new Set();\n\n  // Object pools for collision results to reduce GC pressure\n  private _collisionResultPool: ActorCollisionResult[] = [];\n  private _collisionResultPoolIndex: number = 0;\n  private _actorCollisionPool: ActorCollision[] = [];\n  private _actorCollisionPoolIndex: number = 0;\n\n  // Debugging\n  private _debugContainer: Container;\n  private _debugGfx: Graphics | null = null;\n  private _debug: boolean = false;\n\n  private _movedActors: Set<Actor> = new Set();\n  private _activeGridCells: Set<string> = new Set();\n  private _potentialCollisions: Map<string, [Actor, Actor]> = new Map();\n\n  set debug(value: boolean) {\n    this._debug = value;\n\n    if (this._debug) {\n      if (!this._debugContainer) {\n        this._debugContainer = this.options.plugin.container.addChild(new Container());\n      }\n      if (!this._debugGfx) {\n        this._debugGfx = new Graphics();\n      }\n      this._debugContainer.addChild(this._debugGfx);\n    } else {\n      this._debugGfx?.clear();\n      this._debugContainer?.removeChildren();\n    }\n  }\n\n  set gridSize(value: number) {\n    this.options.gridSize = value;\n    this.grid.clear();\n\n    for (const solid of this.solids) {\n      this.addSolidToGrid(solid);\n    }\n  }\n\n  set gravity(value: number) {\n    this.options.gravity = value;\n  }\n\n  get gravity(): number {\n    return this.options.gravity;\n  }\n\n  set maxVelocity(value: number) {\n    this.options.maxVelocity = value;\n  }\n\n  get maxVelocity(): number {\n    return this.options.maxVelocity;\n  }\n\n  set boundary(value: Rectangle) {\n    this.options.boundary = value;\n  }\n\n  get boundary(): Rectangle {\n    return this.options.boundary!;\n  }\n\n  get container(): Container {\n    return this.options.plugin.container;\n  }\n\n  public addView(view: PhysicsEntityView): void {\n    this.container.addChild(view);\n  }\n\n  constructor(options: PhysicsSystemOptions) {\n    this.options = {\n      ...options,\n      culling: options.culling ?? false,\n    };\n    this.debug = options.debug ?? false;\n    this._debugContainer = new Container();\n    options.plugin.container.addChild(this._debugContainer);\n  }\n\n  private _resetPositionFlags(entity: Entity): void {\n    entity.updatedFollowPosition = false;\n    entity.updatedGroupPosition = false;\n  }\n\n  public update(dt: number): void {\n    if (!this.options.plugin.enabled) return;\n\n    // Clear collections at the start with pre-allocated capacity\n    this.collisions.length = 0;\n    this.sensorOverlaps.length = 0;\n    this.actorCollisions.length = 0;\n\n    // Reset object pools\n    this.resetCollisionPools();\n\n    // Convert delta time to seconds (cache this calculation)\n    const deltaTime = dt / 60;\n\n    // Update containers first (groups)\n    for (const group of this.groups) {\n      group.update(deltaTime);\n    }\n\n    // Update solids with optimized grid management\n    this.updateSolids(deltaTime);\n\n    // Update sensors (before actors so they can detect entry/exit in the same frame)\n    for (const sensor of this.sensors) {\n      this.updateSensor(sensor, deltaTime);\n    }\n\n    // Clear actor collision lists before updating actors\n    for (const actor of this.actors) {\n      if (actor.actorCollisions.length > 0) {\n        actor.actorCollisions.length = 0;\n      }\n    }\n\n    // Update actors with potential batching\n    this.updateActors(deltaTime);\n\n    // Process position updates for followers and group entities\n    this.updateEntityPositions();\n\n    // Process overlaps, collisions, and culling in batch operations\n    this.processCollisionsAndOverlaps();\n\n    // Cull out-of-bounds entities if enabled and boundary is set\n    if (this.options.culling && this.options.boundary) {\n      this.cullOutOfBounds();\n    }\n\n    // Update debug rendering if enabled\n    if (this._debug) {\n      this.debugRender();\n    }\n  }\n\n  // New optimized methods to break up the update loop\n  private updateSolids(deltaTime: number): void {\n    // Fast path if no solids are moving\n    let hasMovingSolids = false;\n\n    for (const solid of this.solids) {\n      solid.preUpdate();\n      solid.update(deltaTime);\n      solid.postUpdate();\n\n      if (solid.moving) {\n        hasMovingSolids = true;\n      }\n    }\n\n    // Skip grid updates if nothing is moving\n    if (!hasMovingSolids) return;\n\n    // Batch grid updates for moving solids\n    const movedSolids = new Set<Solid>();\n\n    for (const solid of this.solids) {\n      if (solid.moving) {\n        // Remove from old grid cells\n        this.removeSolidFromGrid(solid);\n        // Move the solid (which will handle pushing/carrying actors and sensors)\n        solid.move(0, 0, this.actors, this.sensors, true);\n        // Track for batch grid update\n        movedSolids.add(solid);\n      }\n    }\n\n    // Batch add to grid after all movements are complete\n    for (const solid of movedSolids) {\n      this.addSolidToGrid(solid);\n    }\n  }\n\n  private updateActors(deltaTime: number): void {\n    // Skip if no active actors\n    if (this.actors.size === 0) return;\n\n    // Use for...of instead of forEach for better performance\n    for (const actor of this.actors) {\n      if (actor.active) {\n        actor.preUpdate();\n        actor.update(deltaTime);\n        actor.postUpdate();\n\n        // Collect collisions in batch\n        const actorCollisions = actor.collisions;\n        if (actorCollisions.length > 0) {\n          for (const result of actorCollisions) {\n            this.collisions.push({\n              type: `${actor.type}|${result.solid!.type}`,\n              entity1: actor,\n              entity2: result.solid!,\n              result: {\n                collided: result.collided,\n                normal: result.normal,\n                penetration: result.penetration,\n                solid: result.solid,\n              },\n            });\n          }\n        }\n      }\n    }\n  }\n\n  private updateEntityPositions(): void {\n    this._flaggedEntities.clear();\n\n    // Process followers first (most dependent)\n    for (const [entity, followers] of this.followers) {\n      const followX = entity.x;\n      const followY = entity.y;\n\n      for (const follower of followers) {\n        if (!follower.updatedFollowPosition) {\n          // Cache group checks to avoid repeated property access\n          const hasGroup = follower.group !== null;\n          const sameGroup = hasGroup && follower.group === entity.group;\n\n          if (sameGroup) {\n            // Get the entity's position relative to its group using the offset\n            const entityGroupOffset = entity.groupOffset;\n            const groupX = follower.group!.x;\n            const groupY = follower.group!.y;\n\n            // Set position using combined offsets relative to group\n            follower.setPosition(\n              groupX + entityGroupOffset.x + follower.followOffset.x,\n              groupY + entityGroupOffset.y + follower.followOffset.y,\n            );\n          } else if (hasGroup) {\n            // Different groups or followed entity not in a group\n            follower.setPosition(\n              followX + follower.followOffset.x + follower.group!.x + follower.groupOffset.x,\n              followY + follower.followOffset.y + follower.group!.y + follower.groupOffset.y,\n            );\n          } else {\n            // No group, just following\n            follower.setPosition(followX + follower.followOffset.x, followY + follower.followOffset.y);\n          }\n\n          follower.updatedFollowPosition = true;\n          this._flaggedEntities.add(follower);\n\n          if (hasGroup) {\n            follower.updatedGroupPosition = true;\n          }\n        }\n      }\n    }\n\n    // Process remaining group entities\n    for (const [group, groupEntities] of this.groupWithEntities) {\n      const groupX = group.x;\n      const groupY = group.y;\n\n      for (const entity of groupEntities) {\n        if (!entity.updatedGroupPosition && !entity.updatedFollowPosition) {\n          entity.setPosition(groupX + entity.groupOffset.x, groupY + entity.groupOffset.y);\n          entity.updatedGroupPosition = true;\n          this._flaggedEntities.add(entity);\n        }\n      }\n    }\n\n    // Reset flags in batch\n    this._flaggedEntities.forEach(this._resetPositionFlags);\n  }\n\n  private processCollisionsAndOverlaps(): void {\n    // Process overlaps if resolver is set and we have overlaps\n    if (this.options.overlapResolver && this.sensorOverlaps.length > 0) {\n      this.options.overlapResolver(this.sensorOverlaps);\n    }\n\n    // Check actor-to-actor collisions if enabled and we have multiple actors\n    if (this.options.enableActorCollisions && this.actors.size > 1) {\n      this.checkActorCollisions();\n    }\n\n    // Process collisions if resolver is set and we have collisions\n    if (this.collisions.length > 0 && this.options.collisionResolver) {\n      this.options.collisionResolver(this.collisions);\n    }\n\n    // Process actor-to-actor collisions if resolver is set and we have collisions\n    if (this.actorCollisions.length > 0 && this.options.actorCollisionResolver) {\n      this.options.actorCollisionResolver(this.actorCollisions);\n    }\n  }\n\n  // Optimize the cullOutOfBounds method\n  private cullOutOfBounds(): void {\n    // Skip if no boundary\n    if (!this.options.boundary) return;\n\n    const boundary = this.options.boundary;\n    // Pre-allocate removal arrays with reasonable capacity\n    const toRemoveActors: Actor[] = [];\n    const toRemoveSolids: Solid[] = [];\n    const toRemoveSensors: Sensor[] = [];\n    const toRemoveGroups: Group[] = [];\n\n    // Cache boundary values to avoid repeated property access\n    const boundX = boundary.x;\n    const boundY = boundary.y;\n    const boundRight = boundX + boundary.width;\n    const boundBottom = boundY + boundary.height;\n\n    // Check actors with optimized bounds check\n    for (const actor of this.actors) {\n      const actorRight = actor.x + actor.width;\n      const actorBottom = actor.y + actor.height;\n\n      const inBounds = !(\n        actor.x >= boundRight || // Completely to the right\n        actorRight <= boundX || // Completely to the left\n        actor.y >= boundBottom || // Completely below\n        actorBottom <= boundY // Completely above\n      );\n\n      if (!inBounds) {\n        if (!actor.isCulled) {\n          actor.onCull();\n        }\n        if (actor.shouldRemoveOnCull) {\n          toRemoveActors.push(actor);\n        }\n      } else if (actor.isCulled) {\n        // Uncull if back in bounds\n        actor.onUncull();\n      }\n    }\n\n    // Check solids with the same optimized bounds check\n    for (const solid of this.solids) {\n      const solidRight = solid.x + solid.width;\n      const solidBottom = solid.y + solid.height;\n\n      const inBounds = !(\n        solid.x >= boundRight ||\n        solidRight <= boundX ||\n        solid.y >= boundBottom ||\n        solidBottom <= boundY\n      );\n\n      if (!inBounds) {\n        if (!solid.isCulled) {\n          solid.onCull();\n        }\n        if (solid.shouldRemoveOnCull) {\n          toRemoveSolids.push(solid);\n        }\n      } else if (solid.isCulled) {\n        solid.onUncull();\n      }\n    }\n\n    // Check sensors with the same optimized bounds check\n    for (const sensor of this.sensors) {\n      const sensorRight = sensor.x + sensor.width;\n      const sensorBottom = sensor.y + sensor.height;\n\n      const inBounds = !(\n        sensor.x >= boundRight ||\n        sensorRight <= boundX ||\n        sensor.y >= boundBottom ||\n        sensorBottom <= boundY\n      );\n\n      if (!inBounds) {\n        if (!sensor.isCulled) {\n          sensor.onCull();\n        }\n        if (sensor.shouldRemoveOnCull) {\n          toRemoveSensors.push(sensor);\n        }\n      } else if (sensor.isCulled) {\n        sensor.onUncull();\n      }\n    }\n\n    // Check groups with the same optimized bounds check\n    for (const group of this.groups) {\n      const groupRight = group.x + group.width;\n      const groupBottom = group.y + group.height;\n\n      const inBounds = !(\n        group.x >= boundRight ||\n        groupRight <= boundX ||\n        group.y >= boundBottom ||\n        groupBottom <= boundY\n      );\n\n      if (!inBounds) {\n        if (!group.isCulled) {\n          group.onCull();\n        }\n        if (group.shouldRemoveOnCull) {\n          toRemoveGroups.push(group);\n        }\n      } else if (group.isCulled) {\n        group.onUncull();\n      }\n    }\n\n    // Batch remove culled entities if any exist\n    const actorCount = toRemoveActors.length;\n    const solidCount = toRemoveSolids.length;\n    const sensorCount = toRemoveSensors.length;\n    const groupCount = toRemoveGroups.length;\n\n    if (actorCount + solidCount + sensorCount + groupCount === 0) return;\n\n    // Use for loops instead of forEach for better performance\n    for (let i = 0; i < actorCount; i++) {\n      this.removeActor(toRemoveActors[i]);\n    }\n\n    for (let i = 0; i < solidCount; i++) {\n      this.removeSolid(toRemoveSolids[i]);\n    }\n\n    for (let i = 0; i < sensorCount; i++) {\n      this.removeSensor(toRemoveSensors[i]);\n    }\n\n    for (let i = 0; i < groupCount; i++) {\n      this.removeGroup(toRemoveGroups[i]);\n    }\n  }\n\n  private updateSensor(sensor: Sensor, dt: number): void {\n    sensor.preUpdate();\n    sensor.update(dt);\n    sensor.postUpdate();\n\n    const overlaps = sensor.checkActorOverlaps();\n    this.sensorOverlaps.push(...overlaps);\n  }\n\n  public createEntity(config: PhysicsEntityConfig): Actor | Solid | Sensor | Group {\n    if (config.type === 'actor') {\n      return this.createActor(config);\n    } else if (config.type === 'solid') {\n      return this.createSolid(config);\n    } else if (config.type === 'sensor') {\n      return this.createSensor(config);\n    } else if (config.type === 'group') {\n      return this.createGroup(config);\n    }\n    throw new Error(`Invalid entity type: ${config.type}`);\n  }\n\n  public addEntity(entity: Entity | Actor | Solid | Sensor | Group): Actor | Solid | Sensor | Group {\n    if (!entity || !entity.entityType) {\n      throw new Error('Entity is required');\n    }\n    if (entity.entityType === 'Actor') {\n      return this.addActor(entity as Actor);\n    } else if (entity.entityType === 'Solid') {\n      return this.addSolid(entity as Solid);\n    } else if (entity.entityType === 'Sensor') {\n      return this.addSensor(entity as Sensor);\n    } else if (entity.entityType === 'Group') {\n      return this.addGroup(entity as Group);\n    }\n    throw new Error(`Invalid entity type: ${entity!.entityType}`);\n  }\n\n  public removeEntity(entity: Entity | Actor | Solid | Sensor | Group): void {\n    if (entity.entityType === 'Actor') {\n      this.removeActor(entity as Actor);\n    } else if (entity.entityType === 'Solid') {\n      this.removeSolid(entity as Solid);\n    } else if (entity.entityType === 'Sensor') {\n      this.removeSensor(entity as Sensor);\n    } else if (entity.entityType === 'Group') {\n      this.removeGroup(entity as Group);\n    }\n  }\n\n  public createActor(config: PhysicsEntityConfig): Actor {\n    // Apply default collision settings if not specified in config\n    if (this.options.defaultCollisionLayer !== undefined && config.collisionLayer === undefined) {\n      config.collisionLayer = this.options.defaultCollisionLayer;\n    }\n    if (this.options.defaultCollisionMask !== undefined && config.collisionMask === undefined) {\n      config.collisionMask = this.options.defaultCollisionMask;\n    }\n\n    const actor = config.class ? (new config.class(config) as Actor) : new Actor(config);\n    return this.addActor(actor);\n  }\n\n  public addActor(actor: Actor): Actor {\n    this.entities.add(actor);\n    this.actors.add(actor);\n\n    // Add to type index\n    if (!this.actorsByType.has(actor.type)) {\n      this.actorsByType.set(actor.type, new Set());\n    }\n    this.actorsByType.get(actor.type)!.add(actor);\n\n    // Add to actor grid if actor collisions are enabled\n    if (this.options.enableActorCollisions) {\n      actor.updateGridCells();\n    }\n\n    return actor;\n  }\n\n  public createSensor(config: PhysicsEntityConfig): Sensor {\n    // Apply default collision settings if not specified in config\n    if (this.options.defaultCollisionLayer !== undefined && config.collisionLayer === undefined) {\n      config.collisionLayer = this.options.defaultCollisionLayer;\n    }\n    if (this.options.defaultCollisionMask !== undefined && config.collisionMask === undefined) {\n      config.collisionMask = this.options.defaultCollisionMask;\n    }\n\n    const sensor = config.class ? (new config.class(config) as Sensor) : new Sensor(config);\n    return this.addSensor(sensor);\n  }\n\n  public addSensor(sensor: Sensor): Sensor {\n    this.entities.add(sensor);\n    this.sensors.add(sensor);\n    // Add to type index\n    if (!this.sensorsByType.has(sensor.type)) {\n      this.sensorsByType.set(sensor.type, new Set());\n    }\n    this.sensorsByType.get(sensor.type)!.add(sensor);\n    return sensor;\n  }\n\n  public createSolid(config: PhysicsEntityConfig): Solid {\n    // Apply default collision settings if not specified in config\n    if (this.options.defaultCollisionLayer !== undefined && config.collisionLayer === undefined) {\n      config.collisionLayer = this.options.defaultCollisionLayer;\n    }\n    if (this.options.defaultCollisionMask !== undefined && config.collisionMask === undefined) {\n      config.collisionMask = this.options.defaultCollisionMask;\n    }\n\n    const solid = config.class ? (new config.class(config) as Solid) : new Solid(config);\n    return this.addSolid(solid);\n  }\n\n  public addSolid(solid: Solid): Solid {\n    this.entities.add(solid);\n    this.solids.add(solid);\n    // Add to type index\n    if (!this.solidsByType.has(solid.type)) {\n      this.solidsByType.set(solid.type, new Set());\n    }\n    this.solidsByType.get(solid.type)!.add(solid);\n    // Add to spatial grid\n    this.addSolidToGrid(solid);\n\n    return solid;\n  }\n\n  public removeActor(actor: Actor, destroyView: boolean = true): void {\n    this.entities.delete(actor);\n    this.actors.delete(actor);\n    // Remove from type index\n    const typeSet = this.actorsByType.get(actor.type);\n    if (typeSet) {\n      typeSet.delete(actor);\n      if (typeSet.size === 0) {\n        this.actorsByType.delete(actor.type);\n      }\n    }\n    actor.onRemoved();\n\n    if (destroyView) {\n      actor.view?.removeFromParent();\n    }\n\n    // Remove from actor grid\n    if (this.options.enableActorCollisions) {\n      this.removeActorFromGrid(actor);\n    }\n  }\n\n  public removeSolid(solid: Solid, destroyView: boolean = true): void {\n    this.entities.delete(solid);\n    this.solids.delete(solid);\n    // Remove from type index\n    const typeSet = this.solidsByType.get(solid.type);\n    if (typeSet) {\n      typeSet.delete(solid);\n      if (typeSet.size === 0) {\n        this.solidsByType.delete(solid.type);\n      }\n    }\n    this.removeSolidFromGrid(solid);\n\n    if (destroyView) {\n      solid.view?.removeFromParent();\n    }\n\n    solid.onRemoved();\n  }\n\n  public removeSensor(sensor: Sensor, destroyView: boolean = true): void {\n    this.entities.delete(sensor);\n    this.sensors.delete(sensor);\n    // Remove from type index\n    const typeSet = this.sensorsByType.get(sensor.type);\n    if (typeSet) {\n      typeSet.delete(sensor);\n      if (typeSet.size === 0) {\n        this.sensorsByType.delete(sensor.type);\n      }\n    }\n\n    sensor.onRemoved();\n\n    if (destroyView) {\n      sensor.view?.removeFromParent();\n    }\n  }\n\n  public moveSolid(solid: Solid, x: number, y: number): void {\n    // Remove from old grid cells\n    this.removeSolidFromGrid(solid);\n\n    // Move the solid (which will handle pushing/carrying actors)\n    solid.move(x, y, this.actors, this.sensors);\n\n    // Add to new grid cells\n    this.addSolidToGrid(solid);\n\n    solid.updateView();\n  }\n\n  public getSolidsAt(x: number, y: number, entity: Actor | Sensor): Solid[] {\n    // Early return if entity has no collision mask\n    if (entity.collisionMask === 0) return [];\n\n    const bounds = {\n      x,\n      y,\n      width: entity.width,\n      height: entity.height,\n    };\n\n    // Calculate movement direction from current position to check position\n    const dx = x - entity.x;\n    const dy = y - entity.y;\n\n    // Get the base cells that the bounds intersect\n    const cells = this.getCells(bounds);\n\n    // Add one extra cell in the direction of movement\n    if (dx !== 0) {\n      const extraX =\n        dx > 0 ? Math.ceil((x + bounds.width) / this.options.gridSize) : Math.floor(x / this.options.gridSize) - 1;\n\n      for (\n        let y = Math.floor(bounds.y / this.options.gridSize);\n        y < Math.ceil((bounds.y + bounds.height) / this.options.gridSize);\n        y++\n      ) {\n        cells.push(`${extraX},${y}`);\n      }\n    }\n\n    if (dy !== 0) {\n      const extraY =\n        dy > 0 ? Math.ceil((y + bounds.height) / this.options.gridSize) : Math.floor(y / this.options.gridSize) - 1;\n\n      for (\n        let x = Math.floor(bounds.x / this.options.gridSize);\n        x < Math.ceil((bounds.x + bounds.width) / this.options.gridSize);\n        x++\n      ) {\n        cells.push(`${x},${extraY}`);\n      }\n    }\n\n    // Create a Set of excluded types for O(1) lookups\n    // Pre-allocate result array with a reasonable size to avoid resizing\n    const result: Solid[] = [];\n    const seen = new Set<Solid>();\n\n    // Cache entity collision layer and mask for faster access\n    const entityLayer = entity.collisionLayer;\n    const entityMask = entity.collisionMask;\n\n    for (const cell of cells) {\n      const gridCell = this.grid.get(cell);\n      if (gridCell) {\n        for (const solid of gridCell.solids) {\n          // Skip already seen solids\n          if (seen.has(solid)) continue;\n\n          // Fast collision layer check\n          if ((entityLayer & solid.collisionMask) === 0 || (solid.collisionLayer & entityMask) === 0) continue;\n\n          seen.add(solid);\n\n          // Only add solids that actually overlap with the entity's bounds\n          if (\n            this.overlaps(bounds, {\n              x: solid.x,\n              y: solid.y,\n              width: solid.width,\n              height: solid.height,\n            })\n          ) {\n            result.push(solid);\n          }\n        }\n      }\n    }\n\n    return result;\n  }\n\n  public addFollower(entity: Entity, follower: Entity): void {\n    // Logger.log('adding follower', entity.type, follower.type);\n    if (!this.followers.has(entity)) {\n      this.followers.set(entity, new Set());\n    }\n    this.followers.get(entity)!.add(follower);\n  }\n\n  public removeFollower(entity: Entity): void {\n    // remove the entity from any set in the followers map\n    for (const followers of this.followers.values()) {\n      followers.delete(entity);\n    }\n  }\n\n  public getFollowersOf(entity: Entity): Entity[] {\n    return Array.from(this.followers.get(entity) || []);\n  }\n\n  public removeFollowersOf(entity: Entity): void {\n    const set = this.followers.get(entity);\n    if (set) {\n      set.forEach((follower) => {\n        follower.destroy();\n      });\n      set.clear();\n      this.followers.delete(entity);\n    }\n  }\n\n  public addToGroup(group: Group, entity: Entity): Entity {\n    if (!this.groupWithEntities.has(group)) {\n      this.groupWithEntities.set(group, new Set());\n    }\n    this.groupWithEntities.get(group)!.add(entity);\n    return entity;\n  }\n\n  public removeFromGroup(entity: Entity): Entity {\n    for (const group of this.groupWithEntities.values()) {\n      group.delete(entity);\n    }\n    return entity;\n  }\n\n  public getEntitiesInGroup(group: Group): Entity[] {\n    return Array.from(this.groupWithEntities.get(group) || []);\n  }\n\n  public removeEntitiesOfGroup(group: Group): Entity[] {\n    const entities = Array.from(this.groupWithEntities.get(group) || []) || [];\n    entities.forEach((entity) => {\n      entity.setGroup(null);\n    });\n    this.groupWithEntities.delete(group);\n    return entities;\n  }\n\n  private overlaps(a: Rectangle, b: Rectangle): boolean {\n    return a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y;\n  }\n\n  private getCells(bounds: Rectangle): string[] {\n    const cells: string[] = [];\n    const { gridSize } = this.options;\n\n    // Calculate the exact grid cells that the bounds intersect with\n    const startX = Math.floor(bounds.x / gridSize);\n    const startY = Math.floor(bounds.y / gridSize);\n    const endX = Math.ceil((bounds.x + bounds.width) / gridSize);\n    const endY = Math.ceil((bounds.y + bounds.height) / gridSize);\n\n    // Pre-allocate array with exact size to avoid resizing\n    cells.length = (endX - startX) * (endY - startY);\n\n    // Use a single index counter to avoid array.push() operations\n    let index = 0;\n\n    // Only check one additional cell in the direction of movement for actors\n    // For solids or static bounds, just use the exact cells\n    for (let x = startX; x < endX; x++) {\n      for (let y = startY; y < endY; y++) {\n        // Use template string only once per iteration\n        cells[index++] = `${x},${y}`;\n      }\n    }\n\n    return cells;\n  }\n\n  private addSolidToGrid(solid: Solid): void {\n    const bounds = {\n      x: solid.x,\n      y: solid.y,\n      width: solid.width,\n      height: solid.height,\n    };\n    const cells = this.getCells(bounds);\n\n    for (const cell of cells) {\n      if (!this.grid.has(cell)) {\n        this.grid.set(cell, { solids: new Set(), actors: new Set() });\n      }\n      this.grid.get(cell)!.solids.add(solid);\n    }\n  }\n\n  private removeSolidFromGrid(solid: Solid): void {\n    const bounds = {\n      x: solid.x,\n      y: solid.y,\n      width: solid.width,\n      height: solid.height,\n    };\n    const cells = this.getCells(bounds);\n\n    for (const cell of cells) {\n      const gridCell = this.grid.get(cell);\n      if (gridCell) {\n        gridCell.solids.delete(solid);\n        if (gridCell.solids.size === 0 && gridCell.actors.size === 0) {\n          this.grid.delete(cell);\n        }\n      }\n    }\n  }\n\n  public debugRender(): void {\n    if (!this._debugGfx) {\n      return;\n    }\n    const gfx = this._debugGfx!;\n    gfx.clear();\n\n    // Draw boundary if set\n    if (this.options.boundary) {\n      const b = this.options.boundary;\n      gfx.rect(b.x, b.y, b.width, b.height);\n      gfx.stroke({ color: 0xff0000, width: 2, alignment: 0.5 });\n    }\n\n    // Draw grid\n    for (const cell of this.grid.keys()) {\n      const [x, y] = cell.split(',').map(Number);\n      gfx.rect(x * this.options.gridSize, y * this.options.gridSize, this.options.gridSize, this.options.gridSize);\n    }\n    gfx.stroke({ color: 0x00ff00, width: 1, join: 'miter', cap: 'butt' });\n\n    // Draw solids\n    for (const solid of this.solids) {\n      gfx.rect(solid.x, solid.y, solid.width, solid.height);\n      gfx.stroke({ color: solid.debugColor ?? 0x00ff00, alpha: 1 });\n    }\n\n    // Draw actors\n    for (const actor of this.actors) {\n      gfx.rect(actor.x, actor.y, actor.width, actor.height);\n      gfx.stroke({ color: actor.debugColor ?? 0xff0000, alpha: 1 });\n    }\n\n    // Draw sensors\n    for (const sensor of this.sensors) {\n      gfx.rect(sensor.x, sensor.y, sensor.width, sensor.height);\n      gfx.stroke({ color: sensor.debugColor ?? 0xffff00, alpha: 1 });\n    }\n  }\n\n  /**\n   * Get all entities of a specific type\n   * @param type The type to look for\n   * @returns Array of entities matching the type\n   */\n  public getByType(type: string): (Actor | Solid)[] {\n    const actors = this.actorsByType.get(type) || new Set<Actor>();\n    const solids = this.solidsByType.get(type) || new Set<Solid>();\n    return [...actors, ...solids];\n  }\n\n  /**\n   * Get all actors of a specific type\n   * @param type The type to look for\n   * @returns Array of actors matching the type\n   */\n  public getActorsByType(type: string | string[]): Actor[] {\n    if (Array.isArray(type)) {\n      return type.flatMap((t) => Array.from(this.actorsByType.get(t) || new Set()));\n    }\n    return Array.from(this.actorsByType.get(type) || new Set());\n  }\n  /**\n   * Get all solids of a specific type\n   * @param type The type to look for\n   * @returns Array of solids matching the type\n   */\n  public getSolidsByType(type: string | string[]): Solid[] {\n    if (Array.isArray(type)) {\n      return type.flatMap((t) => Array.from(this.solidsByType.get(t) || new Set()));\n    }\n    return Array.from(this.solidsByType.get(type) || new Set());\n  }\n  /**\n   * Get all sensors of a specific type\n   * @param type The type to look for\n   * @returns Array of sensors matching the type\n   */\n  public getSensorsByType(type: string | string[]): Sensor[] {\n    if (Array.isArray(type)) {\n      return type.flatMap((t) => Array.from(this.sensorsByType.get(t) || new Set()));\n    }\n    return Array.from(this.sensorsByType.get(type) || new Set());\n  }\n\n  public clearGrid(): void {\n    this.grid.clear();\n  }\n\n  public clearAll(destroy: boolean = true) {\n    this.grid.clear();\n    this.entities.clear();\n\n    if (destroy) {\n      this.solids.forEach((solid) => {\n        solid.destroy();\n      });\n      this.actors.forEach((actor) => {\n        actor.destroy();\n      });\n      this.sensors.forEach((sensor) => sensor.destroy());\n    }\n\n    this.solids.clear();\n    this.actors.clear();\n    this.sensors.clear();\n\n    this.solidsByType.clear();\n    this.actorsByType.clear();\n    this.sensorsByType.clear();\n  }\n\n  public destroy(): void {\n    this.debug = false;\n    this.gravity = 0;\n    this.maxVelocity = 0;\n\n    this.clearAll();\n  }\n\n  /**\n   * Gets a collision result object from the pool or creates a new one if needed\n   */\n  private getCollisionResult(): ActorCollisionResult {\n    if (this._collisionResultPoolIndex < this._collisionResultPool.length) {\n      const result = this._collisionResultPool[this._collisionResultPoolIndex++];\n      result.collided = false;\n      result.actor = null as any;\n      result.normal = undefined;\n      result.penetration = 0;\n      return result;\n    }\n\n    // Create a new object and add it to the pool\n    const newResult: ActorCollisionResult = {\n      collided: false,\n      actor: null as any,\n      normal: undefined,\n      penetration: 0,\n    };\n\n    this._collisionResultPool.push(newResult);\n    this._collisionResultPoolIndex++;\n    return newResult;\n  }\n\n  /**\n   * Gets an actor collision object from the pool or creates a new one if needed\n   */\n  private getActorCollision(): ActorCollision {\n    if (this._actorCollisionPoolIndex < this._actorCollisionPool.length) {\n      return this._actorCollisionPool[this._actorCollisionPoolIndex++];\n    }\n\n    // Create a new object and add it to the pool\n    const newCollision: ActorCollision = {\n      type: 'unknown|unknown' as `${string}|${string}`,\n      actor1: null as any,\n      actor2: null as any,\n      result: null as any,\n    };\n\n    this._actorCollisionPool.push(newCollision);\n    this._actorCollisionPoolIndex++;\n    return newCollision;\n  }\n\n  /**\n   * Resets the collision result pools for the next frame\n   */\n  private resetCollisionPools(): void {\n    this._collisionResultPoolIndex = 0;\n    this._actorCollisionPoolIndex = 0;\n  }\n\n  /**\n   * Updates an actor's position in the grid.\n   * This is called when an actor moves or when its size changes.\n   *\n   * @param actor - The actor to update in the grid\n   */\n  public updateActorInGrid(actor: Actor): void {\n    // Skip if actor collisions are disabled\n    if (!this.options.enableActorCollisions) return;\n\n    // Skip if actor can't collide\n    if (!actor.active || actor.collisionLayer === 0 || actor.collisionMask === 0) {\n      // If actor has cells, remove it from them\n      if (actor.currentGridCells.length > 0) {\n        this.removeActorFromGrid(actor);\n      }\n      return;\n    }\n\n    // First remove from current cells\n    this.removeActorFromGrid(actor);\n\n    // Calculate new cells\n    const bounds = {\n      x: actor.x,\n      y: actor.y,\n      width: actor.width,\n      height: actor.height,\n    };\n\n    const cells = this.getCells(bounds);\n\n    // Store new cells in actor\n    actor.currentGridCells = cells;\n\n    // Add to new cells\n    for (const cell of cells) {\n      if (!this.grid.has(cell)) {\n        this.grid.set(cell, { solids: new Set(), actors: new Set() });\n      }\n\n      const gridCell = this.grid.get(cell)!;\n      gridCell.actors.add(actor);\n    }\n  }\n\n  /**\n   * Removes an actor from its current grid cells.\n   *\n   * @param actor - The actor to remove from the grid\n   */\n  public removeActorFromGrid(actor: Actor): void {\n    const currentCells = actor.currentGridCells;\n\n    for (const cell of currentCells) {\n      const gridCell = this.grid.get(cell);\n\n      if (gridCell) {\n        gridCell.actors.delete(actor);\n\n        // Remove the cell if it's empty\n        if (gridCell.actors.size === 0 && gridCell.solids.size === 0) {\n          this.grid.delete(cell);\n        }\n      }\n    }\n\n    // Clear the actor's cells\n    actor.currentGridCells = [];\n  }\n\n  /**\n   * Checks for collisions between all active actors.\n   * This is an O(n²) operation, so it can be expensive with many actors.\n   */\n  private checkActorCollisions(): void {\n    // Skip if there are no actors or only one actor\n    if (this.actors.size <= 1 || !this.options.enableActorCollisions) return;\n\n    // Clear the checked pairs set and potential collisions\n    this._checkedPairs.clear();\n    this._potentialCollisions.clear();\n    this._activeGridCells.clear();\n\n    // First pass: Mark cells with moving actors as active\n    for (const [cellKey, gridCell] of this.grid.entries()) {\n      for (const actor of gridCell.actors) {\n        if (!actor.active) continue;\n\n        // If actor is moving or recently moved\n        if (actor.velocity.x !== 0 || actor.velocity.y !== 0) {\n          this._activeGridCells.add(cellKey);\n          break;\n        }\n      }\n    }\n\n    // Second pass: Generate potential collision pairs from active cells\n    for (const cellKey of this._activeGridCells) {\n      const gridCell = this.grid.get(cellKey);\n      if (!gridCell || gridCell.actors.size <= 1) continue;\n\n      const actorsInCell = Array.from(gridCell.actors);\n      const cellActorCount = actorsInCell.length;\n\n      // Check each actor against others in the same cell\n      for (let i = 0; i < cellActorCount; i++) {\n        const actor1 = actorsInCell[i];\n        if (!actor1.active) continue;\n\n        for (let j = i + 1; j < cellActorCount; j++) {\n          const actor2 = actorsInCell[j];\n          if (!actor2.active) continue;\n\n          // Create a unique key for this actor pair\n          const pairKey = actor1.id < actor2.id ? `${actor1.id}|${actor2.id}` : `${actor2.id}|${actor1.id}`;\n\n          // Skip if we've already checked this pair\n          if (this._checkedPairs.has(pairKey)) continue;\n          this._checkedPairs.add(pairKey);\n\n          // Fast collision layer check\n          if (\n            (actor1.collisionLayer & actor2.collisionMask) === 0 &&\n            (actor2.collisionLayer & actor1.collisionMask) === 0\n          )\n            continue;\n\n          // Fast AABB check\n          if (\n            actor1.x < actor2.x + actor2.width &&\n            actor1.x + actor1.width > actor2.x &&\n            actor1.y < actor2.y + actor2.height &&\n            actor1.y + actor1.height > actor2.y\n          ) {\n            // Store potential collision pair\n            this._potentialCollisions.set(pairKey, [actor1, actor2]);\n          }\n        }\n      }\n    }\n\n    // Final pass: Detailed collision checks for potential pairs\n    for (const [actor1, actor2] of this._potentialCollisions.values()) {\n      // Check for collision\n      const collisionResult = actor1.checkActorCollision(actor2);\n\n      if (collisionResult.collided) {\n        // Add to actor1's collision list\n        actor1.actorCollisions.push(collisionResult);\n\n        // Get a mirrored result from the pool\n        const mirroredResult = this.getCollisionResult();\n        mirroredResult.collided = true;\n        mirroredResult.actor = actor1;\n\n        if (collisionResult.normal) {\n          if (!mirroredResult.normal) {\n            mirroredResult.normal = { x: 0, y: 0 };\n          }\n          mirroredResult.normal.x = -collisionResult.normal.x;\n          mirroredResult.normal.y = -collisionResult.normal.y;\n        } else {\n          mirroredResult.normal = undefined;\n        }\n\n        mirroredResult.penetration = collisionResult.penetration;\n\n        // Add to actor2's collision list\n        actor2.actorCollisions.push(mirroredResult);\n\n        // Get an actor collision from the pool and add to system's collision list\n        const actorCollision = this.getActorCollision();\n        actorCollision.type = `${actor1.type}|${actor2.type}`;\n        actorCollision.actor1 = actor1;\n        actorCollision.actor2 = actor2;\n        actorCollision.result = collisionResult;\n        this.actorCollisions[this._actorCollisionPoolIndex++] = actorCollision;\n\n        // Call collision handlers\n        actor1.onActorCollide(collisionResult);\n        actor2.onActorCollide(mirroredResult);\n\n        // Resolve the collision\n        actor1.resolveActorCollision(collisionResult);\n        actor2.resolveActorCollision(mirroredResult);\n      }\n    }\n\n    // Process collisions with resolver if provided\n    if (this._actorCollisionPoolIndex > 0 && this.options.actorCollisionResolver) {\n      this.options.actorCollisionResolver(this.actorCollisions.slice(0, this._actorCollisionPoolIndex));\n    }\n  }\n\n  setCollisionResolver(resolver: (collisions: Collision[]) => void): void {\n    this.options.collisionResolver = resolver;\n  }\n\n  /**\n   * Sets a custom resolver for actor-to-actor collisions.\n   *\n   * @param resolver - Function to handle actor-to-actor collisions\n   */\n  public setActorCollisionResolver(resolver: (collisions: ActorCollision[]) => void): void {\n    this.options.actorCollisionResolver = resolver;\n  }\n\n  /**\n   * Returns whether actor-to-actor collision detection is enabled.\n   *\n   * @returns True if actor collisions are enabled\n   */\n  public get enableActorCollisions(): boolean {\n    return !!this.options.enableActorCollisions;\n  }\n\n  /**\n   * Enables or disables actor-to-actor collision detection.\n   * When enabled, it initializes the grid for all existing actors.\n   *\n   * @param enabled - Whether to enable actor-to-actor collisions\n   */\n  public setActorCollisionsEnabled(enabled: boolean): void {\n    const wasEnabled = this.options.enableActorCollisions;\n    this.options.enableActorCollisions = enabled;\n\n    // If newly enabled, add all actors to the grid\n    if (enabled && !wasEnabled) {\n      for (const actor of this.actors) {\n        actor.updateGridCells();\n      }\n    } else if (!enabled && wasEnabled) {\n      // If newly disabled, clear the actor grid\n      this.grid.clear();\n\n      // Clear all actors' grid cells\n      for (const actor of this.actors) {\n        actor.currentGridCells = [];\n      }\n    }\n  }\n\n  public createGroup(config: PhysicsEntityConfig): Group {\n    // Apply default collision settings if not specified in config\n    if (this.options.defaultCollisionLayer !== undefined && config.collisionLayer === undefined) {\n      config.collisionLayer = this.options.defaultCollisionLayer;\n    }\n    if (this.options.defaultCollisionMask !== undefined && config.collisionMask === undefined) {\n      config.collisionMask = this.options.defaultCollisionMask;\n    }\n\n    const group = config.class ? (new config.class(config) as unknown as Group) : new Group(config);\n    return this.addGroup(group);\n  }\n\n  public addGroup(group: Group): Group {\n    this.entities.add(group);\n    this.groups.add(group);\n\n    // Add to type index\n    if (!this.groupsByType.has(group.type)) {\n      this.groupsByType.set(group.type, new Set());\n    }\n    this.groupsByType.get(group.type)!.add(group);\n\n    return group;\n  }\n\n  public removeGroup(group: Group, destroyView: boolean = true): void {\n    // Early return if group doesn't exist\n    if (!this.groups.has(group)) return;\n\n    this.entities.delete(group);\n    this.groups.delete(group);\n\n    // Remove from type index\n    const typeSet = this.groupsByType.get(group.type);\n    if (typeSet) {\n      typeSet.delete(group);\n      if (typeSet.size === 0) {\n        this.groupsByType.delete(group.type);\n      }\n    }\n\n    // Get all entities in the group before removing them\n    const groupEntities = this.groupWithEntities.get(group);\n    if (groupEntities && groupEntities.size > 0) {\n      // Create arrays for each entity type to batch process\n      const actors: Actor[] = [];\n      const solids: Solid[] = [];\n      const sensors: Sensor[] = [];\n\n      // Sort entities by type for batch processing\n      for (const entity of groupEntities) {\n        if (entity.entityType === 'Actor') {\n          actors.push(entity as Actor);\n        } else if (entity.entityType === 'Solid') {\n          solids.push(entity as Solid);\n        } else if (entity.entityType === 'Sensor') {\n          sensors.push(entity as Sensor);\n        }\n      }\n\n      // Batch remove entities by type\n      for (const actor of actors) {\n        this.removeActor(actor, destroyView);\n      }\n\n      for (const solid of solids) {\n        this.removeSolid(solid, destroyView);\n      }\n\n      for (const sensor of sensors) {\n        this.removeSensor(sensor, destroyView);\n      }\n    }\n\n    // Clean up the group's entry in the tracking map\n    this.groupWithEntities.delete(group);\n\n    group.onRemoved();\n  }\n\n  /**\n   * Get all groups of a specific type\n   * @param type The type to look for\n   * @returns Array of groups matching the type\n   */\n  public getGroupsByType(type: string | string[]): Group[] {\n    if (Array.isArray(type)) {\n      // Pre-calculate total size to avoid array resizing\n      let totalSize = 0;\n      for (const t of type) {\n        const set = this.groupsByType.get(t);\n        if (set) totalSize += set.size;\n      }\n\n      // Pre-allocate result array\n      const result = new Array<Group>(totalSize);\n      let index = 0;\n\n      // Fill array without using flatMap (more efficient)\n      for (const t of type) {\n        const set = this.groupsByType.get(t);\n        if (set) {\n          for (const group of set) {\n            result[index++] = group;\n          }\n        }\n      }\n\n      return result;\n    }\n\n    return Array.from(this.groupsByType.get(type) || new Set());\n  }\n\n  /**\n   * Checks if two AABB rectangles overlap.\n   *\n   * @param a - The first AABB rectangle\n   * @param b - The second AABB rectangle\n   * @returns True if the rectangles overlap, false otherwise\n   */\n  public aabbOverlap(a: AABBLike, b: AABBLike): boolean {\n    return a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y;\n  }\n}\n","import { Application, IApplication, IPlugin, isDev, Logger, Plugin, version } from 'dill-pixel';\nimport { Container as PIXIContainer, Rectangle, Ticker } from 'pixi.js';\nimport { Actor } from './Actor';\nimport { Group } from './Group';\nimport { AABBLike, CrunchPhysicsOptions } from './interfaces';\nimport { Sensor } from './Sensor';\nimport { Solid } from './Solid';\nimport { System } from './System';\nimport {\n  ActorCollision,\n  Collision,\n  CollisionLayer,\n  CollisionLayers,\n  PhysicsEntityConfig,\n  RegisteredCollisionLayer,\n  SensorOverlap,\n} from './types';\n\n/**\n * Interface for the Crunch physics plugin, providing a simple yet powerful 2D physics system\n * inspired by Towerfall's physics mechanics. Supports dynamic actors, static solids, and trigger sensors.\n *\n * @example\n * ```typescript\n * // Initialize the physics system\n * const physics = this.app.getPlugin('crunch-physics') as ICrunchPhysicsPlugin;\n *\n * const physics = await this.physics.initialize({\n *   gravity: 900,\n *   debug: true,\n *   gridSize: 32\n * });\n *\n * // Create a player character\n * const playerSprite = this.add.sprite({asset:Texture.WHITE, width: 32, height: 64});\n *\n * const player = physics.createActor({\n *   type: 'Player',\n *   position: [100, 100],\n *   size: [32, 64],\n *   view: playerSprite\n * });\n *\n * // Create a platform\n * const platformSprite = this.add.sprite({asset:Texture.WHITE, width: 800, height: 32, tint: 0x00FF00});\n * const platform = physics.createSolid({\n *   type: 'Platform',\n *   position: [0, 500],\n *   size: [800, 32],\n *   view: platformSprite\n * });\n *\n * // Create a coin pickup sensor\n * const coinSprite = this.add.sprite({asset:Texture.WHITE, width: 32, height: 32, tint: 0x00FF00});\n * const coin = physics.createSensor({\n *   type: 'Coin',\n *   position: [400, 400],\n *   size: [32, 32],\n *   view: coinSprite\n * });\n * ```\n */\nexport interface ICrunchPhysicsPlugin extends IPlugin<CrunchPhysicsOptions> {\n  system: System;\n  container: PIXIContainer;\n  enabled: boolean;\n\n  /**\n   * Initializes the physics system with the specified options.\n   */\n  initialize(options?: Partial<CrunchPhysicsOptions>, app?: IApplication): Promise<void>;\n\n  /**\n   * Sets a custom collision resolver function that will be called when collisions occur.\n   *\n   * @param resolver - Function to handle collisions\n   *\n   * @example\n   * ```typescript\n   * physics.setCollisionResolver((collisions) => {\n   *   collisions.forEach(collision => {\n   *     if (collision.actor.type === 'Player' && collision.solid.type === 'Spike') {\n   *       player.damage(10);\n   *     }\n   *   });\n   * });\n   * ```\n   */\n  setCollisionResolver(resolver: (collisions: Collision[]) => void): void;\n\n  /**\n   * Sets a custom resolver for actor-to-actor collisions.\n   *\n   * @param resolver - Function to handle actor-to-actor collisions\n   *\n   * @example\n   * ```typescript\n   * physics.setActorCollisionResolver((collisions) => {\n   *   collisions.forEach(collision => {\n   *     if (collision.actor1.type === 'Player' && collision.actor2.type === 'Enemy') {\n   *       player.takeDamage(10);\n   *     }\n   *   });\n   * });\n   * ```\n   */\n  setActorCollisionResolver(resolver: (collisions: ActorCollision[]) => void): void;\n\n  /**\n   * Enables or disables actor-to-actor collision detection.\n   *\n   * @param enabled - Whether to enable actor-to-actor collisions\n   *\n   * @example\n   * ```typescript\n   * // Enable actor-to-actor collisions\n   * physics.setActorCollisionsEnabled(true);\n   *\n   * // Disable actor-to-actor collisions for performance\n   * physics.setActorCollisionsEnabled(false);\n   * ```\n   */\n  setActorCollisionsEnabled(enabled: boolean): void;\n\n  /**\n   * Creates a generic physics entity based on the provided configuration.\n   * Use this when you need to create an entity without knowing its specific type at compile time.\n   *\n   * @param config - Configuration for the physics entity\n   * @returns The created physics entity\n   *\n   * @example\n   * ```typescript\n   * const entityConfig = {\n   *   type: 'Platform',\n   *   position: [100, 100],\n   *   size: [200, 32],\n   *   view: sprite\n   * };\n   * const entity = physics.createEntity(entityConfig);\n   * ```\n   */\n  createEntity(config: PhysicsEntityConfig): Actor | Solid | Sensor | Group;\n\n  /**\n   * Adds an existing physics entity to the system.\n   * Useful when you want to manage entity creation yourself.\n   *\n   * @param entity - The physics entity to add\n   * @returns The added entity\n   *\n   * @example\n   * ```typescript\n   * class CustomActor extends Actor {\n   *   constructor() {\n   *     super({ type: 'Custom', position: [0, 0], size: [32, 32] });\n   *   }\n   * }\n   *\n   * const customActor = new CustomActor();\n   * physics.addEntity(customActor);\n   * ```\n   */\n  addEntity(entity: Actor | Solid | Sensor | Group): Actor | Solid | Sensor | Group;\n\n  /**\n   * Creates a dynamic physics actor that can move and collide with other entities.\n   * Actors are typically used for players, enemies, or any moving game objects.\n   *\n   * @param config - Configuration for the actor\n   * @returns The created actor\n   *\n   * @example\n   * ```typescript\n   * // Create a player character\n   * const player = physics.createActor({\n   *   type: 'Player',\n   *   position: [100, 100],\n   *   size: [32, 64],\n   *   view: playerSprite\n   * });\n   *\n   * // Update player in game loop\n   * player.velocity.x = 300; // Move right\n   * player.velocity.y = -600; // Jump\n   * ```\n   */\n  createActor(config: PhysicsEntityConfig): Actor;\n\n  /**\n   * Creates a static solid object that other entities can collide with.\n   * Solids are typically used for platforms, walls, and other immovable objects.\n   *\n   * @param config - Configuration for the solid\n   * @returns The created solid\n   *\n   * @example\n   * ```typescript\n   * // Create a static platform\n   * const platform = physics.createSolid({\n   *   type: 'Platform',\n   *   position: [0, 500],\n   *   size: [800, 32],\n   *   view: platformSprite\n   * });\n   *\n   * // Create a moving platform\n   * const movingPlatform = physics.createSolid({\n   *   type: 'Platform',\n   *   position: [100, 300],\n   *   size: [200, 32],\n   *   view: platformSprite\n   * });\n   *\n   * // Update platform position\n   * gsap.to(movingPlatform, {\n   *   x: 500,\n   *   duration: 2,\n   *   yoyo: true,\n   *   repeat: -1\n   * });\n   * ```\n   */\n  createSolid(config: PhysicsEntityConfig): Solid;\n\n  /**\n   * Creates a sensor zone that can detect overlaps with other entities.\n   * Sensors are typically used for triggers, collectibles, or detection zones.\n   *\n   * @param config - Configuration for the sensor\n   * @returns The created sensor\n   *\n   * @example\n   * ```typescript\n   * // Create a coin pickup\n   * const coin = physics.createSensor({\n   *   type: 'Coin',\n   *   position: [400, 300],\n   *   size: [32, 32],\n   *   view: coinSprite\n   * });\n   *\n   * // Handle coin collection\n   * coin.onActorEnter = (actor) => {\n   *   if (actor.type === 'Player') {\n   *     increaseScore(10);\n   *     physics.removeSensor(coin);\n   *   }\n   * };\n   * ```\n   */\n  createSensor(config: PhysicsEntityConfig): Sensor;\n\n  createGroup(config: PhysicsEntityConfig): Group;\n\n  addActor(actor: Actor): Actor;\n\n  addSolid(solid: Solid): Solid;\n\n  addSensor(sensor: Sensor): Sensor;\n\n  addGroup(group: Group): Group;\n\n  /**\n   * Removes an actor from the physics system.\n   *\n   * @param actor - The actor to remove\n   *\n   * @example\n   * ```typescript\n   * // Remove player when they die\n   * function killPlayer(player: Actor) {\n   *   playDeathAnimation();\n   *   physics.removeActor(player);\n   * }\n   * ```\n   */\n  removeActor(actor: Actor): void;\n\n  /**\n   * Removes a solid from the physics system.\n   *\n   * @param solid - The solid to remove\n   *\n   * @example\n   * ```typescript\n   * // Remove a platform when it's destroyed\n   * function destroyPlatform(platform: Solid) {\n   *   playBreakAnimation();\n   *   physics.removeSolid(platform);\n   * }\n   * ```\n   */\n  removeSolid(solid: Solid): void;\n\n  /**\n   * Removes a sensor from the physics system.\n   *\n   * @param sensor - The sensor to remove\n   *\n   * @example\n   * ```typescript\n   * // Remove a coin when it's collected\n   * function collectCoin(coin: Sensor) {\n   *   playCollectSound();\n   *   physics.removeSensor(coin);\n   * }\n   * ```\n   */\n  removeSensor(sensor: Sensor): void;\n\n  /**\n   * Cleans up the physics system and removes all entities.\n   * Call this when transitioning between scenes or shutting down the game.\n   *\n   * @example\n   * ```typescript\n   * class GameScene extends Scene {\n   *   destroy() {\n   *     this.physics.destroy();\n   *     super.destroy();\n   *   }\n   * }\n   * ```\n   */\n  destroy(): void;\n\n  /**\n   * Creates a custom collision layer.\n   *\n   * @param index Index from 0-15 representing which user bit to use (gets shifted to bits 16-31)\n   * @returns A unique collision layer value\n   *\n   * @example\n   * ```typescript\n   * // Create custom collision layers\n   * const WATER_LAYER = physics.createCollisionLayer(0);\n   * const LAVA_LAYER = physics.createCollisionLayer(1);\n   *\n   * // Use in entity creation\n   * const waterEntity = physics.createActor({\n   *   type: 'Water',\n   *   position: [100, 400],\n   *   size: [800, 100],\n   *   collisionLayer: WATER_LAYER,\n   *   collisionMask: CollisionLayer.PLAYER | CollisionLayer.ENEMY\n   * });\n   * ```\n   */\n  createCollisionLayer(index: number): number;\n\n  /**\n   * Creates a collision mask from multiple layers.\n   *\n   * @param layers Array of collision layers to combine\n   * @returns A combined collision mask\n   *\n   * @example\n   * ```typescript\n   * // Create a mask that collides with players, enemies and projectiles\n   * const mask = physics.createCollisionMask([\n   *   CollisionLayer.PLAYER,\n   *   CollisionLayer.ENEMY,\n   *   CollisionLayer.PROJECTILE\n   * ]);\n   * ```\n   */\n  createCollisionMask(...layers: number[]): number;\n\n  /**\n   * Registers a named collision layer for better intellisense support.\n   *\n   * @param name Name of the collision layer (used for intellisense)\n   * @param indexOrDescription Index or description of the layer\n   * @param description Optional description of the layer\n   * @returns The numeric value of the registered collision layer\n   *\n   * @example\n   * ```typescript\n   * // Register named collision layers\n   * const WATER = physics.registerCollisionLayer('WATER', 0, 'Water surfaces');\n   * const LAVA = physics.registerCollisionLayer('LAVA', 1, 'Lava surfaces that damage players');\n   *\n   * // Use in entity creation\n   * const waterEntity = physics.createActor({\n   *   type: 'Water',\n   *   position: [100, 400],\n   *   size: [800, 100],\n   *   collisionLayer: WATER,\n   *   collisionMask: CollisionLayer.PLAYER | CollisionLayer.ENEMY\n   * });\n   * ```\n   */\n  registerCollisionLayer(name: string, indexOrDescription?: number | string, description?: string): number;\n\n  /**\n   * Gets a registered collision layer by name.\n   *\n   * @param name Name of the collision layer\n   * @returns The numeric value of the registered collision layer or undefined if not found\n   *\n   * @example\n   * ```typescript\n   * // Get a registered collision layer\n   * const waterLayer = physics.getCollisionLayer('WATER');\n   * if (waterLayer !== undefined) {\n   *   // Use the layer\n   *   entity.setCollisionLayer(waterLayer);\n   * }\n   * ```\n   */\n  getCollisionLayer(name: string): number | undefined;\n\n  /**\n   * Gets all registered collision layers.\n   *\n   * @returns Array of all registered collision layers\n   *\n   * @example\n   * ```typescript\n   * // Get all registered collision layers\n   * const layers = physics.getCollisionLayers();\n   * console.log(`Registered layers: ${layers.map(l => l.name).join(', ')}`);\n   * ```\n   */\n  getCollisionLayers(): RegisteredCollisionLayer[];\n\n  /**\n   * Removes a registered collision layer.\n   *\n   * @param name Name of the collision layer to remove\n   * @returns True if the layer was removed, false if it didn't exist\n   *\n   * @example\n   * ```typescript\n   * // Remove a registered collision layer\n   * physics.removeCollisionLayer('WATER');\n   * ```\n   */\n  removeCollisionLayer(name: string): boolean;\n\n  /**\n   * Clears all registered collision layers.\n   *\n   * @example\n   * ```typescript\n   * // Clear all registered collision layers\n   * physics.clearCollisionLayers();\n   * ```\n   */\n  clearCollisionLayers(): void;\n}\n\nconst defaultOptions: Partial<CrunchPhysicsOptions> = {\n  gridSize: 128,\n  gravity: 900,\n  maxVelocity: 400,\n  debug: false,\n  culling: true,\n  boundary: new Rectangle(0, 0, 800, 600),\n};\n\n/**\n * Implementation of the Crunch physics plugin.\n * See {@link ICrunchPhysicsPlugin} for detailed API documentation and examples.\n */\nexport default class CrunchPhysicsPlugin\n  extends Plugin<Application, CrunchPhysicsOptions>\n  implements ICrunchPhysicsPlugin\n{\n  public system: System;\n  public container: PIXIContainer;\n  public enabled = false;\n  private collisionResolver?: (collisions: Collision[]) => void;\n  private overlapResolver?: (overlaps: SensorOverlap[]) => void;\n  private actorCollisionResolver?: (collisions: ActorCollision[]) => void;\n\n  constructor() {\n    super('crunch-physics');\n  }\n\n  private hello() {\n    const hello = `%c Dill Pixel Crunch Physics Plugin v${version}`;\n    console.log(hello, 'background: rgba(31, 41, 55, 1);color: #74b64c');\n  }\n\n  public async initialize(options?: Partial<CrunchPhysicsOptions>, app?: IApplication): Promise<void> {\n    this.hello();\n    if (!options) {\n      return;\n    }\n\n    console.log({ options, app });\n    this._options = { ...defaultOptions, ...options } as CrunchPhysicsOptions;\n\n    this.enabled = true;\n    this.container = options.container || this.app.stage;\n\n    if (isDev) {\n      Logger.log(this._options);\n    }\n\n    // Create the physics system\n    const gridSize = options.gridSize ?? 32;\n    const gravity = options.gravity ?? 900;\n    const maxVelocity = options.maxVelocity ?? 400;\n    const debug = options.debug ?? false;\n    const enableActorCollisions = options.enableActorCollisions ?? false;\n\n    // Create the system with default collision layers set to NONE for better performance\n    this.system = new System({\n      gridSize,\n      gravity,\n      maxVelocity,\n      boundary: options.boundary,\n      culling: options.culling,\n      plugin: this,\n      collisionResolver: this.collisionResolver,\n      overlapResolver: this.overlapResolver,\n      actorCollisionResolver: this.actorCollisionResolver,\n      enableActorCollisions,\n      defaultCollisionLayer: CollisionLayer.NONE,\n      defaultCollisionMask: CollisionLayer.NONE,\n    });\n\n    if (debug) {\n      this.system.debug = true;\n    }\n\n    // Register update loop\n    this.app.ticker.add(this.update);\n  }\n\n  public setCollisionResolver(resolver: (collisions: Collision[]) => void): void {\n    this.collisionResolver = resolver;\n    this.system.setCollisionResolver(resolver);\n  }\n\n  public setActorCollisionResolver(resolver: (collisions: ActorCollision[]) => void): void {\n    this.actorCollisionResolver = resolver;\n    this.system.setActorCollisionResolver(resolver);\n  }\n\n  public setActorCollisionsEnabled(enabled: boolean): void {\n    this.system.setActorCollisionsEnabled(enabled);\n  }\n\n  public createEntity(config: PhysicsEntityConfig): Actor | Solid | Sensor | Group {\n    return this.system.createEntity(config);\n  }\n\n  public addEntity(entity: Actor | Solid | Sensor | Group): Actor | Solid | Sensor | Group {\n    return this.system.addEntity(entity);\n  }\n\n  public createActor(config: PhysicsEntityConfig): Actor {\n    return this.system.createActor(config);\n  }\n\n  public createSolid(config: PhysicsEntityConfig): Solid {\n    return this.system.createSolid(config);\n  }\n\n  public createSensor(config: PhysicsEntityConfig): Sensor {\n    return this.system.createSensor(config);\n  }\n\n  public createGroup(config: PhysicsEntityConfig): Group {\n    return this.system.createGroup(config);\n  }\n\n  public addActor(actor: Actor): Actor {\n    return this.system.addActor(actor);\n  }\n\n  public addSolid(solid: Solid): Solid {\n    return this.system.addSolid(solid);\n  }\n\n  public addSensor(sensor: Sensor): Sensor {\n    return this.system.addSensor(sensor);\n  }\n\n  public addGroup(group: Group): Group {\n    return this.system.addGroup(group);\n  }\n\n  public removeActor(actor: Actor): void {\n    this.system.removeActor(actor);\n  }\n\n  public removeSolid(solid: Solid): void {\n    this.system.removeSolid(solid);\n  }\n\n  public removeSensor(sensor: Sensor): void {\n    this.system.removeSensor(sensor);\n  }\n\n  public removeGroup(group: Group): void {\n    this.system.removeGroup(group);\n  }\n\n  public destroy(): void {\n    this.enabled = false;\n    this.app.ticker.remove(this.update);\n    if (this.system) {\n      this.system.destroy();\n      // @ts-expect-error system can't be null\n      this.system = null;\n    }\n    super.destroy();\n  }\n\n  private update(_ticker: Ticker) {\n    if (!this.enabled) return;\n    this.system.update(_ticker.deltaTime);\n  }\n\n  /**\n   * Creates a custom collision layer.\n   *\n   * @param index Index from 0-15 representing which user bit to use (gets shifted to bits 16-31)\n   * @returns A unique collision layer value\n   */\n  public createCollisionLayer(index: number): number {\n    return CollisionLayers.createLayer(index);\n  }\n\n  /**\n   * Creates a collision mask from multiple layers.\n   *\n   * @param layers Array of collision layers to combine\n   * @returns A combined collision mask\n   */\n  public createCollisionMask(...layers: number[]): number {\n    return CollisionLayers.createMask(layers);\n  }\n\n  /**\n   * Registers a named collision layer for better intellisense support.\n   *\n   * @param name Name of the collision layer (used for intellisense)\n   * @param indexOrDescription Index or description of the layer\n   * @param description Optional description of the layer\n   * @returns The numeric value of the registered collision layer\n   */\n  public registerCollisionLayer(name: string, indexOrDescription?: number | string, description?: string): number {\n    const registry = CollisionLayers.getRegistry();\n\n    // Handle overloaded method signature\n    if (typeof indexOrDescription === 'number') {\n      // First overload: registerCollisionLayer(name, index, description?)\n      const index = indexOrDescription;\n      const layer = registry.register(name, index, description);\n      return layer.value;\n    } else {\n      // Second overload: registerCollisionLayer(name, description?)\n      const layerDescription = indexOrDescription;\n      const nextIndex = registry.getNextAvailableIndex();\n\n      if (nextIndex === -1) {\n        throw new Error('No more collision layer indices available (maximum 16)');\n      }\n\n      const layer = registry.register(name, nextIndex, layerDescription);\n      return layer.value;\n    }\n  }\n\n  /**\n   * Gets a registered collision layer by name.\n   *\n   * @param name Name of the collision layer\n   * @returns The numeric value of the registered collision layer or undefined if not found\n   */\n  public getCollisionLayer(name: string): number | undefined {\n    const registry = CollisionLayers.getRegistry();\n    const layer = registry.get(name);\n    return layer?.value;\n  }\n\n  /**\n   * Gets all registered collision layers.\n   *\n   * @returns Array of all registered collision layers\n   */\n  public getCollisionLayers(): RegisteredCollisionLayer[] {\n    const registry = CollisionLayers.getRegistry();\n    return registry.getAll();\n  }\n\n  /**\n   * Removes a registered collision layer.\n   *\n   * @param name Name of the collision layer to remove\n   * @returns True if the layer was removed, false if it didn't exist\n   */\n  public removeCollisionLayer(name: string): boolean {\n    const registry = CollisionLayers.getRegistry();\n    return registry.remove(name);\n  }\n\n  /**\n   * Clears all registered collision layers.\n   */\n  public clearCollisionLayers(): void {\n    const registry = CollisionLayers.getRegistry();\n    registry.clear();\n  }\n\n  /**\n   * Checks if two AABB rectangles overlap.\n   *\n   * @param a - The first AABB rectangle\n   * @param b - The second AABB rectangle\n   * @returns True if the rectangles overlap, false otherwise\n   */\n  public aabbOverlap(a: AABBLike, b: AABBLike): boolean {\n    return this.system.aabbOverlap(a, b);\n  }\n}\n"],"names":["CollisionLayer","CollisionLayerRegistry","name","index","description","value","layer","i","CollisionLayers","layers","mask","resolveEntityPosition","config","x","y","resolvePointLike","resolveEntitySize","width","height","resolveSizeLike","Entity","bindAllMethods","SignalConnections","entityToFollow","offset","group","Application","dt","randomUUID","position","size","view","args","connection","entity","Actor","_a","result","solid","actorBottom","onTop","overlap","overlapWidth","isRiding","solids","cells","amount","collisionHandler","pushingSolid","move","collisions","actorLayer","actorMask","sign","remaining","step","nextX","collided","nextY","_x","_y","actor","thisLeft","thisRight","thisTop","thisBottom","otherLeft","otherRight","otherTop","otherBottom","overlapX","overlapY","normal","penetration","sizeChanged","Group","dx","dy","type","child","Sensor","sensorBottom","sensorTop","onBottom","deltaTime","sensorLayer","sensorMask","nearbyActors","temp","Solid","actors","sensors","force","totalX","totalY","moveX","moveY","ridingActors","ridingSensors","sensor","System","options","Container","Graphics","_b","hasMovingSolids","movedSolids","actorCollisions","followers","followX","followY","follower","hasGroup","entityGroupOffset","groupX","groupY","groupEntities","boundary","toRemoveActors","toRemoveSolids","toRemoveSensors","toRemoveGroups","boundX","boundY","boundRight","boundBottom","actorRight","solidRight","solidBottom","sensorRight","groupRight","groupBottom","actorCount","solidCount","sensorCount","groupCount","overlaps","destroyView","typeSet","bounds","extraX","extraY","seen","entityLayer","entityMask","cell","gridCell","set","entities","a","b","gridSize","startX","startY","endX","endY","gfx","t","destroy","newResult","newCollision","currentCells","cellKey","actorsInCell","cellActorCount","actor1","j","actor2","pairKey","collisionResult","mirroredResult","actorCollision","resolver","enabled","wasEnabled","totalSize","defaultOptions","Rectangle","CrunchPhysicsPlugin","Plugin","hello","version","app","isDev","Logger","gravity","maxVelocity","debug","enableActorCollisions","_ticker","indexOrDescription","registry","layerDescription","nextIndex"],"mappings":"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"}