{"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  type AppTypeOverrides,\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<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(): AppTypeOverrides['App'] {\n    return Application.getInstance();\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 { 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<D extends EntityData = EntityData> extends Entity<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 { 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<D extends EntityData = EntityData> extends Entity<D> {\n  protected _visible: boolean = true;\n\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  set visible(value: boolean) {\n    this.system.getEntitiesInGroup(this).forEach((entity) => {\n      entity.view.visible = value;\n    });\n  }\n\n  get visible(): boolean {\n    return this._visible;\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    this.system.removeGroup(this);\n    super.destroy();\n  }\n}\n","import { 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<D extends EntityData = EntityData> extends Entity<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 { 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<D extends EntityData = EntityData> extends Entity<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 { 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 extends Plugin<CrunchPhysicsOptions> implements ICrunchPhysicsPlugin {\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    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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"}