{"version":3,"sources":["../src/index.ts","../src/internal/duplicateModuleGuard.ts","../src/types.ts","../src/RendererPlugin.ts","../src/effects/filterBounds.ts","../src/effects/EffectStack.ts","../src/effects/defineEffect.ts","../src/effects/EffectsHost.ts","../src/drawing.ts","../src/DisplaySystem.ts","../src/SceneRenderTree.ts","../src/CameraComponent.ts","../src/CameraFollow.ts","../src/FollowTarget.ts","../src/internal/attribution.ts","../src/internal/validate.ts","../src/CameraShake.ts","../src/CameraZoom.ts","../src/CameraBoundsComponent.ts","../src/CameraModifiers.ts","../src/SortGroupComponent.ts","../src/VisualComponent.ts","../src/internal/renderFacet.ts","../src/VisualModifiers.ts","../src/masks/attachMask.ts","../src/cameraTransform.ts","../src/RenderFacetContributor.ts","../src/Fit.ts","../src/internal/textConstruction.ts","../src/internal/bitmapFontVariants.ts","../src/RenderTarget.ts","../src/SceneRenderTreeProvider.ts","../src/RenderLayer.ts","../src/effects/fanOutHandle.ts","../src/assets.ts","../src/spritesheet.ts","../src/internal/bitmapFontRegistry.ts","../src/SpriteComponent.ts","../src/GraphicsComponent.ts","../src/TextComponent.ts","../src/SplitTextComponent.ts","../src/internal/split-text-guard.ts","../src/gradient.ts","../src/AnimatedSpriteComponent.ts","../src/AnimationController.ts","../src/internal/animationSpeedGroup.ts","../src/LayeredAnimationController.ts","../src/CameraEntity.ts","../src/ScreenFollow.ts","../src/ySort.ts","../src/transitions/fade.ts","../src/transitions/helpers.ts","../src/transitions/flash.ts","../src/transitions/crossFade.ts","../src/transitions/iris.ts","../src/transitions/irisReveal.ts","../src/transitions/chessboard.ts","../src/transitions/slidePush.ts","../src/effects/rawFilter.ts","../src/masks/defineMask.ts","../src/masks/rectMask.ts","../src/masks/spriteMask.ts","../src/masks/graphicsMask.ts"],"sourcesContent":["// Side-effect import activates `declare module \"@yagejs/core\"` augmentation\n// that types Scene's `readonly layers` field.\nimport \"./scene-augmentation.js\";\nimport \"./internal/duplicateModuleGuard.js\";\n\n// Service keys & config\nexport { RendererKey } from \"./types.js\";\nexport type { RendererConfig, FitMode, RendererFitOptions } from \"./types.js\";\nexport type { CanvasRect, VirtualRect } from \"./Fit.js\";\nexport type {\n  Application,\n  ApplicationOptions,\n  BitmapFontHandle,\n  BitmapFontResource,\n  BlendMode,\n  ColorValue,\n  DestroyOptions,\n  DisplayAnimatedSprite,\n  DisplayBitmapText,\n  DisplayContainer,\n  DisplaySplitBitmapText,\n  DisplaySplitText,\n  DisplaySprite,\n  DisplayText,\n  Filter,\n  GradientFill,\n  GraphicsContext,\n  NineSliceSprite,\n  Particle,\n  ParticleContainer,\n  PointLike,\n  RendererAsset,\n  TextStyle,\n  TextureHandle,\n  TextureInput,\n  TextureRef,\n  TextureResource,\n  TextureSliceOptions,\n  WebFontHandle,\n  WebFontResource,\n} from \"./public-types.js\";\n\n// Plugin\nexport { RendererPlugin } from \"./RendererPlugin.js\";\nexport type { CreateTextureOptions } from \"./RendererPlugin.js\";\n\n// Inspector render facet — the renderer owns this type and publishes it into the\n// Inspector snapshot via RenderFacetContributor (which also augments core's\n// `InspectorFacets` so `snapshot.entities[].facets?.render` is typed). Exporting\n// the contributor activates that `declare module` augmentation for consumers.\nexport { RenderFacetContributor } from \"./RenderFacetContributor.js\";\nexport type {\n  RenderFacetSnapshot,\n  RenderInspectable,\n} from \"./internal/renderFacet.js\";\n\n// Components\nexport { VisualComponent } from \"./VisualComponent.js\";\nexport type {\n  VisualComponentOptions,\n  VisualInteractiveOptions,\n} from \"./VisualComponent.js\";\nexport { SpriteComponent } from \"./SpriteComponent.js\";\nexport type { SpriteComponentOptions } from \"./SpriteComponent.js\";\nexport { GraphicsComponent } from \"./GraphicsComponent.js\";\nexport type { GraphicsComponentOptions } from \"./GraphicsComponent.js\";\nexport { TextComponent } from \"./TextComponent.js\";\nexport type { TextComponentOptions } from \"./TextComponent.js\";\nexport { SplitTextComponent } from \"./SplitTextComponent.js\";\nexport type {\n  SplitTextComponentOptions,\n  SegmentAnchor,\n  SplitTextRenderFacet,\n  SplitTextRenderFacetExtras,\n} from \"./SplitTextComponent.js\";\nexport {\n  SortGroupComponent,\n  resolveRenderParent,\n} from \"./SortGroupComponent.js\";\nexport type {\n  SortGroupComponentOptions,\n  LayerRenderable,\n} from \"./SortGroupComponent.js\";\n/** @internal - shared Text/BitmapText constructor logic for @yagejs/ui, not for public consumption. */\nexport {\n  buildTextOptions,\n  resolveTextStyle,\n  getDefaultTextStyle,\n  setDefaultTextStyle,\n} from \"./internal/textConstruction.js\";\n/** @internal - shared empty-string guards for Pixi's split text, not for public consumption. */\nexport {\n  initialAutoSplit,\n  setSplitText,\n  splitIfNotEmpty,\n} from \"./internal/split-text-guard.js\";\nexport { linearGradient, radialGradient } from \"./gradient.js\";\nexport type {\n  GradientStop,\n  GradientSpace,\n  LinearGradientOptions,\n  RadialGradientOptions,\n} from \"./gradient.js\";\nexport { AnimatedSpriteComponent } from \"./AnimatedSpriteComponent.js\";\nexport type { AnimatedSpriteComponentOptions } from \"./AnimatedSpriteComponent.js\";\nexport { AnimationController } from \"./AnimationController.js\";\nexport type {\n  AnimationDef,\n  AnimationOneShotOptions,\n  AnimationTimingOptions,\n} from \"./AnimationController.js\";\nexport { LayeredAnimationController } from \"./LayeredAnimationController.js\";\nexport type { LayeredAnimationControllerOptions } from \"./LayeredAnimationController.js\";\n\n// Spritesheet utilities\nexport {\n  sliceSheet,\n  sliceGrid,\n  resolveFrames,\n  isSheetSource,\n  isAtlasSource,\n} from \"./spritesheet.js\";\nexport type {\n  FrameSource,\n  SheetFrameSource,\n  AtlasFrameSource,\n} from \"./spritesheet.js\";\n\n// Camera — entity-based system\nexport { CameraEntity } from \"./CameraEntity.js\";\nexport type { CameraEntityParams, CameraFitToRect } from \"./CameraEntity.js\";\nexport { CameraComponent } from \"./CameraComponent.js\";\nexport type {\n  CameraBounds,\n  CameraFollowOptions,\n  CameraShakeOptions,\n  CameraBinding,\n  CameraComponentOptions,\n} from \"./CameraComponent.js\";\nexport { CameraFollow } from \"./CameraFollow.js\";\nexport type { FollowTarget } from \"./FollowTarget.js\";\nexport { CameraShake } from \"./CameraShake.js\";\nexport { CameraBoundsComponent } from \"./CameraBoundsComponent.js\";\nexport { CameraZoom } from \"./CameraZoom.js\";\nexport { CameraModifierHost } from \"./CameraModifiers.js\";\nexport type {\n  CameraModifierHandle,\n  CameraModifierOptions,\n} from \"./CameraModifiers.js\";\nexport { ScreenFollow } from \"./ScreenFollow.js\";\nexport type {\n  ScreenFollowOptions,\n  ScreenFollowTarget,\n} from \"./ScreenFollow.js\";\n\n// Display\nexport { DisplaySystem } from \"./DisplaySystem.js\";\nexport { VisualModifierHost } from \"./VisualModifiers.js\";\nexport type {\n  VisualOpacityModifierHandle,\n  VisualTransformModifierHandle,\n  VisualTransformModifierOptions,\n  VisualVisibilityModifierHandle,\n} from \"./VisualModifiers.js\";\nexport { RenderLayer, RenderLayerManager } from \"./RenderLayer.js\";\nexport type { CreateLayerOptions } from \"./RenderLayer.js\";\n\n// Per-scene render tree\nexport type { LayerDef, LayerSortFn, LayerSpace } from \"./LayerDef.js\";\nexport { ySort, ySortBy } from \"./ySort.js\";\nexport type {\n  EnsureLayerOptions,\n  SceneRenderTree,\n  SceneRenderTreeProvider,\n} from \"./SceneRenderTree.js\";\nexport {\n  SceneRenderTreeKey,\n  SceneRenderTreeProviderKey,\n} from \"./SceneRenderTree.js\";\nexport { SceneRenderTreeProviderImpl } from \"./SceneRenderTreeProvider.js\";\n\n// Transitions\nexport * from \"./transitions/index.js\";\n\n// Asset factories\nexport {\n  bitmapFont,\n  createNineSlice,\n  installBitmapFont,\n  measureWrappedText,\n  registerTexture,\n  renderAsset,\n  resolveTextureInput,\n  sliceTextureFrames,\n  spritesheet,\n  texture,\n  uninstallBitmapFont,\n  unregisterTexture,\n  webFont,\n} from \"./assets.js\";\nexport type {\n  BitmapFontVariant,\n  InstallBitmapFontOptions,\n  MeasuredText,\n  MeasureTextOptions,\n  NineSliceOptions,\n  TextureOptions,\n  WebFontBakeOptions,\n  WebFontOptions,\n} from \"./assets.js\";\n\n// Effects\nexport type { EffectHandle } from \"./effects/EffectHandle.js\";\nexport type {\n  Effect,\n  EffectFactory,\n  EffectScope,\n  EffectTarget,\n} from \"./effects/Effect.js\";\nexport { EffectStack } from \"./effects/EffectStack.js\";\nexport { EffectsHost } from \"./effects/EffectsHost.js\";\nexport { defineEffect } from \"./effects/defineEffect.js\";\nexport type { EffectDefinition } from \"./effects/defineEffect.js\";\nexport { rawFilter } from \"./effects/rawFilter.js\";\nexport type { RawFilterOptions } from \"./effects/rawFilter.js\";\n\n// Offscreen buffers\nexport type {\n  RenderTargetHandle,\n  RenderTargetOptions,\n} from \"./RenderTarget.js\";\n\n// Masks\nexport type { MaskHandle } from \"./masks/MaskHandle.js\";\nexport type { Mask, MaskFactory } from \"./masks/MaskFactory.js\";\nexport { attachMask } from \"./masks/attachMask.js\";\nexport { defineMask } from \"./masks/defineMask.js\";\nexport type { MaskDefinition } from \"./masks/defineMask.js\";\nexport { rectMask } from \"./masks/rectMask.js\";\nexport type { RectMaskOptions } from \"./masks/rectMask.js\";\nexport { spriteMask } from \"./masks/spriteMask.js\";\nexport { graphicsMask } from \"./masks/graphicsMask.js\";\nexport { syncCameraTransform } from \"./cameraTransform.js\";\n","import { devWarn, isDev } from \"@yagejs/core\";\n\nconst RENDERER_INSTANCE_KEY = Symbol.for(\"@yagejs/renderer/module-instance\");\nconst MODULE_INSTANCE = {};\n\ninterface RendererInstanceRegistration {\n  instance: object;\n  warned: boolean;\n}\n\ntype RendererGlobal = typeof globalThis & {\n  [RENDERER_INSTANCE_KEY]?: RendererInstanceRegistration;\n};\n\n/**\n * Register one renderer module identity on a global-like object.\n *\n * Kept separate from the module side effect so the duplicate-copy behavior\n * can be tested without loading a second physical package tree.\n *\n * @internal\n */\nexport function registerRendererModule(\n  host: RendererGlobal,\n  instance: object,\n  warn: (message: string) => void,\n): void {\n  const registered = host[RENDERER_INSTANCE_KEY];\n  if (!registered) {\n    host[RENDERER_INSTANCE_KEY] = { instance, warned: false };\n    return;\n  }\n  if (registered.instance === instance || registered.warned) return;\n\n  registered.warned = true;\n  warn(\n    \"Multiple copies of @yagejs/renderer are loaded. This can break \" +\n      \"instance checks and surface unrelated Pixi errors. Deduplicate \" +\n      \"@yagejs/renderer and pixi.js, and make sure addons declare them as \" +\n      \"peer dependencies.\",\n  );\n}\n\nif (isDev()) {\n  registerRendererModule(\n    globalThis as RendererGlobal,\n    MODULE_INSTANCE,\n    devWarn,\n  );\n}\n","import { ServiceKey } from \"@yagejs/core\";\nimport type { RendererPlugin } from \"./RendererPlugin.js\";\nimport type { ApplicationOptions, TextStyle } from \"./public-types.js\";\n\n/** Service key for the RendererPlugin. */\nexport const RendererKey = new ServiceKey<RendererPlugin>(\"renderer\");\n\n/**\n * Scale mode for the responsive-fit API.\n * - `letterbox` — preserve aspect, fit inside the host, paint bars with the background color.\n * - `expand` — same scaling as `letterbox` (virtual rect always fully visible), but\n *   the bar region is left to the game to draw into. Pair with\n *   `RendererPlugin.extendedVirtualRects` / `visibleCanvasRect` to render fog, parallax,\n *   or a decorative backdrop into the extra space.\n * - `cover` — preserve aspect, fill the host; content overflows the virtual rect on the long axis.\n * - `stretch` — non-uniform scale; the virtual rect is squashed/pulled to match the host.\n */\nexport type FitMode = \"letterbox\" | \"expand\" | \"cover\" | \"stretch\";\n\n/** Options for the responsive-fit API. */\nexport interface RendererFitOptions {\n  /** Scale mode. See {@link FitMode}. */\n  mode: FitMode;\n  /**\n   * Element whose size the canvas matches. Defaults, in order:\n   * {@link RendererConfig.container}, then `canvas.parentElement`. If neither\n   * is available the controller falls back to a one-shot transform against\n   * the initial `width × height` and installs no `ResizeObserver` — pass\n   * `{ target: document.body }` explicitly for full-page fit.\n   */\n  target?: HTMLElement;\n}\n\n/** Configuration for the renderer plugin. */\nexport interface RendererConfig {\n  /** Initial canvas width in CSS pixels before responsive `fit` takes over. Backing-store size is `width × resolution`. */\n  width: number;\n  /** Initial canvas height in CSS pixels before responsive `fit` takes over. Backing-store size is `height × resolution`. */\n  height: number;\n  /** Game coordinate width (default: width). */\n  virtualWidth?: number;\n  /** Game coordinate height (default: height). */\n  virtualHeight?: number;\n  /** Background color as a hex number. */\n  backgroundColor?: number;\n  /** Existing canvas element to use. */\n  canvas?: HTMLCanvasElement;\n  /** Container element — canvas will be auto-appended here. */\n  container?: HTMLElement;\n  /** Device pixel ratio. Defaults to `window.devicePixelRatio` for crisp rendering on HiDPI displays. Set to 1 to disable. */\n  resolution?: number;\n  /** Additional PixiJS Application options. */\n  pixi?: Partial<ApplicationOptions>;\n  /**\n   * Responsive fit. Defaults to `{ mode: \"letterbox\" }` against the resolved\n   * target (see {@link RendererFitOptions.target}), so the canvas is\n   * responsive out of the box — override to change mode or pin to a specific\n   * host. See {@link RendererFitOptions}.\n   */\n  fit?: RendererFitOptions;\n  /**\n   * One-flag preset for pixel-art games. When `true`, the plugin:\n   *\n   * - Sets `TextureStyle.defaultOptions.scaleMode = \"nearest\"` so freshly\n   *   loaded textures sample without bilinear blur.\n   * - Enables `roundPixels` on the Pixi `Application` so subpixel transforms\n   *   don't smear sprite edges.\n   * - Applies `image-rendering: pixelated` (with `-webkit-optimize-contrast`\n   *   for Safari) to the canvas element so the browser scales the backing\n   *   store with nearest-neighbor, not bicubic.\n   *\n   * Composes with `pixi`: explicit `pixi.roundPixels: false` wins over the\n   * preset. Default: `false`.\n   */\n  pixelArtPreset?: boolean;\n  /**\n   * Engine-level default text style, applied as the base under every\n   * `TextComponent` / `UIText` `style` (per-text values win). Lets you set an\n   * app-wide font / fill without importing pixi to touch\n   * `TextStyle.defaultTextStyle`. `resolution` is not a style property — pass it\n   * per `TextComponent`. `@yagejs/ui`'s `UIPlugin({ defaultTextStyle })`\n   * can layer a UI-only override on top.\n   */\n  defaultTextStyle?: TextStyle;\n}\n","import {\n  AssetManagerKey,\n  EventBusKey,\n  GameLoopKey,\n  InspectorKey,\n  getPointerConsumePolicy,\n  makeGlobalScopedQueue,\n  ProcessSystemKey,\n  RendererAdapterKey,\n  SceneHookRegistryKey,\n  SceneManagerKey,\n  Vec2,\n} from \"@yagejs/core\";\nimport type {\n  EngineContext,\n  EngineEvents,\n  EventBus,\n  Plugin,\n  ProcessSystem,\n  RendererAdapter,\n  RendererPointerEventType,\n  RendererUIHit,\n  SystemScheduler,\n} from \"@yagejs/core\";\nimport {\n  Application as PixiApplication,\n  Assets,\n  Container,\n  Graphics,\n  Rectangle,\n  TextureStyle,\n  UPDATE_PRIORITY,\n} from \"pixi.js\";\nimport type { BitmapFont, Spritesheet, SCALE_MODE } from \"pixi.js\";\nimport { EffectsHost } from \"./effects/EffectsHost.js\";\nimport { synchronizeInteraction } from \"./drawing.js\";\nimport { DisplaySystem } from \"./DisplaySystem.js\";\nimport { RenderFacetContributor } from \"./RenderFacetContributor.js\";\nimport { FitController } from \"./Fit.js\";\nimport type { CanvasRect, VirtualRect } from \"./Fit.js\";\nimport type {\n  Application,\n  DisplayContainer,\n  GraphicsContext,\n  TextStyle,\n  TextureResource,\n} from \"./public-types.js\";\nimport {\n  getDefaultTextStyle,\n  setDefaultTextStyle,\n} from \"./internal/textConstruction.js\";\nimport { createRenderTarget } from \"./RenderTarget.js\";\nimport type {\n  RenderTargetHandle,\n  RenderTargetOptions,\n} from \"./RenderTarget.js\";\nimport { RendererKey } from \"./types.js\";\nimport type { RendererConfig, RendererFitOptions } from \"./types.js\";\nimport type { SceneRenderTreeProvider } from \"./SceneRenderTree.js\";\nimport {\n  SceneRenderTreeKey,\n  SceneRenderTreeProviderKey,\n} from \"./SceneRenderTree.js\";\nimport { SceneRenderTreeProviderImpl } from \"./SceneRenderTreeProvider.js\";\nimport { loadTexture, loadWebFont, unloadWebFont } from \"./assets.js\";\nimport { assertPositiveNumber } from \"./internal/validate.js\";\n\nimport \"./scene-augmentation.js\";\n\n/** The DOM event each synthetic pointer event is dispatched as. */\nconst DOM_POINTER_EVENTS: Record<RendererPointerEventType, string> = {\n  down: \"pointerdown\",\n  up: \"pointerup\",\n  move: \"pointermove\",\n};\n\n/**\n * `PointerEvent.buttons` bit per mouse button, as the DOM numbers them: left\n * is 1, right 2, middle 4.\n */\nconst POINTER_BUTTON_BITS = { 0: 1, 1: 4, 2: 2 } as const;\n\n/** Identifies the one pointer {@link RendererPlugin.dispatchPointerEvent} drives. */\nconst SYNTHETIC_POINTER_ID = 1;\n\n/** `PointerEvent.button` for an event that presses and releases nothing. */\nconst NO_BUTTON_CHANGE = -1;\n\n/** The region {@link RendererPlugin.createTexture} bakes, in pixels. */\nexport interface CreateTextureOptions {\n  /** Width of the baked texture, measured from x = 0. */\n  readonly width: number;\n  /** Height of the baked texture, measured from y = 0. */\n  readonly height: number;\n}\n\n/** RendererPlugin wraps PixiJS v8 behind the YAGE plugin interface. */\nexport class RendererPlugin implements Plugin, RendererAdapter {\n  readonly name = \"renderer\";\n  /** Whether automatic canvas and render-target drawing is enabled. */\n  drawingEnabled = true;\n  readonly version = \"4.0.0\";\n\n  // `_app`, `_provider`, `_fitController` use definite-assignment (`!`)\n  // since every method/getter past install assumes they're set; `onDestroy`\n  // explicitly guards each one so a partial-install failure (e.g. `await\n  // app.init()` rejecting before `_provider` is assigned) is safe to tear\n  // down. The `_installed` flag tracks how far install got.\n  private _app!: Application;\n  private readonly _config: RendererConfig;\n  private readonly _virtualWidth: number;\n  private readonly _virtualHeight: number;\n  private _provider!: SceneRenderTreeProviderImpl;\n  private _tickerFn: (() => void) | null = null;\n  private _unregisterHooks: (() => void) | null = null;\n  private _fitController!: FitController;\n  /**\n   * Holds the fit transform (scale + offset) and parents every per-scene\n   * render tree. Sits as the only \"world\" child of `app.stage`, which we\n   * deliberately keep at identity.\n   *\n   * Why this layer exists: in Pixi v8 the active render group's transform\n   * is fed to shaders via `uWorldTransformMatrix`, and `@pixi/tilemap`'s\n   * pipe composes `uProjection × uWorldTransformMatrix × tilemap.worldTransform`.\n   * `tilemap.worldTransform` is already cumulative from root, so any\n   * non-identity transform on the active render group (= `app.stage` by\n   * default) is applied twice — silently mis-scaling tile rendering vs.\n   * Sprites/Graphics, which the batched renderer pre-transforms on CPU.\n   * Pushing the fit onto a non-render-group child (this `_worldRoot`)\n   * keeps `uWorldTransformMatrix` identity at render time. Stage-direct\n   * children (transition overlays, screen-scope effects) keep their\n   * intended canvas-pixel coordinates.\n   */\n  private _worldRoot!: DisplayContainer;\n  private _installed = {\n    app: false,\n    fit: false,\n    provider: false,\n  };\n  private _processSystem: ProcessSystem | undefined;\n  /**\n   * `PointerEvent.buttons` the synthetic pointer currently holds. A move\n   * reports it, so a drag between a press and its release looks to a handler\n   * the way a person's drag does.\n   */\n  private _syntheticPointerButtons = 0;\n  /**\n   * Screen-scope effects host — `.fx.addEffect(...)` attaches a filter to\n   * `app.stage`, so it persists across scene transitions and composites\n   * everything the renderer draws (every scene, every layer). Common use:\n   * screen-wide post-process like vignette or chromatic aberration.\n   *\n   * The handle survives scene changes; remove it explicitly when no longer\n   * wanted, or it lives until the renderer plugin is destroyed.\n   */\n  fx!: EffectsHost;\n  private _unregisterFacetContributor: (() => void) | null = null;\n  private _context: EngineContext | null = null;\n  private _unregisterFullscreenListener: (() => void) | null = null;\n  private _unregisterOrientationListener: (() => void) | null = null;\n  private _unregisterSceneVisibility: (() => void) | null = null;\n  /**\n   * Snapshot of `TextureStyle.defaultOptions.scaleMode` captured before\n   * `pixelArtPreset` flips it to `\"nearest\"`. Pixi's defaults live on a\n   * module-level singleton, so without restoring this on destroy the\n   * mutation leaks across plugin lifecycles — any later `RendererPlugin`\n   * instance (or any texture loaded after teardown) silently inherits\n   * nearest sampling even with `pixelArtPreset: false`. The companion\n   * `_scaleModeCaptured` flag distinguishes \"preset was off, leave the\n   * field alone\" from \"preset was on and the original value was\n   * `undefined`\" — both round-trip back through the same restore.\n   */\n  private _originalScaleMode: SCALE_MODE | undefined = undefined;\n  private _scaleModeCaptured = false;\n  private _prevDefaultTextStyle: TextStyle | undefined = undefined;\n  private _defaultTextStyleCaptured = false;\n\n  constructor(config: RendererConfig) {\n    this._config = config;\n    this._virtualWidth = config.virtualWidth ?? config.width;\n    this._virtualHeight = config.virtualHeight ?? config.height;\n  }\n\n  async install(context: EngineContext): Promise<void> {\n    // 1. Apply pixel-art preset BEFORE Application.init so the texture-style\n    //    default propagates to every texture/spritesheet loaded by Assets\n    //    afterward. User-passed `pixi.roundPixels` still wins via the spread\n    //    order below. `TextureStyle.defaultOptions` is a module-level\n    //    singleton, so we capture the previous value and restore it in\n    //    `onDestroy` to keep the mutation scoped to this plugin's lifetime.\n    if (this._config.pixelArtPreset) {\n      this._originalScaleMode = TextureStyle.defaultOptions.scaleMode;\n      this._scaleModeCaptured = true;\n      TextureStyle.defaultOptions.scaleMode = \"nearest\";\n    }\n\n    // Apply the engine-level default text style. Captured/restored like the\n    // scale mode above so this module-singleton mutation stays scoped to the\n    // plugin's lifetime (test isolation, multiple engines in one process).\n    if (this._config.defaultTextStyle !== undefined) {\n      this._prevDefaultTextStyle = getDefaultTextStyle();\n      this._defaultTextStyleCaptured = true;\n      setDefaultTextStyle(this._config.defaultTextStyle);\n    }\n\n    // 2. Create & init PixiJS Application\n    this._app = new PixiApplication();\n    const resolution =\n      this._config.resolution ??\n      (typeof window !== \"undefined\" ? window.devicePixelRatio : 1);\n    await this._app.init({\n      width: this._config.width,\n      height: this._config.height,\n      backgroundColor: this._config.backgroundColor ?? 0x000000,\n      resolution,\n      autoDensity: true,\n      ...(this._config.pixelArtPreset ? { roundPixels: true } : undefined),\n      ...this._config.pixi,\n      ...(this._config.canvas ? { canvas: this._config.canvas } : undefined),\n    });\n    this._installed.app = true;\n    const draw = this._app.render;\n    this._app.ticker.remove(draw, this._app);\n    this._app.render = () => {\n      if (this.drawingEnabled) draw.call(this._app);\n      else synchronizeInteraction(this._app.stage);\n    };\n    this._app.ticker.add(this._app.render, this._app, UPDATE_PRIORITY.LOW);\n\n    // 2b. Tell the browser to scale the canvas backing store with\n    //     nearest-neighbor when it's CSS-scaled past 1:1 (e.g. on a HiDPI\n    //     monitor, under fit, or when the host CSS-sizes the canvas larger\n    //     than its backing store). Without this the browser bicubic-blurs\n    //     the pixel art back into mush. We write both declarations via\n    //     `cssText` because the CSS cascade only keeps the LAST\n    //     `image-rendering` value the browser understands — Safari falls\n    //     through `pixelated` (which it ignores) to the older\n    //     `-webkit-optimize-contrast`; everywhere else `pixelated` wins.\n    //     Guarded for headless test runs that stub `canvas` as a plain\n    //     object without a `style`.\n    if (this._config.pixelArtPreset) {\n      const style = (this._app.canvas as { style?: CSSStyleDeclaration }).style;\n      if (style) {\n        style.cssText +=\n          \"image-rendering:-webkit-optimize-contrast;image-rendering:pixelated;\";\n      }\n    }\n\n    // 2b. Force `display:block` on the canvas. The <canvas> UA default is\n    //     `display:inline`, which seats it on the text baseline and leaves a\n    //     ~4px line-box descender beneath it. On a fit host whose height is\n    //     content-driven (no explicit/bounded height) that descender makes\n    //     the host measure taller than the canvas the FitController just\n    //     sized to it, the ResizeObserver re-fires, the canvas grows, the\n    //     host grows again — an unbounded loop. `display:block` removes the\n    //     descender so the host content box equals the canvas height and the\n    //     controller reaches a fixed point. Canvas-local and overridable from\n    //     a developer stylesheet. Guarded for headless test runs that stub\n    //     `canvas` without a `style`.\n    const canvasStyle = (this._app.canvas as { style?: CSSStyleDeclaration })\n      .style;\n    if (canvasStyle) canvasStyle.display = \"block\";\n\n    // 3. Append canvas to container if specified\n    if (this._config.container) {\n      this._config.container.appendChild(this._app.canvas);\n    }\n\n    // 4. Insert the world-root container between `app.stage` and every\n    //    per-scene tree. The fit transform lives here, not on stage —\n    //    see the field-level comment on `_worldRoot` for why.\n    this._worldRoot = new Container();\n    this._worldRoot.label = \"yage:worldRoot\";\n    this._app.stage.addChild(this._worldRoot);\n\n    // 5. FitController owns the world-root transform. When `fit` is\n    //    configured (or defaulted), it observes a host element and re-maps\n    //    the virtual rectangle on each resize. In environments without a\n    //    DOM target (tests, headless), it applies the transform once against\n    //    the initial `width × height` and installs no observer.\n    this.startFit(this._config.fit ?? { mode: \"letterbox\" });\n    this._installed.fit = true;\n\n    // 6. Resolve ProcessSystem so layer/scene/screen-scope effects can\n    //    schedule fade tweens. Already registered by Engine before plugin\n    //    install runs.\n    this._processSystem = context.resolve(ProcessSystemKey);\n\n    // 6b. Build the screen-scope EffectsHost over `app.stage`. The underlying\n    //     EffectStack is created lazily on first `addEffect` so a game with no\n    //     screen-scope filters pays nothing.\n    const ps = this._processSystem;\n    this.fx = new EffectsHost(\n      () => this._app.stage,\n      \"screen\",\n      () => makeGlobalScopedQueue(ps),\n    );\n\n    // 7. Create the per-scene render tree provider.\n    //    Each scene gets one root container as a direct child of `_worldRoot`\n    //    (which is itself the only world-space child of `app.stage`).\n    this._provider = new SceneRenderTreeProviderImpl(\n      this._worldRoot,\n      this._processSystem,\n    );\n    this._installed.provider = true;\n\n    // 8. Register services\n    context.register(RendererKey, this);\n    // Also register under the cross-package adapter key so @yagejs/input\n    // (and other renderer-agnostic consumers) can auto-wire to the canvas\n    // and canvasToVirtual transform without importing @yagejs/renderer.\n    context.register(RendererAdapterKey, this);\n    context.register(SceneRenderTreeProviderKey, this._provider);\n\n    // 9. Register scene hooks: materialize a tree per scene on enter,\n    //    tear it down on exit.\n    const hookRegistry = context.resolve(SceneHookRegistryKey);\n    this._unregisterHooks = hookRegistry.register({\n      beforeEnter: (scene) => {\n        const tree = this._provider.createForScene(scene);\n        scene._registerScoped(SceneRenderTreeKey, tree);\n      },\n      afterExit: (scene) => {\n        this._provider.destroyForScene(scene);\n      },\n    });\n\n    // 9b. Apply `Scene.transparentBelow` to the visibility of every below-stack\n    //     scene tree. The flag was previously documented but unenforced — UI\n    //     in a below scene (and any world content) painted through even when\n    //     the topmost scene was meant to fully cover it. Walking the stack on\n    //     every stack mutation hides scenes underneath a `transparentBelow:\n    //     false` neighbour. While a scene transition is running we re-show\n    //     every tree so both the outgoing and incoming scenes can render\n    //     (e.g. crossFade); the chain is reapplied on `scene:transition:ended`.\n    this.installSceneVisibilityListeners(context);\n\n    // 10. Attach PixiJS ticker to GameLoop\n    const gameLoop = context.resolve(GameLoopKey);\n    gameLoop.attachTicker((callback) => {\n      const fn = () => callback(this._app.ticker.deltaMS);\n      this._tickerFn = fn;\n      this._app.ticker.add(fn);\n      return () => this._app.ticker.remove(fn);\n    });\n\n    // 10b. Wire viewport-lifecycle listeners (fullscreen + orientation).\n    //     Both emit onto the engine event bus. Gated behind environment\n    //     checks so node-environment tests that don't stub the globals\n    //     skip the wiring without crashing.\n    const bus = context.resolve(EventBusKey);\n    this.installFullscreenListener(bus);\n    this.installOrientationListener(bus);\n\n    // 11. Register asset loaders (if AssetManager is available)\n    const am = context.tryResolve(AssetManagerKey);\n    am?.registerLoader(\"texture\", {\n      load: (path: string, data?: unknown) => loadTexture(path, data),\n      unload: (path: string) => {\n        return Assets.unload(path);\n      },\n    });\n    am?.registerLoader(\"render-asset\", {\n      load: (path: string) => Assets.load(path),\n      unload: (path: string) => {\n        return Assets.unload(path);\n      },\n    });\n    am?.registerLoader(\"spritesheet\", {\n      load: (path: string) => Assets.load<Spritesheet>(path),\n      unload: (path: string) => {\n        return Assets.unload(path);\n      },\n    });\n    am?.registerLoader(\"bitmap-font\", {\n      load: (path: string) => Assets.load<BitmapFont>(path),\n      unload: (path: string) => {\n        return Assets.unload(path);\n      },\n    });\n    am?.registerLoader(\"web-font\", {\n      // The `webFont` handle stashes the `@font-face` family (Pixi derives it\n      // from the file name when omitted) plus the optional declarative\n      // bitmap-bake config. `loadWebFont` loads the canvas face and, when\n      // `bitmap` is set, bakes a `BitmapText` atlas under the same family;\n      // `unloadWebFont` drops both. The bake/teardown lives in `assets.ts` so\n      // it's unit-testable without standing up the whole plugin.\n      load: (path: string, data?: unknown) => loadWebFont(path, data),\n      unload: (path: string) => {\n        unloadWebFont(path);\n      },\n    });\n\n    // 12. Keep the context for onStart, which publishes the render facet.\n    this._context = context;\n  }\n\n  registerSystems(scheduler: SystemScheduler): void {\n    scheduler.add(new DisplaySystem());\n  }\n\n  onStart(): void {\n    // Publish the render facet (rendered geometry + visibility) into the\n    // Inspector through `registerFacetContributor`, so `@yagejs/core` stays\n    // agnostic of any rendering concept. In onStart rather than install: the\n    // Inspector is installed by a plugin (DebugPlugin or InspectorPlugin),\n    // and every install has run by now whatever order the plugins were\n    // registered in.\n    const inspector = this._context?.tryResolve(InspectorKey);\n    if (inspector) {\n      this._unregisterFacetContributor = inspector.registerFacetContributor(\n        new RenderFacetContributor(),\n      );\n    }\n  }\n\n  onDestroy(): void {\n    // Tear down only the steps install actually completed — `_installed`\n    // tracks how far we got. If install rejected mid-way (e.g.\n    // `await app.init()` failed), the unset fields stay untouched here\n    // instead of throwing on access.\n    this._unregisterFacetContributor?.();\n    this._unregisterFacetContributor = null;\n    this._context = null;\n    this._unregisterFullscreenListener?.();\n    this._unregisterFullscreenListener = null;\n    this._unregisterOrientationListener?.();\n    this._unregisterOrientationListener = null;\n    this._unregisterSceneVisibility?.();\n    this._unregisterSceneVisibility = null;\n    this._unregisterHooks?.();\n    this._unregisterHooks = null;\n    if (this._installed.fit) this._fitController.stop();\n    if (this._installed.app && this._tickerFn) {\n      this._app.ticker.remove(this._tickerFn);\n      this._tickerFn = null;\n    }\n    // Strip stage-level effects before destroying the app — preserves any\n    // user-assigned filters on app.stage outside our addEffect calls.\n    this.fx?.destroy();\n    if (this._installed.provider) this._provider.destroyAll();\n    if (this._installed.app) this._app.destroy();\n    // Restore the global TextureStyle default the pixel-art preset\n    // mutated on install. Skipped when nothing was captured (preset was\n    // off, leave the field alone) — assigning `undefined` to\n    // `defaultOptions.scaleMode` would TS-error and is the wrong shape\n    // anyway, since the preset never ran.\n    if (this._scaleModeCaptured) {\n      if (this._originalScaleMode !== undefined) {\n        TextureStyle.defaultOptions.scaleMode = this._originalScaleMode;\n      }\n      this._scaleModeCaptured = false;\n      this._originalScaleMode = undefined;\n    }\n\n    if (this._defaultTextStyleCaptured) {\n      setDefaultTextStyle(this._prevDefaultTextStyle);\n      this._defaultTextStyleCaptured = false;\n      this._prevDefaultTextStyle = undefined;\n    }\n  }\n\n  /** The PixiJS Application instance. */\n  get application(): Application {\n    return this._app;\n  }\n\n  /** The canvas element. */\n  get canvas(): HTMLCanvasElement {\n    return this._app.canvas;\n  }\n\n  /**\n   * The container that carries the responsive-fit transform — the natural\n   * parent for things that should live inside the virtual play area\n   * (transition overlays scoped to the play rect, world-space HUD, etc.).\n   * Children operate in virtual-space pixels.\n   *\n   * Use `app.stage` instead when the geometry must cover the canvas\n   * including letterbox / expand bars (full-screen dip-to-color overlays).\n   */\n  get worldRoot(): DisplayContainer {\n    return this._worldRoot;\n  }\n\n  /** Virtual resolution size. */\n  get virtualSize(): { width: number; height: number } {\n    return { width: this._virtualWidth, height: this._virtualHeight };\n  }\n\n  /** Current canvas size in CSS pixels. Changes on host resize under responsive fit. */\n  get canvasSize(): { width: number; height: number } {\n    return this._fitController.canvasSize;\n  }\n\n  /** Current fit configuration. */\n  get fit(): RendererFitOptions {\n    const target = this._fitController.currentTarget;\n    return {\n      mode: this._fitController.currentMode,\n      ...(target ? { target } : {}),\n    };\n  }\n\n  /**\n   * Change the fit mode and/or target at runtime. Omitting `target` keeps the\n   * element the fit currently observes, so switching mode alone does not send\n   * the fit back to its default host.\n   */\n  setFit(options: RendererFitOptions): void {\n    if (options.target !== undefined) {\n      this.startFit(options);\n      return;\n    }\n    const current = this._fitController.currentTarget;\n    this.startFit(current ? { ...options, target: current } : options);\n  }\n\n  /**\n   * Convert CSS pixels relative to the canvas top-left into virtual-space\n   * pixels. Inverts the stage transform currently applied by the fit controller.\n   */\n  canvasToVirtual(x: number, y: number): Vec2 {\n    return this._fitController.canvasToVirtual(x, y);\n  }\n\n  /**\n   * Virtual-space pixels → CSS pixels relative to the canvas top-left.\n   * Symmetric with {@link canvasToVirtual}; useful when mapping virtual\n   * coordinates back out to DOM overlays or pointer regions.\n   */\n  virtualToCanvas(x: number, y: number): Vec2 {\n    return this._fitController.virtualToCanvas(x, y);\n  }\n\n  /**\n   * Hit-test at virtual-space `(x, y)` and return `true` when the topmost\n   * interactive Pixi container resolves to a consuming policy. The nearest\n   * explicit boolean wins; UI without an explicit ancestor defaults to true.\n   * The input drain uses this to claim presses landing on UI surfaces.\n   *\n   * Scope: this only sees surfaces marked via `markPointerConsumeContainer` —\n   * `@yagejs/ui` primitives (`UIPanel`, `UIButton`, …) plus any visual\n   * component (`Sprite`, `AnimatedSprite`, `Graphics`, `Text`, `SplitText`)\n   * configured with `interactive: { consumeOnInteraction: true }`. A plain\n   * sprite is not a consume surface. UI drawn on raw Pixi containers outside\n   * those paths — such as the `@yagejs-addons/dialogue` box, which never\n   * marks its containers — is not detected. Dialogue-aware callers should\n   * gate on `DialogueController.isActive()` / `isChoosing()` instead.\n   *\n   * Coordinates are supplied in virtual space (matching how the input plugin\n   * stores pointer positions); they are converted to canvas space via\n   * `FitController.virtualToCanvas` before being forwarded to\n   * `EventBoundary.hitTest`, which per the Pixi v8 spec expects canvas-\n   * relative (\"world space above the boundary\") coordinates. At fit ratio 1\n   * the two spaces coincide; at any other ratio (mobile / responsive) the\n   * conversion is required for the hit-test to land on the correct surface.\n   */\n  hitTestUI(x: number, y: number): boolean {\n    return this.hitTestUIPath(x, y)?.consumed ?? false;\n  }\n\n  /**\n   * The hit test behind {@link hitTestUI}, reporting what it found: the\n   * topmost interactive container and its ancestors, innermost first, plus\n   * their resolved consumption policy. `null` when nothing\n   * interactive sits under `(x, y)`.\n   *\n   * Callers that address a container — matching it against an Inspector\n   * user-interface snapshot, for one — need the chain rather than the\n   * boolean. Same coordinate contract as {@link hitTestUI}: `(x, y)` is in\n   * virtual space.\n   */\n  hitTestUIPath(x: number, y: number): RendererUIHit | null {\n    const boundary = this._app.renderer.events?.rootBoundary;\n    if (!boundary) return null;\n    // Pixi v8 sets `rootBoundary.rootTarget` on each render. Before the first\n    // frame (or under `inspector.time.freeze()` in deterministic test runs\n    // that pause the ticker) it can be null — and `boundary.hitTest` reads\n    // `rootTarget.eventMode` unconditionally, so the call would crash. Bind\n    // it to `_worldRoot` ourselves so the hit-test has a valid root before\n    // the first frame; Pixi's render loop will keep `rootTarget` accurate\n    // once frames start landing.\n    if (!boundary.rootTarget) {\n      boundary.rootTarget = this._worldRoot;\n    }\n    const canvas = this._fitController.virtualToCanvas(x, y);\n    const hit = boundary.hitTest(canvas.x, canvas.y) as DisplayContainer | null;\n    if (!hit) return null;\n    const path: DisplayContainer[] = [];\n    let consumed: boolean | undefined;\n    let hasUI = false;\n    let node: DisplayContainer | null = hit;\n    while (node) {\n      path.push(node);\n      const policy = getPointerConsumePolicy(node);\n      if (policy !== undefined) hasUI = true;\n      if (consumed === undefined && typeof policy === \"boolean\") {\n        consumed = policy;\n      }\n      node = node.parent ?? null;\n    }\n    return { path, consumed: consumed ?? hasUI };\n  }\n\n  /**\n   * Whether a frame has been drawn. Pixi roots its event boundary at the last\n   * object rendered and drops an event silently when there is none, so a\n   * pointer dispatched before the first frame reaches nothing.\n   */\n  hasRenderedFrame(): boolean {\n    return this._app.renderer.lastObjectRendered != null;\n  }\n\n  /**\n   * Deliver a pointer event at virtual-space `point`, so Pixi hit-tests and\n   * delivers it the way it does for a person clicking: a `@yagejs/ui` button\n   * runs its `onClick`, and stacking order, a disabled button's pointer mode\n   * and clipping all apply. `button` is the mouse button a press or a release\n   * carries; a move omits it and reports whichever buttons a press left held.\n   *\n   * The event goes to the canvas, never to the window: Pixi renames a\n   * pointer-up whose composed path starts elsewhere to `pointerupoutside`,\n   * which skips a button's click path. It bubbles, because `@yagejs/input`\n   * listens for pointer-up on the window in the bubble phase — so the engine\n   * receives the same event and applies it at the next drain, one frame after\n   * the handler has already run.\n   *\n   * One primary mouse pointer, id {@link SYNTHETIC_POINTER_ID}. Multi-touch\n   * is not reachable this way.\n   */\n  dispatchPointerEvent(\n    type: RendererPointerEventType,\n    point: { x: number; y: number },\n    button?: 0 | 1 | 2,\n  ): void {\n    if (!this.hasRenderedFrame()) {\n      throw new Error(\n        \"RendererPlugin.dispatchPointerEvent() needs a rendered frame: \" +\n          \"the event boundary hit-tests against the last object rendered and \" +\n          \"drops every event until one exists. Step one frame first.\",\n      );\n    }\n    const bit = button === undefined ? 0 : POINTER_BUTTON_BITS[button];\n    if (type === \"down\") this._syntheticPointerButtons |= bit;\n    if (type === \"up\") this._syntheticPointerButtons &= ~bit;\n    const canvas = this.canvas;\n    const offset = this._fitController.virtualToCanvas(point.x, point.y);\n    const rect = canvas.getBoundingClientRect();\n    canvas.dispatchEvent(\n      new PointerEvent(DOM_POINTER_EVENTS[type], {\n        bubbles: true,\n        cancelable: true,\n        composed: true,\n        clientX: rect.left + offset.x,\n        clientY: rect.top + offset.y,\n        button: type === \"move\" ? NO_BUTTON_CHANGE : (button ?? 0),\n        buttons: this._syntheticPointerButtons,\n        pointerId: SYNTHETIC_POINTER_ID,\n        pointerType: \"mouse\",\n        isPrimary: true,\n      }),\n    );\n  }\n\n  /**\n   * Sub-rectangle of the declared virtual space that is actually on-screen.\n   * Use this to anchor HUD / UI that must stay inside the play area; use\n   * {@link visibleCanvasRect} if your HUD is allowed to live in the bars.\n   * Gameplay queries should stay on `virtualSize`.\n   *\n   * Under `letterbox` / `expand` / `stretch` this equals the full virtual\n   * rect. Under `cover` the long axis is cropped by the canvas edges.\n   */\n  get visibleVirtualRect(): VirtualRect {\n    return this._fitController.visibleVirtualRect;\n  }\n\n  /**\n   * Rectangles of virtual space that are currently off-screen — the\n   * complement of {@link visibleVirtualRect} inside `virtualSize`. Use\n   * these for effects that need to reason about cropped regions (e.g.\n   * fog-of-war overlays at the visible boundary).\n   *\n   * Empty under `letterbox` / `expand` / `stretch`. Under `cover`, returns 1–2 strips.\n   */\n  get croppedVirtualRects(): readonly VirtualRect[] {\n    return this._fitController.croppedVirtualRects;\n  }\n\n  /**\n   * Where the declared virtual rectangle sits on the canvas, in CSS pixels.\n   * Use for DOM overlays positioned over the play area, cropping screenshots\n   * to gameplay, or mapping CSS-coord hit regions. The rect may extend past\n   * the canvas (negative coords, dimensions larger than `canvasSize`) under\n   * `cover`.\n   */\n  get virtualCanvasRect(): CanvasRect {\n    return this._fitController.virtualCanvasRect;\n  }\n\n  /**\n   * Full canvas extent expressed in virtual-space pixels — unlike\n   * {@link visibleVirtualRect}, not clamped to the declared virtual rect.\n   * Under `letterbox` / `expand` on an off-aspect host this extends past\n   * `virtualSize` on the unscaled axis (useful for drawing backdrops that\n   * fill the bars). Under `cover` it equals `visibleVirtualRect`; under\n   * `stretch` it equals the virtual rect.\n   */\n  get visibleCanvasRect(): VirtualRect {\n    return this._fitController.visibleCanvasRect;\n  }\n\n  /**\n   * Rectangles of the visible canvas OUTSIDE the declared virtual rect —\n   * the letterbox/expand \"bars\" expressed in virtual-space pixels.\n   *\n   * Populated under `letterbox` and `expand` whenever aspect mismatches;\n   * empty under `cover` and `stretch`. Under `expand` these are the\n   * play-adjacent strips the game is expected to draw into (fog, parallax,\n   * HUD).\n   *\n   * Under `letterbox` they only report where the background-color bars land.\n   * Every scene layer is clipped to the virtual rect under that mode, so\n   * content placed at these coordinates on a scene layer is invisible. To\n   * draw in the bars, parent a container directly on `renderer.application.stage` and\n   * position it in canvas pixels.\n   */\n  get extendedVirtualRects(): readonly VirtualRect[] {\n    return this._fitController.extendedVirtualRects;\n  }\n\n  /** The per-scene render tree provider. */\n  get sceneRenderTrees(): SceneRenderTreeProvider {\n    return this._provider;\n  }\n\n  /**\n   * Bake a texture once by drawing into a temporary graphics context. The\n   * result never changes again; for a buffer the game redraws, use\n   * {@link createRenderTarget}.\n   *\n   * With `size`, the texture measures exactly that region of the drawing,\n   * starting at `(0, 0)`: a 4-frame strip of 32-pixel cells is `width: 128,\n   * height: 32` however much of each cell the drawing covers. Without it the\n   * texture is the drawn bounds, so its top-left corner is the first pixel\n   * drawn rather than `(0, 0)`, and a drawing that starts at `(10, 4)` bakes\n   * shifted by that much.\n   *\n   * The pixels live only on the GPU, with no image to reload from. Calling\n   * `update()` on the returned texture's `source` re-uploads it empty and\n   * everything drawn from it turns transparent.\n   */\n  createTexture(\n    draw: (graphics: GraphicsContext) => void,\n    size?: CreateTextureOptions,\n  ): TextureResource {\n    if (size) {\n      assertPositiveNumber(\"RendererPlugin.createTexture\", \"width\", size.width);\n      assertPositiveNumber(\n        \"RendererPlugin.createTexture\",\n        \"height\",\n        size.height,\n      );\n    }\n    const graphics = new Graphics();\n    try {\n      draw(graphics);\n      return this._app.renderer.generateTexture({\n        target: graphics,\n        ...(size\n          ? { frame: new Rectangle(0, 0, size.width, size.height) }\n          : {}),\n      });\n    } finally {\n      graphics.destroy();\n    }\n  }\n\n  /**\n   * Create an offscreen buffer that draws `source` into a texture the game\n   * owns and redraws on its own schedule — the repeatable counterpart of\n   * {@link createTexture}, with control over when the buffer refreshes and\n   * how many texels it gets.\n   *\n   * Composite the result by showing `target.texture` (a `SpriteComponent`, a\n   * mask, a filter input). See {@link RenderTargetHandle} for the coordinate\n   * space the source is drawn in and the reasons to keep it out of the live\n   * scene graph.\n   */\n  createRenderTarget(\n    source: DisplayContainer,\n    options: RenderTargetOptions,\n  ): RenderTargetHandle {\n    return createRenderTarget(this._app.renderer, source, options, {\n      stage: this._app.stage,\n      isEnabled: () => this.drawingEnabled,\n    });\n  }\n\n  /** Draw the current stage and pending targets without advancing time. */\n  render(): void {\n    const enabled = this.drawingEnabled;\n    this.drawingEnabled = true;\n    try {\n      this._app.render();\n    } finally {\n      this.drawingEnabled = enabled;\n    }\n  }\n\n  /** Capture the current stage and pending targets without advancing time. */\n  captureCanvas(): HTMLCanvasElement {\n    const enabled = this.drawingEnabled;\n    this.drawingEnabled = true;\n    try {\n      return this._app.renderer.extract.canvas(\n        this._app.stage,\n      ) as HTMLCanvasElement;\n    } finally {\n      this.drawingEnabled = enabled;\n    }\n  }\n\n  // ─── Fullscreen ──────────────────────────────────────────────────\n\n  /**\n   * Request fullscreen for the renderer's host element. Targets the\n   * configured `container` when present (so DOM overlays placed\n   * alongside the canvas remain inside the fullscreened area), falling\n   * back to the canvas itself otherwise. Wraps `Element.requestFullscreen`\n   * with the legacy `webkitRequestFullscreen` fallback for iOS Safari.\n   *\n   * Must be called from a user-gesture handler (click, touch, key);\n   * browsers reject the returned Promise with a `TypeError` otherwise.\n   */\n  async requestFullscreen(): Promise<void> {\n    const target = this.fullscreenTarget();\n    if (!target) {\n      throw new Error(\n        \"RendererPlugin.requestFullscreen: no host element available.\",\n      );\n    }\n    await getFullscreenAPI(target).request();\n  }\n\n  /** Exit fullscreen. No-op if the page isn't currently fullscreen. */\n  async exitFullscreen(): Promise<void> {\n    const target = this.fullscreenTarget();\n    if (!target) return;\n    await getFullscreenAPI(target).exit();\n  }\n\n  /**\n   * Whether the renderer's host element is currently the fullscreen\n   * element. Reads live from the DOM, so this stays accurate when the\n   * user exits fullscreen via Esc or the browser UI.\n   */\n  get isFullscreen(): boolean {\n    const target = this.fullscreenTarget();\n    if (!target) return false;\n    const current = getFullscreenAPI(target).fullscreenElement();\n    return current === target;\n  }\n\n  /**\n   * Current device orientation. Returns `null` when neither the\n   * `screen.orientation` API nor the legacy `window.orientation` angle\n   * is available — typical of headless tests and very old browsers.\n   */\n  get orientation(): OrientationType | null {\n    return deriveOrientationType();\n  }\n\n  private fullscreenTarget(): HTMLElement | null {\n    if (this._config.container) return this._config.container;\n    if (this._installed.app) return this._app.canvas;\n    return null;\n  }\n\n  private installSceneVisibilityListeners(context: EngineContext): void {\n    const sceneManager = context.tryResolve(SceneManagerKey);\n    // SceneManager is engine-globally registered before plugin install in\n    // production. The tryResolve path covers minimal test fixtures that\n    // exercise the plugin without standing up an Engine.\n    if (!sceneManager) return;\n    const bus = context.resolve(EventBusKey);\n    const recompute = (): void =>\n      this._provider.applyTransparentBelow(sceneManager.all);\n    const showAll = (): void =>\n      this._provider.resetVisibility(sceneManager.all);\n    // Event-ordering invariant relied on for push-with-transition:\n    // `SceneManager.push` awaits `_pushScene` (which emits `scene:pushed`)\n    // BEFORE `_runTransition` (which emits `scene:transition:started`).\n    // So `recompute` runs first and may hide the outgoing scene; then\n    // `showAll` re-shows it for the transition's duration; then\n    // `scene:transition:ended` runs `recompute` again to settle the chain.\n    // If that order ever flipped, a cross-fade-on-push would cut the\n    // outgoing scene to black instead of dissolving — see the\n    // \"keeps the outgoing scene visible during a push-with-transition\"\n    // test in RendererPlugin.test.ts which pins the contract.\n    const unsubs = [\n      bus.on(\"scene:pushed\", recompute),\n      bus.on(\"scene:popped\", recompute),\n      bus.on(\"scene:replaced\", recompute),\n      bus.on(\"scene:transition:started\", showAll),\n      bus.on(\"scene:transition:ended\", recompute),\n    ];\n    this._unregisterSceneVisibility = () => {\n      for (const u of unsubs) u();\n    };\n  }\n\n  private installFullscreenListener(bus: EventBus<EngineEvents>): void {\n    if (typeof document === \"undefined\") return;\n    const handler = (): void => {\n      bus.emit(\"screen:fullscreen\", { active: this.isFullscreen });\n    };\n    document.addEventListener(\"fullscreenchange\", handler);\n    document.addEventListener(\"webkitfullscreenchange\", handler);\n    this._unregisterFullscreenListener = () => {\n      document.removeEventListener(\"fullscreenchange\", handler);\n      document.removeEventListener(\"webkitfullscreenchange\", handler);\n    };\n  }\n\n  private installOrientationListener(bus: EventBus<EngineEvents>): void {\n    if (typeof window === \"undefined\") return;\n    const emit = (): void => {\n      const type = deriveOrientationType();\n      if (type !== null) bus.emit(\"screen:orientation\", { type });\n    };\n    const orientation = window.screen?.orientation;\n    if (orientation && typeof orientation.addEventListener === \"function\") {\n      orientation.addEventListener(\"change\", emit);\n      this._unregisterOrientationListener = () => {\n        orientation.removeEventListener(\"change\", emit);\n      };\n      return;\n    }\n    // Legacy fallback: window.orientationchange. Deprecated but still the\n    // only signal on older iOS Safari.\n    window.addEventListener(\"orientationchange\", emit);\n    this._unregisterOrientationListener = () => {\n      window.removeEventListener(\"orientationchange\", emit);\n    };\n  }\n\n  // ─── Internal ────────────────────────────────────────────────────\n\n  private startFit(options: RendererFitOptions): void {\n    const target = this.resolveFitTarget(options);\n    this._fitController?.stop();\n    this._fitController = new FitController(\n      this._app,\n      this._worldRoot,\n      this._virtualWidth,\n      this._virtualHeight,\n      options.mode,\n      target,\n      this._config.width,\n      this._config.height,\n    );\n    this._fitController.start();\n  }\n\n  /**\n   * Resolve the fit target. Returns `null` when no reasonable host can be\n   * inferred — the controller then applies a one-shot transform against\n   * `config.width × config.height` without observing. We intentionally do\n   * NOT fall through to `document.body`: a `ResizeObserver` on `body` fires\n   * on any page layout change (font loads, text reflows, dynamic content),\n   * not just viewport resizes, which would silently re-layout the canvas\n   * every frame. Callers that want full-page fit must opt in explicitly\n   * via `fit: { target: document.body }`.\n   */\n  private resolveFitTarget(options: RendererFitOptions): HTMLElement | null {\n    if (options.target) return options.target;\n    if (this._config.container) return this._config.container;\n    const parent = this._config.canvas?.parentElement;\n    if (parent) return parent;\n    return null;\n  }\n}\n\n// ─── Module-private helpers ──────────────────────────────────────────\n\ninterface FullscreenAPI {\n  request(): Promise<void>;\n  exit(): Promise<void>;\n  fullscreenElement(): Element | null;\n}\n\ntype WebkitElement = Element & {\n  webkitRequestFullscreen?: () => void | Promise<void>;\n};\n\ntype WebkitDocument = Document & {\n  webkitExitFullscreen?: () => void | Promise<void>;\n  webkitFullscreenElement?: Element | null;\n};\n\n/**\n * Resolve the fullscreen API at call time, picking the unprefixed\n * standard methods when present and falling back to the `webkit*`\n * variants on iOS Safari. Detection runs on each call rather than at\n * module load so the helper still works if the prefixed API is\n * polyfilled or wrapped after import.\n */\nfunction getFullscreenAPI(el: Element): FullscreenAPI {\n  if (typeof document === \"undefined\") {\n    return {\n      request: () =>\n        Promise.reject(new Error(\"Fullscreen unavailable: no document\")),\n      exit: () => Promise.resolve(),\n      fullscreenElement: () => null,\n    };\n  }\n  if (\"requestFullscreen\" in el) {\n    return {\n      request: () => Promise.resolve(el.requestFullscreen()),\n      exit: () => Promise.resolve(document.exitFullscreen()),\n      fullscreenElement: () => document.fullscreenElement,\n    };\n  }\n  const webkitEl = el as WebkitElement;\n  const webkitDoc = document as WebkitDocument;\n  if (typeof webkitEl.webkitRequestFullscreen === \"function\") {\n    return {\n      request: () => Promise.resolve(webkitEl.webkitRequestFullscreen?.()),\n      exit: () => Promise.resolve(webkitDoc.webkitExitFullscreen?.()),\n      fullscreenElement: () => webkitDoc.webkitFullscreenElement ?? null,\n    };\n  }\n  return {\n    request: () =>\n      Promise.reject(new Error(\"Fullscreen API not supported in this browser\")),\n    exit: () => Promise.resolve(),\n    fullscreenElement: () => null,\n  };\n}\n\n/**\n * Best-effort device orientation read. Prefers `window.screen.orientation.type`,\n * falling back to deriving from the legacy numeric `window.orientation` angle\n * (deprecated but still the only signal on some old iOS Safari versions).\n * Returns `null` when neither API is available.\n */\nfunction deriveOrientationType(): OrientationType | null {\n  if (typeof window === \"undefined\") return null;\n  const modern = window.screen?.orientation?.type;\n  if (modern) return modern;\n  const legacyAngle =\n    (window as Window & { orientation?: number }).orientation ?? null;\n  if (legacyAngle === null) return null;\n  if (legacyAngle === 0) return \"portrait-primary\";\n  if (legacyAngle === 180) return \"portrait-secondary\";\n  if (legacyAngle === 90) return \"landscape-primary\";\n  if (legacyAngle === -90 || legacyAngle === 270) return \"landscape-secondary\";\n  return null;\n}\n","import type { Bounds } from \"pixi.js\";\nimport type { DisplayContainer, Filter } from \"../public-types.js\";\n\ninterface FilterBoundsEffect {\n  filters: readonly Filter[] | null;\n  addBounds?: (bounds: Bounds, skipUpdate?: boolean) => void;\n}\n\n/**\n * Pixi's filter effect does not contribute its output extent to ancestor\n * bounds. Extend that existing effect rather than tracking a second tree.\n * Only fast filter-input bounds expand; ordinary and local bounds stay unchanged.\n * @internal\n */\nexport function attachFilterBounds(container: DisplayContainer): () => void {\n  // Pixi v8 stores the filter effect here; filters= retains this instance.\n  const effect = (container as unknown as { _filterEffect: FilterBoundsEffect })\n    ._filterEffect;\n  const boundsDescriptor = Object.getOwnPropertyDescriptor(effect, \"addBounds\");\n  const fastDescriptor = Object.getOwnPropertyDescriptor(\n    container,\n    \"getFastGlobalBounds\",\n  );\n  const previousBounds = effect.addBounds;\n  const previousFast = container.getFastGlobalBounds;\n  let readingOwnInput = false;\n  const padding = (): number => {\n    let value = 0;\n    for (const filter of effect.filters ?? []) {\n      if (filter.enabled) value += filter.padding;\n    }\n    return Math.ceil(value);\n  };\n  const addBounds = (bounds: Bounds, skipUpdate?: boolean): void => {\n    previousBounds?.call(effect, bounds, skipUpdate);\n    if (skipUpdate !== true) return;\n    const value = padding();\n    if (value > 0) bounds.pad(value);\n  };\n  Object.defineProperty(effect, \"addBounds\", {\n    configurable: true,\n    get: () => {\n      // Pixi transforms bounds to world space and back whenever a hook exists.\n      // An absent hook avoids that expansion when there is no contribution.\n      if (readingOwnInput || padding() <= 0) return previousBounds;\n      return addBounds;\n    },\n  });\n  container.getFastGlobalBounds = function (factorRenderLayers, bounds) {\n    // FilterSystem asks this method for the host's INPUT, then adds its own\n    // filter padding. Descendants are visited by Pixi's recursive traversal,\n    // so their output extents still contribute through addBounds above.\n    const previous = readingOwnInput;\n    readingOwnInput = true;\n    try {\n      return previousFast.call(this, factorRenderLayers, bounds);\n    } finally {\n      // Restore query state, including when a bounds query throws.\n      readingOwnInput = previous;\n    }\n  };\n  return () => {\n    if (boundsDescriptor)\n      Object.defineProperty(effect, \"addBounds\", boundsDescriptor);\n    else delete effect.addBounds;\n    if (fastDescriptor)\n      Object.defineProperty(container, \"getFastGlobalBounds\", fastDescriptor);\n    else Reflect.deleteProperty(container, \"getFastGlobalBounds\");\n  };\n}\n","import { attachFilterBounds } from \"./filterBounds.js\";\nimport { Tween } from \"@yagejs/core\";\nimport type { Process, ScopedProcessQueue } from \"@yagejs/core\";\nimport type { DisplayContainer as Container, Filter } from \"../public-types.js\";\nimport type { Effect, EffectFactory, EffectScope } from \"./Effect.js\";\nimport type { EffectHandle } from \"./EffectHandle.js\";\nimport { getEffectMeta } from \"./defineEffect.js\";\n\nfunction effectFilters(effect: Effect): Filter[] {\n  return Array.isArray(effect.filter) ? effect.filter : [effect.filter];\n}\n\nfunction readCurrentFilters(displayObject: Container): Filter[] {\n  const current = displayObject.filters as\n    | Filter\n    | readonly Filter[]\n    | null\n    | undefined;\n  if (current == null) return [];\n  return Array.isArray(current) ? [...current] : [current as Filter];\n}\n\n/**\n * Internal: a list of attached effects bound to one pixi `Container`.\n *\n * - Coexists with external `displayObject.filters` assignments. The stack\n *   tracks the filter instances it owns; any other filter present on the\n *   target at sync time is treated as external and preserved (placed before\n *   the stack's owned filters in the chain, so user filters render first\n *   and stack effects composite on top).\n * - `fadeIn` / `fadeOut` are implemented via `Tween.custom`, scheduled on\n *   the supplied `ScopedProcessQueue`. Per-effect processes are tracked so\n *   `handle.remove()` cancels in-flight fades for that effect rather than\n *   letting them keep firing `setIntensity` after detach.\n *\n * @internal\n */\nexport class EffectStack {\n  private readonly entries = new Set<Effect>();\n  private readonly handles = new Map<Effect, EffectHandle>();\n  private readonly ownedFilters = new Set<Filter>();\n  private readonly effectProcesses = new Map<Effect, Set<Process>>();\n  private destroyed = false;\n  private detachBounds: (() => void) | undefined;\n\n  constructor(\n    private readonly displayObject: Container,\n    private readonly queue: ScopedProcessQueue,\n    private readonly scope: EffectScope,\n  ) {}\n\n  /** Build and attach an effect, returning its handle. */\n  add<H extends EffectHandle>(factory: EffectFactory<H>): H {\n    if (this.destroyed) {\n      throw new Error(\n        `EffectStack: cannot add effect to a destroyed ${this.scope}-scope stack.`,\n      );\n    }\n    const effect = factory() as Effect<H>;\n    // Run onAttach BEFORE registering the effect with the stack so a thrown\n    // onAttach can't leave an orphan entry that `destroy()`\n    // would later see. (`onDetach` won't fire for a never-attached effect,\n    // which is the right pairing.)\n    effect.onAttach?.({ displayObject: this.displayObject, scope: this.scope });\n    this.entries.add(effect);\n    this.syncFilters();\n\n    // Per-effect process tracking — fades, hitFlash trigger ramps, CRT\n    // uniform tickers, and any user-scheduled `handle.run(p)` all flow\n    // through here so `removeEffect` can cancel them in one shot.\n    const trackProcess = (p: Process): Process => {\n      let set = this.effectProcesses.get(effect);\n      if (!set) {\n        set = new Set();\n        this.effectProcesses.set(effect, set);\n      }\n      // Lazy-prune completed entries on each new schedule — the host's\n      // pruning only spans its own bookkeeping; this set lives until the\n      // effect is removed, so without pruning a long-lived screen/layer\n      // handle would accumulate Process refs over the app's lifetime.\n      for (const old of set) {\n        if (old.completed) set.delete(old);\n      }\n      set.add(p);\n      return this.queue.run(p);\n    };\n\n    // Built directly (not via spread) so the `enabled` getter survives —\n    // spreading an object literal eagerly invokes getters and copies their\n    // values as static properties.\n    const handle: EffectHandle = {\n      remove: () => this.removeEffect(effect),\n      setEnabled: (on: boolean) => {\n        for (const f of effectFilters(effect)) f.enabled = on;\n      },\n      enabled: true,\n      setIntensity: (value: number) => {\n        effect.setIntensity(Math.min(1, Math.max(0, value)));\n      },\n      fadeIn: (duration: number) =>\n        trackProcess(\n          Tween.custom(\n            (v) => effect.setIntensity(v),\n            effect.getIntensity(),\n            1,\n            duration,\n          ),\n        ),\n      fadeOut: (duration: number) =>\n        trackProcess(\n          Tween.custom(\n            (v) => effect.setIntensity(v),\n            effect.getIntensity(),\n            0,\n            duration,\n          ),\n        ),\n      run: (p) => trackProcess(p),\n    };\n    Object.defineProperty(handle, \"enabled\", {\n      get: () => effectFilters(effect).every((f) => f.enabled),\n      enumerable: true,\n      configurable: false,\n    });\n\n    // Both buildExtras and onActivate could throw (e.g. a custom factory\n    // mutating something invalid, or onActivate's `base.run(...)` rejecting\n    // before scheduling). Wrap together so partial state — half-merged\n    // extras, half-scheduled processes — gets rolled back via removeEffect\n    // and the caller sees the real exception instead of an inconsistent\n    // stack. Activation runs AFTER buildExtras so onActivate sees the\n    // fully-built handle (the right place for self-scheduled tickers like\n    // CRT's noise animator).\n    try {\n      if (effect.buildExtras) {\n        Object.assign(handle, effect.buildExtras(handle));\n      }\n      this.handles.set(effect, handle);\n      effect.onActivate?.(handle);\n    } catch (err) {\n      this.removeEffect(effect);\n      throw err;\n    }\n    return handle as H;\n  }\n\n  /** Number of attached effects. */\n  get size(): number {\n    return this.entries.size;\n  }\n\n  /**\n   * Find the handle for the first effect in the stack built from a\n   * `defineEffect` definition with the given `name`.\n   *\n   * Returns `undefined` if no matching entry exists. If the stack holds\n   * multiple entries with the same definition name, the first one\n   * encountered (insertion order) is returned.\n   */\n  findHandle(definitionName: string): EffectHandle | undefined {\n    for (const effect of this.entries) {\n      const meta = getEffectMeta(effect);\n      if (meta?.definitionName === definitionName) {\n        return this.handles.get(effect);\n      }\n    }\n    return undefined;\n  }\n\n  /** Tear down every attached effect and cancel any in-flight tweens. */\n  destroy(): void {\n    if (this.destroyed) return;\n    this.destroyed = true;\n    for (const effect of this.entries) {\n      effect.onDetach?.();\n    }\n    this.entries.clear();\n    this.handles.clear();\n    // `effectProcesses` is the per-effect index used by `removeEffect` to\n    // find and cancel a single effect's processes. On destroy we cancel\n    // EVERY process at once via `this.queue.cancelAll()` below, so clearing\n    // the index without iterating it is correct — the queue's own tracking\n    // is the source of truth for the bulk cancellation.\n    this.effectProcesses.clear();\n\n    // Strip our owned filters from the target while leaving any externally-\n    // assigned filters in place. Restore null when nothing external remains.\n    const external = readCurrentFilters(this.displayObject).filter(\n      (f) => !this.ownedFilters.has(f),\n    );\n    this.ownedFilters.clear();\n    this.displayObject.filters = external.length === 0 ? null : external;\n\n    this.detachBounds?.();\n    this.detachBounds = undefined;\n    this.queue.cancelAll();\n  }\n\n  private removeEffect(effect: Effect): void {\n    if (!this.entries.has(effect)) return;\n    this.entries.delete(effect);\n    this.handles.delete(effect);\n    effect.onDetach?.();\n\n    // Cancel any in-flight fades scoped to this effect. Without this, the\n    // tween keeps ticking and calls setIntensity on a now-detached filter.\n    const procs = this.effectProcesses.get(effect);\n    if (procs) {\n      for (const p of procs) {\n        if (!p.completed) p.cancel();\n      }\n      this.effectProcesses.delete(effect);\n    }\n\n    this.syncFilters();\n  }\n\n  private syncFilters(): void {\n    const desired: Filter[] = [];\n    for (const e of this.entries) desired.push(...effectFilters(e));\n\n    // External filters = current filters that are NOT in our previously\n    // owned set. Re-read every sync so user assignments between syncs\n    // (sprite.filters = [their, custom]) are honored.\n    const external = readCurrentFilters(this.displayObject).filter(\n      (f) => !this.ownedFilters.has(f),\n    );\n\n    this.ownedFilters.clear();\n    for (const f of desired) this.ownedFilters.add(f);\n\n    const next = [...external, ...desired];\n    this.displayObject.filters = next.length === 0 ? null : next;\n    if (this.entries.size > 0) {\n      this.detachBounds ??= attachFilterBounds(this.displayObject);\n    } else {\n      this.detachBounds?.();\n      this.detachBounds = undefined;\n    }\n  }\n}\n","import type { Effect, EffectFactory } from \"./Effect.js\";\nimport type { EffectHandle } from \"./EffectHandle.js\";\n\n/**\n * Symbol-keyed metadata stamped onto each effect built from a definition so\n * `EffectsHost.findEffect()` can match it without changing the public Effect\n * interface.\n *\n * @internal\n */\nexport const EFFECT_META = Symbol(\"yage.effectMeta\");\n\n/** Definition metadata recorded on a tagged `Effect`. @internal */\nexport interface EffectMeta {\n  readonly definitionName: string;\n}\n\n/**\n * Named effect definition. The callable shape `(options) => EffectFactory`\n * is what users invoke at call sites (`bloom({ threshold: 0.8 })`); the\n * `name` property lets callers find an attached effect later.\n */\nexport interface EffectDefinition<H extends EffectHandle, O> {\n  (options: O): EffectFactory<H>;\n  readonly name: string;\n}\n\n/**\n * Define a named effect preset. The returned callable accepts the preset's\n * options and yields an `EffectFactory` whose built effect carries the name\n * used by `EffectsHost.findEffect()`.\n *\n * Names are conventionally prefixed (`yage:hitFlash`, `yage:bloom`, …); the\n * `@yagejs/effects` package uses `yage:` for its hero presets.\n */\nexport function defineEffect<H extends EffectHandle, O>(spec: {\n  name: string;\n  factory: (options: O) => Effect<H>;\n}): EffectDefinition<H, O> {\n  const definition = ((options: O): EffectFactory<H> => {\n    return () => {\n      const effect = spec.factory(options);\n      const meta: EffectMeta = {\n        definitionName: spec.name,\n      };\n      Object.defineProperty(effect, EFFECT_META, {\n        value: meta,\n        enumerable: false,\n        writable: false,\n        configurable: false,\n      });\n      return effect;\n    };\n  }) as EffectDefinition<H, O>;\n  Object.defineProperty(definition, \"name\", {\n    value: spec.name,\n    enumerable: true,\n    writable: false,\n    configurable: false,\n  });\n  return definition;\n}\n\n/** Read definition metadata stamped on an `Effect`, if any. @internal */\nexport function getEffectMeta(effect: Effect): EffectMeta | undefined {\n  return (effect as unknown as Record<symbol, EffectMeta | undefined>)[\n    EFFECT_META\n  ];\n}\n","import type { ScopedProcessQueue } from \"@yagejs/core\";\nimport type { DisplayContainer as Container } from \"../public-types.js\";\nimport { EffectStack } from \"./EffectStack.js\";\nimport type { EffectFactory, EffectScope } from \"./Effect.js\";\nimport type { EffectDefinition } from \"./defineEffect.js\";\nimport type { EffectHandle } from \"./EffectHandle.js\";\n\n/**\n * Per-attachment-site holder for an `EffectStack`. Every scope (component,\n * layer, scene, screen) carries its own `EffectsHost` exposed as `.fx`, so\n * the user-facing API for adding / finding / fading effects is identical\n * regardless of where the effect lives.\n *\n * The underlying `EffectStack` is built lazily on first `addEffect` so sites\n * that never use effects pay zero cost.\n *\n * `getContainer` is a thunk because some sites (component scope) wire the\n * host at construction time but the underlying display object may itself be\n * created in the same constructor — the thunk removes \"is this stable yet?\"\n * thinking. `makeQueue` is optional because some test setups omit a\n * `ProcessSystem`; calling `addEffect` then throws a clear error.\n */\nexport class EffectsHost {\n  private _stack: EffectStack | undefined;\n\n  constructor(\n    private readonly getContainer: () => Container,\n    private readonly scope: EffectScope,\n    private readonly makeQueue: (() => ScopedProcessQueue) | undefined,\n  ) {}\n\n  /**\n   * Attach a visual effect. Returns a typed handle for fading, removal,\n   * intensity, and any per-effect extras the factory exposes.\n   */\n  addEffect<H extends EffectHandle>(factory: EffectFactory<H>): H {\n    return this._ensureStack().add(factory);\n  }\n\n  /**\n   * Recover the handle for the first effect attached here whose underlying\n   * definition is `definition`. Returns `null` if no match exists.\n   */\n  findEffect<H extends EffectHandle, O>(\n    definition: EffectDefinition<H, O>,\n  ): H | null {\n    return (this._stack?.findHandle(definition.name) as H | undefined) ?? null;\n  }\n\n  /** Number of attached effects on this host. */\n  get size(): number {\n    return this._stack?.size ?? 0;\n  }\n\n  /**\n   * @internal — torn down by the owning site (component/layer/scene/screen)\n   * before its container is destroyed, so user-assigned external filters\n   * survive the EffectStack teardown.\n   */\n  destroy(): void {\n    this._stack?.destroy();\n    this._stack = undefined;\n  }\n\n  private _ensureStack(): EffectStack {\n    if (this._stack) return this._stack;\n    if (!this.makeQueue) {\n      throw new Error(\n        `EffectsHost (${this.scope}-scope): no queue factory wired. ` +\n          `This host was constructed outside a fully-wired renderer plugin.`,\n      );\n    }\n    this._stack = new EffectStack(\n      this.getContainer(),\n      this.makeQueue(),\n      this.scope,\n    );\n    return this._stack;\n  }\n}\n","import { updateRenderGroupTransforms } from \"pixi.js\";\nimport type { DisplayContainer } from \"./public-types.js\";\n\n/** Refresh the same transforms and sibling order Pixi uses for pointer events. */\nexport function synchronizeInteraction(stage: DisplayContainer): void {\n  stage.enableRenderGroup();\n  const prepare = (container: DisplayContainer): void => {\n    if (container.sortableChildren) container.sortChildren();\n    if (container.renderGroup) {\n      // Pending view changes need validation before Pixi updates render batches.\n      // Defer those groups to the next draw; transform-only changes can update\n      // existing batches without rebuilding them.\n      if (container.renderGroup.childrenRenderablesToUpdate.index > 0) {\n        container.renderGroup.structureDidChange = true;\n      }\n      container.renderGroup.invalidateMatrices();\n    }\n    for (const child of container.children) prepare(child);\n  };\n  prepare(stage);\n  stage.updateLocalTransform();\n  updateRenderGroupTransforms(stage.renderGroup!, true);\n}\n","import {\n  System,\n  Phase,\n  Transform,\n  Vec2Buffer,\n  QueryCacheKey,\n  ErrorBoundaryKey,\n} from \"@yagejs/core\";\nimport type {\n  EngineContext,\n  ErrorBoundary,\n  QueryResult,\n  Scene,\n} from \"@yagejs/core\";\nimport type { SceneRenderTreeProvider } from \"./SceneRenderTree.js\";\nimport { SceneRenderTreeProviderKey } from \"./SceneRenderTree.js\";\nimport { CameraComponent } from \"./CameraComponent.js\";\nimport {\n  SortGroupComponent,\n  sortGroupForContainer,\n} from \"./SortGroupComponent.js\";\nimport type { Container } from \"pixi.js\";\nimport { VisualComponent } from \"./VisualComponent.js\";\nimport { attributed } from \"./internal/attribution.js\";\nimport { syncCameraTransform } from \"./cameraTransform.js\";\n\n/**\n * Syncs Transform components to PixiJS display objects and applies\n * camera-based per-layer transforms. Each scene's CameraEntity bindings\n * determine which layers receive the camera transform; unbound layers\n * stay at identity (screen-space behavior).\n */\nexport class DisplaySystem extends System {\n  private readonly transformScratch = new Vec2Buffer();\n  readonly phase = Phase.Render;\n  readonly priority = 0;\n\n  private visualQuery!: QueryResult;\n  private cameraQuery!: QueryResult;\n  private sortGroupQuery!: QueryResult;\n  private treeProvider!: SceneRenderTreeProvider;\n  private boundary: ErrorBoundary | undefined;\n\n  onRegister(context: EngineContext): void {\n    const queryCache = context.resolve(QueryCacheKey);\n    this.visualQuery = queryCache.register([Transform, VisualComponent]);\n    this.cameraQuery = queryCache.register([CameraComponent]);\n    this.sortGroupQuery = queryCache.register([SortGroupComponent]);\n    this.treeProvider = context.resolve(SceneRenderTreeProviderKey);\n    this.boundary = context.tryResolve(ErrorBoundaryKey);\n  }\n\n  update(): void {\n    // 1. Sync transforms to display objects. One entity can carry several\n    //    visuals of different classes (a background plus a label), so every\n    //    assignable component is synced, not just the first.\n    for (const entity of this.visualQuery) {\n      const transform = entity.get(Transform);\n      const position = transform.getWorldPositionInto(this.transformScratch);\n      const x = position.x;\n      const y = position.y;\n      const rotation = transform.worldRotation;\n      const scale = transform.getWorldScaleInto(this.transformScratch);\n      const scaleX = scale.x;\n      const scaleY = scale.y;\n      for (const visual of entity.getAll(VisualComponent)) {\n        if (!visual.effectiveEnabled) continue;\n        const displayObject = visual.renderObject as Container;\n        displayObject.position.set(x, y);\n        displayObject.rotation = rotation;\n        displayObject.scale.set(scaleX, scaleY);\n      }\n    }\n\n    // 2. Apply per-layer depth keys. Runs AFTER authoritative transform sync so\n    //    position-based depth keys see the frame's current values.\n    //    Order vs. camera transforms doesn't matter — we're writing\n    //    `zIndex`, which Pixi's render-time `sortChildren()` consumes;\n    //    the camera transform on the layer container is independent.\n    this.applyLayerSort();\n\n    // 3. Apply render-only modifiers after sorting. Transient shake and punch\n    //    offsets do not change an entity's stable depth key.\n    this.applyVisualModifiers();\n\n    // 4. Apply camera transforms to layers\n    this.applyCameraTransforms();\n  }\n\n  private applyVisualModifiers(): void {\n    for (const entity of this.visualQuery) {\n      for (const visual of entity.getAll(VisualComponent)) {\n        if (visual.effectiveEnabled) this.applyModifiers(visual);\n      }\n    }\n  }\n\n  private applyModifiers(visual: VisualComponent): void {\n    const modifiers = visual.modifiers;\n    if (!modifiers.hasTransformModifiers) return;\n    const displayObject = visual.renderObject as Container;\n    displayObject.position.x += modifiers.positionOffset.x;\n    displayObject.position.y += modifiers.positionOffset.y;\n    displayObject.rotation += modifiers.rotationOffset;\n    displayObject.scale.x *= modifiers.scaleFactor.x;\n    displayObject.scale.y *= modifiers.scaleFactor.y;\n  }\n\n  /**\n   * Per-frame depth-key hook. For every layer with a `sort` fn, writes\n   * `child.zIndex = sort(child)` on every direct child. The layer's\n   * container already has `sortableChildren = true` (set in `RenderLayer`),\n   * so Pixi's render-pipeline sort runs at frame end and orders the\n   * children by zIndex — no custom sort path on our side. Pixi's\n   * `zIndex` setter marks `sortDirty` automatically, so we don't need\n   * to flip it ourselves.\n   *\n   * A `SortGroupComponent`'s container is a direct child of the layer too, but\n   * sorting it by its own (origin) position would be meaningless — it's keyed\n   * off the group's anchor instead, so the whole group sorts as one unit. The\n   * group's members are nested inside it, so this layer-level pass never\n   * touches them; an optional `innerSort` re-keys them in a second pass.\n   *\n   * Layers without a `sort` keep insertion order.\n   */\n  private applyLayerSort(): void {\n    // Pass 1: key every sorted layer's direct children. A group container is\n    // keyed off its anchor (so the whole group sorts as one unit); everything\n    // else by the layer's depth-key fn. `sortGroupForContainer` is an O(1)\n    // registry lookup — no per-frame allocation in this hot path.\n    for (const [scene, tree] of this.treeProvider.allTrees()) {\n      for (const layer of tree.getAll()) {\n        const sort = layer.sort;\n        if (!sort) continue;\n        const info = {\n          kind: \"Layer depth-key function\",\n          scene: scene.name,\n          event: layer.name,\n        };\n        for (const child of layer.container.children) {\n          const group = sortGroupForContainer(child);\n          child.zIndex = attributed(this.boundary, info, () =>\n            group ? group.resolveSortKey(sort) : sort(child),\n          );\n        }\n      }\n    }\n\n    // Pass 2: intra-group member ordering. A group with an `innerSort` re-keys\n    // its own members each frame (independent of whether its layer has a sort);\n    // groups without one keep insertion order and honour a manual `zIndex`. A\n    // disabled group is skipped, matching the visual sync pass.\n    for (const entity of this.sortGroupQuery) {\n      const group = entity.get(SortGroupComponent);\n      const inner = group.innerSort;\n      if (!inner || !group.effectiveEnabled) continue;\n      const info = {\n        kind: \"Sort group innerSort function\",\n        entity: entity.name,\n      };\n      for (const member of group.container.children) {\n        member.zIndex = attributed(this.boundary, info, () => inner(member));\n      }\n    }\n  }\n\n  /**\n   * Apply per-layer camera transforms for every live scene.\n   *\n   * Layers are reset to identity first so disabling or destroying the last\n   * camera cannot leave stale transforms behind on a scene's containers.\n   *\n   * Within a scene, enabled cameras are sorted by ascending `priority`; when\n   * multiple cameras bind the same layer, the later write wins, so the\n   * highest-priority camera fully overwrites translation, scale, and rotation\n   * rather than blending with earlier cameras.\n   *\n   * Each binding's three ratios (`translateRatio`, `rotateRatio`, `scaleRatio`)\n   * independently blend from identity (`0`) to full camera effect (`1`). All\n   * default to `1`, matching the classic \"this layer follows the camera\"\n   * behavior. Parallax is `translateRatio < 1`; a billboard layer is\n   * `rotateRatio: 0, scaleRatio: 0`.\n   */\n  private applyCameraTransforms(): void {\n    // Reset every live scene's layers to identity. This must cover scenes\n    // even when they have no active camera — otherwise layers keep the last\n    // transform after the final camera is destroyed/disabled.\n    for (const [, tree] of this.treeProvider.allTrees()) {\n      for (const layer of tree.getAll()) {\n        syncCameraTransform(layer.container);\n      }\n    }\n\n    const camerasByScene = new Map<Scene, CameraComponent[]>();\n    for (const entity of this.cameraQuery) {\n      const cam = entity.get(CameraComponent);\n      const scene = entity.tryScene;\n      if (!scene || !cam.enabled) continue;\n      const list = camerasByScene.get(scene);\n      if (list) list.push(cam);\n      else camerasByScene.set(scene, [cam]);\n    }\n\n    for (const [scene, cameras] of camerasByScene) {\n      const tree = this.treeProvider.getTree(scene);\n      if (!tree) continue;\n\n      cameras.sort((a, b) => a.priority - b.priority);\n\n      for (const cam of cameras) {\n        const bindings = cam.getResolvedBindings(tree);\n\n        for (const binding of bindings) {\n          const layer = tree.tryGet(binding.layer);\n          if (!layer) continue;\n\n          syncCameraTransform(layer.container, cam, binding);\n        }\n      }\n    }\n  }\n}\n","import { ServiceKey } from \"@yagejs/core\";\nimport type { Scene } from \"@yagejs/core\";\nimport type { LayerDef } from \"./LayerDef.js\";\nimport type { RenderLayer, CreateLayerOptions } from \"./RenderLayer.js\";\nimport type { EffectFactory } from \"./effects/Effect.js\";\nimport type { EffectHandle } from \"./effects/EffectHandle.js\";\nimport type { EffectsHost } from \"./effects/EffectsHost.js\";\nimport type { MaskFactory } from \"./masks/MaskFactory.js\";\nimport type { MaskHandle } from \"./masks/MaskHandle.js\";\nimport type { DisplayContainer } from \"./public-types.js\";\n\n/**\n * Options for `ensureLayer` beyond the declarative `LayerDef`. Used by\n * plugins (e.g. UI) to auto-provision screen-space layers so they stay\n * fixed to the viewport under the default camera.\n */\nexport type EnsureLayerOptions = Pick<\n  CreateLayerOptions,\n  \"space\" | \"eventMode\"\n>;\n\n/**\n * Scene-owned render tree. Created by `SceneRenderTreeProvider` when a scene\n * enters. Scoped DI: components resolve via `this.use(SceneRenderTreeKey)`.\n */\nexport interface SceneRenderTree {\n  /** The single root container for the scene. Lives under the renderer's\n   * world-root container (which sits under `app.stage` and holds the fit\n   * transform). */\n  readonly root: DisplayContainer;\n  /** Get a layer by name. Throws if not found. */\n  get(name: string): RenderLayer;\n  /** Get a layer by name, or undefined if not found. */\n  tryGet(name: string): RenderLayer | undefined;\n  /** All layers, sorted by draw order. */\n  getAll(): readonly RenderLayer[];\n  /** The auto-created \"default\" layer (order 0). */\n  readonly defaultLayer: RenderLayer;\n  /**\n   * Get an existing layer or create it from the given definition. Used by\n   * plugins like UI that auto-provision a layer if the game didn't declare\n   * one explicitly. Pass `{ space: \"screen\" }` so a default camera leaves\n   * the layer fixed to the viewport (e.g. screen-space HUD).\n   * Existing layers keep their settings. A differing requested order warns in\n   * development once per tree, layer name, and expected order.\n   */\n  ensureLayer(def: LayerDef, opts?: EnsureLayerOptions): RenderLayer;\n  /**\n   * Scene-scope effects host — `.fx.addEffect(...)` attaches a filter to the\n   * entire per-scene root container, after layer-scope effects have composited.\n   * Common use: scene-wide CRT, color grade, vignette. Survives until the\n   * scene exits or the handle is `.remove()`d.\n   *\n   * `.fx.findEffect(definition)` finds an attached effect when the caller no\n   * longer has its original handle.\n   */\n  readonly fx: EffectsHost;\n  /**\n   * Attach one effect to several layers and control it through one handle.\n   * The factory is called once per layer, so this is one filter pass per\n   * listed layer: N fullscreen layers cost N fullscreen passes per frame. For\n   * a single layer prefer `tree.get(name).fx.addEffect(...)`.\n   *\n   * Handle methods fan out to every layer; values (`enabled`, return values\n   * of extras such as `trigger`) come from the first listed layer. Layers\n   * with different camera bindings receive the same layer-local arguments.\n   * Throws when `layers` is empty or names a layer the scene does not have.\n   *\n   * ```ts\n   * const grade = tree.addLayerEffect(colorGrade({ preset: \"night\" }), [\n   *   \"background\",\n   *   \"world\",\n   *   \"props\",\n   * ]);\n   * grade.fadeOut(1); // fades on all three\n   * ```\n   */\n  addLayerEffect<H extends EffectHandle>(\n    factory: EffectFactory<H>,\n    layers: readonly string[],\n  ): H;\n  /**\n   * Attach a scene-scope mask, replacing any existing one. Clips the entire\n   * per-scene root. Torn down on scene exit.\n   */\n  setMask(factory: MaskFactory): MaskHandle;\n  /** Detach and destroy the scene-scope mask, if any. */\n  clearMask(): void;\n  /**\n   * Draw `node` after this scene's layers, outside every layer- and\n   * scene-scope effect and mask, while it keeps its logical parent (position,\n   * alpha, visibility, camera). Screen-scope effects still cover it. Draw\n   * order among nodes attached this way is attach order. `node` must be in\n   * this scene's tree.\n   *\n   * Visual components expose the same thing as\n   * `VisualComponentOptions.renderAboveEffects`; use this for a display\n   * object the game parents into the tree itself.\n   */\n  renderAboveEffects(node: DisplayContainer): void;\n  /** Undo `renderAboveEffects`. No-op when `node` is not attached. */\n  renderWithEffects(node: DisplayContainer): void;\n}\n\n/**\n * Provider that materializes and tears down per-scene render trees. Held\n * engine-globally so the inspector and renderer-owned tools can enumerate\n * trees.\n */\nexport interface SceneRenderTreeProvider {\n  createForScene(scene: Scene): SceneRenderTree;\n  destroyForScene(scene: Scene): void;\n  /** Look up the render tree for a given scene. */\n  getTree(scene: Scene): SceneRenderTree | undefined;\n  /** Iterate every live scene/tree pair. */\n  allTrees(): Iterable<[Scene, SceneRenderTree]>;\n  /** Reorder the scene's container to render on top of its root peers. */\n  bringSceneToFront?(scene: Scene): void;\n}\n\n/**\n * Engine-scope key for the render-tree provider. Used by cross-scene tools\n * (inspector, debug plugin, tests) to enumerate or ensure layers.\n */\nexport const SceneRenderTreeProviderKey =\n  new ServiceKey<SceneRenderTreeProvider>(\"sceneRenderTreeProvider\");\n\n/**\n * Scene-scope key for the active scene's render tree. Registered by the\n * renderer's `beforeEnter` hook; components resolve with `this.use()`.\n */\nexport const SceneRenderTreeKey = new ServiceKey<SceneRenderTree>(\n  \"sceneRenderTree\",\n  { scope: \"scene\" },\n);\n","import { Component, Vec2, Vec2Buffer } from \"@yagejs/core\";\nimport type { Vec2Like, EasingFunction } from \"@yagejs/core\";\nimport { RendererKey } from \"./types.js\";\nimport type { SceneRenderTree } from \"./SceneRenderTree.js\";\nimport { CameraFollow } from \"./CameraFollow.js\";\nimport type { FollowTarget } from \"./FollowTarget.js\";\nimport { CameraShake } from \"./CameraShake.js\";\nimport { CameraZoom } from \"./CameraZoom.js\";\nimport { CameraBoundsComponent } from \"./CameraBoundsComponent.js\";\nimport { CameraModifierHost } from \"./CameraModifiers.js\";\n\n/** Bounding rectangle for camera clamping. */\nexport interface CameraBounds {\n  minX: number;\n  minY: number;\n  maxX: number;\n  maxY: number;\n}\n\n/** Options for camera follow behavior. */\nexport interface CameraFollowOptions {\n  /**\n   * Smoothing factor 0..1. `1` = instant snap, lower = smoother. `0` never\n   * moves the camera at all, so the follow appears frozen. Default: `1`.\n   */\n  smoothing?: number;\n  /** Offset from the target position, in world pixels. */\n  offset?: Vec2Like;\n  /**\n   * Deadzone rectangle in world pixels (half-width, half-height). The camera\n   * stays put while the target is inside it.\n   */\n  deadzone?: { halfWidth: number; halfHeight: number };\n  /**\n   * Place the camera on the target as following starts, instead of easing in\n   * from wherever the camera currently is. Default: false.\n   */\n  snap?: boolean;\n}\n\n/** Options for camera shake. */\nexport interface CameraShakeOptions {\n  /**\n   * How much the shake fades across its duration. `0` (the default) holds\n   * full intensity until the shake ends. `1` fades linearly to zero over the\n   * duration. Values above `1` reach zero earlier — at `2` the camera stops\n   * moving halfway through.\n   */\n  decay?: number;\n}\n\n/**\n * Binding that associates a camera with a named render layer.\n *\n * Each ratio is a linear blend from identity (`0`) to full camera effect\n * (`1`), applied independently per axis. Defaults are all `1`, giving the\n * classic \"this layer follows the camera\" behavior.\n *\n * Common recipes:\n * - Parallax: `translateRatio: 0.5` (half the camera's translation).\n * - Dampened zoom, still upright: `rotateRatio: 0, scaleRatio: 0.3`.\n *\n * A ratio below `1` scales the layer by less than the camera does while the\n * layer still translates by the full camera offset, so content drifts away\n * from the world position it should sit on as the zoom leaves `1`. For UI\n * that must track a world point at constant size, use `ScreenFollow`, which\n * projects the point through the camera every frame.\n */\nexport interface CameraBinding {\n  /** Layer name to transform. */\n  layer: string;\n  /** Translation follow factor. `0` = stay at world origin, `1` = full. Default: `1`. */\n  translateRatio?: number;\n  /** Rotation follow factor. `0` = stay upright, `1` = full camera rotation. Default: `1`. */\n  rotateRatio?: number;\n  /** Zoom follow factor. `0` = constant size, `1` = full camera zoom. Default: `1`. */\n  scaleRatio?: number;\n}\n\nexport interface CameraComponentOptions {\n  position?: Vec2;\n  zoom?: number;\n  rotation?: number;\n  bindings?: CameraBinding[];\n  autoBind?: boolean;\n  priority?: number;\n  name?: string;\n}\n\n/** Frame-rate-independent reference timestep (seconds). */\nexport const CAMERA_REFERENCE_DT = 1 / 60;\n\n/** Shared empty result for a camera that binds nothing. */\nconst NO_BINDINGS: readonly CameraBinding[] = [];\n\n/**\n * Core camera state component. Added by `CameraEntity`; holds position,\n * zoom, rotation, and layer bindings. Provides convenience methods that\n * delegate to sibling behavior components (CameraFollow, CameraShake, etc.).\n *\n * Added by `CameraEntity`; access via direct reference from `spawn()`\n * or by querying entities with this component.\n */\nexport class CameraComponent extends Component {\n  private readonly projectionScratch = new Vec2Buffer();\n  position: Vec2;\n  zoom: number;\n  rotation: number;\n  /** Transient position, rotation, and zoom contributions. */\n  readonly modifiers = new CameraModifierHost();\n\n  readonly bindings: CameraBinding[] | null;\n  /** Bind every world-space layer before applying `bindings`. Default: `true`. */\n  readonly autoBind: boolean;\n  readonly priority: number;\n  readonly cameraName: string | undefined;\n\n  constructor(options?: CameraComponentOptions) {\n    super();\n    this.position = options?.position ?? Vec2.ZERO;\n    this.zoom = options?.zoom ?? 1;\n    this.rotation = options?.rotation ?? 0;\n    this.bindings = options?.bindings ?? null;\n    this.autoBind = options?.autoBind ?? true;\n    this.priority = options?.priority ?? 0;\n    this.cameraName = options?.name;\n  }\n\n  get viewportWidth(): number {\n    return this.use(RendererKey).virtualSize.width;\n  }\n\n  get viewportHeight(): number {\n    return this.use(RendererKey).virtualSize.height;\n  }\n\n  /** Effective position including every active camera modifier. */\n  get effectivePosition(): Vec2 {\n    const position = this.getEffectivePositionInto(this.projectionScratch);\n    return new Vec2(position.x, position.y);\n  }\n\n  /** Copy the position including active modifiers into caller-owned scratch. */\n  getEffectivePositionInto(out: Vec2Buffer): Vec2Buffer {\n    return Vec2.addInto(out, this.position, this.modifiers.positionOffset);\n  }\n\n  /** Effective rotation including every active camera modifier. */\n  get effectiveRotation(): number {\n    return this.rotation + this.modifiers.rotationOffset;\n  }\n\n  /** Effective zoom including every active camera modifier. */\n  get effectiveZoom(): number {\n    return this.zoom * this.modifiers.zoomFactor;\n  }\n\n  /** Start following a target. */\n  follow(target: FollowTarget, options?: CameraFollowOptions): void {\n    this.entity.get(CameraFollow).start(target, options);\n  }\n\n  /** Stop following any target. */\n  unfollow(): void {\n    this.entity.get(CameraFollow).stop();\n  }\n\n  /** Cut to the current follow target, skipping the smoothing ease. */\n  snapToTarget(): void {\n    this.entity.get(CameraFollow).snapToTarget();\n  }\n\n  /**\n   * Start a screen shake effect. `intensity` is the maximum displacement per\n   * axis in **world pixels**, so what the player sees scales with zoom — the\n   * same intensity moves twice as far on screen at zoom 2.\n   */\n  shake(\n    intensity: number,\n    duration: number,\n    options?: CameraShakeOptions,\n  ): void {\n    this.entity.get(CameraShake).start(intensity, duration, options);\n  }\n\n  /** Animate zoom to a target value over a duration. */\n  zoomTo(target: number, duration: number, easing?: EasingFunction): void {\n    this.entity.get(CameraZoom).start(target, duration, easing);\n  }\n\n  /** Get or set camera bounds. */\n  get bounds(): CameraBounds | undefined {\n    return this.entity.get(CameraBoundsComponent).bounds;\n  }\n\n  set bounds(value: CameraBounds | undefined) {\n    this.entity.get(CameraBoundsComponent).bounds = value;\n  }\n\n  /**\n   * Convert screen coordinates to world coordinates.\n   *\n   * The conversion uses the camera's own transform, not any layer's. A layer\n   * bound with a ratio below `1` (parallax, dampened zoom) renders under a\n   * different transform, so this result does not name a point on that layer.\n   *\n   * The result is undefined for a zoom of `0` or a non-finite camera value.\n   */\n  screenToWorld(screenX: number, screenY: number): Vec2 {\n    const position = this.screenToWorldInto(\n      this.projectionScratch,\n      screenX,\n      screenY,\n    );\n    return new Vec2(position.x, position.y);\n  }\n\n  /** Copy a screen-to-world projection into caller-owned scratch. */\n  screenToWorldInto(\n    out: Vec2Buffer,\n    screenX: number,\n    screenY: number,\n  ): Vec2Buffer {\n    this.getEffectivePositionInto(out);\n    const zoom = this.effectiveZoom;\n    const rotation = this.effectiveRotation;\n    const x = (screenX - this.viewportWidth / 2) * (1 / zoom);\n    const y = (screenY - this.viewportHeight / 2) * (1 / zoom);\n    const cos = Math.cos(rotation);\n    const sin = Math.sin(rotation);\n    return out.set(out.x + (x * cos - y * sin), out.y + (x * sin + y * cos));\n  }\n\n  /**\n   * Convert world coordinates to screen coordinates.\n   *\n   * The conversion uses the camera's own transform, not any layer's. Content\n   * on a layer bound with a ratio below `1` (parallax, dampened zoom) is\n   * drawn somewhere else on screen than this result says.\n   */\n  worldToScreen(worldX: number, worldY: number): Vec2 {\n    const position = this.worldToScreenInto(\n      this.projectionScratch,\n      worldX,\n      worldY,\n    );\n    return new Vec2(position.x, position.y);\n  }\n\n  /** Copy a world-to-screen projection into caller-owned scratch. */\n  worldToScreenInto(\n    out: Vec2Buffer,\n    worldX: number,\n    worldY: number,\n  ): Vec2Buffer {\n    this.getEffectivePositionInto(out);\n    const zoom = this.effectiveZoom;\n    const rotation = this.effectiveRotation;\n    const x = worldX - out.x;\n    const y = worldY - out.y;\n    const cos = Math.cos(-rotation);\n    const sin = Math.sin(-rotation);\n    return out.set(\n      (x * cos - y * sin) * zoom + this.viewportWidth / 2,\n      (x * sin + y * cos) * zoom + this.viewportHeight / 2,\n    );\n  }\n\n  /**\n   * Resolve bindings for this camera against the given render tree.\n   *\n   * Every world-space layer (`LayerDef.space === \"world\"`, the default) is\n   * bound at full strength. Screen-space layers — declared with\n   * `space: \"screen\"` or auto-provisioned by plugins via\n   * `ensureLayer(def, { space: \"screen\" })`, e.g. the UI layer — are skipped\n   * so they stay fixed to the viewport.\n   *\n   * An entry in `bindings` replaces the binding for the layer it names; an\n   * entry naming a screen-space layer, or a layer the tree does not hold,\n   * is added. With `autoBind: false` the camera binds exactly the entries in\n   * `bindings` and nothing else — the only way to leave a world-space layer\n   * untransformed, since a binding with all three ratios at `0` centres the\n   * layer on the viewport instead.\n   *\n   * Called once per camera per frame, so a layer created after the camera\n   * spawned is bound on the next frame.\n   */\n  getResolvedBindings(tree: SceneRenderTree): readonly CameraBinding[] {\n    const explicit = this.bindings;\n    if (!this.autoBind) return explicit ?? NO_BINDINGS;\n\n    const worldLayers = tree\n      .getAll()\n      .filter((layer) => layer.space === \"world\");\n    if (!explicit || explicit.length === 0) {\n      return worldLayers.map((layer) => ({\n        layer: layer.name,\n        translateRatio: 1,\n      }));\n    }\n\n    const resolved = new Map<string, CameraBinding>();\n    for (const layer of worldLayers) {\n      resolved.set(layer.name, { layer: layer.name, translateRatio: 1 });\n    }\n    for (const binding of explicit) resolved.set(binding.layer, binding);\n    return [...resolved.values()];\n  }\n  onDestroy(): void {\n    this.modifiers._destroy();\n  }\n}\n","import { Component, Vec2, Vec2Buffer } from \"@yagejs/core\";\nimport { CameraComponent, CAMERA_REFERENCE_DT } from \"./CameraComponent.js\";\nimport type { CameraFollowOptions } from \"./CameraComponent.js\";\nimport { resolveFollowTarget } from \"./FollowTarget.js\";\nimport type { FollowTarget } from \"./FollowTarget.js\";\nimport { assertFiniteNumber } from \"./internal/validate.js\";\n\n/**\n * Camera follow behavior. Smoothly moves `CameraComponent.position`\n * toward the target's world position each frame.\n */\nexport class CameraFollow extends Component {\n  private readonly cam = this.sibling(CameraComponent);\n  private readonly targetScratch = new Vec2Buffer();\n  private target: FollowTarget | null = null;\n  private smoothing = 1;\n  private offset: Vec2 = Vec2.ZERO;\n  private deadzone: { halfWidth: number; halfHeight: number } | null = null;\n\n  /** Start following a target. */\n  start(target: FollowTarget, options?: CameraFollowOptions): void {\n    const smoothing = options?.smoothing ?? 1;\n    assertFiniteNumber(\"CameraFollow.start\", \"smoothing\", smoothing, 0);\n    this.target = target;\n    this.smoothing = smoothing;\n    this.offset = options?.offset\n      ? new Vec2(options.offset.x, options.offset.y)\n      : Vec2.ZERO;\n    this.deadzone = options?.deadzone ?? null;\n    if (options?.snap) this.snapToTarget();\n  }\n\n  /** Stop following any target. */\n  stop(): void {\n    this.target = null;\n    this.deadzone = null;\n  }\n\n  /**\n   * Place the camera on its target right away, offset included. Skips both\n   * the smoothing ease and the deadzone, so the camera cuts rather than\n   * glides — use it after a teleport (room change, respawn). Any deadzone\n   * applies again from the next frame. Does nothing without a target.\n   */\n  snapToTarget(): void {\n    const targetPos = this.targetPosition();\n    if (targetPos) this.cam.position = new Vec2(targetPos.x, targetPos.y);\n  }\n\n  update(dt: number): void {\n    const targetPos = this.targetPosition();\n    if (!targetPos) return;\n\n    if (this.deadzone) {\n      const dx = targetPos.x - this.cam.position.x;\n      const dy = targetPos.y - this.cam.position.y;\n      const hw = this.deadzone.halfWidth;\n      const hh = this.deadzone.halfHeight;\n\n      let moveX = 0;\n      let moveY = 0;\n      if (dx > hw) moveX = dx - hw;\n      else if (dx < -hw) moveX = dx + hw;\n      if (dy > hh) moveY = dy - hh;\n      else if (dy < -hh) moveY = dy + hh;\n\n      if (moveX === 0 && moveY === 0) return;\n\n      const destination = this.targetScratch.set(\n        this.cam.position.x + moveX,\n        this.cam.position.y + moveY,\n      );\n      const t = frameLerp(this.smoothing, dt);\n      this.cam.position = this.cam.position.lerp(destination, t);\n    } else {\n      const t = frameLerp(this.smoothing, dt);\n      this.cam.position = this.cam.position.lerp(targetPos, t);\n    }\n  }\n\n  /** Current target world position with the follow offset applied. */\n  private targetPosition(): Vec2Buffer | null {\n    if (!this.target) return null;\n    const pos = resolveFollowTarget(this.target, this, this.targetScratch);\n    if (!pos) return null;\n    return pos.set(pos.x + this.offset.x, pos.y + this.offset.y);\n  }\n}\n\nfunction frameLerp(smoothing: number, dt: number): number {\n  if (smoothing >= 1) return 1;\n  return 1 - Math.pow(1 - smoothing, dt / CAMERA_REFERENCE_DT);\n}\n","import { Entity, Transform, Vec2 } from \"@yagejs/core\";\nimport type { Component, Vec2Like, Vec2Buffer } from \"@yagejs/core\";\nimport { attributed, boundaryFor } from \"./internal/attribution.js\";\n\n/**\n * What a follow tracks each frame, always in world coordinates. An `Entity`\n * or a `Transform` reads the current `worldPosition`, so a target parented\n * under a moving platform tracks where it actually is on screen; a `Vec2Like`\n * is a fixed world coord; a function is called every frame and may compute\n * any world coord (the midpoint of two entities, a position along a path).\n */\nexport type FollowTarget = Entity | Transform | Vec2Like | (() => Vec2Like);\n\n/**\n * Current world position of a follow target, or `undefined` when the target\n * cannot supply one (an entity without a `Transform`). A function target runs\n * through the error boundary, so a throw is attributed to the game's callback.\n * @internal\n */\nexport function resolveFollowTarget(\n  target: FollowTarget,\n  owner: Component,\n  out: Vec2Buffer,\n): Vec2Buffer | undefined {\n  if (typeof target === \"function\") {\n    const name = (owner.entity as Entity | undefined)?.name;\n    const position = attributed(\n      boundaryFor(owner),\n      {\n        kind: \"Follow target function\",\n        ...(name !== undefined ? { entity: name } : {}),\n      },\n      target,\n    );\n    return Vec2.copyInto(out, position);\n  }\n  if (target instanceof Entity)\n    return target.tryGet(Transform)?.getWorldPositionInto(out);\n  if (target instanceof Transform) return target.getWorldPositionInto(out);\n  return Vec2.copyInto(out, target);\n}\n","import { ErrorBoundaryKey } from \"@yagejs/core\";\nimport type {\n  CallbackErrorInfo,\n  Component,\n  Entity,\n  ErrorBoundary,\n} from \"@yagejs/core\";\n\n/**\n * The boundary a component's throws should be attributed to, or `undefined`\n * before the component is wired to a scene (tests, a component built but not\n * yet added).\n * @internal\n */\nexport function boundaryFor(component: Component): ErrorBoundary | undefined {\n  return (component.entity as Entity | undefined)?.tryScene?.context.tryResolve(\n    ErrorBoundaryKey,\n  );\n}\n\n/**\n * Run a game-supplied callback that returns a value, attributing a throw to\n * the callback rather than to the engine code that called it. The error is\n * recorded, logged, and rethrown — nothing is swallowed.\n * @internal\n */\nexport function attributed<T>(\n  boundary: ErrorBoundary | undefined,\n  info: CallbackErrorInfo,\n  fn: () => T,\n): T {\n  if (!boundary) return fn();\n  let value!: T;\n  boundary.wrapCallback(() => {\n    value = fn();\n  }, info);\n  return value;\n}\n\n/**\n * Run a game-supplied callback that returns nothing, naming the component's\n * entity and scene in the report. The callback reaches `wrapCallback`\n * directly, so an async callback's rejection is attributed too.\n *\n * The boundary is resolved per call rather than cached: a component can be\n * constructed before its entity joins a scene, and the entity's scene can\n * change afterwards. An entity with no scene has no boundary to report\n * through, so the callback runs directly and its throw propagates unchanged.\n * @internal\n */\nexport function runAttributed(\n  component: Component,\n  kind: string,\n  fn: () => void,\n): void {\n  const boundary = boundaryFor(component);\n  if (!boundary) {\n    fn();\n    return;\n  }\n  const entity = component.entity as Entity | undefined;\n  const scene = entity?.tryScene;\n  boundary.wrapCallback(fn, {\n    kind,\n    ...(entity?.name !== undefined ? { entity: entity.name } : {}),\n    ...(scene?.name !== undefined ? { scene: scene.name } : {}),\n  });\n}\n","/**\n * Numeric gates for game-supplied values entering engine state. Each throws a\n * plain `Error` naming the input and the constraint it violates, before the\n * value is stored — a `NaN` written into position, zoom, or an animation\n * clock never recovers, since every later comparison against it is false.\n * @internal\n */\n\n/** Throws unless `value` is a finite number that is at least `min`. */\nexport function assertFiniteNumber(\n  context: string,\n  name: string,\n  value: number,\n  min?: number,\n): void {\n  const belowMin = min !== undefined && value < min;\n  if (Number.isFinite(value) && !belowMin) return;\n  const constraint =\n    min === undefined ? \"must be finite\" : `must be finite and >= ${min}`;\n  throw new Error(`${context}: ${name} ${constraint}, got ${value}.`);\n}\n\n/** Throws unless `value` is a finite number above 0. */\nexport function assertPositiveNumber(\n  context: string,\n  name: string,\n  value: number,\n): void {\n  if (Number.isFinite(value) && value > 0) return;\n  throw new Error(`${context}: ${name} must be finite and > 0, got ${value}.`);\n}\n\n/** Throws unless `value` is a whole count, at least 1. */\nexport function assertCount(\n  context: string,\n  name: string,\n  value: number,\n): void {\n  if (Number.isInteger(value) && value >= 1) return;\n  throw new Error(`${context}: ${name} must be an integer >= 1, got ${value}.`);\n}\n","import { Component, Vec2 } from \"@yagejs/core\";\nimport type { CameraShakeOptions } from \"./CameraComponent.js\";\nimport { CameraComponent } from \"./CameraComponent.js\";\nimport type { CameraModifierHandle } from \"./CameraModifiers.js\";\n\n/**\n * Camera shake behavior. Writes one removable contribution to\n * `CameraComponent.modifiers` and leaves the base position unchanged.\n */\nexport class CameraShake extends Component {\n  private intensity = 0;\n  private duration = 0;\n  private elapsed = 0;\n  private decay = 0;\n\n  private _offset: Vec2 = Vec2.ZERO;\n  private modifier: CameraModifierHandle | undefined;\n\n  /** Current shake offset contributed through `CameraComponent.modifiers`. */\n  get offset(): Vec2 {\n    return this._offset;\n  }\n\n  /**\n   * Start a screen shake effect. `intensity` is the maximum displacement per\n   * axis in **world pixels**, so what the player sees scales with zoom — the\n   * same intensity moves twice as far on screen at zoom 2.\n   */\n  start(\n    intensity: number,\n    duration: number,\n    options?: CameraShakeOptions,\n  ): void {\n    this.stop();\n    this.intensity = intensity;\n    this.duration = duration;\n    this.elapsed = 0;\n    this.decay = options?.decay ?? 0;\n    if (duration > 0 && intensity !== 0) this.ensureModifier();\n  }\n\n  /** Cancel the current shake immediately. */\n  stop(): void {\n    this.setOffset(Vec2.ZERO);\n    this.modifier?.remove();\n    this.modifier = undefined;\n    this.duration = 0;\n    this.intensity = 0;\n    this.elapsed = 0;\n    this.decay = 0;\n  }\n\n  update(dt: number): void {\n    if (this.duration <= 0) return;\n\n    this.elapsed += dt;\n    if (this.elapsed >= this.duration) {\n      this.stop();\n      return;\n    }\n\n    let currentIntensity = this.intensity;\n    if (this.decay > 0) {\n      const progress = this.elapsed / this.duration;\n      currentIntensity = Math.max(\n        0,\n        this.intensity * (1 - progress * this.decay),\n      );\n    }\n\n    // `elapsed` is in seconds; the multiplier sets the oscillation frequency.\n    const phase = this.elapsed * 100;\n    this.setOffset(\n      new Vec2(\n        Math.sin(phase * 7.3) * currentIntensity,\n        Math.cos(phase * 13.7) * currentIntensity,\n      ),\n    );\n  }\n  onDestroy(): void {\n    this.modifier?.remove();\n    this.modifier = undefined;\n  }\n\n  private setOffset(offset: Vec2): void {\n    this._offset = offset;\n    this.modifier?.setPosition(offset);\n  }\n\n  private ensureModifier(): void {\n    this.modifier ??= this.sibling(CameraComponent).modifiers.add({\n      position: this._offset,\n    });\n  }\n}\n","import { Component } from \"@yagejs/core\";\nimport type { EasingFunction } from \"@yagejs/core\";\nimport { CameraComponent } from \"./CameraComponent.js\";\nimport { attributed, boundaryFor } from \"./internal/attribution.js\";\nimport {\n  assertFiniteNumber,\n  assertPositiveNumber,\n} from \"./internal/validate.js\";\n\nconst LINEAR_EASING: EasingFunction = (t) => t;\n\n/**\n * Camera zoom animation behavior. Smoothly interpolates\n * `CameraComponent.zoom` toward a target value over a duration.\n */\nexport class CameraZoom extends Component {\n  private readonly cam = this.sibling(CameraComponent);\n  private zoomFrom = 1;\n  private zoomTarget = 1;\n  private duration = 0;\n  private elapsed = 0;\n  private easing: EasingFunction = LINEAR_EASING;\n  private zooming = false;\n\n  /** Start a zoom animation. */\n  start(target: number, duration: number, easing?: EasingFunction): void {\n    assertPositiveNumber(\"CameraZoom.start\", \"target\", target);\n    assertFiniteNumber(\"CameraZoom.start\", \"duration\", duration, 0);\n    this.zoomFrom = this.cam.zoom;\n    this.zoomTarget = target;\n    this.duration = duration;\n    this.elapsed = 0;\n    this.easing = easing ?? LINEAR_EASING;\n    this.zooming = true;\n  }\n\n  update(dt: number): void {\n    if (!this.zooming) return;\n\n    this.elapsed += dt;\n    if (this.elapsed >= this.duration) {\n      this.cam.zoom = this.zoomTarget;\n      this.zooming = false;\n      return;\n    }\n\n    const rawT = this.elapsed / this.duration;\n    const easing = this.easing;\n    const easedT = attributed(\n      boundaryFor(this),\n      { kind: \"Camera zoom easing\", entity: this.entity.name },\n      () => easing(rawT),\n    );\n    this.cam.zoom = this.zoomFrom + (this.zoomTarget - this.zoomFrom) * easedT;\n  }\n}\n","import { Component, Vec2 } from \"@yagejs/core\";\nimport { CameraComponent } from \"./CameraComponent.js\";\nimport type { CameraBounds } from \"./CameraComponent.js\";\n\n/**\n * Camera bounds clamping. Restricts `CameraComponent.position` to a bounding\n * rectangle each frame. Runs after every camera behaviour that moves or zooms\n * the camera, so the clamp sees this frame's position and zoom rather than\n * last frame's.\n */\nexport class CameraBoundsComponent extends Component {\n  static updatePriority = 10;\n\n  private readonly cam = this.sibling(CameraComponent);\n\n  bounds: CameraBounds | undefined;\n\n  update(): void {\n    if (!this.bounds) return;\n\n    const halfViewW = this.cam.viewportWidth / (2 * this.cam.zoom);\n    const halfViewH = this.cam.viewportHeight / (2 * this.cam.zoom);\n\n    const minCamX = this.bounds.minX + halfViewW;\n    const maxCamX = this.bounds.maxX - halfViewW;\n    const minCamY = this.bounds.minY + halfViewH;\n    const maxCamY = this.bounds.maxY - halfViewH;\n\n    const clampedX =\n      minCamX > maxCamX\n        ? (this.bounds.minX + this.bounds.maxX) / 2\n        : Math.max(minCamX, Math.min(maxCamX, this.cam.position.x));\n    const clampedY =\n      minCamY > maxCamY\n        ? (this.bounds.minY + this.bounds.maxY) / 2\n        : Math.max(minCamY, Math.min(maxCamY, this.cam.position.y));\n    this.cam.position = new Vec2(clampedX, clampedY);\n  }\n}\n","import { Vec2 } from \"@yagejs/core\";\nimport type { Vec2Like } from \"@yagejs/core\";\n\n/** Initial values for one camera contribution. */\nexport interface CameraModifierOptions {\n  /** Additive world-space position offset. Default: `{ x: 0, y: 0 }`. */\n  position?: Vec2Like;\n  /** Additive rotation in radians. Default: `0`. */\n  rotation?: number;\n  /** Multiplicative zoom factor. Default: `1`. */\n  zoom?: number;\n}\n\n/** Removable contribution owned by a {@link CameraModifierHost}. */\nexport interface CameraModifierHandle {\n  /** Whether this contribution is still active. */\n  readonly active: boolean;\n  /** Replace this contribution's additive position offset. */\n  setPosition(offset: Vec2Like): void;\n  /** Replace this contribution's additive rotation offset. */\n  setRotation(radians: number): void;\n  /** Replace this contribution's multiplicative zoom factor. */\n  setZoom(factor: number): void;\n  /** Remove only this contribution. Safe to call more than once. */\n  remove(): void;\n}\n\ninterface CameraContribution {\n  active: boolean;\n  position: Vec2;\n  rotation: number;\n  zoom: number;\n}\n\n/** Transient contributions combined with a camera's authoritative values. */\nexport class CameraModifierHost {\n  private readonly contributions = new Set<CameraContribution>();\n  private _positionOffset = Vec2.ZERO;\n  private _rotationOffset = 0;\n  private _zoomFactor = 1;\n  private destroyed = false;\n\n  /** Combined additive world-space position offset. */\n  get positionOffset(): Vec2 {\n    return this._positionOffset;\n  }\n\n  /** Combined additive rotation offset in radians. */\n  get rotationOffset(): number {\n    return this._rotationOffset;\n  }\n\n  /** Combined multiplicative zoom factor. */\n  get zoomFactor(): number {\n    return this._zoomFactor;\n  }\n\n  /** Number of active contributions. */\n  get size(): number {\n    return this.contributions.size;\n  }\n\n  /** Add one independently removable camera contribution. */\n  add(options: CameraModifierOptions = {}): CameraModifierHandle {\n    this.assertLive();\n    const contribution: CameraContribution = {\n      active: true,\n      position: options.position\n        ? toFiniteVec2(options.position, \"position\")\n        : Vec2.ZERO,\n      rotation:\n        options.rotation === undefined\n          ? 0\n          : finite(options.rotation, \"rotation\"),\n      zoom: options.zoom === undefined ? 1 : positive(options.zoom, \"zoom\"),\n    };\n    this.contributions.add(contribution);\n    this.recompute();\n\n    return {\n      get active() {\n        return contribution.active;\n      },\n      setPosition: (offset) => {\n        if (!contribution.active) return;\n        contribution.position = toFiniteVec2(offset, \"position\");\n        this.recompute();\n      },\n      setRotation: (radians) => {\n        if (!contribution.active) return;\n        contribution.rotation = finite(radians, \"rotation\");\n        this.recompute();\n      },\n      setZoom: (factor) => {\n        if (!contribution.active) return;\n        contribution.zoom = positive(factor, \"zoom\");\n        this.recompute();\n      },\n      remove: () => {\n        if (!contribution.active) return;\n        contribution.active = false;\n        this.contributions.delete(contribution);\n        this.recompute();\n      },\n    };\n  }\n\n  /** @internal Invalidates every outstanding handle during component teardown. */\n  _destroy(): void {\n    if (this.destroyed) return;\n    this.destroyed = true;\n    for (const contribution of this.contributions) contribution.active = false;\n    this.contributions.clear();\n    this._positionOffset = Vec2.ZERO;\n    this._rotationOffset = 0;\n    this._zoomFactor = 1;\n  }\n\n  private assertLive(): void {\n    if (this.destroyed) {\n      throw new Error(\"CameraModifierHost: the owning camera was destroyed.\");\n    }\n  }\n\n  private recompute(): void {\n    let position = Vec2.ZERO;\n    let rotation = 0;\n    let zoom = 1;\n    for (const contribution of this.contributions) {\n      position = position.add(contribution.position);\n      rotation += contribution.rotation;\n      zoom *= contribution.zoom;\n    }\n    this._positionOffset = position;\n    this._rotationOffset = rotation;\n    this._zoomFactor = zoom;\n  }\n}\n\nfunction toFiniteVec2(value: Vec2Like, label: string): Vec2 {\n  return new Vec2(finite(value.x, `${label}.x`), finite(value.y, `${label}.y`));\n}\n\nfunction positive(value: number, label: string): number {\n  finite(value, label);\n  if (value <= 0) {\n    throw new Error(\n      `CameraModifierHost: ${label} must be greater than 0, got ${value}.`,\n    );\n  }\n  return value;\n}\n\nfunction finite(value: number, label: string): number {\n  if (!Number.isFinite(value)) {\n    throw new Error(\n      `CameraModifierHost: ${label} must be finite, got ${value}.`,\n    );\n  }\n  return value;\n}\n","import { Component, Transform, Vec2Buffer, devWarn } from \"@yagejs/core\";\nimport type { Entity } from \"@yagejs/core\";\nimport { Container } from \"pixi.js\";\nimport type { LayerSortFn } from \"./LayerDef.js\";\nimport type { DisplayContainer } from \"./public-types.js\";\nimport type { SceneRenderTree } from \"./SceneRenderTree.js\";\nimport { SceneRenderTreeKey } from \"./SceneRenderTree.js\";\n\n/**\n * Contract a single-display-object visual component satisfies: a layer name\n * plus the Pixi object it renders. All five built-in visual components\n * (`SpriteComponent`, `GraphicsComponent`, `AnimatedSpriteComponent`,\n * `TextComponent`, `SplitTextComponent`) expose it through their `renderObject`\n * getter, and `SortGroupComponent` uses it to gather a subtree's visuals\n * without importing the concrete classes (which would create an import cycle).\n *\n * It's also the extension point for custom visual components: implement\n * `renderObject` + `layerName`, and route through {@link resolveRenderParent}\n * in `onAdd`, and the component takes part in sort groups exactly like the\n * built-ins.\n */\nexport interface LayerRenderable {\n  /** Name of the layer this component renders into. */\n  readonly layerName: string;\n  /** The underlying Pixi display object. */\n  readonly renderObject: DisplayContainer;\n}\n\n/**\n * Duck-typed check for {@link LayerRenderable}. Visual components expose a\n * `renderObject` getter; nothing else in the engine does, so a positive match\n * is reliable without an `instanceof` against five concrete classes.\n */\nfunction isLayerRenderable(\n  component: Component,\n): component is Component & LayerRenderable {\n  const candidate = component as Partial<LayerRenderable>;\n  return (\n    typeof candidate.layerName === \"string\" && candidate.renderObject != null\n  );\n}\n\n/**\n * Resolve the Pixi container a visual should render into: the nearest ancestor\n * {@link SortGroupComponent} bound to the same layer, or the layer container\n * itself when there is no enclosing group. Walks the entity hierarchy starting\n * at `entity` (inclusive), so a visual on a group-owning entity joins that\n * group.\n *\n * When `layerName` names a layer the scene never declared in its `layers`,\n * this warns in dev (naming the entity, the missing layer, and the scene) and\n * falls back to the scene's default layer, so the visual still renders instead\n * of throwing or silently disappearing.\n *\n * The built-in visual components call this in their `onAdd`. A custom visual\n * component (one implementing {@link LayerRenderable}) should do the same, so\n * it joins an enclosing group on its initial add rather than only when the\n * group next re-homes its subtree:\n *\n * ```ts\n * onAdd() {\n *   const tree = this.use(SceneRenderTreeKey);\n *   resolveRenderParent(this.entity, this.layerName, tree).addChild(\n *     this.renderObject,\n *   );\n * }\n * ```\n */\nexport function resolveRenderParent(\n  entity: Entity,\n  layerName: string,\n  tree: SceneRenderTree,\n): DisplayContainer {\n  let current: Entity | null = entity;\n  while (current) {\n    const group = current.tryGet(SortGroupComponent);\n    if (group && group.layer === layerName) return group.container;\n    current = current.parent;\n  }\n  const layer = tree.tryGet(layerName);\n  if (layer) return layer.container;\n  devWarn(\n    `Entity \"${entity.name}\" renders on layer \"${layerName}\" which scene ` +\n      `\"${entity.tryScene?.name ?? \"<unattached>\"}\" does not declare in its ` +\n      `\\`layers\\`; falling back to the \"default\" layer. Add ` +\n      `\\`{ name: \"${layerName}\", order: 0 }\\` to the scene's \\`layers\\`.`,\n  );\n  return tree.defaultLayer.container;\n}\n\n/**\n * Container → owning sort group, maintained as groups enter and leave the\n * scene tree (see `SortGroupComponent`'s `onAdd` / `onDestroy`). Lets\n * `DisplaySystem` recognise a group container during its per-frame sort pass\n * with an O(1) lookup and no per-frame allocation.\n */\nconst groupByContainer = new WeakMap<DisplayContainer, SortGroupComponent>();\n\n/**\n * The sort group that owns `container`, or `undefined` for a plain visual.\n *\n * @internal Used by `DisplaySystem.applyLayerSort`.\n */\nexport function sortGroupForContainer(\n  container: DisplayContainer,\n): SortGroupComponent | undefined {\n  return groupByContainer.get(container);\n}\n\n/** Options for {@link SortGroupComponent}. */\nexport interface SortGroupComponentOptions {\n  /**\n   * Layer the group renders into. Visuals in the entity's subtree that target\n   * this same layer are gathered into the group; visuals targeting a different\n   * layer are left alone (so a child's shadow can still live on a separate\n   * `\"ground\"` layer). Default: `\"default\"`.\n   */\n  layer?: string;\n  /**\n   * Optional depth key for ordering the group's own members. Default (unset):\n   * members keep insertion order, and any member's manually-set `zIndex` is\n   * honoured — a real stacking context, matching Unity's `SortingGroup`. Pass\n   * `ySort` (or any {@link LayerSortFn}) to instead order members by position\n   * among themselves, while the group as a whole still sorts as one unit\n   * against the rest of the layer.\n   */\n  innerSort?: LayerSortFn;\n}\n\n/**\n * Renders an entity's subtree of visuals as a single depth unit.\n *\n * Under a layer `sort` (e.g. `ySort`) every sprite is otherwise a flat child of\n * the layer with its own independent depth key, so a multi-part entity — a body\n * plus an offset held item, or a parent plus child entities — can be split when\n * an unrelated entity's key falls between its parts. A `SortGroupComponent`\n * gives the entity its own Pixi sub-container: the members sort *within* the\n * group, and the group sorts as **one unit** against the rest of the layer\n * (keyed off the group-owning entity's own sprite, falling back to its\n * `Transform` position when it has no sprite of its own).\n *\n * The group container is kept at identity/origin, so members hold their normal\n * world transforms — adding a group changes paint **order** only, never\n * position, rotation, or scale (those stay composed by the ECS `Transform`).\n *\n * ```ts\n * class Knight extends Entity {\n *   setup() {\n *     this.add(new Transform({ position: { x: 200, y: 200 } }));\n *     this.add(new SortGroupComponent({ layer: \"world\" }));\n *     this.add(new SpriteComponent({ texture: \"knight-body\", layer: \"world\" }));\n *     // Child sprites on the \"world\" layer join the group automatically:\n *     this.spawnChild(\"weapon\", Weapon); // a sprite offset toward the camera\n *     this.spawnChild(\"plume\", Plume);\n *   }\n * }\n * ```\n *\n * Add the component **before** the visuals it should capture (it also re-homes\n * any already-present subtree visuals when added late).\n * A `SortGroupComponent` on a descendant entity starts its own independent\n * unit rather than nesting inside the ancestor's.\n */\nexport class SortGroupComponent extends Component {\n  private readonly positionScratch = new Vec2Buffer();\n  /** The group's Pixi container. Kept at identity; holds the member visuals. */\n  readonly container: DisplayContainer;\n  /** Layer this group renders into. */\n  readonly layer: string;\n  /** Depth key for intra-group member order, or `undefined` for insertion order. */\n  innerSort: LayerSortFn | undefined;\n  /** Lazily-created stand-in used for the group's sort key when the owning\n   * entity has no sprite of its own. */\n  private _proxy: DisplayContainer | undefined;\n\n  constructor(options?: SortGroupComponentOptions) {\n    super();\n    this.layer = options?.layer ?? \"default\";\n    this.innerSort = options?.innerSort;\n    this.container = new Container();\n    this.container.label = `sort-group:${this.layer}`;\n    // Members order by their own zIndex; default 0 keeps stable insertion order\n    // and lets a member opt above/below its siblings with a manual zIndex.\n    this.container.sortableChildren = true;\n  }\n\n  onAdd(): void {\n    groupByContainer.set(this.container, this);\n    const tree = this.use(SceneRenderTreeKey);\n    // Each group is its own unit at the layer level — even a group nested under\n    // another entity's group. Transform parenting (ECS) and sort grouping\n    // stay independent.\n    tree.get(this.layer).container.addChild(this.container);\n    this.regroup();\n  }\n\n  onDestroy(): void {\n    groupByContainer.delete(this.container);\n    // Return members to the layer so removing the grouping doesn't orphan\n    // sprites; on scene teardown they're destroyed by their own components\n    // immediately after. Destroy only the wrapper, never its (borrowed) children.\n    const layerContainer = this.tryLayerContainer();\n    if (layerContainer) {\n      for (const child of [...this.container.children]) {\n        layerContainer.addChild(child);\n      }\n    } else {\n      this.container.removeChildren();\n    }\n    this.container.destroy({ children: false });\n  }\n\n  /**\n   * Compute this group's depth key under the layer `sort`. Samples the\n   * group-owning entity's own visual (so `ySort`/`ySortBy` read a real sprite's\n   * position and offset); falls back to a proxy at the entity's `Transform`\n   * world position when the owner renders nothing itself.\n   *\n   * @internal Called by `DisplaySystem` each Render phase.\n   */\n  resolveSortKey(sort: LayerSortFn): number {\n    const sample = this.findSample();\n    if (sample) return sort(sample);\n\n    const proxy = (this._proxy ??= new Container());\n    const transform = this.entity.tryGet(Transform);\n    if (transform) {\n      const world = transform.getWorldPositionInto(this.positionScratch);\n      proxy.position.set(world.x, world.y);\n    }\n    return sort(proxy);\n  }\n\n  /** The owning entity's own visual on this layer, if currently in the group. */\n  private findSample(): DisplayContainer | undefined {\n    for (const component of this.entity.getAll()) {\n      if (\n        isLayerRenderable(component) &&\n        component.layerName === this.layer &&\n        component.renderObject.parent === this.container\n      ) {\n        return component.renderObject;\n      }\n    }\n    return undefined;\n  }\n\n  /** Gather every subtree visual on this layer into the group container. */\n  private regroup(): void {\n    this.collect(this.entity, true);\n  }\n\n  private collect(entity: Entity, isRoot: boolean): void {\n    if (!isRoot && entity.tryGet(SortGroupComponent)?.layer === this.layer) {\n      // A descendant group owns its own subtree as a separate unit.\n      return;\n    }\n    for (const component of entity.getAll()) {\n      if (component === this) continue;\n      if (isLayerRenderable(component) && component.layerName === this.layer) {\n        this.container.addChild(component.renderObject);\n      }\n    }\n    for (const child of entity.children.values()) {\n      this.collect(child, false);\n    }\n  }\n\n  private tryLayerContainer(): DisplayContainer | undefined {\n    if (!this.entity.tryScene) return undefined;\n    return this.use(SceneRenderTreeKey).tryGet(this.layer)?.container;\n  }\n}\n","import {\n  Component,\n  makeEntityScopedQueue,\n  markPointerConsumeContainer,\n  unmarkPointerConsumeContainer,\n} from \"@yagejs/core\";\nimport { computeRenderFacet } from \"./internal/renderFacet.js\";\nimport type { RenderFacetSnapshot } from \"./internal/renderFacet.js\";\nimport { SceneRenderTreeKey } from \"./SceneRenderTree.js\";\nimport { resolveRenderParent } from \"./SortGroupComponent.js\";\nimport { EffectsHost } from \"./effects/EffectsHost.js\";\nimport { VisualModifierHost } from \"./VisualModifiers.js\";\nimport { attachMask } from \"./masks/attachMask.js\";\nimport type { MaskFactory } from \"./masks/MaskFactory.js\";\nimport type { MaskHandle } from \"./masks/MaskHandle.js\";\nimport type {\n  BlendMode,\n  ColorValue,\n  DestroyOptions,\n  DisplayContainer,\n} from \"./public-types.js\";\n\n/**\n * Pixi event-mode + pointer-consume config shared by every visual\n * component's `interactive` option.\n */\nexport interface VisualInteractiveOptions {\n  /**\n   * Pixi event mode. Defaults to `\"static\"` when the option object is set\n   * (interactive, no children-recurse cost). Pass `\"dynamic\"` for Pixi\n   * behavior where event-mode propagates to children automatically.\n   */\n  eventMode?: \"static\" | \"dynamic\";\n  /** When `true`, claim pointer events landing on this container. Default `false`. */\n  consumeOnInteraction?: boolean;\n}\n\n/** Options shared by all five visual components. */\nexport interface VisualComponentOptions {\n  /** Render layer name. Default: \"default\". */\n  layer?: string;\n  /** Initial visibility. Default: true. */\n  visible?: boolean;\n  /** Tint color. */\n  tint?: ColorValue;\n  /** Alpha (opacity). Default: 1. */\n  alpha?: number;\n  /**\n   * How this object's pixels combine with what is drawn beneath it.\n   * Default: `\"inherit\"` — the mode of the nearest ancestor that sets one,\n   * which is `\"normal\"` unless a parent changed it. Set it explicitly to\n   * `\"normal\"` inside a group that uses another mode. See {@link BlendMode}\n   * for the modes that need `import \"pixi.js/advanced-blend-modes\"`.\n   */\n  blendMode?: BlendMode;\n  /**\n   * Make the container interactive. When set, Pixi `eventMode` is configured\n   * so it participates in pointer hit-testing — required for any\n   * `.on(\"pointerdown\", ...)` listener to fire.\n   *\n   * `consumeOnInteraction: true` additionally marks it as a UI-input surface\n   * (via `@yagejs/core`'s consume registry), so a `pointerdown` landing on it\n   * is auto-claimed by `@yagejs/input` — preventing the same press from also\n   * firing gameplay action-map edges like `MouseLeft`. Default `false`: an\n   * interactive container still propagates the action, matching the \"I want\n   * both Pixi events AND the action map\" use case.\n   */\n  interactive?: VisualInteractiveOptions;\n  /**\n   * Draw this visual after the scene's layers, outside every layer- and\n   * scene-scope effect and mask. Default `false`. See\n   * {@link VisualComponent.renderAboveEffects}.\n   */\n  renderAboveEffects?: boolean;\n}\n\n/**\n * Shared base for the renderer's five visual components (Sprite,\n * AnimatedSprite, Graphics, Text, SplitText). Carries the render-layer field,\n * lazy effects host, mask lifecycle, scene-tree parenting, and the generic\n * visible/tint/alpha/interactive vocabulary — every underlying Pixi display\n * object supports all four directly on `Container`, so this operates on\n * `renderObject` rather than each subclass re-deriving the same three-liner.\n *\n * Subclasses provide `renderObject` (their concrete Pixi display object,\n * created in their own constructor) and call {@link applyVisualOptions} once\n * it exists — options can't be applied during `VisualComponent`'s own\n * constructor since `renderObject` isn't assigned yet at that point.\n */\nexport abstract class VisualComponent extends Component {\n  /** The underlying Pixi display object. */\n  abstract readonly renderObject: DisplayContainer;\n  private _layerName: string;\n  /**\n   * Component-scope effects host. `.fx.addEffect(...)` attaches a filter to\n   * this component's render object; the effect is torn down automatically\n   * when the entity or component is destroyed. `.fx.findEffect(definition)`\n   * recovers the handle for the first matching effect.\n   */\n  readonly fx: EffectsHost;\n  /**\n   * Render-only transform, opacity, and visibility contributions. Modifiers\n   * combine with the component's live base values and are never serialized.\n   */\n  readonly modifiers: VisualModifierHost;\n  private _mask: MaskHandle | undefined;\n  /**\n   * The visibility the game asked for. The Pixi flag is this AND the\n   * component being effectively enabled, so hiding a sprite by hand survives\n   * a `setActive(false)` / `setActive(true)` cycle.\n   */\n  private _userVisible = true;\n  /** The alpha requested by the game, before transient opacity modifiers. */\n  private _userAlpha = 1;\n  /** See {@link renderAboveEffects}. */\n  private _renderAboveEffects = false;\n\n  constructor(layer: string | undefined) {\n    super();\n    this._layerName = layer ?? \"default\";\n    this.fx = new EffectsHost(\n      () => this.renderObject,\n      \"component\",\n      () => makeEntityScopedQueue(this.entity),\n    );\n    this.modifiers = new VisualModifierHost(() => this.applyAppearance());\n  }\n\n  /**\n   * Apply the shared visible/tint/alpha/interactive options to\n   * `renderObject`. Call once from the subclass constructor, after the\n   * concrete Pixi object is created.\n   */\n  protected applyVisualOptions(options: VisualComponentOptions): void {\n    if (options.visible !== undefined) this.visible = options.visible;\n    if (options.tint !== undefined) this.renderObject.tint = options.tint;\n    if (options.alpha !== undefined) this.alpha = options.alpha;\n    if (options.blendMode !== undefined) {\n      this.renderObject.blendMode = options.blendMode;\n    }\n    if (options.interactive) {\n      this.renderObject.eventMode = options.interactive.eventMode ?? \"static\";\n      if (options.interactive.consumeOnInteraction) {\n        markPointerConsumeContainer(this.renderObject);\n      }\n    }\n    if (options.renderAboveEffects !== undefined) {\n      this.renderAboveEffects = options.renderAboveEffects;\n    }\n  }\n\n  /**\n   * Whether this visual draws after the scene's layers, outside every layer-\n   * and scene-scope effect and mask, while keeping its logical parent\n   * (position, alpha, visibility, camera). Screen-scope effects still cover\n   * it, and hit testing follows the logical tree — a UI element drawn under\n   * an escaped visual still receives the pointer first.\n   *\n   * Set while the visual is out of the display tree — in a subclass\n   * constructor, or on a component not yet added — it records the flag and\n   * applies it on add.\n   */\n  get renderAboveEffects(): boolean {\n    return this._renderAboveEffects;\n  }\n\n  set renderAboveEffects(value: boolean) {\n    if (value === this._renderAboveEffects) return;\n    this._renderAboveEffects = value;\n    // Out of the tree: `onAdd` applies the recorded flag when the object\n    // reaches its layer.\n    if (!this.renderObject.parent) return;\n    const tree = this.use(SceneRenderTreeKey);\n    if (value) tree.renderAboveEffects(this.renderObject);\n    else tree.renderWithEffects(this.renderObject);\n  }\n\n  /** The layer this visual draws on. See {@link setLayer}. */\n  get layerName(): string {\n    return this._layerName;\n  }\n\n  /**\n   * Draw this visual on another layer.\n   *\n   * Called before the component reaches the display tree — in a subclass\n   * constructor, or on a component that has not been added yet — it records\n   * the name and nothing else. Called afterwards it detaches the render\n   * object and re-parents it through the same resolution `onAdd` uses, so a\n   * `SortGroupComponent` on the new layer still claims it.\n   *\n   * The visual joins its new parent last, which on a layer with no `sort`\n   * means it draws in front of everything already there.\n   */\n  setLayer(name: string): void {\n    if (name === this._layerName) return;\n    this._layerName = name;\n    // Nothing to move while the object is out of the tree: `onAdd` reads the\n    // name when it puts the object in.\n    if (!this.renderObject.parent) return;\n    this.renderObject.removeFromParent();\n    resolveRenderParent(\n      this.entity,\n      name,\n      this.use(SceneRenderTreeKey),\n    ).addChild(this.renderObject);\n  }\n\n  /** Set the container's tint color. */\n  set tint(color: ColorValue) {\n    this.renderObject.tint = color;\n  }\n\n  /** Get the container's tint color. */\n  get tint(): number {\n    return this.renderObject.tint;\n  }\n\n  /** Set the container's alpha (opacity). */\n  set alpha(alpha: number) {\n    this._userAlpha = alpha;\n    this.applyAppearance();\n  }\n\n  /** Get the requested alpha before transient opacity modifiers. */\n  get alpha(): number {\n    return this._userAlpha;\n  }\n\n  /** Set how the container combines with what is drawn beneath it. */\n  set blendMode(mode: BlendMode) {\n    this.renderObject.blendMode = mode;\n  }\n\n  /** Get the container's blend mode. */\n  get blendMode(): BlendMode {\n    return this.renderObject.blendMode;\n  }\n\n  /**\n   * Set the container's visibility. Written while the entity is dormant, it\n   * is remembered and applied when the entity is activated.\n   */\n  set visible(value: boolean) {\n    this._userVisible = value;\n    this.applyAppearance();\n  }\n\n  /** Get the requested visibility, whatever the entity's activeness. */\n  get visible(): boolean {\n    return this._userVisible;\n  }\n\n  /**\n   * Attach a mask to this component's render object, replacing any existing\n   * mask. Returns a handle for inverse toggling, redraw (graphicsMask), or\n   * removal. The mask is torn down automatically when the component is\n   * destroyed.\n   */\n  setMask(factory: MaskFactory): MaskHandle {\n    this._mask?.remove();\n    this._mask = attachMask(this.renderObject, factory, this);\n    return this._mask;\n  }\n\n  /** Detach and destroy the current mask, if any. */\n  clearMask(): void {\n    this._mask?.remove();\n    this._mask = undefined;\n  }\n\n  /** The currently attached mask handle, if any. */\n  get mask(): MaskHandle | undefined {\n    return this._mask;\n  }\n\n  /**\n   * Derived render facet for the Inspector — world-space `bounds` and the\n   * component's own (local, non-inherited) `visible` flag, computed on\n   * demand from the live render object. See {@link computeRenderFacet} for\n   * the bounds coordinate space.\n   */\n  inspectRender(): RenderFacetSnapshot {\n    return computeRenderFacet(this.renderObject);\n  }\n\n  onAdd(): void {\n    const tree = this.use(SceneRenderTreeKey);\n    resolveRenderParent(this.entity, this._layerName, tree).addChild(\n      this.renderObject,\n    );\n    if (this._renderAboveEffects) tree.renderAboveEffects(this.renderObject);\n    // A component is never effectively enabled during `onAdd` — `onEnable`\n    // runs right after, and only for an active entity. Start hidden so a\n    // component added to a dormant entity doesn't inherit Pixi's\n    // visible-by-default and show before it should.\n    this.renderObject.visible = false;\n  }\n\n  onEnable(): void {\n    this.applyAppearance();\n  }\n\n  onDisable(): void {\n    this.renderObject.visible = false;\n  }\n\n  onDestroy(): void {\n    unmarkPointerConsumeContainer(this.renderObject);\n    this.modifiers._destroy();\n    this.fx.destroy();\n    this._mask?.remove();\n    this.renderObject.removeFromParent();\n    this.renderObject.destroy(this.destroyOptions());\n  }\n\n  /**\n   * Pixi destroy options passed to `renderObject.destroy()`. Default:\n   * `undefined` (Pixi's own defaults). Override for a component whose\n   * destroy must cascade to children (SplitText's per-segment display\n   * objects).\n   */\n  protected destroyOptions(): DestroyOptions | undefined {\n    return undefined;\n  }\n\n  /** Apply the final alpha after transient modifiers. */\n  protected applyEffectiveAlpha(alpha: number): void {\n    this.renderObject.alpha = alpha;\n  }\n\n  private applyAppearance(): void {\n    this.applyEffectiveAlpha(this._userAlpha * this.modifiers.opacityFactor);\n    this.renderObject.visible =\n      this._userVisible && this.effectiveEnabled && this.modifiers.visible;\n  }\n}\n","import { Point } from \"pixi.js\";\nimport type { Container } from \"pixi.js\";\n\n/**\n * Derived, read-only rendered-geometry and visibility facet for a graphical\n * component, computed on demand from its live display object. For a\n * typewriter, this reports the glyphs and bounds actually painted rather than\n * only the component's declared full string.\n *\n * Owned by `@yagejs/renderer`: the renderer publishes it into the Inspector\n * snapshot through the generic {@link InspectorFacetContributor} seam (see\n * {@link RenderFacetContributor}), so `@yagejs/core` stays agnostic of any\n * rendering concept.\n *\n * `bounds` / `visible` are the cross-cutting fields. A component reporting\n * richer, mode-specific state (e.g. per-glyph visibility for split text) widens\n * the shape via the `Extra` parameter on its own side.\n */\nexport type RenderFacetSnapshot<Extra = unknown> = {\n  /**\n   * Axis-aligned bounding box of the component's geometry, in world space (the\n   * same coordinate space the Inspector reports for `entity.transform` — pixels,\n   * before camera/viewport projection). Measured from the geometry itself, so a\n   * sized-but-hidden object still reports its real box; `null` means there is no\n   * measurable geometry at all (an empty `Graphics`, a zero-area object), NOT\n   * that the object is hidden. Read {@link RenderFacetSnapshot.visible} for the\n   * hidden/shown state.\n   */\n  bounds: { x: number; y: number; width: number; height: number } | null;\n  /**\n   * The component's own (local, non-inherited) visibility flag at snapshot\n   * time. A hidden ancestor (e.g. a parent/layer container set invisible) is\n   * NOT folded in — read the relevant parent separately if you need the fully\n   * resolved on-screen state.\n   */\n  visible: boolean;\n} & Extra;\n\n/**\n * Renderer-internal contract a graphical component implements to publish its\n * render facet. {@link RenderFacetContributor} duck-types this off each\n * component when building an Inspector snapshot.\n */\nexport interface RenderInspectable {\n  inspectRender(): RenderFacetSnapshot;\n}\n\n/**\n * Compute the {@link RenderFacetSnapshot} for a single display object.\n *\n * ## Bounds coordinate space\n *\n * The returned `bounds` are an axis-aligned box in **world space** — the same\n * coordinate space the Inspector reports for `entity.transform` (pixels,\n * before the camera and the responsive `fit` transform are applied). In the\n * YAGE render tree the camera transform lives on the *layer container*\n * (`DisplaySystem` writes `layer.container.position/scale/rotation`), while each\n * display object is positioned straight from `transform.worldPosition`. So a\n * display object's *own local transform* is exactly its placement within world\n * space, and mapping its local-space bounds through that matrix yields a\n * world-space box — independent of the camera, which lives one level up on the\n * parent. (This holds with or without a parent: an unparented object's local\n * transform is still its world placement, so no special-case is needed.)\n *\n * ## Why `getLocalBounds()` and not `getBounds()`\n *\n * `getBounds()` measures in *global* (screen) space and, critically, returns an\n * empty box for an object whose own `visible` flag is `false` — Pixi refuses to\n * measure invisible subtrees. That conflates \"currently hidden\" with \"paints\n * nothing\", which is exactly what `bounds: null` must NOT mean. `getLocalBounds()`\n * measures the object's own geometry in local space and does *not* gate the root\n * object on visibility (only its invisible children are skipped), so a real\n * sized-but-hidden object still reports its true box. `bounds` is therefore\n * `null` only when the object genuinely has no measurable geometry (an empty\n * `Graphics`, a zero-area display object) — never merely because it is hidden.\n * Read `visible` for the hidden/shown state.\n *\n * `getLocalBounds()` also keeps the snapshot read-only against the wider scene\n * graph: unlike `getBounds()` (which walks every ancestor calling\n * `updateLocalTransform`), it never touches ancestors, and the lone\n * `updateLocalTransform()` we call refreshes only *this* object's matrix\n * (cached / a no-op when already current).\n *\n * ## Visibility\n *\n * `visible` is the display object's *own* (local) flag — Pixi v8 has no public\n * world-resolved visibility getter, so a hidden ancestor (e.g. a layer\n * container with `visible = false`) is NOT reflected here. For the per-glyph\n * reveal use case this is exactly right (glyphs are toggled directly); callers\n * hiding an entity via a parent container should read the parent's flag too.\n */\nexport function computeRenderFacet(\n  displayObject: Container,\n): RenderFacetSnapshot {\n  return {\n    bounds: computeWorldBounds(displayObject),\n    visible: displayObject.visible,\n  };\n}\n\nfunction computeWorldBounds(\n  displayObject: Container,\n): RenderFacetSnapshot[\"bounds\"] {\n  const local = displayObject.getLocalBounds();\n  if (\n    !isFiniteBox(local.x, local.y, local.width, local.height) ||\n    local.width === 0 ||\n    local.height === 0\n  ) {\n    // No measurable geometry: an empty Graphics, or a collapsed axis — a\n    // zero-area shape (a line, a zero-height rect) paints nothing fillable. This\n    // is the ONLY reason bounds are null — a hidden-but-sized object falls through.\n    return null;\n  }\n\n  // Refresh only this object's local matrix (no-op when already current), then\n  // map the four local-space corners into the parent/world frame and re-derive\n  // an AABB. A single-corner mapping is insufficient under rotation or\n  // non-uniform scale, so we transform all four and take the extents.\n  displayObject.updateLocalTransform();\n  const toWorld = displayObject.localTransform;\n  const corners = [\n    new Point(local.x, local.y),\n    new Point(local.x + local.width, local.y),\n    new Point(local.x + local.width, local.y + local.height),\n    new Point(local.x, local.y + local.height),\n  ].map((corner) => toWorld.apply(corner));\n\n  let minX = Infinity;\n  let minY = Infinity;\n  let maxX = -Infinity;\n  let maxY = -Infinity;\n  for (const corner of corners) {\n    if (corner.x < minX) minX = corner.x;\n    if (corner.y < minY) minY = corner.y;\n    if (corner.x > maxX) maxX = corner.x;\n    if (corner.y > maxY) maxY = corner.y;\n  }\n\n  if (!isFiniteBox(minX, minY, maxX - minX, maxY - minY)) {\n    return null;\n  }\n\n  return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n}\n\nfunction isFiniteBox(\n  x: number,\n  y: number,\n  width: number,\n  height: number,\n): boolean {\n  return (\n    Number.isFinite(x) &&\n    Number.isFinite(y) &&\n    Number.isFinite(width) &&\n    Number.isFinite(height)\n  );\n}\n","import { Vec2 } from \"@yagejs/core\";\nimport type { Vec2Like } from \"@yagejs/core\";\n\n/** Initial values for one transform contribution. */\nexport interface VisualTransformModifierOptions {\n  /** Additive offset in the render layer's coordinate space. Default: `{ x: 0, y: 0 }`. */\n  position?: Vec2Like;\n  /** Additive rotation in radians. Default: `0`. */\n  rotation?: number;\n  /** Multiplicative scale. A number applies to both axes. Default: `1`. */\n  scale?: number | Vec2Like;\n}\n\n/** Removable transform contribution owned by a {@link VisualModifierHost}. */\nexport interface VisualTransformModifierHandle {\n  /** Whether this contribution is still active. */\n  readonly active: boolean;\n  /** Replace this contribution's additive position offset. */\n  setPosition(offset: Vec2Like): void;\n  /** Replace this contribution's additive rotation offset. */\n  setRotation(radians: number): void;\n  /** Replace this contribution's multiplicative scale factor. */\n  setScale(scale: number | Vec2Like): void;\n  /** Remove only this contribution. Safe to call more than once. */\n  remove(): void;\n}\n\n/** Removable opacity contribution owned by a {@link VisualModifierHost}. */\nexport interface VisualOpacityModifierHandle {\n  /** Whether this contribution is still active. */\n  readonly active: boolean;\n  /** Replace this contribution's multiplicative opacity factor. */\n  setFactor(factor: number): void;\n  /** Remove only this contribution. Safe to call more than once. */\n  remove(): void;\n}\n\n/** Removable visibility contribution owned by a {@link VisualModifierHost}. */\nexport interface VisualVisibilityModifierHandle {\n  /** Whether this contribution is still active. */\n  readonly active: boolean;\n  /** Replace whether this contribution permits the visual to be shown. */\n  setVisible(visible: boolean): void;\n  /** Remove only this contribution. Safe to call more than once. */\n  remove(): void;\n}\n\ninterface TransformContribution {\n  active: boolean;\n  position: Vec2;\n  rotation: number;\n  scale: Vec2;\n}\n\ninterface OpacityContribution {\n  active: boolean;\n  factor: number;\n}\n\ninterface VisibilityContribution {\n  active: boolean;\n  visible: boolean;\n}\n\n/**\n * Transient render-only contributions for one visual component.\n *\n * The host stores offsets and factors, never the component's base values.\n * `DisplaySystem` combines the current world transform with these values every\n * render, so gameplay and physics remain authoritative while modifiers are\n * active.\n */\nexport class VisualModifierHost {\n  private readonly transforms = new Set<TransformContribution>();\n  private readonly opacities = new Set<OpacityContribution>();\n  private readonly visibilities = new Set<VisibilityContribution>();\n  private _positionOffset = Vec2.ZERO;\n  private _rotationOffset = 0;\n  private _scaleFactor = Vec2.ONE;\n  private _opacityFactor = 1;\n  private _visible = true;\n  private destroyed = false;\n\n  constructor(private readonly appearanceChanged?: () => void) {}\n\n  /** Combined additive position offset. */\n  get positionOffset(): Vec2 {\n    return this._positionOffset;\n  }\n\n  /** Combined additive rotation offset in radians. */\n  get rotationOffset(): number {\n    return this._rotationOffset;\n  }\n\n  /** Combined multiplicative scale factor. */\n  get scaleFactor(): Vec2 {\n    return this._scaleFactor;\n  }\n\n  /** Combined multiplicative opacity factor. */\n  get opacityFactor(): number {\n    return this._opacityFactor;\n  }\n\n  /** Whether every active visibility contribution permits drawing. */\n  get visible(): boolean {\n    return this._visible;\n  }\n\n  /** Number of active contributions across every visual property. */\n  get size(): number {\n    return this.transforms.size + this.opacities.size + this.visibilities.size;\n  }\n\n  /** Whether at least one transform contribution is active. */\n  get hasTransformModifiers(): boolean {\n    return this.transforms.size > 0;\n  }\n\n  /** Add one independently removable transform contribution. */\n  addTransform(\n    options: VisualTransformModifierOptions = {},\n  ): VisualTransformModifierHandle {\n    this.assertLive();\n    const contribution: TransformContribution = {\n      active: true,\n      position: options.position\n        ? toFiniteVec2(options.position, \"position\")\n        : Vec2.ZERO,\n      rotation:\n        options.rotation === undefined\n          ? 0\n          : finite(options.rotation, \"rotation\"),\n      scale: resolveScale(options.scale),\n    };\n    this.transforms.add(contribution);\n    this.recomputeTransform();\n\n    return {\n      get active() {\n        return contribution.active;\n      },\n      setPosition: (offset) => {\n        if (!contribution.active) return;\n        contribution.position = toFiniteVec2(offset, \"position\");\n        this.recomputeTransform();\n      },\n      setRotation: (radians) => {\n        if (!contribution.active) return;\n        contribution.rotation = finite(radians, \"rotation\");\n        this.recomputeTransform();\n      },\n      setScale: (scale) => {\n        if (!contribution.active) return;\n        contribution.scale = resolveScale(scale);\n        this.recomputeTransform();\n      },\n      remove: () => {\n        if (!contribution.active) return;\n        contribution.active = false;\n        this.transforms.delete(contribution);\n        this.recomputeTransform();\n      },\n    };\n  }\n\n  /** Add one independently removable opacity factor. */\n  addOpacity(factor = 1): VisualOpacityModifierHandle {\n    this.assertLive();\n    const contribution: OpacityContribution = {\n      active: true,\n      factor: finite(factor, \"opacity factor\"),\n    };\n    this.opacities.add(contribution);\n    this.recomputeOpacity();\n\n    return {\n      get active() {\n        return contribution.active;\n      },\n      setFactor: (value) => {\n        if (!contribution.active) return;\n        contribution.factor = finite(value, \"opacity factor\");\n        this.recomputeOpacity();\n      },\n      remove: () => {\n        if (!contribution.active) return;\n        contribution.active = false;\n        this.opacities.delete(contribution);\n        this.recomputeOpacity();\n      },\n    };\n  }\n\n  /** Add one independently removable visibility condition. */\n  addVisibility(visible = true): VisualVisibilityModifierHandle {\n    this.assertLive();\n    const contribution: VisibilityContribution = { active: true, visible };\n    this.visibilities.add(contribution);\n    this.recomputeVisibility();\n\n    return {\n      get active() {\n        return contribution.active;\n      },\n      setVisible: (value) => {\n        if (!contribution.active) return;\n        contribution.visible = value;\n        this.recomputeVisibility();\n      },\n      remove: () => {\n        if (!contribution.active) return;\n        contribution.active = false;\n        this.visibilities.delete(contribution);\n        this.recomputeVisibility();\n      },\n    };\n  }\n\n  /** @internal Invalidates every outstanding handle during component teardown. */\n  _destroy(): void {\n    if (this.destroyed) return;\n    this.destroyed = true;\n    for (const contribution of this.transforms) contribution.active = false;\n    for (const contribution of this.opacities) contribution.active = false;\n    for (const contribution of this.visibilities) contribution.active = false;\n    this.transforms.clear();\n    this.opacities.clear();\n    this.visibilities.clear();\n    this._positionOffset = Vec2.ZERO;\n    this._rotationOffset = 0;\n    this._scaleFactor = Vec2.ONE;\n    this._opacityFactor = 1;\n    this._visible = true;\n  }\n\n  private assertLive(): void {\n    if (this.destroyed) {\n      throw new Error(\n        \"VisualModifierHost: the owning component was destroyed.\",\n      );\n    }\n  }\n\n  private recomputeTransform(): void {\n    let position = Vec2.ZERO;\n    let rotation = 0;\n    let scale = Vec2.ONE;\n    for (const contribution of this.transforms) {\n      position = position.add(contribution.position);\n      rotation += contribution.rotation;\n      scale = scale.multiply(contribution.scale);\n    }\n    this._positionOffset = position;\n    this._rotationOffset = rotation;\n    this._scaleFactor = scale;\n  }\n\n  private recomputeOpacity(): void {\n    let opacity = 1;\n    for (const contribution of this.opacities) opacity *= contribution.factor;\n    this._opacityFactor = opacity;\n    this.appearanceChanged?.();\n  }\n\n  private recomputeVisibility(): void {\n    let visible = true;\n    for (const contribution of this.visibilities) {\n      visible &&= contribution.visible;\n    }\n    this._visible = visible;\n    this.appearanceChanged?.();\n  }\n}\n\nfunction resolveScale(scale: number | Vec2Like | undefined): Vec2 {\n  if (scale === undefined) return Vec2.ONE;\n  if (typeof scale === \"number\") {\n    const value = finite(scale, \"scale\");\n    return new Vec2(value, value);\n  }\n  return toFiniteVec2(scale, \"scale\");\n}\n\nfunction toFiniteVec2(value: Vec2Like, label: string): Vec2 {\n  return new Vec2(finite(value.x, `${label}.x`), finite(value.y, `${label}.y`));\n}\n\nfunction finite(value: number, label: string): number {\n  if (!Number.isFinite(value)) {\n    throw new Error(\n      `VisualModifierHost: ${label} must be finite, got ${value}.`,\n    );\n  }\n  return value;\n}\n","import type { Component } from \"@yagejs/core\";\nimport type { DisplayContainer as Container } from \"../public-types.js\";\nimport type { MaskHandle } from \"./MaskHandle.js\";\nimport type { MaskFactory } from \"./MaskFactory.js\";\nimport { attributed, boundaryFor } from \"../internal/attribution.js\";\n\n/**\n * Apply a mask to any pixi `Container`. Returns a {@link MaskHandle} that\n * controls the mask's lifecycle and inverse state.\n *\n * The high-level `setMask` methods on the visual components, `RenderLayer`,\n * and `SceneRenderTree` are thin wrappers around this — use those when you\n * have one of those targets in hand. Reach for `attachMask` directly when\n * you only have a raw `Container` (e.g. `UIPanel` masking its own root).\n *\n * Idempotent on `remove()`. The handle's `setInverse` toggles\n * pixi v8 `Container.setMask({ mask, inverse })`.\n *\n * Pass `owner` when a component holds the mask: a throw from the game's own\n * draw callback is then attributed to the callback (readable via\n * `Inspector.getErrors().callbackErrors`) instead of to whichever engine pass\n * triggered the redraw.\n */\nexport function attachMask(\n  target: Container,\n  factory: MaskFactory,\n  owner?: Component,\n): MaskHandle {\n  const info = { kind: \"Mask draw callback\" };\n  const boundary = owner ? boundaryFor(owner) : undefined;\n  const mask = attributed(boundary, info, factory);\n  let inverse = mask.inverse;\n  let removed = false;\n\n  if (mask.attachToTarget) {\n    target.addChild(mask.node);\n  }\n  target.setMask({ mask: mask.node, inverse });\n\n  return {\n    remove(): void {\n      if (removed) return;\n      removed = true;\n      // Pixi v8 quirk: `setMask({ mask: null, inverse: false })` only\n      // updates the cached `_maskOptions`; it leaves the live mask effect\n      // pointing at our (about-to-be-destroyed) node, so the next render\n      // dereferences a freed `_gpuData` and crashes. Direct\n      // `target.mask = null` runs the proper teardown — `removeEffect()`\n      // + `MaskEffectManager.returnMaskEffect()` — which is what we want.\n      target.mask = null;\n      if (mask.owned) {\n        // Detach BEFORE destroy so the previous parent (could be the\n        // target, the target's parent, or a layer container) drops its\n        // children-list reference before pixi tears down GPU resources.\n        // `Container.destroy()` does call `removeFromParent`, but doing\n        // it explicitly first avoids any lingering structure-changed\n        // refs in the render group from the same frame.\n        mask.node.removeFromParent();\n        mask.node.destroy();\n      }\n    },\n    setInverse(on: boolean): void {\n      if (removed) return;\n      inverse = on;\n      target.setMask({ mask: mask.node, inverse });\n    },\n    get inverse(): boolean {\n      return inverse;\n    },\n    redraw(): void {\n      if (removed || !mask.redraw) return;\n      const redraw = mask.redraw.bind(mask);\n      attributed(boundary, info, redraw);\n    },\n  };\n}\n","import { Vec2Buffer } from \"@yagejs/core\";\nimport type { DisplayContainer } from \"./public-types.js\";\nimport type { CameraBinding, CameraComponent } from \"./CameraComponent.js\";\n\nconst positionScratch = new Vec2Buffer();\n\n/** Apply a camera's effective pose. Without a camera, restore identity. */\nexport function syncCameraTransform(\n  target: DisplayContainer,\n  camera?: CameraComponent,\n  binding?: CameraBinding,\n): void {\n  if (!camera) {\n    target.position.set(0, 0);\n    target.scale.set(1, 1);\n    target.rotation = 0;\n    return;\n  }\n  const scale = 1 + (camera.effectiveZoom - 1) * (binding?.scaleRatio ?? 1);\n  const rotation = camera.effectiveRotation * (binding?.rotateRatio ?? 1);\n  const position = camera.getEffectivePositionInto(positionScratch);\n  const translationScale = scale * (binding?.translateRatio ?? 1);\n  const x = position.x * translationScale;\n  const y = position.y * translationScale;\n  const cos = Math.cos(-rotation);\n  const sin = Math.sin(-rotation);\n  target.position.set(\n    camera.viewportWidth / 2 - (x * cos - y * sin),\n    camera.viewportHeight / 2 - (x * sin + y * cos),\n  );\n  target.scale.set(scale);\n  target.rotation = -rotation;\n}\n","import type { Component, InspectorFacetContributor } from \"@yagejs/core\";\nimport type {\n  RenderFacetSnapshot,\n  RenderInspectable,\n} from \"./internal/renderFacet.js\";\n\n// Type the renderer's `render` namespace on the Inspector's open facet map, so\n// `snapshot.entities[].facets?.render` / `component.facets?.render` are typed as\n// a RenderFacetSnapshot for anyone importing @yagejs/renderer. Core declares\n// only the generic index signature and stays agnostic of what `render` means.\ndeclare module \"@yagejs/core\" {\n  interface InspectorFacets {\n    /**\n     * Rendered geometry (world-space bounds) + local visibility, contributed by\n     * the renderer. `SplitTextComponent` publishes a wider\n     * {@link import(\"./SplitTextComponent.js\").SplitTextRenderFacet} under this\n     * same key — cast when you need its `glyphs` / `visibleText` extras.\n     */\n    render?: RenderFacetSnapshot;\n  }\n}\n\n/**\n * Publishes each graphical component's {@link RenderFacetSnapshot} into the\n * Inspector snapshot via the generic facet-contributor seam. Registered by\n * {@link import(\"./RendererPlugin.js\").RendererPlugin} on install and removed on\n * teardown — the renderer owns the \"render\" namespace and the policy for which\n * component represents an entity, keeping `@yagejs/core` free of any rendering\n * concept.\n */\nexport class RenderFacetContributor implements InspectorFacetContributor {\n  readonly namespace = \"render\";\n\n  /**\n   * Duck-type the renderer-internal `inspectRender()` contract off a component.\n   * Returns `undefined` for components that don't paint (no hook). A hook that\n   * throws is caught by the Inspector, which omits the facet.\n   */\n  inspectComponent(component: Component): RenderFacetSnapshot | undefined {\n    const hook = (component as Partial<RenderInspectable>).inspectRender;\n    return typeof hook === \"function\" ? hook.call(component) : undefined;\n  }\n\n  /**\n   * Surface the first painted component's facet at the entity level — the\n   * common single-sprite/text case. `componentFacets` arrives in component\n   * insertion order (with `undefined` gaps for non-graphical components).\n   */\n  inspectEntity(\n    componentFacets: readonly unknown[],\n  ): RenderFacetSnapshot | undefined {\n    return (\n      (componentFacets.find((facet) => facet != null) as\n        | RenderFacetSnapshot\n        | undefined) ?? undefined\n    );\n  }\n}\n","import { Vec2 } from \"@yagejs/core\";\nimport { Graphics } from \"pixi.js\";\nimport type { Application, Container } from \"pixi.js\";\nimport type { FitMode } from \"./types.js\";\n\n/** The stage transform currently applied by a {@link FitController}. */\nexport interface FitTransform {\n  scaleX: number;\n  scaleY: number;\n  /** Screen-space pixel offset where virtual (0, 0) lands on the canvas. */\n  offsetX: number;\n  offsetY: number;\n}\n\n/** A rectangle in virtual-space pixels. */\nexport interface VirtualRect {\n  x: number;\n  y: number;\n  width: number;\n  height: number;\n}\n\n/**\n * A rectangle in canvas CSS pixels (what the DOM sees). Structurally identical\n * to {@link VirtualRect}; distinguished at the type level so signatures can\n * signal which coordinate space a rect lives in.\n */\nexport type CanvasRect = VirtualRect;\n\n/**\n * Runaway-feedback guard thresholds. A fit host whose own height is\n * content-driven has no stable size: the canvas the controller sizes to it\n * becomes its tallest child, so the host's measured size is a function of the\n * canvas size. The renderer sets `display:block` on the canvas, which\n * collapses the common ~4px inline-descender gap to zero so the loop\n * converges. These bound the residual cases it can't (a vertical margin on\n * the canvas, sub-pixel / devicePixelRatio rounding, an extra wrapper\n * element): once the host has grown by at most `RUNAWAY_STEP_PX` on this many\n * consecutive observer fires with the other axis held stable, treat it as a\n * runaway, freeze auto-resize, and warn once. The thresholds are deliberately\n * loose — a real resize jumps by more than `RUNAWAY_STEP_PX` or stops growing\n * (resetting the streak) long before `RUNAWAY_LIMIT`, while a true feedback\n * loop never stops.\n */\nconst RUNAWAY_STEP_PX = 16;\nconst RUNAWAY_LIMIT = 64;\n\n/**\n * Owns the world-root transform + canvas size under responsive fit.\n *\n * On `start()`, observes the target element and re-applies both\n * `app.renderer.resize(hostW, hostH)` and a scale/position transform on the\n * supplied container that maps the virtual rectangle into the new canvas\n * according to the fit mode. Guards against zero-size firings (detached /\n * `display:none` hosts).\n *\n * The container we transform must NOT be `app.stage` itself — Pixi's stage\n * is the active render group and `@pixi/tilemap`'s pipe double-applies any\n * transform on the active render group. The renderer plugin owns a\n * dedicated `_worldRoot` child of stage for this purpose; constructors in\n * tests pass any plain Container.\n *\n * With a null target (headless environments, tests without a DOM), applies\n * the transform once against a fixed host size and installs no observer.\n */\nexport class FitController {\n  private observer: ResizeObserver | null = null;\n  private transform: FitTransform = {\n    scaleX: 1,\n    scaleY: 1,\n    offsetX: 0,\n    offsetY: 0,\n  };\n  private canvasW: number;\n  private canvasH: number;\n  /**\n   * Mask applied to the stage under `letterbox` to clip rendering to the\n   * virtual rect. Lives as a child of `stage` so it inherits the same\n   * scale/offset transform — drawing it at virtual-local `(0,0,vW,vH)`\n   * lands it exactly on the virtual rect after the transform is applied.\n   * `null` outside `letterbox` mode (no clipping needed for `expand`,\n   * `cover`, or `stretch`).\n   */\n  private letterboxMask: Graphics | null = null;\n  /**\n   * Runaway-feedback guard. See {@link RUNAWAY_LIMIT}. `runawayStreak` counts\n   * consecutive small monotonic host growths on one axis; on crossing the\n   * limit `frozen` latches (auto-resize stops) and `runawayWarned` debounces\n   * the console warning. All three reset whenever observation (re)starts.\n   */\n  private runawayStreak = 0;\n  private runawayWarned = false;\n  private frozen = false;\n\n  constructor(\n    private readonly app: Application,\n    private readonly stage: Container,\n    private readonly virtualWidth: number,\n    private readonly virtualHeight: number,\n    private mode: FitMode,\n    private target: HTMLElement | null,\n    initialCanvasW: number,\n    initialCanvasH: number,\n  ) {\n    this.canvasW = initialCanvasW;\n    this.canvasH = initialCanvasH;\n  }\n\n  /**\n   * Apply the current host size synchronously, then start observing it for\n   * subsequent resizes. Idempotent: a second call while already observing\n   * is a no-op. Pair with {@link stop} to disconnect.\n   * With a null target, applies once using the initial canvas size and does\n   * not observe.\n   */\n  start(): void {\n    if (this.observer) return;\n\n    this.runawayStreak = 0;\n    this.runawayWarned = false;\n    this.frozen = false;\n\n    if (!this.target) {\n      this.apply(this.canvasW, this.canvasH);\n      return;\n    }\n\n    const { width, height } = this.measure(this.target);\n    if (width > 0 && height > 0) {\n      this.apply(width, height);\n    }\n\n    if (typeof ResizeObserver === \"undefined\") return;\n    this.observer = new ResizeObserver((entries) => {\n      const entry = entries[0];\n      if (!entry) return;\n      // Read the host's content box, not its border box. The canvas is a\n      // block-level child (the renderer forces `display:block`) laid out\n      // inside the host content box; measuring the host's border-box would\n      // re-add padding+border to the canvas on every apply and the observer\n      // would chase its own output. contentBoxSize already excludes both.\n      const size = entry.contentBoxSize?.[0];\n      const w = size ? size.inlineSize : entry.contentRect.width;\n      const h = size ? size.blockSize : entry.contentRect.height;\n      if (w <= 0 || h <= 0) return;\n      if (w === this.canvasW && h === this.canvasH) {\n        this.runawayStreak = 0;\n        return;\n      }\n      if (this.frozen) return;\n\n      // A host with no bounded height of its own is sized by the canvas we\n      // just put in it, so each apply can make it measure slightly larger\n      // and the observer re-fires forever. `display:block` kills the common\n      // ~4px descender; this catches the residual (canvas margin, sub-pixel\n      // / DPR rounding, wrapper elements): a small monotonic growth on one\n      // axis with the other axis exactly stable, sustained for the limit.\n      const dw = w - this.canvasW;\n      const dh = h - this.canvasH;\n      const creeping =\n        (dh > 0 && dh <= RUNAWAY_STEP_PX && w === this.canvasW) ||\n        (dw > 0 && dw <= RUNAWAY_STEP_PX && h === this.canvasH);\n      this.runawayStreak = creeping ? this.runawayStreak + 1 : 0;\n\n      if (this.runawayStreak >= RUNAWAY_LIMIT) {\n        this.frozen = true;\n        if (!this.runawayWarned) {\n          this.runawayWarned = true;\n          // The two `creeping` branches are mutually exclusive (`w ===\n          // canvasW` forces `dw === 0`, contradicting `dw > 0`), so a\n          // positive `dh` unambiguously identifies the runaway axis.\n          const axis = dh > 0 ? \"height\" : \"width\";\n          console.warn(\n            `FitController: the fit container's ${axis} is being driven ` +\n              `by the canvas inside it — it grows on every resize and ` +\n              `never settles. The renderer sets \\`display:block\\` on the ` +\n              `canvas to prevent this; the loop persists when the ` +\n              `container has no bounded ${axis} of its own. Give it an ` +\n              `explicit or bounded ${axis} (e.g. \\`${axis}:100%\\` under a ` +\n              `sized ancestor, or \\`max-${axis}\\`). Auto-resize frozen at ` +\n              `${this.canvasW}×${this.canvasH}px.`,\n          );\n        }\n        return;\n      }\n\n      this.apply(w, h);\n    });\n    this.observer.observe(this.target);\n  }\n\n  /**\n   * Stop observing and release the ResizeObserver. Removes the letterbox\n   * mask from the stage so re-installing fit (or destroying the renderer)\n   * doesn't leave a dangling Graphics child. Leaves the scale/position\n   * transform on the stage untouched.\n   */\n  stop(): void {\n    this.observer?.disconnect();\n    this.observer = null;\n    this.removeLetterboxMask();\n  }\n\n  /** Update mode and/or target without rebuilding the controller. */\n  reconfigure(mode: FitMode, target: HTMLElement | null): void {\n    const targetChanged = target !== this.target;\n    this.mode = mode;\n    this.target = target;\n    if (targetChanged) {\n      this.observer?.disconnect();\n      this.observer = null;\n      this.start();\n    } else if (this.target) {\n      const { width, height } = this.measure(this.target);\n      if (width > 0 && height > 0) this.apply(width, height);\n    } else {\n      this.apply(this.canvasW, this.canvasH);\n    }\n  }\n\n  get currentMode(): FitMode {\n    return this.mode;\n  }\n\n  get currentTarget(): HTMLElement | null {\n    return this.target;\n  }\n\n  get canvasSize(): { width: number; height: number } {\n    return { width: this.canvasW, height: this.canvasH };\n  }\n\n  get currentTransform(): Readonly<FitTransform> {\n    return this.transform;\n  }\n\n  /** CSS pixels relative to the canvas → virtual-space pixels. */\n  canvasToVirtual(x: number, y: number): Vec2 {\n    const { scaleX, scaleY, offsetX, offsetY } = this.transform;\n    return new Vec2((x - offsetX) / scaleX, (y - offsetY) / scaleY);\n  }\n\n  /** Virtual-space pixels → CSS pixels relative to the canvas. */\n  virtualToCanvas(x: number, y: number): Vec2 {\n    const { scaleX, scaleY, offsetX, offsetY } = this.transform;\n    return new Vec2(x * scaleX + offsetX, y * scaleY + offsetY);\n  }\n\n  /**\n   * Where the declared virtual rectangle sits on the canvas, in CSS pixels.\n   * Useful for positioning DOM overlays over the play area, cropping\n   * screenshots to gameplay, or mapping CSS-coord picking regions. Derived\n   * from the stage transform: `{ x: offsetX, y: offsetY, width: vW*scaleX,\n   * height: vH*scaleY }`.\n   */\n  get virtualCanvasRect(): CanvasRect {\n    const { scaleX, scaleY, offsetX, offsetY } = this.transform;\n    return {\n      x: offsetX,\n      y: offsetY,\n      width: this.virtualWidth * scaleX,\n      height: this.virtualHeight * scaleY,\n    };\n  }\n\n  /**\n   * Full canvas extent expressed in virtual-space pixels. Unlike\n   * {@link visibleVirtualRect} this is NOT clamped to the declared virtual\n   * bounds — under `letterbox` / `expand` on an off-aspect host it extends\n   * past `virtualSize` on the unscaled axis (negative `x`/`y` or\n   * `width`/`height` greater than the virtual dimension). Under `cover` it\n   * equals `visibleVirtualRect`; under `stretch` it equals the virtual rect.\n   */\n  get visibleCanvasRect(): VirtualRect {\n    const { scaleX, scaleY, offsetX, offsetY } = this.transform;\n    // `+ 0` normalizes `-0` (e.g. when `offsetX === 0`) so consumer\n    // comparisons with strict equality / `Object.is` don't trip up.\n    const x = -offsetX / scaleX + 0;\n    const y = -offsetY / scaleY + 0;\n    const width = this.canvasW / scaleX;\n    const height = this.canvasH / scaleY;\n    return { x, y, width, height };\n  }\n\n  /**\n   * The sub-rectangle of the declared virtual space (0..virtualWidth,\n   * 0..virtualHeight) that is actually on-screen, clamped to the virtual\n   * bounds. Use this to anchor HUD / UI to what the player can see, while\n   * gameplay continues to use the full `virtualSize` as its play area.\n   *\n   * - `letterbox` / `expand` / `stretch`: always the full virtual rect (no cropping).\n   * - `cover`: a strict sub-rect — the long axis is cropped by the canvas\n   *   edges. Example: under 1000×600 host with 400×300 virtual, cover\n   *   scales to 2.5 and crops 30 virtual pixels off each of top / bottom,\n   *   so `visibleVirtualRect` is `{ x: 0, y: 30, width: 400, height: 240 }`.\n   */\n  get visibleVirtualRect(): VirtualRect {\n    const { scaleX, scaleY, offsetX, offsetY } = this.transform;\n    // Inverse-transform the canvas corners back into virtual space.\n    const xStart = -offsetX / scaleX;\n    const xEnd = (this.canvasW - offsetX) / scaleX;\n    const yStart = -offsetY / scaleY;\n    const yEnd = (this.canvasH - offsetY) / scaleY;\n    // Clamp to the declared virtual rect — matters for `cover`; no-op\n    // otherwise since letterbox/stretch already stay within bounds.\n    const x = Math.max(0, xStart);\n    const y = Math.max(0, yStart);\n    const width = Math.max(0, Math.min(this.virtualWidth, xEnd) - x);\n    const height = Math.max(0, Math.min(this.virtualHeight, yEnd) - y);\n    return { x, y, width, height };\n  }\n\n  /**\n   * Rectangles of virtual space that are currently off-screen (inside\n   * `virtualSize` but outside `visibleVirtualRect`). Gameplay still runs\n   * in these regions — they are just clipped by the canvas edges.\n   *\n   * - `letterbox` / `expand` / `stretch`: always `[]` (nothing cropped inside virtual).\n   * - `cover`: 1 or 2 strips on the cropped axis (top + bottom on a wide\n   *   host; left + right on a tall host). Example: under 1000×600 host with\n   *   400×300 virtual, cover crops 30 px off top/bottom, so the rects are\n   *   `[{x:0,y:0,w:400,h:30}, {x:0,y:270,w:400,h:30}]`.\n   *\n   * Strips are returned in axis order: top-then-bottom or left-then-right.\n   * Zero-sized strips are omitted.\n   */\n  get croppedVirtualRects(): readonly VirtualRect[] {\n    const vis = this.visibleVirtualRect;\n    const vw = this.virtualWidth;\n    const vh = this.virtualHeight;\n    const out: VirtualRect[] = [];\n    // Top strip\n    if (vis.y > 0) {\n      out.push({ x: 0, y: 0, width: vw, height: vis.y });\n    }\n    // Bottom strip\n    const bottomStart = vis.y + vis.height;\n    if (bottomStart < vh) {\n      out.push({\n        x: 0,\n        y: bottomStart,\n        width: vw,\n        height: vh - bottomStart,\n      });\n    }\n    // Left strip (only if not already captured by top/bottom which span full width)\n    if (vis.x > 0) {\n      out.push({ x: 0, y: vis.y, width: vis.x, height: vis.height });\n    }\n    // Right strip\n    const rightStart = vis.x + vis.width;\n    if (rightStart < vw) {\n      out.push({\n        x: rightStart,\n        y: vis.y,\n        width: vw - rightStart,\n        height: vis.height,\n      });\n    }\n    return out;\n  }\n\n  /**\n   * Rectangles of the visible canvas that sit OUTSIDE the declared virtual\n   * rect — the letterbox/expand \"bars\" expressed in virtual-space pixels.\n   * Geometric complement of `virtualRect` inside {@link visibleCanvasRect}.\n   *\n   * Populated whenever the host aspect doesn't match virtual and there's\n   * canvas area beyond virtual: true under `letterbox` and `expand`, empty\n   * under `cover` (virtual always covers the canvas) and `stretch` (virtual\n   * exactly fills the canvas).\n   *\n   * Under `expand` these are the \"play-adjacent\" strips the game is expected\n   * to draw into — fog, parallax, decorative backdrop, bar-anchored HUD.\n   * Under `letterbox` they describe where the background-color bars land, so\n   * the same rects can drive optional bar customization on top of a\n   * letterbox render.\n   *\n   * Strips are returned in axis order: top-then-bottom on tall hosts,\n   * left-then-right on wide hosts. Zero-sized strips are omitted.\n   */\n  get extendedVirtualRects(): readonly VirtualRect[] {\n    const vc = this.visibleCanvasRect;\n    const vw = this.virtualWidth;\n    const vh = this.virtualHeight;\n    const out: VirtualRect[] = [];\n    // Top strip\n    if (vc.y < 0) {\n      out.push({ x: vc.x, y: vc.y, width: vc.width, height: -vc.y });\n    }\n    // Bottom strip\n    const vcBottom = vc.y + vc.height;\n    if (vcBottom > vh) {\n      out.push({ x: vc.x, y: vh, width: vc.width, height: vcBottom - vh });\n    }\n    // Left strip (only the portion not already captured by full-width top/bottom).\n    // Full-width strips and full-height strips are mutually exclusive under\n    // letterbox/expand (only one axis of bars exists at a time), so we can\n    // safely emit the side strips keyed to the visible-inside-virtual band.\n    const insideTop = Math.max(0, vc.y);\n    const insideBottom = Math.min(vh, vcBottom);\n    const insideHeight = Math.max(0, insideBottom - insideTop);\n    if (vc.x < 0) {\n      out.push({\n        x: vc.x,\n        y: insideTop,\n        width: -vc.x,\n        height: insideHeight,\n      });\n    }\n    const vcRight = vc.x + vc.width;\n    if (vcRight > vw) {\n      out.push({\n        x: vw,\n        y: insideTop,\n        width: vcRight - vw,\n        height: insideHeight,\n      });\n    }\n    return out;\n  }\n\n  private measure(el: HTMLElement): { width: number; height: number } {\n    // Match the ResizeObserver path: return the content box, not the\n    // border-box. `getBoundingClientRect()` always reports border-box, so\n    // subtract padding + border via computed style. Without this, the\n    // initial synchronous apply (before any observer fire) sizes the canvas\n    // to the host's outer rect; on a host without an explicit height that\n    // pushes the host taller, and the observer then chases it.\n    const rect = el.getBoundingClientRect();\n    if (typeof getComputedStyle === \"undefined\") {\n      return { width: rect.width, height: rect.height };\n    }\n    const style = getComputedStyle(el);\n    const padX =\n      (parseFloat(style.paddingLeft) || 0) +\n      (parseFloat(style.paddingRight) || 0);\n    const padY =\n      (parseFloat(style.paddingTop) || 0) +\n      (parseFloat(style.paddingBottom) || 0);\n    const borderX =\n      (parseFloat(style.borderLeftWidth) || 0) +\n      (parseFloat(style.borderRightWidth) || 0);\n    const borderY =\n      (parseFloat(style.borderTopWidth) || 0) +\n      (parseFloat(style.borderBottomWidth) || 0);\n    return {\n      width: Math.max(0, rect.width - padX - borderX),\n      height: Math.max(0, rect.height - padY - borderY),\n    };\n  }\n\n  private apply(hostW: number, hostH: number): void {\n    const vW = this.virtualWidth;\n    const vH = this.virtualHeight;\n\n    let scaleX: number;\n    let scaleY: number;\n    let offsetX: number;\n    let offsetY: number;\n\n    if (this.mode === \"stretch\") {\n      scaleX = hostW / vW;\n      scaleY = hostH / vH;\n      offsetX = 0;\n      offsetY = 0;\n    } else {\n      // letterbox + expand share the same transform (uniform min-scale,\n      // centered). They differ only in rendering convention: letterbox\n      // paints the leftover canvas with the app background color, expand\n      // lets the game draw into it. Exposed via `extendedVirtualRects`.\n      const scale =\n        this.mode === \"cover\"\n          ? Math.max(hostW / vW, hostH / vH)\n          : Math.min(hostW / vW, hostH / vH);\n      scaleX = scale;\n      scaleY = scale;\n      offsetX = (hostW - vW * scale) / 2;\n      offsetY = (hostH - vH * scale) / 2;\n    }\n\n    this.app.renderer.resize(hostW, hostH);\n    this.stage.scale.set(scaleX, scaleY);\n    this.stage.position.set(offsetX, offsetY);\n\n    this.canvasW = hostW;\n    this.canvasH = hostH;\n    this.transform = { scaleX, scaleY, offsetX, offsetY };\n\n    // Letterbox is documented as \"leftover space painted with backgroundColor\"\n    // — i.e. bars are blank. Without a mask, content drawn at stage-local\n    // coords outside (0,0,vW,vH) leaks into the bars (visible whenever the\n    // game's world is larger than the virtual rect, e.g. a side-scroller\n    // wider than the viewport). Install a clip rect to enforce the doc'd\n    // contract. `expand`, `cover`, and `stretch` deliberately don't clip:\n    // `expand` lets the game draw into bars on purpose, `cover` and\n    // `stretch` fully cover the canvas already.\n    this.applyLetterboxMask();\n  }\n\n  private applyLetterboxMask(): void {\n    if (this.mode === \"letterbox\") {\n      if (!this.letterboxMask) {\n        // Don't clobber a pre-existing stage mask. Letterbox clipping is a\n        // fit-level convenience; a caller-installed `stage.mask` is the\n        // explicit escape hatch and takes precedence. Removal is also\n        // defensive — `removeLetterboxMask` only clears `stage.mask` when\n        // it still points at our Graphics. The comparison must be loose:\n        // pixi's `Container.mask` getter reads through an internal effect\n        // object, so an unmasked container reports `undefined`, not `null`.\n        if (this.stage.mask != null) return;\n        this.letterboxMask = new Graphics();\n        this.stage.addChild(this.letterboxMask);\n        this.stage.mask = this.letterboxMask;\n      }\n      this.letterboxMask\n        .clear()\n        .rect(0, 0, this.virtualWidth, this.virtualHeight)\n        .fill(0xffffff);\n      return;\n    }\n    this.removeLetterboxMask();\n  }\n\n  private removeLetterboxMask(): void {\n    if (!this.letterboxMask) return;\n    if (this.stage.mask === this.letterboxMask) {\n      this.stage.mask = null;\n    }\n    this.stage.removeChild(this.letterboxMask);\n    this.letterboxMask.destroy();\n    this.letterboxMask = null;\n  }\n}\n","import { devWarn } from \"@yagejs/core\";\nimport type { TextOptions } from \"pixi.js\";\nimport { resolveBitmapFontVariant } from \"./bitmapFontVariants.js\";\nimport type { TextStyle } from \"../public-types.js\";\n\n/**\n * Engine-level default text style, applied as the base under every per-text\n * `style`. Set by `RendererPlugin` from `RendererConfig.defaultTextStyle` so\n * consumers don't have to reach into pixi's `TextStyle.defaultTextStyle`.\n * `@yagejs/ui` layers its own override on top via `buildTextOptions`'s\n * `extraDefault`. `undefined` means \"no default — use pixi's\".\n *\n * @internal\n */\nlet _defaultTextStyle: TextStyle | undefined;\n\n/** @internal Set the renderer-level default text style (RendererPlugin). */\nexport function setDefaultTextStyle(style: TextStyle | undefined): void {\n  _defaultTextStyle = style ? { ...style } : undefined;\n}\n\n/** @internal Current renderer-level default text style, if any. */\nexport function getDefaultTextStyle(): TextStyle | undefined {\n  return _defaultTextStyle;\n}\n\n/** Merge two partial styles, returning `undefined` when both are empty. */\nfunction mergeStyles(\n  base: TextStyle | undefined,\n  over: TextStyle | undefined,\n): TextStyle | undefined {\n  if (!base) return over;\n  if (!over) return base;\n  return { ...base, ...over };\n}\n\n/**\n * Resolve the final style assigned to a Pixi text node: engine default (+ an\n * optional caller default, e.g. the UIPlugin override) as the base, then the\n * per-text `style` on top. Used by both construction and the `setStyle`\n * update paths so a re-render keeps the resolved default.\n *\n * @internal\n */\nexport function resolveTextStyle(\n  style: TextStyle | undefined,\n  extraDefault?: TextStyle | undefined,\n): TextStyle | undefined {\n  if (style && \"bitmap\" in style) {\n    devWarn(\n      \"Text: `bitmap` was found inside `style` — it's a sibling prop, not a \" +\n        \"style key, and is ignored there. Move it out: \" +\n        \"`{ style: { … }, bitmap: true }`.\",\n    );\n  }\n  const base = mergeStyles(_defaultTextStyle, extraDefault);\n  return mergeStyles(base, style);\n}\n\n/**\n * Build the shared `Text` / `BitmapText` constructor options and pick the\n * Pixi class for both `TextComponent` and `UIText`. `bitmap` selects\n * `BitmapText`, which bakes / looks up its glyph atlas from `style.fontFamily`.\n * `resolution` is forwarded only to canvas `Text` — `BitmapText` resolution\n * is fixed at font-bake time (Pixi v8 warns if you set it per-instance), so\n * use `installBitmapFont({ resolution })`.\n *\n * Centralised so the two text classes can't drift on the Pixi-v8\n * resolution-gating rule. `extraDefault` layers a caller-owned default\n * (the UIPlugin override) between the engine default and the per-text style.\n *\n * @internal\n */\nexport function buildTextOptions(\n  text: string,\n  style: TextStyle | undefined,\n  bitmap: boolean | undefined,\n  resolution: number | undefined,\n  extraDefault?: TextStyle | undefined,\n): { options: TextOptions; bitmap: boolean } {\n  // `bitmap`-in-`style` warning lives in `resolveTextStyle` (the shared\n  // chokepoint), so construction and the `setStyle` paths all surface it.\n  const useBitmap = bitmap === true;\n  const resolvedStyle = useBitmap\n    ? selectBitmapVariant(resolveTextStyle(style, extraDefault))\n    : resolveTextStyle(style, extraDefault);\n  return {\n    bitmap: useBitmap,\n    options: {\n      text,\n      ...(resolvedStyle ? { style: resolvedStyle } : {}),\n      ...(!useBitmap && resolution !== undefined ? { resolution } : {}),\n    },\n  };\n}\n\n/**\n * Honour `fontWeight` / `fontStyle` on bitmap text by swapping `fontFamily`\n * to the emphasis variant atlas baked under that family (issue #90 gap 3,\n * delivered via {@link installBitmapFont}'s `variants`). Plain `BitmapText`\n * ignores those props — but if `installBitmapFont` registered a matching bold/\n * italic atlas, redirect the family to it so the synthetic emphasis renders.\n *\n * The variant atlas already baked its weight/slant, and Pixi resolves a\n * `BitmapText` font by the `fontFamily` cache key alone, so the original\n * `fontWeight`/`fontStyle` are dropped from the redirected style to avoid a\n * second dynamic bake. When no variant is registered for the family the style\n * is returned untouched (regular text, an unbaked family, or a font without\n * variants all fall through unchanged).\n *\n * Exported for `measureWrappedText`, which must resolve the same atlas the\n * render path draws from (measure/render parity).\n *\n * @internal\n */\nexport function selectBitmapVariant(\n  style: TextStyle | undefined,\n): TextStyle | undefined {\n  if (!style || typeof style.fontFamily !== \"string\") return style;\n  const variantName = resolveBitmapFontVariant(style.fontFamily, {\n    ...(style.fontWeight !== undefined ? { fontWeight: style.fontWeight } : {}),\n    ...(style.fontStyle !== undefined ? { fontStyle: style.fontStyle } : {}),\n  });\n  if (variantName === undefined || variantName === style.fontFamily) {\n    return style;\n  }\n  const redirected: TextStyle = { ...style, fontFamily: variantName };\n  delete redirected.fontWeight;\n  delete redirected.fontStyle;\n  return redirected;\n}\n","import type { TextStyle } from \"../public-types.js\";\n\n/**\n * The weight/style emphasis axes a baked bitmap-font variant can carry. A\n * variant is identified by the combination of these two — `bold`, `italic`,\n * `bold italic`, or the unemphasised base.\n *\n * @internal\n */\nexport interface BitmapFontEmphasis {\n  /** `TextStyle.fontWeight` the variant atlas was baked at. */\n  fontWeight?: TextStyle[\"fontWeight\"];\n  /** `TextStyle.fontStyle` the variant atlas was baked at. */\n  fontStyle?: TextStyle[\"fontStyle\"];\n}\n\n/**\n * Per-base-font map of emphasis → the registered bitmap-font name baked for\n * that emphasis. Keyed first by the base font `name` (the family a\n * `BitmapText` asks for), then by a normalized emphasis key.\n *\n * @internal\n */\nconst variantRegistry = new Map<string, Map<string, string>>();\n\n/**\n * A `fontWeight` counts as bold when it's the keyword `\"bold\"`/`\"bolder\"` or a\n * numeric weight >= 600. Anything lighter (including the `\"normal\"` default and\n * unset) is treated as the regular axis so `BitmapText` without explicit\n * emphasis resolves the base atlas.\n */\nfunction isBoldWeight(weight: TextStyle[\"fontWeight\"] | undefined): boolean {\n  if (weight === undefined) return false;\n  if (weight === \"bold\" || weight === \"bolder\") return true;\n  // Pixi types `fontWeight` as a string union (`\"700\"`, not `700`); parse the\n  // numeric keywords so a `\"600\"`+ request lands on the bold axis.\n  const numeric = Number(weight);\n  return Number.isFinite(numeric) && numeric >= 600;\n}\n\n/** `fontStyle` counts as slanted for `italic` and `oblique`. */\nfunction isItalicStyle(style: TextStyle[\"fontStyle\"] | undefined): boolean {\n  return style === \"italic\" || style === \"oblique\";\n}\n\n/**\n * Collapse an emphasis to a stable lookup key on the two boolean axes\n * (bold / italic). Variants only differ along those axes, so a request for\n * `fontWeight: \"700\"` resolves the same atlas baked for `fontWeight: \"bold\"`.\n *\n * @internal\n */\nexport function emphasisKey(emphasis: BitmapFontEmphasis): string {\n  const bold = isBoldWeight(emphasis.fontWeight);\n  const italic = isItalicStyle(emphasis.fontStyle);\n  return `${bold ? \"b\" : \"r\"}${italic ? \"i\" : \"u\"}`;\n}\n\n/**\n * Derive the registration name for an emphasis variant of `baseName`. Driven\n * by the same bold/italic axis classification as {@link emphasisKey} (not a\n * raw presence check) so the name and the lookup key can never disagree — a\n * `{ fontWeight: \"lighter\" }` variant resolves to the base axis and reuses\n * `baseName` rather than minting a spurious `\"… bold\"` atlas that collides\n * with the regular entry.\n *\n * @internal\n */\nexport function variantFontName(\n  baseName: string,\n  emphasis: BitmapFontEmphasis,\n): string {\n  const parts: string[] = [baseName];\n  if (isBoldWeight(emphasis.fontWeight)) parts.push(\"bold\");\n  if (isItalicStyle(emphasis.fontStyle)) parts.push(\"italic\");\n  return parts.join(\" \");\n}\n\n/**\n * Record that `variantName` is the bitmap font baked for `baseName` at the\n * given emphasis. The base (unemphasised) atlas registers itself too so a\n * `BitmapText` with `fontWeight: \"normal\"` resolves back to it.\n *\n * @internal\n */\nexport function registerBitmapFontVariant(\n  baseName: string,\n  emphasis: BitmapFontEmphasis,\n  variantName: string,\n): void {\n  let byEmphasis = variantRegistry.get(baseName);\n  if (!byEmphasis) {\n    byEmphasis = new Map();\n    variantRegistry.set(baseName, byEmphasis);\n  }\n  byEmphasis.set(emphasisKey(emphasis), variantName);\n}\n\n/**\n * Resolve the bitmap-font name a `BitmapText` should use given the family it\n * asked for and the emphasis on its style. Returns the matching variant name\n * when one is registered, the base name when no specific variant exists, or\n * `undefined` when `baseName` hosts no variants at all (so the caller leaves\n * `fontFamily` untouched).\n *\n * @internal\n */\nexport function resolveBitmapFontVariant(\n  baseName: string,\n  emphasis: BitmapFontEmphasis,\n): string | undefined {\n  const byEmphasis = variantRegistry.get(baseName);\n  if (!byEmphasis) return undefined;\n  // Fall back to the unemphasised (base) atlas for any emphasis that has no\n  // baked variant. `emphasisKey({})` keeps the fallback key tied to the\n  // encoding rather than a hardcoded literal.\n  return (\n    byEmphasis.get(emphasisKey(emphasis)) ?? byEmphasis.get(emphasisKey({}))\n  );\n}\n\n/**\n * Drop every variant registered under `baseName`. Two callers:\n *\n *   - `installBitmapFont` calls this at the top of its variants block, so\n *     re-installing the same font name with a smaller / different variant\n *     set can't silently inherit stale entries from a previous install.\n *   - `unloadWebFont` calls this when a `webFont({ bitmap })` is unloaded —\n *     the symmetric teardown of the `registerBitmapFontVariant` calls\n *     `bakeBitmapFontFamily` made on load, so a `BitmapText` asking for the\n *     family afterwards no longer resolves a destroyed atlas.\n *\n * A no-op when the family hosts no variants. @internal\n */\nexport function unregisterBitmapFontVariants(baseName: string): void {\n  variantRegistry.delete(baseName);\n}\n\n/** Drop every registered variant — test isolation only. @internal */\nexport function clearBitmapFontVariants(): void {\n  variantRegistry.clear();\n}\n","import { Color, RenderTexture } from \"pixi.js\";\nimport type { Renderer } from \"pixi.js\";\nimport type {\n  ColorValue,\n  DisplayContainer,\n  TextureResource,\n} from \"./public-types.js\";\n\n/** Options for `RendererPlugin.createRenderTarget`. */\nexport interface RenderTargetOptions {\n  /** Buffer width, in the source container's own coordinates. */\n  width: number;\n  /** Buffer height, in the source container's own coordinates. */\n  height: number;\n  /**\n   * Texel density as a fraction of the renderer's own resolution. `1`\n   * (the default) gives the buffer the same sharpness as the canvas; `0.5`\n   * allocates a quarter of the texels and stretches them back over the same\n   * area.\n   *\n   * The texture still measures `width × height` whatever the value, so\n   * lowering it costs sharpness and never layout. Worth doing for content\n   * that is already soft — gradients, blurred glows — and not for text or\n   * pixel art.\n   */\n  resolutionScale?: number;\n  /** Antialias the buffer's own edges. Default `false`. */\n  antialias?: boolean;\n  /** Colour the buffer is cleared to before each render. Default: transparent. */\n  clearColor?: ColorValue;\n  /** Label on the underlying texture, shown in the Pixi devtools. */\n  label?: string;\n  /** Targets sampled by this pass. Drawing waits until these targets are clean. */\n  dependsOn?: readonly RenderTargetHandle[];\n}\n\n/**\n * An offscreen texture the game draws into on its own schedule, returned by\n * `RendererPlugin.createRenderTarget`.\n *\n * The buffer starts out needing a render and is redrawn only when the game\n * asks — call {@link renderIfNeeded} every frame and {@link invalidate}\n * whenever the source content changes, or call {@link render} directly for a\n * buffer that must follow moving content.\n *\n * Drawing happens in the source container's own coordinate space: a child at\n * local `(100, 50)` lands at texture pixel `(100, 50)`. Ancestor transforms\n * do not reach the buffer, so neither the camera nor the responsive-fit\n * scale moves or scales what is drawn. Position the source's children in the\n * space you want the texture to hold.\n *\n * Keep the source out of the live scene graph. Pixi promotes a rendered\n * container to a render group, which changes how it batches where it is\n * parented, and content drawn into a buffer is normally shown through the\n * buffer's texture rather than twice.\n */\nexport interface RenderTargetHandle {\n  /** The texture the buffer draws into. Show it with a `SpriteComponent`, a mask, or a filter. */\n  readonly texture: TextureResource;\n  /**\n   * The container drawn into the buffer. The game owns it: {@link destroy}\n   * frees the texture and leaves this container alone.\n   */\n  readonly source: DisplayContainer;\n  /** Buffer width in source coordinates. */\n  readonly width: number;\n  /** Buffer height in source coordinates. */\n  readonly height: number;\n  /** Texels per source pixel actually allocated — the renderer's resolution times `resolutionScale`. */\n  readonly resolution: number;\n  /** Whether a render is pending. */\n  readonly needsRender: boolean;\n\n  /** Mark the buffer stale so the next {@link renderIfNeeded} redraws it. */\n  invalidate(): void;\n\n  /**\n   * Draw the source into the buffer now and clear the pending flag.\n   * Defers while the source is hidden, an input target is pending, or drawing is disabled.\n   * The request stays pending until an allowed draw or explicit stage capture.\n   * Deferred targets flush in creation order; create inputs before consumers.\n   */\n  render(): void;\n\n  /**\n   * Draw the source only when a render is pending. Returns whether it drew,\n   * so a caller can skip downstream work on an unchanged buffer.\n   */\n  renderIfNeeded(): boolean;\n\n  /**\n   * Resize the buffer and mark it stale. Anything already showing the\n   * texture picks up the new size on its next draw.\n   */\n  resize(width: number, height: number, resolutionScale?: number): void;\n\n  /**\n   * Destroy the texture and its GPU memory. Safe to call repeatedly. Frees\n   * the texture only: destroy the source container yourself, and call\n   * `unregisterTexture(key)` for any key the texture was registered under, or\n   * that key keeps resolving a destroyed texture.\n   */\n  destroy(): void;\n}\n\n/** @internal Drawing policy supplied by the owning renderer. */\nexport interface RenderTargetDrawing {\n  readonly stage: DisplayContainer;\n  isEnabled(): boolean;\n}\n\nclass RenderTargetImpl implements RenderTargetHandle {\n  readonly source: DisplayContainer;\n  private readonly _renderer: Renderer;\n  private readonly _texture: RenderTexture;\n  private readonly _dependencies: readonly RenderTargetHandle[];\n  /**\n   * Pre-converted to RGBA. Pixi only normalises a *truthy* `clearColor`, so a\n   * numeric `0x000000` would reach the backend as a bare number where an array\n   * is expected and clear to undefined channels.\n   */\n  private readonly _clearColor: number[] | undefined;\n  /**\n   * Kept so `resize` can re-derive the texture resolution from the renderer's\n   * current one. Storing only the absolute resolution would silently pin the\n   * buffer to whatever the renderer happened to be at construction time.\n   */\n  private _resolutionScale: number;\n  private _state: \"clean\" | \"dirty\" | \"deferred\" = \"dirty\";\n  private _destroyed = false;\n\n  constructor(\n    renderer: Renderer,\n    source: DisplayContainer,\n    options: RenderTargetOptions,\n    private readonly drawing?: RenderTargetDrawing,\n  ) {\n    if (source === drawing?.stage) {\n      throw new Error(\n        \"createRenderTarget: source must not be the application stage.\",\n      );\n    }\n    const scale = options.resolutionScale ?? 1;\n    assertPositive(options.width, \"width\");\n    assertPositive(options.height, \"height\");\n    assertPositive(scale, \"resolutionScale\");\n\n    this._renderer = renderer;\n    this._dependencies = [...(options.dependsOn ?? [])];\n    this.source = source;\n    this._resolutionScale = scale;\n    this._clearColor =\n      options.clearColor !== undefined\n        ? // `toArray` may hand back a Float32Array; the render options want a\n          // plain array.\n          Array.from(new Color(options.clearColor).toArray())\n        : undefined;\n    this._texture = RenderTexture.create({\n      width: options.width,\n      height: options.height,\n      resolution: renderer.resolution * scale,\n      antialias: options.antialias ?? false,\n      // Lets anything showing the texture re-read its size after `resize`.\n      dynamic: true,\n      ...(options.label !== undefined ? { label: options.label } : undefined),\n    });\n    if (drawing) renderer.runners.prerender.add(this);\n  }\n\n  /** Pixi's existing pre-render dispatch flushes targets in creation order. */\n  prerender(options: { container: DisplayContainer }): void {\n    if (\n      options.container === this.drawing?.stage &&\n      this._state === \"deferred\"\n    ) {\n      this.draw(true);\n    }\n  }\n\n  get texture(): TextureResource {\n    this._assertLive(\"texture\");\n    return this._texture;\n  }\n\n  get width(): number {\n    this._assertLive(\"width\");\n    return this._texture.width;\n  }\n\n  get height(): number {\n    this._assertLive(\"height\");\n    return this._texture.height;\n  }\n\n  get resolution(): number {\n    this._assertLive(\"resolution\");\n    return this._texture.source.resolution;\n  }\n\n  get needsRender(): boolean {\n    return this._state !== \"clean\";\n  }\n\n  invalidate(): void {\n    if (this._state === \"clean\") this._state = \"dirty\";\n  }\n\n  render(): void {\n    this.draw(false);\n  }\n\n  private draw(force: boolean): void {\n    this._assertLive(\"render\");\n    // Pixi tears out the transform fields on destroy, so drawing a destroyed\n    // source throws from deep inside its own update with nothing naming the\n    // real mistake. Skipping instead would leave a permanently stale buffer.\n    if (this.source.destroyed) {\n      throw new Error(\n        \"RenderTarget: the source container has been destroyed, so this buffer \" +\n          \"can never draw again. Destroy the target alongside its source.\",\n      );\n    }\n    // Pixi draws nothing for a hidden container, which would leave the buffer\n    // silently stale. Leave the request pending so it catches up once the\n    // source is shown again — including a forced render on a clean target,\n    // which would otherwise be dropped with nothing left to replay it.\n    if (\n      !this.source.visible ||\n      this._dependencies.some((target) => target.needsRender) ||\n      (!force && this.drawing?.isEnabled() === false)\n    ) {\n      this._state = \"deferred\";\n      return;\n    }\n    this._renderer.render({\n      container: this.source,\n      target: this._texture,\n      clear: true,\n      ...(this._clearColor !== undefined\n        ? { clearColor: this._clearColor }\n        : undefined),\n    });\n    this._state = \"clean\";\n  }\n\n  renderIfNeeded(): boolean {\n    if (!this.needsRender) return false;\n    this.render();\n    return !this.needsRender;\n  }\n\n  resize(width: number, height: number, resolutionScale?: number): void {\n    this._assertLive(\"resize\");\n    assertPositive(width, \"width\");\n    assertPositive(height, \"height\");\n    if (resolutionScale !== undefined) {\n      assertPositive(resolutionScale, \"resolutionScale\");\n      this._resolutionScale = resolutionScale;\n    }\n    // Always re-derive from the renderer's current resolution, so a buffer\n    // keeps the density it was asked for rather than the absolute one it\n    // happened to get at construction.\n    this._texture.resize(\n      width,\n      height,\n      this._renderer.resolution * this._resolutionScale,\n    );\n    if (this._state === \"clean\") this._state = \"dirty\";\n  }\n\n  destroy(): void {\n    if (this._destroyed) return;\n    this._destroyed = true;\n    if (this.drawing) this._renderer.runners.prerender.remove(this);\n    this._texture.destroy(true);\n  }\n\n  /**\n   * Every member but `destroy` reads through the texture, which Pixi empties\n   * out on destroy. Without this the read fails as a bare\n   * `Cannot read properties of null` from inside Pixi.\n   */\n  private _assertLive(member: string): void {\n    if (!this._destroyed) return;\n    throw new Error(\n      `RenderTargetHandle.${member}: the handle is destroyed. ` +\n        `Create a new render target instead of reusing a destroyed one.`,\n    );\n  }\n}\n\nfunction assertPositive(value: number, name: string): void {\n  if (!Number.isFinite(value) || value <= 0) {\n    throw new Error(\n      `createRenderTarget: ${name} must be a positive number, got ${value}.`,\n    );\n  }\n}\n\n/**\n * Build a render target around `source`. Reached through\n * `RendererPlugin.createRenderTarget`, which supplies the live renderer.\n */\nexport function createRenderTarget(\n  renderer: Renderer,\n  source: DisplayContainer,\n  options: RenderTargetOptions,\n  drawing?: RenderTargetDrawing,\n): RenderTargetHandle {\n  return new RenderTargetImpl(renderer, source, options, drawing);\n}\n","import { Container, RenderLayer as PixiRenderLayer } from \"pixi.js\";\nimport type { ProcessSystem, Scene } from \"@yagejs/core\";\nimport { devWarn, isDev, makeSceneScopedQueue } from \"@yagejs/core\";\nimport type { LayerDef } from \"./LayerDef.js\";\nimport type {\n  SceneRenderTree,\n  SceneRenderTreeProvider,\n  EnsureLayerOptions,\n} from \"./SceneRenderTree.js\";\nimport { RenderLayerManager, layerDefToOptions } from \"./RenderLayer.js\";\nimport type { EffectQueueFactory, RenderLayer } from \"./RenderLayer.js\";\nimport type { EffectFactory } from \"./effects/Effect.js\";\nimport type { EffectHandle } from \"./effects/EffectHandle.js\";\nimport { EffectsHost } from \"./effects/EffectsHost.js\";\nimport { fanOutHandle } from \"./effects/fanOutHandle.js\";\nimport { attachMask } from \"./masks/attachMask.js\";\nimport type { MaskFactory } from \"./masks/MaskFactory.js\";\nimport type { MaskHandle } from \"./masks/MaskHandle.js\";\nimport type { DisplayContainer } from \"./public-types.js\";\n\ninterface SceneEntry {\n  root: DisplayContainer;\n  manager: RenderLayerManager;\n  tree: SceneRenderTreeImpl;\n}\n\nclass SceneRenderTreeImpl implements SceneRenderTree {\n  readonly fx: EffectsHost;\n  private _mask: MaskHandle | undefined;\n  private readonly warnedOrders = new Map<string, Set<number>>();\n  /**\n   * Pixi render layer holding the nodes drawn after this scene's layers.\n   * Built on the first `renderAboveEffects` call.\n   */\n  private _aboveLayer: PixiRenderLayer | undefined;\n  /**\n   * Attached node → the listener that re-attaches it after a re-parent.\n   * Pixi drops a render-layer attachment in `removeChild`, which every\n   * re-parent (`setLayer`, a sort group claiming a visual) goes through.\n   */\n  private readonly _aboveListeners = new WeakMap<\n    DisplayContainer,\n    () => void\n  >();\n\n  constructor(\n    readonly root: DisplayContainer,\n    private readonly manager: RenderLayerManager,\n    queueFactory?: EffectQueueFactory,\n  ) {\n    this.fx = new EffectsHost(() => this.root, \"scene\", queueFactory);\n  }\n\n  get(name: string): RenderLayer {\n    return this.manager.get(name);\n  }\n\n  tryGet(name: string): RenderLayer | undefined {\n    return this.manager.tryGet(name);\n  }\n\n  getAll(): readonly RenderLayer[] {\n    return this.manager.getAll();\n  }\n\n  get defaultLayer(): RenderLayer {\n    return this.manager.defaultLayer;\n  }\n\n  ensureLayer(def: LayerDef, opts?: EnsureLayerOptions): RenderLayer {\n    const existing = this.manager.tryGet(def.name);\n    if (!existing) return this.manager.createFromDef(def, opts);\n    if (isDev() && existing.order !== def.order) {\n      let orders = this.warnedOrders.get(def.name);\n      if (!orders) {\n        orders = new Set();\n        this.warnedOrders.set(def.name, orders);\n      }\n      if (!orders.has(def.order)) {\n        orders.add(def.order);\n        devWarn(\n          `SceneRenderTree.ensureLayer: layer \"${def.name}\" has order ${existing.order}; requested ${def.order}. The existing order is preserved.`,\n        );\n      }\n    }\n    return existing;\n  }\n\n  addLayerEffect<H extends EffectHandle>(\n    factory: EffectFactory<H>,\n    layers: readonly string[],\n  ): H {\n    if (layers.length === 0) {\n      throw new Error(\n        \"SceneRenderTree.addLayerEffect: layers must name at least one layer, got [].\",\n      );\n    }\n    // Resolve every name before attaching anything, so an unknown name\n    // leaves no half-applied effect behind.\n    const targets: RenderLayer[] = [];\n    for (const name of layers) {\n      if (targets.some((t) => t.name === name)) {\n        throw new Error(\n          `SceneRenderTree.addLayerEffect: layer \"${name}\" is listed twice; ` +\n            `each layer gets one filter pass.`,\n        );\n      }\n      const layer = this.manager.tryGet(name);\n      if (!layer) {\n        const declared = this.manager\n          .getAll()\n          .map((l) => l.name)\n          .join(\", \");\n        throw new Error(\n          `SceneRenderTree.addLayerEffect: unknown layer \"${name}\". ` +\n            `Declared layers: ${declared}.`,\n        );\n      }\n      targets.push(layer);\n    }\n    return fanOutHandle(targets.map((layer) => layer.fx.addEffect(factory)));\n  }\n\n  setMask(factory: MaskFactory): MaskHandle {\n    this._mask?.remove();\n    this._mask = attachMask(this.root, factory);\n    return this._mask;\n  }\n\n  clearMask(): void {\n    this._mask?.remove();\n    this._mask = undefined;\n  }\n\n  renderAboveEffects(node: DisplayContainer): void {\n    if (this._aboveListeners.has(node)) return;\n    if (!this.contains(node)) {\n      throw new Error(\n        `SceneRenderTree.renderAboveEffects: node \"${node.label}\" is not in ` +\n          `the \"${this.root.label}\" tree. Add it to a layer first.`,\n      );\n    }\n    const reattach = (): void => {\n      this._aboveLayer?.attach(node);\n    };\n    this._aboveListeners.set(node, reattach);\n    node.on(\"added\", reattach);\n    this.ensureAboveLayer().attach(node);\n  }\n\n  renderWithEffects(node: DisplayContainer): void {\n    const reattach = this._aboveListeners.get(node);\n    if (!reattach) return;\n    this._aboveListeners.delete(node);\n    node.off(\"added\", reattach);\n    this._aboveLayer?.detach(node);\n  }\n\n  /** @internal — called by the provider before container teardown. */\n  _destroyMask(): void {\n    this._mask?.remove();\n    this._mask = undefined;\n  }\n\n  /**\n   * Re-seat the render layer immediately after the scene root. Called after\n   * the provider moves the root among its siblings.\n   * @internal\n   */\n  _placeAboveLayer(): void {\n    const layer = this._aboveLayer;\n    const parent = this.root.parent;\n    if (!layer || !parent) return;\n    layer.removeFromParent();\n    parent.addChildAt(layer, parent.children.indexOf(this.root) + 1);\n  }\n\n  /** @internal — called by the provider after the root is destroyed. */\n  _destroyAboveLayer(): void {\n    if (!this._aboveLayer) return;\n    this._aboveLayer.detachAll();\n    this._aboveLayer.removeFromParent();\n    this._aboveLayer.destroy();\n    this._aboveLayer = undefined;\n  }\n\n  private ensureAboveLayer(): PixiRenderLayer {\n    if (this._aboveLayer) return this._aboveLayer;\n    const layer = new PixiRenderLayer({ sortableChildren: false });\n    layer.label = `${this.root.label}:above`;\n    this._aboveLayer = layer;\n    this._placeAboveLayer();\n    return layer;\n  }\n\n  /** Whether `node` sits somewhere under this scene's root. */\n  private contains(node: DisplayContainer): boolean {\n    for (let current = node.parent; current != null; current = current.parent) {\n      if (current === this.root) return true;\n    }\n    return false;\n  }\n}\n\n/**\n * Materializes a per-scene render tree with one root container per scene,\n * added as a direct child of the renderer plugin's `_worldRoot` container\n * (which itself sits under `app.stage`, but holds the fit transform — see\n * `RendererPlugin._worldRoot` for the rationale). Registered under\n * `SceneRenderTreeProviderKey` by the renderer plugin.\n *\n * ```\n * app.stage                  // identity\n *  └── _worldRoot           // fit transform lives here\n *       ├── scene A root\n *       │    ├── layer \"bg\" (order -10)\n *       │    ├── layer \"world\" (order 0)\n *       │    └── layer \"hud\" (order 100)\n *       └── scene B root\n *            └── ...\n * ```\n *\n * A scene that uses `renderAboveEffects` also owns a Pixi `RenderLayer`\n * placed immediately after its root, so the nodes attached to it draw after\n * the scene's layers and outside the scene root's filters and mask.\n */\nexport class SceneRenderTreeProviderImpl implements SceneRenderTreeProvider {\n  private entries = new Map<Scene, SceneEntry>();\n\n  constructor(\n    private readonly stage: DisplayContainer,\n    private readonly processSystem?: ProcessSystem,\n  ) {}\n\n  createForScene(scene: Scene): SceneRenderTree {\n    if (this.entries.has(scene)) {\n      throw new Error(\n        `Scene \"${scene.name}\" already has a render tree attached.`,\n      );\n    }\n\n    const root = new Container();\n    root.label = `scene:${scene.name}`;\n    this.stage.addChild(root);\n\n    // Bind the queue factory to (processSystem, scene) so every layer- and\n    // scene-scope effect created on this tree pauses and time-scales with\n    // the owning scene, matching component-scope behavior.\n    const ps = this.processSystem;\n    const queueFactory: EffectQueueFactory | undefined = ps\n      ? () => makeSceneScopedQueue(ps, scene)\n      : undefined;\n\n    // A declared `{ name: \"default\", ... }` configures the pre-created\n    // default layer (order 0) rather than being skipped: the manager bakes\n    // its `sort`/`space`/`isRenderGroup` into the layer it builds in its\n    // ctor. `order` stays 0 — \"default\" is the order-0 layer by definition.\n    const layers = scene.layers ?? [];\n    const defaultDef = layers.find((def) => def.name === \"default\");\n    const manager = new RenderLayerManager(\n      root,\n      \"passive\",\n      queueFactory,\n      defaultDef ? layerDefToOptions(defaultDef) : undefined,\n    );\n\n    for (const def of layers) {\n      if (manager.tryGet(def.name)) continue;\n      warnUiLayerShadow(def);\n      manager.createFromDef(def);\n    }\n\n    const tree = new SceneRenderTreeImpl(root, manager, queueFactory);\n    this.entries.set(scene, { root, manager, tree });\n    return tree;\n  }\n\n  destroyForScene(scene: Scene): void {\n    const entry = this.entries.get(scene);\n    if (!entry) return;\n    // Tear down effect stacks AND masks while containers are still alive so\n    // user-assigned external filters survive the EffectStack teardown and\n    // owned mask Graphics aren't destroyed twice (once via remove(), once\n    // via root.destroy({ children: true })).\n    entry.tree.fx.destroy();\n    entry.tree._destroyMask();\n    entry.manager.destroyEffects();\n    entry.manager.destroyMasks();\n    entry.root.removeFromParent();\n    entry.root.destroy({ children: true });\n    entry.tree._destroyAboveLayer();\n    entry.manager.destroy();\n    this.entries.delete(scene);\n  }\n\n  getTree(scene: Scene): SceneRenderTree | undefined {\n    return this.entries.get(scene)?.tree;\n  }\n\n  *allTrees(): IterableIterator<[Scene, SceneRenderTree]> {\n    for (const [scene, entry] of this.entries) {\n      yield [scene, entry.tree];\n    }\n  }\n\n  bringSceneToFront(scene: Scene): void {\n    const entry = this.entries.get(scene);\n    if (!entry) return;\n    const parent = entry.root.parent;\n    if (parent) {\n      parent.removeChild(entry.root);\n      parent.addChild(entry.root);\n      entry.tree._placeAboveLayer();\n    }\n  }\n\n  /**\n   * Hide below-stack scene trees whose top neighbour has\n   * `transparentBelow = false`. The topmost scene is always visible; below\n   * neighbours stay visible only while every scene above them is\n   * `transparentBelow = true`. Detached scenes (mounted via\n   * `_mountDetached`, e.g. the debug overlay) are not in the stack and\n   * their visibility is left alone.\n   * @internal\n   */\n  applyTransparentBelow(stack: readonly Scene[]): void {\n    let visible = true;\n    for (let i = stack.length - 1; i >= 0; i--) {\n      const scene = stack[i]!;\n      const entry = this.entries.get(scene);\n      if (entry) entry.root.visible = visible;\n      if (!scene.transparentBelow) visible = false;\n    }\n  }\n\n  /**\n   * Restore in-stack scene roots to visible. Used while a scene transition\n   * runs so both the outgoing and incoming scenes can render even when the\n   * new topmost scene has `transparentBelow = false`; the visibility chain\n   * is reapplied when the transition ends. Detached scenes (mounted via\n   * `_mountDetached`, e.g. the debug overlay) are left alone — same\n   * contract as `applyTransparentBelow`, so callers can hide a detached\n   * root without it being silently un-hidden on every transition start.\n   * @internal\n   */\n  resetVisibility(stack: readonly Scene[]): void {\n    for (const scene of stack) {\n      const entry = this.entries.get(scene);\n      if (entry) entry.root.visible = true;\n    }\n  }\n\n  /** Destroy every tracked scene's tree. Used on renderer shutdown. */\n  destroyAll(): void {\n    for (const scene of [...this.entries.keys()]) {\n      this.destroyForScene(scene);\n    }\n  }\n}\n\n// String-duplicated from @yagejs/ui's `UI_DEFAULT_LAYER` (\"ui\") to avoid a\n// reverse import (renderer is below ui in the dep graph). Kept in sync via\n// the dev warning + a co-located test that pins the literal.\nconst UI_DEFAULT_LAYER_NAME = \"ui\";\nconst warnedShadowScenes = new WeakSet<LayerDef>();\n\nfunction warnUiLayerShadow(def: LayerDef): void {\n  if (def.name !== UI_DEFAULT_LAYER_NAME) return;\n  if (def.space !== undefined) return;\n  if (warnedShadowScenes.has(def)) return;\n  warnedShadowScenes.add(def);\n  devWarn(\n    `Layer 'ui' is the canonical UI layer name; declaring it without ` +\n      `space: 'screen' replaces the auto-screen-space layer with a ` +\n      `world-space one. Add \\`space: 'screen'\\` or rename the layer.`,\n  );\n}\n","import { Container } from \"pixi.js\";\nimport type { EventMode } from \"pixi.js\";\nimport type { ScopedProcessQueue } from \"@yagejs/core\";\nimport type { LayerDef, LayerSortFn, LayerSpace } from \"./LayerDef.js\";\nimport { EffectsHost } from \"./effects/EffectsHost.js\";\nimport { attachMask } from \"./masks/attachMask.js\";\nimport type { MaskFactory } from \"./masks/MaskFactory.js\";\nimport type { MaskHandle } from \"./masks/MaskHandle.js\";\nimport type { DisplayContainer } from \"./public-types.js\";\n\n/**\n * Factory that produces a fresh `ScopedProcessQueue` instance — called once\n * per `EffectStack` so each stack's cancellation scope stays isolated.\n */\nexport type EffectQueueFactory = () => ScopedProcessQueue;\n\n/** Options for creating a layer. */\nexport interface CreateLayerOptions {\n  /** Per-layer override for PixiJS event mode. Falls back to the manager default. */\n  eventMode?: EventMode;\n  /**\n   * Coordinate space. `\"world\"` (default) layers are auto-bound by every\n   * camera unless it sets `autoBind: false`; `\"screen\"` layers are skipped\n   * so they stay fixed to the viewport. Cameras can still explicitly bind screen-space layers by\n   * naming them in `bindings`.\n   */\n  space?: LayerSpace;\n  /**\n   * Promote the layer's container to a Pixi v8 render group. See\n   * `LayerDef.isRenderGroup` for the full rationale — isolates filter\n   * uniforms from sibling layers that read `globalUniforms` directly.\n   */\n  isRenderGroup?: boolean;\n  /**\n   * Depth-key function. See `LayerDef.sort` — when set, `DisplaySystem`\n   * writes `child.zIndex = sort(child)` on every child each frame, and\n   * flips `container.sortableChildren = true` so Pixi orders the layer\n   * by zIndex at render time. Default: undefined (insertion order).\n   */\n  sort?: LayerSortFn;\n}\n\n/**\n * Derive `CreateLayerOptions` from a declarative `LayerDef`. Fields set on\n * the def (`space`, `isRenderGroup`, `sort`) take precedence over `base` so\n * a scene's declaration stays authoritative; `base` carries plugin-side\n * defaults for fields the def leaves unset.\n */\nexport function layerDefToOptions(\n  def: LayerDef,\n  base?: CreateLayerOptions,\n): CreateLayerOptions {\n  const merged: CreateLayerOptions = { ...base };\n  if (def.space !== undefined) merged.space = def.space;\n  if (def.isRenderGroup !== undefined) merged.isRenderGroup = def.isRenderGroup;\n  if (def.sort !== undefined) merged.sort = def.sort;\n  return merged;\n}\n\n/** A named rendering layer — a pixi container at a given draw order. */\nexport class RenderLayer {\n  readonly name: string;\n  readonly order: number;\n  readonly container: DisplayContainer;\n  /** Coordinate space — see `CreateLayerOptions.space`. */\n  readonly space: LayerSpace;\n  private _sort: LayerSortFn | undefined;\n  /**\n   * Layer-scope effects host. `.fx.addEffect(...)` applies a filter to every\n   * entity rendered through this layer (one full-screen render pass per\n   * layer-scope effect, regardless of how many entities are in the layer).\n   * Fades pause with the owning scene and are scaled by its `timeScale`,\n   * matching component-scope behavior. Effects survive until the scene\n   * exits or the handle is `.remove()`d.\n   */\n  readonly fx: EffectsHost;\n  private _mask: MaskHandle | undefined;\n\n  constructor(\n    name: string,\n    order: number,\n    container: DisplayContainer,\n    space: LayerSpace = \"world\",\n    queueFactory?: EffectQueueFactory,\n    sort?: LayerSortFn,\n  ) {\n    this.name = name;\n    this.order = order;\n    this.container = container;\n    this.space = space;\n    this._sort = sort;\n    if (sort) container.sortableChildren = true;\n    this.fx = new EffectsHost(() => this.container, \"layer\", queueFactory);\n  }\n\n  /**\n   * Per-frame depth-key function, or `undefined` for insertion-order\n   * rendering. Set via `LayerDef.sort` / `CreateLayerOptions.sort` at\n   * creation, or {@link setSort} at runtime. `DisplaySystem` writes\n   * `child.zIndex = sort(child)` on every child each Render phase.\n   */\n  get sort(): LayerSortFn | undefined {\n    return this._sort;\n  }\n\n  /**\n   * Set (or clear) this layer's depth-key function at runtime, flipping\n   * `container.sortableChildren` to match. Useful for opting the\n   * auto-created `\"default\"` layer into `ySort` after the scene is live,\n   * or toggling depth sorting on dynamically.\n   *\n   * Passing `undefined` stops the per-frame re-sort, but does **not**\n   * restore the original insertion order: Pixi reorders `container.children`\n   * in place while sorting is on, so clearing `sortableChildren` only halts\n   * further sorting — children keep their current (last-sorted) order and\n   * `zIndex`. Re-establish paint order yourself if you need the original\n   * sequence back.\n   */\n  setSort(sort: LayerSortFn | undefined): void {\n    this._sort = sort;\n    this.container.sortableChildren = sort !== undefined;\n  }\n\n  /**\n   * Attach a mask to this layer's container, replacing any existing mask.\n   * Returns a handle for inverse toggling, redraw (graphicsMask), or\n   * removal. Torn down on scene exit.\n   */\n  setMask(factory: MaskFactory): MaskHandle {\n    this._mask?.remove();\n    this._mask = attachMask(this.container, factory);\n    return this._mask;\n  }\n\n  /** Detach and destroy the layer-scope mask, if any. */\n  clearMask(): void {\n    this._mask?.remove();\n    this._mask = undefined;\n  }\n\n  /**\n   * Tear down any layer-scope mask. Called by `RenderLayerManager` before\n   * the layer's container is destroyed so the owned mask Graphics gets\n   * cleaned up exactly once.\n   * @internal\n   */\n  _destroyMask(): void {\n    this._mask?.remove();\n    this._mask = undefined;\n  }\n}\n\n/**\n * Manages named render layers for a single scene. All layers are children\n * of a single root container. Camera transforms are applied per-layer\n * by the DisplaySystem based on CameraEntity bindings.\n */\nexport class RenderLayerManager {\n  private layers = new Map<string, RenderLayer>();\n  private readonly rootContainer: DisplayContainer;\n  private readonly _defaultLayer: RenderLayer;\n  private readonly _defaultEventMode: EventMode | undefined;\n  private readonly _queueFactory: EffectQueueFactory | undefined;\n\n  constructor(\n    root: DisplayContainer,\n    defaultEventMode?: EventMode,\n    queueFactory?: EffectQueueFactory,\n    /**\n     * Config for the auto-created `\"default\"` layer (order 0). Lets a scene\n     * that declares `{ name: \"default\", sort, space, isRenderGroup }`\n     * configure the pre-created layer instead of the declaration being a\n     * no-op. The provider derives this from the matching `LayerDef`.\n     */\n    defaultLayerOptions?: CreateLayerOptions,\n  ) {\n    this.rootContainer = root;\n    this._defaultEventMode = defaultEventMode;\n    this._queueFactory = queueFactory;\n    this._defaultLayer = this.create(\"default\", 0, defaultLayerOptions);\n  }\n\n  /** Create a new named layer. Throws if `name` already exists. */\n  create(name: string, order: number, opts?: CreateLayerOptions): RenderLayer {\n    if (this.layers.has(name)) {\n      throw new Error(`RenderLayer \"${name}\" already exists.`);\n    }\n    const container = new Container();\n    container.label = name;\n\n    const eventMode = opts?.eventMode ?? this._defaultEventMode;\n    if (eventMode) container.eventMode = eventMode;\n    if (opts?.isRenderGroup) container.isRenderGroup = true;\n    // `sort` is a depth-key fn — DisplaySystem writes the result to each\n    // child's zIndex every frame, and Pixi's render pipeline orders the\n    // layer by zIndex when `sortableChildren` is true. The `RenderLayer`\n    // ctor flips that flag; Pixi's `zIndex` setter marks `sortDirty` on\n    // the parent automatically, so we don't need to re-sort manually.\n    const layer = new RenderLayer(\n      name,\n      order,\n      container,\n      opts?.space ?? \"world\",\n      this._queueFactory,\n      opts?.sort,\n    );\n    this.layers.set(name, layer);\n\n    this.rootContainer.addChild(container);\n    this.sortLayers();\n\n    return layer;\n  }\n\n  /**\n   * Create a layer from a declarative `LayerDef`. Fields on the def\n   * (`space`, `sortableChildren`) take precedence over the runtime `opts`\n   * so a scene's declaration stays authoritative; `opts` is primarily for\n   * plugin-side overrides when auto-provisioning a layer the scene didn't\n   * declare (via `ensureLayer`).\n   */\n  createFromDef(def: LayerDef, opts?: CreateLayerOptions): RenderLayer {\n    return this.create(def.name, def.order, layerDefToOptions(def, opts));\n  }\n\n  /** Get a layer by name. Throws if not found. */\n  get(name: string): RenderLayer {\n    const layer = this.layers.get(name);\n    if (!layer) {\n      throw new Error(`RenderLayer \"${name}\" not found.`);\n    }\n    return layer;\n  }\n\n  /** Get a layer by name, returning undefined if not found. */\n  tryGet(name: string): RenderLayer | undefined {\n    return this.layers.get(name);\n  }\n\n  /** Get an existing layer, or create it if it doesn't exist. */\n  getOrCreate(\n    name: string,\n    order: number,\n    opts?: CreateLayerOptions,\n  ): RenderLayer {\n    return this.layers.get(name) ?? this.create(name, order, opts);\n  }\n\n  /** The default layer (order 0). */\n  get defaultLayer(): RenderLayer {\n    return this._defaultLayer;\n  }\n\n  /** All layers sorted by draw order. */\n  getAll(): readonly RenderLayer[] {\n    return [...this.layers.values()].sort((a, b) => a.order - b.order);\n  }\n\n  /** The root container holding all layers. */\n  get root(): DisplayContainer {\n    return this.rootContainer;\n  }\n\n  /**\n   * Tear down every layer's effect stack. Call BEFORE the root container is\n   * destroyed so external (user-assigned) filters get preserved by each\n   * stack's destroy logic instead of being clobbered by the container\n   * teardown.\n   */\n  destroyEffects(): void {\n    for (const layer of this.layers.values()) {\n      layer.fx.destroy();\n    }\n  }\n\n  /**\n   * Tear down every layer's mask. Call BEFORE the root container is\n   * destroyed so owned mask Graphics get destroyed exactly once.\n   */\n  destroyMasks(): void {\n    for (const layer of this.layers.values()) {\n      layer._destroyMask();\n    }\n  }\n\n  /** Clear internal state. Call after the root container has been destroyed. */\n  destroy(): void {\n    this.layers.clear();\n  }\n\n  private sortLayers(): void {\n    for (const layer of this.layers.values()) {\n      layer.container.zIndex = layer.order;\n    }\n    this.rootContainer.sortableChildren = true;\n    this.rootContainer.sortChildren();\n  }\n}\n","import type { EffectHandle } from \"./EffectHandle.js\";\n\n/**\n * Keys `EffectHandle` itself defines. Every other own enumerable key on a\n * handle comes from a preset's `buildExtras`.\n */\nconst BASE_KEYS: ReadonlySet<string> = new Set([\n  \"remove\",\n  \"setEnabled\",\n  \"enabled\",\n  \"setIntensity\",\n  \"fadeIn\",\n  \"fadeOut\",\n  \"run\",\n]);\n\n/** Call `invoke` on every handle; return the first handle's result. */\nfunction fanOut<H, R>(handles: readonly H[], invoke: (handle: H) => R): R {\n  let first: R | undefined;\n  for (let i = 0; i < handles.length; i++) {\n    const result = invoke(handles[i]!);\n    if (i === 0) first = result;\n  }\n  return first as R;\n}\n\n/**\n * Merge several handles for the same effect into one. Methods fan out to\n * every handle; values (`enabled`, an extra's return value) come from the\n * first. Preset extras are discovered on the first handle and fan out the\n * same way.\n *\n * Used by `SceneRenderTree.addLayerEffect`, which attaches one effect per\n * listed layer and returns a single handle for all of them.\n *\n * @internal\n */\nexport function fanOutHandle<H extends EffectHandle>(handles: readonly H[]): H {\n  const first = handles[0];\n  if (!first) throw new Error(\"fanOutHandle: needs at least one handle.\");\n\n  const composite: EffectHandle = {\n    remove: () => {\n      for (const handle of handles) handle.remove();\n    },\n    setEnabled: (on) => {\n      for (const handle of handles) handle.setEnabled(on);\n    },\n    get enabled() {\n      return first.enabled;\n    },\n    setIntensity: (value) => {\n      for (const handle of handles) handle.setIntensity(value);\n    },\n    fadeIn: (duration) => fanOut(handles, (h) => h.fadeIn(duration)),\n    fadeOut: (duration) => fanOut(handles, (h) => h.fadeOut(duration)),\n    run: (process) => fanOut(handles, (h) => h.run(process)),\n  };\n  const extras = first as unknown as Record<string, unknown>;\n  for (const key of Object.keys(extras)) {\n    if (BASE_KEYS.has(key)) continue;\n    // Classifying reads the key once. `buildExtras` returns plain values and\n    // closures, so this is the same read a caller would make.\n    if (typeof extras[key] === \"function\") {\n      Object.defineProperty(composite, key, {\n        value: (...args: unknown[]) =>\n          fanOut(handles, (handle) => {\n            const method = (handle as unknown as Record<string, unknown>)[key];\n            return (method as (...a: unknown[]) => unknown).apply(handle, args);\n          }),\n        enumerable: true,\n      });\n    } else {\n      Object.defineProperty(composite, key, {\n        get: () => extras[key],\n        enumerable: true,\n      });\n    }\n  }\n\n  return composite as H;\n}\n","import { AssetHandle } from \"@yagejs/core\";\nimport {\n  Assets,\n  BitmapFont,\n  BitmapFontManager,\n  CanvasTextMetrics,\n  NineSliceSprite as PixiNineSliceSprite,\n  Texture,\n  TextStyle as PixiTextStyle,\n} from \"pixi.js\";\nimport type { Spritesheet } from \"pixi.js\";\nimport { sliceGridNamed } from \"./spritesheet.js\";\nimport {\n  emphasisKey,\n  registerBitmapFontVariant,\n  unregisterBitmapFontVariants,\n  variantFontName,\n  type BitmapFontEmphasis,\n} from \"./internal/bitmapFontVariants.js\";\nimport {\n  acquireBakedFamily,\n  releaseBakedFamily,\n} from \"./internal/bitmapFontRegistry.js\";\nimport {\n  resolveTextStyle,\n  selectBitmapVariant,\n} from \"./internal/textConstruction.js\";\nimport type {\n  BitmapFontHandle,\n  NineSliceSprite,\n  RendererAsset,\n  TextStyle,\n  TextureHandle,\n  TextureInput,\n  TextureResource,\n  TextureSliceOptions,\n  WebFontHandle,\n  WebFontResource,\n} from \"./public-types.js\";\n\n/** Options for {@link texture}. */\nexport interface TextureOptions {\n  /**\n   * How the GPU samples this texture when it is drawn at a size other than\n   * its own: `\"nearest\"` keeps pixel-art edges hard, `\"linear\"` smooths them.\n   * Omit to leave Pixi's default (`\"linear\"`, or whatever `pixelArtPreset`\n   * set globally).\n   *\n   * The setting lands on the loaded image, so every sprite drawing from it\n   * samples the same way.\n   */\n  scaleMode?: \"nearest\" | \"linear\";\n}\n\n/** Loader metadata stashed onto a {@link texture} handle. @internal */\ninterface TextureHandleData {\n  scaleMode: \"nearest\" | \"linear\";\n}\n\n/**\n * Create a typed asset handle for a texture.\n *\n * ```ts\n * const Hero = texture(\"hero.png\");\n * const Tiles = texture(\"tiles.png\", { scaleMode: \"nearest\" });\n * ```\n */\nexport function texture(path: string, opts?: TextureOptions): TextureHandle {\n  return new AssetHandle(\n    \"texture\",\n    path,\n    opts?.scaleMode !== undefined ? { scaleMode: opts.scaleMode } : undefined,\n  );\n}\n\n/**\n * Load a texture for the `texture` asset loader, applying the handle's\n * `scaleMode` to the loaded image.\n *\n * Split out of the loader registration so it is unit testable against the\n * Pixi mock rather than through the whole plugin.\n *\n * @internal\n */\nexport async function loadTexture(\n  path: string,\n  data?: unknown,\n): Promise<TextureResource> {\n  const loaded = await Assets.load<TextureResource>(path);\n  const scaleMode = (data as TextureHandleData | undefined)?.scaleMode;\n  if (scaleMode !== undefined) loaded.source.scaleMode = scaleMode;\n  return loaded;\n}\n\n/** Create a typed asset handle for a spritesheet JSON atlas. */\nexport function spritesheet(path: string): AssetHandle<Spritesheet> {\n  return new AssetHandle(\"spritesheet\", path);\n}\n\n/** Create a typed handle for an arbitrary renderer-managed asset. */\nexport function renderAsset<T = unknown>(path: string): RendererAsset<T> {\n  return new AssetHandle(\"render-asset\", path);\n}\n\n/**\n * Create a typed asset handle for a bitmap font — a BMFont `.fnt`/`.xml`\n * descriptor plus its glyph atlas. Resolve it through the asset manager\n * (`engine.assets`) like any other handle; the loaded font registers itself\n * under the `fontFamily` declared in the descriptor, so pass that same name\n * as `style.fontFamily` (with `bitmap: true`) on `UIText` / `TextComponent`.\n *\n * For runtime-baked fonts from a `.ttf` instead, see {@link installBitmapFont}.\n */\nexport function bitmapFont(path: string): BitmapFontHandle {\n  return new AssetHandle(\"bitmap-font\", path);\n}\n\n/**\n * Declarative atlas-baking config for a {@link webFont} loaded with `bitmap`\n * set. Mirrors {@link InstallBitmapFontOptions} minus `name` / `family` — the\n * baked bitmap font registers under the same family as the canvas face, so one\n * `webFont` name drives both the canvas `Text` and the `BitmapText` registries\n * (separate registries, no collision).\n */\nexport interface WebFontBakeOptions {\n  /** Glyph size (px) to bake the atlas at. Default `32`. */\n  size?: number;\n  /**\n   * Character set to bake. Accepts Pixi's range syntax, e.g.\n   * `[[\"a\", \"z\"], [\"A\", \"Z\"], \"0123456789 .,!?\"]`. Defaults to Pixi's\n   * alphanumeric set — remember to include a space.\n   */\n  chars?: string | (string | string[])[];\n  /**\n   * Atlas resolution multiplier. `2` keeps glyphs crisp when the text is\n   * upscaled by a pixel-art camera. Default `2`.\n   */\n  resolution?: number;\n  /** Glyph padding in the atlas. Default `4`. */\n  padding?: number;\n  /**\n   * Extra `TextStyle` props baked into every glyph (fill, stroke, weight,\n   * drop shadow…). `fontFamily` / `fontSize` are managed by the baker.\n   * `fill` defaults to white so per-text `fill` / `tint` can recolour the\n   * glyphs — set it explicitly to bake a fixed colour instead.\n   */\n  style?: Partial<TextStyle>;\n  /**\n   * Weight/style emphasis atlases to bake alongside the base font from the\n   * same source face — the same declarative model as\n   * {@link InstallBitmapFontOptions.variants}. A `BitmapText` whose\n   * `style.fontWeight`/`fontStyle` asks for bold or italic then renders from\n   * the matching synthetic atlas.\n   */\n  variants?: BitmapFontVariant[];\n}\n\n/** Options for {@link webFont}. */\nexport interface WebFontOptions {\n  /**\n   * `@font-face` family the loaded face registers under — the name you then\n   * pass as `style.fontFamily` on `Text` / `UIText` / `TextComponent`.\n   * Omit to let Pixi derive it from the file name.\n   */\n  family?: string;\n  /**\n   * Also bake a bitmap glyph atlas from the loaded face under the same family,\n   * so the one `webFont` name works for both canvas `Text` (no `bitmap`) and\n   * `BitmapText` (`bitmap: true`). `true` bakes with defaults; pass a\n   * {@link WebFontBakeOptions} object to control size, charset, emphasis\n   * variants, and baked style.\n   *\n   * Requires `family` so the baked atlas has a stable name to register under\n   * and uninstall on unload; baking is skipped (with a warning) when `family`\n   * is omitted.\n   *\n   * ```ts\n   * webFont(\"fonts/Inter.woff2\", { family: \"Inter\", bitmap: { size: 24 } });\n   * // <TextComponent style={{ fontFamily: \"Inter\" }} />        → canvas Text\n   * // <TextComponent bitmap style={{ fontFamily: \"Inter\" }} /> → bitmap atlas\n   * ```\n   */\n  bitmap?: boolean | WebFontBakeOptions;\n}\n\n/**\n * Loader metadata stashed onto a {@link webFont} handle — the `@font-face`\n * family plus the optional declarative bitmap-bake config. Read by the\n * `web-font` loader, never by user code.\n *\n * @internal\n */\nexport interface WebFontHandleData {\n  /** `@font-face` family the loaded face registers under. */\n  family?: string;\n  /** Declarative bitmap-bake config, copied through from `WebFontOptions`. */\n  bitmap?: boolean | WebFontBakeOptions;\n}\n\n/**\n * Create a typed asset handle for a plain web font (a `.ttf`/`.woff`/`.woff2`\n * loaded for canvas `Text`, the canvas sibling of {@link bitmapFont}). Resolve\n * it through a scene's `preload` so the face is registered before the first\n * draw — Pixi caches fallback metrics on first paint otherwise, so a font that\n * loads late never applies.\n *\n * Pass `bitmap` to also bake a `BitmapText` atlas from the same face under the\n * same family, so a single declared font works for both text paths.\n *\n * ```ts\n * class MenuScene extends Scene {\n *   readonly preload = [webFont(\"fonts/Inter.woff2\", { family: \"Inter\" })];\n *   // …then: new TextComponent({ text: \"Play\", style: { fontFamily: \"Inter\" } })\n * }\n * ```\n */\nexport function webFont(path: string, opts?: WebFontOptions): WebFontHandle {\n  const data: WebFontHandleData = {\n    ...(opts?.family !== undefined ? { family: opts.family } : {}),\n    ...(opts?.bitmap !== undefined ? { bitmap: opts.bitmap } : {}),\n  };\n  return new AssetHandle(\n    \"web-font\",\n    path,\n    Object.keys(data).length > 0 ? data : undefined,\n  );\n}\n\n/**\n * Base family a web-font load baked a bitmap atlas for, keyed by the load path.\n * The `web-font` loader's `unload(path, asset)` never sees the handle's bake\n * config, so this recovers which baked family to release (the actual names to\n * uninstall come from the ref-counted {@link releaseBakedFamily} ledger).\n *\n * @internal\n */\nconst bakedWebFontFamilies = new Map<string, string>();\n\n/**\n * Source `.ttf`/`.woff` path each {@link installBitmapFont} loaded, keyed by the\n * registered font name, so {@link uninstallBitmapFont} — which only receives the\n * name — can `Assets.unload` the face it loaded, symmetric with the install.\n *\n * @internal\n */\nconst installedBitmapFontSources = new Map<string, string>();\n\n/** Owner key a `webFont({ bitmap })` load holds its baked family under. */\nfunction webFontOwner(path: string): string {\n  return `web-font:${path}`;\n}\n\n/** Owner key an `installBitmapFont` call holds its baked family under. */\nfunction installOwner(name: string): string {\n  return `install:${name}`;\n}\n\n/**\n * Release one owner's hold on the baked family `baseName`, performing the real\n * Pixi teardown only when it was the last owner: `BitmapFont.uninstall` every\n * atlas (base + variants) and drop the family's emphasis-variant registry so a\n * later request no longer resolves a destroyed atlas. A no-op while another\n * owner (a second `webFont` load, or an `installBitmapFont` sharing the family)\n * still holds it.\n *\n * @internal\n */\nfunction teardownBakedFamily(owner: string, baseName: string): void {\n  const names = releaseBakedFamily(owner, baseName);\n  if (!names) return;\n  for (const name of names) BitmapFont.uninstall(name);\n  unregisterBitmapFontVariants(baseName);\n}\n\n/**\n * Load a web font for the `web-font` asset loader, optionally baking a bitmap\n * atlas under the same family when `data.bitmap` is set. Returns the loaded\n * `FontFace[]` so the asset cache holds the canvas face as before.\n *\n * Split out of the loader registration so the bake/teardown logic is unit\n * testable against the same Pixi mock as {@link installBitmapFont}.\n *\n * @internal\n */\nexport async function loadWebFont(\n  path: string,\n  data?: unknown,\n): Promise<WebFontResource> {\n  const meta = data as WebFontHandleData | undefined;\n  const family = meta?.family;\n  const faces = await Assets.load<WebFontResource>(\n    family !== undefined ? { src: path, data: { family } } : path,\n  );\n\n  if (meta?.bitmap) {\n    if (family === undefined) {\n      console.warn(\n        `webFont(\"${path}\", { bitmap }) needs an explicit \\`family\\` to name ` +\n          `the baked atlas — skipping the bitmap bake.`,\n      );\n    } else {\n      const bake = meta.bitmap === true ? {} : meta.bitmap;\n      const names = bakeBitmapFontFamily(family, family, bake);\n      bakedWebFontFamilies.set(path, family);\n      // Hold the baked family under this load's owner key so a teardown only\n      // fires once every owner (other loads, a same-family installBitmapFont)\n      // has released it.\n      acquireBakedFamily(webFontOwner(path), family, names);\n    }\n  }\n\n  return faces;\n}\n\n/**\n * Unload a web font for the `web-font` asset loader: drop this load's canvas\n * face via `Assets.unload` and release its hold on any baked bitmap family. The\n * baked atlas is `BitmapFont.uninstall`ed only when no other owner still holds\n * the family — see {@link teardownBakedFamily}. The core loader's\n * `unload(path, asset)` never sees the handle's bake config, so the baked\n * family is recovered from {@link bakedWebFontFamilies}.\n *\n * @internal\n */\nexport function unloadWebFont(path: string): void {\n  Assets.unload(path);\n  const family = bakedWebFontFamilies.get(path);\n  if (family !== undefined) {\n    bakedWebFontFamilies.delete(path);\n    teardownBakedFamily(webFontOwner(path), family);\n  }\n}\n\n/** Drop the baked-web-font tracking — test isolation only. @internal */\nexport function clearBakedWebFontFamilies(): void {\n  bakedWebFontFamilies.clear();\n}\n\n/** Drop the install-font source tracking — test isolation only. @internal */\nexport function clearInstalledBitmapFontSources(): void {\n  installedBitmapFontSources.clear();\n}\n\n/** Options for {@link installBitmapFont}. */\nexport interface InstallBitmapFontOptions {\n  /**\n   * Name to register the baked font under. This is what you pass as\n   * `style.fontFamily` (alongside `bitmap: true`) on `UIText` /\n   * `TextComponent`, and what `installBitmapFont` returns.\n   */\n  name: string;\n  /** Glyph size (px) to bake the atlas at. Default `32`. */\n  size?: number;\n  /**\n   * Character set to bake. Accepts Pixi's range syntax, e.g.\n   * `[[\"a\", \"z\"], [\"A\", \"Z\"], \"0123456789 .,!?\"]`. Defaults to Pixi's\n   * alphanumeric set — remember to include a space.\n   */\n  chars?: string | (string | string[])[];\n  /**\n   * Atlas resolution multiplier. `2` keeps glyphs crisp when the text is\n   * upscaled by a pixel-art camera. Default `2`.\n   */\n  resolution?: number;\n  /** Glyph padding in the atlas. Default `4`. */\n  padding?: number;\n  /**\n   * Extra `TextStyle` props baked into every glyph (fill, stroke, weight,\n   * drop shadow…). `fontFamily` / `fontSize` are managed by this helper.\n   * `fill` defaults to white so per-text `fill` / `tint` can recolour the\n   * glyphs — set it explicitly to bake a fixed colour instead.\n   */\n  style?: Partial<TextStyle>;\n  /**\n   * `@font-face` family the loaded `.ttf` registers under. Defaults to\n   * `name`, so the loaded face and the baked bitmap font share one\n   * coherent identifier.\n   */\n  family?: string;\n  /**\n   * Bake weight/style emphasis atlases alongside the base font from the same\n   * source `.ttf`, so a `BitmapText` whose `style.fontWeight`/`fontStyle`\n   * asks for bold or italic renders from the matching synthetic atlas instead\n   * of being ignored (canvas `Text` honours those props; plain `BitmapText`\n   * does not).\n   *\n   * Every variant is baked through the same pipeline as the base, then has\n   * its baseline metrics aligned to the base atlas — so a bold span and\n   * regular text sit on one shared baseline with no vertical drift. Variants\n   * register under derived names (`\"<name> bold\"`, `\"<name> italic\"`, …); you\n   * never name them yourself. Just set `style.fontWeight: \"bold\"` on a\n   * `BitmapText` using this font and the bold atlas is selected automatically.\n   *\n   * ```ts\n   * await installBitmapFont(\"fonts/Body.ttf\", {\n   *   name: \"Body\",\n   *   variants: [{ fontWeight: \"bold\" }, { fontStyle: \"italic\" }],\n   * });\n   * // <BitmapText style={{ fontFamily: \"Body\", fontWeight: \"bold\" }} /> → bold atlas\n   * ```\n   */\n  variants?: BitmapFontVariant[];\n}\n\n/**\n * One weight/style emphasis to bake as a sibling atlas of a base bitmap font.\n * Identified by the `fontWeight`/`fontStyle` a `BitmapText` will ask for — a\n * variant only differs from the base along the bold and italic axes, so a\n * request for `fontWeight: \"700\"` resolves the atlas baked for\n * `fontWeight: \"bold\"`.\n *\n * This is the declarative shape the loader-level bitmap-font config reuses, so\n * the same `variants` array can be authored inline or hung off an asset\n * manifest.\n */\nexport interface BitmapFontVariant {\n  /**\n   * Weight to synthesise this variant at. Keyword (`\"bold\"`) or numeric\n   * string (`\"700\"`); >= 600 (or `\"bold\"`/`\"bolder\"`) selects the bold axis.\n   */\n  fontWeight?: TextStyle[\"fontWeight\"];\n  /** Slant to synthesise this variant at — `\"italic\"` or `\"oblique\"`. */\n  fontStyle?: TextStyle[\"fontStyle\"];\n  /**\n   * Extra `TextStyle` props baked into this variant's glyphs only, layered\n   * over the base font's `style`. `fontFamily` / `fontSize` /\n   * `fontWeight` / `fontStyle` are managed by the variant pipeline.\n   */\n  style?: Partial<TextStyle>;\n}\n\n/**\n * Load a `.ttf`/`.woff` and bake a bitmap glyph atlas from it via Pixi v8's\n * `BitmapFont.install`. Returns the registered font name, ready to hand to\n * `style.fontFamily` (with `bitmap: true`) on `UIText` / `TextComponent`. Pair\n * with {@link uninstallBitmapFont} to free the atlas when it's no longer used.\n *\n * ```ts\n * const font = await installBitmapFont(\"fonts/PressStart2P.ttf\", {\n *   name: \"PressStart\",\n *   size: 16,\n * });\n * entity.add(\n *   new TextComponent({ text: \"READY\", bitmap: true, style: { fontFamily: font } }),\n * );\n * ```\n */\nexport async function installBitmapFont(\n  source: string | AssetHandle<unknown>,\n  opts: InstallBitmapFontOptions,\n): Promise<string> {\n  const path = typeof source === \"string\" ? source : source.path;\n  const family = opts.family ?? opts.name;\n\n  await Assets.load({ src: path, data: { family } });\n\n  const names = bakeBitmapFontFamily(opts.name, family, {\n    ...(opts.size !== undefined ? { size: opts.size } : {}),\n    ...(opts.chars !== undefined ? { chars: opts.chars } : {}),\n    ...(opts.resolution !== undefined ? { resolution: opts.resolution } : {}),\n    ...(opts.padding !== undefined ? { padding: opts.padding } : {}),\n    ...(opts.style !== undefined ? { style: opts.style } : {}),\n    ...(opts.variants !== undefined ? { variants: opts.variants } : {}),\n  });\n\n  // Remember the source face so `uninstallBitmapFont` can drop it, and hold the\n  // baked family under a stable per-name owner key — re-installing the same\n  // name re-bakes but stays one owner (no leaked reference).\n  installedBitmapFontSources.set(opts.name, path);\n  acquireBakedFamily(installOwner(opts.name), opts.name, names);\n\n  return opts.name;\n}\n\n/**\n * Tear down a font installed by {@link installBitmapFont}: drop its source face\n * and free the baked atlas (and every emphasis variant) plus its registry\n * entries. The symmetric counterpart of `installBitmapFont` — without it an\n * install-once font's atlas lives until the page unloads.\n *\n * Safe to interleave with a `webFont({ bitmap })` sharing the same family: the\n * atlas is reference-counted, so it's only destroyed once the last owner (this\n * install and any web-font load) has released it. A no-op for a name that was\n * never installed.\n *\n * ```ts\n * const font = await installBitmapFont(\"fonts/PressStart2P.ttf\", { name: \"PressStart\" });\n * // …later, when nothing renders with it anymore:\n * uninstallBitmapFont(font);\n * ```\n */\nexport function uninstallBitmapFont(name: string): void {\n  const path = installedBitmapFontSources.get(name);\n  if (path !== undefined) {\n    Assets.unload(path);\n    installedBitmapFontSources.delete(name);\n  }\n  teardownBakedFamily(installOwner(name), name);\n}\n\n/**\n * Keys currently held by {@link registerTexture}, so registration can tell its\n * own cache entries apart from loaded-asset entries (which it must never\n * shadow) and re-registration can replace without Pixi's duplicate-key warn.\n *\n * @internal\n */\nconst registeredTextures = new Map<string, TextureResource>();\n\n/**\n * Register a runtime-created texture under an asset key, so every key-based\n * surface resolves it exactly like a preloaded asset: `texture: key` on\n * `SpriteComponent` and on a particle emitter, and `{ sheet: key, frameWidth }`\n * on a `FrameSource`.\n *\n * Registered keys are engine-global and live until {@link unregisterTexture} —\n * registration is a boot-scoped act, outside the asset manager's ref counts\n * and unloads. A game-owned save root can store the key, but the game must\n * re-register runtime textures under the same keys during boot before it\n * reconstructs scenes and components. Resolving a missing key throws and\n * names the key.\n *\n * Re-registering a key this API still owns replaces the cache entry;\n * components constructed before the replacement keep the old texture instance\n * (resolution happens at construction). A key present in the cache but owned\n * by the asset pipeline — a loaded asset's path, or an asset that overwrote a\n * stale registration — throws: shadowing a loaded asset would let that asset's\n * unload destroy the registered texture later.\n *\n * ```ts\n * // The size names the strip's region, so every 32-pixel cell holds one circle.\n * const strip = renderer.createTexture(\n *   (g) => {\n *     for (let i = 0; i < 4; i++) g.circle(i * 32 + 16, 16, 4 + i * 3).fill(0xffcc00);\n *   },\n *   { width: 128, height: 32 },\n * );\n * registerTexture(\"boss-idle\", strip);\n * entity.add(new AnimatedSpriteComponent({ source: { sheet: \"boss-idle\", frameWidth: 32 } }));\n * ```\n */\nexport function registerTexture(key: string, texture: TextureResource): void {\n  const registered = registeredTextures.get(key);\n  if (registered !== undefined && Assets.cache.get(key) === registered) {\n    // Replacing our own prior registration.\n    Assets.cache.remove(key);\n  } else if (Assets.cache.has(key)) {\n    // A loaded asset's key, or an asset that overwrote a stale registration —\n    // foreign either way: shadowing it would let the asset's unload destroy\n    // the registered texture later.\n    throw new Error(\n      `registerTexture(\"${key}\"): the key is already used by a loaded asset — ` +\n        `pick a key that doesn't collide with an asset path.`,\n    );\n  }\n  Assets.cache.set(key, texture);\n  registeredTextures.set(key, texture);\n}\n\n/**\n * Remove a texture registered by {@link registerTexture}. A no-op for keys\n * this API never registered. Never destroys the texture — the creator owns\n * the GPU resource; call `texture.destroy()` once nothing draws it anymore.\n *\n * Only evicts the cache entry while it still holds the registered texture: if\n * an asset preloaded under the same key overwrote it after registration, that\n * entry belongs to the asset pipeline and is left in place.\n */\nexport function unregisterTexture(key: string): void {\n  const registered = registeredTextures.get(key);\n  if (registered === undefined) return;\n  if (Assets.cache.get(key) === registered) Assets.cache.remove(key);\n  registeredTextures.delete(key);\n}\n\n/** Drop every registered texture entry — test isolation only. @internal */\nexport function clearRegisteredTextures(): void {\n  for (const [key, texture] of registeredTextures) {\n    if (Assets.cache.get(key) === texture) Assets.cache.remove(key);\n  }\n  registeredTextures.clear();\n}\n\n/**\n * Bake the base atlas for `name` from an already-loaded `family` face, plus\n * any declared emphasis variants, registering each so a `BitmapText` resolves\n * the right sibling. Returns every installed font name (base first) so the\n * caller can hold the family in the reference-counted ledger\n * ({@link acquireBakedFamily}) and uninstall the whole set on final release.\n *\n * Shared by {@link installBitmapFont} (one-shot `.ttf` bake) and the `web-font`\n * loader (declarative `webFont({ bitmap })`), so both bake an identical family.\n */\nfunction bakeBitmapFontFamily(\n  name: string,\n  family: string,\n  opts: WebFontBakeOptions,\n): string[] {\n  // Shared bake params reused by the base atlas and every variant, so the\n  // whole family is sized/charset/padded identically and only the emphasis\n  // axes differ between siblings.\n  const shared = {\n    family,\n    ...(opts.size !== undefined ? { size: opts.size } : {}),\n    ...(opts.chars !== undefined ? { chars: opts.chars } : {}),\n    ...(opts.resolution !== undefined ? { resolution: opts.resolution } : {}),\n    ...(opts.padding !== undefined ? { padding: opts.padding } : {}),\n    ...(opts.style !== undefined ? { style: opts.style } : {}),\n  } satisfies Omit<BakeBitmapFontParams, \"name\">;\n\n  const baseFont = bakeBitmapFont({ name, ...shared });\n  const installed: string[] = [name];\n\n  // Re-installing a font name replaces that family, so the previous install's\n  // emphasis entries go whether or not this install supplies variants (the\n  // registry is process-global and a stale bold would otherwise keep\n  // resolving).\n  unregisterBitmapFontVariants(name);\n\n  // The base atlas registers itself as the regular variant so a `BitmapText`\n  // with an explicit `fontWeight: \"normal\"` resolves back to it.\n  if (opts.variants && opts.variants.length > 0) {\n    const baseKey = emphasisKey({});\n    registerBitmapFontVariant(name, {}, name);\n\n    for (const variant of opts.variants) {\n      const emphasis: BitmapFontEmphasis = {\n        ...(variant.fontWeight !== undefined\n          ? { fontWeight: variant.fontWeight }\n          : {}),\n        ...(variant.fontStyle !== undefined\n          ? { fontStyle: variant.fontStyle }\n          : {}),\n      };\n      // A variant whose weight/style doesn't cross the bold or italic axis\n      // (e.g. `{ fontWeight: \"lighter\" }`) collapses onto the base — skip it\n      // rather than re-bake and clobber the regular atlas under its own name.\n      if (emphasisKey(emphasis) === baseKey) continue;\n      const variantName = variantFontName(name, emphasis);\n      const variantFont = bakeBitmapFont({\n        name: variantName,\n        ...shared,\n        style: {\n          ...shared.style,\n          ...variant.style,\n          ...(variant.fontWeight !== undefined\n            ? { fontWeight: variant.fontWeight }\n            : {}),\n          ...(variant.fontStyle !== undefined\n            ? { fontStyle: variant.fontStyle }\n            : {}),\n        },\n      });\n      // Synthesised bold/italic measure to a different baseline offset and\n      // line height than the regular face even from the same source, which\n      // drifts a mixed-weight line vertically (issue #109). Align the variant\n      // to the base so siblings are baseline-interchangeable.\n      alignBaselineMetrics(variantFont, baseFont);\n      registerBitmapFontVariant(name, emphasis, variantName);\n      installed.push(variantName);\n    }\n  }\n\n  return installed;\n}\n\n/**\n * Copy the reference font's vertical metrics onto a variant so both lay glyphs\n * out on one baseline. `getBitmapTextLayout` seeds `offsetY` from\n * `baseLineOffset` and advances lines by `lineHeight`, so matching those two\n * is what keeps a mixed-emphasis line aligned.\n */\nfunction alignBaselineMetrics(\n  variant: BakedFontMetrics,\n  reference: BakedFontMetrics,\n): void {\n  variant.baseLineOffset = reference.baseLineOffset;\n  variant.lineHeight = reference.lineHeight;\n}\n\n/**\n * The two vertical metrics a baked bitmap font lays glyphs out from, exposed\n * as a writable view so variant baselines can be aligned to the base. Pixi\n * types these `readonly` on `AbstractBitmapFont` and they're inert plain\n * fields at runtime, so writing them is safe — and required to fix #109. The\n * font instance is also Pixi's runtime return of `BitmapFont.install`, which\n * its types declare as `void`.\n */\ninterface BakedFontMetrics {\n  /** Glyph offset from the line baseline (px). */\n  baseLineOffset: number;\n  /** Line advance (px). */\n  lineHeight: number;\n}\n\n/** Parameters for {@link bakeBitmapFont}. */\ninterface BakeBitmapFontParams {\n  /** Name to register the baked font under. */\n  name: string;\n  /** `@font-face` family the loaded face is registered under. */\n  family: string;\n  /** Glyph size (px) to bake the atlas at. Default `32`. */\n  size?: number;\n  /** Character set to bake (Pixi range syntax). Defaults to Pixi's set. */\n  chars?: string | (string | string[])[];\n  /** Atlas resolution multiplier. Default `2`. */\n  resolution?: number;\n  /** Glyph padding in the atlas. Default `4`. */\n  padding?: number;\n  /** Extra `TextStyle` props baked into every glyph. */\n  style?: Partial<TextStyle>;\n}\n\n/**\n * Bake a bitmap glyph atlas from an already-loaded font face via Pixi v8's\n * `BitmapFont.install`. Assumes `family` is registered (e.g. by an\n * `Assets.load` of the source `.ttf`). The single chokepoint that turns a\n * loaded face into a registered bitmap font. Returns the installed font's\n * writable baseline metrics so callers can read or align them (e.g. baseline\n * normalization across emphasis variants).\n */\nfunction bakeBitmapFont(params: BakeBitmapFontParams): BakedFontMetrics {\n  // Pixi types `install` as returning `void` but it returns the installed\n  // DynamicBitmapFont at runtime; we only need its (runtime-mutable) baseline\n  // metrics to normalize emphasis variants onto a shared baseline.\n  const font = BitmapFont.install({\n    name: params.name,\n    style: {\n      // Bake glyphs white by default so per-text `fill` / `tint` (a multiply\n      // over the atlas) can colour them — a black atlas yields `black × tint\n      // = black`. A caller-supplied `style.fill` still wins.\n      fill: 0xffffff,\n      ...params.style,\n      fontFamily: params.family,\n      fontSize: params.size ?? 32,\n    },\n    resolution: params.resolution ?? 2,\n    padding: params.padding ?? 4,\n    ...(params.chars !== undefined ? { chars: params.chars } : {}),\n  }) as unknown as BakedFontMetrics;\n  return font;\n}\n\n/**\n * Resolve a texture input into a concrete texture resource. Keys and handles\n * resolve from the global asset cache — preloaded assets and\n * {@link registerTexture} entries; an unresolvable key throws rather than\n * handing the caller an empty texture.\n */\nexport function resolveTextureInput(input: TextureInput): TextureResource {\n  if (input instanceof AssetHandle || typeof input === \"string\") {\n    const key = typeof input === \"string\" ? input : input.path;\n    const resolved = Texture.from(key) as TextureResource | undefined;\n    if (!resolved) {\n      throw new Error(\n        `Texture \"${key}\" is not loaded — preload it or register it with registerTexture().`,\n      );\n    }\n    return resolved;\n  }\n  return input;\n}\n\n/** Options for {@link createNineSlice}. Slice insets follow pixi's `NineSliceSprite`. */\nexport interface NineSliceOptions {\n  /** Frame {@link TextureInput} — handle, asset key, or raw `Texture`. */\n  readonly texture: TextureInput;\n  /** Left slice-guide inset (source px). */\n  readonly leftWidth: number;\n  /** Top slice-guide inset (source px). */\n  readonly topHeight: number;\n  /** Right slice-guide inset (source px). */\n  readonly rightWidth: number;\n  /** Bottom slice-guide inset (source px). */\n  readonly bottomHeight: number;\n  /** Rendered width (px) the frame stretches to. */\n  readonly width: number;\n  /** Rendered height (px) the frame stretches to. */\n  readonly height: number;\n}\n\n/**\n * Build a `NineSliceSprite` from an engine-resolved {@link TextureInput} — a\n * stretchable textured frame whose corners stay crisp at any size. Returns the\n * raw display object so callers can parent it into their own container, the\n * same escape-hatch shape as {@link resolveTextureInput}. This is the renderer's\n * nine-slice primitive: reach for it (not a direct `pixi.js` import) when\n * building textured panels, dialogue/UI frames, or buttons.\n *\n * `width`/`height` are required: a nine-slice is stretched to a target size, and\n * defaulting to the (possibly unloaded → 0×0) texture size would silently bake a\n * degenerate frame.\n */\nexport function createNineSlice(options: NineSliceOptions): NineSliceSprite {\n  return new PixiNineSliceSprite({\n    texture: resolveTextureInput(options.texture),\n    leftWidth: options.leftWidth,\n    topHeight: options.topHeight,\n    rightWidth: options.rightWidth,\n    bottomHeight: options.bottomHeight,\n    width: options.width,\n    height: options.height,\n  });\n}\n\n/** Inputs for {@link measureWrappedText}. */\nexport interface MeasureTextOptions {\n  /** Canvas font family (or a baked bitmap-font name when `bitmap`). */\n  readonly fontFamily?: string;\n  /** Font size in px. */\n  readonly fontSize: number;\n  /** Vertical advance per line in px (defaults to the font's natural height). */\n  readonly lineHeight?: number;\n  /** Wrap width in px. Omit or `<= 0` to measure a single unwrapped line. */\n  readonly wordWrapWidth?: number;\n  /**\n   * Measure via the bitmap-font path (`BitmapFontManager`): `fontFamily` names\n   * a baked atlas. Wrap-aware like the canvas path, and returns px (the atlas's\n   * base-unit metrics are scaled to `fontSize`).\n   */\n  readonly bitmap?: boolean;\n}\n\n/** Natural laid-out size of a (optionally wrapped) text string. */\nexport interface MeasuredText {\n  readonly width: number;\n  readonly height: number;\n  /** Number of laid-out lines (wrap-aware on the canvas path; `>= 1`). */\n  readonly lineCount: number;\n}\n\n/**\n * One reused mutable style for all measurement. Pixi keys its metrics caches on\n * `style.styleKey` = `${uid}-${tick}` (identity-based), so a fresh `TextStyle`\n * per call could never hit and would push a dead entry into the 1000-slot LRU\n * each time. Reusing one instance keeps the key stable across identical\n * consecutive measures (pixi setters no-op on same-value writes). Lazy so\n * importing this module never constructs pixi state.\n */\nlet measureStyle: PixiTextStyle | undefined;\n/** Style keys applied by the previous measure (to reset what this one omits). */\nlet measureStyleKeys: readonly string[] = [];\n\n/** Apply `resolved` onto the shared measurement style, clearing leftovers. */\nfunction applyMeasureStyle(resolved: TextStyle): PixiTextStyle {\n  const style = (measureStyle ??= new PixiTextStyle());\n  const target = style as unknown as Record<string, unknown>;\n  const next = resolved as Record<string, unknown>;\n  const defaults = PixiTextStyle.defaultTextStyle as Record<string, unknown>;\n  for (const key of measureStyleKeys) {\n    if (!(key in next)) target[key] = defaults[key];\n  }\n  for (const key in next) target[key] = next[key];\n  measureStyleKeys = Object.keys(next);\n  return style;\n}\n\n/**\n * Measure the natural size of a text string — wrap-aware — without constructing\n * a live text node. This is the renderer's text-metrics primitive: reach for it\n * (not a direct `pixi.js` import) when a layout needs to size a panel to its\n * text (e.g. a content-sized dialogue bubble).\n *\n * Both paths honour `wordWrapWidth`, so `lineCount` reflects the wrapped line\n * count: canvas via Pixi's `CanvasTextMetrics`, bitmap via `BitmapFontManager`\n * (whose base-unit metrics are scaled to `fontSize`, matching what a\n * `BitmapText` renders at). Measurement resolves the engine-level\n * `defaultTextStyle` under the given options — the same merge the render path\n * applies — so the measured box matches the drawn text.\n *\n * Requires a DOM/canvas at runtime (the browser) for the canvas path; unit tests\n * mock `CanvasTextMetrics` (there is no canvas under the node test env).\n */\nexport function measureWrappedText(\n  text: string,\n  options: MeasureTextOptions,\n): MeasuredText {\n  const wrap = options.wordWrapWidth !== undefined && options.wordWrapWidth > 0;\n  const resolved =\n    resolveTextStyle({\n      fontSize: options.fontSize,\n      ...(options.fontFamily !== undefined\n        ? { fontFamily: options.fontFamily }\n        : {}),\n      ...(options.lineHeight !== undefined\n        ? { lineHeight: options.lineHeight }\n        : {}),\n      wordWrap: wrap,\n      ...(wrap ? { wordWrapWidth: options.wordWrapWidth } : {}),\n    }) ?? {};\n  // Bitmap text redirects `fontFamily` to a registered emphasis-variant atlas\n  // (e.g. a defaultTextStyle `fontWeight` selecting the bold bake) — measure\n  // through the same atlas the render path draws from.\n  const style = applyMeasureStyle(\n    options.bitmap ? (selectBitmapVariant(resolved) ?? resolved) : resolved,\n  );\n  if (options.bitmap) {\n    // `getLayout` (what `measureText` delegates to, with `lines` in its type)\n    // returns font base-measurement units; scale to px the same way pixi's own\n    // `BitmapText.updateBounds` does.\n    const m = BitmapFontManager.getLayout(text, style);\n    return {\n      width: m.width * m.scale,\n      height: m.height * m.scale,\n      lineCount: m.lines.length,\n    };\n  }\n  const m = CanvasTextMetrics.measureText(text, style);\n  return { width: m.width, height: m.height, lineCount: m.lines.length };\n}\n\n/** Slice a texture input into an array of frame textures. */\nexport function sliceTextureFrames(\n  input: TextureInput,\n  options: TextureSliceOptions,\n): TextureResource[] {\n  return sliceGridNamed(\n    resolveTextureInput(input),\n    options,\n    \"sliceTextureFrames\",\n  );\n}\n","import { Texture, Rectangle, Assets } from \"pixi.js\";\nimport type { Spritesheet } from \"pixi.js\";\nimport type { TextureRef, TextureSliceOptions } from \"./public-types.js\";\nimport { resolveTextureInput } from \"./assets.js\";\nimport { assertCount, assertFiniteNumber } from \"./internal/validate.js\";\n\n/** Grid options with defaults applied against a concrete texture. */\ninterface GridLayout {\n  frameWidth: number;\n  frameHeight: number;\n  startX: number;\n  startY: number;\n  gapX: number;\n  gapY: number;\n  columns: number;\n  count: number;\n}\n\n/**\n * Names the public entry a grid error is attributed to, plus the sheet key\n * when the caller resolved one.\n */\ninterface GridContext {\n  fn: string;\n  sheet?: string;\n}\n\n/**\n * Resolve slice options into a concrete grid and validate it against the\n * texture. Every public entry that slices a grid goes through here, so the\n * degenerate cases fail with an authored message instead of producing an\n * unbounded frame count or frames that read past the texture.\n */\nfunction resolveGridLayout(\n  base: Texture,\n  options: TextureSliceOptions,\n  context: GridContext,\n): GridLayout {\n  const frameWidth = options.frameWidth;\n  const frameHeight = options.frameHeight ?? frameWidth;\n  const startX = options.startX ?? 0;\n  const startY = options.startY ?? 0;\n  const gapX = options.gapX ?? 0;\n  const gapY = options.gapY ?? 0;\n  const columns =\n    options.columns ??\n    Math.max(1, Math.floor((base.width - startX + gapX) / (frameWidth + gapX)));\n  const count = options.count ?? columns;\n  const layout: GridLayout = {\n    frameWidth,\n    frameHeight,\n    startX,\n    startY,\n    gapX,\n    gapY,\n    columns,\n    count,\n  };\n  validateGridLayout(base, layout, context);\n  return layout;\n}\n\nfunction validateGridLayout(\n  base: Texture,\n  layout: GridLayout,\n  { fn, sheet }: GridContext,\n): void {\n  const forSheet = sheet !== undefined ? ` for sheet \"${sheet}\"` : \"\";\n  const context = `${fn}${forSheet}`;\n  for (const [name, value, min] of [\n    [\"frameWidth\", layout.frameWidth, 1],\n    [\"frameHeight\", layout.frameHeight, 1],\n    [\"startX\", layout.startX, 0],\n    [\"startY\", layout.startY, 0],\n    [\"gapX\", layout.gapX, 0],\n    [\"gapY\", layout.gapY, 0],\n  ] as const) {\n    assertFiniteNumber(context, name, value, min);\n  }\n  // Both index the grid: a fractional columns places frames at fractional\n  // offsets, and a fractional count slices one frame too many.\n  assertCount(context, \"columns\", layout.columns);\n  assertCount(context, \"count\", layout.count);\n  const usedColumns = Math.min(layout.count, layout.columns);\n  const rows = Math.ceil(layout.count / layout.columns);\n  const maxX =\n    layout.startX +\n    usedColumns * layout.frameWidth +\n    (usedColumns - 1) * layout.gapX;\n  const maxY =\n    layout.startY + rows * layout.frameHeight + (rows - 1) * layout.gapY;\n  if (maxX > base.width || maxY > base.height) {\n    throw new Error(\n      `${fn}: the frame grid${forSheet} extends to ` +\n        `${maxX}×${maxY}, exceeding the ${base.width}×${base.height} texture ` +\n        `(frameWidth ${layout.frameWidth}, frameHeight ${layout.frameHeight}, ` +\n        `columns ${layout.columns}, count ${layout.count}).`,\n    );\n  }\n}\n\nfunction buildFrames(base: Texture, layout: GridLayout): Texture[] {\n  const frames: Texture[] = [];\n  for (let index = 0; index < layout.count; index++) {\n    const column = index % layout.columns;\n    const row = Math.floor(index / layout.columns);\n    frames.push(\n      new Texture({\n        source: base.source,\n        frame: new Rectangle(\n          layout.startX + column * (layout.frameWidth + layout.gapX),\n          layout.startY + row * (layout.frameHeight + layout.gapY),\n          layout.frameWidth,\n          layout.frameHeight,\n        ),\n      }),\n    );\n  }\n  return frames;\n}\n\n/**\n * Slice a grid, attributing a validation failure to the public function the\n * game actually called.\n *\n * @internal\n */\nexport function sliceGridNamed(\n  base: Texture,\n  options: TextureSliceOptions,\n  fn: string,\n): Texture[] {\n  return buildFrames(base, resolveGridLayout(base, options, { fn }));\n}\n\n/**\n * Slice a texture into frame Textures on a uniform grid.\n *\n * Frame `i` is read at column `i % columns`, row `floor(i / columns)`.\n * Without `columns`, the column count is derived from the texture width;\n * without `count`, a single full row is read.\n *\n * Throws when a field is not a finite number at or above its minimum, or when\n * the resulting grid extends past the texture.\n */\nexport function sliceGrid(\n  base: Texture,\n  options: TextureSliceOptions,\n): Texture[] {\n  return sliceGridNamed(base, options, \"sliceGrid\");\n}\n\n/**\n * Slice a single-row horizontal spritesheet into individual frame Textures.\n *\n * Only reads the top row of the image (`y = 0`). For multi-row grid sheets,\n * use a {@link SheetFrameSource} with `count`/`columns` (or call\n * {@link sliceGrid} directly); for non-uniform frame layouts, use PixiJS's\n * `Spritesheet` class with a JSON atlas descriptor (TexturePacker / Aseprite\n * JSON export format).\n *\n * @param source - A PixiJS Texture or asset path string.\n * @param frameWidth - Width of each frame in pixels.\n * @param frameHeight - Height of each frame (defaults to `frameWidth` for square frames).\n */\nexport function sliceSheet(\n  source: Texture | string,\n  frameWidth: number,\n  frameHeight?: number,\n): Texture[] {\n  // String keys resolve through the shared guard, so an unloaded /\n  // unregistered sheet fails loudly naming the key instead of slicing an\n  // empty texture.\n  const base = source instanceof Texture ? source : resolveTextureInput(source);\n  return sliceGridNamed(\n    base,\n    {\n      frameWidth,\n      ...(frameHeight !== undefined ? { frameHeight } : {}),\n    },\n    \"sliceSheet\",\n  );\n}\n\n// ---------------------------------------------------------------------------\n// FrameSource — asset-backed frame descriptors\n// ---------------------------------------------------------------------------\n\n/**\n * A sprite sheet sliced on a uniform grid. Without `count`/`columns` it\n * reads the single top row (a horizontal strip); `count` extends the slice\n * across rows, wrapping every `columns` frames. Offsets and gaps follow\n * {@link TextureSliceOptions}.\n */\nexport interface SheetFrameSource extends TextureSliceOptions {\n  /**\n   * The sheet to slice: an asset key, or the texture handle a `texture(...)`\n   * declaration returns. Both resolve from the cache a `SpriteComponent`\n   * texture resolves from.\n   */\n  sheet: TextureRef;\n}\n\n/** A named animation within a JSON atlas spritesheet. */\nexport interface AtlasFrameSource {\n  atlas: string;\n  animation: string;\n}\n\n/** Union type for asset-backed frame references. */\nexport type FrameSource = SheetFrameSource | AtlasFrameSource;\n\nexport function isSheetSource(s: FrameSource): s is SheetFrameSource {\n  return \"sheet\" in s;\n}\n\nexport function isAtlasSource(s: FrameSource): s is AtlasFrameSource {\n  return \"atlas\" in s;\n}\n\n/**\n * Resolve a FrameSource to concrete Texture[].\n * Assets must already be loaded (via scene preload) — this is synchronous.\n */\nexport function resolveFrames(source: FrameSource): Texture[] {\n  if (isSheetSource(source)) {\n    const { sheet, ...options } = source;\n    // Resolve through the shared guard so an unloaded / unregistered sheet\n    // fails loudly naming the key instead of reading an undefined texture.\n    const base = resolveTextureInput(sheet);\n    const layout = resolveGridLayout(base, options, {\n      fn: \"resolveFrames\",\n      sheet: typeof sheet === \"string\" ? sheet : sheet.path,\n    });\n    return buildFrames(base, layout);\n  }\n  const spritesheet = Assets.get<Spritesheet>(source.atlas);\n  if (!spritesheet) {\n    throw new Error(\n      `resolveFrames: atlas \"${source.atlas}\" is not loaded. Add it to scene preload.`,\n    );\n  }\n  const textures = spritesheet.animations[source.animation];\n  if (!textures) {\n    throw new Error(\n      `resolveFrames: animation \"${source.animation}\" not found in atlas \"${source.atlas}\".`,\n    );\n  }\n  if (textures.length === 0) {\n    throw new Error(\n      `resolveFrames: animation \"${source.animation}\" in atlas \"${source.atlas}\" has no frames.`,\n    );\n  }\n  return textures;\n}\n","/**\n * Ownership ledger for baked bitmap-font families, keyed by the base font name\n * a `BitmapText` resolves against. A single baked family can have more than one\n * owner:\n *\n *   - each `installBitmapFont(name)` call (owner key `install:<name>`), and\n *   - each `webFont(path, { bitmap })` load (owner key `web-font:<path>`).\n *\n * Pixi's `BitmapFont.uninstall` and our emphasis-variant registry are both\n * global and NOT reference-counted, so tearing a family down the instant one\n * owner releases it would destroy the atlas under every other owner. This\n * ledger ref-counts by base name (an owner *set*, so re-acquiring under the\n * same key is idempotent — re-installing a font is one owner, not two) and\n * hands back the full list of installed names to uninstall only once the last\n * owner has let go. Keeping the actual Pixi teardown in the caller keeps this\n * module free of a `pixi.js` import, mirroring `bitmapFontVariants`.\n *\n * @internal\n */\ninterface BakedFamily {\n  /** Owner keys currently holding this family alive. */\n  owners: Set<string>;\n  /**\n   * Every Pixi font name installed for this family (base + emphasis variants),\n   * unioned across owners so a final release uninstalls them all — even atlases\n   * a clobbered re-bake orphaned from the variant registry.\n   */\n  names: Set<string>;\n}\n\nconst bakedFamilies = new Map<string, BakedFamily>();\n\n/**\n * Record that `owner` holds the baked family `baseName`, installed as `names`\n * (base first, then any emphasis variants). Re-acquiring under the same owner\n * key only unions in any newly-baked names — it does not add a second\n * reference, so an idempotent re-install stays a single owner.\n *\n * @internal\n */\nexport function acquireBakedFamily(\n  owner: string,\n  baseName: string,\n  names: readonly string[],\n): void {\n  let entry = bakedFamilies.get(baseName);\n  if (!entry) {\n    entry = { owners: new Set(), names: new Set() };\n    bakedFamilies.set(baseName, entry);\n  }\n  entry.owners.add(owner);\n  for (const name of names) entry.names.add(name);\n}\n\n/**\n * Release `owner`'s hold on the baked family `baseName`. Returns every Pixi\n * font name to uninstall (base + variants) when the last owner let go, so the\n * caller can `BitmapFont.uninstall` each and drop the variant registry; returns\n * `null` while other owners still hold the family (or when the family/owner is\n * unknown), meaning nothing should be torn down.\n *\n * @internal\n */\nexport function releaseBakedFamily(\n  owner: string,\n  baseName: string,\n): string[] | null {\n  const entry = bakedFamilies.get(baseName);\n  if (!entry) return null;\n  entry.owners.delete(owner);\n  if (entry.owners.size > 0) return null;\n  bakedFamilies.delete(baseName);\n  return [...entry.names];\n}\n\n/** Drop the baked-family ledger — test isolation only. @internal */\nexport function clearBakedFamilies(): void {\n  bakedFamilies.clear();\n}\n","import { Sprite } from \"pixi.js\";\nimport { resolveTextureInput } from \"./assets.js\";\nimport type { DisplaySprite, TextureRef } from \"./public-types.js\";\nimport {\n  VisualComponent,\n  type VisualComponentOptions,\n} from \"./VisualComponent.js\";\n\n/** Options for creating a SpriteComponent. */\nexport interface SpriteComponentOptions extends VisualComponentOptions {\n  /**\n   * Texture asset key or typed handle. Runtime-created textures are\n   * referenced by registering them under a key first (`registerTexture`).\n   */\n  texture: TextureRef;\n  /** Anchor point (0-1). */\n  anchor?: { x: number; y: number };\n}\n\n/** Component that displays a PixiJS Sprite. */\nexport class SpriteComponent extends VisualComponent {\n  readonly sprite: DisplaySprite;\n\n  constructor(options: SpriteComponentOptions) {\n    super(options.layer);\n    this.sprite = Sprite.from(resolveTextureInput(options.texture));\n    if (options.anchor) {\n      this.sprite.anchor.set(options.anchor.x, options.anchor.y);\n    }\n    this.applyVisualOptions(options);\n  }\n\n  /** The underlying Pixi display object. */\n  get renderObject(): DisplaySprite {\n    return this.sprite;\n  }\n\n  /** Replace the sprite's texture. */\n  setTexture(texture: TextureRef): void {\n    this.sprite.texture = resolveTextureInput(texture);\n  }\n}\n","import type { Vec2Like } from \"@yagejs/core\";\nimport { Graphics } from \"pixi.js\";\nimport { assertFiniteNumber } from \"./internal/validate.js\";\nimport type { GraphicsContext } from \"./public-types.js\";\nimport {\n  VisualComponent,\n  type VisualComponentOptions,\n} from \"./VisualComponent.js\";\n\n/** Options for creating a GraphicsComponent. */\nexport interface GraphicsComponentOptions extends VisualComponentOptions {\n  /**\n   * The point of the drawing that sits on the entity position, in the\n   * drawing's own pixels. Rotation and scale turn the drawing about it.\n   * Default `{ x: 0, y: 0 }`, the origin the `draw` callback draws around.\n   * The other visual components take `anchor` for the same purpose, as a\n   * fraction of the texture; a drawing has no texture size to take a fraction\n   * of, so this is in pixels.\n   */\n  pivot?: Vec2Like;\n}\n\n/** Component that wraps a PixiJS Graphics object for procedural drawing. */\nexport class GraphicsComponent extends VisualComponent {\n  readonly graphics: GraphicsContext;\n\n  constructor(options?: GraphicsComponentOptions) {\n    super(options?.layer);\n    this.graphics = new Graphics();\n    if (options?.pivot) {\n      const { x, y } = options.pivot;\n      assertFiniteNumber(\"GraphicsComponent.constructor\", \"pivot.x\", x);\n      assertFiniteNumber(\"GraphicsComponent.constructor\", \"pivot.y\", y);\n      this.graphics.pivot.set(x, y);\n    }\n    if (options) this.applyVisualOptions(options);\n  }\n\n  /** The underlying Pixi display object. */\n  get renderObject(): GraphicsContext {\n    return this.graphics;\n  }\n\n  /** Execute a drawing function on the graphics object. Returns this for chaining. */\n  draw(fn: (g: GraphicsContext) => void): this {\n    fn(this.graphics);\n    return this;\n  }\n}\n","import { BitmapText, Text } from \"pixi.js\";\nimport { buildTextOptions } from \"./internal/textConstruction.js\";\nimport type {\n  DisplayBitmapText,\n  DisplayText,\n  TextStyle,\n} from \"./public-types.js\";\nimport {\n  VisualComponent,\n  type VisualComponentOptions,\n} from \"./VisualComponent.js\";\n\n/** Options for creating a TextComponent. */\nexport interface TextComponentOptions extends VisualComponentOptions {\n  /** The text string to render. */\n  text: string;\n  /** Text style — forwards to PixiJS TextStyleOptions (CSS-like font properties). */\n  style?: TextStyle;\n  /**\n   * Render with a bitmap font instead of canvas-rasterised `Text` — the\n   * pixel-art escape hatch that stays crisp at non-integer scale. Pixi bakes\n   * or looks up the glyph atlas from `style.fontFamily` (the name an\n   * {@link installBitmapFont} call registered, or any font for a dynamic\n   * bake) at `style.fontSize`.\n   */\n  bitmap?: boolean;\n  /**\n   * Per-text render resolution. Mirrors the Pixi v8 `Text` constructor\n   * option — note `resolution` is NOT a `TextStyle` property in v8, so\n   * setting it here is the only way to get crisp canvas text without a\n   * prototype patch. Ignored when `bitmap` is set (bitmap resolution is\n   * fixed at font-bake time).\n   */\n  resolution?: number;\n  /** Anchor point (0-1). Default: { x: 0, y: 0 } (top-left). */\n  anchor?: { x: number; y: number };\n}\n\n/** Component that displays text on a render layer. */\nexport class TextComponent extends VisualComponent {\n  readonly text: DisplayText | DisplayBitmapText;\n  // Raw style options are kept so mergeStyle can preserve prior values.\n  private _styleOptions?: TextStyle;\n  // The bitmap choice is needed when a later style update rebuilds options.\n  private _bitmap?: boolean;\n\n  constructor(options: TextComponentOptions) {\n    super(options.layer);\n    const { options: textOptions, bitmap } = buildTextOptions(\n      options.text,\n      options.style,\n      options.bitmap,\n      options.resolution,\n    );\n    this.text = bitmap ? new BitmapText(textOptions) : new Text(textOptions);\n    // Shallow-clone so external mutation does not affect later mergeStyle calls.\n    if (options.style) this._styleOptions = { ...options.style };\n    if (options.bitmap !== undefined) this._bitmap = options.bitmap;\n\n    if (options.anchor) {\n      this.text.anchor.set(options.anchor.x, options.anchor.y);\n    }\n    this.applyVisualOptions(options);\n  }\n\n  /** The underlying Pixi display object. */\n  get renderObject(): DisplayText | DisplayBitmapText {\n    return this.text;\n  }\n\n  /**\n   * The string currently displayed. {@link text} is the Pixi display object,\n   * so this is the way to read the rendered string back — including from the\n   * Inspector, which reflects public getters but skips the display object.\n   */\n  get content(): string {\n    return this.text.text;\n  }\n\n  /** Replace the displayed string. */\n  setText(value: string): void {\n    this.text.text = value;\n  }\n\n  /**\n   * Replace the text style. Unset properties fall back to the engine default\n   * (then Pixi's), so this is a full replace, not a patch — to change a few\n   * properties while keeping the rest, use {@link mergeStyle}.\n   */\n  setStyle(style: TextStyle): void {\n    // Route through buildTextOptions so the bitmap-variant redirect (synthetic\n    // bold/italic via baked variant atlases) runs on the update path too —\n    // calling resolveTextStyle directly would let `fontWeight`/`fontStyle`\n    // changes silently land on the base atlas on a `bitmap: true` text.\n    const { options } = buildTextOptions(\n      this.text.text,\n      style,\n      this._bitmap,\n      undefined,\n    );\n    this.text.style = options.style ?? style;\n    this._styleOptions = { ...style };\n  }\n\n  /**\n   * Patch the current style: merge `style` over the properties already set\n   * (construction or a prior `setStyle`/`mergeStyle`) and re-apply. Unlike\n   * {@link setStyle}, properties you don't pass are preserved — handy for an\n   * imperative recolour (`mergeStyle({ fill })`) that keeps the font, size,\n   * weight, etc.\n   */\n  mergeStyle(style: TextStyle): void {\n    this.setStyle({ ...this._styleOptions, ...style });\n  }\n}\n","import { SplitText, SplitBitmapText } from \"pixi.js\";\nimport { buildTextOptions } from \"./internal/textConstruction.js\";\nimport {\n  initialAutoSplit,\n  setSplitText,\n  splitIfNotEmpty,\n} from \"./internal/split-text-guard.js\";\nimport type {\n  DestroyOptions,\n  DisplayBitmapText,\n  DisplayContainer,\n  DisplaySplitBitmapText,\n  DisplaySplitText,\n  DisplayText,\n  TextStyle,\n} from \"./public-types.js\";\nimport type { RenderFacetSnapshot } from \"./internal/renderFacet.js\";\nimport {\n  VisualComponent,\n  type VisualComponentOptions,\n} from \"./VisualComponent.js\";\n\n/**\n * Renderer-specific extras `SplitTextComponent.inspectRender()` attaches on\n * top of the shared {@link RenderFacetSnapshot} base. Lets a typewriter reveal\n * be observed purely through the Inspector — `glyphs[i].visible` mirrors the\n * per-character display objects, and `visibleText` is the currently-painted\n * substring (whitespace-stripped: Pixi treats spaces as separators between\n * `words`/`lines`, not as `chars`, so a fully-revealed `\"Hello world\"` reports\n * `\"Helloworld\"`).\n */\nexport interface SplitTextRenderFacetExtras {\n  glyphs: Array<{ visible: boolean }>;\n  visibleText: string;\n}\n\n/** The full render facet shape returned by {@link SplitTextComponent.inspectRender}. */\nexport type SplitTextRenderFacet =\n  RenderFacetSnapshot<SplitTextRenderFacetExtras>;\n\n/**\n * Transform origin for a text segment, normalized 0–1. `0` is top-left, `0.5`\n * is center, `1` is bottom-right. A single number applies to both axes.\n */\nexport type SegmentAnchor = number | { x: number; y: number };\n\n/** Options for creating a {@link SplitTextComponent}. */\nexport interface SplitTextComponentOptions extends VisualComponentOptions {\n  /** The text string to render and segment. */\n  text: string;\n  /** Text style — forwards to PixiJS TextStyleOptions (CSS-like font properties). */\n  style?: TextStyle;\n  /**\n   * Transform origin for the whole text block, normalized 0–1.\n   * Default: { x: 0, y: 0 } (top-left).\n   */\n  anchor?: { x: number; y: number };\n  /**\n   * Render the segments with a bitmap font (`SplitBitmapText`) instead of\n   * canvas `Text` (`SplitText`). Pass the installed/baked font name as\n   * `style.fontFamily` (and glyph size as `style.fontSize`).\n   */\n  bitmap?: boolean;\n  /** Transform origin for each character. Default `0` (top-left). */\n  charAnchor?: SegmentAnchor;\n  /** Transform origin for each word. Default `0` (top-left). */\n  wordAnchor?: SegmentAnchor;\n  /** Transform origin for each line. Default `0` (top-left). */\n  lineAnchor?: SegmentAnchor;\n  /**\n   * Re-split automatically when `text` / `style` change. Default `true`.\n   * Set `false` and call {@link SplitTextComponent.resplit} to batch updates.\n   */\n  autoSplit?: boolean;\n}\n\n/**\n * Displays text split into per-character / per-word / per-line display\n * objects, for animated and rich text — typewriter reveals, per-letter\n * colour / wave, staggered line entrances. Wraps Pixi v8's `SplitText`\n * (canvas) / `SplitBitmapText` (bitmap); the segments are exposed as\n * {@link SplitTextComponent.chars}, {@link SplitTextComponent.words}, and\n * {@link SplitTextComponent.lines} for the game to animate directly.\n *\n * For static or simple dynamic strings prefer {@link TextComponent} — a single\n * display object is cheaper and `SplitText` re-layout on every `text` change is\n * not free.\n *\n * @experimental Pixi marks `SplitText` experimental; its char spacing can\n * differ slightly from `Text` (browser kerning is lost once glyphs are split).\n */\nexport class SplitTextComponent extends VisualComponent {\n  /** The underlying Pixi `SplitText` / `SplitBitmapText` container. */\n  readonly splitText: DisplaySplitText | DisplaySplitBitmapText;\n  /** Whether this renders with a bitmap font (`SplitBitmapText`). */\n  readonly isBitmap: boolean;\n  private _bitmap?: boolean;\n  private _anchor?: { x: number; y: number };\n  private readonly _autoSplit: boolean;\n\n  constructor(options: SplitTextComponentOptions) {\n    super(options.layer);\n    // Reuse the shared builder for style-default resolution and the\n    // canvas/bitmap class pick. `resolution` is N/A for split text (Pixi's\n    // SplitOptions has no resolution), so it's not forwarded.\n    const { options: textOptions, bitmap } = buildTextOptions(\n      options.text,\n      options.style,\n      options.bitmap,\n      undefined,\n    );\n    this.isBitmap = bitmap;\n    this._autoSplit = options.autoSplit ?? true;\n    const splitOptions = {\n      text: options.text,\n      style: textOptions.style ?? {},\n      ...(options.charAnchor !== undefined\n        ? { charAnchor: options.charAnchor }\n        : {}),\n      ...(options.wordAnchor !== undefined\n        ? { wordAnchor: options.wordAnchor }\n        : {}),\n      ...(options.lineAnchor !== undefined\n        ? { lineAnchor: options.lineAnchor }\n        : {}),\n      // Never hand Pixi's split an empty string; see `setSplitText`.\n      autoSplit: initialAutoSplit(this._autoSplit, options.text),\n    };\n    this.splitText = bitmap\n      ? new SplitBitmapText(splitOptions)\n      : new SplitText(splitOptions);\n\n    if (options.bitmap !== undefined) this._bitmap = options.bitmap;\n    if (options.anchor) this._anchor = { ...options.anchor };\n\n    this.applyBlockAnchor();\n    this.applyVisualOptions(options);\n  }\n\n  /** The underlying Pixi display object. */\n  get renderObject(): DisplaySplitText | DisplaySplitBitmapText {\n    return this.splitText;\n  }\n\n  /** Individual character segments (`Text` or `BitmapText`), in reading order. */\n  get chars(): (DisplayText | DisplayBitmapText)[] {\n    return this.splitText.chars;\n  }\n\n  /** Word-group containers, each holding its character segments. */\n  get words(): DisplayContainer[] {\n    return this.splitText.words;\n  }\n\n  /** Line-group containers, each holding its word containers. */\n  get lines(): DisplayContainer[] {\n    return this.splitText.lines;\n  }\n\n  /**\n   * Replace the displayed string (re-splits when `autoSplit` is on). An empty\n   * string renders nothing and leaves the segments empty.\n   */\n  setText(value: string): void {\n    setSplitText(this.splitText, value, this._autoSplit);\n    this.applyBlockAnchor();\n  }\n\n  /**\n   * The string currently displayed. {@link splitText} is the Pixi display\n   * object, so this is the way to read the rendered string back — including\n   * from the Inspector, which reflects public getters but skips display\n   * objects.\n   */\n  get content(): string {\n    return this.splitText.text;\n  }\n\n  /** Replace the text style (re-splits when `autoSplit` is on). */\n  setStyle(style: TextStyle): void {\n    const { options } = buildTextOptions(\n      this.splitText.text,\n      style,\n      this._bitmap,\n      undefined,\n    );\n    this.splitText.style = options.style ?? style;\n    this.applyBlockAnchor();\n  }\n\n  /**\n   * Re-split now. Only needed when constructed with `autoSplit: false` — after\n   * mutating `text` / `style`, call this to apply the change in one pass.\n   */\n  resplit(): void {\n    if (!splitIfNotEmpty(this.splitText)) return;\n    this.applyBlockAnchor();\n  }\n\n  /** Transform origin for each character (normalized 0–1). */\n  set charAnchor(anchor: SegmentAnchor) {\n    this.splitText.charAnchor = anchor;\n  }\n  get charAnchor(): SegmentAnchor {\n    return this.splitText.charAnchor;\n  }\n\n  /** Transform origin for each word (normalized 0–1). */\n  set wordAnchor(anchor: SegmentAnchor) {\n    this.splitText.wordAnchor = anchor;\n  }\n  get wordAnchor(): SegmentAnchor {\n    return this.splitText.wordAnchor;\n  }\n\n  /** Transform origin for each line (normalized 0–1). */\n  set lineAnchor(anchor: SegmentAnchor) {\n    this.splitText.lineAnchor = anchor;\n  }\n  get lineAnchor(): SegmentAnchor {\n    return this.splitText.lineAnchor;\n  }\n\n  private applyBlockAnchor(): void {\n    if (!this._anchor) return;\n    const bounds = this.splitText.getLocalBounds();\n    this.splitText.pivot.set(\n      bounds.x + bounds.width * this._anchor.x,\n      bounds.y + bounds.height * this._anchor.y,\n    );\n  }\n\n  /**\n   * Derived render facet for the Inspector. Beyond the shared world-space\n   * `bounds` and container-level `visible`, this walks the per-character\n   * segments and reports `glyphs` (one `{ visible }` per char in reading\n   * order) plus `visibleText` — the substring currently painted. This is the\n   * read-only window into a typewriter reveal: `visibleText` reports only the\n   * glyphs whose `chars[i].visible` is still on. See {@link computeRenderFacet}\n   * for the bounds coordinate space.\n   *\n   * Note: Pixi's `chars` array (and therefore `glyphs` / `visibleText`)\n   * contains only the rendered glyph segments — whitespace is laid out via\n   * `words`/`lines` and is NOT a char. So `visibleText` strips spaces: a fully\n   * revealed `\"Hello world\"` reports `\"Helloworld\"`. Use it to compare *which\n   * glyphs* are on screen, not to reconstruct the original string verbatim.\n   */\n  inspectRender(): SplitTextRenderFacet {\n    const facet = super.inspectRender();\n    const chars = this.splitText.chars;\n    const glyphs = chars.map((char) => ({ visible: char.visible }));\n    const visibleText = chars\n      .filter((char) => char.visible)\n      .map((char) => char.text)\n      .join(\"\");\n    return { ...facet, glyphs, visibleText };\n  }\n\n  /**\n   * `{ children: true }` so the per-line / word / char display objects that\n   * `split()` parented are destroyed too (not freed by the default destroy).\n   */\n  protected destroyOptions(): DestroyOptions {\n    return { children: true };\n  }\n}\n","import type {\n  DisplaySplitBitmapText,\n  DisplaySplitText,\n} from \"../public-types.js\";\n\ntype AnySplitText = DisplaySplitText | DisplaySplitBitmapText;\n\n/**\n * Pixi's split of an empty string produces zero line containers, and\n * `AbstractSplitText.split()` then calls `addChild()` with no arguments,\n * which reads `children[0].parent` and throws a `TypeError` naming Pixi\n * internals (pixi.js 8.17). Every function here keeps that call from\n * happening while the text is empty: the segment arrays stay empty, which is\n * what an empty string should produce, and the first non-empty value splits\n * normally.\n *\n * `AbstractSplitText` takes `autoSplit` as a constructor option and exposes no\n * setter for it, so the field is written directly. A Pixi release that renames\n * it would silently restore the crash; the empty-string specs beside the two\n * components are what catches that.\n */\nfunction setAutoSplit(target: AnySplitText, on: boolean): void {\n  (target as unknown as { _autoSplit: boolean })._autoSplit = on;\n}\n\n/**\n * The `autoSplit` constructor option for a split text built with `text`.\n * `autoSplit` is what the caller asked for.\n */\nexport function initialAutoSplit(autoSplit: boolean, text: string): boolean {\n  return autoSplit && text !== \"\";\n}\n\n/**\n * Assign `text` and keep automatic splitting on only while there is something\n * to split. `autoSplit` is what the caller asked for.\n */\nexport function setSplitText(\n  target: AnySplitText,\n  text: string,\n  autoSplit: boolean,\n): void {\n  setAutoSplit(target, initialAutoSplit(autoSplit, text));\n  target.text = text;\n}\n\n/**\n * Split now, unless the text is empty. Reports whether it split, so a caller\n * can skip the work that only makes sense around fresh segments.\n */\nexport function splitIfNotEmpty(target: AnySplitText): boolean {\n  if (target.text === \"\") return false;\n  target.split();\n  return true;\n}\n","import { FillGradient } from \"pixi.js\";\nimport type { GradientFill } from \"./public-types.js\";\n\n/** A single color stop along a gradient, with yage's numeric color + alpha pair. */\nexport interface GradientStop {\n  /** Position along the gradient, 0 (start) to 1 (end). */\n  offset: number;\n  /** Color as 0xRRGGBB. */\n  color: number;\n  /** Opacity 0-1. Default: 1. */\n  alpha?: number;\n}\n\n/**\n * How gradient coordinates are interpreted.\n *\n * - `\"local\"` — `start`/`end` (or `innerCenter`/`outerCenter`) are in the 0-1\n *   space of the shape the gradient fills. A vertical gradient from {0,0} to\n *   {0,1} scales to cover any rect it's applied to. This is the default.\n * - `\"global\"` — coordinates are absolute world/screen pixels. Useful when\n *   multiple shapes should share a single gradient \"ruler.\"\n */\nexport type GradientSpace = \"local\" | \"global\";\n\n/** Options for {@link linearGradient}. */\nexport interface LinearGradientOptions {\n  stops: readonly GradientStop[];\n  /**\n   * Shorthand for common orientations. Ignored if {@link start} / {@link end}\n   * are provided. Default: `\"vertical\"`.\n   */\n  axis?: \"horizontal\" | \"vertical\";\n  /** Explicit start point. Overrides `axis`. */\n  start?: { x: number; y: number };\n  /** Explicit end point. Overrides `axis`. */\n  end?: { x: number; y: number };\n  /** Coordinate space for `start`/`end`. Default: `\"local\"`. */\n  space?: GradientSpace;\n}\n\n/** Options for {@link radialGradient}. */\nexport interface RadialGradientOptions {\n  stops: readonly GradientStop[];\n  /** Center of the gradient. Default: `{ x: 0.5, y: 0.5 }` in local space. */\n  center?: { x: number; y: number };\n  /**\n   * Center of the outer (end) circle. Default: same as {@link center}.\n   * Set to a different point for offset / non-concentric radial gradients\n   * (rim lighting, directional glows).\n   */\n  outerCenter?: { x: number; y: number };\n  /** Radius of the inner (start) circle. Default: `0`. */\n  innerRadius?: number;\n  /** Radius of the outer (end) circle. Default: `0.5` in local space. */\n  outerRadius?: number;\n  /** Coordinate space for centers and radii. Default: `\"local\"`. */\n  space?: GradientSpace;\n}\n\nfunction stopToCss(stop: GradientStop): { offset: number; color: string } {\n  const r = (stop.color >> 16) & 0xff;\n  const g = (stop.color >> 8) & 0xff;\n  const b = stop.color & 0xff;\n  const a = stop.alpha ?? 1;\n  return { offset: stop.offset, color: `rgba(${r},${g},${b},${a})` };\n}\n\n/**\n * Create a linear gradient fill usable with `GraphicsComponent` draws\n * (`g.rect(...).fill(myGradient)`).\n *\n * Uses yage-style numeric colors with optional alpha per stop, and a simple\n * axis shorthand for the common vertical/horizontal cases.\n *\n * Returns a `GradientFill` (pixi `FillGradient` under the hood). Call\n * `.destroy()` when you're done with it to release the backing texture —\n * components typically do this in `onDestroy()`.\n */\nexport function linearGradient(options: LinearGradientOptions): GradientFill {\n  const axis = options.axis ?? \"vertical\";\n  const start = options.start ?? { x: 0, y: 0 };\n  const end =\n    options.end ?? (axis === \"horizontal\" ? { x: 1, y: 0 } : { x: 0, y: 1 });\n  return new FillGradient({\n    type: \"linear\",\n    start,\n    end,\n    colorStops: options.stops.map(stopToCss),\n    textureSpace: options.space ?? \"local\",\n  });\n}\n\n/**\n * Create a radial gradient fill. In `\"local\"` space (the default), centers\n * are in the 0-1 range of the filled shape's bounds.\n */\nexport function radialGradient(options: RadialGradientOptions): GradientFill {\n  const center = options.center ?? { x: 0.5, y: 0.5 };\n  return new FillGradient({\n    type: \"radial\",\n    center,\n    outerCenter: options.outerCenter ?? center,\n    innerRadius: options.innerRadius ?? 0,\n    outerRadius: options.outerRadius ?? 0.5,\n    colorStops: options.stops.map(stopToCss),\n    textureSpace: options.space ?? \"local\",\n  });\n}\n","import type { Vec2Like } from \"@yagejs/core\";\nimport { AnimatedSprite, Ticker } from \"pixi.js\";\nimport type { DisplayAnimatedSprite } from \"./public-types.js\";\nimport { resolveFrames } from \"./spritesheet.js\";\nimport type { FrameSource } from \"./spritesheet.js\";\nimport { runAttributed } from \"./internal/attribution.js\";\nimport { assertFiniteNumber } from \"./internal/validate.js\";\nimport {\n  VisualComponent,\n  type VisualComponentOptions,\n} from \"./VisualComponent.js\";\n\nlet animationTicker: Ticker | undefined;\n\n/** Options for creating an AnimatedSpriteComponent. */\nexport interface AnimatedSpriteComponentOptions extends VisualComponentOptions {\n  /** Frame source (sheet grid or atlas animation). */\n  source: FrameSource;\n  /**\n   * Default sprite anchor (0,0 = top-left, 0.5,0.5 = center, 1,1 = bottom-right).\n   * Per-{@link AnimationController} `AnimationDef.anchor` overrides this when set.\n   */\n  anchor?: Vec2Like;\n  /**\n   * Playback rate applied at construction: frames advanced per tick at 60 fps.\n   * Default `1`. `play({ speed })` and the\n   * {@link AnimatedSpriteComponent.speed} property retime the clip afterwards,\n   * and an {@link AnimationController} writes the rate at every animation\n   * switch.\n   */\n  speed?: number;\n}\n\n/** Component that displays a PixiJS AnimatedSprite. */\nexport class AnimatedSpriteComponent extends VisualComponent {\n  readonly animatedSprite: DisplayAnimatedSprite;\n\n  private readonly _frameListeners: ((frame: number) => void)[] = [];\n\n  constructor(options: AnimatedSpriteComponentOptions) {\n    super(options.layer);\n    this.animatedSprite = new AnimatedSprite(\n      resolveFrames(options.source),\n      false,\n    );\n\n    if (options.anchor) {\n      this.animatedSprite.anchor.set(options.anchor.x, options.anchor.y);\n    }\n    if (options.speed !== undefined) {\n      assertFiniteNumber(\n        \"AnimatedSpriteComponent.constructor\",\n        \"speed\",\n        options.speed,\n      );\n      this.animatedSprite.animationSpeed = options.speed;\n    }\n    this.applyVisualOptions(options);\n  }\n\n  /** The underlying Pixi display object. */\n  get renderObject(): DisplayAnimatedSprite {\n    return this.animatedSprite;\n  }\n\n  /**\n   * Resumes from the current frame; `fromStart: true` restarts at frame 0.\n   *\n   * `speed` and `loop` are sticky — the next play keeps whatever this one set.\n   * `onComplete` is not: a play owns its completion callback, so a play\n   * without one clears the callback the previous play installed.\n   *\n   * Use the {@link AnimatedSpriteComponent.speed} property to retime a clip\n   * that is already running.\n   */\n  play(options?: {\n    speed?: number;\n    loop?: boolean;\n    onComplete?: () => void;\n    fromStart?: boolean;\n  }): void {\n    if (options?.speed !== undefined) {\n      assertFiniteNumber(\n        \"AnimatedSpriteComponent.play\",\n        \"speed\",\n        options.speed,\n      );\n      this.animatedSprite.animationSpeed = options.speed;\n    }\n    if (options?.loop !== undefined) {\n      this.animatedSprite.loop = options.loop;\n    }\n    const onComplete = options?.onComplete;\n    if (onComplete) {\n      this.animatedSprite.onComplete = () =>\n        runAttributed(this, \"Animation onComplete\", onComplete);\n    } else {\n      delete this.animatedSprite.onComplete;\n    }\n    if (options?.fromStart) {\n      this.animatedSprite.gotoAndPlay(0);\n    } else {\n      this.animatedSprite.play();\n    }\n  }\n\n  /**\n   * Subscribe to frame changes on the underlying sprite. Returns an\n   * unsubscribe function, so `this.addCleanup(sprite.onFrameChange(fn))`\n   * drops the listener with the subscribing component.\n   *\n   * Pixi delivers a frame change on `play`, on a frame advance, and on the\n   * frame reset an animation switch performs, so a listener sees controller\n   * switches too. Assigning `animatedSprite.onFrameChange` directly replaces\n   * the dispatcher this installs and silences every subscriber.\n   */\n  onFrameChange(listener: (frame: number) => void): () => void {\n    if (this._frameListeners.length === 0) {\n      this.animatedSprite.onFrameChange = (frame: number) => {\n        // Copy: a listener that unsubscribes itself mid-dispatch would\n        // otherwise shift the next one past the iterator.\n        for (const l of [...this._frameListeners]) {\n          runAttributed(this, \"Animation frame listener\", () => l(frame));\n        }\n      };\n    }\n    this._frameListeners.push(listener);\n    return () => {\n      const idx = this._frameListeners.indexOf(listener);\n      if (idx !== -1) this._frameListeners.splice(idx, 1);\n    };\n  }\n\n  /** Stop the animation. */\n  stop(): void {\n    this.animatedSprite.stop();\n  }\n\n  /** Stop playback and hold `index` as a static pose. */\n  gotoFrame(index: number): void {\n    const last = this.animatedSprite.textures.length - 1;\n    if (index < 0 || index > last) {\n      throw new Error(\n        `AnimatedSpriteComponent.gotoFrame: frame ${index} is out of range (0-${last})`,\n      );\n    }\n    this.animatedSprite.gotoAndStop(index);\n  }\n\n  /** Current frame index of the underlying AnimatedSprite. */\n  get frame(): number {\n    return this.animatedSprite.currentFrame;\n  }\n\n  /** Whether the animation is currently playing. */\n  get isPlaying(): boolean {\n    return this.animatedSprite.playing;\n  }\n\n  /**\n   * Playback rate of the underlying sprite: frames advanced per tick at 60\n   * fps, so `0.15` moves on about every seventh tick and `1` on every tick.\n   * Defaults to `1`. Writing it retimes the clip that is already running,\n   * without restarting it, and reads back the same number `play({ speed })`\n   * writes.\n   *\n   * `0` holds the current frame while {@link isPlaying} stays `true`, and a\n   * negative value plays backwards. Scene and entity `timeScale` multiply\n   * this. A non-finite value throws.\n   *\n   * With an {@link AnimationController} on the entity this reads the rate the\n   * sprite is actually running at: the animation definition's `speed`, times\n   * the controller's `speed`, times the `playOneShot({ speed })` factor. The\n   * controller writes it again at its next animation switch and whenever its\n   * own `speed` is written. Set `AnimationController.speed` to retime every\n   * animation; set this to retime only the clip on screen. Writing this does\n   * not retime a running one-shot's lock: the lock keeps the duration computed\n   * when the one-shot started, so the clip and the lock can end at different\n   * times.\n   */\n  get speed(): number {\n    return this.animatedSprite.animationSpeed;\n  }\n\n  set speed(value: number) {\n    assertFiniteNumber(\"AnimatedSpriteComponent.speed\", \"speed\", value);\n    this.animatedSprite.animationSpeed = value;\n  }\n\n  /** Advance playback using engine-scaled time. */\n  update(dt: number): void {\n    if (dt === 0) return;\n    const ticker = (animationTicker ??= new Ticker());\n    ticker.deltaTime = dt * 1000 * Ticker.targetFPMS;\n    this.animatedSprite.update(ticker);\n  }\n}\n","import { Component } from \"@yagejs/core\";\nimport { AnimatedSpriteComponent } from \"./AnimatedSpriteComponent.js\";\nimport type { Texture } from \"pixi.js\";\nimport { resolveFrames } from \"./spritesheet.js\";\nimport type { FrameSource } from \"./spritesheet.js\";\nimport { routeAnimationSpeedChange } from \"./internal/animationSpeedGroup.js\";\nimport { runAttributed } from \"./internal/attribution.js\";\n\n/** Definition for a single named animation. */\nexport interface AnimationDef {\n  /** Frame source (sheet grid or atlas animation). */\n  source: FrameSource;\n  /** PixiJS animationSpeed value (e.g. 0.15). */\n  speed: number;\n  /** Whether the animation loops. Default: true. */\n  loop?: boolean;\n  /** Per-animation anchor override. */\n  anchor?: { x: number; y: number };\n}\n\n/** Options for a one-shot play. */\nexport interface AnimationOneShotOptions {\n  /** Frame to start from (integer, 0 to the last frame). Default: 0. */\n  startFrame?: number;\n  /**\n   * Playback multiplier for this one-shot only, on top of the controller's\n   * `speed`. Finite and greater than 0. Default: 1.\n   */\n  speed?: number;\n  /** Explicit lock duration in seconds, replacing the automatic calculation. */\n  duration?: number;\n  /** Called when the one-shot plays out. */\n  onComplete?: () => void;\n  /** Called when anything else ends the one-shot first. */\n  onCancel?: () => void;\n}\n\n/** Options that change how long a one-shot takes to play. */\nexport interface AnimationTimingOptions {\n  /** Frame the play starts from. Default: 0. */\n  startFrame?: number;\n  /** Per-play speed multiplier. Default: 1. */\n  speed?: number;\n}\n\n// Internal: AnimationDef with frames resolved from its source.\ninterface ResolvedAnimDef {\n  frames: Texture[];\n  speed: number;\n  loop?: boolean;\n  anchor?: { x: number; y: number };\n}\n\n/**\n * High-level animation controller that manages named animations on top of\n * a sibling {@link AnimatedSpriteComponent}.\n *\n * Provides one-shot locking, per-animation anchors, and type-safe animation\n * names via the generic parameter.\n *\n * **Narrowing the animation-name type** — `entity.get(AnimationController)`\n * returns `AnimationController<string>` (the default `T`); the runtime class\n * isn't generic, and a string-typed instance can't substitute for a narrower\n * one (the `current: T | \"\"` getter is covariant on `T`). Cast at the field\n * declaration so every consumer downstream sees the narrow type:\n *\n * ```ts\n * type Anim = \"idle\" | \"walk\" | \"shoot\";\n *\n * class HeroController extends Component {\n *   private readonly _anim = this.sibling(AnimationController) as\n *     AnimationController<Anim>;\n * }\n * ```\n *\n * For multi-sprite (head + body + outfit) characters, see\n * {@link LayeredAnimationController} — it fans `play()`/`playOneShot()` across\n * a list of sibling controllers with a single shared lock timer.\n */\nexport class AnimationController<T extends string = string> extends Component {\n  private readonly _anims: Record<T, ResolvedAnimDef>;\n  private readonly _sprite = this.sibling(AnimatedSpriteComponent);\n\n  private _current: T | \"\" = \"\";\n  private _locked = false;\n  private _lockTimer = 0;\n  private _lockDuration = 0;\n  private _lockUsesAnimationDuration = false;\n  private _lockStartFrame = 0;\n  private _shotSpeed = 1;\n  private _onComplete: (() => void) | undefined;\n  private _onCancel: (() => void) | undefined;\n  private _speed = 1;\n\n  constructor(animations: Record<T, AnimationDef>) {\n    super();\n\n    const resolved = {} as Record<T, ResolvedAnimDef>;\n    for (const name of Object.keys(animations) as T[]) {\n      const def = animations[name];\n      resolved[name] = {\n        frames: resolveFrames(def.source),\n        speed: def.speed,\n        ...(def.loop != null && { loop: def.loop }),\n        ...(def.anchor && { anchor: def.anchor }),\n      };\n    }\n\n    this._anims = resolved;\n  }\n\n  /** Currently playing animation name, or \"\" if none. */\n  get current(): T | \"\" {\n    return this._current;\n  }\n\n  /** True if a one-shot animation is blocking. */\n  get locked(): boolean {\n    return this._locked;\n  }\n\n  /** Current frame index of the underlying AnimatedSprite. */\n  get frame(): number {\n    return this._sprite.animatedSprite.currentFrame;\n  }\n\n  /**\n   * Runtime speed multiplier (default 1). A controller owned by a\n   * {@link LayeredAnimationController} shares this value with every layer.\n   */\n  get speed(): number {\n    return this._speed;\n  }\n\n  set speed(value: number) {\n    if (routeAnimationSpeedChange(this, value)) return;\n    if (!Number.isFinite(value)) {\n      throw new Error(\n        `AnimationController.speed must be finite, got ${value}.`,\n      );\n    }\n    const nextLockDuration =\n      this._locked && this._lockUsesAnimationDuration && this._current\n        ? this.calcDurationAtSpeed(\n            this._current,\n            value,\n            this._shotSpeed,\n            this._lockStartFrame,\n          )\n        : null;\n    const lockProgress =\n      this._locked && this._lockUsesAnimationDuration && this._lockDuration > 0\n        ? Math.min(this._lockTimer / this._lockDuration, 1)\n        : 0;\n    this._speed = value;\n    if (!this._current) return;\n    this._sprite.animatedSprite.animationSpeed =\n      this._anims[this._current].speed * value * this._shotSpeed;\n    if (nextLockDuration !== null) {\n      this._lockDuration = nextLockDuration;\n      this._lockTimer = this._lockDuration * lockProgress;\n    }\n  }\n\n  /** Whether this controller defines the given animation name. */\n  has(name: string): name is T {\n    return Object.hasOwn(this._anims, name);\n  }\n\n  /** Play a named animation. No-op if already current or locked. */\n  play(name: T): void {\n    const def = this._def(name, \"play\");\n    if (this._current === name || this._locked) return;\n    this._apply(name, def);\n  }\n\n  /** Play an animation as a one-shot, locking out other plays until complete.\n   *  No-op if already locked on the same animation (prevents restart flicker).\n   *\n   *  Exactly one of `onComplete` and `onCancel` runs per one-shot:\n   *  `onComplete` when the lock timer plays out, `onCancel` when another\n   *  one-shot, `forcePlay`, `unlock` or component destruction ends it first.\n   *  A cancel callback runs after the new state is in place, so calling\n   *  `playOneShot` from inside it takes effect.\n   *\n   *  When `options.duration` is omitted, the lock duration is auto-calculated\n   *  from the frames that will actually play — the frame count from\n   *  `startFrame` on, at the controller speed times `options.speed`. Pass an\n   *  explicit `duration` to synchronise lock release across multiple\n   *  controllers (see {@link LayeredAnimationController}). */\n  playOneShot(name: T, options?: AnimationOneShotOptions): void {\n    const def = this._def(name, \"playOneShot\");\n    if (this._locked && this._current === name) return;\n    const startFrame = options?.startFrame ?? 0;\n    const shotSpeed = options?.speed ?? 1;\n    this._validateTiming(def, startFrame, shotSpeed, \"playOneShot\");\n    const duration =\n      options?.duration ??\n      this.calcDurationAtSpeed(name, this._speed, shotSpeed, startFrame);\n\n    const cancelled = this._onCancel;\n    this._apply(name, def, { startFrame, speed: shotSpeed });\n    this._sprite.animatedSprite.loop = false;\n    this._locked = true;\n    this._lockTimer = 0;\n    this._lockDuration = duration;\n    this._lockUsesAnimationDuration = options?.duration === undefined;\n    this._lockStartFrame = startFrame;\n    this._onComplete = options?.onComplete;\n    this._onCancel = options?.onCancel;\n    // Notify last: the new lock is fully installed, so a re-entrant\n    // playOneShot from inside the cancelled callback wins.\n    if (cancelled) runAttributed(this, \"Animation onCancel\", cancelled);\n  }\n\n  /** Clear lock and force-switch to the given animation. */\n  forcePlay(name: T): void {\n    const def = this._def(name, \"forcePlay\");\n    const cancelled = this._onCancel;\n    this._clearLock();\n    this._apply(name, def);\n    if (cancelled) runAttributed(this, \"Animation onCancel\", cancelled);\n  }\n\n  /** Manually release the one-shot lock, firing a pending `onCancel`. */\n  unlock(): void {\n    const cancelled = this._onCancel;\n    this._clearLock();\n    if (cancelled) runAttributed(this, \"Animation onCancel\", cancelled);\n  }\n\n  /**\n   * Calculate the engine-scaled duration (seconds) a one-shot of this\n   * animation would take, matching what `playOneShot` locks for.\n   *\n   * Frame-rate independent: PixiJS normalises `deltaTime` via\n   * `Ticker.targetFPMS` (0.06), so the formula holds at any actual fps. The\n   * controller timer and animated sprite both receive engine-scaled time.\n   * Throws unless the effective speed is positive and produces a finite\n   * duration. Use an explicit one-shot duration for paused or reverse playback.\n   */\n  calcDuration(name: T, options?: AnimationTimingOptions): number {\n    const def = this._def(name, \"calcDuration\");\n    const startFrame = options?.startFrame ?? 0;\n    const shotSpeed = options?.speed ?? 1;\n    this._validateTiming(def, startFrame, shotSpeed, \"calcDuration\");\n    return this.calcDurationAtSpeed(name, this._speed, shotSpeed, startFrame);\n  }\n\n  /**\n   * Throw if this controller would reject the timing, without deriving a\n   * duration from it. `LayeredAnimationController` checks every layer before\n   * any layer switches; when the caller passes an explicit shared duration,\n   * no layer's own duration feeds the timer, so only the frame and speed\n   * gates apply.\n   * @internal\n   */\n  _assertTiming(name: T, options: AnimationTimingOptions | undefined): void {\n    const def = this._def(name, \"playOneShot\");\n    this._validateTiming(\n      def,\n      options?.startFrame ?? 0,\n      options?.speed ?? 1,\n      \"playOneShot\",\n    );\n  }\n\n  private calcDurationAtSpeed(\n    name: T,\n    controllerSpeed: number,\n    shotSpeed: number,\n    startFrame: number,\n  ): number {\n    const def = this._anims[name];\n    const effectiveSpeed = def.speed * controllerSpeed * shotSpeed;\n    const duration =\n      ((def.frames.length - startFrame) * (1 / 60)) / effectiveSpeed;\n    if (\n      !Number.isFinite(effectiveSpeed) ||\n      effectiveSpeed <= 0 ||\n      !Number.isFinite(duration) ||\n      duration <= 0\n    ) {\n      throw new Error(\n        \"An automatically timed one-shot requires a positive effective speed that produces a finite duration. \" +\n          \"Pass an explicit duration to playOneShot() to pause or reverse it.\",\n      );\n    }\n    return duration;\n  }\n\n  /** Check whether the current frame is within [start, end] inclusive. */\n  inFrameRange(start: number, end: number): boolean {\n    const f = this.frame;\n    return f >= start && f <= end;\n  }\n\n  /** Auto-play the first defined animation. */\n  onAdd(): void {\n    const names = Object.keys(this._anims) as T[];\n    const first = names[0];\n    if (first !== undefined) {\n      this._apply(first, this._anims[first]);\n    }\n  }\n\n  /** A live one-shot ends with the component, so its `onCancel` still runs. */\n  onDestroy(): void {\n    this.unlock();\n  }\n\n  /** Tick the one-shot lock timer. */\n  update(dt: number): void {\n    if (!this._locked) return;\n    this._lockTimer += dt;\n    if (this._lockTimer >= this._lockDuration) {\n      const cb = this._onComplete;\n      this._clearLock();\n      if (cb) runAttributed(this, \"Animation onComplete\", cb);\n    }\n  }\n\n  /** Drop the lock and both of its callbacks without notifying either. */\n  private _clearLock(): void {\n    this._locked = false;\n    this._lockTimer = 0;\n    this._lockDuration = 0;\n    this._lockUsesAnimationDuration = false;\n    this._lockStartFrame = 0;\n    this._onComplete = undefined;\n    this._onCancel = undefined;\n  }\n\n  /** Resolve a caller-supplied name, naming the entry it was passed to. */\n  private _def(name: T, method: string): ResolvedAnimDef {\n    if (!Object.hasOwn(this._anims, name)) {\n      const defined = Object.keys(this._anims);\n      throw new Error(\n        `AnimationController.${method}: unknown animation \"${name}\", ` +\n          `expected one of ${defined.length > 0 ? defined.join(\", \") : \"(none defined)\"}.`,\n      );\n    }\n    return this._anims[name];\n  }\n\n  private _validateTiming(\n    def: ResolvedAnimDef,\n    startFrame: number,\n    speed: number,\n    method: string,\n  ): void {\n    const last = def.frames.length - 1;\n    if (!Number.isInteger(startFrame)) {\n      throw new Error(\n        `AnimationController.${method}: startFrame must be an integer, got ${startFrame}.`,\n      );\n    }\n    if (startFrame < 0 || startFrame > last) {\n      throw new Error(\n        `AnimationController.${method}: startFrame ${startFrame} is out of range (0-${last}).`,\n      );\n    }\n    if (!Number.isFinite(speed) || speed <= 0) {\n      throw new Error(\n        `AnimationController.${method}: speed must be a finite number greater than 0, got ${speed}.`,\n      );\n    }\n  }\n\n  private _apply(\n    name: T,\n    def: ResolvedAnimDef,\n    options?: { startFrame: number; speed: number },\n  ): void {\n    this._current = name;\n    this._shotSpeed = options?.speed ?? 1;\n    const sprite = this._sprite.animatedSprite;\n    sprite.textures = def.frames;\n    if (def.anchor) {\n      sprite.anchor.set(def.anchor.x, def.anchor.y);\n    }\n    sprite.animationSpeed = def.speed * this._speed * this._shotSpeed;\n    sprite.loop = def.loop ?? true;\n    // A completion callback belongs to the play that installed it, so a\n    // switch must not carry it into an animation its author never saw.\n    delete sprite.onComplete;\n    sprite.gotoAndPlay(options?.startFrame ?? 0);\n  }\n}\n","type AnimationSpeedOwner = (value: number) => void;\n\nconst speedOwners = new WeakMap<object, AnimationSpeedOwner>();\nconst bypassedControllers = new WeakSet<object>();\n\nexport function registerAnimationSpeedOwner(\n  controllers: readonly object[],\n  owner: AnimationSpeedOwner,\n): () => void {\n  for (const controller of controllers) {\n    if (speedOwners.has(controller)) {\n      throw new Error(\n        \"An AnimationController cannot belong to more than one LayeredAnimationController.\",\n      );\n    }\n  }\n  for (const controller of controllers) speedOwners.set(controller, owner);\n  return () => {\n    for (const controller of controllers) {\n      if (speedOwners.get(controller) === owner) {\n        speedOwners.delete(controller);\n      }\n    }\n  };\n}\n\nexport function routeAnimationSpeedChange(\n  controller: object,\n  value: number,\n): boolean {\n  if (bypassedControllers.has(controller)) return false;\n  const owner = speedOwners.get(controller);\n  if (!owner) return false;\n  owner(value);\n  return true;\n}\n\nexport function withoutAnimationSpeedOwner<T>(\n  controller: object,\n  fn: () => T,\n): T {\n  bypassedControllers.add(controller);\n  try {\n    return fn();\n  } finally {\n    bypassedControllers.delete(controller);\n  }\n}\n","import { Component } from \"@yagejs/core\";\nimport { AnimationController } from \"./AnimationController.js\";\nimport type { AnimationOneShotOptions } from \"./AnimationController.js\";\nimport {\n  registerAnimationSpeedOwner,\n  withoutAnimationSpeedOwner,\n} from \"./internal/animationSpeedGroup.js\";\nimport { runAttributed } from \"./internal/attribution.js\";\n\n/** Options for {@link LayeredAnimationController}. */\nexport interface LayeredAnimationControllerOptions<T extends string> {\n  /**\n   * Sibling controllers to drive in lockstep. Typically one per visual layer\n   * (head, body, outfit) of a layered character, each living on its own child\n   * entity with its own {@link AnimatedSpriteComponent}.\n   */\n  controllers: AnimationController<T>[];\n}\n\n/**\n * Fan-out wrapper around N sibling {@link AnimationController} instances.\n *\n * Use this when a single logical character is composed of multiple sprite\n * layers (head + body + outfit) — each layer has its own\n * `AnimatedSpriteComponent` + `AnimationController`, but they all need to\n * `play(\"walk\")` or `playOneShot(\"attack\")` in unison.\n *\n * - `play(name)` is forwarded to every child controller.\n * - `speed` writes the same runtime multiplier to every child.\n * - `playOneShot(name, opts)` uses the first child as the shared timer and\n *   keeps every other child locked until that timer completes.\n * - The wrapper fires exactly one of the user's `onComplete` / `onCancel`.\n * - Every layer must define every name played through the wrapper; a missing\n *   name throws before any layer switches, and so does a `startFrame` or\n *   `speed` that any layer rejects when the timing is automatic.\n *\n * ```ts\n * class Hero extends Entity {\n *   setup() {\n *     this.add(new Transform());\n *     const body = this.spawnChild(\"body\", HeroLayer, { sheet: \"body.png\" });\n *     const head = this.spawnChild(\"head\", HeroLayer, { sheet: \"head.png\" });\n *     this.add(new LayeredAnimationController({\n *       controllers: [body.get(AnimationController), head.get(AnimationController)],\n *     }));\n *   }\n * }\n * ```\n */\nexport class LayeredAnimationController<\n  T extends string = string,\n> extends Component {\n  private readonly _controllers: AnimationController<T>[];\n  private readonly _leader: AnimationController<T>;\n  private _current: T | \"\" = \"\";\n  private _locked = false;\n  private _onComplete: (() => void) | undefined;\n  private _onCancel: (() => void) | undefined;\n\n  constructor(options: LayeredAnimationControllerOptions<T>) {\n    super();\n    const [leader] = options.controllers;\n    if (!leader) {\n      throw new Error(\n        \"LayeredAnimationController requires at least one controller.\",\n      );\n    }\n    this._controllers = [...options.controllers];\n    this._leader = leader;\n  }\n\n  /** Sibling controllers being driven. */\n  get controllers(): readonly AnimationController<T>[] {\n    return this._controllers;\n  }\n\n  /** Currently playing animation name, or \"\" if none. */\n  get current(): T | \"\" {\n    return this._current;\n  }\n\n  /** True if a one-shot animation is blocking. */\n  get locked(): boolean {\n    return this._locked;\n  }\n\n  /**\n   * Shared runtime speed multiplier, read from the first controller and\n   * applied to every controller. Writes to any participating controller's\n   * `speed` property route through this group while the wrapper is attached.\n   */\n  get speed(): number {\n    return this._leader.speed;\n  }\n\n  set speed(value: number) {\n    for (const controller of this._controllers) {\n      withoutAnimationSpeedOwner(controller, () => {\n        controller.speed = value;\n      });\n    }\n  }\n\n  onAdd(): void {\n    this.addCleanup(\n      registerAnimationSpeedOwner(this._controllers, (value) => {\n        this.speed = value;\n      }),\n    );\n  }\n\n  /** Play a named animation on every layer. No-op if already current or locked. */\n  play(name: T): void {\n    this._assertEveryLayerHas(name, \"play\");\n    if (this._current === name || this._locked) return;\n    this._current = name;\n    for (const c of this._controllers) c.play(name);\n  }\n\n  /** Play a one-shot on every layer with a shared lock duration.\n   *\n   * The first controller owns the shared timer. Its normal automatic timing\n   * keeps the lock aligned when its speed changes. Other controllers receive\n   * an infinite lock duration and are released with the wrapper. Pass an\n   * explicit duration to keep the shared timer independent of playback speed.\n   *\n   * The shared `startFrame` and `speed` are checked against every layer\n   * first, so a value one layer rejects throws with every layer still on its\n   * previous animation.\n   *\n   * The wrapper owns the interruption signal: exactly one of `onComplete` and\n   * `onCancel` runs per one-shot, and layers never receive a cancel of their\n   * own. */\n  playOneShot(name: T, options?: AnimationOneShotOptions): void {\n    this._assertEveryLayerHas(name, \"playOneShot\");\n    if (this._locked && this._current === name) return;\n    const leader = this._leader;\n    const timing = {\n      ...(options?.startFrame !== undefined && {\n        startFrame: options.startFrame,\n      }),\n      ...(options?.speed !== undefined && { speed: options.speed }),\n    };\n    // Layers can define the same name with different frame counts, so a\n    // startFrame legal for one is out of range for another. Validate the\n    // shared timing against every layer before anything mutates. An explicit\n    // duration drives the shared timer on its own, so those layers are only\n    // checked for the frame and speed they will play at.\n    for (const controller of this._controllers) {\n      if (options?.duration === undefined)\n        controller.calcDuration(name, timing);\n      else controller._assertTiming(name, timing);\n    }\n\n    const cancelled = this._onCancel;\n    this._clearLock();\n\n    leader.playOneShot(name, {\n      ...timing,\n      ...(options?.duration !== undefined && { duration: options.duration }),\n      onComplete: () => this.completeOneShot(),\n    });\n    for (const controller of this._controllers.slice(1)) {\n      controller.playOneShot(name, {\n        ...timing,\n        duration: Number.POSITIVE_INFINITY,\n      });\n    }\n\n    // Commit the wrapper's own lock only once every layer has accepted the\n    // play, so a layer that rejects the timing cannot leave the wrapper\n    // locked on an animation no leader timer will ever complete.\n    this._current = name;\n    this._locked = true;\n    this._onComplete = options?.onComplete;\n    this._onCancel = options?.onCancel;\n    // Notify last, so a re-entrant playOneShot from inside the cancelled\n    // callback replaces what was just installed instead of being clobbered.\n    if (cancelled) runAttributed(this, \"Animation onCancel\", cancelled);\n  }\n\n  /** Clear the lock and force-switch every layer to the given animation. */\n  forcePlay(name: T): void {\n    this._assertEveryLayerHas(name, \"forcePlay\");\n    const cancelled = this._onCancel;\n    this._clearLock();\n    this._current = name;\n    for (const c of this._controllers) c.forcePlay(name);\n    if (cancelled) runAttributed(this, \"Animation onCancel\", cancelled);\n  }\n\n  /** Manually release the one-shot lock on this wrapper and every child. */\n  unlock(): void {\n    const cancelled = this._onCancel;\n    this._clearLock();\n    if (cancelled) runAttributed(this, \"Animation onCancel\", cancelled);\n  }\n\n  /** A live one-shot ends with the component, so its `onCancel` still runs. */\n  onDestroy(): void {\n    this.unlock();\n  }\n\n  private completeOneShot(): void {\n    if (!this._locked) return;\n    const cb = this._onComplete;\n    this._clearLock();\n    if (cb) runAttributed(this, \"Animation onComplete\", cb);\n  }\n\n  /** Release the lock on this wrapper and every layer, notifying nobody. */\n  private _clearLock(): void {\n    this._locked = false;\n    this._onComplete = undefined;\n    this._onCancel = undefined;\n    for (const c of this._controllers) c.unlock();\n  }\n\n  private _assertEveryLayerHas(name: T, method: string): void {\n    for (let i = 0; i < this._controllers.length; i++) {\n      if (!this._controllers[i]!.has(name)) {\n        throw new Error(\n          `LayeredAnimationController.${method}: layer ${i} has no animation ` +\n            `\"${name}\"; every layer must define it.`,\n        );\n      }\n    }\n  }\n}\n","import { Entity, Vec2 } from \"@yagejs/core\";\nimport type { Vec2Like, Vec2Buffer, EasingFunction } from \"@yagejs/core\";\nimport { CameraComponent } from \"./CameraComponent.js\";\nimport type {\n  CameraBounds,\n  CameraBinding,\n  CameraComponentOptions,\n  CameraFollowOptions,\n  CameraShakeOptions,\n} from \"./CameraComponent.js\";\nimport { CameraFollow } from \"./CameraFollow.js\";\nimport type { FollowTarget } from \"./FollowTarget.js\";\nimport {\n  assertFiniteNumber,\n  assertPositiveNumber,\n} from \"./internal/validate.js\";\nimport { CameraShake } from \"./CameraShake.js\";\nimport { CameraBoundsComponent } from \"./CameraBoundsComponent.js\";\nimport { CameraZoom } from \"./CameraZoom.js\";\nimport { RendererKey } from \"./types.js\";\nimport type { CameraModifierHost } from \"./CameraModifiers.js\";\n\nexport type { CameraBinding } from \"./CameraComponent.js\";\n\n/** Axis-aligned rectangle in world space, used by `CameraEntityParams.fitTo`. */\nexport interface CameraFitToRect {\n  x: number;\n  y: number;\n  width: number;\n  height: number;\n}\n\nexport interface CameraEntityParams {\n  /** Initial position. */\n  position?: Vec2;\n  /** Follow target — an `Entity`, a `Transform`, a world point, or a function returning one. */\n  follow?: FollowTarget;\n  /** Follow smoothing factor 0..1. Default: 1 (instant). */\n  smoothing?: number;\n  /** Follow offset. */\n  offset?: Vec2Like;\n  /** Follow deadzone. */\n  deadzone?: { halfWidth: number; halfHeight: number };\n  /**\n   * Start on the follow target instead of easing in from `position`. Without\n   * it a smoothed camera glides in from wherever it spawned — the world\n   * origin, unless `position` or `fitTo` places it elsewhere. Ignored when no\n   * `follow` target is given.\n   */\n  snap?: boolean;\n  /** Camera bounds for position clamping. */\n  bounds?: CameraBounds;\n  /** Initial zoom level. Default: 1. */\n  zoom?: number;\n  /**\n   * Per-layer bindings applied on top of the auto-bound world layers. An\n   * entry replaces the binding for the layer it names; an entry naming a\n   * screen-space layer adds it.\n   */\n  bindings?: CameraBinding[];\n  /**\n   * Bind every world-space layer at full strength before applying\n   * `bindings`. Default: `true`. `false` binds exactly what `bindings`\n   * names, and nothing else.\n   */\n  autoBind?: boolean;\n  /** Camera priority (lower = processed first). Default: 0. */\n  priority?: number;\n  /** Camera name (for multi-camera lookup). */\n  name?: string;\n  /**\n   * Frame an axis-aligned world rectangle: position the camera on the\n   * rect's centre and zoom so the entire rect fits inside the viewport\n   * (`contain` semantics — `zoom = min(viewportW / rect.w, viewportH /\n   * rect.h)`). Wins over `position` and `zoom` when supplied. Applied\n   * once at setup against the current renderer viewport — for fixed\n   * cameras where the framed area is known up front (puzzle boards,\n   * arcade levels, dialog-scene insets). For runtime re-framing, set\n   * `position` + `zoom` directly on the camera.\n   */\n  fitTo?: CameraFitToRect;\n}\n\n/**\n * Camera entity. Spawn in a scene to enable camera-based layer transforms.\n *\n * ```ts\n * const cam = this.spawn(CameraEntity, {\n *   follow: player.get(Transform),\n *   smoothing: 0.15,\n *   bounds: { minX: 0, minY: 0, maxX: 2000, maxY: 2000 },\n * });\n *\n * // All camera operations are available directly on the entity:\n * cam.shake(8, 0.3);\n * cam.zoomTo(1.5, 1);\n * cam.follow(otherTarget, { smoothing: 0.1 });\n * ```\n */\nexport class CameraEntity extends Entity {\n  private cam!: CameraComponent;\n\n  setup(params: CameraEntityParams = {}): void {\n    const camOpts: CameraComponentOptions = {};\n    if (params.position !== undefined) camOpts.position = params.position;\n    if (params.zoom !== undefined) camOpts.zoom = params.zoom;\n    // `fitTo` computes position + zoom together from the supplied rect\n    // and the current viewport — wins over both. Resolve the renderer\n    // off the scene context so the viewport read happens at setup\n    // (snapshotting the framed area against the *current* viewport;\n    // fitTo is a one-shot, not a responsive binding).\n    if (params.fitTo !== undefined) {\n      assertPositiveNumber(\n        \"CameraEntity.setup\",\n        \"fitTo.width\",\n        params.fitTo.width,\n      );\n      assertPositiveNumber(\n        \"CameraEntity.setup\",\n        \"fitTo.height\",\n        params.fitTo.height,\n      );\n      assertFiniteNumber(\"CameraEntity.setup\", \"fitTo.x\", params.fitTo.x);\n      assertFiniteNumber(\"CameraEntity.setup\", \"fitTo.y\", params.fitTo.y);\n      const viewport = this.scene.context.resolve(RendererKey).virtualSize;\n      camOpts.position = new Vec2(\n        params.fitTo.x + params.fitTo.width / 2,\n        params.fitTo.y + params.fitTo.height / 2,\n      );\n      camOpts.zoom = Math.min(\n        viewport.width / params.fitTo.width,\n        viewport.height / params.fitTo.height,\n      );\n    }\n    if (params.bindings !== undefined) camOpts.bindings = params.bindings;\n    if (params.autoBind !== undefined) camOpts.autoBind = params.autoBind;\n    if (params.priority !== undefined) camOpts.priority = params.priority;\n    if (params.name !== undefined) camOpts.name = params.name;\n    this.cam = this.add(new CameraComponent(camOpts));\n\n    const followComp = this.add(new CameraFollow());\n    this.add(new CameraBoundsComponent());\n    this.add(new CameraShake());\n    this.add(new CameraZoom());\n\n    if (params.follow) {\n      const followOpts: CameraFollowOptions = {};\n      if (params.smoothing !== undefined)\n        followOpts.smoothing = params.smoothing;\n      if (params.offset !== undefined) followOpts.offset = params.offset;\n      if (params.deadzone !== undefined) followOpts.deadzone = params.deadzone;\n      if (params.snap !== undefined) followOpts.snap = params.snap;\n      followComp.start(params.follow, followOpts);\n    }\n\n    if (params.bounds) {\n      this.cam.bounds = params.bounds;\n    }\n  }\n\n  // ---------------------------------------------------------------------------\n  // Property delegates\n  // ---------------------------------------------------------------------------\n\n  get position(): Vec2 {\n    return this.cam.position;\n  }\n\n  set position(value: Vec2) {\n    this.cam.position = value;\n  }\n\n  get zoom(): number {\n    return this.cam.zoom;\n  }\n\n  set zoom(value: number) {\n    this.cam.zoom = value;\n  }\n\n  get rotation(): number {\n    return this.cam.rotation;\n  }\n\n  set rotation(value: number) {\n    this.cam.rotation = value;\n  }\n\n  get bounds(): CameraBounds | undefined {\n    return this.cam.bounds;\n  }\n\n  set bounds(value: CameraBounds | undefined) {\n    this.cam.bounds = value;\n  }\n\n  get effectivePosition(): Vec2 {\n    return this.cam.effectivePosition;\n  }\n\n  get effectiveRotation(): number {\n    return this.cam.effectiveRotation;\n  }\n\n  get effectiveZoom(): number {\n    return this.cam.effectiveZoom;\n  }\n\n  get modifiers(): CameraModifierHost {\n    return this.cam.modifiers;\n  }\n\n  // ---------------------------------------------------------------------------\n  // Method delegates\n  // ---------------------------------------------------------------------------\n\n  follow(target: FollowTarget, options?: CameraFollowOptions): void {\n    this.cam.follow(target, options);\n  }\n\n  unfollow(): void {\n    this.cam.unfollow();\n  }\n\n  snapToTarget(): void {\n    this.cam.snapToTarget();\n  }\n\n  shake(\n    intensity: number,\n    duration: number,\n    options?: CameraShakeOptions,\n  ): void {\n    this.cam.shake(intensity, duration, options);\n  }\n\n  zoomTo(target: number, duration: number, easing?: EasingFunction): void {\n    this.cam.zoomTo(target, duration, easing);\n  }\n\n  screenToWorld(screenX: number, screenY: number): Vec2 {\n    return this.cam.screenToWorld(screenX, screenY);\n  }\n\n  getEffectivePositionInto(out: Vec2Buffer): Vec2Buffer {\n    return this.cam.getEffectivePositionInto(out);\n  }\n\n  screenToWorldInto(\n    out: Vec2Buffer,\n    screenX: number,\n    screenY: number,\n  ): Vec2Buffer {\n    return this.cam.screenToWorldInto(out, screenX, screenY);\n  }\n\n  worldToScreenInto(\n    out: Vec2Buffer,\n    worldX: number,\n    worldY: number,\n  ): Vec2Buffer {\n    return this.cam.worldToScreenInto(out, worldX, worldY);\n  }\n\n  worldToScreen(worldX: number, worldY: number): Vec2 {\n    return this.cam.worldToScreen(worldX, worldY);\n  }\n}\n","import { Component, Entity, Transform, Vec2, Vec2Buffer } from \"@yagejs/core\";\nimport type { Vec2Like } from \"@yagejs/core\";\nimport type { CameraEntity } from \"./CameraEntity.js\";\nimport { resolveFollowTarget } from \"./FollowTarget.js\";\nimport type { FollowTarget } from \"./FollowTarget.js\";\n\n/** What the follow tracks each frame. See {@link FollowTarget}. */\nexport type ScreenFollowTarget = FollowTarget;\n\n/** Options for `ScreenFollow`. */\nexport interface ScreenFollowOptions {\n  /** What world coord to track. */\n  target: ScreenFollowTarget;\n\n  /**\n   * Camera whose `worldToScreen` projection defines the screen mapping.\n   * Required — YAGE doesn't have a global \"main\" camera, so the projection\n   * source must be explicit.\n   */\n  camera: CameraEntity;\n\n  /**\n   * Screen-pixel offset added to the projected position. Default `(0, 0)`.\n   *\n   * Applied *after* projection (`cam.worldToScreen(target) + offset`), not\n   * before — so the visual gap between UI and target stays fixed under any\n   * camera zoom or rotation. Adding it in world coords before projection\n   * would let the camera transform warp the offset.\n   */\n  offset?: Vec2Like;\n\n  /**\n   * When the target is an `Entity` or a `Transform`, copy its\n   * `worldRotation` onto this\n   * entity's Transform each frame. Useful when the UI should rotate with\n   * the target itself (e.g. a vehicle UI that tilts with the vehicle) but\n   * stay stable against the camera. Default `false` — this entity's\n   * rotation is left alone, so a panel on a screen-space layer renders\n   * axis-aligned. Ignored when `target` is a Vec2 or a function.\n   */\n  trackRotation?: boolean;\n}\n\n/**\n * Each frame, projects a world source through a camera and writes the\n * resulting screen coord to this entity's `Transform.worldPosition`.\n *\n * The canonical \"billboard\" primitive: pair with a `UISurface` (or `UIRoot`)\n * on a screen-space layer using `positioning: \"transform\"` to produce UI\n * that tracks a target entity but stays axis-aligned and constant-size\n * regardless of camera zoom or rotation — nameplates, health bars,\n * damage numbers, interaction prompts.\n *\n * ```ts\n * class Nameplate extends Entity {\n *   constructor(private readonly target: Entity, private readonly camera: CameraEntity) {\n *     super();\n *   }\n *   setup() {\n *     this.add(new Transform());\n *     this.add(new ScreenFollow({\n *       target: this.target,\n *       camera: this.camera,\n *       offset: new Vec2(0, -40),      // 40 screen px above the target\n *     }));\n *     const panel = this.add(new UISurface({\n *       positioning: \"transform\",      // reads Transform.worldPosition\n *       anchor: Anchor.BottomCenter,   // pivot on the panel\n *     }));\n *     panel.text(\"Grunt-42\", { fontSize: 11 });\n *   }\n * }\n * ```\n */\nexport class ScreenFollow extends Component {\n  private readonly positionScratch = new Vec2Buffer();\n  private _target: ScreenFollowTarget | null;\n  private _camera: CameraEntity | null;\n  private _offset: Vec2;\n  private _trackRotation: boolean;\n\n  constructor(opts?: ScreenFollowOptions) {\n    super();\n    this._target = opts?.target ?? null;\n    this._camera = opts?.camera ?? null;\n    this._offset = opts?.offset\n      ? new Vec2(opts.offset.x, opts.offset.y)\n      : Vec2.ZERO;\n    this._trackRotation = opts?.trackRotation ?? false;\n  }\n\n  override update(): void {\n    if (!this._camera || this._target === null) return;\n    const world = this.resolveTargetPosition();\n    if (!world) return;\n\n    // Project the target alone, then add the offset in screen coords.\n    // Adding it in world coords would let camera zoom/rotation warp the\n    // offset — a 40px offset would become 80px at zoom 2 and would rotate\n    // off-axis as the camera rotates. Screen-space addition keeps the\n    // visual gap between UI and target fixed under any camera transform.\n    const projected = this._camera.worldToScreenInto(\n      this.positionScratch,\n      world.x,\n      world.y,\n    );\n    const t = this.entity.get(Transform);\n    t.setWorldPosition(\n      projected.x + this._offset.x,\n      projected.y + this._offset.y,\n    );\n\n    if (this._trackRotation) {\n      const source =\n        this._target instanceof Entity\n          ? this._target.tryGet(Transform)\n          : this._target instanceof Transform\n            ? this._target\n            : undefined;\n      if (source) t.worldRotation = source.worldRotation;\n    }\n  }\n\n  private resolveTargetPosition(): Vec2Like | undefined {\n    const target = this._target;\n    if (target === null) return undefined;\n    return resolveFollowTarget(target, this, this.positionScratch);\n  }\n}\n","import type { DisplayContainer as Container } from \"./public-types.js\";\nimport type { LayerSortFn } from \"./LayerDef.js\";\n\n/**\n * Built-in y-depth key: a container's `position.y` becomes its paint\n * order. Lower y renders first (behind); higher y renders on top —\n * matches the classic top-down 2D depth rule, where a character \"in\n * front of\" a tree (higher `position.y`) draws over it.\n *\n * ```ts\n * import { ySort } from \"@yagejs/renderer\";\n *\n * // Depth-sort the auto-created default layer your entities already use —\n * // no per-component `layer` wiring needed.\n * class GameScene extends Scene {\n *   readonly layers: readonly LayerDef[] = [\n *     { name: \"default\", order: 0, sort: ySort },\n *   ];\n * }\n * ```\n */\nexport const ySort: LayerSortFn = (c: Container) => c.position.y;\n\n/**\n * Y-depth key with a per-container offset, the way Godot's\n * `y_sort_origin` shifts a sprite's apparent \"footprint\" for depth\n * comparisons. Use when a sprite's anchor is set to its top (so the\n * visual base sits well below `position.y`) and the raw `position.y`\n * produces wrong overlaps — a player whose feet are at the bottom of\n * the sprite should pass *behind* a tree whose trunk is at the bottom\n * of its own sprite, not be sorted by the headtop.\n *\n * `offsetOf(container)` is called once per child per frame; cheap data\n * (a getter / a property read) keeps the per-frame cost negligible. The\n * key falls back to plain `position.y` when `offsetOf` returns\n * `undefined`, so mixed-content layers work without every child having\n * a depth offset.\n *\n * ```ts\n * import { ySortBy } from \"@yagejs/renderer\";\n *\n * // Read the offset off a custom property (containers are extensible).\n * const sort = ySortBy((c) => (c as { depthOffset?: number }).depthOffset);\n *\n * // Then per-sprite:\n * sprite.sprite.depthOffset = 32; // pivot for sort lives 32 px below `position.y`\n * ```\n */\nexport function ySortBy(\n  offsetOf: (c: Container) => number | undefined,\n): LayerSortFn {\n  return (c) => c.position.y + (offsetOf(c) ?? 0);\n}\n","import type { SceneTransition, SceneTransitionContext } from \"@yagejs/core\";\nimport { Graphics } from \"pixi.js\";\nimport type { Container } from \"pixi.js\";\nimport { RendererKey } from \"../types.js\";\nimport { getSceneContainer } from \"./helpers.js\";\n\nexport interface FadeOptions {\n  /** Fade duration in seconds. Default: 0.3. */\n  duration?: number;\n  /** Fill color as a hex number. Default: 0x000000. */\n  color?: number;\n  /**\n   * When `true`, the overlay covers the full canvas including\n   * letterbox / expand bars. When `false` (default), it covers only the\n   * virtual play area — bars stay visible during the dip.\n   */\n  coverScreen?: boolean;\n}\n\n/**\n * Fade to a solid color, then fade back in. The fade-out takes the first\n * half of the duration, the fade-in takes the second half. The scene swap\n * happens when the overlay is fully opaque:\n * - push/replace: incoming scene stays hidden until the half-way mark, then\n *   is revealed underneath the decaying overlay.\n * - pop: outgoing scene stays visible through the fade-out, then is hidden\n *   at the half-way mark so the destination shows through during fade-in.\n *\n * Without this, pop would render the outgoing scene the whole way through\n * and \"pop\" suddenly to the destination once the stack is popped at end().\n */\nexport function fade(opts: FadeOptions = {}): SceneTransition {\n  const duration = opts.duration ?? 0.3;\n  const color = opts.color ?? 0x000000;\n  const coverScreen = opts.coverScreen ?? false;\n\n  let overlay: Graphics | undefined;\n  let toContainer: Container | undefined;\n  let fromContainer: Container | undefined;\n  let crossedHalfway = false;\n\n  return {\n    duration,\n    begin(ctx: SceneTransitionContext) {\n      const renderer = ctx.engineContext.resolve(RendererKey);\n      overlay = new Graphics();\n      if (coverScreen) {\n        // `app.stage` sits at identity, so its children operate in canvas\n        // pixels — sized to cover the bars too.\n        const { width, height } = renderer.application.screen;\n        overlay.rect(0, 0, width, height);\n        renderer.application.stage.addChild(overlay);\n      } else {\n        // Size against `visibleCanvasRect` (canvas extent in virtual-px\n        // coords). Under letterbox the worldRoot mask clips the overshoot\n        // back to virtual; under expand there's no mask, so the overlay\n        // paints into the bars too — exactly what `expand` games want.\n        const r = renderer.visibleCanvasRect;\n        overlay.rect(r.x, r.y, r.width, r.height);\n        renderer.worldRoot.addChild(overlay);\n      }\n      overlay.fill({ color, alpha: 1 });\n      overlay.alpha = 0;\n\n      crossedHalfway = false;\n      if (ctx.kind === \"pop\") {\n        fromContainer = getSceneContainer(ctx, ctx.fromScene);\n      } else {\n        toContainer = getSceneContainer(ctx, ctx.toScene);\n        if (toContainer) toContainer.visible = false;\n      }\n    },\n    tick(_dt: number, ctx: SceneTransitionContext) {\n      if (!overlay) return;\n      const t = ctx.elapsed / duration;\n      overlay.alpha = t < 0.5 ? t * 2 : (1 - t) * 2;\n      if (!crossedHalfway && t >= 0.5) {\n        if (toContainer) toContainer.visible = true;\n        if (fromContainer) fromContainer.visible = false;\n        crossedHalfway = true;\n      }\n    },\n    end() {\n      if (overlay) {\n        overlay.destroy();\n        overlay = undefined;\n      }\n      // Restore visibility on the incoming scene as a `clear()`-mid-run\n      // safety net — the scene lives on and leaving it hidden would\n      // corrupt state. Deliberately do NOT restore `fromContainer`: on\n      // pop/replace it's about to be destroyed, but `end()` fires inside\n      // the tick's update phase before PIXI renders — restoring visible\n      // here would paint the outgoing scene for one last frame before\n      // teardown, producing a visible \"pop\".\n      if (toContainer) toContainer.visible = true;\n      toContainer = undefined;\n      fromContainer = undefined;\n      crossedHalfway = false;\n    },\n  };\n}\n","import type { Scene, SceneTransitionContext } from \"@yagejs/core\";\nimport type { DisplayContainer } from \"../public-types.js\";\nimport { SceneRenderTreeProviderKey } from \"../SceneRenderTree.js\";\nimport { RendererKey } from \"../types.js\";\n\n/**\n * Resolve the root container for a scene that participates in a transition.\n * Returns `undefined` if `scene` is undefined or its tree hasn't been\n * materialized. Intended for use inside `SceneTransition.begin/tick/end`\n * so custom transitions can manipulate per-scene containers without\n * boilerplate.\n */\nexport function getSceneContainer(\n  ctx: SceneTransitionContext,\n  scene: Scene | undefined,\n): DisplayContainer | undefined {\n  if (!scene) return undefined;\n  return ctx.engineContext.resolve(SceneRenderTreeProviderKey).getTree(scene)\n    ?.root;\n}\n\n/**\n * Bounds of the declared virtual play area — equivalent to\n * `renderer.virtualSize`. Use this to size masks, translations, or\n * geometry that's scoped to a single scene's content (e.g. a per-cell\n * mask painted onto a scene root). Children of scene roots and of\n * `_worldRoot` operate in virtual pixels.\n *\n * For full-screen overlays parented to `renderer.worldRoot`, prefer\n * `renderer.visibleCanvasRect` — it equals the virtual rect under\n * `letterbox` (clipped) but extends into the bars under `expand`, which\n * is usually what an obscuring overlay wants. For overlays that must\n * also paint over letterbox bars, parent on `app.stage` and size in\n * canvas pixels via `app.screen.width / .height`.\n */\nexport function getVirtualBounds(ctx: SceneTransitionContext): {\n  width: number;\n  height: number;\n} {\n  return ctx.engineContext.resolve(RendererKey).virtualSize;\n}\n","import type { SceneTransition, SceneTransitionContext } from \"@yagejs/core\";\nimport { Graphics } from \"pixi.js\";\nimport type { Container } from \"pixi.js\";\nimport { RendererKey } from \"../types.js\";\nimport { getSceneContainer } from \"./helpers.js\";\n\nexport interface FlashOptions {\n  /** Flash duration in seconds. Default: 0.2. */\n  duration?: number;\n  /** Flash color as a hex number. Default: 0xffffff. */\n  color?: number;\n  /**\n   * When `true`, the overlay covers the full canvas including\n   * letterbox / expand bars. When `false` (default), it covers only the\n   * virtual play area — bars stay visible during the flash.\n   */\n  coverScreen?: boolean;\n}\n\n/**\n * Flash a solid color that decays from full opacity to zero over the\n * duration. The overlay is fully opaque at begin, so the scene swap happens\n * invisibly under the flash:\n * - push/replace: no visibility juggling — the incoming scene is already\n *   mounted on top of the outgoing one in the stage order, so as the\n *   overlay decays only the incoming scene shows through.\n * - pop: outgoing (top) scene is hidden from begin. Overlay masks the hide,\n *   and the destination beneath shows through as the flash tapers.\n */\nexport function flash(opts: FlashOptions = {}): SceneTransition {\n  const duration = opts.duration ?? 0.2;\n  const color = opts.color ?? 0xffffff;\n  const coverScreen = opts.coverScreen ?? false;\n\n  let overlay: Graphics | undefined;\n  let fromContainer: Container | undefined;\n\n  return {\n    duration,\n    begin(ctx: SceneTransitionContext) {\n      const renderer = ctx.engineContext.resolve(RendererKey);\n      overlay = new Graphics();\n      if (coverScreen) {\n        const { width, height } = renderer.application.screen;\n        overlay.rect(0, 0, width, height);\n        renderer.application.stage.addChild(overlay);\n      } else {\n        // `visibleCanvasRect` returns the full canvas extent in virtual\n        // pixels — clipped to virtual under letterbox, extends into the\n        // bars under expand.\n        const r = renderer.visibleCanvasRect;\n        overlay.rect(r.x, r.y, r.width, r.height);\n        renderer.worldRoot.addChild(overlay);\n      }\n      overlay.fill({ color, alpha: 1 });\n      overlay.alpha = 1;\n\n      if (ctx.kind === \"pop\") {\n        fromContainer = getSceneContainer(ctx, ctx.fromScene);\n        if (fromContainer) fromContainer.visible = false;\n      }\n    },\n    tick(_dt: number, ctx: SceneTransitionContext) {\n      if (!overlay) return;\n      overlay.alpha = 1 - ctx.elapsed / duration;\n    },\n    end() {\n      if (overlay) {\n        overlay.destroy();\n        overlay = undefined;\n      }\n      // Deliberately don't restore fromContainer — on pop it's about to be\n      // destroyed and end() fires inside the tick's update phase before\n      // PIXI renders, so restoring would paint the outgoing scene for one\n      // last frame.\n      fromContainer = undefined;\n    },\n  };\n}\n","import type { SceneTransition, SceneTransitionContext } from \"@yagejs/core\";\nimport type { Container } from \"pixi.js\";\nimport { getSceneContainer } from \"./helpers.js\";\n\nexport interface CrossFadeOptions {\n  /** Duration in seconds. Default: 0.4. */\n  duration?: number;\n}\n\n/**\n * Cross-dissolve between two scenes: the outgoing scene fades from full\n * opacity to zero while the incoming scene fades in. Both scenes remain\n * visible throughout, so there's no blackout in the middle — good for\n * menu→game and level→level handoffs.\n */\nexport function crossFade(opts: CrossFadeOptions = {}): SceneTransition {\n  const duration = opts.duration ?? 0.4;\n\n  let fromContainer: Container | undefined;\n  let toContainer: Container | undefined;\n\n  return {\n    duration,\n    begin(ctx: SceneTransitionContext) {\n      fromContainer = getSceneContainer(ctx, ctx.fromScene);\n      toContainer = getSceneContainer(ctx, ctx.toScene);\n      if (fromContainer) fromContainer.alpha = 1;\n      if (toContainer) toContainer.alpha = 0;\n    },\n    tick(_dt: number, ctx: SceneTransitionContext) {\n      const t = Math.min(ctx.elapsed / duration, 1);\n      if (fromContainer) fromContainer.alpha = 1 - t;\n      if (toContainer) toContainer.alpha = t;\n    },\n    end(ctx: SceneTransitionContext) {\n      // Only restore the outgoing alpha when the outgoing scene survives\n      // (push keeps it on the stack, paused below). For pop/replace the\n      // outgoing scene is about to be removed — restoring to 1 here causes\n      // a one-frame flash because end() fires during the tick phase,\n      // before the same rAF's render runs, while the actual removal waits\n      // on a microtask.\n      if (fromContainer && ctx.kind === \"push\") fromContainer.alpha = 1;\n      if (toContainer) toContainer.alpha = 1;\n      fromContainer = undefined;\n      toContainer = undefined;\n    },\n  };\n}\n","import type { SceneTransition, SceneTransitionContext } from \"@yagejs/core\";\nimport { Container, Graphics } from \"pixi.js\";\nimport { RendererKey } from \"../types.js\";\nimport { getSceneContainer, getVirtualBounds } from \"./helpers.js\";\n\nexport interface IrisOptions {\n  /** Iris duration in seconds. Default: 0.6. */\n  duration?: number;\n  /** Fill color visible outside the iris. Default: 0x000000. */\n  color?: number;\n  /**\n   * Iris center in **virtual-space pixels** — the same coord system you\n   * use for game logic. Default: virtual-space center. The maximum radius\n   * is the distance from this point to the farthest corner of whatever\n   * the overlay covers (virtual rect by default, full canvas under\n   * `coverScreen: true`), so the iris always fully covers its target at\n   * the mid-point.\n   */\n  center?: { x: number; y: number };\n  /**\n   * When `true`, the dip-to-color overlay covers the full canvas\n   * including letterbox / expand bars. When `false` (default), it covers\n   * only the virtual play area — bars stay visible during the dip.\n   */\n  coverScreen?: boolean;\n}\n\n/**\n * Iris-out → swap → iris-in. A circular cut-out of the screen shrinks to\n * zero over the first half (covering everything in `color`), then grows\n * back over the second half to reveal the destination. Symmetric to\n * `fade()` but with a circular shape — useful for retro-style transitions\n * (Zelda overworld→cave, classic Mario level intros).\n *\n * Implementation: a fullscreen color overlay carries an inverse circular\n * mask so the area inside the circle stays transparent (revealing the\n * scene below) while the outside fills with `color`. The mask is redrawn\n * each frame to animate the radius.\n *\n * - push/replace: incoming scene stays hidden until the half-way mark,\n *   then is revealed underneath the opening iris.\n * - pop: outgoing scene stays visible through the closing iris, then is\n *   hidden at the half-way mark so the destination shows through during\n *   the opening half.\n */\nexport function iris(opts: IrisOptions = {}): SceneTransition {\n  const duration = opts.duration ?? 0.6;\n  const color = opts.color ?? 0x000000;\n  const coverScreen = opts.coverScreen ?? false;\n\n  let overlay: Container | undefined;\n  let maskGfx: Graphics | undefined;\n  let cx = 0;\n  let cy = 0;\n  let maxRadius = 0;\n  let toContainer: Container | undefined;\n  let fromContainer: Container | undefined;\n  let crossedHalfway = false;\n\n  return {\n    duration,\n    begin(ctx: SceneTransitionContext) {\n      const renderer = ctx.engineContext.resolve(RendererKey);\n      const virtual = getVirtualBounds(ctx);\n      const cxv = opts.center?.x ?? virtual.width / 2;\n      const cyv = opts.center?.y ?? virtual.height / 2;\n\n      let rx: number;\n      let ry: number;\n      let rw: number;\n      let rh: number;\n      if (coverScreen) {\n        // Overlay covers the canvas including bars; sized + positioned in\n        // canvas pixels. Convert the virtual-px center through the fit\n        // transform so callers stay in game coords either way.\n        const screen = renderer.application.screen;\n        rx = 0;\n        ry = 0;\n        rw = screen.width;\n        rh = screen.height;\n        const canvasCenter = renderer.virtualToCanvas(cxv, cyv);\n        cx = canvasCenter.x;\n        cy = canvasCenter.y;\n      } else {\n        // Overlay scoped to the on-screen canvas extent in virtual pixels.\n        // Under letterbox the worldRoot mask clips overshoot back to\n        // virtual; under expand the overlay paints into the bars too.\n        const r = renderer.visibleCanvasRect;\n        rx = r.x;\n        ry = r.y;\n        rw = r.width;\n        rh = r.height;\n        cx = cxv;\n        cy = cyv;\n      }\n      const farX = Math.max(cx - rx, rx + rw - cx);\n      const farY = Math.max(cy - ry, ry + rh - cy);\n      maxRadius = Math.hypot(farX, farY);\n\n      // Pixi v8: Graphics is no longer a Container — children must live on\n      // a real Container. The overlay holds the color fill + mask geometry.\n      overlay = new Container();\n      const fill = new Graphics();\n      fill.rect(rx, ry, rw, rh).fill({ color, alpha: 1 });\n      maskGfx = new Graphics();\n      drawCircleMask(maskGfx, cx, cy, maxRadius);\n      overlay.addChild(fill);\n      overlay.addChild(maskGfx);\n      overlay.setMask({ mask: maskGfx, inverse: true });\n      if (coverScreen) {\n        renderer.application.stage.addChild(overlay);\n      } else {\n        renderer.worldRoot.addChild(overlay);\n      }\n\n      crossedHalfway = false;\n      if (ctx.kind === \"pop\") {\n        fromContainer = getSceneContainer(ctx, ctx.fromScene);\n      } else {\n        toContainer = getSceneContainer(ctx, ctx.toScene);\n        if (toContainer) toContainer.visible = false;\n      }\n    },\n    tick(_dt: number, ctx: SceneTransitionContext) {\n      if (!maskGfx) return;\n      const t = Math.min(ctx.elapsed / duration, 1);\n      const r = Math.abs(1 - t * 2) * maxRadius;\n      drawCircleMask(maskGfx, cx, cy, r);\n      if (!crossedHalfway && t >= 0.5) {\n        if (toContainer) toContainer.visible = true;\n        if (fromContainer) fromContainer.visible = false;\n        crossedHalfway = true;\n      }\n    },\n    end() {\n      if (overlay) {\n        overlay.destroy({ children: true });\n        overlay = undefined;\n      }\n      maskGfx = undefined;\n      // Restore visibility on the incoming scene as a `clear()`-mid-run\n      // safety net. Deliberately do NOT restore `fromContainer`: on\n      // pop/replace it's about to be destroyed but `end()` fires inside\n      // the tick's update phase before PIXI renders, so restoring would\n      // paint the outgoing scene for one last frame.\n      if (toContainer) toContainer.visible = true;\n      toContainer = undefined;\n      fromContainer = undefined;\n      crossedHalfway = false;\n    },\n  };\n}\n\nfunction drawCircleMask(g: Graphics, x: number, y: number, r: number): void {\n  g.clear();\n  // A zero-radius circle would still register as a draw command; skip so\n  // the inverse mask cleanly degrades to \"fully covered\" at the midpoint.\n  if (r > 0) g.circle(x, y, r).fill({ color: 0xffffff });\n}\n","import { easeLinear, ErrorBoundaryKey } from \"@yagejs/core\";\nimport type {\n  EasingFunction,\n  SceneTransition,\n  SceneTransitionContext,\n} from \"@yagejs/core\";\nimport { attributed } from \"../internal/attribution.js\";\nimport { Graphics } from \"pixi.js\";\nimport type { Container } from \"pixi.js\";\nimport { SceneRenderTreeProviderKey } from \"../SceneRenderTree.js\";\nimport { getSceneContainer, getVirtualBounds } from \"./helpers.js\";\n\nexport interface IrisRevealOptions {\n  /** Iris duration in seconds. Default: 0.6. */\n  duration?: number;\n  /**\n   * Iris center in virtual-space pixels. Default: virtual-space center.\n   * The maximum radius is the distance from this point to the farthest\n   * corner of the virtual rect, so the iris always fully covers the\n   * canvas at `t = 1`.\n   */\n  center?: { x: number; y: number };\n  /** Easing function applied to the radius. Default: `easeLinear`. */\n  easing?: EasingFunction;\n}\n\n/**\n * Reveal the destination scene through an expanding circular mask. The\n * incoming scene's container is masked by a circle that grows from\n * radius 0 to a radius covering the canvas, so the new scene \"blooms\"\n * over the previous one from the chosen center point. The previous\n * scene stays visible outside the iris until the circle fully covers\n * it — no color overlay, no mid-point swap.\n *\n * Pairs with `iris()` (the symmetric close-then-open variant): pick\n * `iris` for retro Zelda-style dip-to-black handoffs, `irisReveal` for\n * a one-way reveal where the new scene grows over the old.\n *\n * On `pop` the destination scene is brought to the front of the scene\n * stack so the same mechanic applies — without it the outgoing scene\n * would render over the masked destination.\n */\nexport function irisReveal(opts: IrisRevealOptions = {}): SceneTransition {\n  const duration = opts.duration ?? 0.6;\n  const easing = opts.easing ?? easeLinear;\n\n  let toContainer: Container | undefined;\n  let maskGfx: Graphics | undefined;\n  let cx = 0;\n  let cy = 0;\n  let maxRadius = 0;\n\n  return {\n    duration,\n    begin(ctx: SceneTransitionContext) {\n      const provider = ctx.engineContext.resolve(SceneRenderTreeProviderKey);\n      if (ctx.toScene) provider.bringSceneToFront?.(ctx.toScene);\n\n      toContainer = getSceneContainer(ctx, ctx.toScene);\n      if (!toContainer) return;\n\n      const { width: w, height: h } = getVirtualBounds(ctx);\n      cx = opts.center?.x ?? w / 2;\n      cy = opts.center?.y ?? h / 2;\n      const farX = Math.max(cx, w - cx);\n      const farY = Math.max(cy, h - cy);\n      maxRadius = Math.hypot(farX, farY);\n\n      maskGfx = new Graphics();\n      toContainer.addChild(maskGfx);\n      toContainer.setMask({ mask: maskGfx, inverse: false });\n      drawCircleMask(maskGfx, cx, cy, 0);\n    },\n    tick(_dt: number, ctx: SceneTransitionContext) {\n      if (!maskGfx) return;\n      const t = Math.min(ctx.elapsed / duration, 1);\n      const r =\n        attributed(\n          ctx.engineContext.tryResolve(ErrorBoundaryKey),\n          { kind: \"Scene transition easing\", event: \"irisReveal\" },\n          () => easing(t),\n        ) * maxRadius;\n      drawCircleMask(maskGfx, cx, cy, r);\n    },\n    end() {\n      // Direct assignment — see `chessboard.end()` and `attachMask` for the\n      // pixi v8 setMask({ mask: null }) hazard.\n      if (toContainer) toContainer.mask = null;\n      if (maskGfx) {\n        maskGfx.removeFromParent();\n        maskGfx.destroy();\n        maskGfx = undefined;\n      }\n      toContainer = undefined;\n    },\n  };\n}\n\nfunction drawCircleMask(g: Graphics, x: number, y: number, r: number): void {\n  g.clear();\n  if (r > 0) g.circle(x, y, r).fill({ color: 0xffffff });\n}\n","import type { SceneTransition, SceneTransitionContext } from \"@yagejs/core\";\nimport { Graphics } from \"pixi.js\";\nimport type { Container } from \"pixi.js\";\nimport { SceneRenderTreeProviderKey } from \"../SceneRenderTree.js\";\nimport { getSceneContainer, getVirtualBounds } from \"./helpers.js\";\n\nexport interface ChessboardOptions {\n  /** Total duration in seconds. Default: 0.7. */\n  duration?: number;\n  /** Grid rows. Default: 6. */\n  rows?: number;\n  /** Grid columns. Default: 10. */\n  cols?: number;\n}\n\n/**\n * Reveal the destination scene through a staggered checkerboard mask. The\n * incoming scene's container is masked by a grid of cells that grow from\n * a center point to fill their slot — even-parity cells first, odd-parity\n * second — so the new scene \"paints in\" cell-by-cell on top of the\n * previous one. No blackout mid-point and no color overlay: the previous\n * scene stays visible underneath until each cell of the new scene covers it.\n *\n * - Even cells (`(row + col) & 1 === 0`): grow over `[0, 0.7]`\n * - Odd cells  (`(row + col) & 1 === 1`): grow over `[0.3, 1]`\n *\n * Pixi v8 Graphics masks are stencil clips (binary in/out, no alpha) —\n * scaling each cell from 0 to its full size with smoothstep easing produces\n * the soft per-cell entry that mask-fill alpha can't. The 0.4 overlap means\n * odd cells start growing while even cells are still mid-grow, removing the\n * \"second wave pops in\" jolt at the midpoint.\n *\n * On `pop` the destination scene is brought to the front of the scene\n * stack so the same mechanic applies — without it the outgoing scene\n * would render over the masked destination.\n */\nexport function chessboard(opts: ChessboardOptions = {}): SceneTransition {\n  const duration = opts.duration ?? 0.7;\n  const rows = Math.max(1, Math.floor(opts.rows ?? 6));\n  const cols = Math.max(1, Math.floor(opts.cols ?? 10));\n\n  let toContainer: Container | undefined;\n  let maskGfx: Graphics | undefined;\n\n  return {\n    duration,\n    begin(ctx: SceneTransitionContext) {\n      const provider = ctx.engineContext.resolve(SceneRenderTreeProviderKey);\n      // Pop normally leaves the outgoing scene on top — bring the\n      // destination to the front so its mask drives the visual reveal.\n      // No-op for push/replace where the new scene is already topmost.\n      if (ctx.toScene) provider.bringSceneToFront?.(ctx.toScene);\n\n      toContainer = getSceneContainer(ctx, ctx.toScene);\n      if (!toContainer) return;\n      const { width, height } = getVirtualBounds(ctx);\n      maskGfx = new Graphics();\n      toContainer.addChild(maskGfx);\n      toContainer.setMask({ mask: maskGfx, inverse: false });\n      drawCells(maskGfx, width, height, rows, cols, 0);\n    },\n    tick(_dt: number, ctx: SceneTransitionContext) {\n      if (!maskGfx) return;\n      const t = Math.min(ctx.elapsed / duration, 1);\n      const { width, height } = getVirtualBounds(ctx);\n      drawCells(maskGfx, width, height, rows, cols, t);\n    },\n    end() {\n      // Direct assignment instead of `setMask({ mask: null })` — pixi v8's\n      // setMask with null only updates the cached options and leaves the\n      // live effect dangling on a destroyed mask. Same gotcha attachMask\n      // documents at length.\n      if (toContainer) toContainer.mask = null;\n      if (maskGfx) {\n        maskGfx.removeFromParent();\n        maskGfx.destroy();\n        maskGfx = undefined;\n      }\n      toContainer = undefined;\n    },\n  };\n}\n\nfunction drawCells(\n  g: Graphics,\n  width: number,\n  height: number,\n  rows: number,\n  cols: number,\n  t: number,\n): void {\n  g.clear();\n  const cw = width / cols;\n  const ch = height / rows;\n  for (let r = 0; r < rows; r++) {\n    for (let c = 0; c < cols; c++) {\n      const phase = ((r + c) & 1) as 0 | 1;\n      const s = cellScale(t, phase);\n      if (s <= 0) continue;\n      const w = cw * s;\n      const h = ch * s;\n      const x = c * cw + (cw - w) / 2;\n      const y = r * ch + (ch - h) / 2;\n      g.rect(x, y, w, h).fill({ color: 0xffffff });\n    }\n  }\n}\n\nfunction cellScale(t: number, phase: 0 | 1): number {\n  const start = phase === 0 ? 0 : 0.3;\n  const end = phase === 0 ? 0.7 : 1;\n  if (t <= start) return 0;\n  if (t >= end) return 1;\n  const x = (t - start) / (end - start);\n  return x * x * (3 - 2 * x);\n}\n","import { easeOutCubic, ErrorBoundaryKey } from \"@yagejs/core\";\nimport type {\n  EasingFunction,\n  SceneTransition,\n  SceneTransitionContext,\n} from \"@yagejs/core\";\nimport { attributed } from \"../internal/attribution.js\";\nimport type { Container } from \"pixi.js\";\nimport { getSceneContainer, getVirtualBounds } from \"./helpers.js\";\n\n/** Direction the outgoing scene exits the frame in. */\nexport type SlideDirection = \"left\" | \"right\" | \"up\" | \"down\";\n\nexport interface SlidePushOptions {\n  /** Total duration in seconds. Default: 0.5. */\n  duration?: number;\n  /**\n   * Direction the OUTGOING scene exits in. The incoming scene enters from\n   * the opposite edge. Default: `\"left\"` (incoming slides in from the right,\n   * pushing the previous scene off to the left — book-style forward turn).\n   */\n  direction?: SlideDirection;\n  /**\n   * When `true` (default), `pop` reverses `direction` so the back motion\n   * mirrors the forward motion — pairs naturally with a scene's\n   * `defaultTransition`. Set to `false` if the call-site direction is\n   * already authored for a specific kind.\n   */\n  reverseOnPop?: boolean;\n  /** Easing function applied to the slide progress. Default: `easeOutCubic`. */\n  easing?: EasingFunction;\n}\n\n/**\n * Slide both scenes off and on together: the incoming scene enters from\n * one edge while the outgoing scene exits the opposite edge at the same\n * pace, locked together as a single horizontal/vertical translation.\n * Ideal for menu carousels, level-to-level book turns, or wizard flows.\n *\n * Unlike a pure `slideIn`, this transition translates BOTH containers,\n * giving the visual impression that the new scene is physically pushing\n * the old one off the screen.\n *\n * On `pop`, the direction is mirrored by default so that \"back\" reverses\n * \"forward\" — opt out via `reverseOnPop: false` for explicit control.\n */\nexport function slidePush(opts: SlidePushOptions = {}): SceneTransition {\n  const duration = opts.duration ?? 0.5;\n  const direction = opts.direction ?? \"left\";\n  const reverseOnPop = opts.reverseOnPop ?? true;\n  const easing = opts.easing ?? easeOutCubic;\n\n  let toContainer: Container | undefined;\n  let fromContainer: Container | undefined;\n  let dx = 0;\n  let dy = 0;\n\n  return {\n    duration,\n    begin(ctx: SceneTransitionContext) {\n      const { width: w, height: h } = getVirtualBounds(ctx);\n      const effective =\n        ctx.kind === \"pop\" && reverseOnPop ? reverse(direction) : direction;\n      const off = directionOffsets(effective, w, h);\n      dx = off.dx;\n      dy = off.dy;\n\n      fromContainer = getSceneContainer(ctx, ctx.fromScene);\n      toContainer = getSceneContainer(ctx, ctx.toScene);\n\n      if (toContainer) {\n        toContainer.x = -dx;\n        toContainer.y = -dy;\n      }\n      if (fromContainer) {\n        fromContainer.x = 0;\n        fromContainer.y = 0;\n      }\n    },\n    tick(_dt: number, ctx: SceneTransitionContext) {\n      const t = attributed(\n        ctx.engineContext.tryResolve(ErrorBoundaryKey),\n        { kind: \"Scene transition easing\", event: \"slidePush\" },\n        () => easing(Math.min(ctx.elapsed / duration, 1)),\n      );\n      if (toContainer) {\n        toContainer.x = -dx * (1 - t);\n        toContainer.y = -dy * (1 - t);\n      }\n      if (fromContainer) {\n        fromContainer.x = dx * t;\n        fromContainer.y = dy * t;\n      }\n    },\n    end(ctx: SceneTransitionContext) {\n      if (toContainer) {\n        toContainer.x = 0;\n        toContainer.y = 0;\n      }\n      // Only reset the outgoing scene when it survives (push). On pop /\n      // replace it's about to be destroyed and a one-frame snap back to\n      // origin would flash before teardown — same hazard `crossFade`\n      // documents at end().\n      if (fromContainer && ctx.kind === \"push\") {\n        fromContainer.x = 0;\n        fromContainer.y = 0;\n      }\n      toContainer = undefined;\n      fromContainer = undefined;\n    },\n  };\n}\n\nfunction reverse(d: SlideDirection): SlideDirection {\n  switch (d) {\n    case \"left\":\n      return \"right\";\n    case \"right\":\n      return \"left\";\n    case \"up\":\n      return \"down\";\n    case \"down\":\n      return \"up\";\n  }\n}\n\nfunction directionOffsets(\n  d: SlideDirection,\n  w: number,\n  h: number,\n): { dx: number; dy: number } {\n  switch (d) {\n    case \"left\":\n      return { dx: -w, dy: 0 };\n    case \"right\":\n      return { dx: w, dy: 0 };\n    case \"up\":\n      return { dx: 0, dy: -h };\n    case \"down\":\n      return { dx: 0, dy: h };\n  }\n}\n","import type { Filter } from \"../public-types.js\";\nimport type { Effect, EffectFactory } from \"./Effect.js\";\n\n/** Options for {@link rawFilter}. */\nexport interface RawFilterOptions {\n  /**\n   * Optional accessor for the filter's primary intensity uniform. If\n   * provided, `fadeIn` / `fadeOut` on the resulting handle will tween it.\n   * If omitted, fades become no-ops and a one-shot dev warning fires.\n   */\n  intensity?: { get: () => number; set: (value: number) => void };\n}\n\nlet warned = false;\n\n/**\n * Wrap a user-supplied pixi `Filter` so it can be attached through the\n * `addEffect` API and managed by the same handle interface as built-in\n * effect presets. The escape hatch for custom shaders or any pixi-filters\n * import the engine doesn't expose a typed wrapper for.\n *\n * ```ts\n * import { BlurFilter } from \"pixi.js\";\n *\n * const filter = new BlurFilter({ strength: 8 });\n * sprite.fx.addEffect(rawFilter(filter, {\n *   intensity: {\n *     get: () => filter.strength / 8,\n *     set: (v) => { filter.strength = v * 8; },\n *   },\n * }));\n * ```\n *\n * Without the `intensity` option, `fadeIn` / `fadeOut` will return an\n * already-completed Process and warn once per session — the system can't\n * guess which uniform represents the effect's \"strength.\"\n */\nexport function rawFilter(\n  filter: Filter,\n  options?: RawFilterOptions,\n): EffectFactory {\n  return () => {\n    const intensity = options?.intensity;\n    const effect: Effect = {\n      filter,\n      getIntensity: () => intensity?.get() ?? 1,\n      setIntensity: (value) => {\n        if (intensity) {\n          intensity.set(value);\n          return;\n        }\n        if (!warned) {\n          warned = true;\n          console.warn(\n            \"rawFilter: fadeIn/fadeOut called on a filter without an `intensity` option — fades will no-op. \" +\n              \"Pass { intensity: { get, set } } to enable fading.\",\n          );\n        }\n      },\n    };\n    return effect;\n  };\n}\n\n/** @internal — reset the one-shot warning flag for tests. */\nexport function _resetRawFilterWarning(): void {\n  warned = false;\n}\n","import type { Mask, MaskFactory } from \"./MaskFactory.js\";\n\n/**\n * Named mask definition. Mirrors {@link EffectDefinition}. The callable\n * shape `(options) => MaskFactory` is what users invoke (`rectMask({ ... })`).\n */\nexport interface MaskDefinition<O> {\n  (options: O): MaskFactory;\n  readonly name: string;\n}\n\n/**\n * Define a named mask preset. The returned callable accepts the preset's\n * options and yields a `MaskFactory`.\n */\nexport function defineMask<O>(spec: {\n  name: string;\n  factory: (options: O) => Mask;\n}): MaskDefinition<O> {\n  const definition = ((options: O): MaskFactory => {\n    return () => spec.factory(options);\n  }) as MaskDefinition<O>;\n  Object.defineProperty(definition, \"name\", {\n    value: spec.name,\n    enumerable: true,\n    writable: false,\n    configurable: false,\n  });\n  return definition;\n}\n","import { Graphics } from \"pixi.js\";\nimport { defineMask } from \"./defineMask.js\";\n\n/** Options for {@link rectMask}. */\nexport interface RectMaskOptions {\n  x: number;\n  y: number;\n  width: number;\n  height: number;\n  /** Corner radius in pixels. Omit or pass 0 for a sharp rectangle. */\n  rounded?: number;\n}\n\n/**\n * Build a static rectangular mask. The renderer owns the underlying\n * `Graphics` node and destroys it on `remove()`.\n *\n * `x`/`y`/`width`/`height` are in the masked object's own local space, which\n * is world pixels on a world layer — the mask then scrolls with the camera —\n * and virtual pixels on a screen layer, where it stays put.\n *\n * For a mask that needs to update with the target's dimensions (e.g. a\n * layout-driven panel), use {@link graphicsMask} so you can call\n * `handle.redraw()` after each layout pass.\n */\nexport const rectMask = defineMask<RectMaskOptions>({\n  name: \"yage:rectMask\",\n  factory: (opts) => {\n    const g = new Graphics();\n    if (opts.rounded && opts.rounded > 0) {\n      g.roundRect(opts.x, opts.y, opts.width, opts.height, opts.rounded);\n    } else {\n      g.rect(opts.x, opts.y, opts.width, opts.height);\n    }\n    g.fill({ color: 0xffffff });\n    return {\n      node: g,\n      owned: true,\n      attachToTarget: true,\n      inverse: false,\n    };\n  },\n});\n","import type { DisplaySprite } from \"../public-types.js\";\nimport type { MaskFactory } from \"./MaskFactory.js\";\n\n/**\n * Use a caller-supplied `Sprite` as a mask — the sprite's alpha channel\n * defines the visible region. Useful for soft-edged or texture-driven\n * clipping (vignettes, organic frames) that a Graphics shape can't express.\n *\n * Ownership stays with the caller: the sprite is NOT parented or destroyed\n * by the mask system. Make sure it's already in the display tree\n * (typically as a child of the target or a hidden sibling) before calling\n * `setMask`, or pixi will silently fail to apply the mask.\n */\nexport function spriteMask(sprite: DisplaySprite): MaskFactory {\n  return () => ({\n    node: sprite,\n    owned: false,\n    attachToTarget: false,\n    inverse: false,\n  });\n}\n","import { Graphics } from \"pixi.js\";\nimport type { GraphicsContext } from \"../public-types.js\";\nimport type { MaskFactory } from \"./MaskFactory.js\";\n\n/**\n * Build a procedurally-drawn mask from a `Graphics` callback. The renderer\n * owns the `Graphics` node, runs `draw(g)` once at attach time, and re-runs\n * it whenever you call `handle.redraw()` — typically after a layout pass\n * changes the dimensions the closure references.\n *\n * ```ts\n * const handle = attachMask(panel.container, graphicsMask((g) => {\n *   g.clear();\n *   g.rect(0, 0, panel.width, panel.height);\n *   g.fill({ color: 0xffffff });\n * }));\n * // …after layout changes:\n * handle.redraw();\n * ```\n *\n * Everything the callback draws is in the masked object's own local space,\n * which is world pixels on a world layer — the mask then scrolls with the\n * camera — and virtual pixels on a screen layer, where it stays put.\n *\n * **Two gotchas:**\n *\n * 1. **Always `g.clear()` first.** Pixi `Graphics` commands accumulate, so\n *    without `clear()` each `redraw()` layers another shape on top of the\n *    previous one. We don't auto-clear — some draws intentionally compose.\n * 2. **Read live state inside the closure, don't snapshot it outside.** JS\n *    closures capture variable bindings, not values; if you save a number\n *    into a `const` and reference that, `redraw()` keeps using the original\n *    number. Reach through to a live source — a property access on a\n *    captured object, a method call, a getter — so each invocation pulls\n *    the current value:\n *\n *    ```ts\n *    // ❌ Stale — captures const value\n *    const w = 200, h = 100;\n *    graphicsMask((g) => { g.clear(); g.rect(0, 0, w, h).fill(0xffffff); });\n *\n *    // ✅ Fresh — reads live state every call\n *    graphicsMask((g) => {\n *      g.clear();\n *      g.rect(0, 0, panel.width, panel.height).fill(0xffffff);\n *    });\n *    ```\n */\nexport function graphicsMask(draw: (g: GraphicsContext) => void): MaskFactory {\n  return () => {\n    const g = new Graphics();\n    draw(g);\n    return {\n      node: g,\n      owned: true,\n      attachToTarget: true,\n      inverse: false,\n      redraw: () => draw(g),\n    };\n  };\n}\n"],"mappings":"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","names":["import_core","import_core","import_pixi","import_core","import_core","import_core","import_core","import_core","import_core","import_core","import_core","import_core","import_core","import_core","import_core","import_pixi","import_core","import_pixi","import_core","toFiniteVec2","finite","import_core","import_core","import_pixi","import_core","import_pixi","import_pixi","import_core","import_pixi","PixiRenderLayer","import_core","import_pixi","import_pixi","spritesheet","texture","PixiNineSliceSprite","PixiTextStyle","m","PixiApplication","import_pixi","texture","import_pixi","import_pixi","import_pixi","import_pixi","import_pixi","import_core","import_core","import_core","import_core","import_pixi","import_pixi","import_pixi","import_core","import_pixi","drawCircleMask","import_pixi","import_core","import_pixi","import_pixi"]}