@canvas-tile-engine/core 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/constants.ts","../src/utils/viewport.ts","../src/modules/Camera.ts","../src/modules/Config.ts","../src/modules/CoordinateTransformer.ts","../src/modules/SpatialIndex.ts","../src/modules/CanvasDraw.ts","../src/modules/EventManager/EventBinder.ts","../src/modules/EventManager/GestureController.ts","../src/modules/EventManager/ResizeWatcher.ts","../src/modules/EventManager/index.ts","../src/modules/ImageLoader.ts","../src/modules/Layer.ts","../src/modules/ViewportState.ts","../src/modules/CoordinateOverlayRenderer.ts","../src/modules/CanvasDebug.ts","../src/modules/Renderer/CanvasRenderer.ts","../src/modules/SizeController.ts","../src/modules/AnimationController.ts","../src/modules/RendererFactory.ts","../src/CanvasTileEngine.ts"],"sourcesContent":["/**\n * Global constants for the canvas grid engine.\n * Centralizes magic numbers and configuration values.\n */\n\nexport const DEFAULT_VALUES = {\n /** Default animation duration in milliseconds */\n ANIMATION_DURATION_MS: 500,\n\n /** Pixel offset for centering cells (0.5 = center of pixel) */\n CELL_CENTER_OFFSET: 0.5,\n\n /** Default retry count for image loading */\n IMAGE_LOAD_RETRY_COUNT: 1,\n\n /** Maximum wheel delta value for zoom (prevents extreme zooming) */\n MAX_WHEEL_DELTA: 100,\n\n /** Minimum wheel delta value for zoom */\n MIN_WHEEL_DELTA: -100,\n\n /** Zoom sensitivity factor */\n ZOOM_SENSITIVITY: 0.001,\n} as const;\n\nexport const SCALE_LIMITS = {\n /** Default minimum scale multiplier */\n MIN_SCALE_MULTIPLIER: 0.5,\n\n /** Default maximum scale multiplier */\n MAX_SCALE_MULTIPLIER: 2,\n} as const;\n\nexport const SIZE_LIMITS = {\n /** Default minimum canvas width in pixels */\n MIN_WIDTH: 100,\n\n /** Default minimum canvas height in pixels */\n MIN_HEIGHT: 100,\n\n /** Default maximum width (infinity means no limit) */\n MAX_WIDTH: Infinity,\n\n /** Default maximum height (infinity means no limit) */\n MAX_HEIGHT: Infinity,\n} as const;\n\nexport const RENDER_DEFAULTS = {\n /** Default background color */\n BACKGROUND_COLOR: \"#ffffff\",\n\n /** Default renderer type */\n RENDERER_TYPE: \"canvas\" as const,\n} as const;\n\nexport const COORDINATE_OVERLAY = {\n /** Coordinate overlay border width in pixels */\n BORDER_WIDTH: 20,\n\n /** Coordinate text opacity */\n TEXT_OPACITY: 0.8,\n\n /** Border overlay opacity */\n BORDER_OPACITY: 0.1,\n\n /** Minimum font size for coordinate labels */\n MIN_FONT_SIZE: 8,\n\n /** Maximum font size for coordinate labels */\n MAX_FONT_SIZE: 12,\n\n /** Font size scale factor relative to camera scale */\n FONT_SIZE_SCALE_FACTOR: 0.25,\n} as const;\n\nexport const DEBUG_HUD = {\n /** Debug HUD panel width in pixels */\n PANEL_WIDTH: 160,\n\n /** Debug HUD padding in pixels */\n PADDING: 8,\n\n /** Debug HUD line height in pixels */\n LINE_HEIGHT: 16,\n} as const;\n\nexport const VISIBILITY_BUFFER = {\n /** Buffer zone for visibility culling (tiles) */\n TILE_BUFFER: 1,\n} as const;\n","import { Coords } from \"../types\";\nimport { DEFAULT_VALUES } from \"../constants\";\n\n/** Pan the top-left point by screen pixel delta, respecting current scale. */\nexport function computePan(topLeft: Coords, scale: number, dx: number, dy: number): Coords {\n return { x: topLeft.x - dx / scale, y: topLeft.y - dy / scale };\n}\n\n/** Compute new top-left and scale when zooming around a mouse point. */\nexport function computeZoom(\n topLeft: Coords,\n oldScale: number,\n deltaY: number,\n minScale: number,\n maxScale: number,\n mouse: { x: number; y: number }\n): { topLeft: Coords; scale: number } {\n const limitedDelta = Math.min(Math.max(deltaY, DEFAULT_VALUES.MIN_WHEEL_DELTA), DEFAULT_VALUES.MAX_WHEEL_DELTA);\n const scaleFactor = Math.exp(-limitedDelta * DEFAULT_VALUES.ZOOM_SENSITIVITY);\n const newScale = Math.min(maxScale, Math.max(minScale, oldScale * scaleFactor));\n if (newScale === oldScale) return { topLeft, scale: oldScale };\n return {\n topLeft: {\n x: topLeft.x + mouse.x * (1 / oldScale - 1 / newScale),\n y: topLeft.y + mouse.y * (1 / oldScale - 1 / newScale),\n },\n scale: newScale,\n };\n}\n\n/** Convert world grid coordinates to screen pixels using camera state. */\nexport function worldToScreen(world: Coords, cam: { x: number; y: number; scale: number }): Coords {\n return {\n x: (world.x + DEFAULT_VALUES.CELL_CENTER_OFFSET - cam.x) * cam.scale,\n y: (world.y + DEFAULT_VALUES.CELL_CENTER_OFFSET - cam.y) * cam.scale,\n };\n}\n\n/** Convert screen pixels back to world grid coordinates using camera state. */\nexport function screenToWorld(screen: Coords, cam: { x: number; y: number; scale: number }): Coords {\n return { x: cam.x + screen.x / cam.scale, y: cam.y + screen.y / cam.scale };\n}\n","import { Coords } from \"../types\";\nimport { computePan, computeZoom } from \"../utils/viewport\";\nimport { DEFAULT_VALUES } from \"../constants\";\nimport { ViewportState } from \"./ViewportState\";\n\n/**\n * Camera contract used by rendering and coordinate transforms.\n * @internal\n */\nexport interface ICamera {\n /** Current top-left world x coordinate. */\n readonly x: number;\n /** Current top-left world y coordinate. */\n readonly y: number;\n /** Current zoom scale. */\n readonly scale: number;\n\n /**\n * Pan the camera by screen-space deltas.\n * @param deltaScreenX X delta in pixels.\n * @param deltaScreenY Y delta in pixels.\n */\n pan(deltaScreenX: number, deltaScreenY: number): void;\n\n /**\n * Zoom around a mouse position.\n * @param mouseX Mouse X relative to viewport.\n * @param mouseY Mouse Y relative to viewport.\n * @param deltaY Wheel delta (positive scroll down).\n * @param canvasRect Canvas bounding rect for mouse offset.\n */\n zoom(mouseX: number, mouseY: number, deltaY: number, canvasRect: DOMRect): void;\n\n /**\n * Canvas center coordinates in world space.\n * @param canvasWidth Canvas width in pixels.\n * @param canvasHeight Canvas height in pixels.\n * @returns Center point in world coordinates.\n */\n getCenter(canvasWidth: number, canvasHeight: number): Coords;\n\n /**\n * Set top-left coordinates based on a target center.\n * @param center Desired center in world space.\n * @param canvasWidth Canvas width in pixels.\n * @param canvasHeight Canvas height in pixels.\n */\n setCenter(center: Coords, canvasWidth: number, canvasHeight: number): void;\n\n /**\n * Adjust view so center stays stable on resize.\n * @param deltaWidthPx Change in canvas width (pixels).\n * @param deltaHeightPx Change in canvas height (pixels).\n */\n adjustForResize(deltaWidthPx: number, deltaHeightPx: number): void;\n\n /**\n * Zoom by a scale factor around a specific point (for pinch-to-zoom).\n * @param factor Scale multiplier (>1 zooms in, <1 zooms out).\n * @param centerX Center X in screen coordinates.\n * @param centerY Center Y in screen coordinates.\n */\n zoomByFactor(factor: number, centerX: number, centerY: number): void;\n}\n\n/**\n * Tracks camera position and zoom for converting between world and screen space.\n * @internal\n */\nexport class Camera implements ICamera {\n private _x: number;\n private _y: number;\n private _scale: number;\n readonly minScale: number;\n readonly maxScale: number;\n private bounds?: {\n minX: number;\n maxX: number;\n minY: number;\n maxY: number;\n };\n private viewport?: ViewportState;\n\n constructor(initialTopLeft: Coords, scale = 1, minScale = 0.1, maxScale = 10, viewport?: ViewportState) {\n this._x = initialTopLeft.x + DEFAULT_VALUES.CELL_CENTER_OFFSET; // Center of the pixel\n this._y = initialTopLeft.y + DEFAULT_VALUES.CELL_CENTER_OFFSET; // Center of the pixel\n this._scale = scale;\n this.minScale = minScale;\n this.maxScale = maxScale;\n this.viewport = viewport;\n }\n\n /**\n * Set camera bounds to limit panning area.\n * @param bounds Min and max coordinates for x and y axes. Set to undefined to remove bounds.\n */\n setBounds(bounds?: { minX: number; maxX: number; minY: number; maxY: number }) {\n this.bounds = bounds;\n // Clamp current position to new bounds\n if (this.bounds) {\n this.clampToBounds();\n }\n }\n\n private clampToBounds() {\n if (!this.bounds || !this.viewport) {\n return;\n }\n\n const { width: viewportWidth, height: viewportHeight } = this.viewport.getSize();\n\n // Calculate viewport size in world units\n const viewWidthWorld = viewportWidth / this._scale;\n const viewHeightWorld = viewportHeight / this._scale;\n\n this._x = this.clampAxis(this._x, viewWidthWorld, this.bounds.minX, this.bounds.maxX);\n this._y = this.clampAxis(this._y, viewHeightWorld, this.bounds.minY, this.bounds.maxY);\n }\n\n /**\n * Clamp a single axis value to bounds.\n * If viewport is larger than bounds, center it. Otherwise, keep viewport within bounds.\n */\n private clampAxis(value: number, viewSize: number, min: number, max: number): number {\n const boundsSize = max - min;\n\n // If viewport is larger than bounds, center the bounds in viewport\n if (viewSize >= boundsSize) {\n return min - (viewSize - boundsSize) / 2;\n }\n\n // Normal clamping: ensure viewport stays within bounds\n if (value < min) {\n return min;\n }\n if (value + viewSize > max) {\n return max - viewSize;\n }\n return value;\n }\n\n get x(): number {\n return this._x;\n }\n\n get y(): number {\n return this._y;\n }\n\n get scale(): number {\n return this._scale;\n }\n\n pan(deltaScreenX: number, deltaScreenY: number) {\n const next = computePan({ x: this._x, y: this._y }, this._scale, deltaScreenX, deltaScreenY);\n this._x = next.x;\n this._y = next.y;\n this.clampToBounds();\n }\n\n zoom(mouseX: number, mouseY: number, deltaY: number, canvasRect: DOMRect) {\n // Mouse position relative to canvas\n const mx = mouseX - canvasRect.left;\n const my = mouseY - canvasRect.top;\n\n const next = computeZoom({ x: this._x, y: this._y }, this._scale, deltaY, this.minScale, this.maxScale, {\n x: mx,\n y: my,\n });\n this._x = next.topLeft.x;\n this._y = next.topLeft.y;\n this._scale = next.scale;\n this.clampToBounds();\n }\n\n /**\n * Zoom by a scale factor around a specific point (for pinch-to-zoom).\n * @param factor Scale multiplier (>1 zooms in, <1 zooms out).\n * @param centerX Center X in screen coordinates.\n * @param centerY Center Y in screen coordinates.\n */\n zoomByFactor(factor: number, centerX: number, centerY: number) {\n const newScale = Math.min(this.maxScale, Math.max(this.minScale, this._scale * factor));\n if (newScale === this._scale) {\n return;\n }\n\n // Adjust top-left to keep the pinch center stationary\n this._x = this._x + centerX * (1 / this._scale - 1 / newScale);\n this._y = this._y + centerY * (1 / this._scale - 1 / newScale);\n this._scale = newScale;\n this.clampToBounds();\n }\n\n getCenter(canvasWidth: number, canvasHeight: number): Coords {\n return {\n x: this._x + canvasWidth / (2 * this._scale) - 0.5,\n y: this._y + canvasHeight / (2 * this._scale) - 0.5,\n };\n }\n\n setCenter(center: Coords, canvasWidth: number, canvasHeight: number) {\n this._x = center.x - canvasWidth / (2 * this._scale) + 0.5;\n this._y = center.y - canvasHeight / (2 * this._scale) + 0.5;\n this.clampToBounds();\n }\n\n adjustForResize(deltaWidthPx: number, deltaHeightPx: number) {\n this._x -= deltaWidthPx / (2 * this._scale);\n this._y -= deltaHeightPx / (2 * this._scale);\n this.clampToBounds();\n }\n}\n","import { CanvasTileEngineConfig, EventHandlers } from \"../types\";\nimport { SCALE_LIMITS, SIZE_LIMITS, RENDER_DEFAULTS } from \"../constants\";\n\n/**\n * Normalizes and stores grid engine configuration with safe defaults.\n * @internal\n */\nexport class Config {\n private config: Required<CanvasTileEngineConfig>;\n\n /**\n * Create a config store with defaults merged from the provided partial config.\n * @param config Incoming configuration values.\n */\n constructor(config: CanvasTileEngineConfig) {\n const base: Required<CanvasTileEngineConfig> = {\n renderer: RENDER_DEFAULTS.RENDERER_TYPE,\n scale: config.scale,\n minScale: config.minScale ?? config.scale * SCALE_LIMITS.MIN_SCALE_MULTIPLIER,\n maxScale: config.maxScale ?? config.scale * SCALE_LIMITS.MAX_SCALE_MULTIPLIER,\n\n size: {\n width: config.size.width,\n height: config.size.height,\n maxHeight: config.size.maxHeight ?? SIZE_LIMITS.MAX_HEIGHT,\n maxWidth: config.size.maxWidth ?? SIZE_LIMITS.MAX_WIDTH,\n minHeight: config.size.minHeight ?? SIZE_LIMITS.MIN_HEIGHT,\n minWidth: config.size.minWidth ?? SIZE_LIMITS.MIN_WIDTH,\n },\n\n backgroundColor: config.backgroundColor ?? RENDER_DEFAULTS.BACKGROUND_COLOR,\n\n eventHandlers: {\n click: config.eventHandlers?.click ?? false,\n hover: config.eventHandlers?.hover ?? false,\n drag: config.eventHandlers?.drag ?? false,\n zoom: config.eventHandlers?.zoom ?? false,\n resize: config.eventHandlers?.resize ?? false,\n },\n\n bounds: config.bounds ?? {\n minX: -Infinity,\n maxX: Infinity,\n minY: -Infinity,\n maxY: Infinity,\n },\n\n coordinates: {\n enabled: config.coordinates?.enabled ?? false,\n shownScaleRange: config.coordinates?.shownScaleRange ?? { min: 0, max: Infinity },\n },\n\n cursor: {\n default: config.cursor?.default ?? \"default\",\n move: config.cursor?.move ?? \"move\",\n },\n\n debug: {\n enabled: config.debug?.enabled ?? false,\n hud: {\n enabled: config.debug?.hud?.enabled ?? false,\n topLeftCoordinates: config.debug?.hud?.topLeftCoordinates ?? false,\n coordinates: config.debug?.hud?.coordinates ?? false,\n scale: config.debug?.hud?.scale ?? false,\n tilesInView: config.debug?.hud?.tilesInView ?? false,\n fps: config.debug?.hud?.fps ?? false,\n },\n eventHandlers: {\n click: config.debug?.eventHandlers?.click ?? true,\n hover: config.debug?.eventHandlers?.hover ?? true,\n drag: config.debug?.eventHandlers?.drag ?? true,\n zoom: config.debug?.eventHandlers?.zoom ?? true,\n resize: config.debug?.eventHandlers?.resize ?? true,\n },\n },\n };\n this.config = {\n ...base,\n size: Object.freeze(base.size),\n eventHandlers: Object.freeze(base.eventHandlers),\n bounds: Object.freeze(base.bounds),\n coordinates: Object.freeze({\n ...base.coordinates,\n shownScaleRange: Object.freeze(base.coordinates.shownScaleRange),\n }),\n cursor: Object.freeze(base.cursor),\n debug: Object.freeze({\n enabled: base.debug.enabled,\n hud: Object.freeze(base.debug.hud),\n eventHandlers: Object.freeze(base.debug.eventHandlers),\n }),\n };\n }\n\n /**\n * Get a defensive copy of the current configuration.\n * @returns Normalized configuration snapshot e.g. `{ scale: 1, size: { width: 800, height: 600 }, ... }`.\n */\n get(): Readonly<Required<CanvasTileEngineConfig>> {\n const cfg = this.config;\n return {\n ...cfg,\n size: { ...cfg.size },\n eventHandlers: { ...cfg.eventHandlers },\n bounds: { ...cfg.bounds },\n coordinates: {\n ...cfg.coordinates,\n shownScaleRange: {\n min: cfg.coordinates.shownScaleRange?.min ?? 0,\n max: cfg.coordinates.shownScaleRange?.max ?? Infinity,\n },\n },\n cursor: { ...cfg.cursor },\n debug: {\n ...cfg.debug,\n hud: { ...cfg.debug.hud },\n eventHandlers: { ...cfg.debug.eventHandlers },\n },\n };\n }\n\n /**\n * Update event handlers at runtime.\n * @param handlers Partial event handlers to update.\n */\n updateEventHandlers(handlers: Partial<EventHandlers>) {\n this.config = {\n ...this.config,\n eventHandlers: Object.freeze({\n ...this.config.eventHandlers,\n ...handlers,\n }),\n };\n }\n\n /**\n * Update map bounds at runtime.\n * @param bounds New boundary limits. Use Infinity/-Infinity to remove limits on specific axes.\n */\n updateBounds(bounds: { minX: number; maxX: number; minY: number; maxY: number }) {\n this.config = {\n ...this.config,\n bounds: Object.freeze(bounds),\n };\n }\n}\n","import type { Coords } from \"../types\";\nimport { ICamera } from \"./Camera\";\nimport { screenToWorld, worldToScreen } from \"../utils/viewport\";\n\n/**\n * Transforms coordinates between world space and screen space using the active camera.\n * @internal\n */\nexport class CoordinateTransformer {\n /**\n * @param camera Camera providing origin and scaling for transformations.\n */\n constructor(private camera: ICamera) {}\n\n /**\n * Convert a world grid coordinate to screen pixels, accounting for camera offset and scale.\n * @param worldX Grid X in world space (tile index).\n * @param worldY Grid Y in world space (tile index).\n * @returns Screen-space coordinates in pixels. e.g., (e.g. `{ x: 100.5, y: 200.5 }`).\n */\n worldToScreen(worldX: number, worldY: number): Coords {\n return worldToScreen(\n { x: worldX, y: worldY },\n { x: this.camera.x, y: this.camera.y, scale: this.camera.scale }\n );\n }\n\n /**\n * Convert screen pixel coordinates back to world space grid coordinates.\n * @param screenX X coordinate in screen space (pixels).\n * @param screenY Y coordinate in screen space (pixels).\n * @returns World-space grid coordinates. (e.g. `{ x: 10, y: 20 }`).\n */\n screenToWorld(screenX: number, screenY: number): Coords {\n return screenToWorld(\n { x: screenX, y: screenY },\n { x: this.camera.x, y: this.camera.y, scale: this.camera.scale }\n );\n }\n}\n","/**\n * Spatial indexing wrapper using RBush (R-Tree) for fast viewport queries\n * @internal\n */\n\nimport RBush from \"rbush\";\n\nexport interface SpatialItem {\n x: number;\n y: number;\n /**\n * Optional world-space size (width/height). Defaults to 0 for point-like items.\n */\n size?: number;\n}\n\ninterface RBushItem<T> {\n minX: number;\n minY: number;\n maxX: number;\n maxY: number;\n item: T;\n}\n\nexport class SpatialIndex<T extends SpatialItem> {\n private tree: RBush<RBushItem<T>>;\n\n constructor() {\n this.tree = new RBush();\n }\n\n /**\n * Bulk load items into the R-Tree (much faster than individual inserts)\n */\n load(items: T[]): void {\n const rbushItems: RBushItem<T>[] = items.map((item) => {\n const size = typeof item.size === \"number\" ? item.size : 0;\n const half = size / 2;\n\n return {\n minX: item.x - half,\n minY: item.y - half,\n maxX: item.x + half,\n maxY: item.y + half,\n item,\n };\n });\n this.tree.load(rbushItems);\n }\n\n /**\n * Query all items within a rectangular range\n */\n query(minX: number, minY: number, maxX: number, maxY: number): T[] {\n const results = this.tree.search({ minX, minY, maxX, maxY });\n return results.map((r) => r.item);\n }\n\n /**\n * Clear all items\n */\n clear(): void {\n this.tree.clear();\n }\n\n /**\n * Create SpatialIndex from array of items\n */\n static fromArray<T extends SpatialItem>(items: T[]): SpatialIndex<T> {\n const index = new SpatialIndex<T>();\n index.load(items);\n return index;\n }\n}\n","import { Coords, CanvasTileEngineConfig, Rect, Circle, Text, Path, ImageItem } from \"../types\";\nimport { ICamera } from \"./Camera\";\nimport { CoordinateTransformer } from \"./CoordinateTransformer\";\nimport { Layer, type LayerHandle } from \"./Layer\";\nimport { DEFAULT_VALUES, VISIBILITY_BUFFER } from \"../constants\";\nimport { SpatialIndex } from \"./SpatialIndex\";\n\n// Threshold for using spatial indexing (below this, linear scan is faster)\nconst SPATIAL_INDEX_THRESHOLD = 500;\n// Conservative max dimension for offscreen static cache (browser limits often 16384 or 32767)\nconst MAX_STATIC_CANVAS_DIMENSION = 16384;\n\n// Cache for static layers (pre-rendered offscreen canvases)\ninterface StaticCache {\n canvas: OffscreenCanvas | HTMLCanvasElement;\n ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D;\n worldBounds: { minX: number; minY: number; maxX: number; maxY: number };\n scale: number;\n}\n\n/**\n * Canvas-specific helpers for adding draw callbacks to the layer stack.\n * @internal\n */\nexport class CanvasDraw {\n private staticCaches = new Map<string, StaticCache>();\n private staticCacheSupported: boolean;\n private warnedStaticCacheDisabled = false;\n\n constructor(private layers: Layer, private transformer: CoordinateTransformer, private camera: ICamera) {\n this.staticCacheSupported = typeof OffscreenCanvas !== \"undefined\" || typeof document !== \"undefined\";\n }\n\n /**\n * Register a generic draw callback; receives raw context, current coords, and config.\n * @param fn Callback invoked during render.\n * @param layer Layer order (lower draws first).\n */\n\n private isVisible(\n x: number,\n y: number,\n sizeWorld: number,\n topLeft: Coords,\n config: Required<CanvasTileEngineConfig>\n ) {\n const viewW = config.size.width / config.scale;\n const viewH = config.size.height / config.scale;\n const minX = topLeft.x - VISIBILITY_BUFFER.TILE_BUFFER;\n const minY = topLeft.y - VISIBILITY_BUFFER.TILE_BUFFER;\n const maxX = topLeft.x + viewW + VISIBILITY_BUFFER.TILE_BUFFER;\n const maxY = topLeft.y + viewH + VISIBILITY_BUFFER.TILE_BUFFER;\n return x + sizeWorld >= minX && x - sizeWorld <= maxX && y + sizeWorld >= minY && y - sizeWorld <= maxY;\n }\n\n private getViewportBounds(topLeft: Coords, config: Required<CanvasTileEngineConfig>) {\n const viewW = config.size.width / config.scale;\n const viewH = config.size.height / config.scale;\n return {\n minX: topLeft.x - VISIBILITY_BUFFER.TILE_BUFFER,\n minY: topLeft.y - VISIBILITY_BUFFER.TILE_BUFFER,\n maxX: topLeft.x + viewW + VISIBILITY_BUFFER.TILE_BUFFER,\n maxY: topLeft.y + viewH + VISIBILITY_BUFFER.TILE_BUFFER,\n };\n }\n\n addDrawFunction(\n fn: (ctx: CanvasRenderingContext2D, coords: Coords, config: Required<CanvasTileEngineConfig>) => void,\n layer: number = 1\n ): LayerHandle {\n return this.layers.add(layer, ({ ctx, config, topLeft }) => {\n fn(ctx, topLeft, config);\n });\n }\n\n drawRect(items: Array<Rect> | Rect, layer: number = 1): LayerHandle {\n const list = Array.isArray(items) ? items : [items];\n\n // Build spatial index for large datasets (RBush R-Tree)\n const useSpatialIndex = list.length > SPATIAL_INDEX_THRESHOLD;\n const spatialIndex = useSpatialIndex ? SpatialIndex.fromArray(list) : null;\n\n return this.layers.add(layer, ({ ctx, config, topLeft }) => {\n const bounds = this.getViewportBounds(topLeft, config);\n const visibleItems = spatialIndex\n ? spatialIndex.query(bounds.minX, bounds.minY, bounds.maxX, bounds.maxY)\n : list;\n\n ctx.save();\n let lastFillStyle: string | undefined;\n let lastStrokeStyle: string | undefined;\n let lastLineWidth: number | undefined;\n\n for (const item of visibleItems) {\n const size = item.size ?? 1;\n const origin = {\n mode: item.origin?.mode === \"self\" ? \"self\" : (\"cell\" as \"cell\" | \"self\"),\n x: item.origin?.x ?? 0.5,\n y: item.origin?.y ?? 0.5,\n };\n const style = item.style;\n\n // Skip visibility check if using spatial index (already filtered)\n if (!spatialIndex && !this.isVisible(item.x, item.y, size / 2, topLeft, config)) continue;\n\n const pos = this.transformer.worldToScreen(item.x, item.y);\n const pxSize = size * this.camera.scale;\n const { x: drawX, y: drawY } = this.computeOriginOffset(pos, pxSize, origin, this.camera);\n\n // Only update style when changed (reduces state changes)\n if (style?.fillStyle && style.fillStyle !== lastFillStyle) {\n ctx.fillStyle = style.fillStyle;\n lastFillStyle = style.fillStyle;\n }\n if (style?.strokeStyle && style.strokeStyle !== lastStrokeStyle) {\n ctx.strokeStyle = style.strokeStyle;\n lastStrokeStyle = style.strokeStyle;\n }\n if (style?.lineWidth && style.lineWidth !== lastLineWidth) {\n ctx.lineWidth = style.lineWidth;\n lastLineWidth = style.lineWidth;\n }\n\n const rotationDeg = item.rotate ?? 0;\n const rotation = rotationDeg * (Math.PI / 180);\n\n const radius = item.radius;\n\n if (rotationDeg !== 0) {\n const centerX = drawX + pxSize / 2;\n const centerY = drawY + pxSize / 2;\n ctx.save();\n ctx.translate(centerX, centerY);\n ctx.rotate(rotation);\n ctx.beginPath();\n if (radius && ctx.roundRect) {\n ctx.roundRect(-pxSize / 2, -pxSize / 2, pxSize, pxSize, radius);\n } else {\n ctx.rect(-pxSize / 2, -pxSize / 2, pxSize, pxSize);\n }\n if (style?.fillStyle) ctx.fill();\n if (style?.strokeStyle) ctx.stroke();\n ctx.restore();\n } else {\n ctx.beginPath();\n if (radius && ctx.roundRect) {\n ctx.roundRect(drawX, drawY, pxSize, pxSize, radius);\n } else {\n ctx.rect(drawX, drawY, pxSize, pxSize);\n }\n if (style?.fillStyle) ctx.fill();\n if (style?.strokeStyle) ctx.stroke();\n }\n }\n ctx.restore();\n });\n }\n\n drawLine(\n items: Array<{ from: Coords; to: Coords }> | { from: Coords; to: Coords },\n style?: { strokeStyle?: string; lineWidth?: number },\n layer: number = 1\n ): LayerHandle {\n const list = Array.isArray(items) ? items : [items];\n\n return this.layers.add(layer, ({ ctx, config, topLeft }) => {\n ctx.save();\n if (style?.strokeStyle) ctx.strokeStyle = style.strokeStyle;\n if (style?.lineWidth) ctx.lineWidth = style.lineWidth;\n\n ctx.beginPath();\n for (const item of list) {\n const centerX = (item.from.x + item.to.x) / 2;\n const centerY = (item.from.y + item.to.y) / 2;\n const halfExtent = Math.max(Math.abs(item.from.x - item.to.x), Math.abs(item.from.y - item.to.y)) / 2;\n if (!this.isVisible(centerX, centerY, halfExtent, topLeft, config)) continue;\n\n const a = this.transformer.worldToScreen(item.from.x, item.from.y);\n const b = this.transformer.worldToScreen(item.to.x, item.to.y);\n\n ctx.moveTo(a.x, a.y);\n ctx.lineTo(b.x, b.y);\n }\n ctx.stroke();\n ctx.restore();\n });\n }\n\n drawCircle(items: Array<Circle> | Circle, layer: number = 1): LayerHandle {\n const list = Array.isArray(items) ? items : [items];\n\n // Build spatial index for large datasets (RBush R-Tree)\n const useSpatialIndex = list.length > SPATIAL_INDEX_THRESHOLD;\n const spatialIndex = useSpatialIndex ? SpatialIndex.fromArray(list) : null;\n\n return this.layers.add(layer, ({ ctx, config, topLeft }) => {\n const bounds = this.getViewportBounds(topLeft, config);\n const visibleItems = spatialIndex\n ? spatialIndex.query(bounds.minX, bounds.minY, bounds.maxX, bounds.maxY)\n : list;\n\n ctx.save();\n let lastFillStyle: string | undefined;\n let lastStrokeStyle: string | undefined;\n let lastLineWidth: number | undefined;\n\n for (const item of visibleItems) {\n const size = item.size ?? 1;\n const origin = {\n mode: item.origin?.mode === \"self\" ? \"self\" : (\"cell\" as \"cell\" | \"self\"),\n x: item.origin?.x ?? 0.5,\n y: item.origin?.y ?? 0.5,\n };\n const style = item.style;\n\n // Skip visibility check if using spatial index (already filtered)\n if (!spatialIndex && !this.isVisible(item.x, item.y, size / 2, topLeft, config)) continue;\n\n const pos = this.transformer.worldToScreen(item.x, item.y);\n const pxSize = size * this.camera.scale;\n const radius = pxSize / 2;\n const { x: drawX, y: drawY } = this.computeOriginOffset(pos, pxSize, origin, this.camera);\n\n // Only update style when changed\n if (style?.fillStyle && style.fillStyle !== lastFillStyle) {\n ctx.fillStyle = style.fillStyle;\n lastFillStyle = style.fillStyle;\n }\n if (style?.strokeStyle && style.strokeStyle !== lastStrokeStyle) {\n ctx.strokeStyle = style.strokeStyle;\n lastStrokeStyle = style.strokeStyle;\n }\n if (style?.lineWidth && style.lineWidth !== lastLineWidth) {\n ctx.lineWidth = style.lineWidth;\n lastLineWidth = style.lineWidth;\n }\n\n ctx.beginPath();\n ctx.arc(drawX + radius, drawY + radius, radius, 0, Math.PI * 2);\n if (style?.fillStyle) ctx.fill();\n if (style?.strokeStyle) ctx.stroke();\n }\n ctx.restore();\n });\n }\n\n drawText(\n items: Array<Text> | Text,\n style?: { fillStyle?: string; font?: string; textAlign?: CanvasTextAlign; textBaseline?: CanvasTextBaseline },\n layer: number = 2\n ): LayerHandle {\n const list = Array.isArray(items) ? items : [items];\n\n return this.layers.add(layer, ({ ctx, config, topLeft }) => {\n ctx.save();\n if (style?.font) ctx.font = style.font;\n if (style?.fillStyle) ctx.fillStyle = style.fillStyle;\n ctx.textAlign = style?.textAlign ?? \"center\";\n ctx.textBaseline = style?.textBaseline ?? \"middle\";\n\n for (const item of list) {\n if (!this.isVisible(item.coords.x, item.coords.y, 0, topLeft, config)) continue;\n const pos = this.transformer.worldToScreen(item.coords.x, item.coords.y);\n ctx.fillText(item.text, pos.x, pos.y);\n }\n ctx.restore();\n });\n }\n\n drawPath(\n items: Array<Path> | Path,\n style?: { strokeStyle?: string; lineWidth?: number },\n layer: number = 1\n ): LayerHandle {\n const list = Array.isArray(items[0]) ? (items as Array<Coords[]>) : [items as Coords[]];\n\n return this.layers.add(layer, ({ ctx, config, topLeft }) => {\n ctx.save();\n if (style?.strokeStyle) ctx.strokeStyle = style.strokeStyle;\n if (style?.lineWidth) ctx.lineWidth = style.lineWidth;\n\n ctx.beginPath();\n for (const points of list) {\n if (!points.length) continue;\n const xs = points.map((p) => p.x);\n const ys = points.map((p) => p.y);\n const minX = Math.min(...xs);\n const maxX = Math.max(...xs);\n const minY = Math.min(...ys);\n const maxY = Math.max(...ys);\n const centerX = (minX + maxX) / 2;\n const centerY = (minY + maxY) / 2;\n const halfExtent = Math.max(maxX - minX, maxY - minY) / 2;\n if (!this.isVisible(centerX, centerY, halfExtent, topLeft, config)) continue;\n\n const first = this.transformer.worldToScreen(points[0].x, points[0].y);\n ctx.moveTo(first.x, first.y);\n\n for (let i = 1; i < points.length; i++) {\n const p = this.transformer.worldToScreen(points[i].x, points[i].y);\n ctx.lineTo(p.x, p.y);\n }\n }\n ctx.stroke();\n ctx.restore();\n });\n }\n\n drawImage(items: Array<ImageItem> | ImageItem, layer: number = 1): LayerHandle {\n const list = Array.isArray(items) ? items : [items];\n\n // Build spatial index for large datasets (RBush R-Tree)\n const useSpatialIndex = list.length > SPATIAL_INDEX_THRESHOLD;\n const spatialIndex = useSpatialIndex ? SpatialIndex.fromArray(list) : null;\n\n return this.layers.add(layer, ({ ctx, config, topLeft }) => {\n const bounds = this.getViewportBounds(topLeft, config);\n const visibleItems = spatialIndex\n ? spatialIndex.query(bounds.minX, bounds.minY, bounds.maxX, bounds.maxY)\n : list;\n\n for (const item of visibleItems) {\n const size = item.size ?? 1;\n const origin = {\n mode: item.origin?.mode === \"self\" ? \"self\" : (\"cell\" as \"cell\" | \"self\"),\n x: item.origin?.x ?? 0.5,\n y: item.origin?.y ?? 0.5,\n };\n\n // Skip visibility check if using spatial index (already filtered)\n if (!spatialIndex && !this.isVisible(item.x, item.y, size / 2, topLeft, config)) continue;\n\n const pos = this.transformer.worldToScreen(item.x, item.y);\n const pxSize = size * this.camera.scale;\n\n // preserve aspect\n const aspect = item.img.width / item.img.height;\n\n let drawW = pxSize;\n let drawH = pxSize;\n\n if (aspect > 1) drawH = pxSize / aspect;\n else drawW = pxSize * aspect;\n\n // origin SELF/CELL\n const { x: baseX, y: baseY } = this.computeOriginOffset(pos, pxSize, origin, this.camera);\n\n const offsetX = baseX + (pxSize - drawW) / 2;\n const offsetY = baseY + (pxSize - drawH) / 2;\n\n const rotationDeg = item.rotate ?? 0;\n const rotation = rotationDeg * (Math.PI / 180);\n\n if (rotationDeg !== 0) {\n const centerX = offsetX + drawW / 2;\n const centerY = offsetY + drawH / 2;\n ctx.save();\n ctx.translate(centerX, centerY);\n ctx.rotate(rotation);\n ctx.drawImage(item.img, -drawW / 2, -drawH / 2, drawW, drawH);\n ctx.restore();\n } else {\n ctx.drawImage(item.img, offsetX, offsetY, drawW, drawH);\n }\n }\n });\n }\n\n drawGridLines(cellSize: number, style: { strokeStyle: string; lineWidth: number }, layer: number = 0): LayerHandle {\n return this.layers.add(layer, ({ ctx, config, topLeft }) => {\n const viewW = config.size.width / config.scale;\n const viewH = config.size.height / config.scale;\n\n const startX = Math.floor(topLeft.x / cellSize) * cellSize - DEFAULT_VALUES.CELL_CENTER_OFFSET;\n const endX = Math.ceil((topLeft.x + viewW) / cellSize) * cellSize - DEFAULT_VALUES.CELL_CENTER_OFFSET;\n const startY = Math.floor(topLeft.y / cellSize) * cellSize - DEFAULT_VALUES.CELL_CENTER_OFFSET;\n const endY = Math.ceil((topLeft.y + viewH) / cellSize) * cellSize - DEFAULT_VALUES.CELL_CENTER_OFFSET;\n\n ctx.save();\n\n ctx.strokeStyle = style.strokeStyle;\n ctx.lineWidth = style.lineWidth;\n\n ctx.beginPath();\n\n for (let x = startX; x <= endX; x += cellSize) {\n const p1 = this.transformer.worldToScreen(x, startY);\n const p2 = this.transformer.worldToScreen(x, endY);\n ctx.moveTo(p1.x, p1.y);\n ctx.lineTo(p2.x, p2.y);\n }\n\n for (let y = startY; y <= endY; y += cellSize) {\n const p1 = this.transformer.worldToScreen(startX, y);\n const p2 = this.transformer.worldToScreen(endX, y);\n ctx.moveTo(p1.x, p1.y);\n ctx.lineTo(p2.x, p2.y);\n }\n\n ctx.stroke();\n ctx.restore();\n });\n }\n\n private computeOriginOffset(\n pos: Coords,\n pxSize: number,\n origin: { mode: \"cell\" | \"self\"; x: number; y: number },\n camera: ICamera\n ) {\n if (origin.mode === \"cell\") {\n const cell = camera.scale;\n return {\n x: pos.x - cell / 2 + origin.x * cell - pxSize / 2,\n y: pos.y - cell / 2 + origin.y * cell - pxSize / 2,\n };\n }\n\n return {\n x: pos.x - origin.x * pxSize,\n y: pos.y - origin.y * pxSize,\n };\n }\n\n /**\n * Helper to create or get a static cache for pre-rendered content.\n * Handles bounds calculation, canvas creation, and rebuild logic.\n */\n private getOrCreateStaticCache<T extends { x: number; y: number; size?: number; radius?: number | number[] }>(\n items: T[],\n cacheKey: string,\n renderFn: (\n ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,\n item: T,\n x: number,\n y: number,\n pxSize: number\n ) => void\n ): StaticCache | null {\n if (!this.staticCacheSupported) {\n if (!this.warnedStaticCacheDisabled) {\n console.warn(\"[CanvasDraw] Static cache disabled: OffscreenCanvas not available.\");\n this.warnedStaticCacheDisabled = true;\n }\n return null;\n }\n\n // Calculate world bounds from items\n let minX = Infinity,\n maxX = -Infinity,\n minY = Infinity,\n maxY = -Infinity;\n\n for (const item of items) {\n const size = item.size ?? 1;\n if (item.x - size / 2 < minX) minX = item.x - size / 2;\n if (item.x + size / 2 > maxX) maxX = item.x + size / 2;\n if (item.y - size / 2 < minY) minY = item.y - size / 2;\n if (item.y + size / 2 > maxY) maxY = item.y + size / 2;\n }\n\n // Add padding\n minX -= 1;\n minY -= 1;\n maxX += 1;\n maxY += 1;\n\n const worldWidth = maxX - minX;\n const worldHeight = maxY - minY;\n\n // Use current scale for rendering\n const renderScale = this.camera.scale;\n const canvasWidth = Math.ceil(worldWidth * renderScale);\n const canvasHeight = Math.ceil(worldHeight * renderScale);\n\n if (canvasWidth > MAX_STATIC_CANVAS_DIMENSION || canvasHeight > MAX_STATIC_CANVAS_DIMENSION) {\n if (!this.warnedStaticCacheDisabled) {\n console.warn(`Static cache disabled: offscreen canvas too large (${canvasWidth}x${canvasHeight}).`);\n this.warnedStaticCacheDisabled = true;\n }\n return null;\n }\n\n // Check if we need to create or update cache\n let cache = this.staticCaches.get(cacheKey);\n const needsRebuild =\n !cache ||\n cache.scale !== renderScale ||\n cache.worldBounds.minX !== minX ||\n cache.worldBounds.maxX !== maxX ||\n cache.worldBounds.minY !== minY ||\n cache.worldBounds.maxY !== maxY;\n\n if (needsRebuild) {\n // Create offscreen canvas\n const offscreen =\n typeof OffscreenCanvas !== \"undefined\"\n ? new OffscreenCanvas(canvasWidth, canvasHeight)\n : document.createElement(\"canvas\");\n\n // Guard instanceof with typeof to avoid ReferenceError when OffscreenCanvas is undefined (e.g., jsdom)\n const isOffscreenCanvas = typeof OffscreenCanvas !== \"undefined\" && offscreen instanceof OffscreenCanvas;\n\n if (!isOffscreenCanvas) {\n (offscreen as HTMLCanvasElement).width = canvasWidth;\n (offscreen as HTMLCanvasElement).height = canvasHeight;\n }\n\n const offCtx = offscreen.getContext(\"2d\");\n\n if (!offCtx) {\n if (!this.warnedStaticCacheDisabled) {\n console.warn(\"[CanvasDraw] Static cache disabled: 2D context unavailable.\");\n this.warnedStaticCacheDisabled = true;\n }\n return null;\n }\n\n // Render all items using the provided render function\n for (const item of items) {\n const size = item.size ?? 1;\n const pxSize = size * renderScale;\n const x = (item.x + DEFAULT_VALUES.CELL_CENTER_OFFSET - minX) * renderScale - pxSize / 2;\n const y = (item.y + DEFAULT_VALUES.CELL_CENTER_OFFSET - minY) * renderScale - pxSize / 2;\n\n renderFn(offCtx, item, x, y, pxSize);\n }\n\n cache = {\n canvas: offscreen,\n ctx: offCtx,\n worldBounds: { minX, minY, maxX, maxY },\n scale: renderScale,\n };\n\n this.staticCaches.set(cacheKey, cache);\n }\n\n return cache || null;\n }\n\n /**\n * Helper to add a layer callback that blits from a static cache.\n */\n private addStaticCacheLayer(cache: StaticCache | null, layer: number): LayerHandle | null {\n if (!cache) {\n return null;\n }\n const cachedCanvas = cache.canvas;\n const cachedBounds = cache.worldBounds;\n const cachedScale = cache.scale;\n\n return this.layers.add(layer, ({ ctx, config, topLeft }) => {\n const viewW = config.size.width / config.scale;\n const viewH = config.size.height / config.scale;\n\n // Source rect in cached canvas (what part of cache to draw)\n const srcX = (topLeft.x - cachedBounds.minX) * cachedScale;\n const srcY = (topLeft.y - cachedBounds.minY) * cachedScale;\n const srcW = viewW * cachedScale;\n const srcH = viewH * cachedScale;\n\n // Destination on screen\n ctx.drawImage(cachedCanvas, srcX, srcY, srcW, srcH, 0, 0, config.size.width, config.size.height);\n });\n }\n\n /**\n * Draw rectangles with pre-rendering cache.\n * Renders all items once to an offscreen canvas, then blits the visible portion each frame.\n * Ideal for large static datasets like mini-maps.\n * @param items Array of draw objects\n * @param cacheKey Unique key for this cache (e.g., \"minimap-items\")\n * @param layer Layer order\n */\n drawStaticRect(items: Array<Rect>, cacheKey: string, layer: number = 1): LayerHandle {\n let lastFillStyle: string | undefined;\n\n const cache = this.getOrCreateStaticCache(items, cacheKey, (ctx, item, x, y, pxSize) => {\n const style = item.style;\n const rotationDeg = item.rotate ?? 0;\n const rotation = rotationDeg * (Math.PI / 180);\n const radius = item.radius;\n\n if (style?.fillStyle && style.fillStyle !== lastFillStyle) {\n ctx.fillStyle = style.fillStyle;\n lastFillStyle = style.fillStyle;\n }\n\n if (rotationDeg !== 0) {\n const centerX = x + pxSize / 2;\n const centerY = y + pxSize / 2;\n ctx.save();\n ctx.translate(centerX, centerY);\n ctx.rotate(rotation);\n if (radius && ctx.roundRect) {\n ctx.beginPath();\n ctx.roundRect(-pxSize / 2, -pxSize / 2, pxSize, pxSize, radius);\n ctx.fill();\n } else {\n ctx.fillRect(-pxSize / 2, -pxSize / 2, pxSize, pxSize);\n }\n ctx.restore();\n } else {\n if (radius && ctx.roundRect) {\n ctx.beginPath();\n ctx.roundRect(x, y, pxSize, pxSize, radius);\n ctx.fill();\n } else {\n ctx.fillRect(x, y, pxSize, pxSize);\n }\n }\n });\n\n if (!cache) {\n return this.drawRect(items, layer);\n }\n\n return this.addStaticCacheLayer(cache, layer)!;\n }\n\n /**\n * Draw images with pre-rendering cache.\n * Renders all items once to an offscreen canvas, then blits the visible portion each frame.\n * Ideal for large static datasets like terrain tiles or static decorations.\n * @param items Array of image objects with position and HTMLImageElement\n * @param cacheKey Unique key for this cache (e.g., \"terrain-cache\")\n * @param layer Layer order\n */\n drawStaticImage(items: Array<ImageItem>, cacheKey: string, layer: number = 1): LayerHandle {\n const cache = this.getOrCreateStaticCache(items, cacheKey, (ctx, item, x, y, pxSize) => {\n const img = (item as { img: HTMLImageElement }).img;\n const rotationDeg = (item as { rotate?: number }).rotate ?? 0;\n const rotation = rotationDeg * (Math.PI / 180);\n const aspect = img.width / img.height;\n let drawW = pxSize;\n let drawH = pxSize;\n\n if (aspect > 1) drawH = pxSize / aspect;\n else drawW = pxSize * aspect;\n\n // x, y are top-left of pxSize box, need to center image within it\n const imgX = x + (pxSize - drawW) / 2;\n const imgY = y + (pxSize - drawH) / 2;\n\n if (rotationDeg !== 0) {\n const centerX = imgX + drawW / 2;\n const centerY = imgY + drawH / 2;\n ctx.save();\n ctx.translate(centerX, centerY);\n ctx.rotate(rotation);\n ctx.drawImage(img, -drawW / 2, -drawH / 2, drawW, drawH);\n ctx.restore();\n } else {\n ctx.drawImage(img, imgX, imgY, drawW, drawH);\n }\n });\n\n if (!cache) {\n return this.drawImage(items, layer);\n }\n\n return this.addStaticCacheLayer(cache, layer)!;\n }\n\n /**\n * Draw circles with pre-rendering cache.\n * Renders all items once to an offscreen canvas, then blits the visible portion each frame.\n * Ideal for large static datasets like mini-maps.\n * @param items Array of draw objects\n * @param cacheKey Unique key for this cache (e.g., \"minimap-circles\")\n * @param layer Layer order\n */\n drawStaticCircle(items: Array<Circle>, cacheKey: string, layer: number = 1): LayerHandle {\n let lastFillStyle: string | undefined;\n\n const cache = this.getOrCreateStaticCache(items, cacheKey, (ctx, item, x, y, pxSize) => {\n const style = item.style;\n const radius = pxSize / 2;\n\n if (style?.fillStyle && style.fillStyle !== lastFillStyle) {\n ctx.fillStyle = style.fillStyle;\n lastFillStyle = style.fillStyle;\n }\n\n ctx.beginPath();\n ctx.arc(x + radius, y + radius, radius, 0, Math.PI * 2);\n ctx.fill();\n });\n\n if (!cache) {\n return this.drawCircle(items, layer);\n }\n\n return this.addStaticCacheLayer(cache, layer)!;\n }\n\n /**\n * Clear a static cache\n * @param cacheKey The cache key to clear, or undefined to clear all\n */\n clearStaticCache(cacheKey?: string) {\n if (cacheKey) {\n this.staticCaches.delete(cacheKey);\n } else {\n this.staticCaches.clear();\n }\n }\n\n /**\n * Release cached canvases and layer callbacks.\n */\n destroy() {\n this.staticCaches.clear();\n this.layers.clear();\n }\n}\n","type HandlerMap = {\n click?: (e: MouseEvent) => void;\n mousedown?: (e: MouseEvent) => void;\n mousemove?: (e: MouseEvent) => void;\n mouseup?: (e: MouseEvent) => void;\n mouseleave?: (e: MouseEvent) => void;\n wheel?: (e: WheelEvent) => void;\n touchstart?: (e: TouchEvent) => void;\n touchmove?: (e: TouchEvent) => void;\n touchend?: (e: TouchEvent) => void;\n};\n\n/**\n * Thin wrapper to attach/detach DOM event listeners on the canvas.\n * @internal\n */\nexport class EventBinder {\n constructor(private canvas: HTMLCanvasElement, private handlers: HandlerMap) {}\n\n attach() {\n if (this.handlers.click) {\n this.canvas.addEventListener(\"click\", this.handlers.click);\n }\n\n if (this.handlers.mousedown) {\n this.canvas.addEventListener(\"mousedown\", this.handlers.mousedown);\n }\n\n if (this.handlers.mousemove) {\n this.canvas.addEventListener(\"mousemove\", this.handlers.mousemove);\n }\n\n if (this.handlers.mouseup) {\n this.canvas.addEventListener(\"mouseup\", this.handlers.mouseup);\n }\n\n if (this.handlers.mouseleave) {\n this.canvas.addEventListener(\"mouseleave\", this.handlers.mouseleave);\n }\n\n if (this.handlers.wheel) {\n this.canvas.addEventListener(\"wheel\", this.handlers.wheel, { passive: false });\n }\n\n if (this.handlers.touchstart) {\n this.canvas.addEventListener(\"touchstart\", this.handlers.touchstart, { passive: false });\n }\n\n if (this.handlers.touchmove) {\n this.canvas.addEventListener(\"touchmove\", this.handlers.touchmove, { passive: false });\n }\n\n if (this.handlers.touchend) {\n this.canvas.addEventListener(\"touchend\", this.handlers.touchend, { passive: false });\n }\n }\n\n detach() {\n if (this.handlers.click) {\n this.canvas.removeEventListener(\"click\", this.handlers.click);\n }\n\n if (this.handlers.mousedown) {\n this.canvas.removeEventListener(\"mousedown\", this.handlers.mousedown);\n }\n\n if (this.handlers.mousemove) {\n this.canvas.removeEventListener(\"mousemove\", this.handlers.mousemove);\n }\n\n if (this.handlers.mouseup) {\n this.canvas.removeEventListener(\"mouseup\", this.handlers.mouseup);\n }\n\n if (this.handlers.mouseleave) {\n this.canvas.removeEventListener(\"mouseleave\", this.handlers.mouseleave);\n }\n\n if (this.handlers.wheel) {\n this.canvas.removeEventListener(\"wheel\", this.handlers.wheel);\n }\n\n if (this.handlers.touchstart) {\n this.canvas.removeEventListener(\"touchstart\", this.handlers.touchstart);\n }\n\n if (this.handlers.touchmove) {\n this.canvas.removeEventListener(\"touchmove\", this.handlers.touchmove);\n }\n\n if (this.handlers.touchend) {\n this.canvas.removeEventListener(\"touchend\", this.handlers.touchend);\n }\n }\n}\n","import { onClickCallback, onHoverCallback } from \"../../types\";\nimport { ICamera } from \"../Camera\";\nimport { Config } from \"../Config\";\nimport { CoordinateTransformer } from \"../CoordinateTransformer\";\nimport { ViewportState } from \"../ViewportState\";\n\n/**\n * Handles gesture logic (click, hover, drag, zoom) independent of DOM binding.\n * @internal\n */\nexport class GestureController {\n private isDragging = false;\n private shouldPreventClick = false;\n private lastPos = { x: 0, y: 0 };\n\n // Pinch-to-zoom state\n private isPinching = false;\n private lastPinchDistance = 0;\n private lastPinchCenter = { x: 0, y: 0 };\n\n public onClick?: onClickCallback;\n public onHover?: onHoverCallback;\n public onMouseDown?: () => void;\n public onMouseUp?: () => void;\n public onMouseLeave?: () => void;\n\n constructor(\n private canvas: HTMLCanvasElement,\n private camera: ICamera,\n private viewport: ViewportState,\n private config: Config,\n private transformer: CoordinateTransformer,\n private onCameraChange: () => void\n ) {}\n\n handleClick = (e: MouseEvent) => {\n if (this.shouldPreventClick) {\n this.shouldPreventClick = false;\n return;\n }\n if (!this.config.get().eventHandlers.click || !this.onClick) {\n return;\n }\n const rect = this.canvas.getBoundingClientRect();\n const mouseX = e.clientX - rect.left;\n const mouseY = e.clientY - rect.top;\n const world = this.transformer.screenToWorld(mouseX, mouseY);\n const screen = this.transformer.worldToScreen(Math.floor(world.x), Math.floor(world.y));\n\n this.onClick(\n {\n raw: world,\n snapped: { x: Math.floor(world.x), y: Math.floor(world.y) },\n },\n {\n raw: { x: e.clientX - rect.left, y: e.clientY - rect.top },\n snapped: {\n x: screen.x,\n y: screen.y,\n },\n },\n {\n raw: { x: e.clientX, y: e.clientY },\n snapped: {\n x: screen.x + rect.left,\n y: screen.y + rect.top,\n },\n }\n );\n };\n\n handleMouseDown = (e: MouseEvent) => {\n if (this.onMouseDown) {\n this.onMouseDown();\n }\n\n if (!this.config.get().eventHandlers.drag) {\n return;\n }\n\n this.isDragging = true;\n this.shouldPreventClick = false;\n this.lastPos = { x: e.clientX, y: e.clientY };\n };\n\n handleMouseMove = (e: MouseEvent) => {\n if (!this.isDragging) {\n if (this.onHover && this.config.get().eventHandlers.hover) {\n const rect = this.canvas.getBoundingClientRect();\n const mouseX = e.clientX - rect.left;\n const mouseY = e.clientY - rect.top;\n const world = this.transformer.screenToWorld(mouseX, mouseY);\n const screen = this.transformer.worldToScreen(Math.floor(world.x), Math.floor(world.y));\n\n this.onHover(\n { raw: world, snapped: { x: Math.floor(world.x), y: Math.floor(world.y) } },\n {\n raw: { x: e.clientX - rect.left, y: e.clientY - rect.top },\n snapped: {\n x: screen.x,\n y: screen.y,\n },\n },\n {\n raw: { x: e.clientX, y: e.clientY },\n snapped: {\n x: screen.x + rect.left,\n y: screen.y + rect.top,\n },\n }\n );\n }\n return;\n }\n\n const dx = e.clientX - this.lastPos.x;\n const dy = e.clientY - this.lastPos.y;\n if (dx !== 0 || dy !== 0) {\n this.canvas.style.cursor = this.config.get().cursor.move || \"move\";\n this.shouldPreventClick = true;\n }\n this.camera.pan(dx, dy);\n this.lastPos = { x: e.clientX, y: e.clientY };\n this.onCameraChange();\n };\n\n handleMouseUp = () => {\n if (this.onMouseUp) {\n this.onMouseUp();\n }\n\n this.isDragging = false;\n this.canvas.style.cursor = this.config.get().cursor.default || \"default\";\n };\n\n handleMouseLeave = () => {\n if (this.onMouseLeave) {\n this.onMouseLeave();\n }\n\n this.isDragging = false;\n this.canvas.style.cursor = this.config.get().cursor.default || \"default\";\n };\n\n handleTouchStart = (e: TouchEvent) => {\n const eventHandlers = this.config.get().eventHandlers;\n\n // Handle pinch-to-zoom (2 fingers)\n if (e.touches.length === 2 && eventHandlers.zoom) {\n e.preventDefault();\n this.isPinching = true;\n this.isDragging = false;\n this.lastPinchDistance = this.getTouchDistance(e.touches);\n this.lastPinchCenter = this.getTouchCenter(e.touches);\n return;\n }\n\n // Handle single finger drag\n if (!eventHandlers.drag) return;\n if (e.touches.length !== 1) return;\n const t = e.touches[0];\n this.isDragging = true;\n this.isPinching = false;\n this.shouldPreventClick = false;\n this.lastPos = { x: t.clientX, y: t.clientY };\n };\n\n handleTouchMove = (e: TouchEvent) => {\n // Handle pinch-to-zoom\n if (this.isPinching && e.touches.length === 2) {\n e.preventDefault();\n\n const currentDistance = this.getTouchDistance(e.touches);\n const currentCenter = this.getTouchCenter(e.touches);\n const rect = this.canvas.getBoundingClientRect();\n\n // Calculate zoom factor from pinch distance change\n const scaleFactor = currentDistance / this.lastPinchDistance;\n\n // Get pinch center relative to canvas\n const centerX = currentCenter.x - rect.left;\n const centerY = currentCenter.y - rect.top;\n\n // Apply zoom\n this.camera.zoomByFactor(scaleFactor, centerX, centerY);\n\n // Also pan if pinch center moved\n const dx = currentCenter.x - this.lastPinchCenter.x;\n const dy = currentCenter.y - this.lastPinchCenter.y;\n if (dx !== 0 || dy !== 0) {\n this.camera.pan(dx, dy);\n }\n\n this.lastPinchDistance = currentDistance;\n this.lastPinchCenter = currentCenter;\n this.onCameraChange();\n return;\n }\n\n // Handle single finger drag\n if (!this.isDragging || e.touches.length !== 1) {\n return;\n }\n e.preventDefault();\n const t = e.touches[0];\n const dx = t.clientX - this.lastPos.x;\n const dy = t.clientY - this.lastPos.y;\n if (dx !== 0 || dy !== 0) {\n this.canvas.style.cursor = this.config.get().cursor.move || \"move\";\n this.shouldPreventClick = true;\n }\n this.camera.pan(dx, dy);\n this.lastPos = { x: t.clientX, y: t.clientY };\n this.onCameraChange();\n };\n\n handleTouchEnd = (e: TouchEvent) => {\n // If we still have 2 fingers, stay in pinch mode\n if (e.touches.length >= 2 && this.isPinching) {\n this.lastPinchDistance = this.getTouchDistance(e.touches);\n this.lastPinchCenter = this.getTouchCenter(e.touches);\n return;\n }\n\n // If we have 1 finger left after pinching, switch to drag mode\n if (e.touches.length === 1 && this.isPinching) {\n this.isPinching = false;\n if (this.config.get().eventHandlers.drag) {\n this.isDragging = true;\n const t = e.touches[0];\n this.lastPos = { x: t.clientX, y: t.clientY };\n }\n return;\n }\n\n // All fingers lifted\n this.isDragging = false;\n this.isPinching = false;\n this.canvas.style.cursor = this.config.get().cursor.default || \"default\";\n };\n\n /**\n * Calculate the distance between two touch points.\n */\n private getTouchDistance(touches: TouchList): number {\n const dx = touches[1].clientX - touches[0].clientX;\n const dy = touches[1].clientY - touches[0].clientY;\n return Math.sqrt(dx * dx + dy * dy);\n }\n\n /**\n * Calculate the center point between two touches.\n */\n private getTouchCenter(touches: TouchList): { x: number; y: number } {\n return {\n x: (touches[0].clientX + touches[1].clientX) / 2,\n y: (touches[0].clientY + touches[1].clientY) / 2,\n };\n }\n\n handleWheel = (e: WheelEvent) => {\n if (!this.config.get().eventHandlers.zoom) return;\n e.preventDefault();\n const rect = this.canvas.getBoundingClientRect();\n this.camera.zoom(e.clientX, e.clientY, e.deltaY, rect);\n this.onCameraChange();\n };\n}\n","import { Camera } from \"../Camera\";\nimport { Config } from \"../Config\";\nimport { ViewportState } from \"../ViewportState\";\n\n/**\n * Observes canvas resizing and keeps viewport/camera in sync.\n * @internal\n */\nexport class ResizeWatcher {\n private resizeObserver?: ResizeObserver;\n private handleWindowResize?: () => void;\n private currentDpr: number;\n\n public onResize?: () => void;\n\n constructor(\n private wrapper: HTMLDivElement,\n private canvas: HTMLCanvasElement,\n private viewport: ViewportState,\n private camera: Camera,\n private config: Config,\n private onCameraChange: () => void\n ) {\n this.currentDpr = this.viewport.dpr;\n }\n\n start() {\n // Ensure DPR is up to date before sizing\n this.viewport.updateDpr();\n this.currentDpr = this.viewport.dpr;\n\n const size = this.viewport.getSize();\n\n const configSize = this.config.get().size;\n\n const maxWidth = configSize?.maxWidth;\n const maxHeight = configSize?.maxHeight;\n\n const minWidth = configSize?.minWidth;\n const minHeight = configSize?.minHeight;\n\n size.width = this.clamp(size.width, minWidth, maxWidth);\n size.height = this.clamp(size.height, minHeight, maxHeight);\n\n Object.assign(this.wrapper.style, {\n resize: \"both\",\n overflow: \"hidden\",\n width: `${size.width}px`,\n height: `${size.height}px`,\n touchAction: \"none\",\n position: \"relative\",\n maxWidth: maxWidth ? `${maxWidth}px` : \"\",\n maxHeight: maxHeight ? `${maxHeight}px` : \"\",\n minWidth: minWidth ? `${minWidth}px` : \"\",\n minHeight: minHeight ? `${minHeight}px` : \"\",\n });\n\n this.resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const { width: rawW, height: rawH } = entry.contentRect;\n const width = this.clamp(rawW, minWidth, maxWidth);\n const height = this.clamp(rawH, minHeight, maxHeight);\n const prev = this.viewport.getSize();\n\n if (width === prev.width && height === prev.height) {\n // No effective size change after clamping\n continue;\n }\n\n const diffW = width - prev.width;\n const diffH = height - prev.height;\n const dpr = this.viewport.dpr;\n\n this.camera.adjustForResize(diffW, diffH);\n this.viewport.setSize(width, height);\n\n // Set canvas resolution (physical pixels for HiDPI)\n this.canvas.width = width * dpr;\n this.canvas.height = height * dpr;\n\n // Set CSS size (logical pixels)\n this.canvas.style.width = `${width}px`;\n this.canvas.style.height = `${height}px`;\n\n this.wrapper.style.width = `${width}px`;\n this.wrapper.style.height = `${height}px`;\n\n if (this.onResize) {\n this.onResize();\n }\n this.onCameraChange();\n }\n });\n\n this.resizeObserver.observe(this.wrapper);\n\n this.attachDprWatcher();\n }\n\n stop() {\n if (this.resizeObserver) {\n this.resizeObserver.unobserve(this.wrapper);\n this.resizeObserver.disconnect();\n }\n\n this.resizeObserver = undefined;\n\n if (this.handleWindowResize) {\n window.removeEventListener(\"resize\", this.handleWindowResize);\n this.handleWindowResize = undefined;\n }\n }\n\n private clamp(value: number, min?: number, max?: number) {\n let result = value;\n if (min !== undefined) result = Math.max(min, result);\n if (max !== undefined) result = Math.min(max, result);\n return result;\n }\n\n /**\n * Listen for devicePixelRatio changes (e.g., monitor switch) and rescale canvas.\n */\n private attachDprWatcher() {\n if (typeof window === \"undefined\") {\n return;\n }\n\n this.handleWindowResize = () => {\n const prevDpr = this.currentDpr;\n this.viewport.updateDpr();\n const nextDpr = this.viewport.dpr;\n\n if (nextDpr === prevDpr) {\n return;\n }\n\n this.currentDpr = nextDpr;\n const { width, height } = this.viewport.getSize();\n\n // Update canvas resolution for new DPR while keeping logical size\n this.canvas.width = width * nextDpr;\n this.canvas.height = height * nextDpr;\n this.canvas.style.width = `${width}px`;\n this.canvas.style.height = `${height}px`;\n\n if (this.onResize) {\n this.onResize();\n }\n\n this.onCameraChange();\n };\n\n window.addEventListener(\"resize\", this.handleWindowResize, { passive: true });\n }\n}\n","import { onClickCallback, onHoverCallback } from \"../../types\";\nimport { Camera, ICamera } from \"../Camera\";\nimport { Config } from \"../Config\";\nimport { CoordinateTransformer } from \"../CoordinateTransformer\";\nimport { ViewportState } from \"../ViewportState\";\nimport { EventBinder } from \"./EventBinder\";\nimport { GestureController } from \"./GestureController\";\nimport { ResizeWatcher } from \"./ResizeWatcher\";\n\n/**\n * Coordinates DOM binding, gesture handling, and resize observation.\n * @internal\n */\nexport class EventManager {\n private binder: EventBinder;\n private gestures: GestureController;\n private resizeWatcher?: ResizeWatcher;\n private attached = false;\n\n public onResize?: () => void;\n\n public get onClick(): onClickCallback | undefined {\n return this.gestures.onClick;\n }\n public set onClick(cb: onClickCallback | undefined) {\n this.gestures.onClick = cb;\n }\n\n public get onHover(): onHoverCallback | undefined {\n return this.gestures.onHover;\n }\n public set onHover(cb: onHoverCallback | undefined) {\n this.gestures.onHover = cb;\n }\n\n public get onMouseDown(): (() => void) | undefined {\n return this.gestures.onMouseDown;\n }\n public set onMouseDown(cb: (() => void) | undefined) {\n this.gestures.onMouseDown = cb;\n }\n\n public get onMouseUp(): (() => void) | undefined {\n return this.gestures.onMouseUp;\n }\n public set onMouseUp(cb: (() => void) | undefined) {\n this.gestures.onMouseUp = cb;\n }\n\n public get onMouseLeave(): (() => void) | undefined {\n return this.gestures.onMouseLeave;\n }\n public set onMouseLeave(cb: (() => void) | undefined) {\n this.gestures.onMouseLeave = cb;\n }\n\n constructor(\n private canvasWrapper: HTMLDivElement,\n private canvas: HTMLCanvasElement,\n private camera: ICamera,\n private viewport: ViewportState,\n private config: Config,\n private coordinateTransformer: CoordinateTransformer,\n private onCameraChange: () => void\n ) {\n this.gestures = new GestureController(\n this.canvas,\n this.camera,\n this.viewport,\n this.config,\n this.coordinateTransformer,\n this.onCameraChange\n );\n\n this.binder = new EventBinder(this.canvas, {\n click: this.gestures.handleClick,\n mousedown: this.gestures.handleMouseDown,\n mousemove: this.gestures.handleMouseMove,\n mouseup: this.gestures.handleMouseUp,\n mouseleave: this.gestures.handleMouseLeave,\n wheel: this.gestures.handleWheel,\n touchstart: this.gestures.handleTouchStart,\n touchmove: this.gestures.handleTouchMove,\n touchend: this.gestures.handleTouchEnd,\n });\n }\n\n setupEvents() {\n if (this.attached) return;\n this.binder.attach();\n this.attached = true;\n if (this.config.get().eventHandlers.resize && this.camera instanceof Camera) {\n this.resizeWatcher = new ResizeWatcher(\n this.canvasWrapper,\n this.canvas,\n this.viewport,\n this.camera,\n this.config,\n this.onCameraChange\n );\n this.resizeWatcher.onResize = () => {\n if (this.onResize) {\n this.onResize();\n }\n };\n this.resizeWatcher.start();\n }\n }\n\n destroy() {\n if (!this.attached) return;\n this.binder.detach();\n this.resizeWatcher?.stop();\n this.resizeWatcher = undefined;\n this.attached = false;\n }\n}\n","import { DEFAULT_VALUES } from \"../constants\";\n\n/**\n * Simple image loader with in-memory caching to avoid duplicate network requests.\n */\nexport class ImageLoader {\n private cache = new Map<string, HTMLImageElement>();\n private inflight = new Map<string, Promise<HTMLImageElement>>();\n private listeners = new Set<() => void>();\n\n /**\n * Register a callback fired when a new image finishes loading.\n */\n onLoad(cb: () => void) {\n this.listeners.add(cb);\n return () => this.listeners.delete(cb);\n }\n\n private notifyLoaded() {\n for (const cb of this.listeners) {\n cb();\n }\n }\n\n /**\n * Load an image, reusing cache when possible.\n * @param src Image URL.\n * @param retry How many times to retry on error (default: 1).\n * @returns Promise resolving to the loaded image element.\n */\n async load(src: string, retry: number = DEFAULT_VALUES.IMAGE_LOAD_RETRY_COUNT): Promise<HTMLImageElement> {\n // Cached\n if (this.cache.has(src)) {\n return this.cache.get(src)!;\n }\n\n // Inflight\n if (this.inflight.has(src)) {\n return this.inflight.get(src)!;\n }\n\n const task = new Promise<HTMLImageElement>((resolve, reject) => {\n const img = new Image();\n img.crossOrigin = \"anonymous\";\n img.decoding = \"async\";\n img.loading = \"eager\";\n\n img.onload = async () => {\n try {\n // Wait for decode to finish if supported\n if (\"decode\" in img) {\n await (img as HTMLImageElement & { decode?: () => Promise<void> }).decode?.();\n }\n } catch {\n // ignore decode errors; draw will still attempt\n }\n\n this.cache.set(src, img);\n this.inflight.delete(src);\n this.notifyLoaded();\n resolve(img);\n };\n\n img.onerror = (err) => {\n this.inflight.delete(src);\n if (retry > 0) {\n console.warn(`Retrying image: ${src}`);\n resolve(this.load(src, retry - 1));\n } else {\n console.error(`Image failed to load: ${src}`, err);\n const reason =\n err instanceof Error ? err.message : typeof err === \"string\" ? err : JSON.stringify(err);\n reject(new Error(`Image failed to load: ${src}. Reason: ${reason}`));\n }\n };\n\n img.src = src;\n });\n\n this.inflight.set(src, task);\n return task;\n }\n\n /**\n * Get a cached image without loading.\n * @param src Image URL key.\n */\n get(src: string): HTMLImageElement | undefined {\n return this.cache.get(src);\n }\n\n /**\n * Check if an image is already cached.\n * @param src Image URL key.\n */\n has(src: string): boolean {\n return this.cache.has(src);\n }\n\n /**\n * Clear all cached and inflight images/listeners to free memory.\n */\n clear() {\n this.cache.clear();\n this.inflight.clear();\n this.listeners.clear();\n }\n}\n","import { Coords, CanvasTileEngineConfig } from \"../types\";\nimport type { ICamera } from \"./Camera\";\nimport type { CoordinateTransformer } from \"./CoordinateTransformer\";\n\n/** @internal */\nexport type DrawContext = {\n ctx: CanvasRenderingContext2D;\n camera: ICamera;\n transformer: CoordinateTransformer;\n config: Required<CanvasTileEngineConfig>;\n topLeft: Coords;\n};\n\n/** @internal */\nexport type DrawCallback = (dc: DrawContext) => void;\n\nexport interface LayerHandle {\n layer: number;\n id: symbol;\n}\n\n/**\n * Manages ordered draw callbacks for canvas rendering.\n * @internal\n */\nexport class Layer {\n private layers = new Map<number, { id: symbol; fn: DrawCallback }[]>();\n\n /**\n * Register a draw callback at a specific layer index.\n * @param layer Layer order; lower numbers draw first.\n * @param fn Callback receiving drawing context.\n */\n add(layer: number, fn: DrawCallback): LayerHandle {\n const id = Symbol(\"layer-callback\");\n const entry = { id, fn };\n if (!this.layers.has(layer)) this.layers.set(layer, []);\n this.layers.get(layer)!.push(entry);\n return { layer, id };\n }\n\n /**\n * Remove a previously registered callback.\n * Safe to call multiple times; no-op if not found.\n */\n remove(handle: LayerHandle) {\n const list = this.layers.get(handle.layer);\n if (!list) return;\n this.layers.set(\n handle.layer,\n list.filter((entry) => entry.id !== handle.id)\n );\n }\n\n /**\n * Clear callbacks for a layer or all layers.\n * @param layer Layer to clear; clears all when omitted.\n */\n clear(layer?: number) {\n if (layer === undefined) {\n this.layers.clear();\n return;\n }\n this.layers.set(layer, []);\n }\n\n /**\n * Draw all registered callbacks in layer order.\n * @param dc Drawing context shared with callbacks.\n */\n drawAll(dc: DrawContext) {\n const keys = [...this.layers.keys()].sort((a, b) => a - b);\n for (const layer of keys) {\n const fns = this.layers.get(layer);\n if (!fns) continue;\n for (const { fn } of fns) {\n dc.ctx.save();\n fn(dc);\n dc.ctx.restore();\n }\n }\n }\n}\n","/**\n * Holds mutable viewport size for runtime changes (resize, layout).\n * Also tracks device pixel ratio for HiDPI/Retina display support.\n * @internal\n */\nexport class ViewportState {\n private width: number;\n private height: number;\n private _dpr: number;\n\n constructor(width: number, height: number) {\n this.width = width;\n this.height = height;\n this._dpr = typeof window !== \"undefined\" ? window.devicePixelRatio || 1 : 1;\n }\n\n getSize() {\n return { width: this.width, height: this.height };\n }\n\n setSize(width: number, height: number) {\n this.width = width;\n this.height = height;\n }\n\n /**\n * Get the current device pixel ratio.\n * Used for HiDPI/Retina display rendering.\n */\n get dpr(): number {\n return this._dpr;\n }\n\n /**\n * Update DPR (useful when window moves between displays).\n */\n updateDpr() {\n this._dpr = typeof window !== \"undefined\" ? window.devicePixelRatio || 1 : 1;\n }\n}\n","import { Config } from \"./Config\";\nimport { ICamera } from \"./Camera\";\nimport { ViewportState } from \"./ViewportState\";\nimport { COORDINATE_OVERLAY } from \"../constants\";\n\n/**\n * Renders a coordinate overlay (axes and labels) on top of the canvas.\n * @internal\n */\nexport class CoordinateOverlayRenderer {\n private ctx: CanvasRenderingContext2D;\n private camera: ICamera;\n private config: Config;\n private viewport: ViewportState;\n\n /**\n * @param ctx Canvas context to draw on.\n * @param camera Active camera for position/scale.\n * @param config Normalized grid engine configuration store.\n * @param viewport Mutable viewport size store.\n */\n constructor(ctx: CanvasRenderingContext2D, camera: ICamera, config: Config, viewport: ViewportState) {\n this.ctx = ctx;\n this.camera = camera;\n this.config = config;\n this.viewport = viewport;\n }\n\n /**\n * Draw overlay borders and coordinate labels based on current camera view.\n */\n draw() {\n // Save the current canvas state\n this.ctx.save();\n\n // Set fill style to black with configured opacity\n this.ctx.fillStyle = `rgba(0, 0, 0, ${COORDINATE_OVERLAY.BORDER_OPACITY})`;\n\n // Draw left border - 20px wide, full height\n const { width, height } = this.viewport.getSize();\n this.ctx.fillRect(0, 0, COORDINATE_OVERLAY.BORDER_WIDTH, height);\n\n // Draw bottom border - full width, 20px high\n this.ctx.fillRect(\n COORDINATE_OVERLAY.BORDER_WIDTH,\n height - COORDINATE_OVERLAY.BORDER_WIDTH,\n width,\n COORDINATE_OVERLAY.BORDER_WIDTH\n );\n\n // Set text properties for coordinates\n this.ctx.fillStyle = `rgba(255, 255, 255, ${COORDINATE_OVERLAY.TEXT_OPACITY})`;\n\n // Adjust font size based on scale (min 8px, max 12px)\n const fontSize = Math.min(\n COORDINATE_OVERLAY.MAX_FONT_SIZE,\n Math.max(COORDINATE_OVERLAY.MIN_FONT_SIZE, this.camera.scale * COORDINATE_OVERLAY.FONT_SIZE_SCALE_FACTOR)\n );\n this.ctx.font = `${fontSize}px Arial`;\n this.ctx.textAlign = \"center\";\n this.ctx.textBaseline = \"middle\";\n\n const cordGap = this.camera.scale;\n const visibleAreaWidthInCords = width / cordGap;\n const visibleAreaHeightInCords = height / cordGap;\n\n // Draw Y coordinates (left side)\n for (let i = 0 - (this.camera.y % 1); i <= visibleAreaHeightInCords + 1; i++) {\n this.ctx.fillText(Math.round(this.camera.y + i).toString(), 10, cordGap * i + cordGap / 2);\n }\n\n // Draw X coordinates (bottom)\n for (let i = 0 - (this.camera.x % 1); i <= visibleAreaWidthInCords + 1; i++) {\n this.ctx.fillText(Math.round(this.camera.x + i).toString(), cordGap * i + cordGap / 2, height - 10);\n }\n\n // Restore the canvas state\n this.ctx.restore();\n }\n\n /**\n * Decide whether overlay should be drawn at current scale and config.\n * @param scale Current camera scale.\n * @param coordsConfig Coordinate overlay config.\n * @returns True if overlay is enabled and scale is within range.\n */\n shouldDraw(scale: number): boolean {\n const coordsConfig = this.config.get().coordinates;\n\n if (!coordsConfig.enabled) {\n return false;\n }\n\n if (!coordsConfig.shownScaleRange) {\n return false;\n }\n\n const { min, max } = coordsConfig.shownScaleRange;\n\n return scale >= min && scale <= max;\n }\n}\n","import { ICamera } from \"./Camera\";\nimport { Config } from \"./Config\";\nimport { CoordinateTransformer } from \"./CoordinateTransformer\";\nimport { ViewportState } from \"./ViewportState\";\nimport { DEBUG_HUD } from \"../constants\";\n\nconst FPS_SAMPLE_SIZE = 10;\n\n/**\n * Canvas-only debug overlay: draws grid and HUD information.\n * @internal\n */\nexport class CanvasDebug {\n private ctx: CanvasRenderingContext2D;\n private camera: ICamera;\n private transformer: CoordinateTransformer;\n private config: Config;\n private viewport: ViewportState;\n\n // FPS tracking (runs continuously via rAF)\n private frameTimes: number[] = [];\n private lastFrameTime = 0;\n private currentFps = 0;\n private fpsLoopRunning = false;\n private onFpsUpdate: (() => void) | null = null;\n\n constructor(\n ctx: CanvasRenderingContext2D,\n camera: ICamera,\n transformer: CoordinateTransformer,\n config: Config,\n viewport: ViewportState\n ) {\n this.ctx = ctx;\n this.camera = camera;\n this.transformer = transformer;\n this.config = config;\n this.viewport = viewport;\n }\n\n /**\n * Set callback for FPS updates (triggers re-render)\n */\n setFpsUpdateCallback(callback: () => void) {\n this.onFpsUpdate = callback;\n }\n\n /**\n * Start FPS monitoring loop\n */\n startFpsLoop() {\n if (this.fpsLoopRunning) return;\n this.fpsLoopRunning = true;\n this.lastFrameTime = performance.now();\n this.fpsLoop();\n }\n\n /**\n * Stop FPS monitoring loop\n */\n stopFpsLoop() {\n this.fpsLoopRunning = false;\n }\n\n private fpsLoop() {\n if (!this.fpsLoopRunning) return;\n\n const now = performance.now();\n const delta = now - this.lastFrameTime;\n this.lastFrameTime = now;\n\n this.frameTimes.push(delta);\n if (this.frameTimes.length > FPS_SAMPLE_SIZE) {\n this.frameTimes.shift();\n }\n\n const avgDelta = this.frameTimes.reduce((a, b) => a + b, 0) / this.frameTimes.length;\n const newFps = Math.round(1000 / avgDelta);\n\n // Only trigger update if FPS changed\n if (newFps !== this.currentFps) {\n this.currentFps = newFps;\n this.onFpsUpdate?.();\n }\n\n requestAnimationFrame(() => this.fpsLoop());\n }\n\n draw() {\n this.drawHud();\n }\n\n /**\n * Stop FPS tracking and release callbacks.\n */\n destroy() {\n this.stopFpsLoop();\n this.onFpsUpdate = null;\n }\n\n private drawHud() {\n const config = this.config.get();\n\n if (!config.debug.hud) {\n return;\n }\n\n if (!config.debug.hud.enabled) {\n return;\n }\n\n const datas = [];\n\n const topLeft = { x: this.camera.x, y: this.camera.y };\n\n if (config.debug.hud.topLeftCoordinates) {\n datas.push(`TopLeft: ${topLeft.x.toFixed(2)}, ${topLeft.y.toFixed(2)}`);\n }\n\n if (config.debug.hud.coordinates) {\n const { width, height } = this.viewport.getSize();\n const center = this.camera.getCenter(width, height);\n datas.push(`Coords: ${center.x.toFixed(2)}, ${center.y.toFixed(2)}`);\n }\n\n if (config.debug.hud.scale) {\n datas.push(`Scale: ${this.camera.scale.toFixed(2)}`);\n }\n\n if (config.debug.hud.tilesInView) {\n const { width, height } = this.viewport.getSize();\n datas.push(\n `Tiles in view: ${Math.ceil(width / this.camera.scale)} x ${Math.ceil(height / this.camera.scale)}`\n );\n }\n\n if (config.debug.hud.fps) {\n datas.push(`FPS: ${this.currentFps}`);\n }\n\n const { width } = this.viewport.getSize();\n\n this.ctx.save();\n this.ctx.fillStyle = \"rgba(0,0,0,0.5)\";\n this.ctx.fillRect(\n width - DEBUG_HUD.PANEL_WIDTH - DEBUG_HUD.PADDING,\n DEBUG_HUD.PADDING / 2,\n DEBUG_HUD.PANEL_WIDTH,\n datas.length * DEBUG_HUD.LINE_HEIGHT + DEBUG_HUD.PADDING\n );\n\n this.ctx.fillStyle = \"#00ff99\";\n this.ctx.font = \"12px monospace\";\n\n for (let i = 0; i < datas.length; i++) {\n this.ctx.fillText(\n datas[i],\n width - DEBUG_HUD.PANEL_WIDTH - DEBUG_HUD.PADDING + 5,\n 18 + i * DEBUG_HUD.LINE_HEIGHT\n );\n }\n\n this.ctx.restore();\n }\n}\n","import { Coords, onDrawCallback } from \"../../types\";\nimport { ICamera } from \"../Camera\";\nimport { Config } from \"../Config\";\nimport { CoordinateOverlayRenderer } from \"../CoordinateOverlayRenderer\";\nimport { CoordinateTransformer } from \"../CoordinateTransformer\";\nimport { CanvasDebug } from \"../CanvasDebug\";\nimport { Layer } from \"../Layer\";\nimport { ViewportState } from \"../ViewportState\";\nimport { IRenderer } from \"./Renderer\";\n\n/**\n * Canvas-based renderer that draws engine layers, user callbacks, and coordinate overlays.\n * Supports HiDPI/Retina displays via devicePixelRatio scaling.\n * @internal\n */\nexport class CanvasRenderer implements IRenderer {\n private ctx: CanvasRenderingContext2D;\n private coordinateOverlayRenderer: CoordinateOverlayRenderer;\n private debugOverlay?: CanvasDebug;\n\n /** Optional user-provided draw hook executed after engine layers. */\n public onDraw?: onDrawCallback;\n\n /**\n * @param canvas Target canvas element.\n * @param camera Active camera.\n * @param coordinateTransformer World/screen transformer shared with layers.\n * @param config Normalized engine configuration store.\n * @param layers Layer manager whose callbacks are drawn in order.\n */\n constructor(\n private canvas: HTMLCanvasElement,\n private camera: ICamera,\n private coordinateTransformer: CoordinateTransformer,\n private config: Config,\n private viewport: ViewportState,\n private layers: Layer\n ) {\n const context = canvas.getContext(\"2d\");\n if (!context) {\n throw new Error(\"Failed to get 2D canvas context\");\n }\n\n this.ctx = context;\n this.applyCanvasSize();\n this.coordinateOverlayRenderer = new CoordinateOverlayRenderer(\n this.ctx,\n this.camera,\n this.config,\n this.viewport\n );\n if (this.config.get().debug?.enabled) {\n this.debugOverlay = new CanvasDebug(\n this.ctx,\n this.camera,\n this.coordinateTransformer,\n this.config,\n this.viewport\n );\n // Start FPS loop if fps hud is enabled\n if (this.config.get().debug?.hud?.fps) {\n this.debugOverlay.setFpsUpdateCallback(() => this.render());\n this.debugOverlay.startFpsLoop();\n }\n }\n }\n\n init(): void {\n this.applyCanvasSize();\n }\n\n private applyCanvasSize() {\n const size = this.viewport.getSize();\n const dpr = this.viewport.dpr;\n\n // Set actual canvas resolution (physical pixels)\n this.canvas.width = size.width * dpr;\n this.canvas.height = size.height * dpr;\n\n // Set display size via CSS (logical pixels)\n this.canvas.style.width = `${size.width}px`;\n this.canvas.style.height = `${size.height}px`;\n\n // Scale context to match DPR\n this.ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n }\n\n render(): void {\n const size = this.viewport.getSize();\n const dpr = this.viewport.dpr;\n const config = { ...this.config.get(), size: { ...size }, scale: this.camera.scale };\n const topLeft: Coords = { x: this.camera.x, y: this.camera.y };\n\n // Reset transform for HiDPI support (canvas.width/height changes reset transform)\n this.ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n\n // Clear background\n this.ctx.clearRect(0, 0, config.size.width, config.size.height);\n this.ctx.fillStyle = config.backgroundColor;\n this.ctx.fillRect(0, 0, config.size.width, config.size.height);\n\n // Draw engine layers\n this.layers.drawAll({\n ctx: this.ctx,\n camera: this.camera,\n transformer: this.coordinateTransformer,\n config,\n topLeft,\n });\n\n // User custom draw callback (optional)\n this.onDraw?.(this.ctx, {\n scale: this.camera.scale,\n width: config.size.width,\n height: config.size.height,\n coords: topLeft,\n });\n\n // Coordinate overlay\n if (this.coordinateOverlayRenderer.shouldDraw(this.camera.scale)) {\n this.coordinateOverlayRenderer.draw();\n }\n\n // Debug overlay\n if (config.debug?.enabled) {\n if (!this.debugOverlay) {\n this.debugOverlay = new CanvasDebug(\n this.ctx,\n this.camera,\n this.coordinateTransformer,\n this.config,\n this.viewport\n );\n // Start FPS loop if fps hud is enabled\n if (config.debug?.hud?.fps) {\n this.debugOverlay.setFpsUpdateCallback(() => this.render());\n this.debugOverlay.startFpsLoop();\n }\n }\n this.debugOverlay.draw();\n }\n }\n\n resize(width: number, height: number): void {\n const dpr = this.viewport.dpr;\n\n this.viewport.setSize(width, height);\n\n // Set actual canvas resolution (physical pixels)\n this.canvas.width = width * dpr;\n this.canvas.height = height * dpr;\n\n // Set display size via CSS (logical pixels)\n this.canvas.style.width = `${width}px`;\n this.canvas.style.height = `${height}px`;\n\n // Scale context to match DPR\n this.ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n }\n\n destroy(): void {\n if (this.debugOverlay) {\n this.debugOverlay.destroy();\n this.debugOverlay = undefined;\n }\n this.layers.clear();\n }\n\n /** Access the underlying 2D rendering context for advanced usage. */\n getContext(): CanvasRenderingContext2D {\n return this.ctx;\n }\n}\n","import { Coords } from \"../types\";\nimport { ICamera } from \"./Camera\";\nimport { Config } from \"./Config\";\nimport { IRenderer } from \"./Renderer/Renderer\";\nimport { ViewportState } from \"./ViewportState\";\nimport { AnimationController } from \"./AnimationController\";\n\nexport class SizeController {\n private canvasWrapper: HTMLDivElement;\n private canvas: HTMLCanvasElement;\n private camera: ICamera;\n private viewport: ViewportState;\n private renderer: IRenderer;\n private config: Config;\n private onSizeApplied: () => void;\n\n constructor(\n canvasWrapper: HTMLDivElement,\n canvas: HTMLCanvasElement,\n camera: ICamera,\n renderer: IRenderer,\n viewport: ViewportState,\n\n config: Config,\n onSizeApplied: () => void\n ) {\n this.canvasWrapper = canvasWrapper;\n this.canvas = canvas;\n this.camera = camera;\n this.renderer = renderer;\n this.viewport = viewport;\n this.config = config;\n this.onSizeApplied = onSizeApplied;\n }\n\n /**\n * Manually update canvas size using AnimationController for smooth transitions.\n * @param width New canvas width in pixels.\n * @param height New canvas height in pixels.\n * @param durationMs Animation duration in ms (default 500). Use 0 for instant resize.\n * @param animationController AnimationController instance to handle the animation.\n * @param onComplete Optional callback fired when resize animation completes.\n */\n resizeWithAnimation(\n width: number,\n height: number,\n durationMs: number,\n animationController: AnimationController,\n onComplete?: () => void\n ) {\n if (width <= 0 || height <= 0) {\n return;\n }\n\n const configSize = this.config.get().size;\n const clamp = (value: number, min?: number, max?: number) => {\n let result = value;\n if (min !== undefined) {\n result = Math.max(min, result);\n }\n if (max !== undefined) {\n result = Math.min(max, result);\n }\n return result;\n };\n\n // Clamp to min/max values\n width = clamp(width, configSize?.minWidth, configSize?.maxWidth);\n height = clamp(height, configSize?.minHeight, configSize?.maxHeight);\n\n // Delegate to AnimationController\n animationController.animateResize(width, height, durationMs, (w, h, center) => this.applySize(w, h, center), onComplete);\n }\n\n private applySize(nextW: number, nextH: number, center: Coords) {\n const roundedW = Math.round(nextW);\n const roundedH = Math.round(nextH);\n const dpr = this.viewport.dpr;\n\n this.viewport.setSize(roundedW, roundedH);\n\n // CSS size (logical pixels)\n this.canvasWrapper.style.width = `${roundedW}px`;\n this.canvasWrapper.style.height = `${roundedH}px`;\n\n // Canvas resolution (physical pixels for HiDPI)\n this.canvas.width = roundedW * dpr;\n this.canvas.height = roundedH * dpr;\n this.canvas.style.width = `${roundedW}px`;\n this.canvas.style.height = `${roundedH}px`;\n\n this.camera.setCenter(center, roundedW, roundedH);\n this.renderer.resize(roundedW, roundedH);\n this.onSizeApplied();\n }\n}\n","import { Coords } from \"../types\";\nimport { ICamera } from \"./Camera\";\nimport { ViewportState } from \"./ViewportState\";\nimport { DEFAULT_VALUES } from \"../constants\";\n\n/**\n * Manages smooth animations for camera movements and canvas resizing.\n * Handles animation frame scheduling and cleanup.\n * @internal\n */\nexport class AnimationController {\n private moveAnimationId?: number;\n private resizeAnimationId?: number;\n\n constructor(private camera: ICamera, private viewport: ViewportState, private onAnimationFrame: () => void) {}\n\n /**\n * Smoothly animate camera movement to target coordinates.\n * @param targetX Target world x coordinate.\n * @param targetY Target world y coordinate.\n * @param durationMs Animation duration in milliseconds (default: 500ms). Set to 0 for instant move.\n * @param onComplete Optional callback fired when animation completes.\n */\n animateMoveTo(\n targetX: number,\n targetY: number,\n durationMs: number = DEFAULT_VALUES.ANIMATION_DURATION_MS,\n onComplete?: () => void\n ) {\n // Cancel any existing move animation\n this.cancelMove();\n\n // Instant move if duration is 0 or negative\n if (durationMs <= 0) {\n const size = this.viewport.getSize();\n this.camera.setCenter({ x: targetX, y: targetY }, size.width, size.height);\n this.onAnimationFrame();\n onComplete?.();\n return;\n }\n\n const size = this.viewport.getSize();\n const start = this.camera.getCenter(size.width, size.height);\n const startTime = performance.now();\n\n const step = (currentTime: number) => {\n const elapsed = currentTime - startTime;\n const progress = Math.min(1, elapsed / durationMs);\n\n // Easing function (ease-in-out)\n const eased = progress < 0.5 ? 2 * progress * progress : 1 - Math.pow(-2 * progress + 2, 2) / 2;\n\n const currentX = start.x + (targetX - start.x) * eased;\n const currentY = start.y + (targetY - start.y) * eased;\n\n const size = this.viewport.getSize();\n this.camera.setCenter({ x: currentX, y: currentY }, size.width, size.height);\n this.onAnimationFrame();\n\n if (progress < 1) {\n this.moveAnimationId = requestAnimationFrame(step);\n } else {\n this.moveAnimationId = undefined;\n onComplete?.();\n }\n };\n\n this.moveAnimationId = requestAnimationFrame(step);\n }\n\n /**\n * Smoothly animate canvas size change while keeping view centered.\n * @param targetWidth New canvas width in pixels.\n * @param targetHeight New canvas height in pixels.\n * @param durationMs Animation duration in milliseconds (default: 500ms). Set to 0 for instant resize.\n * @param onApplySize Callback to apply the new size (updates wrapper, canvas, renderer).\n * @param onComplete Optional callback fired when animation completes.\n */\n animateResize(\n targetWidth: number,\n targetHeight: number,\n durationMs: number = DEFAULT_VALUES.ANIMATION_DURATION_MS,\n onApplySize: (width: number, height: number, center: Coords) => void,\n onComplete?: () => void\n ) {\n if (targetWidth <= 0 || targetHeight <= 0) {\n return;\n }\n\n // Cancel any existing resize animation\n this.cancelResize();\n\n const prev = this.viewport.getSize();\n const center = this.camera.getCenter(prev.width, prev.height);\n\n // Instant resize if duration is 0 or negative\n if (durationMs <= 0) {\n onApplySize(targetWidth, targetHeight, center);\n onComplete?.();\n return;\n }\n\n const startW = prev.width;\n const startH = prev.height;\n const deltaW = targetWidth - prev.width;\n const deltaH = targetHeight - prev.height;\n const startTime = performance.now();\n\n const step = (currentTime: number) => {\n const elapsed = currentTime - startTime;\n const progress = Math.min(1, elapsed / durationMs);\n\n const nextW = startW + deltaW * progress;\n const nextH = startH + deltaH * progress;\n\n onApplySize(nextW, nextH, center);\n\n if (progress < 1) {\n this.resizeAnimationId = requestAnimationFrame(step);\n } else {\n this.resizeAnimationId = undefined;\n onComplete?.();\n }\n };\n\n this.resizeAnimationId = requestAnimationFrame(step);\n }\n\n /**\n * Cancel the current move animation if running.\n */\n cancelMove() {\n if (this.moveAnimationId !== undefined) {\n cancelAnimationFrame(this.moveAnimationId);\n this.moveAnimationId = undefined;\n }\n }\n\n /**\n * Cancel the current resize animation if running.\n */\n cancelResize() {\n if (this.resizeAnimationId !== undefined) {\n cancelAnimationFrame(this.resizeAnimationId);\n this.resizeAnimationId = undefined;\n }\n }\n\n /**\n * Cancel all running animations.\n */\n cancelAll() {\n this.cancelMove();\n this.cancelResize();\n }\n\n /**\n * Check if any animation is currently running.\n */\n isAnimating(): boolean {\n return this.moveAnimationId !== undefined || this.resizeAnimationId !== undefined;\n }\n}\n","import { CanvasTileEngineConfig } from \"../types\";\nimport { ICamera } from \"./Camera\";\nimport { Config } from \"./Config\";\nimport { CoordinateTransformer } from \"./CoordinateTransformer\";\nimport { Layer } from \"./Layer\";\nimport { ViewportState } from \"./ViewportState\";\nimport { CanvasRenderer } from \"./Renderer/CanvasRenderer\";\nimport { IRenderer } from \"./Renderer/Renderer\";\n\n/**\n * Factory for creating renderer instances based on configuration.\n * Implements the Factory Pattern to decouple renderer creation from engine initialization.\n * @internal\n */\nexport class RendererFactory {\n /**\n * Create a renderer instance based on the specified type.\n * @param type Renderer type (currently only \"canvas\" is supported).\n * @param canvas Target canvas element.\n * @param camera Active camera.\n * @param coordinateTransformer World/screen coordinate transformer.\n * @param config Normalized engine configuration.\n * @param viewport Viewport state manager.\n * @param layers Layer manager for rendering.\n * @returns Configured renderer instance.\n * @throws Error if renderer type is not supported.\n */\n static createRenderer(\n type: CanvasTileEngineConfig[\"renderer\"],\n canvas: HTMLCanvasElement,\n camera: ICamera,\n coordinateTransformer: CoordinateTransformer,\n config: Config,\n viewport: ViewportState,\n layers: Layer\n ): IRenderer {\n switch (type) {\n case \"canvas\":\n return new CanvasRenderer(canvas, camera, coordinateTransformer, config, viewport, layers);\n default:\n // Type guard ensures this should never happen\n throw new Error(`Unsupported renderer type: ${type}`);\n }\n }\n\n /**\n * Validate if a renderer type is supported.\n * @param type Renderer type to validate.\n * @returns True if the renderer type is supported.\n */\n static isSupported(type: string): type is NonNullable<CanvasTileEngineConfig[\"renderer\"]> {\n return type === \"canvas\";\n }\n\n /**\n * Get list of supported renderer types.\n * @returns Array of supported renderer type names.\n */\n static getSupportedTypes(): ReadonlyArray<NonNullable<CanvasTileEngineConfig[\"renderer\"]>> {\n return [\"canvas\"] as const;\n }\n}\n","import { Camera } from \"./modules/Camera\";\nimport { Config } from \"./modules/Config\";\nimport { CoordinateTransformer } from \"./modules/CoordinateTransformer\";\nimport { CanvasDraw } from \"./modules/CanvasDraw\";\nimport { EventManager } from \"./modules/EventManager\";\nimport { ImageLoader } from \"./modules/ImageLoader\";\nimport { Layer, type LayerHandle } from \"./modules/Layer\";\nimport { ViewportState } from \"./modules/ViewportState\";\nimport { CanvasRenderer } from \"./modules/Renderer/CanvasRenderer\";\nimport { IRenderer } from \"./modules/Renderer/Renderer\";\nimport {\n Coords,\n DrawObject,\n CanvasTileEngineConfig,\n onClickCallback,\n onDrawCallback,\n onHoverCallback,\n EventHandlers,\n} from \"./types\";\nimport { SizeController } from \"./modules/SizeController\";\nimport { AnimationController } from \"./modules/AnimationController\";\nimport { RendererFactory } from \"./modules/RendererFactory\";\n\n/**\n * Core engine wiring camera, config, renderer, events, and draw helpers.\n */\nexport class CanvasTileEngine {\n private config: Config;\n private camera: Camera;\n private viewport: ViewportState;\n private coordinateTransformer: CoordinateTransformer;\n private layers?: Layer;\n private renderer: IRenderer;\n private events: EventManager;\n private draw?: CanvasDraw;\n public images: ImageLoader;\n private sizeController: SizeController;\n private animationController: AnimationController;\n\n public canvasWrapper: HTMLDivElement;\n public canvas: HTMLCanvasElement;\n\n /** Callback: center coordinates change */\n public onCoordsChange?: (coords: Coords) => void;\n\n private _onClick?: onClickCallback;\n\n public get onClick(): onClickCallback | undefined {\n return this._onClick;\n }\n public set onClick(cb: onClickCallback | undefined) {\n this._onClick = cb;\n this.events.onClick = cb;\n }\n\n private _onHover?: onHoverCallback;\n public get onHover(): onHoverCallback | undefined {\n return this._onHover;\n }\n public set onHover(cb: onHoverCallback | undefined) {\n this._onHover = cb;\n this.events.onHover = cb;\n }\n\n private _onMouseDown?: () => void;\n public get onMouseDown(): (() => void) | undefined {\n return this._onMouseDown;\n }\n public set onMouseDown(cb: (() => void) | undefined) {\n this._onMouseDown = cb;\n this.events.onMouseDown = cb;\n }\n\n private _onMouseUp?: () => void;\n public get onMouseUp(): (() => void) | undefined {\n return this._onMouseUp;\n }\n public set onMouseUp(cb: (() => void) | undefined) {\n this._onMouseUp = cb;\n this.events.onMouseUp = cb;\n }\n\n private _onMouseLeave?: () => void;\n public get onMouseLeave(): (() => void) | undefined {\n return this._onMouseLeave;\n }\n public set onMouseLeave(cb: (() => void) | undefined) {\n this._onMouseLeave = cb;\n this.events.onMouseLeave = cb;\n }\n\n private _onDraw?: onDrawCallback;\n public get onDraw(): onDrawCallback | undefined {\n return this._onDraw;\n }\n public set onDraw(cb: onDrawCallback | undefined) {\n this._onDraw = cb;\n this.getCanvasRenderer().onDraw = cb;\n }\n\n private _onResize?: () => void;\n public get onResize(): (() => void) | undefined {\n return this._onResize;\n }\n public set onResize(cb: (() => void) | undefined) {\n this._onResize = cb;\n this.events.onResize = cb;\n }\n\n /**\n * @param canvas Target canvas element.\n * @param config Initial engine configuration.\n * @param center Initial center in world space.\n */\n constructor(canvasWrapper: HTMLDivElement, config: CanvasTileEngineConfig, center: Coords = { x: 0, y: 0 }) {\n this.canvasWrapper = canvasWrapper;\n this.canvas = canvasWrapper.querySelector(\"canvas\")!;\n this.canvasWrapper.style.position = \"relative\";\n this.canvasWrapper.style.width = config.size.width + \"px\";\n this.canvasWrapper.style.height = config.size.height + \"px\";\n this.canvas.style.position = \"absolute\";\n\n this.config = new Config(config);\n\n const rendererType = config.renderer ?? \"canvas\";\n const initialTopLeft: Coords = {\n x: center.x - config.size.width / (2 * config.scale),\n y: center.y - config.size.height / (2 * config.scale),\n };\n\n this.viewport = new ViewportState(config.size.width, config.size.height);\n this.camera = new Camera(\n initialTopLeft,\n this.config.get().scale,\n this.config.get().minScale,\n this.config.get().maxScale,\n this.viewport\n );\n\n this.coordinateTransformer = new CoordinateTransformer(this.camera);\n\n // Initialize animation controller\n this.animationController = new AnimationController(this.camera, this.viewport, () => this.handleCameraChange());\n\n this.renderer = this.createRenderer(rendererType);\n\n this.images = new ImageLoader();\n\n this.events = new EventManager(\n this.canvasWrapper,\n this.canvas,\n this.camera,\n this.viewport,\n this.config,\n this.coordinateTransformer,\n () => this.handleCameraChange()\n );\n this.sizeController = new SizeController(\n this.canvasWrapper,\n this.canvas,\n this.camera,\n this.renderer,\n this.viewport,\n this.config,\n () => this.handleCameraChange()\n );\n this.events.setupEvents();\n\n // Apply initial bounds if provided\n if (config.bounds) {\n this.camera.setBounds(config.bounds);\n }\n }\n\n // ─── PUBLIC API ──────────────────────────────\n\n /** Tear down listeners and observers. */\n destroy() {\n this.events.destroy();\n this.animationController.cancelAll();\n this.draw?.destroy();\n this.layers?.clear();\n this.images.clear();\n this.renderer.destroy();\n }\n\n /** Render a frame using the active renderer. */\n render() {\n this.renderer.render();\n }\n\n /**\n * Manually update canvas size (e.g., user-driven select). Keeps view centered.\n * @param width New canvas width in pixels.\n * @param height New canvas height in pixels.\n * @param durationMs Animation duration in ms (default 500). Use 0 for instant resize.\n * @param onComplete Optional callback fired when resize animation completes.\n */\n resize(width: number, height: number, durationMs: number = 500, onComplete?: () => void) {\n this.sizeController.resizeWithAnimation(width, height, durationMs, this.animationController, () => {\n // Trigger onResize callback after programmatic resize completes\n this._onResize?.();\n onComplete?.();\n });\n }\n\n /**\n * Current canvas size.\n * @returns Current `{ width, height }` in pixels.\n */\n getSize() {\n return this.viewport.getSize();\n }\n\n /**\n * Current canvas scale.\n * @returns Current canvas scale.\n */\n getScale() {\n return this.camera.scale;\n }\n\n /**\n * Zoom in by a given factor, centered on the viewport.\n * @param factor Zoom multiplier (default: 1.5). Higher values zoom in more.\n */\n zoomIn(factor: number = 1.5) {\n const size = this.viewport.getSize();\n this.camera.zoomByFactor(factor, size.width / 2, size.height / 2);\n this.handleCameraChange();\n }\n\n /**\n * Zoom out by a given factor, centered on the viewport.\n * @param factor Zoom multiplier (default: 1.5). Higher values zoom out more.\n */\n zoomOut(factor: number = 1.5) {\n const size = this.viewport.getSize();\n this.camera.zoomByFactor(1 / factor, size.width / 2, size.height / 2);\n this.handleCameraChange();\n }\n\n /** Snapshot of current normalized config. */\n getConfig(): Required<CanvasTileEngineConfig> {\n const base = this.config.get();\n const size = this.viewport.getSize();\n return {\n ...base,\n scale: this.camera.scale,\n size: { ...size },\n };\n }\n\n /** Center coordinates of the map. */\n getCenterCoords(): Coords {\n const size = this.viewport.getSize();\n return this.camera.getCenter(size.width, size.height);\n }\n\n /** Set center coordinates from outside (adjusts the camera accordingly). */\n updateCoords(newCenter: Coords) {\n const size = this.viewport.getSize();\n this.camera.setCenter(newCenter, size.width, size.height);\n this.handleCameraChange();\n }\n\n /**\n * Smoothly move the camera center to target coordinates over the given duration.\n * @param x Target world x.\n * @param y Target world y.\n * @param durationMs Animation duration in milliseconds (default: 500ms). Set to 0 for instant move.\n * @param onComplete Optional callback fired when animation completes.\n */\n goCoords(x: number, y: number, durationMs: number = 500, onComplete?: () => void) {\n this.animationController.animateMoveTo(x, y, durationMs, onComplete);\n }\n\n /**\n * Update event handlers at runtime.\n * This allows you to enable or disable specific interactions dynamically.\n * @param handlers Partial event handlers to update.\n * @example\n * ```ts\n * // Disable drag temporarily\n * engine.setEventHandlers({ drag: false });\n *\n * // Enable painting mode\n * engine.setEventHandlers({ drag: false, hover: true });\n *\n * // Re-enable drag\n * engine.setEventHandlers({ drag: true });\n * ```\n */\n setEventHandlers(handlers: Partial<EventHandlers>) {\n this.config.updateEventHandlers(handlers);\n }\n\n /**\n * Set or update map boundaries to restrict camera movement.\n * @param bounds Boundary limits. Use Infinity/-Infinity to remove limits.\n * @example\n * ```ts\n * // Restrict map to -100 to 100 on both axes\n * engine.setBounds({ minX: -100, maxX: 100, minY: -100, maxY: 100 });\n *\n * // Remove boundaries\n * engine.setBounds({ minX: -Infinity, maxX: Infinity, minY: -Infinity, maxY: Infinity });\n *\n * // Only limit X axis\n * engine.setBounds({ minX: 0, maxX: 500, minY: -Infinity, maxY: Infinity });\n * ```\n */\n setBounds(bounds: { minX: number; maxX: number; minY: number; maxY: number }) {\n this.config.updateBounds(bounds);\n this.camera.setBounds(bounds);\n this.render();\n }\n\n // ─── Draw helpers (canvas renderer only) ───────────\n\n /**\n * Register a generic draw callback (canvas renderer only).\n * @param fn Callback invoked with context, top-left coords, and config.\n * @param layer Layer order (lower draws first).\n */\n addDrawFunction(\n fn: (ctx: CanvasRenderingContext2D, coords: Coords, config: Required<CanvasTileEngineConfig>) => void,\n layer: number = 1\n ): LayerHandle {\n return this.ensureCanvasDraw().addDrawFunction(fn, layer);\n }\n\n /**\n * Draw one or many rectangles in world space (canvas renderer only).\n * Supports rotation via the `rotate` property (degrees, positive = clockwise).\n * @param items Rectangle definitions.\n * @param layer Layer order (lower draws first).\n */\n drawRect(items: DrawObject | Array<DrawObject>, layer: number = 1): LayerHandle {\n return this.ensureCanvasDraw().drawRect(items, layer);\n }\n\n /**\n * Draw rectangles with pre-rendering cache (canvas renderer only).\n * Renders all items once to an offscreen canvas, then blits the visible portion each frame.\n * Ideal for large static datasets like mini-maps where items don't change.\n * Supports rotation via the `rotate` property (degrees, positive = clockwise).\n * @param items Array of rectangle definitions.\n * @param cacheKey Unique key for this cache (e.g., \"minimap-items\").\n * @param layer Layer order (lower draws first).\n */\n drawStaticRect(items: Array<DrawObject>, cacheKey: string, layer: number = 1): LayerHandle {\n return this.ensureCanvasDraw().drawStaticRect(items, cacheKey, layer);\n }\n\n /**\n * Draw circles with pre-rendering cache (canvas renderer only).\n * Renders all items once to an offscreen canvas, then blits the visible portion each frame.\n * Ideal for large static datasets like mini-maps where items don't change.\n * @param items Array of circle definitions.\n * @param cacheKey Unique key for this cache (e.g., \"minimap-circles\").\n * @param layer Layer order (lower draws first).\n */\n drawStaticCircle(items: Array<DrawObject>, cacheKey: string, layer: number = 1): LayerHandle {\n return this.ensureCanvasDraw().drawStaticCircle(items, cacheKey, layer);\n }\n\n /**\n * Draw images with pre-rendering cache (canvas renderer only).\n * Renders all items once to an offscreen canvas, then blits the visible portion each frame.\n * Ideal for large static datasets like terrain tiles or static decorations.\n * Supports rotation via the `rotate` property (degrees, positive = clockwise).\n * @param items Array of image definitions with HTMLImageElement.\n * @param cacheKey Unique key for this cache (e.g., \"terrain-cache\").\n * @param layer Layer order (lower draws first).\n */\n drawStaticImage(\n items: Array<Omit<DrawObject, \"style\"> & { img: HTMLImageElement }>,\n cacheKey: string,\n layer: number = 1\n ): LayerHandle {\n return this.ensureCanvasDraw().drawStaticImage(items, cacheKey, layer);\n }\n\n /**\n * Clear a static rendering cache.\n * @param cacheKey The cache key to clear, or undefined to clear all caches.\n */\n clearStaticCache(cacheKey?: string) {\n this.ensureCanvasDraw().clearStaticCache(cacheKey);\n }\n\n /**\n * Draw one or many lines between world points (canvas renderer only).\n * @param items Line segments.\n * @param style Line style overrides.\n * @param layer Layer order.\n */\n drawLine(\n items: Array<{ from: Coords; to: Coords }> | { from: Coords; to: Coords },\n style?: { strokeStyle?: string; lineWidth?: number },\n layer: number = 1\n ): LayerHandle {\n return this.ensureCanvasDraw().drawLine(items, style, layer);\n }\n\n /**\n * Draw one or many circles sized in world units (canvas renderer only).\n * @param items Circle definitions.\n * @param layer Layer order.\n */\n drawCircle(items: DrawObject | Array<DrawObject>, layer: number = 1): LayerHandle {\n return this.ensureCanvasDraw().drawCircle(items, layer);\n }\n\n /**\n * Draw one or many texts at world positions (canvas renderer only).\n * @param items Text definitions.\n * @param style Text style overrides.\n * @param layer Layer order.\n */\n drawText(\n items: Array<{ coords: Coords; text: string }> | { coords: Coords; text: string },\n style?: { fillStyle?: string; font?: string; textAlign?: CanvasTextAlign; textBaseline?: CanvasTextBaseline },\n layer: number = 2\n ): LayerHandle {\n return this.ensureCanvasDraw().drawText(items, style, layer);\n }\n\n /**\n * Draw one or many polylines through world points (canvas renderer only).\n * @param items Polyline point collections.\n * @param style Stroke style overrides.\n * @param layer Layer order.\n */\n drawPath(\n items: Array<Coords[]> | Coords[],\n style?: { strokeStyle?: string; lineWidth?: number },\n layer: number = 1\n ): LayerHandle {\n return this.ensureCanvasDraw().drawPath(items, style, layer);\n }\n\n /**\n * Draw one or many images scaled in world units (canvas renderer only).\n * Supports rotation via the `rotate` property (degrees, positive = clockwise).\n * @param items Image definitions.\n * @param layer Layer order.\n */\n drawImage(\n items:\n | Array<Omit<DrawObject, \"style\"> & { img: HTMLImageElement }>\n | (Omit<DrawObject, \"style\"> & { img: HTMLImageElement }),\n layer: number = 1\n ): LayerHandle {\n return this.ensureCanvasDraw().drawImage(items, layer);\n }\n\n /**\n * Draw grid lines at specified cell size (canvas renderer only).\n * @param cellSize Size of each grid cell in world units.\n * @example\n * ```ts\n * engine.drawGridLines(50);\n * ```\n */\n drawGridLines(\n cellSize: number,\n lineWidth: number = 1,\n strokeStyle: string = \"black\",\n layer: number = 0\n ): LayerHandle {\n return this.ensureCanvasDraw().drawGridLines(cellSize, { lineWidth, strokeStyle }, layer);\n }\n\n /**\n * Remove a specific draw callback by handle (canvas renderer only).\n * Does not clear other callbacks on the same layer.\n */\n removeLayerHandle(handle: LayerHandle) {\n if (!this.layers) {\n throw new Error(\"removeLayerHandle is only available when renderer is set to 'canvas'.\");\n }\n this.layers.remove(handle);\n }\n\n /**\n * Clear all draw callbacks from a specific layer (canvas renderer only).\n * Use this before redrawing dynamic content to prevent accumulation.\n * @param layer Layer index to clear.\n * @example\n * ```ts\n * engine.clearLayer(1);\n * engine.drawRect(newRects, 1);\n * engine.render();\n * ```\n */\n clearLayer(layer: number) {\n if (!this.layers) {\n throw new Error(\"clearLayer is only available when renderer is set to 'canvas'.\");\n }\n this.layers.clear(layer);\n }\n\n /**\n * Clear all draw callbacks from all layers (canvas renderer only).\n * Useful for complete scene reset.\n * @example\n * ```ts\n * engine.clearAll();\n * // Redraw everything from scratch\n * ```\n */\n clearAll() {\n if (!this.layers) {\n throw new Error(\"clearAll is only available when renderer is set to 'canvas'.\");\n }\n this.layers.clear();\n }\n\n /**\n * Build the active renderer based on config.\n * @param type Renderer type requested.\n */\n private createRenderer(type: CanvasTileEngineConfig[\"renderer\"]): IRenderer {\n // Initialize layers and draw helpers for canvas renderer\n if (type === \"canvas\") {\n this.layers = new Layer();\n this.draw = new CanvasDraw(this.layers, this.coordinateTransformer, this.camera);\n }\n\n return RendererFactory.createRenderer(\n type ?? \"canvas\",\n this.canvas,\n this.camera,\n this.coordinateTransformer,\n this.config,\n this.viewport,\n this.layers!\n );\n }\n\n private ensureCanvasDraw(): CanvasDraw {\n if (!this.draw) {\n throw new Error(\"Draw helpers are only available when renderer is set to 'canvas'.\");\n }\n return this.draw;\n }\n\n private getCanvasRenderer(): CanvasRenderer {\n if (!(this.renderer instanceof CanvasRenderer)) {\n throw new Error(\"Canvas renderer required for this operation.\");\n }\n return this.renderer;\n }\n\n // ─── Internal ───────────────────────────────\n\n private handleCameraChange() {\n if (this.onCoordsChange) {\n this.onCoordsChange(this.getCenterCoords());\n }\n this.render();\n }\n}\n"],"mappings":"AAKO,IAAMA,EAAiB,CAE1B,sBAAuB,IAGvB,mBAAoB,GAGpB,uBAAwB,EAGxB,gBAAiB,IAGjB,gBAAiB,KAGjB,iBAAkB,IACtB,EAEaC,EAAe,CAExB,qBAAsB,GAGtB,qBAAsB,CAC1B,EAEaC,EAAc,CAEvB,UAAW,IAGX,WAAY,IAGZ,UAAW,IAGX,WAAY,GAChB,EAEaC,EAAkB,CAE3B,iBAAkB,UAGlB,cAAe,QACnB,EAEaC,EAAqB,CAE9B,aAAc,GAGd,aAAc,GAGd,eAAgB,GAGhB,cAAe,EAGf,cAAe,GAGf,uBAAwB,GAC5B,EAEaC,EAAY,CAErB,YAAa,IAGb,QAAS,EAGT,YAAa,EACjB,EAEaC,EAAoB,CAE7B,YAAa,CACjB,ECrFO,SAASC,GAAWC,EAAiBC,EAAeC,EAAYC,EAAoB,CACvF,MAAO,CAAE,EAAGH,EAAQ,EAAIE,EAAKD,EAAO,EAAGD,EAAQ,EAAIG,EAAKF,CAAM,CAClE,CAGO,SAASG,GACZJ,EACAK,EACAC,EACAC,EACAC,EACAC,EACkC,CAClC,IAAMC,EAAe,KAAK,IAAI,KAAK,IAAIJ,EAAQK,EAAe,eAAe,EAAGA,EAAe,eAAe,EACxGC,EAAc,KAAK,IAAI,CAACF,EAAeC,EAAe,gBAAgB,EACtEE,EAAW,KAAK,IAAIL,EAAU,KAAK,IAAID,EAAUF,EAAWO,CAAW,CAAC,EAC9E,OAAIC,IAAaR,EAAiB,CAAE,QAAAL,EAAS,MAAOK,CAAS,EACtD,CACH,QAAS,CACL,EAAGL,EAAQ,EAAIS,EAAM,GAAK,EAAIJ,EAAW,EAAIQ,GAC7C,EAAGb,EAAQ,EAAIS,EAAM,GAAK,EAAIJ,EAAW,EAAIQ,EACjD,EACA,MAAOA,CACX,CACJ,CAGO,SAASC,GAAcC,EAAeC,EAAsD,CAC/F,MAAO,CACH,GAAID,EAAM,EAAIJ,EAAe,mBAAqBK,EAAI,GAAKA,EAAI,MAC/D,GAAID,EAAM,EAAIJ,EAAe,mBAAqBK,EAAI,GAAKA,EAAI,KACnE,CACJ,CAGO,SAASC,GAAcC,EAAgBF,EAAsD,CAChG,MAAO,CAAE,EAAGA,EAAI,EAAIE,EAAO,EAAIF,EAAI,MAAO,EAAGA,EAAI,EAAIE,EAAO,EAAIF,EAAI,KAAM,CAC9E,CC4BO,IAAMG,EAAN,KAAgC,CAC3B,GACA,GACA,OACC,SACA,SACD,OAMA,SAER,YAAYC,EAAwBC,EAAQ,EAAGC,EAAW,GAAKC,EAAW,GAAIC,EAA0B,CACpG,KAAK,GAAKJ,EAAe,EAAIK,EAAe,mBAC5C,KAAK,GAAKL,EAAe,EAAIK,EAAe,mBAC5C,KAAK,OAASJ,EACd,KAAK,SAAWC,EAChB,KAAK,SAAWC,EAChB,KAAK,SAAWC,CACpB,CAMA,UAAUE,EAAqE,CAC3E,KAAK,OAASA,EAEV,KAAK,QACL,KAAK,cAAc,CAE3B,CAEQ,eAAgB,CACpB,GAAI,CAAC,KAAK,QAAU,CAAC,KAAK,SACtB,OAGJ,GAAM,CAAE,MAAOC,EAAe,OAAQC,CAAe,EAAI,KAAK,SAAS,QAAQ,EAGzEC,EAAiBF,EAAgB,KAAK,OACtCG,EAAkBF,EAAiB,KAAK,OAE9C,KAAK,GAAK,KAAK,UAAU,KAAK,GAAIC,EAAgB,KAAK,OAAO,KAAM,KAAK,OAAO,IAAI,EACpF,KAAK,GAAK,KAAK,UAAU,KAAK,GAAIC,EAAiB,KAAK,OAAO,KAAM,KAAK,OAAO,IAAI,CACzF,CAMQ,UAAUC,EAAeC,EAAkBC,EAAaC,EAAqB,CACjF,IAAMC,EAAaD,EAAMD,EAGzB,OAAID,GAAYG,EACLF,GAAOD,EAAWG,GAAc,EAIvCJ,EAAQE,EACDA,EAEPF,EAAQC,EAAWE,EACZA,EAAMF,EAEVD,CACX,CAEA,IAAI,GAAY,CACZ,OAAO,KAAK,EAChB,CAEA,IAAI,GAAY,CACZ,OAAO,KAAK,EAChB,CAEA,IAAI,OAAgB,CAChB,OAAO,KAAK,MAChB,CAEA,IAAIK,EAAsBC,EAAsB,CAC5C,IAAMC,EAAOC,GAAW,CAAE,EAAG,KAAK,GAAI,EAAG,KAAK,EAAG,EAAG,KAAK,OAAQH,EAAcC,CAAY,EAC3F,KAAK,GAAKC,EAAK,EACf,KAAK,GAAKA,EAAK,EACf,KAAK,cAAc,CACvB,CAEA,KAAKE,EAAgBC,EAAgBC,EAAgBC,EAAqB,CAEtE,IAAMC,EAAKJ,EAASG,EAAW,KACzBE,EAAKJ,EAASE,EAAW,IAEzBL,EAAOQ,GAAY,CAAE,EAAG,KAAK,GAAI,EAAG,KAAK,EAAG,EAAG,KAAK,OAAQJ,EAAQ,KAAK,SAAU,KAAK,SAAU,CACpG,EAAGE,EACH,EAAGC,CACP,CAAC,EACD,KAAK,GAAKP,EAAK,QAAQ,EACvB,KAAK,GAAKA,EAAK,QAAQ,EACvB,KAAK,OAASA,EAAK,MACnB,KAAK,cAAc,CACvB,CAQA,aAAaS,EAAgBC,EAAiBC,EAAiB,CAC3D,IAAMC,EAAW,KAAK,IAAI,KAAK,SAAU,KAAK,IAAI,KAAK,SAAU,KAAK,OAASH,CAAM,CAAC,EAClFG,IAAa,KAAK,SAKtB,KAAK,GAAK,KAAK,GAAKF,GAAW,EAAI,KAAK,OAAS,EAAIE,GACrD,KAAK,GAAK,KAAK,GAAKD,GAAW,EAAI,KAAK,OAAS,EAAIC,GACrD,KAAK,OAASA,EACd,KAAK,cAAc,EACvB,CAEA,UAAUC,EAAqBC,EAA8B,CACzD,MAAO,CACH,EAAG,KAAK,GAAKD,GAAe,EAAI,KAAK,QAAU,GAC/C,EAAG,KAAK,GAAKC,GAAgB,EAAI,KAAK,QAAU,EACpD,CACJ,CAEA,UAAUC,EAAgBF,EAAqBC,EAAsB,CACjE,KAAK,GAAKC,EAAO,EAAIF,GAAe,EAAI,KAAK,QAAU,GACvD,KAAK,GAAKE,EAAO,EAAID,GAAgB,EAAI,KAAK,QAAU,GACxD,KAAK,cAAc,CACvB,CAEA,gBAAgBE,EAAsBC,EAAuB,CACzD,KAAK,IAAMD,GAAgB,EAAI,KAAK,QACpC,KAAK,IAAMC,GAAiB,EAAI,KAAK,QACrC,KAAK,cAAc,CACvB,CACJ,EC7MO,IAAMC,EAAN,KAAa,CACR,OAMR,YAAYC,EAAgC,CACxC,IAAMC,EAAyC,CAC3C,SAAUC,EAAgB,cAC1B,MAAOF,EAAO,MACd,SAAUA,EAAO,UAAYA,EAAO,MAAQG,EAAa,qBACzD,SAAUH,EAAO,UAAYA,EAAO,MAAQG,EAAa,qBAEzD,KAAM,CACF,MAAOH,EAAO,KAAK,MACnB,OAAQA,EAAO,KAAK,OACpB,UAAWA,EAAO,KAAK,WAAaI,EAAY,WAChD,SAAUJ,EAAO,KAAK,UAAYI,EAAY,UAC9C,UAAWJ,EAAO,KAAK,WAAaI,EAAY,WAChD,SAAUJ,EAAO,KAAK,UAAYI,EAAY,SAClD,EAEA,gBAAiBJ,EAAO,iBAAmBE,EAAgB,iBAE3D,cAAe,CACX,MAAOF,EAAO,eAAe,OAAS,GACtC,MAAOA,EAAO,eAAe,OAAS,GACtC,KAAMA,EAAO,eAAe,MAAQ,GACpC,KAAMA,EAAO,eAAe,MAAQ,GACpC,OAAQA,EAAO,eAAe,QAAU,EAC5C,EAEA,OAAQA,EAAO,QAAU,CACrB,KAAM,KACN,KAAM,IACN,KAAM,KACN,KAAM,GACV,EAEA,YAAa,CACT,QAASA,EAAO,aAAa,SAAW,GACxC,gBAAiBA,EAAO,aAAa,iBAAmB,CAAE,IAAK,EAAG,IAAK,GAAS,CACpF,EAEA,OAAQ,CACJ,QAASA,EAAO,QAAQ,SAAW,UACnC,KAAMA,EAAO,QAAQ,MAAQ,MACjC,EAEA,MAAO,CACH,QAASA,EAAO,OAAO,SAAW,GAClC,IAAK,CACD,QAASA,EAAO,OAAO,KAAK,SAAW,GACvC,mBAAoBA,EAAO,OAAO,KAAK,oBAAsB,GAC7D,YAAaA,EAAO,OAAO,KAAK,aAAe,GAC/C,MAAOA,EAAO,OAAO,KAAK,OAAS,GACnC,YAAaA,EAAO,OAAO,KAAK,aAAe,GAC/C,IAAKA,EAAO,OAAO,KAAK,KAAO,EACnC,EACA,cAAe,CACX,MAAOA,EAAO,OAAO,eAAe,OAAS,GAC7C,MAAOA,EAAO,OAAO,eAAe,OAAS,GAC7C,KAAMA,EAAO,OAAO,eAAe,MAAQ,GAC3C,KAAMA,EAAO,OAAO,eAAe,MAAQ,GAC3C,OAAQA,EAAO,OAAO,eAAe,QAAU,EACnD,CACJ,CACJ,EACA,KAAK,OAAS,CACV,GAAGC,EACH,KAAM,OAAO,OAAOA,EAAK,IAAI,EAC7B,cAAe,OAAO,OAAOA,EAAK,aAAa,EAC/C,OAAQ,OAAO,OAAOA,EAAK,MAAM,EACjC,YAAa,OAAO,OAAO,CACvB,GAAGA,EAAK,YACR,gBAAiB,OAAO,OAAOA,EAAK,YAAY,eAAe,CACnE,CAAC,EACD,OAAQ,OAAO,OAAOA,EAAK,MAAM,EACjC,MAAO,OAAO,OAAO,CACjB,QAASA,EAAK,MAAM,QACpB,IAAK,OAAO,OAAOA,EAAK,MAAM,GAAG,EACjC,cAAe,OAAO,OAAOA,EAAK,MAAM,aAAa,CACzD,CAAC,CACL,CACJ,CAMA,KAAkD,CAC9C,IAAMI,EAAM,KAAK,OACjB,MAAO,CACH,GAAGA,EACH,KAAM,CAAE,GAAGA,EAAI,IAAK,EACpB,cAAe,CAAE,GAAGA,EAAI,aAAc,EACtC,OAAQ,CAAE,GAAGA,EAAI,MAAO,EACxB,YAAa,CACT,GAAGA,EAAI,YACP,gBAAiB,CACb,IAAKA,EAAI,YAAY,iBAAiB,KAAO,EAC7C,IAAKA,EAAI,YAAY,iBAAiB,KAAO,GACjD,CACJ,EACA,OAAQ,CAAE,GAAGA,EAAI,MAAO,EACxB,MAAO,CACH,GAAGA,EAAI,MACP,IAAK,CAAE,GAAGA,EAAI,MAAM,GAAI,EACxB,cAAe,CAAE,GAAGA,EAAI,MAAM,aAAc,CAChD,CACJ,CACJ,CAMA,oBAAoBC,EAAkC,CAClD,KAAK,OAAS,CACV,GAAG,KAAK,OACR,cAAe,OAAO,OAAO,CACzB,GAAG,KAAK,OAAO,cACf,GAAGA,CACP,CAAC,CACL,CACJ,CAMA,aAAaC,EAAoE,CAC7E,KAAK,OAAS,CACV,GAAG,KAAK,OACR,OAAQ,OAAO,OAAOA,CAAM,CAChC,CACJ,CACJ,ECzIO,IAAMC,EAAN,KAA4B,CAI/B,YAAoBC,EAAiB,CAAjB,YAAAA,CAAkB,CAQtC,cAAcC,EAAgBC,EAAwB,CAClD,OAAOC,GACH,CAAE,EAAGF,EAAQ,EAAGC,CAAO,EACvB,CAAE,EAAG,KAAK,OAAO,EAAG,EAAG,KAAK,OAAO,EAAG,MAAO,KAAK,OAAO,KAAM,CACnE,CACJ,CAQA,cAAcE,EAAiBC,EAAyB,CACpD,OAAOC,GACH,CAAE,EAAGF,EAAS,EAAGC,CAAQ,EACzB,CAAE,EAAG,KAAK,OAAO,EAAG,EAAG,KAAK,OAAO,EAAG,MAAO,KAAK,OAAO,KAAM,CACnE,CACJ,CACJ,EClCA,OAAOE,OAAW,QAmBX,IAAMC,EAAN,MAAMC,CAAoC,CACrC,KAER,aAAc,CACV,KAAK,KAAO,IAAIF,EACpB,CAKA,KAAKG,EAAkB,CACnB,IAAMC,EAA6BD,EAAM,IAAKE,GAAS,CAEnD,IAAMC,GADO,OAAOD,EAAK,MAAS,SAAWA,EAAK,KAAO,GACrC,EAEpB,MAAO,CACH,KAAMA,EAAK,EAAIC,EACf,KAAMD,EAAK,EAAIC,EACf,KAAMD,EAAK,EAAIC,EACf,KAAMD,EAAK,EAAIC,EACf,KAAAD,CACJ,CACJ,CAAC,EACD,KAAK,KAAK,KAAKD,CAAU,CAC7B,CAKA,MAAMG,EAAcC,EAAcC,EAAcC,EAAmB,CAE/D,OADgB,KAAK,KAAK,OAAO,CAAE,KAAAH,EAAM,KAAAC,EAAM,KAAAC,EAAM,KAAAC,CAAK,CAAC,EAC5C,IAAKC,GAAMA,EAAE,IAAI,CACpC,CAKA,OAAc,CACV,KAAK,KAAK,MAAM,CACpB,CAKA,OAAO,UAAiCR,EAA6B,CACjE,IAAMS,EAAQ,IAAIV,EAClB,OAAAU,EAAM,KAAKT,CAAK,EACTS,CACX,CACJ,ECjEA,IAAMC,EAA0B,IAE1BC,GAA8B,MAcvBC,EAAN,KAAiB,CAKpB,YAAoBC,EAAuBC,EAA4CC,EAAiB,CAApF,YAAAF,EAAuB,iBAAAC,EAA4C,YAAAC,EACnF,KAAK,qBAAuB,OAAO,gBAAoB,KAAe,OAAO,SAAa,GAC9F,CANQ,aAAe,IAAI,IACnB,qBACA,0BAA4B,GAY5B,UACJC,EACAC,EACAC,EACAC,EACAC,EACF,CACE,IAAMC,EAAQD,EAAO,KAAK,MAAQA,EAAO,MACnCE,EAAQF,EAAO,KAAK,OAASA,EAAO,MACpCG,EAAOJ,EAAQ,EAAIK,EAAkB,YACrCC,EAAON,EAAQ,EAAIK,EAAkB,YACrCE,EAAOP,EAAQ,EAAIE,EAAQG,EAAkB,YAC7CG,EAAOR,EAAQ,EAAIG,EAAQE,EAAkB,YACnD,OAAOR,EAAIE,GAAaK,GAAQP,EAAIE,GAAaQ,GAAQT,EAAIC,GAAaO,GAAQR,EAAIC,GAAaS,CACvG,CAEQ,kBAAkBR,EAAiBC,EAA0C,CACjF,IAAMC,EAAQD,EAAO,KAAK,MAAQA,EAAO,MACnCE,EAAQF,EAAO,KAAK,OAASA,EAAO,MAC1C,MAAO,CACH,KAAMD,EAAQ,EAAIK,EAAkB,YACpC,KAAML,EAAQ,EAAIK,EAAkB,YACpC,KAAML,EAAQ,EAAIE,EAAQG,EAAkB,YAC5C,KAAML,EAAQ,EAAIG,EAAQE,EAAkB,WAChD,CACJ,CAEA,gBACII,EACAC,EAAgB,EACL,CACX,OAAO,KAAK,OAAO,IAAIA,EAAO,CAAC,CAAE,IAAAC,EAAK,OAAAV,EAAQ,QAAAD,CAAQ,IAAM,CACxDS,EAAGE,EAAKX,EAASC,CAAM,CAC3B,CAAC,CACL,CAEA,SAASW,EAA2BF,EAAgB,EAAgB,CAChE,IAAMG,EAAO,MAAM,QAAQD,CAAK,EAAIA,EAAQ,CAACA,CAAK,EAI5CE,EADkBD,EAAK,OAAStB,EACCwB,EAAa,UAAUF,CAAI,EAAI,KAEtE,OAAO,KAAK,OAAO,IAAIH,EAAO,CAAC,CAAE,IAAAC,EAAK,OAAAV,EAAQ,QAAAD,CAAQ,IAAM,CACxD,IAAMgB,EAAS,KAAK,kBAAkBhB,EAASC,CAAM,EAC/CgB,EAAeH,EACfA,EAAa,MAAME,EAAO,KAAMA,EAAO,KAAMA,EAAO,KAAMA,EAAO,IAAI,EACrEH,EAENF,EAAI,KAAK,EACT,IAAIO,EACAC,EACAC,EAEJ,QAAWC,KAAQJ,EAAc,CAC7B,IAAMK,EAAOD,EAAK,MAAQ,EACpBE,EAAS,CACX,KAAMF,EAAK,QAAQ,OAAS,OAAS,OAAU,OAC/C,EAAGA,EAAK,QAAQ,GAAK,GACrB,EAAGA,EAAK,QAAQ,GAAK,EACzB,EACMG,EAAQH,EAAK,MAGnB,GAAI,CAACP,GAAgB,CAAC,KAAK,UAAUO,EAAK,EAAGA,EAAK,EAAGC,EAAO,EAAGtB,EAASC,CAAM,EAAG,SAEjF,IAAMwB,EAAM,KAAK,YAAY,cAAcJ,EAAK,EAAGA,EAAK,CAAC,EACnDK,EAASJ,EAAO,KAAK,OAAO,MAC5B,CAAE,EAAGK,EAAO,EAAGC,CAAM,EAAI,KAAK,oBAAoBH,EAAKC,EAAQH,EAAQ,KAAK,MAAM,EAGpFC,GAAO,WAAaA,EAAM,YAAcN,IACxCP,EAAI,UAAYa,EAAM,UACtBN,EAAgBM,EAAM,WAEtBA,GAAO,aAAeA,EAAM,cAAgBL,IAC5CR,EAAI,YAAca,EAAM,YACxBL,EAAkBK,EAAM,aAExBA,GAAO,WAAaA,EAAM,YAAcJ,IACxCT,EAAI,UAAYa,EAAM,UACtBJ,EAAgBI,EAAM,WAG1B,IAAMK,EAAcR,EAAK,QAAU,EAC7BS,EAAWD,GAAe,KAAK,GAAK,KAEpCE,EAASV,EAAK,OAEpB,GAAIQ,IAAgB,EAAG,CACnB,IAAMG,EAAUL,EAAQD,EAAS,EAC3BO,EAAUL,EAAQF,EAAS,EACjCf,EAAI,KAAK,EACTA,EAAI,UAAUqB,EAASC,CAAO,EAC9BtB,EAAI,OAAOmB,CAAQ,EACnBnB,EAAI,UAAU,EACVoB,GAAUpB,EAAI,UACdA,EAAI,UAAU,CAACe,EAAS,EAAG,CAACA,EAAS,EAAGA,EAAQA,EAAQK,CAAM,EAE9DpB,EAAI,KAAK,CAACe,EAAS,EAAG,CAACA,EAAS,EAAGA,EAAQA,CAAM,EAEjDF,GAAO,WAAWb,EAAI,KAAK,EAC3Ba,GAAO,aAAab,EAAI,OAAO,EACnCA,EAAI,QAAQ,CAChB,MACIA,EAAI,UAAU,EACVoB,GAAUpB,EAAI,UACdA,EAAI,UAAUgB,EAAOC,EAAOF,EAAQA,EAAQK,CAAM,EAElDpB,EAAI,KAAKgB,EAAOC,EAAOF,EAAQA,CAAM,EAErCF,GAAO,WAAWb,EAAI,KAAK,EAC3Ba,GAAO,aAAab,EAAI,OAAO,CAE3C,CACAA,EAAI,QAAQ,CAChB,CAAC,CACL,CAEA,SACIC,EACAY,EACAd,EAAgB,EACL,CACX,IAAMG,EAAO,MAAM,QAAQD,CAAK,EAAIA,EAAQ,CAACA,CAAK,EAElD,OAAO,KAAK,OAAO,IAAIF,EAAO,CAAC,CAAE,IAAAC,EAAK,OAAAV,EAAQ,QAAAD,CAAQ,IAAM,CACxDW,EAAI,KAAK,EACLa,GAAO,cAAab,EAAI,YAAca,EAAM,aAC5CA,GAAO,YAAWb,EAAI,UAAYa,EAAM,WAE5Cb,EAAI,UAAU,EACd,QAAWU,KAAQR,EAAM,CACrB,IAAMmB,GAAWX,EAAK,KAAK,EAAIA,EAAK,GAAG,GAAK,EACtCY,GAAWZ,EAAK,KAAK,EAAIA,EAAK,GAAG,GAAK,EACtCa,EAAa,KAAK,IAAI,KAAK,IAAIb,EAAK,KAAK,EAAIA,EAAK,GAAG,CAAC,EAAG,KAAK,IAAIA,EAAK,KAAK,EAAIA,EAAK,GAAG,CAAC,CAAC,EAAI,EACpG,GAAI,CAAC,KAAK,UAAUW,EAASC,EAASC,EAAYlC,EAASC,CAAM,EAAG,SAEpE,IAAMkC,EAAI,KAAK,YAAY,cAAcd,EAAK,KAAK,EAAGA,EAAK,KAAK,CAAC,EAC3De,EAAI,KAAK,YAAY,cAAcf,EAAK,GAAG,EAAGA,EAAK,GAAG,CAAC,EAE7DV,EAAI,OAAOwB,EAAE,EAAGA,EAAE,CAAC,EACnBxB,EAAI,OAAOyB,EAAE,EAAGA,EAAE,CAAC,CACvB,CACAzB,EAAI,OAAO,EACXA,EAAI,QAAQ,CAChB,CAAC,CACL,CAEA,WAAWC,EAA+BF,EAAgB,EAAgB,CACtE,IAAMG,EAAO,MAAM,QAAQD,CAAK,EAAIA,EAAQ,CAACA,CAAK,EAI5CE,EADkBD,EAAK,OAAStB,EACCwB,EAAa,UAAUF,CAAI,EAAI,KAEtE,OAAO,KAAK,OAAO,IAAIH,EAAO,CAAC,CAAE,IAAAC,EAAK,OAAAV,EAAQ,QAAAD,CAAQ,IAAM,CACxD,IAAMgB,EAAS,KAAK,kBAAkBhB,EAASC,CAAM,EAC/CgB,EAAeH,EACfA,EAAa,MAAME,EAAO,KAAMA,EAAO,KAAMA,EAAO,KAAMA,EAAO,IAAI,EACrEH,EAENF,EAAI,KAAK,EACT,IAAIO,EACAC,EACAC,EAEJ,QAAWC,KAAQJ,EAAc,CAC7B,IAAMK,EAAOD,EAAK,MAAQ,EACpBE,EAAS,CACX,KAAMF,EAAK,QAAQ,OAAS,OAAS,OAAU,OAC/C,EAAGA,EAAK,QAAQ,GAAK,GACrB,EAAGA,EAAK,QAAQ,GAAK,EACzB,EACMG,EAAQH,EAAK,MAGnB,GAAI,CAACP,GAAgB,CAAC,KAAK,UAAUO,EAAK,EAAGA,EAAK,EAAGC,EAAO,EAAGtB,EAASC,CAAM,EAAG,SAEjF,IAAMwB,EAAM,KAAK,YAAY,cAAcJ,EAAK,EAAGA,EAAK,CAAC,EACnDK,EAASJ,EAAO,KAAK,OAAO,MAC5BS,EAASL,EAAS,EAClB,CAAEC,EAAU,EAAGC,CAAM,EAAI,KAAK,oBAAoBH,EAAKC,EAAQH,EAAQ,KAAK,MAAM,EAGpFC,GAAO,WAAaA,EAAM,YAAcN,IACxCP,EAAI,UAAYa,EAAM,UACtBN,EAAgBM,EAAM,WAEtBA,GAAO,aAAeA,EAAM,cAAgBL,IAC5CR,EAAI,YAAca,EAAM,YACxBL,EAAkBK,EAAM,aAExBA,GAAO,WAAaA,EAAM,YAAcJ,IACxCT,EAAI,UAAYa,EAAM,UACtBJ,EAAgBI,EAAM,WAG1Bb,EAAI,UAAU,EACdA,EAAI,IAAIgB,EAAQI,EAAQH,EAAQG,EAAQA,EAAQ,EAAG,KAAK,GAAK,CAAC,EAC1DP,GAAO,WAAWb,EAAI,KAAK,EAC3Ba,GAAO,aAAab,EAAI,OAAO,CACvC,CACAA,EAAI,QAAQ,CAChB,CAAC,CACL,CAEA,SACIC,EACAY,EACAd,EAAgB,EACL,CACX,IAAMG,EAAO,MAAM,QAAQD,CAAK,EAAIA,EAAQ,CAACA,CAAK,EAElD,OAAO,KAAK,OAAO,IAAIF,EAAO,CAAC,CAAE,IAAAC,EAAK,OAAAV,EAAQ,QAAAD,CAAQ,IAAM,CACxDW,EAAI,KAAK,EACLa,GAAO,OAAMb,EAAI,KAAOa,EAAM,MAC9BA,GAAO,YAAWb,EAAI,UAAYa,EAAM,WAC5Cb,EAAI,UAAYa,GAAO,WAAa,SACpCb,EAAI,aAAea,GAAO,cAAgB,SAE1C,QAAWH,KAAQR,EAAM,CACrB,GAAI,CAAC,KAAK,UAAUQ,EAAK,OAAO,EAAGA,EAAK,OAAO,EAAG,EAAGrB,EAASC,CAAM,EAAG,SACvE,IAAMwB,EAAM,KAAK,YAAY,cAAcJ,EAAK,OAAO,EAAGA,EAAK,OAAO,CAAC,EACvEV,EAAI,SAASU,EAAK,KAAMI,EAAI,EAAGA,EAAI,CAAC,CACxC,CACAd,EAAI,QAAQ,CAChB,CAAC,CACL,CAEA,SACIC,EACAY,EACAd,EAAgB,EACL,CACX,IAAMG,EAAO,MAAM,QAAQD,EAAM,CAAC,CAAC,EAAKA,EAA4B,CAACA,CAAiB,EAEtF,OAAO,KAAK,OAAO,IAAIF,EAAO,CAAC,CAAE,IAAAC,EAAK,OAAAV,EAAQ,QAAAD,CAAQ,IAAM,CACxDW,EAAI,KAAK,EACLa,GAAO,cAAab,EAAI,YAAca,EAAM,aAC5CA,GAAO,YAAWb,EAAI,UAAYa,EAAM,WAE5Cb,EAAI,UAAU,EACd,QAAW0B,KAAUxB,EAAM,CACvB,GAAI,CAACwB,EAAO,OAAQ,SACpB,IAAMC,EAAKD,EAAO,IAAKE,GAAMA,EAAE,CAAC,EAC1BC,EAAKH,EAAO,IAAKE,GAAMA,EAAE,CAAC,EAC1BnC,EAAO,KAAK,IAAI,GAAGkC,CAAE,EACrB/B,EAAO,KAAK,IAAI,GAAG+B,CAAE,EACrBhC,EAAO,KAAK,IAAI,GAAGkC,CAAE,EACrBhC,EAAO,KAAK,IAAI,GAAGgC,CAAE,EACrBR,GAAW5B,EAAOG,GAAQ,EAC1B0B,GAAW3B,EAAOE,GAAQ,EAC1B0B,EAAa,KAAK,IAAI3B,EAAOH,EAAMI,EAAOF,CAAI,EAAI,EACxD,GAAI,CAAC,KAAK,UAAU0B,EAASC,EAASC,EAAYlC,EAASC,CAAM,EAAG,SAEpE,IAAMwC,EAAQ,KAAK,YAAY,cAAcJ,EAAO,CAAC,EAAE,EAAGA,EAAO,CAAC,EAAE,CAAC,EACrE1B,EAAI,OAAO8B,EAAM,EAAGA,EAAM,CAAC,EAE3B,QAASC,EAAI,EAAGA,EAAIL,EAAO,OAAQK,IAAK,CACpC,IAAMH,EAAI,KAAK,YAAY,cAAcF,EAAOK,CAAC,EAAE,EAAGL,EAAOK,CAAC,EAAE,CAAC,EACjE/B,EAAI,OAAO4B,EAAE,EAAGA,EAAE,CAAC,CACvB,CACJ,CACA5B,EAAI,OAAO,EACXA,EAAI,QAAQ,CAChB,CAAC,CACL,CAEA,UAAUC,EAAqCF,EAAgB,EAAgB,CAC3E,IAAMG,EAAO,MAAM,QAAQD,CAAK,EAAIA,EAAQ,CAACA,CAAK,EAI5CE,EADkBD,EAAK,OAAStB,EACCwB,EAAa,UAAUF,CAAI,EAAI,KAEtE,OAAO,KAAK,OAAO,IAAIH,EAAO,CAAC,CAAE,IAAAC,EAAK,OAAAV,EAAQ,QAAAD,CAAQ,IAAM,CACxD,IAAMgB,EAAS,KAAK,kBAAkBhB,EAASC,CAAM,EAC/CgB,EAAeH,EACfA,EAAa,MAAME,EAAO,KAAMA,EAAO,KAAMA,EAAO,KAAMA,EAAO,IAAI,EACrEH,EAEN,QAAWQ,KAAQJ,EAAc,CAC7B,IAAMK,EAAOD,EAAK,MAAQ,EACpBE,EAAS,CACX,KAAMF,EAAK,QAAQ,OAAS,OAAS,OAAU,OAC/C,EAAGA,EAAK,QAAQ,GAAK,GACrB,EAAGA,EAAK,QAAQ,GAAK,EACzB,EAGA,GAAI,CAACP,GAAgB,CAAC,KAAK,UAAUO,EAAK,EAAGA,EAAK,EAAGC,EAAO,EAAGtB,EAASC,CAAM,EAAG,SAEjF,IAAMwB,EAAM,KAAK,YAAY,cAAcJ,EAAK,EAAGA,EAAK,CAAC,EACnDK,EAASJ,EAAO,KAAK,OAAO,MAG5BqB,EAAStB,EAAK,IAAI,MAAQA,EAAK,IAAI,OAErCuB,EAAQlB,EACRmB,EAAQnB,EAERiB,EAAS,EAAGE,EAAQnB,EAASiB,EAC5BC,EAAQlB,EAASiB,EAGtB,GAAM,CAAE,EAAGG,EAAO,EAAGC,CAAM,EAAI,KAAK,oBAAoBtB,EAAKC,EAAQH,EAAQ,KAAK,MAAM,EAElFyB,EAAUF,GAASpB,EAASkB,GAAS,EACrCK,EAAUF,GAASrB,EAASmB,GAAS,EAErChB,EAAcR,EAAK,QAAU,EAC7BS,EAAWD,GAAe,KAAK,GAAK,KAE1C,GAAIA,IAAgB,EAAG,CACnB,IAAMG,EAAUgB,EAAUJ,EAAQ,EAC5BX,EAAUgB,EAAUJ,EAAQ,EAClClC,EAAI,KAAK,EACTA,EAAI,UAAUqB,EAASC,CAAO,EAC9BtB,EAAI,OAAOmB,CAAQ,EACnBnB,EAAI,UAAUU,EAAK,IAAK,CAACuB,EAAQ,EAAG,CAACC,EAAQ,EAAGD,EAAOC,CAAK,EAC5DlC,EAAI,QAAQ,CAChB,MACIA,EAAI,UAAUU,EAAK,IAAK2B,EAASC,EAASL,EAAOC,CAAK,CAE9D,CACJ,CAAC,CACL,CAEA,cAAcK,EAAkB1B,EAAmDd,EAAgB,EAAgB,CAC/G,OAAO,KAAK,OAAO,IAAIA,EAAO,CAAC,CAAE,IAAAC,EAAK,OAAAV,EAAQ,QAAAD,CAAQ,IAAM,CACxD,IAAME,EAAQD,EAAO,KAAK,MAAQA,EAAO,MACnCE,EAAQF,EAAO,KAAK,OAASA,EAAO,MAEpCkD,EAAS,KAAK,MAAMnD,EAAQ,EAAIkD,CAAQ,EAAIA,EAAWE,EAAe,mBACtEC,EAAO,KAAK,MAAMrD,EAAQ,EAAIE,GAASgD,CAAQ,EAAIA,EAAWE,EAAe,mBAC7EE,EAAS,KAAK,MAAMtD,EAAQ,EAAIkD,CAAQ,EAAIA,EAAWE,EAAe,mBACtEG,EAAO,KAAK,MAAMvD,EAAQ,EAAIG,GAAS+C,CAAQ,EAAIA,EAAWE,EAAe,mBAEnFzC,EAAI,KAAK,EAETA,EAAI,YAAca,EAAM,YACxBb,EAAI,UAAYa,EAAM,UAEtBb,EAAI,UAAU,EAEd,QAASd,EAAIsD,EAAQtD,GAAKwD,EAAMxD,GAAKqD,EAAU,CAC3C,IAAMM,EAAK,KAAK,YAAY,cAAc3D,EAAGyD,CAAM,EAC7CG,EAAK,KAAK,YAAY,cAAc5D,EAAG0D,CAAI,EACjD5C,EAAI,OAAO6C,EAAG,EAAGA,EAAG,CAAC,EACrB7C,EAAI,OAAO8C,EAAG,EAAGA,EAAG,CAAC,CACzB,CAEA,QAAS3D,EAAIwD,EAAQxD,GAAKyD,EAAMzD,GAAKoD,EAAU,CAC3C,IAAMM,EAAK,KAAK,YAAY,cAAcL,EAAQrD,CAAC,EAC7C2D,EAAK,KAAK,YAAY,cAAcJ,EAAMvD,CAAC,EACjDa,EAAI,OAAO6C,EAAG,EAAGA,EAAG,CAAC,EACrB7C,EAAI,OAAO8C,EAAG,EAAGA,EAAG,CAAC,CACzB,CAEA9C,EAAI,OAAO,EACXA,EAAI,QAAQ,CAChB,CAAC,CACL,CAEQ,oBACJc,EACAC,EACAH,EACA3B,EACF,CACE,GAAI2B,EAAO,OAAS,OAAQ,CACxB,IAAMmC,EAAO9D,EAAO,MACpB,MAAO,CACH,EAAG6B,EAAI,EAAIiC,EAAO,EAAInC,EAAO,EAAImC,EAAOhC,EAAS,EACjD,EAAGD,EAAI,EAAIiC,EAAO,EAAInC,EAAO,EAAImC,EAAOhC,EAAS,CACrD,CACJ,CAEA,MAAO,CACH,EAAGD,EAAI,EAAIF,EAAO,EAAIG,EACtB,EAAGD,EAAI,EAAIF,EAAO,EAAIG,CAC1B,CACJ,CAMQ,uBACJd,EACA+C,EACAC,EAOkB,CAClB,GAAI,CAAC,KAAK,qBACN,OAAK,KAAK,4BACN,QAAQ,KAAK,oEAAoE,EACjF,KAAK,0BAA4B,IAE9B,KAIX,IAAIxD,EAAO,IACPG,EAAO,KACPD,EAAO,IACPE,EAAO,KAEX,QAAWa,KAAQT,EAAO,CACtB,IAAMU,EAAOD,EAAK,MAAQ,EACtBA,EAAK,EAAIC,EAAO,EAAIlB,IAAMA,EAAOiB,EAAK,EAAIC,EAAO,GACjDD,EAAK,EAAIC,EAAO,EAAIf,IAAMA,EAAOc,EAAK,EAAIC,EAAO,GACjDD,EAAK,EAAIC,EAAO,EAAIhB,IAAMA,EAAOe,EAAK,EAAIC,EAAO,GACjDD,EAAK,EAAIC,EAAO,EAAId,IAAMA,EAAOa,EAAK,EAAIC,EAAO,EACzD,CAGAlB,GAAQ,EACRE,GAAQ,EACRC,GAAQ,EACRC,GAAQ,EAER,IAAMqD,EAAatD,EAAOH,EACpB0D,EAActD,EAAOF,EAGrByD,EAAc,KAAK,OAAO,MAC1BC,EAAc,KAAK,KAAKH,EAAaE,CAAW,EAChDE,EAAe,KAAK,KAAKH,EAAcC,CAAW,EAExD,GAAIC,EAAcxE,IAA+ByE,EAAezE,GAC5D,OAAK,KAAK,4BACN,QAAQ,KAAK,sDAAsDwE,CAAW,IAAIC,CAAY,IAAI,EAClG,KAAK,0BAA4B,IAE9B,KAIX,IAAIC,EAAQ,KAAK,aAAa,IAAIP,CAAQ,EAS1C,GAPI,CAACO,GACDA,EAAM,QAAUH,GAChBG,EAAM,YAAY,OAAS9D,GAC3B8D,EAAM,YAAY,OAAS3D,GAC3B2D,EAAM,YAAY,OAAS5D,GAC3B4D,EAAM,YAAY,OAAS1D,EAEb,CAEd,IAAM2D,EACF,OAAO,gBAAoB,IACrB,IAAI,gBAAgBH,EAAaC,CAAY,EAC7C,SAAS,cAAc,QAAQ,EAGf,OAAO,gBAAoB,KAAeE,aAAqB,kBAGpFA,EAAgC,MAAQH,EACxCG,EAAgC,OAASF,GAG9C,IAAMG,EAASD,EAAU,WAAW,IAAI,EAExC,GAAI,CAACC,EACD,OAAK,KAAK,4BACN,QAAQ,KAAK,6DAA6D,EAC1E,KAAK,0BAA4B,IAE9B,KAIX,QAAW/C,KAAQT,EAAO,CAEtB,IAAMc,GADOL,EAAK,MAAQ,GACJ0C,EAChB,GAAK1C,EAAK,EAAI+B,EAAe,mBAAqBhD,GAAQ2D,EAAcrC,EAAS,EACjF5B,GAAKuB,EAAK,EAAI+B,EAAe,mBAAqB9C,GAAQyD,EAAcrC,EAAS,EAEvFkC,EAASQ,EAAQ/C,EAAM,EAAGvB,EAAG4B,CAAM,CACvC,CAEAwC,EAAQ,CACJ,OAAQC,EACR,IAAKC,EACL,YAAa,CAAE,KAAAhE,EAAM,KAAAE,EAAM,KAAAC,EAAM,KAAAC,CAAK,EACtC,MAAOuD,CACX,EAEA,KAAK,aAAa,IAAIJ,EAAUO,CAAK,CACzC,CAEA,OAAOA,GAAS,IACpB,CAKQ,oBAAoBA,EAA2BxD,EAAmC,CACtF,GAAI,CAACwD,EACD,OAAO,KAEX,IAAMG,EAAeH,EAAM,OACrBI,EAAeJ,EAAM,YACrBK,EAAcL,EAAM,MAE1B,OAAO,KAAK,OAAO,IAAIxD,EAAO,CAAC,CAAE,IAAAC,EAAK,OAAAV,EAAQ,QAAAD,CAAQ,IAAM,CACxD,IAAME,EAAQD,EAAO,KAAK,MAAQA,EAAO,MACnCE,EAAQF,EAAO,KAAK,OAASA,EAAO,MAGpCuE,GAAQxE,EAAQ,EAAIsE,EAAa,MAAQC,EACzCE,GAAQzE,EAAQ,EAAIsE,EAAa,MAAQC,EACzCG,EAAOxE,EAAQqE,EACfI,EAAOxE,EAAQoE,EAGrB5D,EAAI,UAAU0D,EAAcG,EAAMC,EAAMC,EAAMC,EAAM,EAAG,EAAG1E,EAAO,KAAK,MAAOA,EAAO,KAAK,MAAM,CACnG,CAAC,CACL,CAUA,eAAeW,EAAoB+C,EAAkBjD,EAAgB,EAAgB,CACjF,IAAIQ,EAEEgD,EAAQ,KAAK,uBAAuBtD,EAAO+C,EAAU,CAAChD,EAAKU,EAAMxB,EAAGC,EAAG4B,IAAW,CACpF,IAAMF,EAAQH,EAAK,MACbQ,EAAcR,EAAK,QAAU,EAC7BS,EAAWD,GAAe,KAAK,GAAK,KACpCE,EAASV,EAAK,OAOpB,GALIG,GAAO,WAAaA,EAAM,YAAcN,IACxCP,EAAI,UAAYa,EAAM,UACtBN,EAAgBM,EAAM,WAGtBK,IAAgB,EAAG,CACnB,IAAMG,EAAUnC,EAAI6B,EAAS,EACvBO,EAAUnC,EAAI4B,EAAS,EAC7Bf,EAAI,KAAK,EACTA,EAAI,UAAUqB,EAASC,CAAO,EAC9BtB,EAAI,OAAOmB,CAAQ,EACfC,GAAUpB,EAAI,WACdA,EAAI,UAAU,EACdA,EAAI,UAAU,CAACe,EAAS,EAAG,CAACA,EAAS,EAAGA,EAAQA,EAAQK,CAAM,EAC9DpB,EAAI,KAAK,GAETA,EAAI,SAAS,CAACe,EAAS,EAAG,CAACA,EAAS,EAAGA,EAAQA,CAAM,EAEzDf,EAAI,QAAQ,CAChB,MACQoB,GAAUpB,EAAI,WACdA,EAAI,UAAU,EACdA,EAAI,UAAUd,EAAGC,EAAG4B,EAAQA,EAAQK,CAAM,EAC1CpB,EAAI,KAAK,GAETA,EAAI,SAASd,EAAGC,EAAG4B,EAAQA,CAAM,CAG7C,CAAC,EAED,OAAKwC,EAIE,KAAK,oBAAoBA,EAAOxD,CAAK,EAHjC,KAAK,SAASE,EAAOF,CAAK,CAIzC,CAUA,gBAAgBE,EAAyB+C,EAAkBjD,EAAgB,EAAgB,CACvF,IAAMwD,EAAQ,KAAK,uBAAuBtD,EAAO+C,EAAU,CAAChD,EAAKU,EAAMxB,EAAGC,EAAG4B,IAAW,CACpF,IAAMkD,EAAOvD,EAAmC,IAC1CQ,EAAeR,EAA6B,QAAU,EACtDS,EAAWD,GAAe,KAAK,GAAK,KACpCc,EAASiC,EAAI,MAAQA,EAAI,OAC3BhC,EAAQlB,EACRmB,EAAQnB,EAERiB,EAAS,EAAGE,EAAQnB,EAASiB,EAC5BC,EAAQlB,EAASiB,EAGtB,IAAMkC,EAAOhF,GAAK6B,EAASkB,GAAS,EAC9BkC,EAAOhF,GAAK4B,EAASmB,GAAS,EAEpC,GAAIhB,IAAgB,EAAG,CACnB,IAAMG,EAAU6C,EAAOjC,EAAQ,EACzBX,EAAU6C,EAAOjC,EAAQ,EAC/BlC,EAAI,KAAK,EACTA,EAAI,UAAUqB,EAASC,CAAO,EAC9BtB,EAAI,OAAOmB,CAAQ,EACnBnB,EAAI,UAAUiE,EAAK,CAAChC,EAAQ,EAAG,CAACC,EAAQ,EAAGD,EAAOC,CAAK,EACvDlC,EAAI,QAAQ,CAChB,MACIA,EAAI,UAAUiE,EAAKC,EAAMC,EAAMlC,EAAOC,CAAK,CAEnD,CAAC,EAED,OAAKqB,EAIE,KAAK,oBAAoBA,EAAOxD,CAAK,EAHjC,KAAK,UAAUE,EAAOF,CAAK,CAI1C,CAUA,iBAAiBE,EAAsB+C,EAAkBjD,EAAgB,EAAgB,CACrF,IAAIQ,EAEEgD,EAAQ,KAAK,uBAAuBtD,EAAO+C,EAAU,CAAChD,EAAKU,EAAMxB,EAAGC,EAAG4B,IAAW,CACpF,IAAMF,EAAQH,EAAK,MACbU,EAASL,EAAS,EAEpBF,GAAO,WAAaA,EAAM,YAAcN,IACxCP,EAAI,UAAYa,EAAM,UACtBN,EAAgBM,EAAM,WAG1Bb,EAAI,UAAU,EACdA,EAAI,IAAId,EAAIkC,EAAQjC,EAAIiC,EAAQA,EAAQ,EAAG,KAAK,GAAK,CAAC,EACtDpB,EAAI,KAAK,CACb,CAAC,EAED,OAAKuD,EAIE,KAAK,oBAAoBA,EAAOxD,CAAK,EAHjC,KAAK,WAAWE,EAAOF,CAAK,CAI3C,CAMA,iBAAiBiD,EAAmB,CAC5BA,EACA,KAAK,aAAa,OAAOA,CAAQ,EAEjC,KAAK,aAAa,MAAM,CAEhC,CAKA,SAAU,CACN,KAAK,aAAa,MAAM,EACxB,KAAK,OAAO,MAAM,CACtB,CACJ,EC5rBO,IAAMoB,EAAN,KAAkB,CACrB,YAAoBC,EAAmCC,EAAsB,CAAzD,YAAAD,EAAmC,cAAAC,CAAuB,CAE9E,QAAS,CACD,KAAK,SAAS,OACd,KAAK,OAAO,iBAAiB,QAAS,KAAK,SAAS,KAAK,EAGzD,KAAK,SAAS,WACd,KAAK,OAAO,iBAAiB,YAAa,KAAK,SAAS,SAAS,EAGjE,KAAK,SAAS,WACd,KAAK,OAAO,iBAAiB,YAAa,KAAK,SAAS,SAAS,EAGjE,KAAK,SAAS,SACd,KAAK,OAAO,iBAAiB,UAAW,KAAK,SAAS,OAAO,EAG7D,KAAK,SAAS,YACd,KAAK,OAAO,iBAAiB,aAAc,KAAK,SAAS,UAAU,EAGnE,KAAK,SAAS,OACd,KAAK,OAAO,iBAAiB,QAAS,KAAK,SAAS,MAAO,CAAE,QAAS,EAAM,CAAC,EAG7E,KAAK,SAAS,YACd,KAAK,OAAO,iBAAiB,aAAc,KAAK,SAAS,WAAY,CAAE,QAAS,EAAM,CAAC,EAGvF,KAAK,SAAS,WACd,KAAK,OAAO,iBAAiB,YAAa,KAAK,SAAS,UAAW,CAAE,QAAS,EAAM,CAAC,EAGrF,KAAK,SAAS,UACd,KAAK,OAAO,iBAAiB,WAAY,KAAK,SAAS,SAAU,CAAE,QAAS,EAAM,CAAC,CAE3F,CAEA,QAAS,CACD,KAAK,SAAS,OACd,KAAK,OAAO,oBAAoB,QAAS,KAAK,SAAS,KAAK,EAG5D,KAAK,SAAS,WACd,KAAK,OAAO,oBAAoB,YAAa,KAAK,SAAS,SAAS,EAGpE,KAAK,SAAS,WACd,KAAK,OAAO,oBAAoB,YAAa,KAAK,SAAS,SAAS,EAGpE,KAAK,SAAS,SACd,KAAK,OAAO,oBAAoB,UAAW,KAAK,SAAS,OAAO,EAGhE,KAAK,SAAS,YACd,KAAK,OAAO,oBAAoB,aAAc,KAAK,SAAS,UAAU,EAGtE,KAAK,SAAS,OACd,KAAK,OAAO,oBAAoB,QAAS,KAAK,SAAS,KAAK,EAG5D,KAAK,SAAS,YACd,KAAK,OAAO,oBAAoB,aAAc,KAAK,SAAS,UAAU,EAGtE,KAAK,SAAS,WACd,KAAK,OAAO,oBAAoB,YAAa,KAAK,SAAS,SAAS,EAGpE,KAAK,SAAS,UACd,KAAK,OAAO,oBAAoB,WAAY,KAAK,SAAS,QAAQ,CAE1E,CACJ,ECpFO,IAAMC,EAAN,KAAwB,CAgB3B,YACYC,EACAC,EACAC,EACAC,EACAC,EACAC,EACV,CANU,YAAAL,EACA,YAAAC,EACA,cAAAC,EACA,YAAAC,EACA,iBAAAC,EACA,oBAAAC,CACT,CAtBK,WAAa,GACb,mBAAqB,GACrB,QAAU,CAAE,EAAG,EAAG,EAAG,CAAE,EAGvB,WAAa,GACb,kBAAoB,EACpB,gBAAkB,CAAE,EAAG,EAAG,EAAG,CAAE,EAEhC,QACA,QACA,YACA,UACA,aAWP,YAAe,GAAkB,CAC7B,GAAI,KAAK,mBAAoB,CACzB,KAAK,mBAAqB,GAC1B,MACJ,CACA,GAAI,CAAC,KAAK,OAAO,IAAI,EAAE,cAAc,OAAS,CAAC,KAAK,QAChD,OAEJ,IAAMC,EAAO,KAAK,OAAO,sBAAsB,EACzCC,EAAS,EAAE,QAAUD,EAAK,KAC1BE,EAAS,EAAE,QAAUF,EAAK,IAC1BG,EAAQ,KAAK,YAAY,cAAcF,EAAQC,CAAM,EACrDE,EAAS,KAAK,YAAY,cAAc,KAAK,MAAMD,EAAM,CAAC,EAAG,KAAK,MAAMA,EAAM,CAAC,CAAC,EAEtF,KAAK,QACD,CACI,IAAKA,EACL,QAAS,CAAE,EAAG,KAAK,MAAMA,EAAM,CAAC,EAAG,EAAG,KAAK,MAAMA,EAAM,CAAC,CAAE,CAC9D,EACA,CACI,IAAK,CAAE,EAAG,EAAE,QAAUH,EAAK,KAAM,EAAG,EAAE,QAAUA,EAAK,GAAI,EACzD,QAAS,CACL,EAAGI,EAAO,EACV,EAAGA,EAAO,CACd,CACJ,EACA,CACI,IAAK,CAAE,EAAG,EAAE,QAAS,EAAG,EAAE,OAAQ,EAClC,QAAS,CACL,EAAGA,EAAO,EAAIJ,EAAK,KACnB,EAAGI,EAAO,EAAIJ,EAAK,GACvB,CACJ,CACJ,CACJ,EAEA,gBAAmB,GAAkB,CAC7B,KAAK,aACL,KAAK,YAAY,EAGhB,KAAK,OAAO,IAAI,EAAE,cAAc,OAIrC,KAAK,WAAa,GAClB,KAAK,mBAAqB,GAC1B,KAAK,QAAU,CAAE,EAAG,EAAE,QAAS,EAAG,EAAE,OAAQ,EAChD,EAEA,gBAAmB,GAAkB,CACjC,GAAI,CAAC,KAAK,WAAY,CAClB,GAAI,KAAK,SAAW,KAAK,OAAO,IAAI,EAAE,cAAc,MAAO,CACvD,IAAMA,EAAO,KAAK,OAAO,sBAAsB,EACzCC,EAAS,EAAE,QAAUD,EAAK,KAC1BE,EAAS,EAAE,QAAUF,EAAK,IAC1BG,EAAQ,KAAK,YAAY,cAAcF,EAAQC,CAAM,EACrDE,EAAS,KAAK,YAAY,cAAc,KAAK,MAAMD,EAAM,CAAC,EAAG,KAAK,MAAMA,EAAM,CAAC,CAAC,EAEtF,KAAK,QACD,CAAE,IAAKA,EAAO,QAAS,CAAE,EAAG,KAAK,MAAMA,EAAM,CAAC,EAAG,EAAG,KAAK,MAAMA,EAAM,CAAC,CAAE,CAAE,EAC1E,CACI,IAAK,CAAE,EAAG,EAAE,QAAUH,EAAK,KAAM,EAAG,EAAE,QAAUA,EAAK,GAAI,EACzD,QAAS,CACL,EAAGI,EAAO,EACV,EAAGA,EAAO,CACd,CACJ,EACA,CACI,IAAK,CAAE,EAAG,EAAE,QAAS,EAAG,EAAE,OAAQ,EAClC,QAAS,CACL,EAAGA,EAAO,EAAIJ,EAAK,KACnB,EAAGI,EAAO,EAAIJ,EAAK,GACvB,CACJ,CACJ,CACJ,CACA,MACJ,CAEA,IAAMK,EAAK,EAAE,QAAU,KAAK,QAAQ,EAC9BC,EAAK,EAAE,QAAU,KAAK,QAAQ,GAChCD,IAAO,GAAKC,IAAO,KACnB,KAAK,OAAO,MAAM,OAAS,KAAK,OAAO,IAAI,EAAE,OAAO,MAAQ,OAC5D,KAAK,mBAAqB,IAE9B,KAAK,OAAO,IAAID,EAAIC,CAAE,EACtB,KAAK,QAAU,CAAE,EAAG,EAAE,QAAS,EAAG,EAAE,OAAQ,EAC5C,KAAK,eAAe,CACxB,EAEA,cAAgB,IAAM,CACd,KAAK,WACL,KAAK,UAAU,EAGnB,KAAK,WAAa,GAClB,KAAK,OAAO,MAAM,OAAS,KAAK,OAAO,IAAI,EAAE,OAAO,SAAW,SACnE,EAEA,iBAAmB,IAAM,CACjB,KAAK,cACL,KAAK,aAAa,EAGtB,KAAK,WAAa,GAClB,KAAK,OAAO,MAAM,OAAS,KAAK,OAAO,IAAI,EAAE,OAAO,SAAW,SACnE,EAEA,iBAAoB,GAAkB,CAClC,IAAMC,EAAgB,KAAK,OAAO,IAAI,EAAE,cAGxC,GAAI,EAAE,QAAQ,SAAW,GAAKA,EAAc,KAAM,CAC9C,EAAE,eAAe,EACjB,KAAK,WAAa,GAClB,KAAK,WAAa,GAClB,KAAK,kBAAoB,KAAK,iBAAiB,EAAE,OAAO,EACxD,KAAK,gBAAkB,KAAK,eAAe,EAAE,OAAO,EACpD,MACJ,CAIA,GADI,CAACA,EAAc,MACf,EAAE,QAAQ,SAAW,EAAG,OAC5B,IAAMC,EAAI,EAAE,QAAQ,CAAC,EACrB,KAAK,WAAa,GAClB,KAAK,WAAa,GAClB,KAAK,mBAAqB,GAC1B,KAAK,QAAU,CAAE,EAAGA,EAAE,QAAS,EAAGA,EAAE,OAAQ,CAChD,EAEA,gBAAmB,GAAkB,CAEjC,GAAI,KAAK,YAAc,EAAE,QAAQ,SAAW,EAAG,CAC3C,EAAE,eAAe,EAEjB,IAAMC,EAAkB,KAAK,iBAAiB,EAAE,OAAO,EACjDC,EAAgB,KAAK,eAAe,EAAE,OAAO,EAC7CV,EAAO,KAAK,OAAO,sBAAsB,EAGzCW,EAAcF,EAAkB,KAAK,kBAGrCG,EAAUF,EAAc,EAAIV,EAAK,KACjCa,EAAUH,EAAc,EAAIV,EAAK,IAGvC,KAAK,OAAO,aAAaW,EAAaC,EAASC,CAAO,EAGtD,IAAMR,EAAKK,EAAc,EAAI,KAAK,gBAAgB,EAC5CJ,EAAKI,EAAc,EAAI,KAAK,gBAAgB,GAC9CL,IAAO,GAAKC,IAAO,IACnB,KAAK,OAAO,IAAID,EAAIC,CAAE,EAG1B,KAAK,kBAAoBG,EACzB,KAAK,gBAAkBC,EACvB,KAAK,eAAe,EACpB,MACJ,CAGA,GAAI,CAAC,KAAK,YAAc,EAAE,QAAQ,SAAW,EACzC,OAEJ,EAAE,eAAe,EACjB,IAAM,EAAI,EAAE,QAAQ,CAAC,EACfL,EAAK,EAAE,QAAU,KAAK,QAAQ,EAC9BC,EAAK,EAAE,QAAU,KAAK,QAAQ,GAChCD,IAAO,GAAKC,IAAO,KACnB,KAAK,OAAO,MAAM,OAAS,KAAK,OAAO,IAAI,EAAE,OAAO,MAAQ,OAC5D,KAAK,mBAAqB,IAE9B,KAAK,OAAO,IAAID,EAAIC,CAAE,EACtB,KAAK,QAAU,CAAE,EAAG,EAAE,QAAS,EAAG,EAAE,OAAQ,EAC5C,KAAK,eAAe,CACxB,EAEA,eAAkB,GAAkB,CAEhC,GAAI,EAAE,QAAQ,QAAU,GAAK,KAAK,WAAY,CAC1C,KAAK,kBAAoB,KAAK,iBAAiB,EAAE,OAAO,EACxD,KAAK,gBAAkB,KAAK,eAAe,EAAE,OAAO,EACpD,MACJ,CAGA,GAAI,EAAE,QAAQ,SAAW,GAAK,KAAK,WAAY,CAE3C,GADA,KAAK,WAAa,GACd,KAAK,OAAO,IAAI,EAAE,cAAc,KAAM,CACtC,KAAK,WAAa,GAClB,IAAM,EAAI,EAAE,QAAQ,CAAC,EACrB,KAAK,QAAU,CAAE,EAAG,EAAE,QAAS,EAAG,EAAE,OAAQ,CAChD,CACA,MACJ,CAGA,KAAK,WAAa,GAClB,KAAK,WAAa,GAClB,KAAK,OAAO,MAAM,OAAS,KAAK,OAAO,IAAI,EAAE,OAAO,SAAW,SACnE,EAKQ,iBAAiBQ,EAA4B,CACjD,IAAMT,EAAKS,EAAQ,CAAC,EAAE,QAAUA,EAAQ,CAAC,EAAE,QACrCR,EAAKQ,EAAQ,CAAC,EAAE,QAAUA,EAAQ,CAAC,EAAE,QAC3C,OAAO,KAAK,KAAKT,EAAKA,EAAKC,EAAKA,CAAE,CACtC,CAKQ,eAAeQ,EAA8C,CACjE,MAAO,CACH,GAAIA,EAAQ,CAAC,EAAE,QAAUA,EAAQ,CAAC,EAAE,SAAW,EAC/C,GAAIA,EAAQ,CAAC,EAAE,QAAUA,EAAQ,CAAC,EAAE,SAAW,CACnD,CACJ,CAEA,YAAe,GAAkB,CAC7B,GAAI,CAAC,KAAK,OAAO,IAAI,EAAE,cAAc,KAAM,OAC3C,EAAE,eAAe,EACjB,IAAMd,EAAO,KAAK,OAAO,sBAAsB,EAC/C,KAAK,OAAO,KAAK,EAAE,QAAS,EAAE,QAAS,EAAE,OAAQA,CAAI,EACrD,KAAK,eAAe,CACxB,CACJ,ECnQO,IAAMe,EAAN,KAAoB,CAOvB,YACYC,EACAC,EACAC,EACAC,EACAC,EACAC,EACV,CANU,aAAAL,EACA,YAAAC,EACA,cAAAC,EACA,YAAAC,EACA,YAAAC,EACA,oBAAAC,EAER,KAAK,WAAa,KAAK,SAAS,GACpC,CAfQ,eACA,mBACA,WAED,SAaP,OAAQ,CAEJ,KAAK,SAAS,UAAU,EACxB,KAAK,WAAa,KAAK,SAAS,IAEhC,IAAMC,EAAO,KAAK,SAAS,QAAQ,EAE7BC,EAAa,KAAK,OAAO,IAAI,EAAE,KAE/BC,EAAWD,GAAY,SACvBE,EAAYF,GAAY,UAExBG,EAAWH,GAAY,SACvBI,EAAYJ,GAAY,UAE9BD,EAAK,MAAQ,KAAK,MAAMA,EAAK,MAAOI,EAAUF,CAAQ,EACtDF,EAAK,OAAS,KAAK,MAAMA,EAAK,OAAQK,EAAWF,CAAS,EAE1D,OAAO,OAAO,KAAK,QAAQ,MAAO,CAC9B,OAAQ,OACR,SAAU,SACV,MAAO,GAAGH,EAAK,KAAK,KACpB,OAAQ,GAAGA,EAAK,MAAM,KACtB,YAAa,OACb,SAAU,WACV,SAAUE,EAAW,GAAGA,CAAQ,KAAO,GACvC,UAAWC,EAAY,GAAGA,CAAS,KAAO,GAC1C,SAAUC,EAAW,GAAGA,CAAQ,KAAO,GACvC,UAAWC,EAAY,GAAGA,CAAS,KAAO,EAC9C,CAAC,EAED,KAAK,eAAiB,IAAI,eAAgBC,GAAY,CAClD,QAAWC,KAASD,EAAS,CACzB,GAAM,CAAE,MAAOE,EAAM,OAAQC,CAAK,EAAIF,EAAM,YACtCG,EAAQ,KAAK,MAAMF,EAAMJ,EAAUF,CAAQ,EAC3CS,EAAS,KAAK,MAAMF,EAAMJ,EAAWF,CAAS,EAC9CS,EAAO,KAAK,SAAS,QAAQ,EAEnC,GAAIF,IAAUE,EAAK,OAASD,IAAWC,EAAK,OAExC,SAGJ,IAAMC,EAAQH,EAAQE,EAAK,MACrBE,EAAQH,EAASC,EAAK,OACtBG,EAAM,KAAK,SAAS,IAE1B,KAAK,OAAO,gBAAgBF,EAAOC,CAAK,EACxC,KAAK,SAAS,QAAQJ,EAAOC,CAAM,EAGnC,KAAK,OAAO,MAAQD,EAAQK,EAC5B,KAAK,OAAO,OAASJ,EAASI,EAG9B,KAAK,OAAO,MAAM,MAAQ,GAAGL,CAAK,KAClC,KAAK,OAAO,MAAM,OAAS,GAAGC,CAAM,KAEpC,KAAK,QAAQ,MAAM,MAAQ,GAAGD,CAAK,KACnC,KAAK,QAAQ,MAAM,OAAS,GAAGC,CAAM,KAEjC,KAAK,UACL,KAAK,SAAS,EAElB,KAAK,eAAe,CACxB,CACJ,CAAC,EAED,KAAK,eAAe,QAAQ,KAAK,OAAO,EAExC,KAAK,iBAAiB,CAC1B,CAEA,MAAO,CACC,KAAK,iBACL,KAAK,eAAe,UAAU,KAAK,OAAO,EAC1C,KAAK,eAAe,WAAW,GAGnC,KAAK,eAAiB,OAElB,KAAK,qBACL,OAAO,oBAAoB,SAAU,KAAK,kBAAkB,EAC5D,KAAK,mBAAqB,OAElC,CAEQ,MAAMK,EAAeC,EAAcC,EAAc,CACrD,IAAIC,EAASH,EACb,OAAIC,IAAQ,SAAWE,EAAS,KAAK,IAAIF,EAAKE,CAAM,GAChDD,IAAQ,SAAWC,EAAS,KAAK,IAAID,EAAKC,CAAM,GAC7CA,CACX,CAKQ,kBAAmB,CACnB,OAAO,OAAW,MAItB,KAAK,mBAAqB,IAAM,CAC5B,IAAMC,EAAU,KAAK,WACrB,KAAK,SAAS,UAAU,EACxB,IAAMC,EAAU,KAAK,SAAS,IAE9B,GAAIA,IAAYD,EACZ,OAGJ,KAAK,WAAaC,EAClB,GAAM,CAAE,MAAAX,EAAO,OAAAC,CAAO,EAAI,KAAK,SAAS,QAAQ,EAGhD,KAAK,OAAO,MAAQD,EAAQW,EAC5B,KAAK,OAAO,OAASV,EAASU,EAC9B,KAAK,OAAO,MAAM,MAAQ,GAAGX,CAAK,KAClC,KAAK,OAAO,MAAM,OAAS,GAAGC,CAAM,KAEhC,KAAK,UACL,KAAK,SAAS,EAGlB,KAAK,eAAe,CACxB,EAEA,OAAO,iBAAiB,SAAU,KAAK,mBAAoB,CAAE,QAAS,EAAK,CAAC,EAChF,CACJ,EC9IO,IAAMW,EAAN,KAAmB,CA2CtB,YACYC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACV,CAPU,mBAAAN,EACA,YAAAC,EACA,YAAAC,EACA,cAAAC,EACA,YAAAC,EACA,2BAAAC,EACA,oBAAAC,EAER,KAAK,SAAW,IAAIC,EAChB,KAAK,OACL,KAAK,OACL,KAAK,SACL,KAAK,OACL,KAAK,sBACL,KAAK,cACT,EAEA,KAAK,OAAS,IAAIC,EAAY,KAAK,OAAQ,CACvC,MAAO,KAAK,SAAS,YACrB,UAAW,KAAK,SAAS,gBACzB,UAAW,KAAK,SAAS,gBACzB,QAAS,KAAK,SAAS,cACvB,WAAY,KAAK,SAAS,iBAC1B,MAAO,KAAK,SAAS,YACrB,WAAY,KAAK,SAAS,iBAC1B,UAAW,KAAK,SAAS,gBACzB,SAAU,KAAK,SAAS,cAC5B,CAAC,CACL,CAvEQ,OACA,SACA,cACA,SAAW,GAEZ,SAEP,IAAW,SAAuC,CAC9C,OAAO,KAAK,SAAS,OACzB,CACA,IAAW,QAAQC,EAAiC,CAChD,KAAK,SAAS,QAAUA,CAC5B,CAEA,IAAW,SAAuC,CAC9C,OAAO,KAAK,SAAS,OACzB,CACA,IAAW,QAAQA,EAAiC,CAChD,KAAK,SAAS,QAAUA,CAC5B,CAEA,IAAW,aAAwC,CAC/C,OAAO,KAAK,SAAS,WACzB,CACA,IAAW,YAAYA,EAA8B,CACjD,KAAK,SAAS,YAAcA,CAChC,CAEA,IAAW,WAAsC,CAC7C,OAAO,KAAK,SAAS,SACzB,CACA,IAAW,UAAUA,EAA8B,CAC/C,KAAK,SAAS,UAAYA,CAC9B,CAEA,IAAW,cAAyC,CAChD,OAAO,KAAK,SAAS,YACzB,CACA,IAAW,aAAaA,EAA8B,CAClD,KAAK,SAAS,aAAeA,CACjC,CAiCA,aAAc,CACN,KAAK,WACT,KAAK,OAAO,OAAO,EACnB,KAAK,SAAW,GACZ,KAAK,OAAO,IAAI,EAAE,cAAc,QAAU,KAAK,kBAAkBC,IACjE,KAAK,cAAgB,IAAIC,EACrB,KAAK,cACL,KAAK,OACL,KAAK,SACL,KAAK,OACL,KAAK,OACL,KAAK,cACT,EACA,KAAK,cAAc,SAAW,IAAM,CAC5B,KAAK,UACL,KAAK,SAAS,CAEtB,EACA,KAAK,cAAc,MAAM,GAEjC,CAEA,SAAU,CACD,KAAK,WACV,KAAK,OAAO,OAAO,EACnB,KAAK,eAAe,KAAK,EACzB,KAAK,cAAgB,OACrB,KAAK,SAAW,GACpB,CACJ,EC/GO,IAAMC,EAAN,KAAkB,CACb,MAAQ,IAAI,IACZ,SAAW,IAAI,IACf,UAAY,IAAI,IAKxB,OAAOC,EAAgB,CACnB,YAAK,UAAU,IAAIA,CAAE,EACd,IAAM,KAAK,UAAU,OAAOA,CAAE,CACzC,CAEQ,cAAe,CACnB,QAAWA,KAAM,KAAK,UAClBA,EAAG,CAEX,CAQA,MAAM,KAAKC,EAAaC,EAAgBC,EAAe,uBAAmD,CAEtG,GAAI,KAAK,MAAM,IAAIF,CAAG,EAClB,OAAO,KAAK,MAAM,IAAIA,CAAG,EAI7B,GAAI,KAAK,SAAS,IAAIA,CAAG,EACrB,OAAO,KAAK,SAAS,IAAIA,CAAG,EAGhC,IAAMG,EAAO,IAAI,QAA0B,CAACC,EAASC,IAAW,CAC5D,IAAMC,EAAM,IAAI,MAChBA,EAAI,YAAc,YAClBA,EAAI,SAAW,QACfA,EAAI,QAAU,QAEdA,EAAI,OAAS,SAAY,CACrB,GAAI,CAEI,WAAYA,GACZ,MAAOA,EAA4D,SAAS,CAEpF,MAAQ,CAER,CAEA,KAAK,MAAM,IAAIN,EAAKM,CAAG,EACvB,KAAK,SAAS,OAAON,CAAG,EACxB,KAAK,aAAa,EAClBI,EAAQE,CAAG,CACf,EAEAA,EAAI,QAAWC,GAAQ,CAEnB,GADA,KAAK,SAAS,OAAOP,CAAG,EACpBC,EAAQ,EACR,QAAQ,KAAK,mBAAmBD,CAAG,EAAE,EACrCI,EAAQ,KAAK,KAAKJ,EAAKC,EAAQ,CAAC,CAAC,MAC9B,CACH,QAAQ,MAAM,yBAAyBD,CAAG,GAAIO,CAAG,EACjD,IAAMC,EACFD,aAAe,MAAQA,EAAI,QAAU,OAAOA,GAAQ,SAAWA,EAAM,KAAK,UAAUA,CAAG,EAC3FF,EAAO,IAAI,MAAM,yBAAyBL,CAAG,aAAaQ,CAAM,EAAE,CAAC,CACvE,CACJ,EAEAF,EAAI,IAAMN,CACd,CAAC,EAED,YAAK,SAAS,IAAIA,EAAKG,CAAI,EACpBA,CACX,CAMA,IAAIH,EAA2C,CAC3C,OAAO,KAAK,MAAM,IAAIA,CAAG,CAC7B,CAMA,IAAIA,EAAsB,CACtB,OAAO,KAAK,MAAM,IAAIA,CAAG,CAC7B,CAKA,OAAQ,CACJ,KAAK,MAAM,MAAM,EACjB,KAAK,SAAS,MAAM,EACpB,KAAK,UAAU,MAAM,CACzB,CACJ,EClFO,IAAMS,EAAN,KAAY,CACP,OAAS,IAAI,IAOrB,IAAIC,EAAeC,EAA+B,CAC9C,IAAMC,EAAK,OAAO,gBAAgB,EAC5BC,EAAQ,CAAE,GAAAD,EAAI,GAAAD,CAAG,EACvB,OAAK,KAAK,OAAO,IAAID,CAAK,GAAG,KAAK,OAAO,IAAIA,EAAO,CAAC,CAAC,EACtD,KAAK,OAAO,IAAIA,CAAK,EAAG,KAAKG,CAAK,EAC3B,CAAE,MAAAH,EAAO,GAAAE,CAAG,CACvB,CAMA,OAAOE,EAAqB,CACxB,IAAMC,EAAO,KAAK,OAAO,IAAID,EAAO,KAAK,EACpCC,GACL,KAAK,OAAO,IACRD,EAAO,MACPC,EAAK,OAAQF,GAAUA,EAAM,KAAOC,EAAO,EAAE,CACjD,CACJ,CAMA,MAAMJ,EAAgB,CAClB,GAAIA,IAAU,OAAW,CACrB,KAAK,OAAO,MAAM,EAClB,MACJ,CACA,KAAK,OAAO,IAAIA,EAAO,CAAC,CAAC,CAC7B,CAMA,QAAQM,EAAiB,CACrB,IAAMC,EAAO,CAAC,GAAG,KAAK,OAAO,KAAK,CAAC,EAAE,KAAK,CAACC,EAAGC,IAAMD,EAAIC,CAAC,EACzD,QAAWT,KAASO,EAAM,CACtB,IAAMG,EAAM,KAAK,OAAO,IAAIV,CAAK,EACjC,GAAKU,EACL,OAAW,CAAE,GAAAT,CAAG,IAAKS,EACjBJ,EAAG,IAAI,KAAK,EACZL,EAAGK,CAAE,EACLA,EAAG,IAAI,QAAQ,CAEvB,CACJ,CACJ,EC7EO,IAAMK,EAAN,KAAoB,CACf,MACA,OACA,KAER,YAAYC,EAAeC,EAAgB,CACvC,KAAK,MAAQD,EACb,KAAK,OAASC,EACd,KAAK,KAAO,OAAO,OAAW,KAAc,OAAO,kBAAoB,CAC3E,CAEA,SAAU,CACN,MAAO,CAAE,MAAO,KAAK,MAAO,OAAQ,KAAK,MAAO,CACpD,CAEA,QAAQD,EAAeC,EAAgB,CACnC,KAAK,MAAQD,EACb,KAAK,OAASC,CAClB,CAMA,IAAI,KAAc,CACd,OAAO,KAAK,IAChB,CAKA,WAAY,CACR,KAAK,KAAO,OAAO,OAAW,KAAc,OAAO,kBAAoB,CAC3E,CACJ,EC9BO,IAAMC,EAAN,KAAgC,CAC3B,IACA,OACA,OACA,SAQR,YAAYC,EAA+BC,EAAiBC,EAAgBC,EAAyB,CACjG,KAAK,IAAMH,EACX,KAAK,OAASC,EACd,KAAK,OAASC,EACd,KAAK,SAAWC,CACpB,CAKA,MAAO,CAEH,KAAK,IAAI,KAAK,EAGd,KAAK,IAAI,UAAY,iBAAiBC,EAAmB,cAAc,IAGvE,GAAM,CAAE,MAAAC,EAAO,OAAAC,CAAO,EAAI,KAAK,SAAS,QAAQ,EAChD,KAAK,IAAI,SAAS,EAAG,EAAGF,EAAmB,aAAcE,CAAM,EAG/D,KAAK,IAAI,SACLF,EAAmB,aACnBE,EAASF,EAAmB,aAC5BC,EACAD,EAAmB,YACvB,EAGA,KAAK,IAAI,UAAY,uBAAuBA,EAAmB,YAAY,IAG3E,IAAMG,EAAW,KAAK,IAClBH,EAAmB,cACnB,KAAK,IAAIA,EAAmB,cAAe,KAAK,OAAO,MAAQA,EAAmB,sBAAsB,CAC5G,EACA,KAAK,IAAI,KAAO,GAAGG,CAAQ,WAC3B,KAAK,IAAI,UAAY,SACrB,KAAK,IAAI,aAAe,SAExB,IAAMC,EAAU,KAAK,OAAO,MACtBC,EAA0BJ,EAAQG,EAClCE,EAA2BJ,EAASE,EAG1C,QAASG,EAAI,EAAK,KAAK,OAAO,EAAI,EAAIA,GAAKD,EAA2B,EAAGC,IACrE,KAAK,IAAI,SAAS,KAAK,MAAM,KAAK,OAAO,EAAIA,CAAC,EAAE,SAAS,EAAG,GAAIH,EAAUG,EAAIH,EAAU,CAAC,EAI7F,QAASG,EAAI,EAAK,KAAK,OAAO,EAAI,EAAIA,GAAKF,EAA0B,EAAGE,IACpE,KAAK,IAAI,SAAS,KAAK,MAAM,KAAK,OAAO,EAAIA,CAAC,EAAE,SAAS,EAAGH,EAAUG,EAAIH,EAAU,EAAGF,EAAS,EAAE,EAItG,KAAK,IAAI,QAAQ,CACrB,CAQA,WAAWM,EAAwB,CAC/B,IAAMC,EAAe,KAAK,OAAO,IAAI,EAAE,YAMvC,GAJI,CAACA,EAAa,SAId,CAACA,EAAa,gBACd,MAAO,GAGX,GAAM,CAAE,IAAAC,EAAK,IAAAC,CAAI,EAAIF,EAAa,gBAElC,OAAOD,GAASE,GAAOF,GAASG,CACpC,CACJ,EC/FA,IAAMC,GAAkB,GAMXC,EAAN,KAAkB,CACb,IACA,OACA,YACA,OACA,SAGA,WAAuB,CAAC,EACxB,cAAgB,EAChB,WAAa,EACb,eAAiB,GACjB,YAAmC,KAE3C,YACIC,EACAC,EACAC,EACAC,EACAC,EACF,CACE,KAAK,IAAMJ,EACX,KAAK,OAASC,EACd,KAAK,YAAcC,EACnB,KAAK,OAASC,EACd,KAAK,SAAWC,CACpB,CAKA,qBAAqBC,EAAsB,CACvC,KAAK,YAAcA,CACvB,CAKA,cAAe,CACP,KAAK,iBACT,KAAK,eAAiB,GACtB,KAAK,cAAgB,YAAY,IAAI,EACrC,KAAK,QAAQ,EACjB,CAKA,aAAc,CACV,KAAK,eAAiB,EAC1B,CAEQ,SAAU,CACd,GAAI,CAAC,KAAK,eAAgB,OAE1B,IAAMC,EAAM,YAAY,IAAI,EACtBC,EAAQD,EAAM,KAAK,cACzB,KAAK,cAAgBA,EAErB,KAAK,WAAW,KAAKC,CAAK,EACtB,KAAK,WAAW,OAAST,IACzB,KAAK,WAAW,MAAM,EAG1B,IAAMU,EAAW,KAAK,WAAW,OAAO,CAACC,EAAGC,IAAMD,EAAIC,EAAG,CAAC,EAAI,KAAK,WAAW,OACxEC,EAAS,KAAK,MAAM,IAAOH,CAAQ,EAGrCG,IAAW,KAAK,aAChB,KAAK,WAAaA,EAClB,KAAK,cAAc,GAGvB,sBAAsB,IAAM,KAAK,QAAQ,CAAC,CAC9C,CAEA,MAAO,CACH,KAAK,QAAQ,CACjB,CAKA,SAAU,CACN,KAAK,YAAY,EACjB,KAAK,YAAc,IACvB,CAEQ,SAAU,CACd,IAAMR,EAAS,KAAK,OAAO,IAAI,EAM/B,GAJI,CAACA,EAAO,MAAM,KAId,CAACA,EAAO,MAAM,IAAI,QAClB,OAGJ,IAAMS,EAAQ,CAAC,EAETC,EAAU,CAAE,EAAG,KAAK,OAAO,EAAG,EAAG,KAAK,OAAO,CAAE,EAMrD,GAJIV,EAAO,MAAM,IAAI,oBACjBS,EAAM,KAAK,YAAYC,EAAQ,EAAE,QAAQ,CAAC,CAAC,KAAKA,EAAQ,EAAE,QAAQ,CAAC,CAAC,EAAE,EAGtEV,EAAO,MAAM,IAAI,YAAa,CAC9B,GAAM,CAAE,MAAAW,EAAO,OAAAC,CAAO,EAAI,KAAK,SAAS,QAAQ,EAC1CC,EAAS,KAAK,OAAO,UAAUF,EAAOC,CAAM,EAClDH,EAAM,KAAK,WAAWI,EAAO,EAAE,QAAQ,CAAC,CAAC,KAAKA,EAAO,EAAE,QAAQ,CAAC,CAAC,EAAE,CACvE,CAMA,GAJIb,EAAO,MAAM,IAAI,OACjBS,EAAM,KAAK,UAAU,KAAK,OAAO,MAAM,QAAQ,CAAC,CAAC,EAAE,EAGnDT,EAAO,MAAM,IAAI,YAAa,CAC9B,GAAM,CAAE,MAAAW,EAAO,OAAAC,CAAO,EAAI,KAAK,SAAS,QAAQ,EAChDH,EAAM,KACF,kBAAkB,KAAK,KAAKE,EAAQ,KAAK,OAAO,KAAK,CAAC,MAAM,KAAK,KAAKC,EAAS,KAAK,OAAO,KAAK,CAAC,EACrG,CACJ,CAEIZ,EAAO,MAAM,IAAI,KACjBS,EAAM,KAAK,QAAQ,KAAK,UAAU,EAAE,EAGxC,GAAM,CAAE,MAAAE,CAAM,EAAI,KAAK,SAAS,QAAQ,EAExC,KAAK,IAAI,KAAK,EACd,KAAK,IAAI,UAAY,kBACrB,KAAK,IAAI,SACLA,EAAQG,EAAU,YAAcA,EAAU,QAC1CA,EAAU,QAAU,EACpBA,EAAU,YACVL,EAAM,OAASK,EAAU,YAAcA,EAAU,OACrD,EAEA,KAAK,IAAI,UAAY,UACrB,KAAK,IAAI,KAAO,iBAEhB,QAASC,EAAI,EAAGA,EAAIN,EAAM,OAAQM,IAC9B,KAAK,IAAI,SACLN,EAAMM,CAAC,EACPJ,EAAQG,EAAU,YAAcA,EAAU,QAAU,EACpD,GAAKC,EAAID,EAAU,WACvB,EAGJ,KAAK,IAAI,QAAQ,CACrB,CACJ,ECrJO,IAAME,EAAN,KAA0C,CAe7C,YACYC,EACAC,EACAC,EACAC,EACAC,EACAC,EACV,CANU,YAAAL,EACA,YAAAC,EACA,2BAAAC,EACA,YAAAC,EACA,cAAAC,EACA,YAAAC,EAER,IAAMC,EAAUN,EAAO,WAAW,IAAI,EACtC,GAAI,CAACM,EACD,MAAM,IAAI,MAAM,iCAAiC,EAGrD,KAAK,IAAMA,EACX,KAAK,gBAAgB,EACrB,KAAK,0BAA4B,IAAIC,EACjC,KAAK,IACL,KAAK,OACL,KAAK,OACL,KAAK,QACT,EACI,KAAK,OAAO,IAAI,EAAE,OAAO,UACzB,KAAK,aAAe,IAAIC,EACpB,KAAK,IACL,KAAK,OACL,KAAK,sBACL,KAAK,OACL,KAAK,QACT,EAEI,KAAK,OAAO,IAAI,EAAE,OAAO,KAAK,MAC9B,KAAK,aAAa,qBAAqB,IAAM,KAAK,OAAO,CAAC,EAC1D,KAAK,aAAa,aAAa,GAG3C,CAjDQ,IACA,0BACA,aAGD,OA8CP,MAAa,CACT,KAAK,gBAAgB,CACzB,CAEQ,iBAAkB,CACtB,IAAMC,EAAO,KAAK,SAAS,QAAQ,EAC7BC,EAAM,KAAK,SAAS,IAG1B,KAAK,OAAO,MAAQD,EAAK,MAAQC,EACjC,KAAK,OAAO,OAASD,EAAK,OAASC,EAGnC,KAAK,OAAO,MAAM,MAAQ,GAAGD,EAAK,KAAK,KACvC,KAAK,OAAO,MAAM,OAAS,GAAGA,EAAK,MAAM,KAGzC,KAAK,IAAI,aAAaC,EAAK,EAAG,EAAGA,EAAK,EAAG,CAAC,CAC9C,CAEA,QAAe,CACX,IAAMD,EAAO,KAAK,SAAS,QAAQ,EAC7BC,EAAM,KAAK,SAAS,IACpBP,EAAS,CAAE,GAAG,KAAK,OAAO,IAAI,EAAG,KAAM,CAAE,GAAGM,CAAK,EAAG,MAAO,KAAK,OAAO,KAAM,EAC7EE,EAAkB,CAAE,EAAG,KAAK,OAAO,EAAG,EAAG,KAAK,OAAO,CAAE,EAG7D,KAAK,IAAI,aAAaD,EAAK,EAAG,EAAGA,EAAK,EAAG,CAAC,EAG1C,KAAK,IAAI,UAAU,EAAG,EAAGP,EAAO,KAAK,MAAOA,EAAO,KAAK,MAAM,EAC9D,KAAK,IAAI,UAAYA,EAAO,gBAC5B,KAAK,IAAI,SAAS,EAAG,EAAGA,EAAO,KAAK,MAAOA,EAAO,KAAK,MAAM,EAG7D,KAAK,OAAO,QAAQ,CAChB,IAAK,KAAK,IACV,OAAQ,KAAK,OACb,YAAa,KAAK,sBAClB,OAAAA,EACA,QAAAQ,CACJ,CAAC,EAGD,KAAK,SAAS,KAAK,IAAK,CACpB,MAAO,KAAK,OAAO,MACnB,MAAOR,EAAO,KAAK,MACnB,OAAQA,EAAO,KAAK,OACpB,OAAQQ,CACZ,CAAC,EAGG,KAAK,0BAA0B,WAAW,KAAK,OAAO,KAAK,GAC3D,KAAK,0BAA0B,KAAK,EAIpCR,EAAO,OAAO,UACT,KAAK,eACN,KAAK,aAAe,IAAIK,EACpB,KAAK,IACL,KAAK,OACL,KAAK,sBACL,KAAK,OACL,KAAK,QACT,EAEIL,EAAO,OAAO,KAAK,MACnB,KAAK,aAAa,qBAAqB,IAAM,KAAK,OAAO,CAAC,EAC1D,KAAK,aAAa,aAAa,IAGvC,KAAK,aAAa,KAAK,EAE/B,CAEA,OAAOS,EAAeC,EAAsB,CACxC,IAAMH,EAAM,KAAK,SAAS,IAE1B,KAAK,SAAS,QAAQE,EAAOC,CAAM,EAGnC,KAAK,OAAO,MAAQD,EAAQF,EAC5B,KAAK,OAAO,OAASG,EAASH,EAG9B,KAAK,OAAO,MAAM,MAAQ,GAAGE,CAAK,KAClC,KAAK,OAAO,MAAM,OAAS,GAAGC,CAAM,KAGpC,KAAK,IAAI,aAAaH,EAAK,EAAG,EAAGA,EAAK,EAAG,CAAC,CAC9C,CAEA,SAAgB,CACR,KAAK,eACL,KAAK,aAAa,QAAQ,EAC1B,KAAK,aAAe,QAExB,KAAK,OAAO,MAAM,CACtB,CAGA,YAAuC,CACnC,OAAO,KAAK,GAChB,CACJ,ECrKO,IAAMI,EAAN,KAAqB,CAChB,cACA,OACA,OACA,SACA,SACA,OACA,cAER,YACIC,EACAC,EACAC,EACAC,EACAC,EAEAC,EACAC,EACF,CACE,KAAK,cAAgBN,EACrB,KAAK,OAASC,EACd,KAAK,OAASC,EACd,KAAK,SAAWC,EAChB,KAAK,SAAWC,EAChB,KAAK,OAASC,EACd,KAAK,cAAgBC,CACzB,CAUA,oBACIC,EACAC,EACAC,EACAC,EACAC,EACF,CACE,GAAIJ,GAAS,GAAKC,GAAU,EACxB,OAGJ,IAAMI,EAAa,KAAK,OAAO,IAAI,EAAE,KAC/BC,EAAQ,CAACC,EAAeC,EAAcC,IAAiB,CACzD,IAAIC,EAASH,EACb,OAAIC,IAAQ,SACRE,EAAS,KAAK,IAAIF,EAAKE,CAAM,GAE7BD,IAAQ,SACRC,EAAS,KAAK,IAAID,EAAKC,CAAM,GAE1BA,CACX,EAGAV,EAAQM,EAAMN,EAAOK,GAAY,SAAUA,GAAY,QAAQ,EAC/DJ,EAASK,EAAML,EAAQI,GAAY,UAAWA,GAAY,SAAS,EAGnEF,EAAoB,cAAcH,EAAOC,EAAQC,EAAY,CAACS,EAAGC,EAAGC,IAAW,KAAK,UAAUF,EAAGC,EAAGC,CAAM,EAAGT,CAAU,CAC3H,CAEQ,UAAUU,EAAeC,EAAeF,EAAgB,CAC5D,IAAMG,EAAW,KAAK,MAAMF,CAAK,EAC3BG,EAAW,KAAK,MAAMF,CAAK,EAC3BG,EAAM,KAAK,SAAS,IAE1B,KAAK,SAAS,QAAQF,EAAUC,CAAQ,EAGxC,KAAK,cAAc,MAAM,MAAQ,GAAGD,CAAQ,KAC5C,KAAK,cAAc,MAAM,OAAS,GAAGC,CAAQ,KAG7C,KAAK,OAAO,MAAQD,EAAWE,EAC/B,KAAK,OAAO,OAASD,EAAWC,EAChC,KAAK,OAAO,MAAM,MAAQ,GAAGF,CAAQ,KACrC,KAAK,OAAO,MAAM,OAAS,GAAGC,CAAQ,KAEtC,KAAK,OAAO,UAAUJ,EAAQG,EAAUC,CAAQ,EAChD,KAAK,SAAS,OAAOD,EAAUC,CAAQ,EACvC,KAAK,cAAc,CACvB,CACJ,ECrFO,IAAME,EAAN,KAA0B,CAI7B,YAAoBC,EAAyBC,EAAiCC,EAA8B,CAAxF,YAAAF,EAAyB,cAAAC,EAAiC,sBAAAC,CAA+B,CAHrG,gBACA,kBAWR,cACIC,EACAC,EACAC,EAAqBC,EAAe,sBACpCC,EACF,CAKE,GAHA,KAAK,WAAW,EAGZF,GAAc,EAAG,CACjB,IAAMG,EAAO,KAAK,SAAS,QAAQ,EACnC,KAAK,OAAO,UAAU,CAAE,EAAGL,EAAS,EAAGC,CAAQ,EAAGI,EAAK,MAAOA,EAAK,MAAM,EACzE,KAAK,iBAAiB,EACtBD,IAAa,EACb,MACJ,CAEA,IAAMC,EAAO,KAAK,SAAS,QAAQ,EAC7BC,EAAQ,KAAK,OAAO,UAAUD,EAAK,MAAOA,EAAK,MAAM,EACrDE,EAAY,YAAY,IAAI,EAE5BC,EAAQC,GAAwB,CAClC,IAAMC,EAAUD,EAAcF,EACxBI,EAAW,KAAK,IAAI,EAAGD,EAAUR,CAAU,EAG3CU,EAAQD,EAAW,GAAM,EAAIA,EAAWA,EAAW,EAAI,KAAK,IAAI,GAAKA,EAAW,EAAG,CAAC,EAAI,EAExFE,EAAWP,EAAM,GAAKN,EAAUM,EAAM,GAAKM,EAC3CE,EAAWR,EAAM,GAAKL,EAAUK,EAAM,GAAKM,EAE3CP,EAAO,KAAK,SAAS,QAAQ,EACnC,KAAK,OAAO,UAAU,CAAE,EAAGQ,EAAU,EAAGC,CAAS,EAAGT,EAAK,MAAOA,EAAK,MAAM,EAC3E,KAAK,iBAAiB,EAElBM,EAAW,EACX,KAAK,gBAAkB,sBAAsBH,CAAI,GAEjD,KAAK,gBAAkB,OACvBJ,IAAa,EAErB,EAEA,KAAK,gBAAkB,sBAAsBI,CAAI,CACrD,CAUA,cACIO,EACAC,EACAd,EAAqBC,EAAe,sBACpCc,EACAb,EACF,CACE,GAAIW,GAAe,GAAKC,GAAgB,EACpC,OAIJ,KAAK,aAAa,EAElB,IAAME,EAAO,KAAK,SAAS,QAAQ,EAC7BC,EAAS,KAAK,OAAO,UAAUD,EAAK,MAAOA,EAAK,MAAM,EAG5D,GAAIhB,GAAc,EAAG,CACjBe,EAAYF,EAAaC,EAAcG,CAAM,EAC7Cf,IAAa,EACb,MACJ,CAEA,IAAMgB,EAASF,EAAK,MACdG,EAASH,EAAK,OACdI,EAASP,EAAcG,EAAK,MAC5BK,EAASP,EAAeE,EAAK,OAC7BX,EAAY,YAAY,IAAI,EAE5BC,EAAQC,GAAwB,CAClC,IAAMC,EAAUD,EAAcF,EACxBI,EAAW,KAAK,IAAI,EAAGD,EAAUR,CAAU,EAE3CsB,EAAQJ,EAASE,EAASX,EAC1Bc,EAAQJ,EAASE,EAASZ,EAEhCM,EAAYO,EAAOC,EAAON,CAAM,EAE5BR,EAAW,EACX,KAAK,kBAAoB,sBAAsBH,CAAI,GAEnD,KAAK,kBAAoB,OACzBJ,IAAa,EAErB,EAEA,KAAK,kBAAoB,sBAAsBI,CAAI,CACvD,CAKA,YAAa,CACL,KAAK,kBAAoB,SACzB,qBAAqB,KAAK,eAAe,EACzC,KAAK,gBAAkB,OAE/B,CAKA,cAAe,CACP,KAAK,oBAAsB,SAC3B,qBAAqB,KAAK,iBAAiB,EAC3C,KAAK,kBAAoB,OAEjC,CAKA,WAAY,CACR,KAAK,WAAW,EAChB,KAAK,aAAa,CACtB,CAKA,aAAuB,CACnB,OAAO,KAAK,kBAAoB,QAAa,KAAK,oBAAsB,MAC5E,CACJ,ECpJO,IAAMkB,EAAN,KAAsB,CAazB,OAAO,eACHC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACS,CACT,OAAQN,EAAM,CACV,IAAK,SACD,OAAO,IAAIO,EAAeN,EAAQC,EAAQC,EAAuBC,EAAQC,EAAUC,CAAM,EAC7F,QAEI,MAAM,IAAI,MAAM,8BAA8BN,CAAI,EAAE,CAC5D,CACJ,CAOA,OAAO,YAAYA,EAAuE,CACtF,OAAOA,IAAS,QACpB,CAMA,OAAO,mBAAoF,CACvF,MAAO,CAAC,QAAQ,CACpB,CACJ,ECnCO,IAAMQ,EAAN,KAAuB,CAClB,OACA,OACA,SACA,sBACA,OACA,SACA,OACA,KACD,OACC,eACA,oBAED,cACA,OAGA,eAEC,SAER,IAAW,SAAuC,CAC9C,OAAO,KAAK,QAChB,CACA,IAAW,QAAQC,EAAiC,CAChD,KAAK,SAAWA,EAChB,KAAK,OAAO,QAAUA,CAC1B,CAEQ,SACR,IAAW,SAAuC,CAC9C,OAAO,KAAK,QAChB,CACA,IAAW,QAAQA,EAAiC,CAChD,KAAK,SAAWA,EAChB,KAAK,OAAO,QAAUA,CAC1B,CAEQ,aACR,IAAW,aAAwC,CAC/C,OAAO,KAAK,YAChB,CACA,IAAW,YAAYA,EAA8B,CACjD,KAAK,aAAeA,EACpB,KAAK,OAAO,YAAcA,CAC9B,CAEQ,WACR,IAAW,WAAsC,CAC7C,OAAO,KAAK,UAChB,CACA,IAAW,UAAUA,EAA8B,CAC/C,KAAK,WAAaA,EAClB,KAAK,OAAO,UAAYA,CAC5B,CAEQ,cACR,IAAW,cAAyC,CAChD,OAAO,KAAK,aAChB,CACA,IAAW,aAAaA,EAA8B,CAClD,KAAK,cAAgBA,EACrB,KAAK,OAAO,aAAeA,CAC/B,CAEQ,QACR,IAAW,QAAqC,CAC5C,OAAO,KAAK,OAChB,CACA,IAAW,OAAOA,EAAgC,CAC9C,KAAK,QAAUA,EACf,KAAK,kBAAkB,EAAE,OAASA,CACtC,CAEQ,UACR,IAAW,UAAqC,CAC5C,OAAO,KAAK,SAChB,CACA,IAAW,SAASA,EAA8B,CAC9C,KAAK,UAAYA,EACjB,KAAK,OAAO,SAAWA,CAC3B,CAOA,YAAYC,EAA+BC,EAAgCC,EAAiB,CAAE,EAAG,EAAG,EAAG,CAAE,EAAG,CACxG,KAAK,cAAgBF,EACrB,KAAK,OAASA,EAAc,cAAc,QAAQ,EAClD,KAAK,cAAc,MAAM,SAAW,WACpC,KAAK,cAAc,MAAM,MAAQC,EAAO,KAAK,MAAQ,KACrD,KAAK,cAAc,MAAM,OAASA,EAAO,KAAK,OAAS,KACvD,KAAK,OAAO,MAAM,SAAW,WAE7B,KAAK,OAAS,IAAIE,EAAOF,CAAM,EAE/B,IAAMG,EAAeH,EAAO,UAAY,SAClCI,EAAyB,CAC3B,EAAGH,EAAO,EAAID,EAAO,KAAK,OAAS,EAAIA,EAAO,OAC9C,EAAGC,EAAO,EAAID,EAAO,KAAK,QAAU,EAAIA,EAAO,MACnD,EAEA,KAAK,SAAW,IAAIK,EAAcL,EAAO,KAAK,MAAOA,EAAO,KAAK,MAAM,EACvE,KAAK,OAAS,IAAIM,EACdF,EACA,KAAK,OAAO,IAAI,EAAE,MAClB,KAAK,OAAO,IAAI,EAAE,SAClB,KAAK,OAAO,IAAI,EAAE,SAClB,KAAK,QACT,EAEA,KAAK,sBAAwB,IAAIG,EAAsB,KAAK,MAAM,EAGlE,KAAK,oBAAsB,IAAIC,EAAoB,KAAK,OAAQ,KAAK,SAAU,IAAM,KAAK,mBAAmB,CAAC,EAE9G,KAAK,SAAW,KAAK,eAAeL,CAAY,EAEhD,KAAK,OAAS,IAAIM,EAElB,KAAK,OAAS,IAAIC,EACd,KAAK,cACL,KAAK,OACL,KAAK,OACL,KAAK,SACL,KAAK,OACL,KAAK,sBACL,IAAM,KAAK,mBAAmB,CAClC,EACA,KAAK,eAAiB,IAAIC,EACtB,KAAK,cACL,KAAK,OACL,KAAK,OACL,KAAK,SACL,KAAK,SACL,KAAK,OACL,IAAM,KAAK,mBAAmB,CAClC,EACA,KAAK,OAAO,YAAY,EAGpBX,EAAO,QACP,KAAK,OAAO,UAAUA,EAAO,MAAM,CAE3C,CAKA,SAAU,CACN,KAAK,OAAO,QAAQ,EACpB,KAAK,oBAAoB,UAAU,EACnC,KAAK,MAAM,QAAQ,EACnB,KAAK,QAAQ,MAAM,EACnB,KAAK,OAAO,MAAM,EAClB,KAAK,SAAS,QAAQ,CAC1B,CAGA,QAAS,CACL,KAAK,SAAS,OAAO,CACzB,CASA,OAAOY,EAAeC,EAAgBC,EAAqB,IAAKC,EAAyB,CACrF,KAAK,eAAe,oBAAoBH,EAAOC,EAAQC,EAAY,KAAK,oBAAqB,IAAM,CAE/F,KAAK,YAAY,EACjBC,IAAa,CACjB,CAAC,CACL,CAMA,SAAU,CACN,OAAO,KAAK,SAAS,QAAQ,CACjC,CAMA,UAAW,CACP,OAAO,KAAK,OAAO,KACvB,CAMA,OAAOC,EAAiB,IAAK,CACzB,IAAMC,EAAO,KAAK,SAAS,QAAQ,EACnC,KAAK,OAAO,aAAaD,EAAQC,EAAK,MAAQ,EAAGA,EAAK,OAAS,CAAC,EAChE,KAAK,mBAAmB,CAC5B,CAMA,QAAQD,EAAiB,IAAK,CAC1B,IAAMC,EAAO,KAAK,SAAS,QAAQ,EACnC,KAAK,OAAO,aAAa,EAAID,EAAQC,EAAK,MAAQ,EAAGA,EAAK,OAAS,CAAC,EACpE,KAAK,mBAAmB,CAC5B,CAGA,WAA8C,CAC1C,IAAMC,EAAO,KAAK,OAAO,IAAI,EACvBD,EAAO,KAAK,SAAS,QAAQ,EACnC,MAAO,CACH,GAAGC,EACH,MAAO,KAAK,OAAO,MACnB,KAAM,CAAE,GAAGD,CAAK,CACpB,CACJ,CAGA,iBAA0B,CACtB,IAAMA,EAAO,KAAK,SAAS,QAAQ,EACnC,OAAO,KAAK,OAAO,UAAUA,EAAK,MAAOA,EAAK,MAAM,CACxD,CAGA,aAAaE,EAAmB,CAC5B,IAAMF,EAAO,KAAK,SAAS,QAAQ,EACnC,KAAK,OAAO,UAAUE,EAAWF,EAAK,MAAOA,EAAK,MAAM,EACxD,KAAK,mBAAmB,CAC5B,CASA,SAASG,EAAWC,EAAWP,EAAqB,IAAKC,EAAyB,CAC9E,KAAK,oBAAoB,cAAcK,EAAGC,EAAGP,EAAYC,CAAU,CACvE,CAkBA,iBAAiBO,EAAkC,CAC/C,KAAK,OAAO,oBAAoBA,CAAQ,CAC5C,CAiBA,UAAUC,EAAoE,CAC1E,KAAK,OAAO,aAAaA,CAAM,EAC/B,KAAK,OAAO,UAAUA,CAAM,EAC5B,KAAK,OAAO,CAChB,CASA,gBACIC,EACAC,EAAgB,EACL,CACX,OAAO,KAAK,iBAAiB,EAAE,gBAAgBD,EAAIC,CAAK,CAC5D,CAQA,SAASC,EAAuCD,EAAgB,EAAgB,CAC5E,OAAO,KAAK,iBAAiB,EAAE,SAASC,EAAOD,CAAK,CACxD,CAWA,eAAeC,EAA0BC,EAAkBF,EAAgB,EAAgB,CACvF,OAAO,KAAK,iBAAiB,EAAE,eAAeC,EAAOC,EAAUF,CAAK,CACxE,CAUA,iBAAiBC,EAA0BC,EAAkBF,EAAgB,EAAgB,CACzF,OAAO,KAAK,iBAAiB,EAAE,iBAAiBC,EAAOC,EAAUF,CAAK,CAC1E,CAWA,gBACIC,EACAC,EACAF,EAAgB,EACL,CACX,OAAO,KAAK,iBAAiB,EAAE,gBAAgBC,EAAOC,EAAUF,CAAK,CACzE,CAMA,iBAAiBE,EAAmB,CAChC,KAAK,iBAAiB,EAAE,iBAAiBA,CAAQ,CACrD,CAQA,SACID,EACAE,EACAH,EAAgB,EACL,CACX,OAAO,KAAK,iBAAiB,EAAE,SAASC,EAAOE,EAAOH,CAAK,CAC/D,CAOA,WAAWC,EAAuCD,EAAgB,EAAgB,CAC9E,OAAO,KAAK,iBAAiB,EAAE,WAAWC,EAAOD,CAAK,CAC1D,CAQA,SACIC,EACAE,EACAH,EAAgB,EACL,CACX,OAAO,KAAK,iBAAiB,EAAE,SAASC,EAAOE,EAAOH,CAAK,CAC/D,CAQA,SACIC,EACAE,EACAH,EAAgB,EACL,CACX,OAAO,KAAK,iBAAiB,EAAE,SAASC,EAAOE,EAAOH,CAAK,CAC/D,CAQA,UACIC,EAGAD,EAAgB,EACL,CACX,OAAO,KAAK,iBAAiB,EAAE,UAAUC,EAAOD,CAAK,CACzD,CAUA,cACII,EACAC,EAAoB,EACpBC,EAAsB,QACtBN,EAAgB,EACL,CACX,OAAO,KAAK,iBAAiB,EAAE,cAAcI,EAAU,CAAE,UAAAC,EAAW,YAAAC,CAAY,EAAGN,CAAK,CAC5F,CAMA,kBAAkBO,EAAqB,CACnC,GAAI,CAAC,KAAK,OACN,MAAM,IAAI,MAAM,uEAAuE,EAE3F,KAAK,OAAO,OAAOA,CAAM,CAC7B,CAaA,WAAWP,EAAe,CACtB,GAAI,CAAC,KAAK,OACN,MAAM,IAAI,MAAM,gEAAgE,EAEpF,KAAK,OAAO,MAAMA,CAAK,CAC3B,CAWA,UAAW,CACP,GAAI,CAAC,KAAK,OACN,MAAM,IAAI,MAAM,8DAA8D,EAElF,KAAK,OAAO,MAAM,CACtB,CAMQ,eAAeQ,EAAqD,CAExE,OAAIA,IAAS,WACT,KAAK,OAAS,IAAIC,EAClB,KAAK,KAAO,IAAIC,EAAW,KAAK,OAAQ,KAAK,sBAAuB,KAAK,MAAM,GAG5EC,EAAgB,eACnBH,GAAQ,SACR,KAAK,OACL,KAAK,OACL,KAAK,sBACL,KAAK,OACL,KAAK,SACL,KAAK,MACT,CACJ,CAEQ,kBAA+B,CACnC,GAAI,CAAC,KAAK,KACN,MAAM,IAAI,MAAM,mEAAmE,EAEvF,OAAO,KAAK,IAChB,CAEQ,mBAAoC,CACxC,GAAI,EAAE,KAAK,oBAAoBI,GAC3B,MAAM,IAAI,MAAM,8CAA8C,EAElE,OAAO,KAAK,QAChB,CAIQ,oBAAqB,CACrB,KAAK,gBACL,KAAK,eAAe,KAAK,gBAAgB,CAAC,EAE9C,KAAK,OAAO,CAChB,CACJ","names":["DEFAULT_VALUES","SCALE_LIMITS","SIZE_LIMITS","RENDER_DEFAULTS","COORDINATE_OVERLAY","DEBUG_HUD","VISIBILITY_BUFFER","computePan","topLeft","scale","dx","dy","computeZoom","oldScale","deltaY","minScale","maxScale","mouse","limitedDelta","DEFAULT_VALUES","scaleFactor","newScale","worldToScreen","world","cam","screenToWorld","screen","Camera","initialTopLeft","scale","minScale","maxScale","viewport","DEFAULT_VALUES","bounds","viewportWidth","viewportHeight","viewWidthWorld","viewHeightWorld","value","viewSize","min","max","boundsSize","deltaScreenX","deltaScreenY","next","computePan","mouseX","mouseY","deltaY","canvasRect","mx","my","computeZoom","factor","centerX","centerY","newScale","canvasWidth","canvasHeight","center","deltaWidthPx","deltaHeightPx","Config","config","base","RENDER_DEFAULTS","SCALE_LIMITS","SIZE_LIMITS","cfg","handlers","bounds","CoordinateTransformer","camera","worldX","worldY","worldToScreen","screenX","screenY","screenToWorld","RBush","SpatialIndex","_SpatialIndex","items","rbushItems","item","half","minX","minY","maxX","maxY","r","index","SPATIAL_INDEX_THRESHOLD","MAX_STATIC_CANVAS_DIMENSION","CanvasDraw","layers","transformer","camera","x","y","sizeWorld","topLeft","config","viewW","viewH","minX","VISIBILITY_BUFFER","minY","maxX","maxY","fn","layer","ctx","items","list","spatialIndex","SpatialIndex","bounds","visibleItems","lastFillStyle","lastStrokeStyle","lastLineWidth","item","size","origin","style","pos","pxSize","drawX","drawY","rotationDeg","rotation","radius","centerX","centerY","halfExtent","a","b","points","xs","p","ys","first","i","aspect","drawW","drawH","baseX","baseY","offsetX","offsetY","cellSize","startX","DEFAULT_VALUES","endX","startY","endY","p1","p2","cell","cacheKey","renderFn","worldWidth","worldHeight","renderScale","canvasWidth","canvasHeight","cache","offscreen","offCtx","cachedCanvas","cachedBounds","cachedScale","srcX","srcY","srcW","srcH","img","imgX","imgY","EventBinder","canvas","handlers","GestureController","canvas","camera","viewport","config","transformer","onCameraChange","rect","mouseX","mouseY","world","screen","dx","dy","eventHandlers","t","currentDistance","currentCenter","scaleFactor","centerX","centerY","touches","ResizeWatcher","wrapper","canvas","viewport","camera","config","onCameraChange","size","configSize","maxWidth","maxHeight","minWidth","minHeight","entries","entry","rawW","rawH","width","height","prev","diffW","diffH","dpr","value","min","max","result","prevDpr","nextDpr","EventManager","canvasWrapper","canvas","camera","viewport","config","coordinateTransformer","onCameraChange","GestureController","EventBinder","cb","Camera","ResizeWatcher","ImageLoader","cb","src","retry","DEFAULT_VALUES","task","resolve","reject","img","err","reason","Layer","layer","fn","id","entry","handle","list","dc","keys","a","b","fns","ViewportState","width","height","CoordinateOverlayRenderer","ctx","camera","config","viewport","COORDINATE_OVERLAY","width","height","fontSize","cordGap","visibleAreaWidthInCords","visibleAreaHeightInCords","i","scale","coordsConfig","min","max","FPS_SAMPLE_SIZE","CanvasDebug","ctx","camera","transformer","config","viewport","callback","now","delta","avgDelta","a","b","newFps","datas","topLeft","width","height","center","DEBUG_HUD","i","CanvasRenderer","canvas","camera","coordinateTransformer","config","viewport","layers","context","CoordinateOverlayRenderer","CanvasDebug","size","dpr","topLeft","width","height","SizeController","canvasWrapper","canvas","camera","renderer","viewport","config","onSizeApplied","width","height","durationMs","animationController","onComplete","configSize","clamp","value","min","max","result","w","h","center","nextW","nextH","roundedW","roundedH","dpr","AnimationController","camera","viewport","onAnimationFrame","targetX","targetY","durationMs","DEFAULT_VALUES","onComplete","size","start","startTime","step","currentTime","elapsed","progress","eased","currentX","currentY","targetWidth","targetHeight","onApplySize","prev","center","startW","startH","deltaW","deltaH","nextW","nextH","RendererFactory","type","canvas","camera","coordinateTransformer","config","viewport","layers","CanvasRenderer","CanvasTileEngine","cb","canvasWrapper","config","center","Config","rendererType","initialTopLeft","ViewportState","Camera","CoordinateTransformer","AnimationController","ImageLoader","EventManager","SizeController","width","height","durationMs","onComplete","factor","size","base","newCenter","x","y","handlers","bounds","fn","layer","items","cacheKey","style","cellSize","lineWidth","strokeStyle","handle","type","Layer","CanvasDraw","RendererFactory","CanvasRenderer"]}
1
+ {"version":3,"sources":["../src/constants.ts","../src/utils/viewport.ts","../src/modules/Camera.ts","../src/modules/Config.ts","../src/modules/CoordinateTransformer.ts","../src/modules/SpatialIndex.ts","../src/modules/CanvasDraw.ts","../src/modules/EventManager/EventBinder.ts","../src/modules/EventManager/GestureController.ts","../src/modules/EventManager/ResizeWatcher.ts","../src/modules/EventManager/index.ts","../src/modules/ImageLoader.ts","../src/modules/Layer.ts","../src/modules/ViewportState.ts","../src/modules/CoordinateOverlayRenderer.ts","../src/modules/CanvasDebug.ts","../src/modules/Renderer/CanvasRenderer.ts","../src/modules/SizeController.ts","../src/modules/AnimationController.ts","../src/modules/RendererFactory.ts","../src/CanvasTileEngine.ts"],"sourcesContent":["/**\n * Global constants for the canvas grid engine.\n * Centralizes magic numbers and configuration values.\n */\n\nexport const DEFAULT_VALUES = {\n /** Default animation duration in milliseconds */\n ANIMATION_DURATION_MS: 500,\n\n /** Pixel offset for centering cells (0.5 = center of pixel) */\n CELL_CENTER_OFFSET: 0.5,\n\n /** Default retry count for image loading */\n IMAGE_LOAD_RETRY_COUNT: 1,\n\n /** Maximum wheel delta value for zoom (prevents extreme zooming) */\n MAX_WHEEL_DELTA: 100,\n\n /** Minimum wheel delta value for zoom */\n MIN_WHEEL_DELTA: -100,\n\n /** Zoom sensitivity factor */\n ZOOM_SENSITIVITY: 0.001,\n} as const;\n\nexport const SCALE_LIMITS = {\n /** Default minimum scale multiplier */\n MIN_SCALE_MULTIPLIER: 0.5,\n\n /** Default maximum scale multiplier */\n MAX_SCALE_MULTIPLIER: 2,\n} as const;\n\nexport const SIZE_LIMITS = {\n /** Default minimum canvas width in pixels */\n MIN_WIDTH: 100,\n\n /** Default minimum canvas height in pixels */\n MIN_HEIGHT: 100,\n\n /** Default maximum width (infinity means no limit) */\n MAX_WIDTH: Infinity,\n\n /** Default maximum height (infinity means no limit) */\n MAX_HEIGHT: Infinity,\n} as const;\n\nexport const RENDER_DEFAULTS = {\n /** Default background color */\n BACKGROUND_COLOR: \"#ffffff\",\n\n /** Default renderer type */\n RENDERER_TYPE: \"canvas\" as const,\n} as const;\n\nexport const COORDINATE_OVERLAY = {\n /** Coordinate overlay border width in pixels */\n BORDER_WIDTH: 20,\n\n /** Coordinate text opacity */\n TEXT_OPACITY: 0.8,\n\n /** Border overlay opacity */\n BORDER_OPACITY: 0.1,\n\n /** Minimum font size for coordinate labels */\n MIN_FONT_SIZE: 8,\n\n /** Maximum font size for coordinate labels */\n MAX_FONT_SIZE: 12,\n\n /** Font size scale factor relative to camera scale */\n FONT_SIZE_SCALE_FACTOR: 0.25,\n} as const;\n\nexport const DEBUG_HUD = {\n /** Debug HUD panel width in pixels */\n PANEL_WIDTH: 160,\n\n /** Debug HUD padding in pixels */\n PADDING: 8,\n\n /** Debug HUD line height in pixels */\n LINE_HEIGHT: 16,\n} as const;\n\nexport const VISIBILITY_BUFFER = {\n /** Buffer zone for visibility culling (tiles) */\n TILE_BUFFER: 1,\n} as const;\n","import { Coords } from \"../types\";\nimport { DEFAULT_VALUES } from \"../constants\";\n\n/** Pan the top-left point by screen pixel delta, respecting current scale. */\nexport function computePan(topLeft: Coords, scale: number, dx: number, dy: number): Coords {\n return { x: topLeft.x - dx / scale, y: topLeft.y - dy / scale };\n}\n\n/** Compute new top-left and scale when zooming around a mouse point. */\nexport function computeZoom(\n topLeft: Coords,\n oldScale: number,\n deltaY: number,\n minScale: number,\n maxScale: number,\n mouse: { x: number; y: number }\n): { topLeft: Coords; scale: number } {\n const limitedDelta = Math.min(Math.max(deltaY, DEFAULT_VALUES.MIN_WHEEL_DELTA), DEFAULT_VALUES.MAX_WHEEL_DELTA);\n const scaleFactor = Math.exp(-limitedDelta * DEFAULT_VALUES.ZOOM_SENSITIVITY);\n const newScale = Math.min(maxScale, Math.max(minScale, oldScale * scaleFactor));\n if (newScale === oldScale) return { topLeft, scale: oldScale };\n return {\n topLeft: {\n x: topLeft.x + mouse.x * (1 / oldScale - 1 / newScale),\n y: topLeft.y + mouse.y * (1 / oldScale - 1 / newScale),\n },\n scale: newScale,\n };\n}\n\n/** Convert world grid coordinates to screen pixels using camera state. */\nexport function worldToScreen(world: Coords, cam: { x: number; y: number; scale: number }): Coords {\n return {\n x: (world.x + DEFAULT_VALUES.CELL_CENTER_OFFSET - cam.x) * cam.scale,\n y: (world.y + DEFAULT_VALUES.CELL_CENTER_OFFSET - cam.y) * cam.scale,\n };\n}\n\n/** Convert screen pixels back to world grid coordinates using camera state. */\nexport function screenToWorld(screen: Coords, cam: { x: number; y: number; scale: number }): Coords {\n return { x: cam.x + screen.x / cam.scale, y: cam.y + screen.y / cam.scale };\n}\n","import { Coords } from \"../types\";\nimport { computePan, computeZoom } from \"../utils/viewport\";\nimport { DEFAULT_VALUES } from \"../constants\";\nimport { ViewportState } from \"./ViewportState\";\n\n/**\n * Camera contract used by rendering and coordinate transforms.\n * @internal\n */\nexport interface ICamera {\n /** Current top-left world x coordinate. */\n readonly x: number;\n /** Current top-left world y coordinate. */\n readonly y: number;\n /** Current zoom scale. */\n readonly scale: number;\n\n /**\n * Pan the camera by screen-space deltas.\n * @param deltaScreenX X delta in pixels.\n * @param deltaScreenY Y delta in pixels.\n */\n pan(deltaScreenX: number, deltaScreenY: number): void;\n\n /**\n * Zoom around a mouse position.\n * @param mouseX Mouse X relative to viewport.\n * @param mouseY Mouse Y relative to viewport.\n * @param deltaY Wheel delta (positive scroll down).\n * @param canvasRect Canvas bounding rect for mouse offset.\n */\n zoom(mouseX: number, mouseY: number, deltaY: number, canvasRect: DOMRect): void;\n\n /**\n * Canvas center coordinates in world space.\n * @param canvasWidth Canvas width in pixels.\n * @param canvasHeight Canvas height in pixels.\n * @returns Center point in world coordinates.\n */\n getCenter(canvasWidth: number, canvasHeight: number): Coords;\n\n /**\n * Set top-left coordinates based on a target center.\n * @param center Desired center in world space.\n * @param canvasWidth Canvas width in pixels.\n * @param canvasHeight Canvas height in pixels.\n */\n setCenter(center: Coords, canvasWidth: number, canvasHeight: number): void;\n\n /**\n * Adjust view so center stays stable on resize.\n * @param deltaWidthPx Change in canvas width (pixels).\n * @param deltaHeightPx Change in canvas height (pixels).\n */\n adjustForResize(deltaWidthPx: number, deltaHeightPx: number): void;\n\n /**\n * Zoom by a scale factor around a specific point (for pinch-to-zoom).\n * @param factor Scale multiplier (>1 zooms in, <1 zooms out).\n * @param centerX Center X in screen coordinates.\n * @param centerY Center Y in screen coordinates.\n */\n zoomByFactor(factor: number, centerX: number, centerY: number): void;\n}\n\n/**\n * Tracks camera position and zoom for converting between world and screen space.\n * @internal\n */\nexport class Camera implements ICamera {\n private _x: number;\n private _y: number;\n private _scale: number;\n readonly minScale: number;\n readonly maxScale: number;\n private bounds?: {\n minX: number;\n maxX: number;\n minY: number;\n maxY: number;\n };\n private viewport?: ViewportState;\n\n constructor(initialTopLeft: Coords, scale = 1, minScale = 0.1, maxScale = 10, viewport?: ViewportState) {\n this._x = initialTopLeft.x + DEFAULT_VALUES.CELL_CENTER_OFFSET; // Center of the pixel\n this._y = initialTopLeft.y + DEFAULT_VALUES.CELL_CENTER_OFFSET; // Center of the pixel\n this._scale = scale;\n this.minScale = minScale;\n this.maxScale = maxScale;\n this.viewport = viewport;\n }\n\n /**\n * Set camera bounds to limit panning area.\n * @param bounds Min and max coordinates for x and y axes. Set to undefined to remove bounds.\n */\n setBounds(bounds?: { minX: number; maxX: number; minY: number; maxY: number }) {\n this.bounds = bounds;\n // Clamp current position to new bounds\n if (this.bounds) {\n this.clampToBounds();\n }\n }\n\n private clampToBounds() {\n if (!this.bounds || !this.viewport) {\n return;\n }\n\n const { width: viewportWidth, height: viewportHeight } = this.viewport.getSize();\n\n // Calculate viewport size in world units\n const viewWidthWorld = viewportWidth / this._scale;\n const viewHeightWorld = viewportHeight / this._scale;\n\n this._x = this.clampAxis(this._x, viewWidthWorld, this.bounds.minX, this.bounds.maxX);\n this._y = this.clampAxis(this._y, viewHeightWorld, this.bounds.minY, this.bounds.maxY);\n }\n\n /**\n * Clamp a single axis value to bounds.\n * If viewport is larger than bounds, center it. Otherwise, keep viewport within bounds.\n */\n private clampAxis(value: number, viewSize: number, min: number, max: number): number {\n const boundsSize = max - min;\n\n // If viewport is larger than bounds, center the bounds in viewport\n if (viewSize >= boundsSize) {\n return min - (viewSize - boundsSize) / 2;\n }\n\n // Normal clamping: ensure viewport stays within bounds\n if (value < min) {\n return min;\n }\n if (value + viewSize > max) {\n return max - viewSize;\n }\n return value;\n }\n\n get x(): number {\n return this._x;\n }\n\n get y(): number {\n return this._y;\n }\n\n get scale(): number {\n return this._scale;\n }\n\n pan(deltaScreenX: number, deltaScreenY: number) {\n const next = computePan({ x: this._x, y: this._y }, this._scale, deltaScreenX, deltaScreenY);\n this._x = next.x;\n this._y = next.y;\n this.clampToBounds();\n }\n\n zoom(mouseX: number, mouseY: number, deltaY: number, canvasRect: DOMRect) {\n // Mouse position relative to canvas\n const mx = mouseX - canvasRect.left;\n const my = mouseY - canvasRect.top;\n\n const next = computeZoom({ x: this._x, y: this._y }, this._scale, deltaY, this.minScale, this.maxScale, {\n x: mx,\n y: my,\n });\n this._x = next.topLeft.x;\n this._y = next.topLeft.y;\n this._scale = next.scale;\n this.clampToBounds();\n }\n\n /**\n * Zoom by a scale factor around a specific point (for pinch-to-zoom).\n * @param factor Scale multiplier (>1 zooms in, <1 zooms out).\n * @param centerX Center X in screen coordinates.\n * @param centerY Center Y in screen coordinates.\n */\n zoomByFactor(factor: number, centerX: number, centerY: number) {\n const newScale = Math.min(this.maxScale, Math.max(this.minScale, this._scale * factor));\n if (newScale === this._scale) {\n return;\n }\n\n // Adjust top-left to keep the pinch center stationary\n this._x = this._x + centerX * (1 / this._scale - 1 / newScale);\n this._y = this._y + centerY * (1 / this._scale - 1 / newScale);\n this._scale = newScale;\n this.clampToBounds();\n }\n\n getCenter(canvasWidth: number, canvasHeight: number): Coords {\n return {\n x: this._x + canvasWidth / (2 * this._scale) - 0.5,\n y: this._y + canvasHeight / (2 * this._scale) - 0.5,\n };\n }\n\n setCenter(center: Coords, canvasWidth: number, canvasHeight: number) {\n this._x = center.x - canvasWidth / (2 * this._scale) + 0.5;\n this._y = center.y - canvasHeight / (2 * this._scale) + 0.5;\n this.clampToBounds();\n }\n\n adjustForResize(deltaWidthPx: number, deltaHeightPx: number) {\n this._x -= deltaWidthPx / (2 * this._scale);\n this._y -= deltaHeightPx / (2 * this._scale);\n this.clampToBounds();\n }\n}\n","import { CanvasTileEngineConfig, EventHandlers } from \"../types\";\nimport { SCALE_LIMITS, SIZE_LIMITS, RENDER_DEFAULTS } from \"../constants\";\n\n/**\n * Normalizes and stores grid engine configuration with safe defaults.\n * @internal\n */\nexport class Config {\n private config: Required<CanvasTileEngineConfig>;\n\n /**\n * Create a config store with defaults merged from the provided partial config.\n * @param config Incoming configuration values.\n */\n constructor(config: CanvasTileEngineConfig) {\n const base: Required<CanvasTileEngineConfig> = {\n renderer: RENDER_DEFAULTS.RENDERER_TYPE,\n scale: config.scale,\n minScale: config.minScale ?? config.scale * SCALE_LIMITS.MIN_SCALE_MULTIPLIER,\n maxScale: config.maxScale ?? config.scale * SCALE_LIMITS.MAX_SCALE_MULTIPLIER,\n\n size: {\n width: config.size.width,\n height: config.size.height,\n maxHeight: config.size.maxHeight ?? SIZE_LIMITS.MAX_HEIGHT,\n maxWidth: config.size.maxWidth ?? SIZE_LIMITS.MAX_WIDTH,\n minHeight: config.size.minHeight ?? SIZE_LIMITS.MIN_HEIGHT,\n minWidth: config.size.minWidth ?? SIZE_LIMITS.MIN_WIDTH,\n },\n\n backgroundColor: config.backgroundColor ?? RENDER_DEFAULTS.BACKGROUND_COLOR,\n\n eventHandlers: {\n click: config.eventHandlers?.click ?? false,\n hover: config.eventHandlers?.hover ?? false,\n drag: config.eventHandlers?.drag ?? false,\n zoom: config.eventHandlers?.zoom ?? false,\n resize: config.eventHandlers?.resize ?? false,\n },\n\n bounds: config.bounds ?? {\n minX: -Infinity,\n maxX: Infinity,\n minY: -Infinity,\n maxY: Infinity,\n },\n\n coordinates: {\n enabled: config.coordinates?.enabled ?? false,\n shownScaleRange: config.coordinates?.shownScaleRange ?? { min: 0, max: Infinity },\n },\n\n cursor: {\n default: config.cursor?.default ?? \"default\",\n move: config.cursor?.move ?? \"move\",\n },\n\n debug: {\n enabled: config.debug?.enabled ?? false,\n hud: {\n enabled: config.debug?.hud?.enabled ?? false,\n topLeftCoordinates: config.debug?.hud?.topLeftCoordinates ?? false,\n coordinates: config.debug?.hud?.coordinates ?? false,\n scale: config.debug?.hud?.scale ?? false,\n tilesInView: config.debug?.hud?.tilesInView ?? false,\n fps: config.debug?.hud?.fps ?? false,\n },\n eventHandlers: {\n click: config.debug?.eventHandlers?.click ?? true,\n hover: config.debug?.eventHandlers?.hover ?? true,\n drag: config.debug?.eventHandlers?.drag ?? true,\n zoom: config.debug?.eventHandlers?.zoom ?? true,\n resize: config.debug?.eventHandlers?.resize ?? true,\n },\n },\n };\n this.config = {\n ...base,\n size: Object.freeze(base.size),\n eventHandlers: Object.freeze(base.eventHandlers),\n bounds: Object.freeze(base.bounds),\n coordinates: Object.freeze({\n ...base.coordinates,\n shownScaleRange: Object.freeze(base.coordinates.shownScaleRange),\n }),\n cursor: Object.freeze(base.cursor),\n debug: Object.freeze({\n enabled: base.debug.enabled,\n hud: Object.freeze(base.debug.hud),\n eventHandlers: Object.freeze(base.debug.eventHandlers),\n }),\n };\n }\n\n /**\n * Get a defensive copy of the current configuration.\n * @returns Normalized configuration snapshot e.g. `{ scale: 1, size: { width: 800, height: 600 }, ... }`.\n */\n get(): Readonly<Required<CanvasTileEngineConfig>> {\n const cfg = this.config;\n return {\n ...cfg,\n size: { ...cfg.size },\n eventHandlers: { ...cfg.eventHandlers },\n bounds: { ...cfg.bounds },\n coordinates: {\n ...cfg.coordinates,\n shownScaleRange: {\n min: cfg.coordinates.shownScaleRange?.min ?? 0,\n max: cfg.coordinates.shownScaleRange?.max ?? Infinity,\n },\n },\n cursor: { ...cfg.cursor },\n debug: {\n ...cfg.debug,\n hud: { ...cfg.debug.hud },\n eventHandlers: { ...cfg.debug.eventHandlers },\n },\n };\n }\n\n /**\n * Update event handlers at runtime.\n * @param handlers Partial event handlers to update.\n */\n updateEventHandlers(handlers: Partial<EventHandlers>) {\n this.config = {\n ...this.config,\n eventHandlers: Object.freeze({\n ...this.config.eventHandlers,\n ...handlers,\n }),\n };\n }\n\n /**\n * Update map bounds at runtime.\n * @param bounds New boundary limits. Use Infinity/-Infinity to remove limits on specific axes.\n */\n updateBounds(bounds: { minX: number; maxX: number; minY: number; maxY: number }) {\n this.config = {\n ...this.config,\n bounds: Object.freeze(bounds),\n };\n }\n}\n","import type { Coords } from \"../types\";\nimport { ICamera } from \"./Camera\";\nimport { screenToWorld, worldToScreen } from \"../utils/viewport\";\n\n/**\n * Transforms coordinates between world space and screen space using the active camera.\n * @internal\n */\nexport class CoordinateTransformer {\n /**\n * @param camera Camera providing origin and scaling for transformations.\n */\n constructor(private camera: ICamera) {}\n\n /**\n * Convert a world grid coordinate to screen pixels, accounting for camera offset and scale.\n * @param worldX Grid X in world space (tile index).\n * @param worldY Grid Y in world space (tile index).\n * @returns Screen-space coordinates in pixels. e.g., (e.g. `{ x: 100.5, y: 200.5 }`).\n */\n worldToScreen(worldX: number, worldY: number): Coords {\n return worldToScreen(\n { x: worldX, y: worldY },\n { x: this.camera.x, y: this.camera.y, scale: this.camera.scale }\n );\n }\n\n /**\n * Convert screen pixel coordinates back to world space grid coordinates.\n * @param screenX X coordinate in screen space (pixels).\n * @param screenY Y coordinate in screen space (pixels).\n * @returns World-space grid coordinates. (e.g. `{ x: 10, y: 20 }`).\n */\n screenToWorld(screenX: number, screenY: number): Coords {\n return screenToWorld(\n { x: screenX, y: screenY },\n { x: this.camera.x, y: this.camera.y, scale: this.camera.scale }\n );\n }\n}\n","/**\n * Spatial indexing wrapper using RBush (R-Tree) for fast viewport queries\n * @internal\n */\n\nimport RBush from \"rbush\";\n\nexport interface SpatialItem {\n x: number;\n y: number;\n /**\n * Optional world-space size (width/height). Defaults to 0 for point-like items.\n */\n size?: number;\n}\n\ninterface RBushItem<T> {\n minX: number;\n minY: number;\n maxX: number;\n maxY: number;\n item: T;\n}\n\nexport class SpatialIndex<T extends SpatialItem> {\n private tree: RBush<RBushItem<T>>;\n\n constructor() {\n this.tree = new RBush();\n }\n\n /**\n * Bulk load items into the R-Tree (much faster than individual inserts)\n */\n load(items: T[]): void {\n const rbushItems: RBushItem<T>[] = items.map((item) => {\n const size = typeof item.size === \"number\" ? item.size : 0;\n const half = size / 2;\n\n return {\n minX: item.x - half,\n minY: item.y - half,\n maxX: item.x + half,\n maxY: item.y + half,\n item,\n };\n });\n this.tree.load(rbushItems);\n }\n\n /**\n * Query all items within a rectangular range\n */\n query(minX: number, minY: number, maxX: number, maxY: number): T[] {\n const results = this.tree.search({ minX, minY, maxX, maxY });\n return results.map((r) => r.item);\n }\n\n /**\n * Clear all items\n */\n clear(): void {\n this.tree.clear();\n }\n\n /**\n * Create SpatialIndex from array of items\n */\n static fromArray<T extends SpatialItem>(items: T[]): SpatialIndex<T> {\n const index = new SpatialIndex<T>();\n index.load(items);\n return index;\n }\n}\n","import { Coords, CanvasTileEngineConfig, Rect, Circle, Text, Path, ImageItem } from \"../types\";\nimport { ICamera } from \"./Camera\";\nimport { CoordinateTransformer } from \"./CoordinateTransformer\";\nimport { Layer, type LayerHandle } from \"./Layer\";\nimport { DEFAULT_VALUES, VISIBILITY_BUFFER } from \"../constants\";\nimport { SpatialIndex } from \"./SpatialIndex\";\n\n// Threshold for using spatial indexing (below this, linear scan is faster)\nconst SPATIAL_INDEX_THRESHOLD = 500;\n// Conservative max dimension for offscreen static cache (browser limits often 16384 or 32767)\nconst MAX_STATIC_CANVAS_DIMENSION = 16384;\n\n// Cache for static layers (pre-rendered offscreen canvases)\ninterface StaticCache {\n canvas: OffscreenCanvas | HTMLCanvasElement;\n ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D;\n worldBounds: { minX: number; minY: number; maxX: number; maxY: number };\n scale: number;\n}\n\n/**\n * Canvas-specific helpers for adding draw callbacks to the layer stack.\n * @internal\n */\nexport class CanvasDraw {\n private staticCaches = new Map<string, StaticCache>();\n private staticCacheSupported: boolean;\n private warnedStaticCacheDisabled = false;\n\n constructor(private layers: Layer, private transformer: CoordinateTransformer, private camera: ICamera) {\n this.staticCacheSupported = typeof OffscreenCanvas !== \"undefined\" || typeof document !== \"undefined\";\n }\n\n /**\n * Register a generic draw callback; receives raw context, current coords, and config.\n * @param fn Callback invoked during render.\n * @param layer Layer order (lower draws first).\n */\n\n private isVisible(\n x: number,\n y: number,\n sizeWorld: number,\n topLeft: Coords,\n config: Required<CanvasTileEngineConfig>\n ) {\n const viewW = config.size.width / config.scale;\n const viewH = config.size.height / config.scale;\n const minX = topLeft.x - VISIBILITY_BUFFER.TILE_BUFFER;\n const minY = topLeft.y - VISIBILITY_BUFFER.TILE_BUFFER;\n const maxX = topLeft.x + viewW + VISIBILITY_BUFFER.TILE_BUFFER;\n const maxY = topLeft.y + viewH + VISIBILITY_BUFFER.TILE_BUFFER;\n return x + sizeWorld >= minX && x - sizeWorld <= maxX && y + sizeWorld >= minY && y - sizeWorld <= maxY;\n }\n\n private getViewportBounds(topLeft: Coords, config: Required<CanvasTileEngineConfig>) {\n const viewW = config.size.width / config.scale;\n const viewH = config.size.height / config.scale;\n return {\n minX: topLeft.x - VISIBILITY_BUFFER.TILE_BUFFER,\n minY: topLeft.y - VISIBILITY_BUFFER.TILE_BUFFER,\n maxX: topLeft.x + viewW + VISIBILITY_BUFFER.TILE_BUFFER,\n maxY: topLeft.y + viewH + VISIBILITY_BUFFER.TILE_BUFFER,\n };\n }\n\n addDrawFunction(\n fn: (ctx: CanvasRenderingContext2D, coords: Coords, config: Required<CanvasTileEngineConfig>) => void,\n layer: number = 1\n ): LayerHandle {\n return this.layers.add(layer, ({ ctx, config, topLeft }) => {\n fn(ctx, topLeft, config);\n });\n }\n\n drawRect(items: Array<Rect> | Rect, layer: number = 1): LayerHandle {\n const list = Array.isArray(items) ? items : [items];\n\n // Build spatial index for large datasets (RBush R-Tree)\n const useSpatialIndex = list.length > SPATIAL_INDEX_THRESHOLD;\n const spatialIndex = useSpatialIndex ? SpatialIndex.fromArray(list) : null;\n\n return this.layers.add(layer, ({ ctx, config, topLeft }) => {\n const bounds = this.getViewportBounds(topLeft, config);\n const visibleItems = spatialIndex\n ? spatialIndex.query(bounds.minX, bounds.minY, bounds.maxX, bounds.maxY)\n : list;\n\n ctx.save();\n let lastFillStyle: string | undefined;\n let lastStrokeStyle: string | undefined;\n let lastLineWidth: number | undefined;\n\n for (const item of visibleItems) {\n const size = item.size ?? 1;\n const origin = {\n mode: item.origin?.mode === \"self\" ? \"self\" : (\"cell\" as \"cell\" | \"self\"),\n x: item.origin?.x ?? 0.5,\n y: item.origin?.y ?? 0.5,\n };\n const style = item.style;\n\n // Skip visibility check if using spatial index (already filtered)\n if (!spatialIndex && !this.isVisible(item.x, item.y, size / 2, topLeft, config)) continue;\n\n const pos = this.transformer.worldToScreen(item.x, item.y);\n const pxSize = size * this.camera.scale;\n const { x: drawX, y: drawY } = this.computeOriginOffset(pos, pxSize, origin, this.camera);\n\n // Only update style when changed (reduces state changes)\n if (style?.fillStyle && style.fillStyle !== lastFillStyle) {\n ctx.fillStyle = style.fillStyle;\n lastFillStyle = style.fillStyle;\n }\n if (style?.strokeStyle && style.strokeStyle !== lastStrokeStyle) {\n ctx.strokeStyle = style.strokeStyle;\n lastStrokeStyle = style.strokeStyle;\n }\n if (style?.lineWidth && style.lineWidth !== lastLineWidth) {\n ctx.lineWidth = style.lineWidth;\n lastLineWidth = style.lineWidth;\n }\n\n const rotationDeg = item.rotate ?? 0;\n const rotation = rotationDeg * (Math.PI / 180);\n\n const radius = item.radius;\n\n if (rotationDeg !== 0) {\n const centerX = drawX + pxSize / 2;\n const centerY = drawY + pxSize / 2;\n ctx.save();\n ctx.translate(centerX, centerY);\n ctx.rotate(rotation);\n ctx.beginPath();\n if (radius && ctx.roundRect) {\n ctx.roundRect(-pxSize / 2, -pxSize / 2, pxSize, pxSize, radius);\n } else {\n ctx.rect(-pxSize / 2, -pxSize / 2, pxSize, pxSize);\n }\n if (style?.fillStyle) ctx.fill();\n if (style?.strokeStyle) ctx.stroke();\n ctx.restore();\n } else {\n ctx.beginPath();\n if (radius && ctx.roundRect) {\n ctx.roundRect(drawX, drawY, pxSize, pxSize, radius);\n } else {\n ctx.rect(drawX, drawY, pxSize, pxSize);\n }\n if (style?.fillStyle) ctx.fill();\n if (style?.strokeStyle) ctx.stroke();\n }\n }\n ctx.restore();\n });\n }\n\n drawLine(\n items: Array<{ from: Coords; to: Coords }> | { from: Coords; to: Coords },\n style?: { strokeStyle?: string; lineWidth?: number },\n layer: number = 1\n ): LayerHandle {\n const list = Array.isArray(items) ? items : [items];\n\n return this.layers.add(layer, ({ ctx, config, topLeft }) => {\n ctx.save();\n if (style?.strokeStyle) ctx.strokeStyle = style.strokeStyle;\n if (style?.lineWidth) ctx.lineWidth = style.lineWidth;\n\n ctx.beginPath();\n for (const item of list) {\n const centerX = (item.from.x + item.to.x) / 2;\n const centerY = (item.from.y + item.to.y) / 2;\n const halfExtent = Math.max(Math.abs(item.from.x - item.to.x), Math.abs(item.from.y - item.to.y)) / 2;\n if (!this.isVisible(centerX, centerY, halfExtent, topLeft, config)) continue;\n\n const a = this.transformer.worldToScreen(item.from.x, item.from.y);\n const b = this.transformer.worldToScreen(item.to.x, item.to.y);\n\n ctx.moveTo(a.x, a.y);\n ctx.lineTo(b.x, b.y);\n }\n ctx.stroke();\n ctx.restore();\n });\n }\n\n drawCircle(items: Array<Circle> | Circle, layer: number = 1): LayerHandle {\n const list = Array.isArray(items) ? items : [items];\n\n // Build spatial index for large datasets (RBush R-Tree)\n const useSpatialIndex = list.length > SPATIAL_INDEX_THRESHOLD;\n const spatialIndex = useSpatialIndex ? SpatialIndex.fromArray(list) : null;\n\n return this.layers.add(layer, ({ ctx, config, topLeft }) => {\n const bounds = this.getViewportBounds(topLeft, config);\n const visibleItems = spatialIndex\n ? spatialIndex.query(bounds.minX, bounds.minY, bounds.maxX, bounds.maxY)\n : list;\n\n ctx.save();\n let lastFillStyle: string | undefined;\n let lastStrokeStyle: string | undefined;\n let lastLineWidth: number | undefined;\n\n for (const item of visibleItems) {\n const size = item.size ?? 1;\n const origin = {\n mode: item.origin?.mode === \"self\" ? \"self\" : (\"cell\" as \"cell\" | \"self\"),\n x: item.origin?.x ?? 0.5,\n y: item.origin?.y ?? 0.5,\n };\n const style = item.style;\n\n // Skip visibility check if using spatial index (already filtered)\n if (!spatialIndex && !this.isVisible(item.x, item.y, size / 2, topLeft, config)) continue;\n\n const pos = this.transformer.worldToScreen(item.x, item.y);\n const pxSize = size * this.camera.scale;\n const radius = pxSize / 2;\n const { x: drawX, y: drawY } = this.computeOriginOffset(pos, pxSize, origin, this.camera);\n\n // Only update style when changed\n if (style?.fillStyle && style.fillStyle !== lastFillStyle) {\n ctx.fillStyle = style.fillStyle;\n lastFillStyle = style.fillStyle;\n }\n if (style?.strokeStyle && style.strokeStyle !== lastStrokeStyle) {\n ctx.strokeStyle = style.strokeStyle;\n lastStrokeStyle = style.strokeStyle;\n }\n if (style?.lineWidth && style.lineWidth !== lastLineWidth) {\n ctx.lineWidth = style.lineWidth;\n lastLineWidth = style.lineWidth;\n }\n\n ctx.beginPath();\n ctx.arc(drawX + radius, drawY + radius, radius, 0, Math.PI * 2);\n if (style?.fillStyle) ctx.fill();\n if (style?.strokeStyle) ctx.stroke();\n }\n ctx.restore();\n });\n }\n\n drawText(\n items: Array<Text> | Text,\n style?: { fillStyle?: string; font?: string; textAlign?: CanvasTextAlign; textBaseline?: CanvasTextBaseline },\n layer: number = 2\n ): LayerHandle {\n const list = Array.isArray(items) ? items : [items];\n\n return this.layers.add(layer, ({ ctx, config, topLeft }) => {\n ctx.save();\n if (style?.font) ctx.font = style.font;\n if (style?.fillStyle) ctx.fillStyle = style.fillStyle;\n ctx.textAlign = style?.textAlign ?? \"center\";\n ctx.textBaseline = style?.textBaseline ?? \"middle\";\n\n for (const item of list) {\n if (!this.isVisible(item.coords.x, item.coords.y, 0, topLeft, config)) continue;\n const pos = this.transformer.worldToScreen(item.coords.x, item.coords.y);\n ctx.fillText(item.text, pos.x, pos.y);\n }\n ctx.restore();\n });\n }\n\n drawPath(\n items: Array<Path> | Path,\n style?: { strokeStyle?: string; lineWidth?: number },\n layer: number = 1\n ): LayerHandle {\n const list = Array.isArray(items[0]) ? (items as Array<Coords[]>) : [items as Coords[]];\n\n return this.layers.add(layer, ({ ctx, config, topLeft }) => {\n ctx.save();\n if (style?.strokeStyle) ctx.strokeStyle = style.strokeStyle;\n if (style?.lineWidth) ctx.lineWidth = style.lineWidth;\n\n ctx.beginPath();\n for (const points of list) {\n if (!points.length) continue;\n const xs = points.map((p) => p.x);\n const ys = points.map((p) => p.y);\n const minX = Math.min(...xs);\n const maxX = Math.max(...xs);\n const minY = Math.min(...ys);\n const maxY = Math.max(...ys);\n const centerX = (minX + maxX) / 2;\n const centerY = (minY + maxY) / 2;\n const halfExtent = Math.max(maxX - minX, maxY - minY) / 2;\n if (!this.isVisible(centerX, centerY, halfExtent, topLeft, config)) continue;\n\n const first = this.transformer.worldToScreen(points[0].x, points[0].y);\n ctx.moveTo(first.x, first.y);\n\n for (let i = 1; i < points.length; i++) {\n const p = this.transformer.worldToScreen(points[i].x, points[i].y);\n ctx.lineTo(p.x, p.y);\n }\n }\n ctx.stroke();\n ctx.restore();\n });\n }\n\n drawImage(items: Array<ImageItem> | ImageItem, layer: number = 1): LayerHandle {\n const list = Array.isArray(items) ? items : [items];\n\n // Build spatial index for large datasets (RBush R-Tree)\n const useSpatialIndex = list.length > SPATIAL_INDEX_THRESHOLD;\n const spatialIndex = useSpatialIndex ? SpatialIndex.fromArray(list) : null;\n\n return this.layers.add(layer, ({ ctx, config, topLeft }) => {\n const bounds = this.getViewportBounds(topLeft, config);\n const visibleItems = spatialIndex\n ? spatialIndex.query(bounds.minX, bounds.minY, bounds.maxX, bounds.maxY)\n : list;\n\n for (const item of visibleItems) {\n const size = item.size ?? 1;\n const origin = {\n mode: item.origin?.mode === \"self\" ? \"self\" : (\"cell\" as \"cell\" | \"self\"),\n x: item.origin?.x ?? 0.5,\n y: item.origin?.y ?? 0.5,\n };\n\n // Skip visibility check if using spatial index (already filtered)\n if (!spatialIndex && !this.isVisible(item.x, item.y, size / 2, topLeft, config)) continue;\n\n const pos = this.transformer.worldToScreen(item.x, item.y);\n const pxSize = size * this.camera.scale;\n\n // preserve aspect\n const aspect = item.img.width / item.img.height;\n\n let drawW = pxSize;\n let drawH = pxSize;\n\n if (aspect > 1) drawH = pxSize / aspect;\n else drawW = pxSize * aspect;\n\n // origin SELF/CELL\n const { x: baseX, y: baseY } = this.computeOriginOffset(pos, pxSize, origin, this.camera);\n\n const offsetX = baseX + (pxSize - drawW) / 2;\n const offsetY = baseY + (pxSize - drawH) / 2;\n\n const rotationDeg = item.rotate ?? 0;\n const rotation = rotationDeg * (Math.PI / 180);\n\n if (rotationDeg !== 0) {\n const centerX = offsetX + drawW / 2;\n const centerY = offsetY + drawH / 2;\n ctx.save();\n ctx.translate(centerX, centerY);\n ctx.rotate(rotation);\n ctx.drawImage(item.img, -drawW / 2, -drawH / 2, drawW, drawH);\n ctx.restore();\n } else {\n ctx.drawImage(item.img, offsetX, offsetY, drawW, drawH);\n }\n }\n });\n }\n\n drawGridLines(cellSize: number, style: { strokeStyle: string; lineWidth: number }, layer: number = 0): LayerHandle {\n return this.layers.add(layer, ({ ctx, config, topLeft }) => {\n const viewW = config.size.width / config.scale;\n const viewH = config.size.height / config.scale;\n\n const startX = Math.floor(topLeft.x / cellSize) * cellSize - DEFAULT_VALUES.CELL_CENTER_OFFSET;\n const endX = Math.ceil((topLeft.x + viewW) / cellSize) * cellSize - DEFAULT_VALUES.CELL_CENTER_OFFSET;\n const startY = Math.floor(topLeft.y / cellSize) * cellSize - DEFAULT_VALUES.CELL_CENTER_OFFSET;\n const endY = Math.ceil((topLeft.y + viewH) / cellSize) * cellSize - DEFAULT_VALUES.CELL_CENTER_OFFSET;\n\n ctx.save();\n\n ctx.strokeStyle = style.strokeStyle;\n ctx.lineWidth = style.lineWidth;\n\n ctx.beginPath();\n\n for (let x = startX; x <= endX; x += cellSize) {\n const p1 = this.transformer.worldToScreen(x, startY);\n const p2 = this.transformer.worldToScreen(x, endY);\n ctx.moveTo(p1.x, p1.y);\n ctx.lineTo(p2.x, p2.y);\n }\n\n for (let y = startY; y <= endY; y += cellSize) {\n const p1 = this.transformer.worldToScreen(startX, y);\n const p2 = this.transformer.worldToScreen(endX, y);\n ctx.moveTo(p1.x, p1.y);\n ctx.lineTo(p2.x, p2.y);\n }\n\n ctx.stroke();\n ctx.restore();\n });\n }\n\n private computeOriginOffset(\n pos: Coords,\n pxSize: number,\n origin: { mode: \"cell\" | \"self\"; x: number; y: number },\n camera: ICamera\n ) {\n if (origin.mode === \"cell\") {\n const cell = camera.scale;\n return {\n x: pos.x - cell / 2 + origin.x * cell - pxSize / 2,\n y: pos.y - cell / 2 + origin.y * cell - pxSize / 2,\n };\n }\n\n return {\n x: pos.x - origin.x * pxSize,\n y: pos.y - origin.y * pxSize,\n };\n }\n\n /**\n * Helper to create or get a static cache for pre-rendered content.\n * Handles bounds calculation, canvas creation, and rebuild logic.\n */\n private getOrCreateStaticCache<T extends { x: number; y: number; size?: number; radius?: number | number[] }>(\n items: T[],\n cacheKey: string,\n renderFn: (\n ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,\n item: T,\n x: number,\n y: number,\n pxSize: number\n ) => void\n ): StaticCache | null {\n if (!this.staticCacheSupported) {\n if (!this.warnedStaticCacheDisabled) {\n console.warn(\"[CanvasDraw] Static cache disabled: OffscreenCanvas not available.\");\n this.warnedStaticCacheDisabled = true;\n }\n return null;\n }\n\n // Calculate world bounds from items\n let minX = Infinity,\n maxX = -Infinity,\n minY = Infinity,\n maxY = -Infinity;\n\n for (const item of items) {\n const size = item.size ?? 1;\n if (item.x - size / 2 < minX) minX = item.x - size / 2;\n if (item.x + size / 2 > maxX) maxX = item.x + size / 2;\n if (item.y - size / 2 < minY) minY = item.y - size / 2;\n if (item.y + size / 2 > maxY) maxY = item.y + size / 2;\n }\n\n // Add padding\n minX -= 1;\n minY -= 1;\n maxX += 1;\n maxY += 1;\n\n const worldWidth = maxX - minX;\n const worldHeight = maxY - minY;\n\n // Use current scale for rendering\n const renderScale = this.camera.scale;\n const canvasWidth = Math.ceil(worldWidth * renderScale);\n const canvasHeight = Math.ceil(worldHeight * renderScale);\n\n if (canvasWidth > MAX_STATIC_CANVAS_DIMENSION || canvasHeight > MAX_STATIC_CANVAS_DIMENSION) {\n if (!this.warnedStaticCacheDisabled) {\n console.warn(`Static cache disabled: offscreen canvas too large (${canvasWidth}x${canvasHeight}).`);\n this.warnedStaticCacheDisabled = true;\n }\n return null;\n }\n\n // Check if we need to create or update cache\n let cache = this.staticCaches.get(cacheKey);\n const needsRebuild =\n !cache ||\n cache.scale !== renderScale ||\n cache.worldBounds.minX !== minX ||\n cache.worldBounds.maxX !== maxX ||\n cache.worldBounds.minY !== minY ||\n cache.worldBounds.maxY !== maxY;\n\n if (needsRebuild) {\n // Create offscreen canvas\n const offscreen =\n typeof OffscreenCanvas !== \"undefined\"\n ? new OffscreenCanvas(canvasWidth, canvasHeight)\n : document.createElement(\"canvas\");\n\n // Guard instanceof with typeof to avoid ReferenceError when OffscreenCanvas is undefined (e.g., jsdom)\n const isOffscreenCanvas = typeof OffscreenCanvas !== \"undefined\" && offscreen instanceof OffscreenCanvas;\n\n if (!isOffscreenCanvas) {\n (offscreen as HTMLCanvasElement).width = canvasWidth;\n (offscreen as HTMLCanvasElement).height = canvasHeight;\n }\n\n const offCtx = offscreen.getContext(\"2d\");\n\n if (!offCtx) {\n if (!this.warnedStaticCacheDisabled) {\n console.warn(\"[CanvasDraw] Static cache disabled: 2D context unavailable.\");\n this.warnedStaticCacheDisabled = true;\n }\n return null;\n }\n\n // Render all items using the provided render function\n for (const item of items) {\n const size = item.size ?? 1;\n const pxSize = size * renderScale;\n const x = (item.x + DEFAULT_VALUES.CELL_CENTER_OFFSET - minX) * renderScale - pxSize / 2;\n const y = (item.y + DEFAULT_VALUES.CELL_CENTER_OFFSET - minY) * renderScale - pxSize / 2;\n\n renderFn(offCtx, item, x, y, pxSize);\n }\n\n cache = {\n canvas: offscreen,\n ctx: offCtx,\n worldBounds: { minX, minY, maxX, maxY },\n scale: renderScale,\n };\n\n this.staticCaches.set(cacheKey, cache);\n }\n\n return cache || null;\n }\n\n /**\n * Helper to add a layer callback that blits from a static cache.\n */\n private addStaticCacheLayer(cache: StaticCache | null, layer: number): LayerHandle | null {\n if (!cache) {\n return null;\n }\n const cachedCanvas = cache.canvas;\n const cachedBounds = cache.worldBounds;\n const cachedScale = cache.scale;\n\n return this.layers.add(layer, ({ ctx, config, topLeft }) => {\n const viewW = config.size.width / config.scale;\n const viewH = config.size.height / config.scale;\n\n // Source rect in cached canvas (what part of cache to draw)\n const srcX = (topLeft.x - cachedBounds.minX) * cachedScale;\n const srcY = (topLeft.y - cachedBounds.minY) * cachedScale;\n const srcW = viewW * cachedScale;\n const srcH = viewH * cachedScale;\n\n // Destination on screen\n ctx.drawImage(cachedCanvas, srcX, srcY, srcW, srcH, 0, 0, config.size.width, config.size.height);\n });\n }\n\n /**\n * Draw rectangles with pre-rendering cache.\n * Renders all items once to an offscreen canvas, then blits the visible portion each frame.\n * Ideal for large static datasets like mini-maps.\n * @param items Array of draw objects\n * @param cacheKey Unique key for this cache (e.g., \"minimap-items\")\n * @param layer Layer order\n */\n drawStaticRect(items: Array<Rect>, cacheKey: string, layer: number = 1): LayerHandle {\n let lastFillStyle: string | undefined;\n\n const cache = this.getOrCreateStaticCache(items, cacheKey, (ctx, item, x, y, pxSize) => {\n const style = item.style;\n const rotationDeg = item.rotate ?? 0;\n const rotation = rotationDeg * (Math.PI / 180);\n const radius = item.radius;\n\n if (style?.fillStyle && style.fillStyle !== lastFillStyle) {\n ctx.fillStyle = style.fillStyle;\n lastFillStyle = style.fillStyle;\n }\n\n if (rotationDeg !== 0) {\n const centerX = x + pxSize / 2;\n const centerY = y + pxSize / 2;\n ctx.save();\n ctx.translate(centerX, centerY);\n ctx.rotate(rotation);\n if (radius && ctx.roundRect) {\n ctx.beginPath();\n ctx.roundRect(-pxSize / 2, -pxSize / 2, pxSize, pxSize, radius);\n ctx.fill();\n } else {\n ctx.fillRect(-pxSize / 2, -pxSize / 2, pxSize, pxSize);\n }\n ctx.restore();\n } else {\n if (radius && ctx.roundRect) {\n ctx.beginPath();\n ctx.roundRect(x, y, pxSize, pxSize, radius);\n ctx.fill();\n } else {\n ctx.fillRect(x, y, pxSize, pxSize);\n }\n }\n });\n\n if (!cache) {\n return this.drawRect(items, layer);\n }\n\n return this.addStaticCacheLayer(cache, layer)!;\n }\n\n /**\n * Draw images with pre-rendering cache.\n * Renders all items once to an offscreen canvas, then blits the visible portion each frame.\n * Ideal for large static datasets like terrain tiles or static decorations.\n * @param items Array of image objects with position and HTMLImageElement\n * @param cacheKey Unique key for this cache (e.g., \"terrain-cache\")\n * @param layer Layer order\n */\n drawStaticImage(items: Array<ImageItem>, cacheKey: string, layer: number = 1): LayerHandle {\n const cache = this.getOrCreateStaticCache(items, cacheKey, (ctx, item, x, y, pxSize) => {\n const img = (item as { img: HTMLImageElement }).img;\n const rotationDeg = (item as { rotate?: number }).rotate ?? 0;\n const rotation = rotationDeg * (Math.PI / 180);\n const aspect = img.width / img.height;\n let drawW = pxSize;\n let drawH = pxSize;\n\n if (aspect > 1) drawH = pxSize / aspect;\n else drawW = pxSize * aspect;\n\n // x, y are top-left of pxSize box, need to center image within it\n const imgX = x + (pxSize - drawW) / 2;\n const imgY = y + (pxSize - drawH) / 2;\n\n if (rotationDeg !== 0) {\n const centerX = imgX + drawW / 2;\n const centerY = imgY + drawH / 2;\n ctx.save();\n ctx.translate(centerX, centerY);\n ctx.rotate(rotation);\n ctx.drawImage(img, -drawW / 2, -drawH / 2, drawW, drawH);\n ctx.restore();\n } else {\n ctx.drawImage(img, imgX, imgY, drawW, drawH);\n }\n });\n\n if (!cache) {\n return this.drawImage(items, layer);\n }\n\n return this.addStaticCacheLayer(cache, layer)!;\n }\n\n /**\n * Draw circles with pre-rendering cache.\n * Renders all items once to an offscreen canvas, then blits the visible portion each frame.\n * Ideal for large static datasets like mini-maps.\n * @param items Array of draw objects\n * @param cacheKey Unique key for this cache (e.g., \"minimap-circles\")\n * @param layer Layer order\n */\n drawStaticCircle(items: Array<Circle>, cacheKey: string, layer: number = 1): LayerHandle {\n let lastFillStyle: string | undefined;\n\n const cache = this.getOrCreateStaticCache(items, cacheKey, (ctx, item, x, y, pxSize) => {\n const style = item.style;\n const radius = pxSize / 2;\n\n if (style?.fillStyle && style.fillStyle !== lastFillStyle) {\n ctx.fillStyle = style.fillStyle;\n lastFillStyle = style.fillStyle;\n }\n\n ctx.beginPath();\n ctx.arc(x + radius, y + radius, radius, 0, Math.PI * 2);\n ctx.fill();\n });\n\n if (!cache) {\n return this.drawCircle(items, layer);\n }\n\n return this.addStaticCacheLayer(cache, layer)!;\n }\n\n /**\n * Clear a static cache\n * @param cacheKey The cache key to clear, or undefined to clear all\n */\n clearStaticCache(cacheKey?: string) {\n if (cacheKey) {\n this.staticCaches.delete(cacheKey);\n } else {\n this.staticCaches.clear();\n }\n }\n\n /**\n * Release cached canvases and layer callbacks.\n */\n destroy() {\n this.staticCaches.clear();\n this.layers.clear();\n }\n}\n","type HandlerMap = {\n click?: (e: MouseEvent) => void;\n mousedown?: (e: MouseEvent) => void;\n mousemove?: (e: MouseEvent) => void;\n mouseup?: (e: MouseEvent) => void;\n mouseleave?: (e: MouseEvent) => void;\n wheel?: (e: WheelEvent) => void;\n touchstart?: (e: TouchEvent) => void;\n touchmove?: (e: TouchEvent) => void;\n touchend?: (e: TouchEvent) => void;\n};\n\n/**\n * Thin wrapper to attach/detach DOM event listeners on the canvas.\n * @internal\n */\nexport class EventBinder {\n constructor(private canvas: HTMLCanvasElement, private handlers: HandlerMap) {}\n\n attach() {\n if (this.handlers.click) {\n this.canvas.addEventListener(\"click\", this.handlers.click);\n }\n\n if (this.handlers.mousedown) {\n this.canvas.addEventListener(\"mousedown\", this.handlers.mousedown);\n }\n\n if (this.handlers.mousemove) {\n this.canvas.addEventListener(\"mousemove\", this.handlers.mousemove);\n }\n\n if (this.handlers.mouseup) {\n this.canvas.addEventListener(\"mouseup\", this.handlers.mouseup);\n }\n\n if (this.handlers.mouseleave) {\n this.canvas.addEventListener(\"mouseleave\", this.handlers.mouseleave);\n }\n\n if (this.handlers.wheel) {\n this.canvas.addEventListener(\"wheel\", this.handlers.wheel, { passive: false });\n }\n\n if (this.handlers.touchstart) {\n this.canvas.addEventListener(\"touchstart\", this.handlers.touchstart, { passive: false });\n }\n\n if (this.handlers.touchmove) {\n this.canvas.addEventListener(\"touchmove\", this.handlers.touchmove, { passive: false });\n }\n\n if (this.handlers.touchend) {\n this.canvas.addEventListener(\"touchend\", this.handlers.touchend, { passive: false });\n }\n }\n\n detach() {\n if (this.handlers.click) {\n this.canvas.removeEventListener(\"click\", this.handlers.click);\n }\n\n if (this.handlers.mousedown) {\n this.canvas.removeEventListener(\"mousedown\", this.handlers.mousedown);\n }\n\n if (this.handlers.mousemove) {\n this.canvas.removeEventListener(\"mousemove\", this.handlers.mousemove);\n }\n\n if (this.handlers.mouseup) {\n this.canvas.removeEventListener(\"mouseup\", this.handlers.mouseup);\n }\n\n if (this.handlers.mouseleave) {\n this.canvas.removeEventListener(\"mouseleave\", this.handlers.mouseleave);\n }\n\n if (this.handlers.wheel) {\n this.canvas.removeEventListener(\"wheel\", this.handlers.wheel);\n }\n\n if (this.handlers.touchstart) {\n this.canvas.removeEventListener(\"touchstart\", this.handlers.touchstart);\n }\n\n if (this.handlers.touchmove) {\n this.canvas.removeEventListener(\"touchmove\", this.handlers.touchmove);\n }\n\n if (this.handlers.touchend) {\n this.canvas.removeEventListener(\"touchend\", this.handlers.touchend);\n }\n }\n}\n","import { onClickCallback, onHoverCallback, onZoomCallback } from \"../../types\";\nimport { ICamera } from \"../Camera\";\nimport { Config } from \"../Config\";\nimport { CoordinateTransformer } from \"../CoordinateTransformer\";\nimport { ViewportState } from \"../ViewportState\";\n\n/**\n * Handles gesture logic (click, hover, drag, zoom) independent of DOM binding.\n * @internal\n */\nexport class GestureController {\n private isDragging = false;\n private shouldPreventClick = false;\n private lastPos = { x: 0, y: 0 };\n\n // Pinch-to-zoom state\n private isPinching = false;\n private lastPinchDistance = 0;\n private lastPinchCenter = { x: 0, y: 0 };\n\n public onClick?: onClickCallback;\n public onHover?: onHoverCallback;\n public onMouseDown?: () => void;\n public onMouseUp?: () => void;\n public onMouseLeave?: () => void;\n public onZoom?: onZoomCallback;\n\n constructor(\n private canvas: HTMLCanvasElement,\n private camera: ICamera,\n private viewport: ViewportState,\n private config: Config,\n private transformer: CoordinateTransformer,\n private onCameraChange: () => void\n ) {}\n\n handleClick = (e: MouseEvent) => {\n if (this.shouldPreventClick) {\n this.shouldPreventClick = false;\n return;\n }\n if (!this.config.get().eventHandlers.click || !this.onClick) {\n return;\n }\n const rect = this.canvas.getBoundingClientRect();\n const mouseX = e.clientX - rect.left;\n const mouseY = e.clientY - rect.top;\n const world = this.transformer.screenToWorld(mouseX, mouseY);\n const screen = this.transformer.worldToScreen(Math.floor(world.x), Math.floor(world.y));\n\n this.onClick(\n {\n raw: world,\n snapped: { x: Math.floor(world.x), y: Math.floor(world.y) },\n },\n {\n raw: { x: e.clientX - rect.left, y: e.clientY - rect.top },\n snapped: {\n x: screen.x,\n y: screen.y,\n },\n },\n {\n raw: { x: e.clientX, y: e.clientY },\n snapped: {\n x: screen.x + rect.left,\n y: screen.y + rect.top,\n },\n }\n );\n };\n\n handleMouseDown = (e: MouseEvent) => {\n if (this.onMouseDown) {\n this.onMouseDown();\n }\n\n if (!this.config.get().eventHandlers.drag) {\n return;\n }\n\n this.isDragging = true;\n this.shouldPreventClick = false;\n this.lastPos = { x: e.clientX, y: e.clientY };\n };\n\n handleMouseMove = (e: MouseEvent) => {\n if (!this.isDragging) {\n if (this.onHover && this.config.get().eventHandlers.hover) {\n const rect = this.canvas.getBoundingClientRect();\n const mouseX = e.clientX - rect.left;\n const mouseY = e.clientY - rect.top;\n const world = this.transformer.screenToWorld(mouseX, mouseY);\n const screen = this.transformer.worldToScreen(Math.floor(world.x), Math.floor(world.y));\n\n this.onHover(\n { raw: world, snapped: { x: Math.floor(world.x), y: Math.floor(world.y) } },\n {\n raw: { x: e.clientX - rect.left, y: e.clientY - rect.top },\n snapped: {\n x: screen.x,\n y: screen.y,\n },\n },\n {\n raw: { x: e.clientX, y: e.clientY },\n snapped: {\n x: screen.x + rect.left,\n y: screen.y + rect.top,\n },\n }\n );\n }\n return;\n }\n\n const dx = e.clientX - this.lastPos.x;\n const dy = e.clientY - this.lastPos.y;\n if (dx !== 0 || dy !== 0) {\n this.canvas.style.cursor = this.config.get().cursor.move || \"move\";\n this.shouldPreventClick = true;\n }\n this.camera.pan(dx, dy);\n this.lastPos = { x: e.clientX, y: e.clientY };\n this.onCameraChange();\n };\n\n handleMouseUp = () => {\n if (this.onMouseUp) {\n this.onMouseUp();\n }\n\n this.isDragging = false;\n this.canvas.style.cursor = this.config.get().cursor.default || \"default\";\n };\n\n handleMouseLeave = () => {\n if (this.onMouseLeave) {\n this.onMouseLeave();\n }\n\n this.isDragging = false;\n this.canvas.style.cursor = this.config.get().cursor.default || \"default\";\n };\n\n handleTouchStart = (e: TouchEvent) => {\n const eventHandlers = this.config.get().eventHandlers;\n\n // Handle pinch-to-zoom (2 fingers)\n if (e.touches.length === 2 && eventHandlers.zoom) {\n e.preventDefault();\n this.isPinching = true;\n this.isDragging = false;\n this.lastPinchDistance = this.getTouchDistance(e.touches);\n this.lastPinchCenter = this.getTouchCenter(e.touches);\n return;\n }\n\n // Handle single finger drag\n if (!eventHandlers.drag) return;\n if (e.touches.length !== 1) return;\n const t = e.touches[0];\n this.isDragging = true;\n this.isPinching = false;\n this.shouldPreventClick = false;\n this.lastPos = { x: t.clientX, y: t.clientY };\n };\n\n handleTouchMove = (e: TouchEvent) => {\n // Handle pinch-to-zoom\n if (this.isPinching && e.touches.length === 2) {\n e.preventDefault();\n\n const currentDistance = this.getTouchDistance(e.touches);\n const currentCenter = this.getTouchCenter(e.touches);\n const rect = this.canvas.getBoundingClientRect();\n\n // Calculate zoom factor from pinch distance change\n const scaleFactor = currentDistance / this.lastPinchDistance;\n\n // Get pinch center relative to canvas\n const centerX = currentCenter.x - rect.left;\n const centerY = currentCenter.y - rect.top;\n\n // Apply zoom\n this.camera.zoomByFactor(scaleFactor, centerX, centerY);\n\n // Also pan if pinch center moved\n const dx = currentCenter.x - this.lastPinchCenter.x;\n const dy = currentCenter.y - this.lastPinchCenter.y;\n if (dx !== 0 || dy !== 0) {\n this.camera.pan(dx, dy);\n }\n\n this.lastPinchDistance = currentDistance;\n this.lastPinchCenter = currentCenter;\n if (this.onZoom) {\n this.onZoom(this.camera.scale);\n }\n this.onCameraChange();\n return;\n }\n\n // Handle single finger drag\n if (!this.isDragging || e.touches.length !== 1) {\n return;\n }\n e.preventDefault();\n const t = e.touches[0];\n const dx = t.clientX - this.lastPos.x;\n const dy = t.clientY - this.lastPos.y;\n if (dx !== 0 || dy !== 0) {\n this.canvas.style.cursor = this.config.get().cursor.move || \"move\";\n this.shouldPreventClick = true;\n }\n this.camera.pan(dx, dy);\n this.lastPos = { x: t.clientX, y: t.clientY };\n this.onCameraChange();\n };\n\n handleTouchEnd = (e: TouchEvent) => {\n // If we still have 2 fingers, stay in pinch mode\n if (e.touches.length >= 2 && this.isPinching) {\n this.lastPinchDistance = this.getTouchDistance(e.touches);\n this.lastPinchCenter = this.getTouchCenter(e.touches);\n return;\n }\n\n // If we have 1 finger left after pinching, switch to drag mode\n if (e.touches.length === 1 && this.isPinching) {\n this.isPinching = false;\n if (this.config.get().eventHandlers.drag) {\n this.isDragging = true;\n const t = e.touches[0];\n this.lastPos = { x: t.clientX, y: t.clientY };\n }\n return;\n }\n\n // All fingers lifted\n this.isDragging = false;\n this.isPinching = false;\n this.canvas.style.cursor = this.config.get().cursor.default || \"default\";\n };\n\n /**\n * Calculate the distance between two touch points.\n */\n private getTouchDistance(touches: TouchList): number {\n const dx = touches[1].clientX - touches[0].clientX;\n const dy = touches[1].clientY - touches[0].clientY;\n return Math.sqrt(dx * dx + dy * dy);\n }\n\n /**\n * Calculate the center point between two touches.\n */\n private getTouchCenter(touches: TouchList): { x: number; y: number } {\n return {\n x: (touches[0].clientX + touches[1].clientX) / 2,\n y: (touches[0].clientY + touches[1].clientY) / 2,\n };\n }\n\n handleWheel = (e: WheelEvent) => {\n if (!this.config.get().eventHandlers.zoom) return;\n e.preventDefault();\n const rect = this.canvas.getBoundingClientRect();\n this.camera.zoom(e.clientX, e.clientY, e.deltaY, rect);\n if (this.onZoom) {\n this.onZoom(this.camera.scale);\n }\n this.onCameraChange();\n };\n}\n","import { Camera } from \"../Camera\";\nimport { Config } from \"../Config\";\nimport { ViewportState } from \"../ViewportState\";\n\n/**\n * Observes canvas resizing and keeps viewport/camera in sync.\n * @internal\n */\nexport class ResizeWatcher {\n private resizeObserver?: ResizeObserver;\n private handleWindowResize?: () => void;\n private currentDpr: number;\n\n public onResize?: () => void;\n\n constructor(\n private wrapper: HTMLDivElement,\n private canvas: HTMLCanvasElement,\n private viewport: ViewportState,\n private camera: Camera,\n private config: Config,\n private onCameraChange: () => void\n ) {\n this.currentDpr = this.viewport.dpr;\n }\n\n start() {\n // Ensure DPR is up to date before sizing\n this.viewport.updateDpr();\n this.currentDpr = this.viewport.dpr;\n\n const size = this.viewport.getSize();\n\n const configSize = this.config.get().size;\n\n const maxWidth = configSize?.maxWidth;\n const maxHeight = configSize?.maxHeight;\n\n const minWidth = configSize?.minWidth;\n const minHeight = configSize?.minHeight;\n\n size.width = this.clamp(size.width, minWidth, maxWidth);\n size.height = this.clamp(size.height, minHeight, maxHeight);\n\n Object.assign(this.wrapper.style, {\n resize: \"both\",\n overflow: \"hidden\",\n width: `${size.width}px`,\n height: `${size.height}px`,\n touchAction: \"none\",\n position: \"relative\",\n maxWidth: maxWidth ? `${maxWidth}px` : \"\",\n maxHeight: maxHeight ? `${maxHeight}px` : \"\",\n minWidth: minWidth ? `${minWidth}px` : \"\",\n minHeight: minHeight ? `${minHeight}px` : \"\",\n });\n\n this.resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const { width: rawW, height: rawH } = entry.contentRect;\n const width = this.clamp(rawW, minWidth, maxWidth);\n const height = this.clamp(rawH, minHeight, maxHeight);\n const prev = this.viewport.getSize();\n\n if (width === prev.width && height === prev.height) {\n // No effective size change after clamping\n continue;\n }\n\n const diffW = width - prev.width;\n const diffH = height - prev.height;\n const dpr = this.viewport.dpr;\n\n this.camera.adjustForResize(diffW, diffH);\n this.viewport.setSize(width, height);\n\n // Set canvas resolution (physical pixels for HiDPI)\n this.canvas.width = width * dpr;\n this.canvas.height = height * dpr;\n\n // Set CSS size (logical pixels)\n this.canvas.style.width = `${width}px`;\n this.canvas.style.height = `${height}px`;\n\n this.wrapper.style.width = `${width}px`;\n this.wrapper.style.height = `${height}px`;\n\n if (this.onResize) {\n this.onResize();\n }\n this.onCameraChange();\n }\n });\n\n this.resizeObserver.observe(this.wrapper);\n\n this.attachDprWatcher();\n }\n\n stop() {\n if (this.resizeObserver) {\n this.resizeObserver.unobserve(this.wrapper);\n this.resizeObserver.disconnect();\n }\n\n this.resizeObserver = undefined;\n\n if (this.handleWindowResize) {\n window.removeEventListener(\"resize\", this.handleWindowResize);\n this.handleWindowResize = undefined;\n }\n }\n\n private clamp(value: number, min?: number, max?: number) {\n let result = value;\n if (min !== undefined) result = Math.max(min, result);\n if (max !== undefined) result = Math.min(max, result);\n return result;\n }\n\n /**\n * Listen for devicePixelRatio changes (e.g., monitor switch) and rescale canvas.\n */\n private attachDprWatcher() {\n if (typeof window === \"undefined\") {\n return;\n }\n\n this.handleWindowResize = () => {\n const prevDpr = this.currentDpr;\n this.viewport.updateDpr();\n const nextDpr = this.viewport.dpr;\n\n if (nextDpr === prevDpr) {\n return;\n }\n\n this.currentDpr = nextDpr;\n const { width, height } = this.viewport.getSize();\n\n // Update canvas resolution for new DPR while keeping logical size\n this.canvas.width = width * nextDpr;\n this.canvas.height = height * nextDpr;\n this.canvas.style.width = `${width}px`;\n this.canvas.style.height = `${height}px`;\n\n if (this.onResize) {\n this.onResize();\n }\n\n this.onCameraChange();\n };\n\n window.addEventListener(\"resize\", this.handleWindowResize, { passive: true });\n }\n}\n","import { onClickCallback, onHoverCallback, onZoomCallback } from \"../../types\";\nimport { Camera, ICamera } from \"../Camera\";\nimport { Config } from \"../Config\";\nimport { CoordinateTransformer } from \"../CoordinateTransformer\";\nimport { ViewportState } from \"../ViewportState\";\nimport { EventBinder } from \"./EventBinder\";\nimport { GestureController } from \"./GestureController\";\nimport { ResizeWatcher } from \"./ResizeWatcher\";\n\n/**\n * Coordinates DOM binding, gesture handling, and resize observation.\n * @internal\n */\nexport class EventManager {\n private binder: EventBinder;\n private gestures: GestureController;\n private resizeWatcher?: ResizeWatcher;\n private attached = false;\n\n public onResize?: () => void;\n\n public get onClick(): onClickCallback | undefined {\n return this.gestures.onClick;\n }\n public set onClick(cb: onClickCallback | undefined) {\n this.gestures.onClick = cb;\n }\n\n public get onHover(): onHoverCallback | undefined {\n return this.gestures.onHover;\n }\n public set onHover(cb: onHoverCallback | undefined) {\n this.gestures.onHover = cb;\n }\n\n public get onMouseDown(): (() => void) | undefined {\n return this.gestures.onMouseDown;\n }\n public set onMouseDown(cb: (() => void) | undefined) {\n this.gestures.onMouseDown = cb;\n }\n\n public get onMouseUp(): (() => void) | undefined {\n return this.gestures.onMouseUp;\n }\n public set onMouseUp(cb: (() => void) | undefined) {\n this.gestures.onMouseUp = cb;\n }\n\n public get onMouseLeave(): (() => void) | undefined {\n return this.gestures.onMouseLeave;\n }\n public set onMouseLeave(cb: (() => void) | undefined) {\n this.gestures.onMouseLeave = cb;\n }\n\n public get onZoom(): onZoomCallback | undefined {\n return this.gestures.onZoom;\n }\n public set onZoom(cb: onZoomCallback | undefined) {\n this.gestures.onZoom = cb;\n }\n\n constructor(\n private canvasWrapper: HTMLDivElement,\n private canvas: HTMLCanvasElement,\n private camera: ICamera,\n private viewport: ViewportState,\n private config: Config,\n private coordinateTransformer: CoordinateTransformer,\n private onCameraChange: () => void\n ) {\n this.gestures = new GestureController(\n this.canvas,\n this.camera,\n this.viewport,\n this.config,\n this.coordinateTransformer,\n this.onCameraChange\n );\n\n this.binder = new EventBinder(this.canvas, {\n click: this.gestures.handleClick,\n mousedown: this.gestures.handleMouseDown,\n mousemove: this.gestures.handleMouseMove,\n mouseup: this.gestures.handleMouseUp,\n mouseleave: this.gestures.handleMouseLeave,\n wheel: this.gestures.handleWheel,\n touchstart: this.gestures.handleTouchStart,\n touchmove: this.gestures.handleTouchMove,\n touchend: this.gestures.handleTouchEnd,\n });\n }\n\n setupEvents() {\n if (this.attached) return;\n this.binder.attach();\n this.attached = true;\n if (this.config.get().eventHandlers.resize && this.camera instanceof Camera) {\n this.resizeWatcher = new ResizeWatcher(\n this.canvasWrapper,\n this.canvas,\n this.viewport,\n this.camera,\n this.config,\n this.onCameraChange\n );\n this.resizeWatcher.onResize = () => {\n if (this.onResize) {\n this.onResize();\n }\n };\n this.resizeWatcher.start();\n }\n }\n\n destroy() {\n if (!this.attached) return;\n this.binder.detach();\n this.resizeWatcher?.stop();\n this.resizeWatcher = undefined;\n this.attached = false;\n }\n}\n","import { DEFAULT_VALUES } from \"../constants\";\n\n/**\n * Simple image loader with in-memory caching to avoid duplicate network requests.\n */\nexport class ImageLoader {\n private cache = new Map<string, HTMLImageElement>();\n private inflight = new Map<string, Promise<HTMLImageElement>>();\n private listeners = new Set<() => void>();\n\n /**\n * Register a callback fired when a new image finishes loading.\n */\n onLoad(cb: () => void) {\n this.listeners.add(cb);\n return () => this.listeners.delete(cb);\n }\n\n private notifyLoaded() {\n for (const cb of this.listeners) {\n cb();\n }\n }\n\n /**\n * Load an image, reusing cache when possible.\n * @param src Image URL.\n * @param retry How many times to retry on error (default: 1).\n * @returns Promise resolving to the loaded image element.\n */\n async load(src: string, retry: number = DEFAULT_VALUES.IMAGE_LOAD_RETRY_COUNT): Promise<HTMLImageElement> {\n // Cached\n if (this.cache.has(src)) {\n return this.cache.get(src)!;\n }\n\n // Inflight\n if (this.inflight.has(src)) {\n return this.inflight.get(src)!;\n }\n\n const task = new Promise<HTMLImageElement>((resolve, reject) => {\n const img = new Image();\n img.crossOrigin = \"anonymous\";\n img.decoding = \"async\";\n img.loading = \"eager\";\n\n img.onload = async () => {\n try {\n // Wait for decode to finish if supported\n if (\"decode\" in img) {\n await (img as HTMLImageElement & { decode?: () => Promise<void> }).decode?.();\n }\n } catch {\n // ignore decode errors; draw will still attempt\n }\n\n this.cache.set(src, img);\n this.inflight.delete(src);\n this.notifyLoaded();\n resolve(img);\n };\n\n img.onerror = (err) => {\n this.inflight.delete(src);\n if (retry > 0) {\n console.warn(`Retrying image: ${src}`);\n resolve(this.load(src, retry - 1));\n } else {\n console.error(`Image failed to load: ${src}`, err);\n const reason =\n err instanceof Error ? err.message : typeof err === \"string\" ? err : JSON.stringify(err);\n reject(new Error(`Image failed to load: ${src}. Reason: ${reason}`));\n }\n };\n\n img.src = src;\n });\n\n this.inflight.set(src, task);\n return task;\n }\n\n /**\n * Get a cached image without loading.\n * @param src Image URL key.\n */\n get(src: string): HTMLImageElement | undefined {\n return this.cache.get(src);\n }\n\n /**\n * Check if an image is already cached.\n * @param src Image URL key.\n */\n has(src: string): boolean {\n return this.cache.has(src);\n }\n\n /**\n * Clear all cached and inflight images/listeners to free memory.\n */\n clear() {\n this.cache.clear();\n this.inflight.clear();\n this.listeners.clear();\n }\n}\n","import { Coords, CanvasTileEngineConfig } from \"../types\";\nimport type { ICamera } from \"./Camera\";\nimport type { CoordinateTransformer } from \"./CoordinateTransformer\";\n\n/** @internal */\nexport type DrawContext = {\n ctx: CanvasRenderingContext2D;\n camera: ICamera;\n transformer: CoordinateTransformer;\n config: Required<CanvasTileEngineConfig>;\n topLeft: Coords;\n};\n\n/** @internal */\nexport type DrawCallback = (dc: DrawContext) => void;\n\nexport interface LayerHandle {\n layer: number;\n id: symbol;\n}\n\n/**\n * Manages ordered draw callbacks for canvas rendering.\n * @internal\n */\nexport class Layer {\n private layers = new Map<number, { id: symbol; fn: DrawCallback }[]>();\n\n /**\n * Register a draw callback at a specific layer index.\n * @param layer Layer order; lower numbers draw first.\n * @param fn Callback receiving drawing context.\n */\n add(layer: number, fn: DrawCallback): LayerHandle {\n const id = Symbol(\"layer-callback\");\n const entry = { id, fn };\n if (!this.layers.has(layer)) this.layers.set(layer, []);\n this.layers.get(layer)!.push(entry);\n return { layer, id };\n }\n\n /**\n * Remove a previously registered callback.\n * Safe to call multiple times; no-op if not found.\n */\n remove(handle: LayerHandle) {\n const list = this.layers.get(handle.layer);\n if (!list) return;\n this.layers.set(\n handle.layer,\n list.filter((entry) => entry.id !== handle.id)\n );\n }\n\n /**\n * Clear callbacks for a layer or all layers.\n * @param layer Layer to clear; clears all when omitted.\n */\n clear(layer?: number) {\n if (layer === undefined) {\n this.layers.clear();\n return;\n }\n this.layers.set(layer, []);\n }\n\n /**\n * Draw all registered callbacks in layer order.\n * @param dc Drawing context shared with callbacks.\n */\n drawAll(dc: DrawContext) {\n const keys = [...this.layers.keys()].sort((a, b) => a - b);\n for (const layer of keys) {\n const fns = this.layers.get(layer);\n if (!fns) continue;\n for (const { fn } of fns) {\n dc.ctx.save();\n fn(dc);\n dc.ctx.restore();\n }\n }\n }\n}\n","/**\n * Holds mutable viewport size for runtime changes (resize, layout).\n * Also tracks device pixel ratio for HiDPI/Retina display support.\n * @internal\n */\nexport class ViewportState {\n private width: number;\n private height: number;\n private _dpr: number;\n\n constructor(width: number, height: number) {\n this.width = width;\n this.height = height;\n this._dpr = typeof window !== \"undefined\" ? window.devicePixelRatio || 1 : 1;\n }\n\n getSize() {\n return { width: this.width, height: this.height };\n }\n\n setSize(width: number, height: number) {\n this.width = width;\n this.height = height;\n }\n\n /**\n * Get the current device pixel ratio.\n * Used for HiDPI/Retina display rendering.\n */\n get dpr(): number {\n return this._dpr;\n }\n\n /**\n * Update DPR (useful when window moves between displays).\n */\n updateDpr() {\n this._dpr = typeof window !== \"undefined\" ? window.devicePixelRatio || 1 : 1;\n }\n}\n","import { Config } from \"./Config\";\nimport { ICamera } from \"./Camera\";\nimport { ViewportState } from \"./ViewportState\";\nimport { COORDINATE_OVERLAY } from \"../constants\";\n\n/**\n * Renders a coordinate overlay (axes and labels) on top of the canvas.\n * @internal\n */\nexport class CoordinateOverlayRenderer {\n private ctx: CanvasRenderingContext2D;\n private camera: ICamera;\n private config: Config;\n private viewport: ViewportState;\n\n /**\n * @param ctx Canvas context to draw on.\n * @param camera Active camera for position/scale.\n * @param config Normalized grid engine configuration store.\n * @param viewport Mutable viewport size store.\n */\n constructor(ctx: CanvasRenderingContext2D, camera: ICamera, config: Config, viewport: ViewportState) {\n this.ctx = ctx;\n this.camera = camera;\n this.config = config;\n this.viewport = viewport;\n }\n\n /**\n * Draw overlay borders and coordinate labels based on current camera view.\n */\n draw() {\n // Save the current canvas state\n this.ctx.save();\n\n // Set fill style to black with configured opacity\n this.ctx.fillStyle = `rgba(0, 0, 0, ${COORDINATE_OVERLAY.BORDER_OPACITY})`;\n\n // Draw left border - 20px wide, full height\n const { width, height } = this.viewport.getSize();\n this.ctx.fillRect(0, 0, COORDINATE_OVERLAY.BORDER_WIDTH, height);\n\n // Draw bottom border - full width, 20px high\n this.ctx.fillRect(\n COORDINATE_OVERLAY.BORDER_WIDTH,\n height - COORDINATE_OVERLAY.BORDER_WIDTH,\n width,\n COORDINATE_OVERLAY.BORDER_WIDTH\n );\n\n // Set text properties for coordinates\n this.ctx.fillStyle = `rgba(255, 255, 255, ${COORDINATE_OVERLAY.TEXT_OPACITY})`;\n\n // Adjust font size based on scale (min 8px, max 12px)\n const fontSize = Math.min(\n COORDINATE_OVERLAY.MAX_FONT_SIZE,\n Math.max(COORDINATE_OVERLAY.MIN_FONT_SIZE, this.camera.scale * COORDINATE_OVERLAY.FONT_SIZE_SCALE_FACTOR)\n );\n this.ctx.font = `${fontSize}px Arial`;\n this.ctx.textAlign = \"center\";\n this.ctx.textBaseline = \"middle\";\n\n const cordGap = this.camera.scale;\n const visibleAreaWidthInCords = width / cordGap;\n const visibleAreaHeightInCords = height / cordGap;\n\n // Draw Y coordinates (left side)\n for (let i = 0 - (this.camera.y % 1); i <= visibleAreaHeightInCords + 1; i++) {\n this.ctx.fillText(Math.round(this.camera.y + i).toString(), 10, cordGap * i + cordGap / 2);\n }\n\n // Draw X coordinates (bottom)\n for (let i = 0 - (this.camera.x % 1); i <= visibleAreaWidthInCords + 1; i++) {\n this.ctx.fillText(Math.round(this.camera.x + i).toString(), cordGap * i + cordGap / 2, height - 10);\n }\n\n // Restore the canvas state\n this.ctx.restore();\n }\n\n /**\n * Decide whether overlay should be drawn at current scale and config.\n * @param scale Current camera scale.\n * @param coordsConfig Coordinate overlay config.\n * @returns True if overlay is enabled and scale is within range.\n */\n shouldDraw(scale: number): boolean {\n const coordsConfig = this.config.get().coordinates;\n\n if (!coordsConfig.enabled) {\n return false;\n }\n\n if (!coordsConfig.shownScaleRange) {\n return false;\n }\n\n const { min, max } = coordsConfig.shownScaleRange;\n\n return scale >= min && scale <= max;\n }\n}\n","import { ICamera } from \"./Camera\";\nimport { Config } from \"./Config\";\nimport { CoordinateTransformer } from \"./CoordinateTransformer\";\nimport { ViewportState } from \"./ViewportState\";\nimport { DEBUG_HUD } from \"../constants\";\n\nconst FPS_SAMPLE_SIZE = 10;\n\n/**\n * Canvas-only debug overlay: draws grid and HUD information.\n * @internal\n */\nexport class CanvasDebug {\n private ctx: CanvasRenderingContext2D;\n private camera: ICamera;\n private transformer: CoordinateTransformer;\n private config: Config;\n private viewport: ViewportState;\n\n // FPS tracking (runs continuously via rAF)\n private frameTimes: number[] = [];\n private lastFrameTime = 0;\n private currentFps = 0;\n private fpsLoopRunning = false;\n private onFpsUpdate: (() => void) | null = null;\n\n constructor(\n ctx: CanvasRenderingContext2D,\n camera: ICamera,\n transformer: CoordinateTransformer,\n config: Config,\n viewport: ViewportState\n ) {\n this.ctx = ctx;\n this.camera = camera;\n this.transformer = transformer;\n this.config = config;\n this.viewport = viewport;\n }\n\n /**\n * Set callback for FPS updates (triggers re-render)\n */\n setFpsUpdateCallback(callback: () => void) {\n this.onFpsUpdate = callback;\n }\n\n /**\n * Start FPS monitoring loop\n */\n startFpsLoop() {\n if (this.fpsLoopRunning) return;\n this.fpsLoopRunning = true;\n this.lastFrameTime = performance.now();\n this.fpsLoop();\n }\n\n /**\n * Stop FPS monitoring loop\n */\n stopFpsLoop() {\n this.fpsLoopRunning = false;\n }\n\n private fpsLoop() {\n if (!this.fpsLoopRunning) return;\n\n const now = performance.now();\n const delta = now - this.lastFrameTime;\n this.lastFrameTime = now;\n\n this.frameTimes.push(delta);\n if (this.frameTimes.length > FPS_SAMPLE_SIZE) {\n this.frameTimes.shift();\n }\n\n const avgDelta = this.frameTimes.reduce((a, b) => a + b, 0) / this.frameTimes.length;\n const newFps = Math.round(1000 / avgDelta);\n\n // Only trigger update if FPS changed\n if (newFps !== this.currentFps) {\n this.currentFps = newFps;\n this.onFpsUpdate?.();\n }\n\n requestAnimationFrame(() => this.fpsLoop());\n }\n\n draw() {\n this.drawHud();\n }\n\n /**\n * Stop FPS tracking and release callbacks.\n */\n destroy() {\n this.stopFpsLoop();\n this.onFpsUpdate = null;\n }\n\n private drawHud() {\n const config = this.config.get();\n\n if (!config.debug.hud) {\n return;\n }\n\n if (!config.debug.hud.enabled) {\n return;\n }\n\n const datas = [];\n\n const topLeft = { x: this.camera.x, y: this.camera.y };\n\n if (config.debug.hud.topLeftCoordinates) {\n datas.push(`TopLeft: ${topLeft.x.toFixed(2)}, ${topLeft.y.toFixed(2)}`);\n }\n\n if (config.debug.hud.coordinates) {\n const { width, height } = this.viewport.getSize();\n const center = this.camera.getCenter(width, height);\n datas.push(`Coords: ${center.x.toFixed(2)}, ${center.y.toFixed(2)}`);\n }\n\n if (config.debug.hud.scale) {\n datas.push(`Scale: ${this.camera.scale.toFixed(2)}`);\n }\n\n if (config.debug.hud.tilesInView) {\n const { width, height } = this.viewport.getSize();\n datas.push(\n `Tiles in view: ${Math.ceil(width / this.camera.scale)} x ${Math.ceil(height / this.camera.scale)}`\n );\n }\n\n if (config.debug.hud.fps) {\n datas.push(`FPS: ${this.currentFps}`);\n }\n\n const { width } = this.viewport.getSize();\n\n this.ctx.save();\n this.ctx.fillStyle = \"rgba(0,0,0,0.5)\";\n this.ctx.fillRect(\n width - DEBUG_HUD.PANEL_WIDTH - DEBUG_HUD.PADDING,\n DEBUG_HUD.PADDING / 2,\n DEBUG_HUD.PANEL_WIDTH,\n datas.length * DEBUG_HUD.LINE_HEIGHT + DEBUG_HUD.PADDING\n );\n\n this.ctx.fillStyle = \"#00ff99\";\n this.ctx.font = \"12px monospace\";\n\n for (let i = 0; i < datas.length; i++) {\n this.ctx.fillText(\n datas[i],\n width - DEBUG_HUD.PANEL_WIDTH - DEBUG_HUD.PADDING + 5,\n 18 + i * DEBUG_HUD.LINE_HEIGHT\n );\n }\n\n this.ctx.restore();\n }\n}\n","import { Coords, onDrawCallback } from \"../../types\";\nimport { ICamera } from \"../Camera\";\nimport { Config } from \"../Config\";\nimport { CoordinateOverlayRenderer } from \"../CoordinateOverlayRenderer\";\nimport { CoordinateTransformer } from \"../CoordinateTransformer\";\nimport { CanvasDebug } from \"../CanvasDebug\";\nimport { Layer } from \"../Layer\";\nimport { ViewportState } from \"../ViewportState\";\nimport { IRenderer } from \"./Renderer\";\n\n/**\n * Canvas-based renderer that draws engine layers, user callbacks, and coordinate overlays.\n * Supports HiDPI/Retina displays via devicePixelRatio scaling.\n * @internal\n */\nexport class CanvasRenderer implements IRenderer {\n private ctx: CanvasRenderingContext2D;\n private coordinateOverlayRenderer: CoordinateOverlayRenderer;\n private debugOverlay?: CanvasDebug;\n\n /** Optional user-provided draw hook executed after engine layers. */\n public onDraw?: onDrawCallback;\n\n /**\n * @param canvas Target canvas element.\n * @param camera Active camera.\n * @param coordinateTransformer World/screen transformer shared with layers.\n * @param config Normalized engine configuration store.\n * @param layers Layer manager whose callbacks are drawn in order.\n */\n constructor(\n private canvas: HTMLCanvasElement,\n private camera: ICamera,\n private coordinateTransformer: CoordinateTransformer,\n private config: Config,\n private viewport: ViewportState,\n private layers: Layer\n ) {\n const context = canvas.getContext(\"2d\");\n if (!context) {\n throw new Error(\"Failed to get 2D canvas context\");\n }\n\n this.ctx = context;\n this.applyCanvasSize();\n this.coordinateOverlayRenderer = new CoordinateOverlayRenderer(\n this.ctx,\n this.camera,\n this.config,\n this.viewport\n );\n if (this.config.get().debug?.enabled) {\n this.debugOverlay = new CanvasDebug(\n this.ctx,\n this.camera,\n this.coordinateTransformer,\n this.config,\n this.viewport\n );\n // Start FPS loop if fps hud is enabled\n if (this.config.get().debug?.hud?.fps) {\n this.debugOverlay.setFpsUpdateCallback(() => this.render());\n this.debugOverlay.startFpsLoop();\n }\n }\n }\n\n init(): void {\n this.applyCanvasSize();\n }\n\n private applyCanvasSize() {\n const size = this.viewport.getSize();\n const dpr = this.viewport.dpr;\n\n // Set actual canvas resolution (physical pixels)\n this.canvas.width = size.width * dpr;\n this.canvas.height = size.height * dpr;\n\n // Set display size via CSS (logical pixels)\n this.canvas.style.width = `${size.width}px`;\n this.canvas.style.height = `${size.height}px`;\n\n // Scale context to match DPR\n this.ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n }\n\n render(): void {\n const size = this.viewport.getSize();\n const dpr = this.viewport.dpr;\n const config = { ...this.config.get(), size: { ...size }, scale: this.camera.scale };\n const topLeft: Coords = { x: this.camera.x, y: this.camera.y };\n\n // Reset transform for HiDPI support (canvas.width/height changes reset transform)\n this.ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n\n // Clear background\n this.ctx.clearRect(0, 0, config.size.width, config.size.height);\n this.ctx.fillStyle = config.backgroundColor;\n this.ctx.fillRect(0, 0, config.size.width, config.size.height);\n\n // Draw engine layers\n this.layers.drawAll({\n ctx: this.ctx,\n camera: this.camera,\n transformer: this.coordinateTransformer,\n config,\n topLeft,\n });\n\n // User custom draw callback (optional)\n this.onDraw?.(this.ctx, {\n scale: this.camera.scale,\n width: config.size.width,\n height: config.size.height,\n coords: topLeft,\n });\n\n // Coordinate overlay\n if (this.coordinateOverlayRenderer.shouldDraw(this.camera.scale)) {\n this.coordinateOverlayRenderer.draw();\n }\n\n // Debug overlay\n if (config.debug?.enabled) {\n if (!this.debugOverlay) {\n this.debugOverlay = new CanvasDebug(\n this.ctx,\n this.camera,\n this.coordinateTransformer,\n this.config,\n this.viewport\n );\n // Start FPS loop if fps hud is enabled\n if (config.debug?.hud?.fps) {\n this.debugOverlay.setFpsUpdateCallback(() => this.render());\n this.debugOverlay.startFpsLoop();\n }\n }\n this.debugOverlay.draw();\n }\n }\n\n resize(width: number, height: number): void {\n const dpr = this.viewport.dpr;\n\n this.viewport.setSize(width, height);\n\n // Set actual canvas resolution (physical pixels)\n this.canvas.width = width * dpr;\n this.canvas.height = height * dpr;\n\n // Set display size via CSS (logical pixels)\n this.canvas.style.width = `${width}px`;\n this.canvas.style.height = `${height}px`;\n\n // Scale context to match DPR\n this.ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n }\n\n destroy(): void {\n if (this.debugOverlay) {\n this.debugOverlay.destroy();\n this.debugOverlay = undefined;\n }\n this.layers.clear();\n }\n\n /** Access the underlying 2D rendering context for advanced usage. */\n getContext(): CanvasRenderingContext2D {\n return this.ctx;\n }\n}\n","import { Coords } from \"../types\";\nimport { ICamera } from \"./Camera\";\nimport { Config } from \"./Config\";\nimport { IRenderer } from \"./Renderer/Renderer\";\nimport { ViewportState } from \"./ViewportState\";\nimport { AnimationController } from \"./AnimationController\";\n\nexport class SizeController {\n private canvasWrapper: HTMLDivElement;\n private canvas: HTMLCanvasElement;\n private camera: ICamera;\n private viewport: ViewportState;\n private renderer: IRenderer;\n private config: Config;\n private onSizeApplied: () => void;\n\n constructor(\n canvasWrapper: HTMLDivElement,\n canvas: HTMLCanvasElement,\n camera: ICamera,\n renderer: IRenderer,\n viewport: ViewportState,\n\n config: Config,\n onSizeApplied: () => void\n ) {\n this.canvasWrapper = canvasWrapper;\n this.canvas = canvas;\n this.camera = camera;\n this.renderer = renderer;\n this.viewport = viewport;\n this.config = config;\n this.onSizeApplied = onSizeApplied;\n }\n\n /**\n * Manually update canvas size using AnimationController for smooth transitions.\n * @param width New canvas width in pixels.\n * @param height New canvas height in pixels.\n * @param durationMs Animation duration in ms (default 500). Use 0 for instant resize.\n * @param animationController AnimationController instance to handle the animation.\n * @param onComplete Optional callback fired when resize animation completes.\n */\n resizeWithAnimation(\n width: number,\n height: number,\n durationMs: number,\n animationController: AnimationController,\n onComplete?: () => void\n ) {\n if (width <= 0 || height <= 0) {\n return;\n }\n\n const configSize = this.config.get().size;\n const clamp = (value: number, min?: number, max?: number) => {\n let result = value;\n if (min !== undefined) {\n result = Math.max(min, result);\n }\n if (max !== undefined) {\n result = Math.min(max, result);\n }\n return result;\n };\n\n // Clamp to min/max values\n width = clamp(width, configSize?.minWidth, configSize?.maxWidth);\n height = clamp(height, configSize?.minHeight, configSize?.maxHeight);\n\n // Delegate to AnimationController\n animationController.animateResize(width, height, durationMs, (w, h, center) => this.applySize(w, h, center), onComplete);\n }\n\n private applySize(nextW: number, nextH: number, center: Coords) {\n const roundedW = Math.round(nextW);\n const roundedH = Math.round(nextH);\n const dpr = this.viewport.dpr;\n\n this.viewport.setSize(roundedW, roundedH);\n\n // CSS size (logical pixels)\n this.canvasWrapper.style.width = `${roundedW}px`;\n this.canvasWrapper.style.height = `${roundedH}px`;\n\n // Canvas resolution (physical pixels for HiDPI)\n this.canvas.width = roundedW * dpr;\n this.canvas.height = roundedH * dpr;\n this.canvas.style.width = `${roundedW}px`;\n this.canvas.style.height = `${roundedH}px`;\n\n this.camera.setCenter(center, roundedW, roundedH);\n this.renderer.resize(roundedW, roundedH);\n this.onSizeApplied();\n }\n}\n","import { Coords } from \"../types\";\nimport { ICamera } from \"./Camera\";\nimport { ViewportState } from \"./ViewportState\";\nimport { DEFAULT_VALUES } from \"../constants\";\n\n/**\n * Manages smooth animations for camera movements and canvas resizing.\n * Handles animation frame scheduling and cleanup.\n * @internal\n */\nexport class AnimationController {\n private moveAnimationId?: number;\n private resizeAnimationId?: number;\n\n constructor(private camera: ICamera, private viewport: ViewportState, private onAnimationFrame: () => void) {}\n\n /**\n * Smoothly animate camera movement to target coordinates.\n * @param targetX Target world x coordinate.\n * @param targetY Target world y coordinate.\n * @param durationMs Animation duration in milliseconds (default: 500ms). Set to 0 for instant move.\n * @param onComplete Optional callback fired when animation completes.\n */\n animateMoveTo(\n targetX: number,\n targetY: number,\n durationMs: number = DEFAULT_VALUES.ANIMATION_DURATION_MS,\n onComplete?: () => void\n ) {\n // Cancel any existing move animation\n this.cancelMove();\n\n // Instant move if duration is 0 or negative\n if (durationMs <= 0) {\n const size = this.viewport.getSize();\n this.camera.setCenter({ x: targetX, y: targetY }, size.width, size.height);\n this.onAnimationFrame();\n onComplete?.();\n return;\n }\n\n const size = this.viewport.getSize();\n const start = this.camera.getCenter(size.width, size.height);\n const startTime = performance.now();\n\n const step = (currentTime: number) => {\n const elapsed = currentTime - startTime;\n const progress = Math.min(1, elapsed / durationMs);\n\n // Easing function (ease-in-out)\n const eased = progress < 0.5 ? 2 * progress * progress : 1 - Math.pow(-2 * progress + 2, 2) / 2;\n\n const currentX = start.x + (targetX - start.x) * eased;\n const currentY = start.y + (targetY - start.y) * eased;\n\n const size = this.viewport.getSize();\n this.camera.setCenter({ x: currentX, y: currentY }, size.width, size.height);\n this.onAnimationFrame();\n\n if (progress < 1) {\n this.moveAnimationId = requestAnimationFrame(step);\n } else {\n this.moveAnimationId = undefined;\n onComplete?.();\n }\n };\n\n this.moveAnimationId = requestAnimationFrame(step);\n }\n\n /**\n * Smoothly animate canvas size change while keeping view centered.\n * @param targetWidth New canvas width in pixels.\n * @param targetHeight New canvas height in pixels.\n * @param durationMs Animation duration in milliseconds (default: 500ms). Set to 0 for instant resize.\n * @param onApplySize Callback to apply the new size (updates wrapper, canvas, renderer).\n * @param onComplete Optional callback fired when animation completes.\n */\n animateResize(\n targetWidth: number,\n targetHeight: number,\n durationMs: number = DEFAULT_VALUES.ANIMATION_DURATION_MS,\n onApplySize: (width: number, height: number, center: Coords) => void,\n onComplete?: () => void\n ) {\n if (targetWidth <= 0 || targetHeight <= 0) {\n return;\n }\n\n // Cancel any existing resize animation\n this.cancelResize();\n\n const prev = this.viewport.getSize();\n const center = this.camera.getCenter(prev.width, prev.height);\n\n // Instant resize if duration is 0 or negative\n if (durationMs <= 0) {\n onApplySize(targetWidth, targetHeight, center);\n onComplete?.();\n return;\n }\n\n const startW = prev.width;\n const startH = prev.height;\n const deltaW = targetWidth - prev.width;\n const deltaH = targetHeight - prev.height;\n const startTime = performance.now();\n\n const step = (currentTime: number) => {\n const elapsed = currentTime - startTime;\n const progress = Math.min(1, elapsed / durationMs);\n\n const nextW = startW + deltaW * progress;\n const nextH = startH + deltaH * progress;\n\n onApplySize(nextW, nextH, center);\n\n if (progress < 1) {\n this.resizeAnimationId = requestAnimationFrame(step);\n } else {\n this.resizeAnimationId = undefined;\n onComplete?.();\n }\n };\n\n this.resizeAnimationId = requestAnimationFrame(step);\n }\n\n /**\n * Cancel the current move animation if running.\n */\n cancelMove() {\n if (this.moveAnimationId !== undefined) {\n cancelAnimationFrame(this.moveAnimationId);\n this.moveAnimationId = undefined;\n }\n }\n\n /**\n * Cancel the current resize animation if running.\n */\n cancelResize() {\n if (this.resizeAnimationId !== undefined) {\n cancelAnimationFrame(this.resizeAnimationId);\n this.resizeAnimationId = undefined;\n }\n }\n\n /**\n * Cancel all running animations.\n */\n cancelAll() {\n this.cancelMove();\n this.cancelResize();\n }\n\n /**\n * Check if any animation is currently running.\n */\n isAnimating(): boolean {\n return this.moveAnimationId !== undefined || this.resizeAnimationId !== undefined;\n }\n}\n","import { CanvasTileEngineConfig } from \"../types\";\nimport { ICamera } from \"./Camera\";\nimport { Config } from \"./Config\";\nimport { CoordinateTransformer } from \"./CoordinateTransformer\";\nimport { Layer } from \"./Layer\";\nimport { ViewportState } from \"./ViewportState\";\nimport { CanvasRenderer } from \"./Renderer/CanvasRenderer\";\nimport { IRenderer } from \"./Renderer/Renderer\";\n\n/**\n * Factory for creating renderer instances based on configuration.\n * Implements the Factory Pattern to decouple renderer creation from engine initialization.\n * @internal\n */\nexport class RendererFactory {\n /**\n * Create a renderer instance based on the specified type.\n * @param type Renderer type (currently only \"canvas\" is supported).\n * @param canvas Target canvas element.\n * @param camera Active camera.\n * @param coordinateTransformer World/screen coordinate transformer.\n * @param config Normalized engine configuration.\n * @param viewport Viewport state manager.\n * @param layers Layer manager for rendering.\n * @returns Configured renderer instance.\n * @throws Error if renderer type is not supported.\n */\n static createRenderer(\n type: CanvasTileEngineConfig[\"renderer\"],\n canvas: HTMLCanvasElement,\n camera: ICamera,\n coordinateTransformer: CoordinateTransformer,\n config: Config,\n viewport: ViewportState,\n layers: Layer\n ): IRenderer {\n switch (type) {\n case \"canvas\":\n return new CanvasRenderer(canvas, camera, coordinateTransformer, config, viewport, layers);\n default:\n // Type guard ensures this should never happen\n throw new Error(`Unsupported renderer type: ${type}`);\n }\n }\n\n /**\n * Validate if a renderer type is supported.\n * @param type Renderer type to validate.\n * @returns True if the renderer type is supported.\n */\n static isSupported(type: string): type is NonNullable<CanvasTileEngineConfig[\"renderer\"]> {\n return type === \"canvas\";\n }\n\n /**\n * Get list of supported renderer types.\n * @returns Array of supported renderer type names.\n */\n static getSupportedTypes(): ReadonlyArray<NonNullable<CanvasTileEngineConfig[\"renderer\"]>> {\n return [\"canvas\"] as const;\n }\n}\n","import { Camera } from \"./modules/Camera\";\nimport { Config } from \"./modules/Config\";\nimport { CoordinateTransformer } from \"./modules/CoordinateTransformer\";\nimport { CanvasDraw } from \"./modules/CanvasDraw\";\nimport { EventManager } from \"./modules/EventManager\";\nimport { ImageLoader } from \"./modules/ImageLoader\";\nimport { Layer, type LayerHandle } from \"./modules/Layer\";\nimport { ViewportState } from \"./modules/ViewportState\";\nimport { CanvasRenderer } from \"./modules/Renderer/CanvasRenderer\";\nimport { IRenderer } from \"./modules/Renderer/Renderer\";\nimport {\n Coords,\n DrawObject,\n CanvasTileEngineConfig,\n onClickCallback,\n onDrawCallback,\n onHoverCallback,\n EventHandlers,\n} from \"./types\";\nimport { SizeController } from \"./modules/SizeController\";\nimport { AnimationController } from \"./modules/AnimationController\";\nimport { RendererFactory } from \"./modules/RendererFactory\";\n\n/**\n * Core engine wiring camera, config, renderer, events, and draw helpers.\n */\nexport class CanvasTileEngine {\n private config: Config;\n private camera: Camera;\n private viewport: ViewportState;\n private coordinateTransformer: CoordinateTransformer;\n private layers?: Layer;\n private renderer: IRenderer;\n private events: EventManager;\n private draw?: CanvasDraw;\n public images: ImageLoader;\n private sizeController: SizeController;\n private animationController: AnimationController;\n\n public canvasWrapper: HTMLDivElement;\n public canvas: HTMLCanvasElement;\n\n /** Callback: center coordinates change */\n public onCoordsChange?: (coords: Coords) => void;\n\n private _onClick?: onClickCallback;\n\n public get onClick(): onClickCallback | undefined {\n return this._onClick;\n }\n public set onClick(cb: onClickCallback | undefined) {\n this._onClick = cb;\n this.events.onClick = cb;\n }\n\n private _onHover?: onHoverCallback;\n public get onHover(): onHoverCallback | undefined {\n return this._onHover;\n }\n public set onHover(cb: onHoverCallback | undefined) {\n this._onHover = cb;\n this.events.onHover = cb;\n }\n\n private _onMouseDown?: () => void;\n public get onMouseDown(): (() => void) | undefined {\n return this._onMouseDown;\n }\n public set onMouseDown(cb: (() => void) | undefined) {\n this._onMouseDown = cb;\n this.events.onMouseDown = cb;\n }\n\n private _onMouseUp?: () => void;\n public get onMouseUp(): (() => void) | undefined {\n return this._onMouseUp;\n }\n public set onMouseUp(cb: (() => void) | undefined) {\n this._onMouseUp = cb;\n this.events.onMouseUp = cb;\n }\n\n private _onMouseLeave?: () => void;\n public get onMouseLeave(): (() => void) | undefined {\n return this._onMouseLeave;\n }\n public set onMouseLeave(cb: (() => void) | undefined) {\n this._onMouseLeave = cb;\n this.events.onMouseLeave = cb;\n }\n\n private _onDraw?: onDrawCallback;\n public get onDraw(): onDrawCallback | undefined {\n return this._onDraw;\n }\n public set onDraw(cb: onDrawCallback | undefined) {\n this._onDraw = cb;\n this.getCanvasRenderer().onDraw = cb;\n }\n\n private _onResize?: () => void;\n public get onResize(): (() => void) | undefined {\n return this._onResize;\n }\n public set onResize(cb: (() => void) | undefined) {\n this._onResize = cb;\n this.events.onResize = cb;\n }\n\n private _onZoom?: (scale: number) => void;\n /** Callback: zoom level changes (wheel or pinch) */\n public get onZoom(): ((scale: number) => void) | undefined {\n return this._onZoom;\n }\n public set onZoom(cb: ((scale: number) => void) | undefined) {\n this._onZoom = cb;\n this.events.onZoom = cb;\n }\n\n /**\n * @param canvas Target canvas element.\n * @param config Initial engine configuration.\n * @param center Initial center in world space.\n */\n constructor(canvasWrapper: HTMLDivElement, config: CanvasTileEngineConfig, center: Coords = { x: 0, y: 0 }) {\n this.canvasWrapper = canvasWrapper;\n this.canvas = canvasWrapper.querySelector(\"canvas\")!;\n this.canvasWrapper.style.position = \"relative\";\n this.canvasWrapper.style.width = config.size.width + \"px\";\n this.canvasWrapper.style.height = config.size.height + \"px\";\n this.canvas.style.position = \"absolute\";\n\n this.config = new Config(config);\n\n const rendererType = config.renderer ?? \"canvas\";\n const initialTopLeft: Coords = {\n x: center.x - config.size.width / (2 * config.scale),\n y: center.y - config.size.height / (2 * config.scale),\n };\n\n this.viewport = new ViewportState(config.size.width, config.size.height);\n this.camera = new Camera(\n initialTopLeft,\n this.config.get().scale,\n this.config.get().minScale,\n this.config.get().maxScale,\n this.viewport\n );\n\n this.coordinateTransformer = new CoordinateTransformer(this.camera);\n\n // Initialize animation controller\n this.animationController = new AnimationController(this.camera, this.viewport, () => this.handleCameraChange());\n\n this.renderer = this.createRenderer(rendererType);\n\n this.images = new ImageLoader();\n\n this.events = new EventManager(\n this.canvasWrapper,\n this.canvas,\n this.camera,\n this.viewport,\n this.config,\n this.coordinateTransformer,\n () => this.handleCameraChange()\n );\n this.sizeController = new SizeController(\n this.canvasWrapper,\n this.canvas,\n this.camera,\n this.renderer,\n this.viewport,\n this.config,\n () => this.handleCameraChange()\n );\n this.events.setupEvents();\n\n // Apply initial bounds if provided\n if (config.bounds) {\n this.camera.setBounds(config.bounds);\n }\n }\n\n // ─── PUBLIC API ──────────────────────────────\n\n /** Tear down listeners and observers. */\n destroy() {\n this.events.destroy();\n this.animationController.cancelAll();\n this.draw?.destroy();\n this.layers?.clear();\n this.images.clear();\n this.renderer.destroy();\n }\n\n /** Render a frame using the active renderer. */\n render() {\n this.renderer.render();\n }\n\n /**\n * Manually update canvas size (e.g., user-driven select). Keeps view centered.\n * @param width New canvas width in pixels.\n * @param height New canvas height in pixels.\n * @param durationMs Animation duration in ms (default 500). Use 0 for instant resize.\n * @param onComplete Optional callback fired when resize animation completes.\n */\n resize(width: number, height: number, durationMs: number = 500, onComplete?: () => void) {\n this.sizeController.resizeWithAnimation(width, height, durationMs, this.animationController, () => {\n // Trigger onResize callback after programmatic resize completes\n this._onResize?.();\n onComplete?.();\n });\n }\n\n /**\n * Current canvas size.\n * @returns Current `{ width, height }` in pixels.\n */\n getSize() {\n return this.viewport.getSize();\n }\n\n /**\n * Current canvas scale.\n * @returns Current canvas scale.\n */\n getScale() {\n return this.camera.scale;\n }\n\n /**\n * Zoom in by a given factor, centered on the viewport.\n * @param factor Zoom multiplier (default: 1.5). Higher values zoom in more.\n */\n zoomIn(factor: number = 1.5) {\n const size = this.viewport.getSize();\n this.camera.zoomByFactor(factor, size.width / 2, size.height / 2);\n this.handleCameraChange();\n }\n\n /**\n * Zoom out by a given factor, centered on the viewport.\n * @param factor Zoom multiplier (default: 1.5). Higher values zoom out more.\n */\n zoomOut(factor: number = 1.5) {\n const size = this.viewport.getSize();\n this.camera.zoomByFactor(1 / factor, size.width / 2, size.height / 2);\n this.handleCameraChange();\n }\n\n /** Snapshot of current normalized config. */\n getConfig(): Required<CanvasTileEngineConfig> {\n const base = this.config.get();\n const size = this.viewport.getSize();\n return {\n ...base,\n scale: this.camera.scale,\n size: { ...size },\n };\n }\n\n /** Center coordinates of the map. */\n getCenterCoords(): Coords {\n const size = this.viewport.getSize();\n return this.camera.getCenter(size.width, size.height);\n }\n\n /** Set center coordinates from outside (adjusts the camera accordingly). */\n updateCoords(newCenter: Coords) {\n const size = this.viewport.getSize();\n this.camera.setCenter(newCenter, size.width, size.height);\n this.handleCameraChange();\n }\n\n /**\n * Smoothly move the camera center to target coordinates over the given duration.\n * @param x Target world x.\n * @param y Target world y.\n * @param durationMs Animation duration in milliseconds (default: 500ms). Set to 0 for instant move.\n * @param onComplete Optional callback fired when animation completes.\n */\n goCoords(x: number, y: number, durationMs: number = 500, onComplete?: () => void) {\n this.animationController.animateMoveTo(x, y, durationMs, onComplete);\n }\n\n /**\n * Update event handlers at runtime.\n * This allows you to enable or disable specific interactions dynamically.\n * @param handlers Partial event handlers to update.\n * @example\n * ```ts\n * // Disable drag temporarily\n * engine.setEventHandlers({ drag: false });\n *\n * // Enable painting mode\n * engine.setEventHandlers({ drag: false, hover: true });\n *\n * // Re-enable drag\n * engine.setEventHandlers({ drag: true });\n * ```\n */\n setEventHandlers(handlers: Partial<EventHandlers>) {\n this.config.updateEventHandlers(handlers);\n }\n\n /**\n * Set or update map boundaries to restrict camera movement.\n * @param bounds Boundary limits. Use Infinity/-Infinity to remove limits.\n * @example\n * ```ts\n * // Restrict map to -100 to 100 on both axes\n * engine.setBounds({ minX: -100, maxX: 100, minY: -100, maxY: 100 });\n *\n * // Remove boundaries\n * engine.setBounds({ minX: -Infinity, maxX: Infinity, minY: -Infinity, maxY: Infinity });\n *\n * // Only limit X axis\n * engine.setBounds({ minX: 0, maxX: 500, minY: -Infinity, maxY: Infinity });\n * ```\n */\n setBounds(bounds: { minX: number; maxX: number; minY: number; maxY: number }) {\n this.config.updateBounds(bounds);\n this.camera.setBounds(bounds);\n this.render();\n }\n\n // ─── Draw helpers (canvas renderer only) ───────────\n\n /**\n * Register a generic draw callback (canvas renderer only).\n * @param fn Callback invoked with context, top-left coords, and config.\n * @param layer Layer order (lower draws first).\n */\n addDrawFunction(\n fn: (ctx: CanvasRenderingContext2D, coords: Coords, config: Required<CanvasTileEngineConfig>) => void,\n layer: number = 1\n ): LayerHandle {\n return this.ensureCanvasDraw().addDrawFunction(fn, layer);\n }\n\n /**\n * Draw one or many rectangles in world space (canvas renderer only).\n * Supports rotation via the `rotate` property (degrees, positive = clockwise).\n * @param items Rectangle definitions.\n * @param layer Layer order (lower draws first).\n */\n drawRect(items: DrawObject | Array<DrawObject>, layer: number = 1): LayerHandle {\n return this.ensureCanvasDraw().drawRect(items, layer);\n }\n\n /**\n * Draw rectangles with pre-rendering cache (canvas renderer only).\n * Renders all items once to an offscreen canvas, then blits the visible portion each frame.\n * Ideal for large static datasets like mini-maps where items don't change.\n * Supports rotation via the `rotate` property (degrees, positive = clockwise).\n * @param items Array of rectangle definitions.\n * @param cacheKey Unique key for this cache (e.g., \"minimap-items\").\n * @param layer Layer order (lower draws first).\n */\n drawStaticRect(items: Array<DrawObject>, cacheKey: string, layer: number = 1): LayerHandle {\n return this.ensureCanvasDraw().drawStaticRect(items, cacheKey, layer);\n }\n\n /**\n * Draw circles with pre-rendering cache (canvas renderer only).\n * Renders all items once to an offscreen canvas, then blits the visible portion each frame.\n * Ideal for large static datasets like mini-maps where items don't change.\n * @param items Array of circle definitions.\n * @param cacheKey Unique key for this cache (e.g., \"minimap-circles\").\n * @param layer Layer order (lower draws first).\n */\n drawStaticCircle(items: Array<DrawObject>, cacheKey: string, layer: number = 1): LayerHandle {\n return this.ensureCanvasDraw().drawStaticCircle(items, cacheKey, layer);\n }\n\n /**\n * Draw images with pre-rendering cache (canvas renderer only).\n * Renders all items once to an offscreen canvas, then blits the visible portion each frame.\n * Ideal for large static datasets like terrain tiles or static decorations.\n * Supports rotation via the `rotate` property (degrees, positive = clockwise).\n * @param items Array of image definitions with HTMLImageElement.\n * @param cacheKey Unique key for this cache (e.g., \"terrain-cache\").\n * @param layer Layer order (lower draws first).\n */\n drawStaticImage(\n items: Array<Omit<DrawObject, \"style\"> & { img: HTMLImageElement }>,\n cacheKey: string,\n layer: number = 1\n ): LayerHandle {\n return this.ensureCanvasDraw().drawStaticImage(items, cacheKey, layer);\n }\n\n /**\n * Clear a static rendering cache.\n * @param cacheKey The cache key to clear, or undefined to clear all caches.\n */\n clearStaticCache(cacheKey?: string) {\n this.ensureCanvasDraw().clearStaticCache(cacheKey);\n }\n\n /**\n * Draw one or many lines between world points (canvas renderer only).\n * @param items Line segments.\n * @param style Line style overrides.\n * @param layer Layer order.\n */\n drawLine(\n items: Array<{ from: Coords; to: Coords }> | { from: Coords; to: Coords },\n style?: { strokeStyle?: string; lineWidth?: number },\n layer: number = 1\n ): LayerHandle {\n return this.ensureCanvasDraw().drawLine(items, style, layer);\n }\n\n /**\n * Draw one or many circles sized in world units (canvas renderer only).\n * @param items Circle definitions.\n * @param layer Layer order.\n */\n drawCircle(items: DrawObject | Array<DrawObject>, layer: number = 1): LayerHandle {\n return this.ensureCanvasDraw().drawCircle(items, layer);\n }\n\n /**\n * Draw one or many texts at world positions (canvas renderer only).\n * @param items Text definitions.\n * @param style Text style overrides.\n * @param layer Layer order.\n */\n drawText(\n items: Array<{ coords: Coords; text: string }> | { coords: Coords; text: string },\n style?: { fillStyle?: string; font?: string; textAlign?: CanvasTextAlign; textBaseline?: CanvasTextBaseline },\n layer: number = 2\n ): LayerHandle {\n return this.ensureCanvasDraw().drawText(items, style, layer);\n }\n\n /**\n * Draw one or many polylines through world points (canvas renderer only).\n * @param items Polyline point collections.\n * @param style Stroke style overrides.\n * @param layer Layer order.\n */\n drawPath(\n items: Array<Coords[]> | Coords[],\n style?: { strokeStyle?: string; lineWidth?: number },\n layer: number = 1\n ): LayerHandle {\n return this.ensureCanvasDraw().drawPath(items, style, layer);\n }\n\n /**\n * Draw one or many images scaled in world units (canvas renderer only).\n * Supports rotation via the `rotate` property (degrees, positive = clockwise).\n * @param items Image definitions.\n * @param layer Layer order.\n */\n drawImage(\n items:\n | Array<Omit<DrawObject, \"style\"> & { img: HTMLImageElement }>\n | (Omit<DrawObject, \"style\"> & { img: HTMLImageElement }),\n layer: number = 1\n ): LayerHandle {\n return this.ensureCanvasDraw().drawImage(items, layer);\n }\n\n /**\n * Draw grid lines at specified cell size (canvas renderer only).\n * @param cellSize Size of each grid cell in world units.\n * @example\n * ```ts\n * engine.drawGridLines(50);\n * ```\n */\n drawGridLines(\n cellSize: number,\n lineWidth: number = 1,\n strokeStyle: string = \"black\",\n layer: number = 0\n ): LayerHandle {\n return this.ensureCanvasDraw().drawGridLines(cellSize, { lineWidth, strokeStyle }, layer);\n }\n\n /**\n * Remove a specific draw callback by handle (canvas renderer only).\n * Does not clear other callbacks on the same layer.\n */\n removeLayerHandle(handle: LayerHandle) {\n if (!this.layers) {\n throw new Error(\"removeLayerHandle is only available when renderer is set to 'canvas'.\");\n }\n this.layers.remove(handle);\n }\n\n /**\n * Clear all draw callbacks from a specific layer (canvas renderer only).\n * Use this before redrawing dynamic content to prevent accumulation.\n * @param layer Layer index to clear.\n * @example\n * ```ts\n * engine.clearLayer(1);\n * engine.drawRect(newRects, 1);\n * engine.render();\n * ```\n */\n clearLayer(layer: number) {\n if (!this.layers) {\n throw new Error(\"clearLayer is only available when renderer is set to 'canvas'.\");\n }\n this.layers.clear(layer);\n }\n\n /**\n * Clear all draw callbacks from all layers (canvas renderer only).\n * Useful for complete scene reset.\n * @example\n * ```ts\n * engine.clearAll();\n * // Redraw everything from scratch\n * ```\n */\n clearAll() {\n if (!this.layers) {\n throw new Error(\"clearAll is only available when renderer is set to 'canvas'.\");\n }\n this.layers.clear();\n }\n\n /**\n * Build the active renderer based on config.\n * @param type Renderer type requested.\n */\n private createRenderer(type: CanvasTileEngineConfig[\"renderer\"]): IRenderer {\n // Initialize layers and draw helpers for canvas renderer\n if (type === \"canvas\") {\n this.layers = new Layer();\n this.draw = new CanvasDraw(this.layers, this.coordinateTransformer, this.camera);\n }\n\n return RendererFactory.createRenderer(\n type ?? \"canvas\",\n this.canvas,\n this.camera,\n this.coordinateTransformer,\n this.config,\n this.viewport,\n this.layers!\n );\n }\n\n private ensureCanvasDraw(): CanvasDraw {\n if (!this.draw) {\n throw new Error(\"Draw helpers are only available when renderer is set to 'canvas'.\");\n }\n return this.draw;\n }\n\n private getCanvasRenderer(): CanvasRenderer {\n if (!(this.renderer instanceof CanvasRenderer)) {\n throw new Error(\"Canvas renderer required for this operation.\");\n }\n return this.renderer;\n }\n\n // ─── Internal ───────────────────────────────\n\n private handleCameraChange() {\n if (this.onCoordsChange) {\n this.onCoordsChange(this.getCenterCoords());\n }\n this.render();\n }\n}\n"],"mappings":"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","names":["DEFAULT_VALUES","SCALE_LIMITS","SIZE_LIMITS","RENDER_DEFAULTS","COORDINATE_OVERLAY","DEBUG_HUD","VISIBILITY_BUFFER","computePan","topLeft","scale","dx","dy","computeZoom","oldScale","deltaY","minScale","maxScale","mouse","limitedDelta","DEFAULT_VALUES","scaleFactor","newScale","worldToScreen","world","cam","screenToWorld","screen","Camera","initialTopLeft","scale","minScale","maxScale","viewport","DEFAULT_VALUES","bounds","viewportWidth","viewportHeight","viewWidthWorld","viewHeightWorld","value","viewSize","min","max","boundsSize","deltaScreenX","deltaScreenY","next","computePan","mouseX","mouseY","deltaY","canvasRect","mx","my","computeZoom","factor","centerX","centerY","newScale","canvasWidth","canvasHeight","center","deltaWidthPx","deltaHeightPx","Config","config","base","RENDER_DEFAULTS","SCALE_LIMITS","SIZE_LIMITS","cfg","handlers","bounds","CoordinateTransformer","camera","worldX","worldY","worldToScreen","screenX","screenY","screenToWorld","RBush","SpatialIndex","_SpatialIndex","items","rbushItems","item","half","minX","minY","maxX","maxY","r","index","SPATIAL_INDEX_THRESHOLD","MAX_STATIC_CANVAS_DIMENSION","CanvasDraw","layers","transformer","camera","x","y","sizeWorld","topLeft","config","viewW","viewH","minX","VISIBILITY_BUFFER","minY","maxX","maxY","fn","layer","ctx","items","list","spatialIndex","SpatialIndex","bounds","visibleItems","lastFillStyle","lastStrokeStyle","lastLineWidth","item","size","origin","style","pos","pxSize","drawX","drawY","rotationDeg","rotation","radius","centerX","centerY","halfExtent","a","b","points","xs","p","ys","first","i","aspect","drawW","drawH","baseX","baseY","offsetX","offsetY","cellSize","startX","DEFAULT_VALUES","endX","startY","endY","p1","p2","cell","cacheKey","renderFn","worldWidth","worldHeight","renderScale","canvasWidth","canvasHeight","cache","offscreen","offCtx","cachedCanvas","cachedBounds","cachedScale","srcX","srcY","srcW","srcH","img","imgX","imgY","EventBinder","canvas","handlers","GestureController","canvas","camera","viewport","config","transformer","onCameraChange","rect","mouseX","mouseY","world","screen","dx","dy","eventHandlers","t","currentDistance","currentCenter","scaleFactor","centerX","centerY","touches","ResizeWatcher","wrapper","canvas","viewport","camera","config","onCameraChange","size","configSize","maxWidth","maxHeight","minWidth","minHeight","entries","entry","rawW","rawH","width","height","prev","diffW","diffH","dpr","value","min","max","result","prevDpr","nextDpr","EventManager","canvasWrapper","canvas","camera","viewport","config","coordinateTransformer","onCameraChange","GestureController","EventBinder","cb","Camera","ResizeWatcher","ImageLoader","cb","src","retry","DEFAULT_VALUES","task","resolve","reject","img","err","reason","Layer","layer","fn","id","entry","handle","list","dc","keys","a","b","fns","ViewportState","width","height","CoordinateOverlayRenderer","ctx","camera","config","viewport","COORDINATE_OVERLAY","width","height","fontSize","cordGap","visibleAreaWidthInCords","visibleAreaHeightInCords","i","scale","coordsConfig","min","max","FPS_SAMPLE_SIZE","CanvasDebug","ctx","camera","transformer","config","viewport","callback","now","delta","avgDelta","a","b","newFps","datas","topLeft","width","height","center","DEBUG_HUD","i","CanvasRenderer","canvas","camera","coordinateTransformer","config","viewport","layers","context","CoordinateOverlayRenderer","CanvasDebug","size","dpr","topLeft","width","height","SizeController","canvasWrapper","canvas","camera","renderer","viewport","config","onSizeApplied","width","height","durationMs","animationController","onComplete","configSize","clamp","value","min","max","result","w","h","center","nextW","nextH","roundedW","roundedH","dpr","AnimationController","camera","viewport","onAnimationFrame","targetX","targetY","durationMs","DEFAULT_VALUES","onComplete","size","start","startTime","step","currentTime","elapsed","progress","eased","currentX","currentY","targetWidth","targetHeight","onApplySize","prev","center","startW","startH","deltaW","deltaH","nextW","nextH","RendererFactory","type","canvas","camera","coordinateTransformer","config","viewport","layers","CanvasRenderer","CanvasTileEngine","cb","canvasWrapper","config","center","Config","rendererType","initialTopLeft","ViewportState","Camera","CoordinateTransformer","AnimationController","ImageLoader","EventManager","SizeController","width","height","durationMs","onComplete","factor","size","base","newCenter","x","y","handlers","bounds","fn","layer","items","cacheKey","style","cellSize","lineWidth","strokeStyle","handle","type","Layer","CanvasDraw","RendererFactory","CanvasRenderer"]}