@overtone-art/canvas-editor-core 0.6.2 → 0.6.4

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.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/editor.ts","../src/events.ts","../src/layer.ts","../src/utils/id.ts","../src/template-explode.ts","../src/history.ts","../src/snapping.ts","../src/crop.ts","../src/utils/clamp.ts","../src/pattern/pattern-manager.ts","../src/pattern/tiled-pattern-object.ts","../src/pattern/tile-geometry.ts","../src/text-curve.ts","../src/text-curve-geometry.ts","../src/mask-presets/manager.ts","../src/mask-presets/shapes.ts","../src/mask-presets/textures.ts","../src/shadow.ts","../src/utils/color.ts","../src/selection-style.ts","../src/transform.ts","../src/utils/units.ts","../src/serialization.ts","../src/export.ts","../src/displacement.ts","../src/utils/svg.ts","../src/fonts.ts","../src/licensing.ts","../src/project.ts","../src/mask.ts","../src/masks/manager.ts","../src/masks/compose.ts","../src/masks/edit.ts","../src/masks/space.ts","../src/masks/store.ts","../src/masks/host.ts","../src/masks/install.ts","../src/types.ts","../src/presets.ts","../src/annotations.ts"],"sourcesContent":["export { CanvasEditor } from './editor';\nexport { Layer, LayerManager } from './layer';\nexport { HistoryManager } from './history';\nexport { SnapManager } from './snapping';\nexport { CropController } from './crop';\nexport {\n PatternManager,\n TiledPatternObject,\n drawTiles,\n computeTilePositions,\n restoreLocks,\n} from './pattern';\nexport type {\n CanvasRenderingProtocol,\n PatternOrigin,\n TileDrawSize,\n TilePlacement,\n} from './pattern';\nexport {\n TextCurveManager,\n DEFAULT_TEXT_CURVE,\n buildCurvePathData,\n buildCurveLinePaths,\n normalizeTextCurve,\n} from './text-curve';\nexport type { CurvePath } from './text-curve';\nexport { explodeTemplateSvg, textPathSpec, textPathCurve } from './template-explode';\nexport type { TemplateLayerSpec } from './template-explode';\nexport {\n MaskPresetManager,\n isMaskPresetId,\n isShapeMaskId,\n isTextureMaskId,\n shapeMaskPathData,\n renderTextureMask,\n clearTextureMaskCache,\n SHAPE_MASK_IDS,\n SHAPE_MASK_BOX,\n TEXTURE_MASK_IDS,\n TEXTURE_MASK_SIZE,\n} from './mask-presets';\nexport {\n LayerMaskManager,\n CANVAS_MASK_TARGET,\n composeMaskGroup,\n needsAbsoluteSpace,\n fitToBox,\n toCanvasSpace,\n toHostSpace,\n unwrapGroup,\n} from './masks';\nexport type { AddMaskOptions } from './masks';\nexport { applyLayerShadow, readLayerShadow, DEFAULT_LAYER_SHADOW } from './shadow';\nexport {\n applyObjectSelectionStyle,\n applySelectionStyle,\n DEFAULT_SELECTION_STYLE,\n} from './selection-style';\nexport type { SelectionStyle } from './selection-style';\nexport { applyAspectLock, resetTransform } from './transform';\nexport { EventEmitter } from './events';\nexport { UnitConverter } from './utils/units';\nexport { generateId } from './utils/id';\nexport { clamp, round2 } from './utils/clamp';\nexport { escapeXml, sanitizeSvg } from './utils/svg';\nexport { isCssColor } from './utils/color';\nexport { serializeEditor, deserializeEditor } from './serialization';\nexport {\n exportPNG,\n exportSVG,\n exportDataURL,\n exportMockup,\n exportPrintArea,\n computeCoverPlacement,\n computePrintAreaClip,\n} from './export';\nexport { DEFAULT_PATTERN_CONFIG } from './types';\nexport { CANVAS_SIZE_PRESETS } from './presets';\nexport { FontRegistry } from './fonts';\nexport { LicenseManager } from './licensing';\nexport { ProjectManager } from './project';\nexport { MaskController, MaskRefinementError } from './mask';\nexport type { MaskRefinementErrorCode, MaskPerformanceSample } from './mask';\nexport { AnnotationOverlay } from './annotations';\nexport type { AnnotationPrimitive, ViewportTransform } from './annotations';\nexport { displaceRgba } from './displacement';\n\nexport type {\n LayerType,\n LayerData,\n LayerMeta,\n SerializedLayer,\n EditorState,\n EditorConfig,\n FileAdapter,\n ImageProvider,\n ImageProviderResult,\n ImageAttribution,\n ImageSearchOptions,\n ImageSearchResult,\n ExportFormat,\n ShapePlugin,\n TemplateDefinition,\n TemplateParameter,\n PrintifyPositioning,\n TileMode,\n PatternConfig,\n PatternState,\n PatternLocks,\n MockupConfig,\n MockupPrintArea,\n MockupBlendMode,\n MockupOverlay,\n MockupDisplacement,\n MockupDisplacementChannel,\n EditorEvents,\n Unit,\n ResizeOptions,\n DpiIssue,\n ImageAdjustments,\n CanvasSizePreset,\n BackgroundImageOptions,\n SerializedBackgroundImageOptions,\n SemanticExportOptions,\n MaskPoint,\n MaskBrushOptions,\n MaskRefinementPrompt,\n MaskRefinementRequest,\n MaskRefinementResult,\n MaskRefinementProvider,\n MaskPresetId,\n ShapeMaskPresetId,\n TextureMaskPresetId,\n LayerMaskEntry,\n LayerMaskMode,\n TextCurveConfig,\n TextCurveInput,\n TextCurveShape,\n LayerShadowConfig,\n FontDefinition,\n SvgExportOptions,\n LicenseConfig,\n LicensePayload,\n LicenseStatus,\n NormalizedLayerPosition,\n PositioningAdapter,\n ProjectPage,\n ProjectState,\n} from './types';\n\nexport type { PngExportOptions, CoverPlacement } from './export';\n","import { Canvas, FabricImage, Group, Textbox, filters } from 'fabric';\nimport type { FabricObject, ImageFormat } from 'fabric';\nimport type {\n EditorConfig,\n DpiIssue,\n BackgroundImageOptions,\n SemanticExportOptions,\n SerializedBackgroundImageOptions,\n SvgExportOptions,\n EditorEvents,\n EditorState,\n FileAdapter,\n ImageProvider,\n ImageProviderResult,\n ImageSearchOptions,\n ImageSearchResult,\n ImageAdjustments,\n LayerShadowConfig,\n MaskPresetId,\n MockupConfig,\n PatternConfig,\n PrintifyPositioning,\n TextCurveConfig,\n ResizeOptions,\n NormalizedLayerPosition,\n PositioningAdapter,\n ShapePlugin,\n TemplateDefinition,\n} from './types';\nimport { EventEmitter } from './events';\nimport { Layer, LayerManager } from './layer';\nimport { explodeTemplateSvg, textPathSpec } from './template-explode';\nimport { HistoryManager } from './history';\nimport { SnapManager } from './snapping';\nimport { CropController } from './crop';\nimport { PatternManager } from './pattern';\nimport { TextCurveManager } from './text-curve';\nimport { MaskPresetManager } from './mask-presets';\nimport { applyLayerShadow, readLayerShadow } from './shadow';\nimport {\n DEFAULT_SELECTION_STYLE,\n applyObjectSelectionStyle,\n applySelectionStyle,\n} from './selection-style';\nimport type { SelectionStyle } from './selection-style';\nimport { applyAspectLock, resetTransform } from './transform';\nimport { UnitConverter } from './utils/units';\nimport { serializeEditor, deserializeEditor } from './serialization';\nimport {\n exportPNG,\n exportSVG,\n exportDataURL,\n exportMockup,\n exportIsolatedPNG,\n exportPrintArea,\n} from './export';\nimport type { PngExportOptions } from './export';\nimport { clamp, round2 } from './utils/clamp';\nimport { escapeXml, sanitizeSvg } from './utils/svg';\nimport { isCssColor } from './utils/color';\nimport { FontRegistry } from './fonts';\nimport { LicenseManager } from './licensing';\nimport { ProjectManager } from './project';\nimport { MaskController } from './mask';\nimport { LayerMaskManager } from './masks';\n\nconst MIN_ZOOM = 0.1;\nconst MAX_ZOOM = 8;\n\nfunction isTaintedCanvasError(error: unknown): boolean {\n return (\n (error instanceof DOMException && error.name === 'SecurityError') ||\n (error instanceof Error && /taint|cross-origin|insecure/i.test(error.message))\n );\n}\n\nexport class CanvasEditor {\n readonly canvas: Canvas;\n readonly layers: LayerManager;\n readonly history: HistoryManager;\n readonly events: EventEmitter<EditorEvents>;\n readonly units: UnitConverter;\n readonly snapping: SnapManager;\n readonly crop: CropController;\n readonly patterns: PatternManager;\n readonly curves: TextCurveManager;\n readonly maskPresets: MaskPresetManager;\n /** Stacked boolean masks, per layer and for the design as a whole. */\n readonly layerMasks: LayerMaskManager;\n readonly fonts: FontRegistry;\n readonly licensing: LicenseManager;\n readonly pages: ProjectManager;\n readonly masks: MaskController;\n\n private fileAdapter?: FileAdapter;\n private imageProvider?: ImageProvider;\n private zoomLevel = 1;\n private selectionStyle: SelectionStyle = { ...DEFAULT_SELECTION_STYLE };\n private mockup: MockupConfig | null = null;\n // The design's configured background. The live canvas background is forced\n // transparent while a mockup preview is shown, so this is the source of truth\n // for serialization and export — not the (possibly transient) canvas value.\n private designBackground: string;\n private designBackgroundImage: FabricObject | null = null;\n private backgroundImageOptions: SerializedBackgroundImageOptions | null = null;\n\n constructor(canvasElement: HTMLCanvasElement, config: EditorConfig) {\n this.events = new EventEmitter<EditorEvents>();\n this.fonts = new FontRegistry();\n config.fonts?.forEach((font) => this.fonts.register(font));\n this.licensing = new LicenseManager(config.license);\n this.units = new UnitConverter(config.unit ?? 'px', config.dpi ?? 72);\n\n const widthPx = this.units.toPixels(config.width);\n const heightPx = this.units.toPixels(config.height);\n this.designBackground = config.backgroundColor ?? '#ffffff';\n\n this.canvas = new Canvas(canvasElement, {\n width: widthPx,\n height: heightPx,\n backgroundColor: this.designBackground,\n preserveObjectStacking: config.preserveObjectStacking ?? true,\n selection: true,\n });\n\n this.layers = new LayerManager(this.canvas, this.events);\n this.fileAdapter = config.fileAdapter;\n this.imageProvider = config.imageProvider;\n\n this.history = new HistoryManager({\n getState: () => JSON.stringify(this.toJSON()),\n restoreState: async (state: string) => {\n const parsed = JSON.parse(state) as EditorState;\n await this.fromJSON(parsed);\n },\n events: this.events,\n });\n this.layers.setHistoryCallback(() => this.history.save());\n\n this.snapping = new SnapManager(this.canvas, this.events);\n this.crop = new CropController(this.canvas, this.history, this.events);\n this.patterns = new PatternManager(this.canvas, this.layers, this.history, this.events);\n this.curves = new TextCurveManager(this.canvas, this.layers, this.history, this.events);\n this.maskPresets = new MaskPresetManager(this.canvas, this.layers, this.history, this.events);\n this.layerMasks = new LayerMaskManager(this.canvas, this.layers, this.history, this.events);\n\n this.setupCanvasEvents();\n this.refreshSelectionStyle();\n this.history.saveImmediate();\n this.pages = new ProjectManager(this);\n this.masks = new MaskController(this);\n }\n\n // ─── Layer Operations ────────────────────────────────\n\n async addImage(url: string, options?: Partial<Record<string, unknown>>): Promise<Layer> {\n // Don't force crossOrigin here: a remote image whose host sends no CORS\n // header would then fail to load at all. The pattern engine requests its own\n // crossOrigin copy when it needs an untainted canvas (see pattern.ts).\n // Fabric v7 defaults originX/originY to 'center'; pin top-left so images\n // land at their left/top like the rest of the editor's coordinate model.\n try {\n const img = await FabricImage.fromURL(\n url,\n {},\n { originX: 'left', originY: 'top', ...options },\n );\n const layer = this.layers.add('image', img);\n // Select what was just created: the panel highlights it, and the property\n // sections open on it, without a second click on the canvas.\n this.layers.select(layer.id);\n this.history.save();\n return layer;\n } catch (error) {\n this.events.emit('error', { message: 'Failed to add image', error });\n throw error;\n }\n }\n\n /** Replace an image source without changing its layer identity or visual transform. */\n async replaceImageSource(layerId: string, url: string): Promise<Layer> {\n const layer = this.layers.get(layerId);\n if (!layer || (layer.type !== 'image' && layer.type !== 'mask')) {\n throw new Error(`Image or mask layer not found: ${layerId}`);\n }\n if (layer.meta.pattern) {\n throw new Error('Clear the pattern before replacing the image source');\n }\n if (this.crop.activeLayerId() === layerId) this.crop.cancel();\n const previous = layer.fabricObject as FabricImage;\n try {\n const replacement = await FabricImage.fromURL(url, {}, { originX: 'left', originY: 'top' });\n replacement.set({\n left: previous.left,\n top: previous.top,\n originX: previous.originX,\n originY: previous.originY,\n width: previous.width,\n height: previous.height,\n cropX: previous.cropX,\n cropY: previous.cropY,\n scaleX: previous.scaleX,\n scaleY: previous.scaleY,\n angle: previous.angle,\n skewX: previous.skewX,\n skewY: previous.skewY,\n flipX: previous.flipX,\n flipY: previous.flipY,\n });\n replacement.filters = [...previous.filters];\n replacement.applyFilters();\n replacement.setCoords();\n this.layers.replaceObject(layerId, replacement);\n return layer;\n } catch (error) {\n this.events.emit('error', { message: 'Failed to replace image source', error });\n throw error;\n }\n }\n\n addText(text: string, options?: Partial<Record<string, unknown>>): Layer {\n const textbox = new Textbox(text, {\n fontSize: 32,\n fontFamily: 'Arial',\n fill: '#000000',\n width: 200,\n // v7 defaults origin to center; keep top-left placement.\n originX: 'left',\n originY: 'top',\n ...options,\n });\n const layer = this.layers.add('text', textbox as unknown as FabricObject);\n this.layers.select(layer.id);\n this.history.save();\n return layer;\n }\n\n addShape(plugin: ShapePlugin, options?: Record<string, unknown>): Layer {\n const obj = plugin.create(options);\n const layer = this.layers.add('shape', obj, plugin.name);\n this.layers.select(layer.id);\n this.history.save();\n return layer;\n }\n\n async addTemplate(\n template: TemplateDefinition,\n params: Record<string, string | number>,\n ): Promise<Layer> {\n const values: Record<string, string | number> = {};\n for (const parameter of template.parameters) {\n const value = params[parameter.key] ?? parameter.default;\n if (value === undefined) throw new Error(`Missing template parameter: ${parameter.key}`);\n if (parameter.type === 'number' && !Number.isFinite(Number(value))) {\n throw new Error(`Invalid number for template parameter: ${parameter.key}`);\n }\n if (parameter.type === 'color' && !isCssColor(value)) {\n throw new Error(`Invalid color for template parameter: ${parameter.key}`);\n }\n values[parameter.key] = value;\n }\n const resolved = sanitizeSvg(\n template.svg.replace(/\\{\\{(\\w+)(?:[|:]([^}]*))?\\}\\}/g, (token, key: string, fallback) => {\n const value = values[key] ?? fallback;\n return value === undefined ? token : escapeXml(value);\n }),\n );\n // A template is a starting point: it lands as the layers it is drawn from,\n // grouped, so its copy can be retyped instead of being a frozen picture.\n // `<textPath>` is unparseable by fabric, so those are rebuilt from their\n // parameters as one curved text layer.\n const specs = resolved.includes('<textPath')\n ? [textPathSpec(template, values)]\n : await explodeTemplateSvg(template, resolved, values);\n if (specs.length === 0) throw new Error('Template SVG contains no renderable objects');\n\n // One checkpoint for the whole insert: undo takes the template back out in\n // a single step, not layer by layer.\n return this.history.transaction(async () => {\n const created = specs.map((spec) => {\n const layer = this.layers.add(spec.type, spec.object, spec.name);\n // `false`: the transaction owns the history entry.\n if (spec.curve) this.curves.apply(layer.id, spec.curve, false);\n return layer;\n });\n\n // A one-layer template needs no group; two or more move as a unit.\n const layer =\n created.length === 1\n ? created[0]\n : ((await this.groupLayers(\n created.map((l) => l.id),\n template.name,\n )) ?? created[0]);\n\n layer.fabricObject.set({\n left: this.canvas.getWidth() / 2,\n top: this.canvas.getHeight() / 2,\n originX: 'center',\n originY: 'center',\n });\n layer.fabricObject.setCoords();\n this.layers.select(layer.id);\n this.canvas.requestRenderAll();\n this.history.save();\n return layer;\n });\n }\n\n removeLayer(id: string): void {\n if (this.crop.activeLayerId() === id) this.crop.cancel();\n if (this.masks.activeLayerId() === id) {\n this.masks.detach(id);\n }\n if (this.layers.remove(id)) this.history.save();\n }\n\n selectLayer(id: string | null): void {\n this.layers.select(id);\n }\n\n /** Select several layers at once — what a panel's shift/⌘ click drives. */\n selectLayers(ids: string[]): void {\n this.layers.selectMany(ids);\n }\n\n getSelectedLayer(): Layer | null {\n const active = this.canvas.getActiveObject();\n if (!active) return null;\n return this.layers.findByObject(active) ?? null;\n }\n\n /** Mirror a layer along the given axis. */\n flipLayer(id: string, axis: 'horizontal' | 'vertical'): void {\n const layer = this.layers.get(id);\n if (!layer) return;\n const obj = layer.fabricObject;\n if (axis === 'horizontal') {\n obj.set('flipX', !obj.flipX);\n } else {\n obj.set('flipY', !obj.flipY);\n }\n obj.setCoords();\n this.canvas.requestRenderAll();\n this.history.save();\n }\n\n /** Clone a layer (offset slightly) and select the copy. */\n async duplicateLayer(id: string): Promise<Layer | null> {\n const layer = this.layers.get(id);\n if (!layer) return null;\n\n const clone = await layer.fabricObject.clone();\n clone.set({ left: (clone.left ?? 0) + 15, top: (clone.top ?? 0) + 15 });\n clone.setCoords();\n\n const copy = this.layers.add(layer.type, clone, `${layer.name} copy`);\n // Carry non-fabric metadata (e.g. pattern config) onto the copy.\n copy.meta = structuredClone(layer.meta);\n copy.visible = layer.visible;\n copy.locked = layer.locked;\n copy.opacity = layer.opacity;\n clone.set({\n visible: layer.visible,\n selectable: !layer.locked,\n evented: !layer.locked,\n opacity: layer.opacity,\n });\n // The copy carries the pattern config, so it needs its own tiling proxy —\n // the meta alone would leave a duplicated pattern rendering nothing.\n this.patterns.attachTo(copy);\n\n // Through the layer manager, not the canvas: fabric only emits selection\n // events for user interaction, so a panel would not follow a bare\n // `setActiveObject` and the copy would look unselected.\n this.layers.select(copy.id);\n this.canvas.requestRenderAll();\n this.history.save();\n return copy;\n }\n\n applyImageAdjustments(layerId: string, adjustments: ImageAdjustments): boolean {\n const layer = this.layers.get(layerId);\n if (!layer || layer.type !== 'image') return false;\n const image = layer.fabricObject as FabricImage;\n const previous = (layer.meta.imageAdjustments ?? {}) as ImageAdjustments;\n const next = { ...previous, ...adjustments };\n const clampAdjustment = (value: number | undefined, min = -1) => clamp(value ?? 0, min, 1);\n image.filters = [\n new filters.Brightness({ brightness: clampAdjustment(next.brightness) }),\n new filters.Contrast({ contrast: clampAdjustment(next.contrast) }),\n new filters.Saturation({ saturation: clampAdjustment(next.saturation) }),\n new filters.Blur({ blur: clampAdjustment(next.blur, 0) }),\n ];\n layer.meta.imageAdjustments = next;\n image.applyFilters();\n this.canvas.requestRenderAll();\n this.history.save();\n return true;\n }\n\n /**\n * Combine two or more layers into one group layer. Picking a group among them\n * **absorbs** it — its children join the new group and the old group record is\n * dropped — because groups are exactly one level deep.\n */\n async groupLayers(ids: string[], name = 'Group'): Promise<Layer | null> {\n const uniqueIds = [...new Set(ids)];\n const picked = uniqueIds\n .map((id) => this.layers.get(id))\n .filter((layer): layer is Layer => layer !== undefined && layer.parentId === null);\n if (picked.length < 2 || picked.length !== uniqueIds.length) return null;\n\n // Where the group belongs in the stack: exactly where its topmost member\n // sat. Appending instead would lift grouped background art above artwork it\n // was deliberately behind.\n const stack = this.layers.getAll();\n const topIndex = Math.max(...picked.map((layer) => stack.indexOf(layer)));\n const insertIndex = stack.slice(0, topIndex).filter((layer) => !picked.includes(layer)).length;\n\n return this.history.transaction(() => {\n const children: Layer[] = [];\n const objects: FabricObject[] = [];\n for (const layer of picked) {\n if (layer.type === 'group' && layer.children.length > 0) {\n // `removeAll` hands back objects with their absolute transform already\n // restored, so they can be re-grouped as they are.\n const inner = (layer.fabricObject as Group).removeAll();\n for (const [index, object] of inner.entries()) {\n object.setCoords();\n const child = layer.children[index];\n if (!child) continue;\n children.push(child);\n objects.push(object);\n }\n layer.children = [];\n this.layers.detach(layer.id);\n } else {\n children.push(layer);\n objects.push(layer.fabricObject);\n this.layers.detach(layer.id);\n }\n }\n\n const group = new Group(objects);\n const grouped = this.layers.add('group', group, name);\n this.layers.adoptChildren(grouped, children);\n this.layers.reorder(grouped.id, insertIndex);\n this.layers.select(grouped.id);\n this.history.save();\n return grouped;\n });\n }\n\n /** Split a group back into the layers it holds, in place. */\n async ungroupLayer(id: string): Promise<Layer[]> {\n const grouped = this.layers.get(id);\n if (!grouped || grouped.type !== 'group' || grouped.children.length === 0) return [];\n\n return this.history.transaction(() => {\n const restored = this.layers.explode(grouped);\n this.history.save();\n this.layers.select(restored[0]?.id ?? null);\n return restored;\n });\n }\n\n // ─── Serialization ──────────────────────────────────\n\n toJSON(): EditorState {\n return serializeEditor(this);\n }\n\n async fromJSON(state: EditorState): Promise<void> {\n const managedByHistory = this.history.isRestoring();\n if (!managedByHistory) {\n this.history.saveImmediate();\n this.history.pause();\n }\n try {\n await deserializeEditor(this, state);\n // Tiling is drawn by a render proxy, which is never serialized: rebuild\n // one per pattern layer. This also migrates states written by the old\n // engine, which baked the tiled bitmap into the layer itself.\n await this.patterns.rehydrateAll();\n // Mask stacks restore as plain clip groups; this re-pins the design overlay\n // and adopts any clip written before stacks existed.\n this.layerMasks.refreshAll();\n } catch (error) {\n if (!managedByHistory) {\n this.events.emit('error', { message: 'Failed to load editor state', error });\n }\n throw error;\n } finally {\n if (!managedByHistory) this.history.resume();\n }\n if (!managedByHistory) {\n this.history.clear();\n this.history.saveImmediate();\n }\n }\n\n // ─── Export ──────────────────────────────────────────\n\n async toPNG(options?: PngExportOptions): Promise<Blob> {\n return this.toRaster((options?.format ?? 'png') as 'png' | 'jpeg' | 'webp', options);\n }\n\n async toJPEG(options?: Omit<PngExportOptions, 'format'>): Promise<Blob> {\n return this.toRaster('jpeg', options);\n }\n\n async toWebP(options?: Omit<PngExportOptions, 'format'>): Promise<Blob> {\n return this.toRaster('webp', options);\n }\n\n /** Export one layer in document coordinates or at its native image resolution. */\n async exportLayer(id: string, options: SemanticExportOptions = {}): Promise<Blob> {\n const layer = this.layers.get(id);\n if (!layer) throw new Error(`Layer not found: ${id}`);\n try {\n if (options.resolution === 'source' && layer.fabricObject instanceof FabricImage) {\n const image = await layer.fabricObject.clone();\n image.set({\n left: 0,\n top: 0,\n originX: 'left',\n originY: 'top',\n scaleX: 1,\n scaleY: 1,\n angle: 0,\n flipX: false,\n flipY: false,\n });\n return await exportIsolatedPNG(this.canvas, [image], {\n ...options,\n width: image.width || 1,\n height: image.height || 1,\n cloneObjects: false,\n });\n }\n // A tiled layer draws through its proxy; its own object is invisible.\n return await exportIsolatedPNG(\n this.canvas,\n [layer.renderProxy ?? layer.fabricObject],\n options,\n );\n } catch (error) {\n this.events.emit('error', { message: `Failed to export layer: ${id}`, error });\n throw error;\n }\n }\n\n /** Export only the configured document background, excluding design layers. */\n async exportBackground(options: SemanticExportOptions = {}): Promise<Blob> {\n try {\n return await exportIsolatedPNG(this.canvas, [], {\n ...options,\n backgroundColor: this.designBackground,\n backgroundImage: this.designBackgroundImage,\n });\n } catch (error) {\n this.events.emit('error', { message: 'Failed to export background', error });\n throw error;\n }\n }\n\n private async toRaster(\n format: 'png' | 'jpeg' | 'webp',\n options?: PngExportOptions,\n ): Promise<Blob> {\n this.events.emit('export:start', { format });\n try {\n await this.fonts.ready();\n const blob = await this.withDesignBackground(() =>\n exportPNG(this.canvas, { ...options, format }),\n );\n this.events.emit('export:complete', { format });\n this.licensing.track(`export:${format}`);\n return blob;\n } catch (error) {\n this.events.emit('error', {\n message: isTaintedCanvasError(error)\n ? 'Canvas export was blocked by cross-origin image data; load remote images with CORS enabled'\n : `Failed to export ${format.toUpperCase()}`,\n error,\n });\n throw error;\n }\n }\n\n toSVG(): string {\n this.events.emit('export:start', { format: 'svg' });\n try {\n const svg = this.withDesignBackground(() => exportSVG(this.canvas));\n this.events.emit('export:complete', { format: 'svg' });\n this.licensing.track('export:svg');\n return svg;\n } catch (error) {\n this.events.emit('error', { message: 'Failed to export SVG', error });\n throw error;\n }\n }\n\n async toSVGAsync(options: SvgExportOptions = {}): Promise<string> {\n await this.fonts.ready();\n const svg = this.toSVG();\n if (options.embedFonts === false || this.fonts.getAll().length === 0) return svg;\n try {\n const css = await this.fonts.getEmbeddedCss();\n return svg.replace(/(<svg\\b[^>]*>)/i, `$1<defs><style>${css}</style></defs>`);\n } catch (error) {\n this.events.emit('error', { message: 'Failed to embed fonts in SVG', error });\n throw error;\n }\n }\n\n toDataURL(format: ImageFormat = 'png', multiplier = 1): string {\n return this.withDesignBackground(() => exportDataURL(this.canvas, format, multiplier));\n }\n\n /**\n * Export the print file: the design cropped to the mockup's print area, on\n * transparency. Without a print area this is the whole canvas, still\n * transparent — a print file never carries the design background.\n */\n async toPrintFile(options: PngExportOptions = {}): Promise<Blob> {\n await this.fonts.ready();\n try {\n const area = this.mockup?.printArea;\n const blob = area\n ? await exportPrintArea(this.canvas, area, options)\n : await exportIsolatedPNG(this.canvas, this.canvas.getObjects(), options);\n this.licensing.track(`export:print:${options.format ?? 'png'}`);\n return blob;\n } catch (error) {\n this.events.emit('error', { message: 'Failed to export print file', error });\n throw error;\n }\n }\n\n /** Export the current product-preview composite. Advanced warping is host-defined. */\n async toMockupImage(options: PngExportOptions = {}): Promise<Blob> {\n if (!this.mockup) throw new Error('No mockup is configured');\n await this.fonts.ready();\n try {\n const blob = await exportMockup(this.canvas, this.mockup, options);\n this.licensing.track(`export:mockup:${options.format ?? 'png'}`);\n return blob;\n } catch (error) {\n this.events.emit('error', { message: 'Failed to export mockup', error });\n throw error;\n }\n }\n\n /**\n * Run an export with the configured design background applied, even when a\n * mockup preview has forced the live canvas transparent — so exports reflect\n * the design, not the preview. Restores the preview state afterwards.\n */\n private withDesignBackground<T>(fn: () => T): T {\n if (!this.mockup) return fn();\n const previewBg = this.canvas.backgroundColor;\n const previewImage = this.canvas.backgroundImage;\n this.canvas.backgroundColor = this.designBackground;\n this.canvas.backgroundImage = this.designBackgroundImage ?? undefined;\n try {\n return fn();\n } finally {\n this.canvas.backgroundColor = previewBg;\n this.canvas.backgroundImage = previewImage;\n }\n }\n\n toPrintifyPositioning(): Record<string, PrintifyPositioning> {\n const result: Record<string, PrintifyPositioning> = {};\n const canvasW = this.canvas.getWidth();\n const canvasH = this.canvas.getHeight();\n\n const imageLayers = this.layers.getAll().filter((l) => l.type === 'image');\n\n if (imageLayers.length === 0) {\n result['front'] = { x: 0.5, y: 0.5, scale: 1, angle: 0 };\n return result;\n }\n\n for (const layer of imageLayers) {\n const obj = layer.fabricObject;\n const center = obj.getCenterPoint();\n const key = result[layer.name] ? `${layer.name}-${layer.id}` : layer.name;\n result[key] = {\n x: round2(center.x / canvasW),\n y: round2(center.y / canvasH),\n scale: round2(obj.scaleX ?? 1),\n angle: round2(obj.angle ?? 0),\n };\n }\n\n return result;\n }\n\n /** Provider-neutral, ID-stable placement data in 0..1 canvas coordinates. */\n toNormalizedPositioning(): NormalizedLayerPosition[] {\n const canvasWidth = this.canvas.getWidth();\n const canvasHeight = this.canvas.getHeight();\n return this.layers.getAll().map((layer) => {\n const object = layer.fabricObject;\n const center = object.getCenterPoint();\n const bounds = object.getBoundingRect();\n return {\n layerId: layer.id,\n name: layer.name,\n type: layer.type,\n centerX: round2(center.x / canvasWidth),\n centerY: round2(center.y / canvasHeight),\n width: round2(bounds.width / canvasWidth),\n height: round2(bounds.height / canvasHeight),\n scaleX: round2(object.scaleX ?? 1),\n scaleY: round2(object.scaleY ?? 1),\n angle: round2(object.angle ?? 0),\n };\n });\n }\n\n toProviderPositioning<T>(adapter: PositioningAdapter<T>): T {\n return adapter.map(this.toNormalizedPositioning(), {\n width: this.canvas.getWidth(),\n height: this.canvas.getHeight(),\n });\n }\n\n // ─── File Operations ────────────────────────────────\n\n async save(\n filename: string,\n format: 'png' | 'jpeg' | 'webp' | 'svg' | 'json',\n ): Promise<string | undefined> {\n if (!this.fileAdapter) return undefined;\n\n let data: Blob | string;\n if (format === 'png') {\n data = await this.toPNG();\n } else if (format === 'jpeg') {\n data = await this.toJPEG();\n } else if (format === 'webp') {\n data = await this.toWebP();\n } else if (format === 'svg') {\n data = await this.toSVGAsync();\n } else {\n data = JSON.stringify(this.toJSON(), null, 2);\n }\n\n try {\n return await this.fileAdapter.save(data, filename, format);\n } catch (error) {\n this.events.emit('error', { message: `Failed to save ${format}`, error });\n throw error;\n }\n }\n\n async uploadImage(file: File): Promise<ImageProviderResult | undefined> {\n if (!this.imageProvider?.upload) return undefined;\n try {\n return await this.imageProvider.upload(file);\n } catch (error) {\n this.events.emit('error', { message: 'Failed to upload image', error });\n throw error;\n }\n }\n\n async browseImages(): Promise<ImageProviderResult | null> {\n if (!this.imageProvider?.browse) return null;\n try {\n return await this.imageProvider.browse();\n } catch (error) {\n this.events.emit('error', { message: 'Failed to browse images', error });\n throw error;\n }\n }\n\n async searchImages(\n query: string,\n options?: ImageSearchOptions,\n ): Promise<ImageSearchResult | null> {\n if (!this.imageProvider?.search) return null;\n try {\n return await this.imageProvider.search(query, options);\n } catch (error) {\n this.events.emit('error', { message: 'Failed to search images', error });\n throw error;\n }\n }\n\n /** Track provider usage, then insert its hotlinked image as a normal layer. */\n async addProviderImage(\n image: ImageProviderResult,\n options?: Partial<Record<string, unknown>>,\n ): Promise<Layer> {\n try {\n await this.imageProvider?.trackUse?.(image);\n } catch (error) {\n this.events.emit('error', { message: 'Failed to record image use', error });\n throw error;\n }\n return this.addImage(image.url, options);\n }\n\n setFileAdapter(adapter: FileAdapter): void {\n this.fileAdapter = adapter;\n }\n\n setImageProvider(provider: ImageProvider): void {\n this.imageProvider = provider;\n }\n\n // ─── Canvas Operations ──────────────────────────────\n\n setBackground(color: string): void {\n this.designBackground = color;\n // Don't override the mockup's transparent preview; it will pick up the new\n // colour when the mockup is cleared.\n if (!this.mockup) {\n this.canvas.backgroundColor = color;\n this.canvas.requestRenderAll();\n }\n this.history.save();\n this.events.emit('canvas:modified', {});\n }\n\n getDesignBackground(): string {\n return this.designBackground;\n }\n\n getDesignBackgroundImage(): FabricObject | null {\n return this.designBackgroundImage;\n }\n\n getBackgroundImageOptions(): SerializedBackgroundImageOptions | null {\n return this.backgroundImageOptions ? { ...this.backgroundImageOptions } : null;\n }\n\n async setBackgroundImage(\n url: string | null,\n options: BackgroundImageOptions = {},\n ): Promise<void> {\n if (url === null) {\n this.setBackgroundImageObject(null);\n return;\n }\n try {\n const image = await FabricImage.fromURL(\n url,\n { crossOrigin: options.crossOrigin ?? null, signal: options.signal },\n { originX: 'left', originY: 'top' },\n );\n const width = image.width || 1;\n const height = image.height || 1;\n const canvasWidth = this.canvas.getWidth();\n const canvasHeight = this.canvas.getHeight();\n const fit = options.fit ?? 'cover';\n const sx = canvasWidth / width;\n const sy = canvasHeight / height;\n const scaleX =\n fit === 'stretch' ? sx : fit === 'contain' ? Math.min(sx, sy) : Math.max(sx, sy);\n const scaleY = fit === 'stretch' ? sy : scaleX;\n image.set({\n left: (canvasWidth - width * scaleX) / 2,\n top: (canvasHeight - height * scaleY) / 2,\n scaleX,\n scaleY,\n opacity: clamp(options.opacity ?? 1, 0, 1),\n selectable: false,\n evented: false,\n });\n const serializableOptions = { ...options };\n delete serializableOptions.signal;\n this.setBackgroundImageObject(image, true, serializableOptions);\n } catch (error) {\n this.events.emit('error', { message: 'Failed to set background image', error });\n throw error;\n }\n }\n\n /** Used by state restoration and advanced integrations with an existing Fabric object. */\n setBackgroundImageObject(\n image: FabricObject | null,\n save = true,\n options: SerializedBackgroundImageOptions | null = null,\n ): void {\n this.designBackgroundImage = image;\n this.backgroundImageOptions = image ? options : null;\n this.canvas.backgroundImage = this.mockup ? undefined : (image ?? undefined);\n this.canvas.requestRenderAll();\n if (save) this.history.save();\n this.events.emit('canvas:modified', {});\n }\n\n setTransparentBackground(): void {\n this.setBackground('');\n }\n\n resize(width: number, height: number, options: ResizeOptions = {}): void {\n const widthPx = this.units.toPixels(width);\n const heightPx = this.units.toPixels(height);\n const oldWidth = this.canvas.getWidth();\n const oldHeight = this.canvas.getHeight();\n const scaleContent = options.scaleContent ?? true;\n if (scaleContent && oldWidth > 0 && oldHeight > 0) {\n const sx = widthPx / oldWidth;\n const sy = heightPx / oldHeight;\n for (const layer of this.layers.getAll()) {\n const object = layer.fabricObject;\n object.set({\n left: (object.left ?? 0) * sx,\n top: (object.top ?? 0) * sy,\n scaleX: (object.scaleX ?? 1) * sx,\n scaleY: (object.scaleY ?? 1) * sy,\n });\n object.setCoords();\n }\n if (this.designBackgroundImage) {\n this.designBackgroundImage.set({\n left: (this.designBackgroundImage.left ?? 0) * sx,\n top: (this.designBackgroundImage.top ?? 0) * sy,\n scaleX: (this.designBackgroundImage.scaleX ?? 1) * sx,\n scaleY: (this.designBackgroundImage.scaleY ?? 1) * sy,\n });\n this.designBackgroundImage.setCoords();\n }\n }\n this.canvas.setDimensions({ width: widthPx, height: heightPx });\n this.patterns.syncArea();\n this.canvas.requestRenderAll();\n this.history.save();\n this.events.emit('canvas:modified', {});\n }\n\n /** Effective source resolution for an image at its current physical size. */\n getImageDpi(layerId: string): number | null {\n const layer = this.layers.get(layerId);\n if (!layer || layer.type !== 'image') return null;\n const image = layer.fabricObject as FabricImage;\n const sourcePixels = image.width ?? 0;\n const displayedPixels = image.getScaledWidth();\n if (sourcePixels <= 0 || displayedPixels <= 0) return null;\n return round2(sourcePixels / (displayedPixels / this.units.getDpi()));\n }\n\n validateImageDpi(minimumDpi = 300): DpiIssue[] {\n return this.layers\n .getAll()\n .filter((layer) => layer.type === 'image' && !layer.meta.pattern)\n .flatMap((layer) => {\n const effectiveDpi = this.getImageDpi(layer.id);\n return effectiveDpi !== null && effectiveDpi < minimumDpi\n ? [{ layerId: layer.id, layerName: layer.name, effectiveDpi, minimumDpi }]\n : [];\n });\n }\n\n /** Render a small data-URL preview without changing document dimensions. */\n toThumbnail(maxWidth = 320, maxHeight = 320, format: ImageFormat = 'png'): string {\n const multiplier = Math.min(\n 1,\n maxWidth / this.canvas.getWidth(),\n maxHeight / this.canvas.getHeight(),\n );\n return this.toDataURL(format, multiplier);\n }\n\n bringToFront(id: string): boolean {\n return this.layers.reorder(id, this.layers.count() - 1);\n }\n\n sendToBack(id: string): boolean {\n return this.layers.reorder(id, 0);\n }\n\n bringForward(id: string): boolean {\n const index = this.layers.getAll().findIndex((layer) => layer.id === id);\n return index >= 0 && this.layers.reorder(id, index + 1);\n }\n\n sendBackward(id: string): boolean {\n const index = this.layers.getAll().findIndex((layer) => layer.id === id);\n return index >= 0 && this.layers.reorder(id, index - 1);\n }\n\n // ─── Zoom ───────────────────────────────────────────\n //\n // Zoom is a *display* transform (the view layer CSS-scales the canvas), not a\n // fabric viewport zoom — fabric's setZoom bakes into toDataURL/toSVG and would\n // corrupt exports. The editor only tracks the level and emits an event.\n\n setZoom(level: number): void {\n const next = clamp(round2(level), MIN_ZOOM, MAX_ZOOM);\n if (next === this.zoomLevel) return;\n this.zoomLevel = next;\n // Handles are sized in screen pixels — re-counter-scale them for the new\n // display zoom, or they would grow and shrink with the artwork.\n this.refreshSelectionStyle();\n this.events.emit('zoom:changed', { zoom: next });\n }\n\n /** @deprecated use setZoom — kept for backward compatibility. */\n zoom(level: number): void {\n this.setZoom(level);\n }\n\n getZoom(): number {\n return this.zoomLevel;\n }\n\n zoomIn(step = 0.1): void {\n this.setZoom(this.zoomLevel + step);\n }\n\n zoomOut(step = 0.1): void {\n this.setZoom(this.zoomLevel - step);\n }\n\n resetZoom(): void {\n this.setZoom(1);\n }\n\n /** Fit the canvas inside a viewport (in px), accounting for padding. */\n zoomToFit(viewportWidth: number, viewportHeight: number, padding = 0): void {\n const w = this.canvas.getWidth();\n const h = this.canvas.getHeight();\n if (w <= 0 || h <= 0) return;\n const sx = (viewportWidth - padding * 2) / w;\n const sy = (viewportHeight - padding * 2) / h;\n this.setZoom(Math.min(sx, sy));\n }\n\n /** Zoom until the current selection fills the artboard viewport. */\n zoomToSelection(padding = 24): void {\n const active = this.canvas.getActiveObject();\n if (!active) return;\n active.setCoords();\n const bounds = active.getBoundingRect();\n if (bounds.width <= 0 || bounds.height <= 0) return;\n this.setZoom(\n Math.min(\n (this.canvas.getWidth() - padding * 2) / bounds.width,\n (this.canvas.getHeight() - padding * 2) / bounds.height,\n ),\n );\n }\n\n // ─── Patterns ───────────────────────────────────────\n\n applyPattern(layerId: string, config: PatternConfig): Promise<void> {\n return this.patterns.apply(layerId, config);\n }\n\n clearPattern(layerId: string): Promise<void> {\n return this.patterns.disable(layerId);\n }\n\n // ─── Text curve ─────────────────────────────────────\n\n applyTextCurve(layerId: string, config: Partial<TextCurveConfig>): boolean {\n return this.curves.apply(layerId, config);\n }\n\n clearTextCurve(layerId: string): boolean {\n return this.curves.clear(layerId);\n }\n\n getTextCurve(layerId: string): TextCurveConfig | null {\n return this.curves.get(layerId);\n }\n\n // ─── Mask presets ───────────────────────────────────\n\n applyMaskPreset(layerId: string, id: MaskPresetId | null): boolean {\n return this.maskPresets.apply(layerId, id);\n }\n\n clearMaskPreset(layerId: string): boolean {\n return this.maskPresets.clear(layerId);\n }\n\n getMaskPreset(layerId: string): MaskPresetId | null {\n return this.maskPresets.get(layerId);\n }\n\n // ─── Layer transform ────────────────────────────────\n\n /**\n * Constrain a layer to its current proportions. Persisted on the layer so a\n * reopened design still resizes the way it was set up to.\n */\n setLayerAspectLock(layerId: string, locked: boolean): boolean {\n const layer = this.layers.get(layerId);\n if (!layer) return false;\n applyAspectLock(layer.fabricObject, locked);\n if (locked) layer.meta.lockAspect = true;\n else delete layer.meta.lockAspect;\n this.canvas.requestRenderAll();\n this.events.emit('layer:modified', { layerId });\n this.history.save();\n return true;\n }\n\n getLayerAspectLock(layerId: string): boolean {\n return this.layers.get(layerId)?.meta.lockAspect === true;\n }\n\n /** Re-apply every stored aspect lock — control visibility is not serialized. */\n restoreAspectLocks(): void {\n for (const layer of this.layers.getAll()) {\n if (layer.meta.lockAspect) applyAspectLock(layer.fabricObject, true);\n }\n }\n\n /** Drop scale, rotation, skew and flips; the layer stays where it is. */\n resetLayerTransform(layerId: string): boolean {\n const layer = this.layers.get(layerId);\n if (!layer) return false;\n resetTransform(layer.fabricObject);\n this.canvas.requestRenderAll();\n this.events.emit('layer:modified', { layerId });\n this.history.save();\n return true;\n }\n\n // ─── Shadow ─────────────────────────────────────────\n\n setLayerShadow(layerId: string, config: Partial<LayerShadowConfig>): boolean {\n const layer = this.layers.get(layerId);\n if (!layer) return false;\n applyLayerShadow(layer.fabricObject, config);\n layer.fabricObject.dirty = true;\n this.canvas.requestRenderAll();\n this.events.emit('layer:modified', { layerId });\n this.history.save();\n return true;\n }\n\n getLayerShadow(layerId: string): LayerShadowConfig | null {\n const layer = this.layers.get(layerId);\n return layer ? readLayerShadow(layer.fabricObject) : null;\n }\n\n // ─── Mockup (preview-only) ──────────────────────────\n\n /**\n * Show (or clear) the product preview. Pass `history: false` for preview-only\n * changes such as swapping a colourway — those are not design edits and\n * should not fill the undo stack.\n */\n setMockup(mockup: MockupConfig | null, options: { history?: boolean } = {}): void {\n this.mockup = mockup;\n // The mockup renders behind the design, so the canvas must be transparent\n // while it is shown; restore the configured background when it is cleared.\n this.canvas.backgroundColor = mockup ? '' : this.designBackground;\n this.canvas.backgroundImage = mockup ? undefined : (this.designBackgroundImage ?? undefined);\n this.canvas.requestRenderAll();\n this.events.emit('mockup:changed', { mockup });\n if (options.history !== false) this.history.save();\n }\n\n clearMockup(): void {\n this.setMockup(null);\n }\n\n getMockup(): MockupConfig | null {\n return this.mockup;\n }\n\n // ─── Cleanup ────────────────────────────────────────\n\n dispose(): void {\n this.masks.dispose();\n this.layerMasks.dispose();\n this.snapping.dispose();\n this.crop.dispose();\n this.history.dispose();\n this.patterns.dispose();\n this.curves.dispose();\n this.events.removeAllListeners();\n this.canvas.dispose();\n }\n\n // ─── Selection style ────────────────────────────────\n\n /** Current look of the selection frame and its handles. */\n getSelectionStyle(): SelectionStyle {\n return { ...this.selectionStyle };\n }\n\n /**\n * Restyles the selection frame and resize handles. Sizes are in screen\n * pixels and stay constant across zoom levels (see `SelectionStyle`).\n */\n setSelectionStyle(style: Partial<SelectionStyle>): void {\n this.selectionStyle = { ...this.selectionStyle, ...style };\n this.refreshSelectionStyle();\n }\n\n private refreshSelectionStyle(): void {\n applySelectionStyle(this.canvas, this.selectionStyle, this.zoomLevel);\n }\n\n // ─── Private ────────────────────────────────────────\n\n private setupCanvasEvents(): void {\n // Objects arrive from adds, restores and undo alike — style them here so\n // there is a single place that can't be forgotten.\n this.canvas.on('object:added', (e) => {\n if (e.target) applyObjectSelectionStyle(e.target, this.selectionStyle, this.zoomLevel);\n });\n\n // The active selection is a transient group fabric creates on the fly; it\n // never passes through 'object:added'.\n const styleActive = () => {\n const active = this.canvas.getActiveObject();\n if (active) applyObjectSelectionStyle(active, this.selectionStyle, this.zoomLevel);\n };\n\n this.canvas.on('object:modified', (e) => {\n if (!e.target) return;\n const layer = this.layers.findByObject(e.target);\n if (layer) {\n this.events.emit('layer:modified', { layerId: layer.id });\n this.history.save();\n }\n });\n\n this.canvas.on('selection:created', (e) => {\n styleActive();\n const selected = (e.selected ?? [])\n .map((obj) => this.layers.findByObject(obj)?.id)\n .filter((id): id is string => id !== undefined);\n this.events.emit('selection:changed', { selected });\n });\n\n this.canvas.on('selection:updated', (e) => {\n styleActive();\n const selected = (e.selected ?? [])\n .map((obj) => this.layers.findByObject(obj)?.id)\n .filter((id): id is string => id !== undefined);\n this.events.emit('selection:changed', { selected });\n });\n\n this.canvas.on('selection:cleared', () => {\n this.events.emit('selection:changed', { selected: [] });\n });\n }\n}\n","type EventHandler<T> = (data: T) => void;\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport class EventEmitter<TEvents extends {} = Record<string, unknown>> {\n private listeners = new Map<keyof TEvents, Set<EventHandler<unknown>>>();\n\n on<K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(handler as EventHandler<unknown>);\n }\n\n off<K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>): void {\n this.listeners.get(event)?.delete(handler as EventHandler<unknown>);\n }\n\n once<K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>): void {\n const wrapped: EventHandler<TEvents[K]> = (data) => {\n this.off(event, wrapped);\n handler(data);\n };\n this.on(event, wrapped);\n }\n\n emit<K extends keyof TEvents>(event: K, data: TEvents[K]): void {\n const handlers = this.listeners.get(event);\n if (!handlers) return;\n for (const handler of handlers) {\n handler(data);\n }\n }\n\n removeAllListeners(event?: keyof TEvents): void {\n if (event) {\n this.listeners.delete(event);\n } else {\n this.listeners.clear();\n }\n }\n}\n","import { ActiveSelection, Group } from 'fabric';\nimport type { Canvas, FabricObject } from 'fabric';\nimport type { LayerData, LayerMeta, LayerType, SerializedLayer } from './types';\nimport type { EditorEvents } from './types';\nimport type { EventEmitter } from './events';\nimport { generateId } from './utils/id';\n\nexport class Layer {\n readonly id: string;\n readonly type: LayerType;\n name: string;\n visible: boolean;\n locked: boolean;\n opacity: number;\n /** Non-fabric data (e.g. pattern config) that must persist with the layer. */\n meta: LayerMeta;\n fabricObject: FabricObject;\n /**\n * Stand-in object drawn in place of `fabricObject` (the tiled pattern). It is\n * part of the canvas but never part of the document: it is not serialized, and\n * the layer's real object stays the one every editor API talks to.\n */\n renderProxy: FabricObject | null;\n /**\n * Layers nested inside this one, in draw order. Only a `group` layer has any:\n * their fabric objects live inside this layer's fabric `Group`, not on the\n * canvas, which is why the manager keeps them off the canvas stack.\n */\n children: Layer[];\n /** Group this layer sits inside, or null when it is on the canvas stack. */\n parentId: string | null;\n\n constructor(type: LayerType, fabricObject: FabricObject, name?: string, id?: string) {\n this.id = id ?? generateId();\n this.type = type;\n this.name = name ?? `${type}-${this.id.slice(0, 4)}`;\n this.visible = true;\n this.locked = false;\n this.opacity = 1;\n this.meta = {};\n this.fabricObject = fabricObject;\n this.renderProxy = null;\n this.children = [];\n this.parentId = null;\n\n (this.fabricObject as FabricObject & { _layerId: string })._layerId = this.id;\n }\n\n private hasMeta(): boolean {\n return Object.keys(this.meta).length > 0;\n }\n\n toData(): LayerData {\n return {\n id: this.id,\n type: this.type,\n name: this.name,\n visible: this.visible,\n locked: this.locked,\n opacity: this.opacity,\n ...(this.hasMeta() ? { meta: this.meta } : {}),\n ...(this.children.length > 0 ? { children: this.children.map((c) => c.toData()) } : {}),\n };\n }\n\n serialize(): SerializedLayer {\n return {\n ...this.toData(),\n // A group's own object already carries its children's geometry, so the\n // child records in `toData` stay identity-only — nothing is duplicated.\n fabricObject: this.fabricObject.toObject() as Record<string, unknown>,\n };\n }\n}\n\nexport class LayerManager {\n private layers: Layer[] = [];\n private onPropertyChanged?: () => void;\n\n constructor(\n private canvas: Canvas,\n private events: EventEmitter<EditorEvents>,\n ) {}\n\n setHistoryCallback(callback: () => void): void {\n this.onPropertyChanged = callback;\n }\n\n add(type: LayerType, fabricObject: FabricObject, name?: string, id?: string): Layer {\n const layer = new Layer(type, fabricObject, name, id);\n this.layers.push(layer);\n this.canvas.add(fabricObject);\n this.events.emit('layer:added', { layer: layer.toData() });\n this.emitChanged();\n return layer;\n }\n\n remove(id: string): boolean {\n const layer = this.get(id);\n if (!layer) return false;\n\n if (layer.parentId) {\n const parent = this.get(layer.parentId);\n if (!parent) return false;\n (parent.fabricObject as Group).remove(layer.fabricObject);\n parent.children = parent.children.filter((c) => c.id !== id);\n layer.parentId = null;\n this.events.emit('layer:removed', { layerId: id });\n // A group of one lies in the panel and traps transforms: the survivor\n // goes back on the canvas stack instead of sitting alone in a group.\n if (parent.children.length < 2) this.dissolve(parent);\n this.emitChanged();\n this.onPropertyChanged?.();\n this.canvas.requestRenderAll();\n return true;\n }\n\n const index = this.layers.findIndex((l) => l.id === id);\n if (index === -1) return false;\n this.canvas.remove(layer.fabricObject);\n if (layer.renderProxy) this.canvas.remove(layer.renderProxy);\n this.layers.splice(index, 1);\n this.events.emit('layer:removed', { layerId: id });\n this.emitChanged();\n this.onPropertyChanged?.();\n return true;\n }\n\n /**\n * Take a top-level layer off the canvas stack **without** disposing it — it is\n * about to become a group's child, so its object has to stay alive.\n */\n detach(id: string): Layer | undefined {\n const index = this.layers.findIndex((l) => l.id === id);\n if (index === -1) return undefined;\n const [layer] = this.layers.splice(index, 1);\n this.canvas.remove(layer.fabricObject);\n if (layer.renderProxy) this.canvas.remove(layer.renderProxy);\n return layer;\n }\n\n /** Put a group's children back on the canvas stack and drop the group. */\n explode(group: Layer): Layer[] {\n const children = [...group.children];\n this.dissolve(group);\n this.events.emit('layer:removed', { layerId: group.id });\n this.emitChanged();\n this.onPropertyChanged?.();\n this.canvas.requestRenderAll();\n return children;\n }\n\n /**\n * Empty a group onto the canvas stack, in the group's own place, and drop the\n * group record. `removeAll` restores each child's absolute transform, so the\n * group's matrix must NOT be re-applied on top of it.\n */\n private dissolve(group: Layer): void {\n const objects = (group.fabricObject as Group).removeAll();\n const at = this.layers.findIndex((l) => l.id === group.id);\n const survivors = group.children;\n group.children = [];\n for (const [index, object] of objects.entries()) {\n object.setCoords();\n const child = survivors[index];\n if (!child) continue;\n child.parentId = null;\n this.layers.splice(at + index, 0, child);\n this.canvas.add(object);\n if (child.renderProxy) this.canvas.add(child.renderProxy);\n }\n this.canvas.remove(group.fabricObject);\n this.layers = this.layers.filter((l) => l.id !== group.id);\n this.syncZOrder();\n }\n\n /**\n * Move existing layer records under a group, and announce the new tree.\n * Assigning `group.children` directly emits nothing, and the reorder that\n * follows a grouping is a no-op whenever the group already sits where it\n * belongs — leaving `layers:changed` describing a childless group, so a panel\n * built on it renders the group with nothing inside.\n */\n adoptChildren(group: Layer, children: Layer[]): void {\n for (const child of children) child.parentId = group.id;\n group.children = children;\n this.emitChanged();\n this.onPropertyChanged?.();\n }\n\n /**\n * Re-attach child records to an enlivened group. `data[i]` describes\n * `group._objects[i]` — the order fabric serializes and restores them in. A\n * missing record still becomes a child, so a hand-edited state cannot drop\n * artwork off the canvas.\n */\n adoptGroupChildren(group: Layer, data: LayerData[]): void {\n const objects = (group.fabricObject as Group).getObjects();\n group.children = objects.map((object, index) => {\n const record = data[index];\n const child = new Layer(record?.type ?? 'shape', object, record?.name, record?.id);\n child.parentId = group.id;\n if (record?.meta) child.meta = structuredClone(record.meta);\n if (record && !record.visible) {\n child.visible = false;\n object.visible = false;\n }\n if (record?.locked) {\n child.locked = true;\n object.selectable = false;\n object.evented = false;\n }\n if (record && record.opacity !== 1) {\n child.opacity = record.opacity;\n object.opacity = record.opacity;\n }\n return child;\n });\n this.emitChanged();\n }\n\n /** Replace a layer's render object while preserving its immutable ID and panel state. */\n replaceObject(id: string, fabricObject: FabricObject): boolean {\n const layer = this.get(id);\n if (!layer || layer.fabricObject === fabricObject) return false;\n const previous = layer.fabricObject;\n const stackIndex = this.canvas.getObjects().indexOf(previous);\n const wasActive = this.canvas.getActiveObject() === previous;\n this.canvas.remove(previous);\n layer.fabricObject = fabricObject;\n (fabricObject as FabricObject & { _layerId: string })._layerId = id;\n fabricObject.set({\n visible: layer.visible,\n opacity: layer.opacity,\n selectable: !layer.locked,\n evented: !layer.locked,\n });\n this.canvas.insertAt(Math.max(0, stackIndex), fabricObject);\n // A proxied layer draws through its proxy; the replacement takes the\n // source's place — invisible, but still the thing the panels talk to.\n if (layer.renderProxy) {\n fabricObject.set({ opacity: 0 });\n this.syncZOrder();\n }\n if (wasActive) this.canvas.setActiveObject(fabricObject);\n this.canvas.requestRenderAll();\n this.events.emit('layer:modified', { layerId: id });\n this.emitChanged();\n this.onPropertyChanged?.();\n return true;\n }\n\n /**\n * Attach (or clear) the object drawn in place of a layer's own object. The\n * proxy tracks the layer's stacking position, visibility and opacity, and is\n * removed with the layer — it must never outlive or drift from its source.\n */\n setRenderProxy(id: string, proxy: FabricObject | null): void {\n const layer = this.get(id);\n if (!layer || layer.renderProxy === proxy) return;\n if (layer.renderProxy) this.canvas.remove(layer.renderProxy);\n layer.renderProxy = proxy;\n if (proxy) {\n // Tagged with the layer id so canvas selection resolves to this layer —\n // the proxy is what the user clicks and drags once it is in place.\n (proxy as FabricObject & { _layerId: string })._layerId = id;\n proxy.set({\n visible: layer.visible,\n opacity: layer.opacity,\n selectable: !layer.locked,\n evented: !layer.locked,\n });\n this.canvas.add(proxy);\n this.syncZOrder();\n }\n this.canvas.requestRenderAll();\n this.emitChanged();\n }\n\n /**\n * Re-stack every canvas object to match layer order, keeping each proxy\n * directly above the source it stands in for. Canvas indices can't be derived\n * from layer indices once proxies are in the array, so the order is rebuilt\n * front-to-back instead of computed.\n */\n private syncZOrder(): void {\n for (const layer of this.layers) {\n this.canvas.bringObjectToFront(layer.fabricObject);\n if (layer.renderProxy) this.canvas.bringObjectToFront(layer.renderProxy);\n }\n }\n\n /** The list a layer lives in: its group's children, or the canvas stack. */\n private siblingsOf(layer: Layer): Layer[] {\n if (!layer.parentId) return this.layers;\n return this.get(layer.parentId)?.children ?? this.layers;\n }\n\n reorder(id: string, newIndex: number): boolean {\n const target = this.get(id);\n if (!target) return false;\n const list = this.siblingsOf(target);\n const oldIndex = list.indexOf(target);\n if (oldIndex === -1) return false;\n if (!Number.isFinite(newIndex)) return false;\n const clamped = Math.max(0, Math.min(list.length - 1, Math.round(newIndex)));\n if (oldIndex === clamped) return false;\n const [layer] = list.splice(oldIndex, 1);\n list.splice(clamped, 0, layer);\n if (layer.parentId) {\n // Inside a group the draw order is the group's own object order; the\n // canvas stack has no say in it.\n const group = this.get(layer.parentId)?.fabricObject as Group | undefined;\n if (group) {\n group.remove(layer.fabricObject);\n group.insertAt(clamped, layer.fabricObject);\n }\n } else {\n this.syncZOrder();\n }\n this.events.emit('layer:reordered', { layerIds: list.map((l) => l.id) });\n this.emitChanged();\n this.onPropertyChanged?.();\n return true;\n }\n\n select(id: string | null): void {\n if (id === null) {\n this.canvas.discardActiveObject();\n this.exitGroups();\n } else {\n const layer = this.get(id);\n if (layer) {\n // A child is only selectable while its group is interactive: fabric\n // otherwise routes every hit to the group and `setActiveObject` on the\n // child leaves the handles on nothing.\n if (layer.parentId) this.enterGroup(layer.parentId);\n else this.exitGroups();\n // Select what the user can actually grab: a proxied layer's own object\n // is invisible and inert, and framing it would put the handles on\n // nothing. See `LayerManager.setRenderProxy`.\n this.canvas.setActiveObject(layer.renderProxy ?? layer.fabricObject);\n }\n }\n this.canvas.requestRenderAll();\n this.events.emit('layer:selected', { layerId: id });\n // Fabric only fires selection:* on user interaction; mirror programmatic\n // selection so React selection state (useSelection) stays in sync.\n const selected = id && this.get(id) ? [id] : [];\n this.events.emit('selection:changed', { selected });\n }\n\n /** Drill into a group so its children can be selected and clicked. */\n private enterGroup(groupId: string): void {\n const parent = this.get(groupId);\n if (!parent) return;\n const group = parent.fabricObject as Group & { interactive: boolean };\n group.subTargetCheck = true;\n group.interactive = true;\n }\n\n /** Leave every entered group — selecting anything else is done drilling in. */\n exitGroups(): void {\n for (const layer of this.layers) {\n if (layer.type !== 'group') continue;\n const group = layer.fabricObject as Group & { interactive: boolean };\n if (group.interactive) group.interactive = false;\n }\n }\n\n /**\n * Select several layers at once, as one fabric `ActiveSelection`. Children are\n * skipped: a selection spanning in and out of a group has no single transform.\n */\n selectMany(ids: string[]): void {\n const layers = ids.flatMap((id) => {\n const layer = this.get(id);\n return layer && !layer.parentId ? [layer] : [];\n });\n if (layers.length === 0) return this.select(null);\n if (layers.length === 1) return this.select(layers[0].id);\n this.canvas.discardActiveObject();\n this.exitGroups();\n const selection = new ActiveSelection(\n layers.map((l) => l.renderProxy ?? l.fabricObject),\n { canvas: this.canvas },\n );\n this.canvas.setActiveObject(selection);\n this.canvas.requestRenderAll();\n // Fabric emits selection events for user interaction only; a programmatic\n // multi-select has to mirror its own, like `select` does.\n this.events.emit('selection:changed', { selected: layers.map((l) => l.id) });\n }\n\n /** Depth-first over the whole tree, each layer before its children. */\n private *walk(layers: Layer[] = this.layers): Generator<Layer> {\n for (const layer of layers) {\n yield layer;\n if (layer.children.length > 0) yield* this.walk(layer.children);\n }\n }\n\n get(id: string): Layer | undefined {\n for (const layer of this.walk()) if (layer.id === id) return layer;\n return undefined;\n }\n\n /** Top-level layers only — the canvas stack. Children hang off their group. */\n getAll(): Layer[] {\n return [...this.layers];\n }\n\n /** Top-level layers, each carrying its children: what the layer panel renders. */\n getTree(): LayerData[] {\n return this.layers.map((l) => l.toData());\n }\n\n findByObject(obj: FabricObject): Layer | undefined {\n const layerId = (obj as FabricObject & { _layerId?: string })._layerId;\n if (layerId) return this.get(layerId);\n for (const layer of this.walk()) if (layer.fabricObject === obj) return layer;\n return undefined;\n }\n\n setVisibility(id: string, visible: boolean): void {\n const layer = this.get(id);\n if (!layer) return;\n if (layer.visible === visible) return;\n layer.visible = visible;\n layer.fabricObject.visible = visible;\n if (layer.renderProxy) layer.renderProxy.visible = visible;\n this.canvas.requestRenderAll();\n this.emitChanged();\n this.onPropertyChanged?.();\n }\n\n setLocked(id: string, locked: boolean): void {\n const layer = this.get(id);\n if (!layer) return;\n if (layer.locked === locked) return;\n layer.locked = locked;\n // A proxied layer interacts through its proxy; its own object stays inert.\n const target = layer.renderProxy ?? layer.fabricObject;\n target.selectable = !locked;\n target.evented = !locked;\n this.canvas.requestRenderAll();\n this.emitChanged();\n this.onPropertyChanged?.();\n }\n\n setOpacity(id: string, opacity: number): void {\n const layer = this.get(id);\n if (!layer || !Number.isFinite(opacity)) return;\n const next = Math.max(0, Math.min(1, opacity));\n if (layer.opacity === next) return;\n layer.opacity = next;\n // A proxied layer's own object is parked at opacity 0 (invisible, still\n // selectable) — the opacity the user set belongs to what is actually drawn.\n if (layer.renderProxy) layer.renderProxy.opacity = next;\n else layer.fabricObject.opacity = next;\n this.canvas.requestRenderAll();\n this.emitChanged();\n this.onPropertyChanged?.();\n }\n\n setName(id: string, name: string): void {\n const layer = this.get(id);\n if (!layer) return;\n if (layer.name === name) return;\n layer.name = name;\n this.emitChanged();\n this.onPropertyChanged?.();\n }\n\n /**\n * Patch a layer's host metadata. A key whose value is `undefined` is removed.\n *\n * `meta` is part of `LayerData` and is serialized, so a host that assigns\n * `layer.meta.x` directly gets neither of the two things every other setter\n * here provides: `layers:changed` (so `useLayers()` keeps returning the old\n * meta) and the history checkpoint (so an undo silently reverts the write —\n * the state IS versioned, it was just never committed at the moment it\n * changed). Going through this method is what makes metadata behave like\n * every other layer property.\n */\n setMeta(id: string, patch: LayerMeta): void {\n const layer = this.get(id);\n if (!layer) return;\n\n const next: LayerMeta = { ...layer.meta };\n let changed = false;\n for (const [key, value] of Object.entries(patch)) {\n if (value === undefined) {\n if (key in next) {\n delete next[key];\n changed = true;\n }\n continue;\n }\n if (next[key] !== value) changed = true;\n next[key] = value;\n }\n if (!changed) return;\n\n layer.meta = next;\n this.emitChanged();\n this.onPropertyChanged?.();\n }\n\n clear(): void {\n for (const layer of this.layers) {\n this.canvas.remove(layer.fabricObject);\n if (layer.renderProxy) this.canvas.remove(layer.renderProxy);\n // Children go with their group; a stale record would survive a restore.\n layer.children = [];\n }\n this.layers = [];\n this.emitChanged();\n }\n\n count(): number {\n return this.layers.length;\n }\n\n private emitChanged(): void {\n this.events.emit('layers:changed', {\n layers: this.layers.map((l) => l.toData()),\n });\n }\n}\n","import { nanoid } from 'nanoid';\n\nexport const generateId = (): string => nanoid(12);\n","import { Textbox, loadSVGFromString } from 'fabric';\nimport type { FabricObject } from 'fabric';\nimport type { TemplateDefinition, TextCurveConfig } from './types';\n\n/**\n * A template is a bootstrap, not a frozen picture: it is taken apart into the\n * layers it is drawn from, so every run of copy stays editable afterwards.\n */\nexport interface TemplateLayerSpec {\n type: 'text' | 'shape';\n name: string;\n object: FabricObject;\n /**\n * Baseline curve to apply once the layer exists (`<textPath>` templates).\n * Partial on purpose: a template states only the parameters it cares about\n * and `TextCurveManager.apply` normalizes the rest.\n */\n curve?: Partial<TextCurveConfig>;\n}\n\n/** Longest layer name taken from a literal run before it is elided. */\nconst NAME_MAX = 24;\n\ninterface ParsedText extends FabricObject {\n text: string;\n fontSize: number;\n fontFamily: string;\n fontWeight: string | number;\n fontStyle: Textbox['fontStyle'];\n textAlign: Textbox['textAlign'];\n charSpacing: number;\n lineHeight: number;\n}\n\nfunction isText(object: FabricObject): object is ParsedText {\n return typeof (object as { text?: unknown }).text === 'string';\n}\n\n/**\n * Resolved run → parameter label, read off the template's own source.\n *\n * The label is what makes a layer say \"Title\" instead of \"text-8fa1\"; matching\n * on the *resolved* value (not the placeholder) is what keeps it working when\n * the caller supplies its own parameter values.\n */\nfunction labelsByRun(\n template: TemplateDefinition,\n values: Record<string, string | number>,\n): Map<string, string> {\n const labels = new Map(template.parameters.map((p) => [p.key, p.label || p.key]));\n const byRun = new Map<string, string>();\n for (const match of template.svg.matchAll(/<text\\b[^>]*>([\\s\\S]*?)<\\/text>/g)) {\n const token = /\\{\\{(\\w+)(?:[|:]([^}]*))?\\}\\}/.exec(match[1]);\n if (!token) continue;\n const label = labels.get(token[1]);\n if (!label) continue;\n const resolved = String(values[token[1]] ?? token[2] ?? '').trim();\n if (resolved) byRun.set(resolved, label);\n }\n return byRun;\n}\n\nfunction textName(run: string, labels: Map<string, string>): string {\n const trimmed = run.trim();\n const label = labels.get(trimmed);\n if (label) return label;\n if (!trimmed) return 'Text';\n return trimmed.length > NAME_MAX ? `${trimmed.slice(0, NAME_MAX - 1)}…` : trimmed;\n}\n\nfunction shapeName(object: FabricObject): string {\n const id = (object as { id?: unknown }).id;\n if (typeof id === 'string' && id) return id;\n const type = object.type || 'shape';\n return type.charAt(0).toUpperCase() + type.slice(1);\n}\n\n/**\n * Rebuild a parsed `<text>` as the `Textbox` `addText` produces.\n *\n * Fabric parses SVG text into a `FabricText`, which the studio's text panel,\n * font picker and curve controls do not drive — a template's copy would look\n * editable and refuse to be edited. Placement, styling and glyphs carry over.\n */\nfunction toTextbox(text: ParsedText): FabricObject {\n const box = new Textbox(text.text, {\n left: text.left,\n top: text.top,\n originX: text.originX,\n originY: text.originY,\n angle: text.angle,\n scaleX: text.scaleX,\n scaleY: text.scaleY,\n fontSize: text.fontSize,\n fontFamily: text.fontFamily,\n fontWeight: text.fontWeight,\n fontStyle: text.fontStyle,\n textAlign: text.textAlign,\n charSpacing: text.charSpacing,\n lineHeight: text.lineHeight,\n fill: text.fill,\n stroke: text.stroke,\n strokeWidth: text.strokeWidth,\n opacity: text.opacity,\n // A Textbox wraps at its box width; size it to the run the template drew so\n // the authored copy never comes in pre-wrapped.\n width: Math.max(1, (text.width ?? 0) + 2),\n });\n return box as unknown as FabricObject;\n}\n\n/**\n * Curve a `<textPath>` template asks for.\n *\n * Fabric's SVG parser cannot read `<textPath>` at all, so these templates are\n * rebuilt from their parameters instead of parsed — the curve is the engine's\n * own, which keeps the text editable rather than rasterized.\n */\nexport function textPathCurve(\n template: TemplateDefinition,\n values: Record<string, string | number>,\n runWidth: number,\n): Partial<TextCurveConfig> {\n // `arc: 100` is the closed ring (see FULL_CIRCLE_ARC in text-curve.ts).\n if (template.id === 'circular-text') return { arc: 100, wave: 0 };\n if (template.id === 'wave-text') return { arc: 0, wave: 50 };\n // arcPathData builds its path with radius = width / sweep and\n // sweep = (arc / 100) · π, so this inverts the template's own radius.\n const radius = Number(values.radius ?? 200);\n if (!Number.isFinite(radius) || radius <= 0) return { arc: 0, wave: 0 };\n const arc = (100 * runWidth) / (Math.PI * radius);\n return { arc: Math.max(-100, Math.min(100, arc)), wave: 0 };\n}\n\n/** The single text layer a `<textPath>` template stands for. */\nexport function textPathSpec(\n template: TemplateDefinition,\n values: Record<string, string | number>,\n): TemplateLayerSpec {\n const content = String(values.text ?? 'Text');\n const fontSize = template.id === 'circular-text' ? 28 : 40;\n const box = new Textbox(content, {\n fontSize,\n fontFamily: String(values.font ?? 'Arial'),\n fontWeight: 'bold',\n fill: String(values.color ?? '#000000'),\n originX: 'left',\n originY: 'top',\n // Wide enough that the run stays on one line before the curve widens it.\n width: Math.max(1, content.length * fontSize * 0.62),\n });\n return {\n type: 'text',\n name: template.parameters.find((p) => p.key === 'text')?.label || 'Text',\n object: box as unknown as FabricObject,\n curve: textPathCurve(template, values, box.width ?? 0),\n };\n}\n\n/**\n * The layers a resolved template SVG is made of, in draw order: every `<text>`\n * an editable text layer, every other top-level element a vector layer.\n */\nexport async function explodeTemplateSvg(\n template: TemplateDefinition,\n resolvedSvg: string,\n values: Record<string, string | number>,\n): Promise<TemplateLayerSpec[]> {\n const labels = labelsByRun(template, values);\n const { objects } = await loadSVGFromString(resolvedSvg);\n const specs: TemplateLayerSpec[] = [];\n for (const object of objects) {\n if (object === null) continue;\n if (isText(object)) {\n specs.push({ type: 'text', name: textName(object.text, labels), object: toTextbox(object) });\n continue;\n }\n specs.push({ type: 'shape', name: shapeName(object), object });\n }\n return specs;\n}\n","import type { EditorEvents } from './types';\nimport type { EventEmitter } from './events';\n\nexport class HistoryManager {\n private static readonly ASSET_KEY = '__canvasEditorHistoryAsset';\n private undoStack: string[] = [];\n private redoStack: string[] = [];\n private assets = new Map<string, string>();\n private assetIds = new Map<string, string>();\n private nextAssetId = 1;\n private maxSize: number;\n private maxBytes: number;\n private paused = false;\n private debounceTimer: ReturnType<typeof setTimeout> | null = null;\n private debounceMs: number;\n private getState: () => string;\n private restoreState: (state: string) => Promise<void>;\n private events: EventEmitter<EditorEvents>;\n private transactionDepth = 0;\n private transactionDirty = false;\n\n constructor(opts: {\n getState: () => string;\n restoreState: (state: string) => Promise<void>;\n events: EventEmitter<EditorEvents>;\n maxSize?: number;\n maxBytes?: number;\n debounceMs?: number;\n }) {\n this.getState = opts.getState;\n this.restoreState = opts.restoreState;\n this.events = opts.events;\n this.maxSize = opts.maxSize ?? 50;\n this.maxBytes = opts.maxBytes ?? 50 * 1024 * 1024;\n this.debounceMs = opts.debounceMs ?? 300;\n }\n\n save(): void {\n if (this.paused) return;\n if (this.transactionDepth > 0) {\n this.transactionDirty = true;\n return;\n }\n\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n }\n\n this.debounceTimer = setTimeout(() => {\n this.saveImmediate();\n }, this.debounceMs);\n this.emitChanged();\n }\n\n saveImmediate(): void {\n if (this.paused) {\n this.cancelPending();\n return;\n }\n if (this.transactionDepth > 0) {\n this.transactionDirty = true;\n return;\n }\n this.cancelPending();\n const rawState = this.getState();\n const state = this.compactState(rawState);\n if (this.undoStack.at(-1) === state) {\n this.emitChanged();\n return;\n }\n this.undoStack.push(state);\n while (this.undoStack.length > this.maxSize) {\n this.undoStack.shift();\n }\n this.redoStack = [];\n this.trimToBudget();\n this.events.emit('history:snapshot', {\n bytes: rawState.length * 2,\n totalBytes: this.snapshotBytes(),\n entries: this.undoStack.length,\n });\n this.emitChanged();\n }\n\n beginTransaction(): void {\n // Commit any prior debounced edit as the transaction's undo baseline.\n if (this.transactionDepth === 0 && this.debounceTimer) this.saveImmediate();\n this.transactionDepth += 1;\n }\n\n endTransaction(): void {\n if (this.transactionDepth === 0) return;\n this.transactionDepth -= 1;\n if (this.transactionDepth === 0 && this.transactionDirty) {\n this.transactionDirty = false;\n this.saveImmediate();\n }\n }\n\n async transaction<T>(operation: () => T | Promise<T>): Promise<T> {\n this.beginTransaction();\n try {\n return await operation();\n } finally {\n this.endTransaction();\n }\n }\n\n async undo(): Promise<void> {\n // Drop any debounced save still pending from an in-progress edit, otherwise\n // its timer would fire after restore completes and clobber the redo stack.\n this.cancelPending();\n const committed = this.undoStack.at(-1);\n if (!committed) return;\n const current = this.compactState(this.getState());\n\n // The stack's top is the current committed state. If a debounced edit is\n // still dirty, restore that top; otherwise step back to the previous item.\n const currentIsCommitted = current === committed;\n if (currentIsCommitted && this.undoStack.length < 2) return;\n const target = currentIsCommitted ? this.undoStack[this.undoStack.length - 2] : committed;\n\n this.paused = true;\n try {\n await this.restoreState(this.expandState(target));\n if (currentIsCommitted) this.undoStack.pop();\n this.redoStack.push(current);\n this.trimToBudget();\n } catch (error) {\n this.events.emit('error', { message: 'Failed to undo the last change', error });\n throw error;\n } finally {\n this.paused = false;\n this.emitChanged();\n }\n }\n\n async redo(): Promise<void> {\n this.cancelPending();\n const state = this.redoStack.at(-1);\n if (!state) return;\n\n this.paused = true;\n try {\n await this.restoreState(this.expandState(state));\n this.redoStack.pop();\n if (this.undoStack.at(-1) !== state) this.undoStack.push(state);\n this.trimToBudget();\n } catch (error) {\n this.events.emit('error', { message: 'Failed to redo the last change', error });\n throw error;\n } finally {\n this.paused = false;\n this.emitChanged();\n }\n }\n\n /** True while a restore (undo/redo/deserialize) is in flight. Managers that\n * react to canvas events should skip mutating history during this window. */\n isRestoring(): boolean {\n return this.paused;\n }\n\n pause(): void {\n this.paused = true;\n }\n\n resume(): void {\n this.paused = false;\n }\n\n canUndo(): boolean {\n return this.undoStack.length > 1 || this.debounceTimer !== null;\n }\n\n canRedo(): boolean {\n return this.redoStack.length > 0;\n }\n\n clear(): void {\n // Drop any debounced save too, otherwise its timer fires after the clear\n // and pushes a snapshot into what the caller believes is empty history.\n this.cancelPending();\n this.undoStack = [];\n this.redoStack = [];\n this.assets.clear();\n this.assetIds.clear();\n this.emitChanged();\n }\n\n getSnapshotBytes(): number {\n return this.snapshotBytes();\n }\n\n private cancelPending(): void {\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n this.debounceTimer = null;\n }\n }\n\n dispose(): void {\n this.cancelPending();\n this.transactionDepth = 0;\n this.transactionDirty = false;\n this.undoStack = [];\n this.redoStack = [];\n this.assets.clear();\n this.assetIds.clear();\n }\n\n private emitChanged(): void {\n this.events.emit('history:changed', {\n canUndo: this.canUndo(),\n canRedo: this.canRedo(),\n });\n }\n\n private snapshotBytes(): number {\n const stackBytes = [...this.undoStack, ...this.redoStack].reduce(\n (total, state) => total + state.length * 2,\n 0,\n );\n const assetBytes = [...this.assets.values()].reduce(\n (total, asset) => total + asset.length * 2,\n 0,\n );\n return stackBytes + assetBytes;\n }\n\n private trimToBudget(): void {\n // Prune first: entries dropped by the size cap, and every state discarded\n // with the redo stack, orphan their rasters. Without this the orphans stay\n // resident and inflate snapshotBytes until they evict live undo entries.\n this.pruneAssets();\n while (this.undoStack.length > 1 && this.snapshotBytes() > this.maxBytes) {\n this.undoStack.shift();\n this.pruneAssets();\n }\n while (this.redoStack.length > 1 && this.snapshotBytes() > this.maxBytes) {\n this.redoStack.shift();\n this.pruneAssets();\n }\n }\n\n /**\n * History is internal and can content-address large raster strings without\n * changing the public EditorState wire format. Unchanged images are retained\n * once even when dozens of snapshots reference them.\n */\n private compactState(state: string): string {\n let parsed: unknown;\n try {\n parsed = JSON.parse(state);\n } catch {\n return state;\n }\n const visit = (value: unknown): unknown => {\n if (typeof value === 'string' && /^data:image\\/(?:png|jpeg|webp);base64,/i.test(value)) {\n let id = this.assetIds.get(value);\n if (!id) {\n id = `a${this.nextAssetId++}`;\n this.assetIds.set(value, id);\n this.assets.set(id, value);\n }\n return { [HistoryManager.ASSET_KEY]: id };\n }\n if (Array.isArray(value)) return value.map(visit);\n if (!value || typeof value !== 'object') return value;\n return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, visit(entry)]));\n };\n return JSON.stringify(visit(parsed));\n }\n\n private expandState(state: string): string {\n let parsed: unknown;\n try {\n parsed = JSON.parse(state);\n } catch {\n return state;\n }\n const visit = (value: unknown): unknown => {\n if (Array.isArray(value)) return value.map(visit);\n if (!value || typeof value !== 'object') return value;\n const record = value as Record<string, unknown>;\n const id = record[HistoryManager.ASSET_KEY];\n if (typeof id === 'string' && Object.keys(record).length === 1) {\n const asset = this.assets.get(id);\n if (!asset) throw new Error(`Missing history raster asset: ${id}`);\n return asset;\n }\n return Object.fromEntries(Object.entries(record).map(([key, entry]) => [key, visit(entry)]));\n };\n return JSON.stringify(visit(parsed));\n }\n\n /**\n * Runs on every commit, so it scans for the serialized reference marker\n * instead of re-parsing every snapshot — parsing multi-megabyte raster states\n * per save would cost more than the retention it reclaims. `JSON.stringify`\n * emits the marker verbatim; the same text inside user data is escaped and\n * therefore cannot match.\n */\n private pruneAssets(): void {\n if (this.assets.size === 0) return;\n const states = [...this.undoStack, ...this.redoStack];\n for (const [id, asset] of this.assets) {\n const marker = `\"${HistoryManager.ASSET_KEY}\":\"${id}\"`;\n if (states.some((state) => state.includes(marker))) continue;\n this.assets.delete(id);\n this.assetIds.delete(asset);\n }\n }\n}\n","import type { Canvas, FabricObject, TPointerEvent } from 'fabric';\nimport type { EventEmitter } from './events';\nimport type { EditorEvents } from './types';\n\ninterface SnapGuide {\n /** Vertical guide at this x (canvas px), or undefined for a horizontal one. */\n x?: number;\n y?: number;\n}\n\nconst STROKE = '#22c55e';\n\n/**\n * Snaps a dragged object's edges and centre to the canvas edges/centre and to\n * other objects, drawing transient guide lines while it does. Switchable via\n * {@link setEnabled}; inert (zero overhead beyond a flag check) when disabled.\n */\nexport class SnapManager {\n private enabled = false;\n private threshold = 8;\n private guides: SnapGuide[] = [];\n\n private readonly onMoving: (e: { target?: FabricObject; e: TPointerEvent }) => void;\n private readonly onAfterRender: () => void;\n private readonly onModified: () => void;\n\n constructor(\n private canvas: Canvas,\n private events: EventEmitter<EditorEvents>,\n ) {\n this.onMoving = (e) => this.handleMoving(e.target);\n this.onAfterRender = () => this.drawGuides();\n this.onModified = () => this.clearGuides();\n\n this.canvas.on('object:moving', this.onMoving);\n this.canvas.on('after:render', this.onAfterRender);\n this.canvas.on('mouse:up', this.onModified);\n this.canvas.on('selection:cleared', this.onModified);\n }\n\n setEnabled(enabled: boolean): void {\n if (this.enabled === enabled) return;\n this.enabled = enabled;\n if (!enabled) this.clearGuides();\n this.events.emit('snap:changed', { enabled });\n }\n\n isEnabled(): boolean {\n return this.enabled;\n }\n\n setThreshold(px: number): void {\n this.threshold = Math.max(0, px);\n }\n\n dispose(): void {\n this.canvas.off('object:moving', this.onMoving);\n this.canvas.off('after:render', this.onAfterRender);\n this.canvas.off('mouse:up', this.onModified);\n this.canvas.off('selection:cleared', this.onModified);\n this.guides = [];\n }\n\n private handleMoving(target?: FabricObject): void {\n if (!this.enabled || !target) return;\n\n target.setCoords();\n const r = target.getBoundingRect();\n const cw = this.canvas.getWidth();\n const ch = this.canvas.getHeight();\n\n // Candidate lines for both axes, collected in a single pass over the objects.\n const { xs, ys } = collectCandidates(this.canvas, target, cw, ch);\n\n this.guides = [];\n\n const dx = bestSnap([r.left, r.left + r.width / 2, r.left + r.width], xs, this.threshold);\n if (dx !== null) {\n target.set('left', (target.left ?? 0) + dx.delta);\n this.guides.push({ x: dx.line });\n }\n\n const dy = bestSnap([r.top, r.top + r.height / 2, r.top + r.height], ys, this.threshold);\n if (dy !== null) {\n target.set('top', (target.top ?? 0) + dy.delta);\n this.guides.push({ y: dy.line });\n }\n\n target.setCoords();\n }\n\n private drawGuides(): void {\n if (!this.enabled || this.guides.length === 0) return;\n const ctx = this.canvas.contextTop;\n if (!ctx) return;\n\n const retina = this.canvas.getRetinaScaling();\n const cw = this.canvas.getWidth();\n const ch = this.canvas.getHeight();\n\n ctx.save();\n ctx.setTransform(retina, 0, 0, retina, 0, 0);\n ctx.lineWidth = 1;\n ctx.strokeStyle = STROKE;\n ctx.setLineDash([4, 4]);\n ctx.beginPath();\n for (const g of this.guides) {\n if (g.x !== undefined) {\n ctx.moveTo(g.x, 0);\n ctx.lineTo(g.x, ch);\n }\n if (g.y !== undefined) {\n ctx.moveTo(0, g.y);\n ctx.lineTo(cw, g.y);\n }\n }\n ctx.stroke();\n ctx.restore();\n }\n\n private clearGuides(): void {\n if (this.guides.length === 0) return;\n this.guides = [];\n this.canvas.clearContext(this.canvas.contextTop);\n }\n}\n\n/**\n * Snap candidate lines (edges + centre) for the canvas and every other object,\n * for both axes, computed in one pass so each object's bounds are read once.\n */\nfunction collectCandidates(\n canvas: Canvas,\n moving: FabricObject,\n cw: number,\n ch: number,\n): { xs: number[]; ys: number[] } {\n const xs = [0, cw / 2, cw];\n const ys = [0, ch / 2, ch];\n for (const obj of canvas.getObjects()) {\n if (obj === moving || !obj.visible) continue;\n obj.setCoords();\n const r = obj.getBoundingRect();\n xs.push(r.left, r.left + r.width / 2, r.left + r.width);\n ys.push(r.top, r.top + r.height / 2, r.top + r.height);\n }\n return { xs, ys };\n}\n\n/**\n * Find the closest (edge, candidate) pair within threshold. Returns the delta\n * to apply and the guide line to draw, or null if nothing is close enough.\n */\nfunction bestSnap(\n edges: number[],\n candidates: number[],\n threshold: number,\n): { delta: number; line: number } | null {\n let best: { delta: number; line: number; dist: number } | null = null;\n for (const edge of edges) {\n for (const c of candidates) {\n const dist = Math.abs(edge - c);\n if (dist <= threshold && (best === null || dist < best.dist)) {\n best = { delta: c - edge, line: c, dist };\n }\n }\n }\n return best ? { delta: best.delta, line: best.line } : null;\n}\n\nexport { bestSnap as _bestSnap };\n","import { Rect } from 'fabric';\nimport type { Canvas, FabricImage } from 'fabric';\nimport type { Layer } from './layer';\nimport type { HistoryManager } from './history';\nimport type { EventEmitter } from './events';\nimport type { EditorEvents } from './types';\nimport { clamp } from './utils/clamp';\n\ninterface CropSession {\n layerId: string;\n image: FabricImage;\n rect: Rect;\n prevSelectable: boolean;\n prevEvented: boolean;\n /** Angle before crop normalised it to 0; restored if the crop is cancelled. */\n prevAngle: number;\n}\n\n/**\n * Interactive crop for image layers. {@link start} drops a draggable/resizable\n * rectangle over the image; {@link apply} converts it into fabric crop props\n * (cropX/cropY/width/height in element pixels) and keeps the displayed size in\n * sync with the rectangle.\n *\n * Rotation is unsupported: an angled image is normalised to 0° on start.\n */\nexport class CropController {\n private session: CropSession | null = null;\n private readonly onSelectionCleared: () => void;\n\n constructor(\n private canvas: Canvas,\n private history: HistoryManager,\n private events: EventEmitter<EditorEvents>,\n ) {\n this.onSelectionCleared = () => {\n // Clicking away from the crop rect abandons the crop.\n if (this.session) this.cancel();\n };\n this.canvas.on('selection:cleared', this.onSelectionCleared);\n }\n\n isActive(): boolean {\n return this.session !== null;\n }\n\n activeLayerId(): string | null {\n return this.session?.layerId ?? null;\n }\n\n start(layer: Layer): void {\n if (layer.type !== 'image') return;\n if (this.session) this.cancel();\n\n const image = layer.fabricObject as FabricImage;\n const prevAngle = image.angle ?? 0;\n if (prevAngle) image.rotate(0);\n image.setCoords();\n const b = image.getBoundingRect();\n\n const rect = new Rect({\n left: b.left,\n top: b.top,\n width: b.width,\n height: b.height,\n originX: 'left',\n originY: 'top',\n fill: 'rgba(34,197,94,0.12)',\n stroke: STROKE,\n strokeWidth: 1,\n strokeDashArray: [4, 4],\n strokeUniform: true,\n lockRotation: true,\n cornerColor: STROKE,\n transparentCorners: false,\n });\n rect.setControlsVisibility({ mtr: false });\n\n const prevSelectable = image.selectable ?? true;\n const prevEvented = image.evented ?? true;\n image.selectable = false;\n image.evented = false;\n\n this.canvas.add(rect);\n this.canvas.setActiveObject(rect);\n this.canvas.requestRenderAll();\n\n this.session = { layerId: layer.id, image, rect, prevSelectable, prevEvented, prevAngle };\n this.events.emit('crop:changed', { active: true, layerId: layer.id });\n }\n\n apply(): void {\n const s = this.session;\n if (!s) return;\n const { image, rect } = s;\n\n rect.setCoords();\n image.setCoords();\n const scaleX = image.scaleX ?? 1;\n const scaleY = image.scaleY ?? 1;\n const imgLeft = image.left ?? 0;\n const imgTop = image.top ?? 0;\n\n const el = image.getElement() as HTMLImageElement;\n const naturalW = el.naturalWidth || image.width || 0;\n const naturalH = el.naturalHeight || image.height || 0;\n\n // Map the rect (canvas px) into the image's element-pixel space.\n let cropX = (image.cropX ?? 0) + (rect.left! - imgLeft) / scaleX;\n let cropY = (image.cropY ?? 0) + (rect.top! - imgTop) / scaleY;\n let cropW = rect.getScaledWidth() / scaleX;\n let cropH = rect.getScaledHeight() / scaleY;\n\n // Keep the crop window inside the source element.\n cropX = clamp(cropX, 0, Math.max(0, naturalW - 1));\n cropY = clamp(cropY, 0, Math.max(0, naturalH - 1));\n cropW = clamp(cropW, 1, naturalW - cropX);\n cropH = clamp(cropH, 1, naturalH - cropY);\n\n image.set({\n cropX,\n cropY,\n width: cropW,\n height: cropH,\n // Anchor the displayed result where the rect sits.\n left: imgLeft + (cropX - (image.cropX ?? 0)) * scaleX,\n top: imgTop + (cropY - (image.cropY ?? 0)) * scaleY,\n });\n image.setCoords();\n\n // Cropping is calculated in the normalized frame, then the original\n // orientation is restored so applying a crop never silently un-rotates it.\n if (s.prevAngle) {\n image.rotate(s.prevAngle);\n image.setCoords();\n }\n\n this.finish();\n this.history.save();\n }\n\n cancel(): void {\n const s = this.session;\n if (!s) return;\n // Cancelling discards the crop, so restore the rotation start() zeroed out.\n if (s.prevAngle) {\n s.image.rotate(s.prevAngle);\n s.image.setCoords();\n }\n this.finish();\n }\n\n dispose(): void {\n this.cancel();\n this.canvas.off('selection:cleared', this.onSelectionCleared);\n }\n\n private finish(): void {\n const s = this.session;\n if (!s) return;\n // Null the session first so the selection:cleared fired by removing the\n // rect / re-selecting does not re-enter cancel().\n this.session = null;\n\n this.canvas.remove(s.rect);\n s.image.selectable = s.prevSelectable;\n s.image.evented = s.prevEvented;\n this.canvas.setActiveObject(s.image);\n this.canvas.requestRenderAll();\n\n this.events.emit('crop:changed', { active: false, layerId: null });\n }\n}\n\nconst STROKE = '#22c55e';\n","export function clamp(v: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, v));\n}\n\nexport function round2(v: number): number {\n return Math.round(v * 100) / 100;\n}\n","import { util } from 'fabric';\nimport type { Canvas, FabricImage, FabricObject } from 'fabric';\nimport type { Layer, LayerManager } from '../layer';\nimport type { HistoryManager } from '../history';\nimport type { EditorEvents, PatternConfig, PatternLocks, PatternState } from '../types';\nimport type { EventEmitter } from '../events';\nimport { TiledPatternObject } from './tiled-pattern-object';\nimport type { PatternArea } from './tiled-pattern-object';\n\n/** Tile-scale bounds, matching the panel slider. */\nconst MIN_TILE_SCALE = 10;\nconst MAX_TILE_SCALE = 300;\n\n/**\n * Repeats a layer's own object across the print area.\n *\n * The layer keeps its real fabric object as the tile *source*: it stays in the\n * document, stays selectable and stays editable, and is simply parked at\n * `opacity: 0` while a {@link TiledPatternObject} render proxy draws the tiling\n * over the print area. Nothing is baked into the layer, so a source edit (text,\n * font, colour, drag, scale) shows up on the very next render, and the saved\n * state stores a `Textbox` rather than a screenshot of one.\n */\nexport class PatternManager {\n private proxies = new Map<string, TiledPatternObject>();\n private readonly onObjectModified = (event: { target?: FabricObject }) => {\n const target = event.target;\n if (target instanceof TiledPatternObject) this.commitGesture(target);\n else this.invalidateFor(target);\n };\n private readonly onSourceModified = (event: { target?: FabricObject }) => {\n this.invalidateFor(event.target);\n };\n private readonly onLayerRemoved = ({ layerId }: { layerId: string }) => {\n // LayerManager already took the proxy off the canvas; drop our reference and\n // its offscreen snapshot too, or a long session leaks one canvas per delete.\n const proxy = this.proxies.get(layerId);\n if (!proxy) return;\n proxy.dispose();\n this.proxies.delete(layerId);\n };\n\n constructor(\n private canvas: Canvas,\n private layers: LayerManager,\n private history: HistoryManager,\n private events: EventEmitter<EditorEvents>,\n ) {\n // A source edit only invalidates the cached snapshot. A gesture on the proxy\n // is a pattern edit: fabric renders it live off the proxy's own transform,\n // and the drop folds that transform back into the config.\n this.canvas.on('object:modified', this.onObjectModified);\n this.canvas.on('text:changed', this.onSourceModified);\n this.events.on('layer:removed', this.onLayerRemoved);\n }\n\n isPattern(layerId: string): boolean {\n return !!this.layers.get(layerId)?.meta.pattern;\n }\n\n getConfig(layerId: string): PatternConfig | null {\n return this.layers.get(layerId)?.meta.pattern?.config ?? null;\n }\n\n /** Turn a layer into a repeating pattern, or update an existing one. */\n async apply(layerId: string, config: PatternConfig): Promise<void> {\n const layer = this.layers.get(layerId);\n if (!layer) return;\n try {\n this.layers.setMeta(layerId, { pattern: { config } });\n const proxy = this.proxies.get(layerId);\n if (proxy) {\n proxy.setConfig(config);\n this.canvas.requestRenderAll();\n } else {\n this.attach(layer, config);\n }\n this.history.save();\n } catch (error) {\n this.events.emit('error', { message: 'Failed to apply pattern', error });\n throw error;\n }\n }\n\n /** Drop the tiling and show the source again. */\n async disable(layerId: string): Promise<void> {\n const layer = this.layers.get(layerId);\n if (!layer?.meta.pattern) return;\n try {\n this.detach(layerId);\n // Legacy states froze the source's handles while it was baked; hand them\n // back rather than leaving the layer un-draggable forever.\n restoreLocks(layer.fabricObject, layer.meta.pattern.originalLocks);\n // Hand interaction back to the layer's own object.\n layer.fabricObject.set({\n opacity: layer.opacity,\n selectable: !layer.locked,\n evented: !layer.locked,\n });\n this.layers.setMeta(layerId, { pattern: undefined });\n this.canvas.requestRenderAll();\n this.history.save();\n } catch (error) {\n this.events.emit('error', { message: 'Failed to clear pattern', error });\n throw error;\n }\n }\n\n /**\n * Rebuild every proxy after a state restore, migrating any layer that was\n * saved by the old bake-into-the-layer engine.\n */\n async rehydrateAll(): Promise<void> {\n // Every restore (including each undo step) replaces the whole layer set, so\n // the proxies from the previous one are dead the moment we are called.\n this.clearProxies();\n for (const layer of this.layers.getAll()) {\n const state = layer.meta.pattern;\n if (!state) continue;\n try {\n if (isLegacyState(state)) {\n await unbakeLegacyLayer(layer, state);\n // The bake is gone for good; drop the fields that described it so the\n // next save writes a clean, source-native state.\n this.layers.setMeta(layer.id, { pattern: { config: state.config } });\n }\n this.attach(layer, state.config);\n } catch (error) {\n this.events.emit('error', { message: 'Failed to restore pattern layer', error });\n }\n }\n this.canvas.requestRenderAll();\n }\n\n /** Re-fit every proxy to the print area (canvas resize). */\n syncArea(): void {\n const area = this.area();\n for (const proxy of this.proxies.values()) proxy.setArea(area);\n if (this.proxies.size > 0) this.canvas.requestRenderAll();\n }\n\n /** Drop a layer's cached source snapshot (its content changed). */\n invalidate(layerId: string): void {\n const proxy = this.proxies.get(layerId);\n if (!proxy) return;\n proxy.invalidate();\n // The source's own size is the tile's size, so an edit re-fits the box.\n proxy.syncBox();\n this.canvas.requestRenderAll();\n }\n\n /** Give a freshly cloned layer its own proxy (duplicating a pattern layer). */\n attachTo(layer: Layer): void {\n const state = layer.meta.pattern;\n if (!state || this.proxies.has(layer.id)) return;\n this.attach(layer, state.config);\n }\n\n dispose(): void {\n this.canvas.off('object:modified', this.onObjectModified);\n this.canvas.off('text:changed', this.onSourceModified);\n this.events.off('layer:removed', this.onLayerRemoved);\n this.clearProxies();\n }\n\n /** Release every proxy and the offscreen snapshot it holds. */\n private clearProxies(): void {\n for (const proxy of this.proxies.values()) proxy.dispose();\n this.proxies.clear();\n }\n\n private attach(layer: Layer, config: PatternConfig): void {\n const proxy = new TiledPatternObject(layer.fabricObject, config, this.area());\n // The source stays in the document (it is still the layer's object, still\n // what panels edit and what gets serialized) but hands over interaction: the\n // proxy's box IS the anchor tile, so the frame the user grabs sits on\n // artwork they can see. Two hit targets for one layer would fight.\n const wasActive = this.canvas.getActiveObject() === layer.fabricObject;\n layer.fabricObject.set({ opacity: 0, selectable: false, evented: false });\n this.proxies.set(layer.id, proxy);\n this.layers.setRenderProxy(layer.id, proxy);\n // Turning tiling on with the layer selected must hand the frame over too,\n // or the handles stay on the object that just went invisible and inert.\n if (wasActive) this.canvas.setActiveObject(proxy);\n this.canvas.requestRenderAll();\n }\n\n /**\n * Fold a finished drag / scale / rotate on the proxy back into the pattern:\n * position becomes the grid origin (carried by the source), scale becomes the\n * tile scale, rotation becomes the pattern angle. Read the live transform\n * first — writing the config re-fits the box and destroys it.\n */\n private commitGesture(proxy: TiledPatternObject): void {\n const layer = this.layers.findByObject(proxy);\n const state = layer?.meta.pattern;\n if (!layer || !state) return;\n\n const origin = proxy.liveOrigin();\n const scale = clamp(proxy.liveScale(), MIN_TILE_SCALE, MAX_TILE_SCALE);\n const angle = normalizeAngle(proxy.liveAngle());\n\n layer.fabricObject.setPositionByOrigin(origin, 'center', 'center');\n layer.fabricObject.setCoords();\n\n const config: PatternConfig = { ...state.config, scale, angle };\n this.layers.setMeta(layer.id, { pattern: { ...state, config } });\n proxy.setConfig(config);\n this.canvas.requestRenderAll();\n this.history.save();\n }\n\n private area(): PatternArea {\n return { width: this.canvas.getWidth(), height: this.canvas.getHeight() };\n }\n\n private detach(layerId: string): void {\n const proxy = this.proxies.get(layerId);\n if (!proxy) {\n this.layers.setRenderProxy(layerId, null);\n return;\n }\n this.layers.setRenderProxy(layerId, null);\n proxy.dispose();\n this.proxies.delete(layerId);\n }\n\n private invalidateFor(target: FabricObject | undefined): void {\n if (!target) return;\n const layer = this.layers.findByObject(target);\n if (layer) this.invalidate(layer.id);\n }\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n if (!Number.isFinite(value)) return min;\n return Math.max(min, Math.min(max, value));\n}\n\n/** Fold an angle into (−180, 180], the range the pattern panel offers. */\nfunction normalizeAngle(angle: number): number {\n if (!Number.isFinite(angle)) return 0;\n const wrapped = ((angle % 360) + 360) % 360;\n return Math.round(wrapped > 180 ? wrapped - 360 : wrapped);\n}\n\n/** A state written by the pre-proxy engine, which baked the tiling into the layer. */\nfunction isLegacyState(state: PatternState): boolean {\n return typeof state.originalSrc === 'string' && state.originalSrc.length > 0;\n}\n\n/**\n * Put a legacy pattern layer back the way it was before it was baked: the\n * layer's object currently holds the *tiled bitmap*, and the real artwork is\n * parked in `meta.pattern.originalSrc`.\n *\n * `left`/`top` are restored raw, exactly as they were captured — the object's\n * origin never changed, so re-deriving a position here would move it.\n */\nasync function unbakeLegacyLayer(layer: Layer, state: PatternState): Promise<void> {\n const image = layer.fabricObject as FabricImage;\n if (typeof image.setSrc !== 'function' || !state.original) return;\n\n await image.setSrc(state.originalSrc as string);\n // setSrc resets width/height to the full element size, so the captured crop\n // window has to go back on too.\n image.set({\n left: state.original.left,\n top: state.original.top,\n scaleX: state.original.scaleX,\n scaleY: state.original.scaleY,\n width: state.original.width,\n height: state.original.height,\n cropX: state.original.cropX,\n cropY: state.original.cropY,\n angle: state.original.angle,\n });\n image.clipPath = state.originalClip\n ? ((await util.enlivenObjects([state.originalClip]))[0] as FabricObject)\n : undefined;\n restoreLocks(image, state.originalLocks);\n image.setCoords();\n}\n\n/**\n * Restore pre-pattern interaction flags. Only legacy states carry a snapshot —\n * the live-source engine never freezes anything — so a missing snapshot means\n * \"fully interactive\", not \"leave it frozen\".\n */\nexport function restoreLocks(obj: FabricObject, locks: PatternLocks | undefined): void {\n obj.set(\n locks ?? {\n lockMovementX: false,\n lockMovementY: false,\n lockScalingX: false,\n lockScalingY: false,\n lockRotation: false,\n hasControls: true,\n },\n );\n}\n","import { FabricObject, Point } from 'fabric';\nimport type { PatternConfig } from '../types';\nimport { drawTiles } from './tile-geometry';\nimport type { PatternOrigin, TileDrawSize } from './tile-geometry';\n\n/**\n * Hard ceiling on the source snapshot, in pixels. A huge source tiled at a huge\n * export multiplier would otherwise allocate an unbounded offscreen canvas.\n */\nconst MAX_SNAPSHOT_PIXELS = 16_000_000;\n/** Ceiling on the snapshot's linear scale, independent of the pixel budget. */\nconst MAX_SNAPSHOT_SCALE = 8;\n/** Rebuild a snapshot this many times too big for what is being drawn. */\nconst SNAPSHOT_SHRINK_FACTOR = 2;\n/**\n * Overlap between neighbouring tiles, in device pixels of whatever is being\n * drawn to (screen or export raster).\n *\n * Tiles abut on fractional pixel boundaries, so each edge is antialiased: two\n * touching tiles leave the shared pixel at ~80% alpha, which reads as a hairline\n * grid over the artwork. Each edge's ramp covers about a pixel, so a pixel of\n * bleed per side is what actually closes it — half a pixel only lifts the seam to\n * ~93%. It scales the tile art by well under a percent, so nothing visibly grows.\n */\nconst TILE_BLEED_DEVICE_PX = 2;\n\nexport interface PatternArea {\n width: number;\n height: number;\n}\n\n/**\n * Renders a layer's source object repeated across the print area.\n *\n * This is a *render proxy*, not a layer: it is attached to the layer that owns\n * the source (see `LayerManager.setRenderProxy`) and never serialized. The\n * document keeps the real object — a `Textbox` stays a `Textbox` — so tiling is\n * non-destructive and every source edit shows up on the next render.\n *\n * **Its box is one tile, its drawing is the whole area.** The object's own\n * width/height/angle/position track the tile drawn at the grid origin (the\n * \"anchor\" tile), so the selection frame the user grabs sits exactly on a tile\n * they can see, while `_render` paints the full print area outside those bounds.\n * That also makes the transform handles meaningful: dragging moves the grid,\n * scaling is the tile scale, rotating is the pattern angle. The live transform\n * is the truth during a gesture; `PatternManager` folds it back into the config\n * when the gesture ends.\n */\nexport class TiledPatternObject extends FabricObject {\n static type = 'TiledPattern';\n\n /** The layer's real object. Never rendered directly (it is kept at opacity 0). */\n source: FabricObject;\n config: PatternConfig;\n /** The print area this pattern fills, in canvas units. */\n area: PatternArea;\n\n private snapshotEl: HTMLCanvasElement | null = null;\n private snapshotScale = 0;\n\n constructor(source: FabricObject, config: PatternConfig, area: PatternArea) {\n super({\n // Centre origin: the box tracks a tile, and a tile is placed by its centre.\n originX: 'center',\n originY: 'center',\n objectCaching: false,\n // Side handles would imply a non-uniform tile scale; the config has one.\n lockScalingFlip: true,\n });\n this.source = source;\n this.config = config;\n this.area = area;\n this.setControlsVisibility({ ml: false, mr: false, mt: false, mb: false });\n this.syncBox();\n }\n\n /** Swap in a new config and re-fit the box to the tile it now describes. */\n setConfig(config: PatternConfig): void {\n this.config = config;\n this.syncBox();\n }\n\n /** Re-fit to a new print area (canvas resize). */\n setArea(area: PatternArea): void {\n this.area = area;\n this.invalidate();\n this.syncBox();\n }\n\n /** Drop the cached source snapshot (the source was edited). */\n invalidate(): void {\n this.snapshotEl = null;\n this.snapshotScale = 0;\n this.dirty = true;\n }\n\n /** Free the offscreen snapshot. */\n dispose(): void {\n this.snapshotEl = null;\n this.snapshotScale = 0;\n }\n\n /**\n * Put the box back on the anchor tile: the tile's size, the pattern angle, and\n * the grid origin displaced by the configured phase shift. Resets any live\n * gesture scale, so it must run only once that gesture has been folded in.\n */\n syncBox(): void {\n const { tileW, tileH } = this.baseTile();\n const origin = this.source.getCenterPoint();\n const anchor = this.anchorFromOrigin(origin, tileW, tileH, this.config.angle);\n this.set({\n left: anchor.x,\n top: anchor.y,\n width: tileW,\n height: tileH,\n scaleX: 1,\n scaleY: 1,\n angle: this.config.angle,\n });\n this.setCoords();\n this.dirty = true;\n }\n\n /** Grid rotation in play right now — the live handle during a rotate gesture. */\n liveAngle(): number {\n return this.angle ?? 0;\n }\n\n /** Tile scale in play right now, as a config percentage. */\n liveScale(): number {\n return (this.config.scale ?? 100) * Math.abs(this.scaleX ?? 1);\n }\n\n /**\n * Where the source's centre would have to sit for the box to stay put — i.e.\n * the grid origin implied by a drag. `PatternManager` moves the source there.\n */\n liveOrigin(): Point {\n const { tileW, tileH } = this.liveTile();\n const centre = this.getCenterPoint();\n const shift = this.shiftVector(tileW, tileH, this.liveAngle());\n return new Point(centre.x - shift.x, centre.y - shift.y);\n }\n\n _render(ctx: CanvasRenderingContext2D): void {\n const { width, height } = this.area;\n if (width <= 0 || height <= 0) return;\n\n const { tileW, tileH } = this.liveTile();\n const scale = contextScale(ctx);\n const snapshot = this.ensureSnapshot(scale * (tileW / Math.max(1, this.baseW())));\n if (!snapshot) return;\n\n const centre = this.getCenterPoint();\n const angle = this.liveAngle();\n ctx.save();\n // Undo this object's own transform: the tile grid is laid out in canvas\n // coordinates, and the box only describes where one tile sits.\n ctx.scale(1 / (this.scaleX || 1), 1 / (this.scaleY || 1));\n ctx.rotate((-angle * Math.PI) / 180);\n ctx.translate(-centre.x, -centre.y);\n\n const shift = this.shiftVector(tileW, tileH, angle);\n const origin: PatternOrigin = { x: centre.x - shift.x, y: centre.y - shift.y };\n // The phase shift is already baked into the anchor position, so the grid is\n // drawn unshifted around that origin.\n const config = { ...this.config, angle, offsetX: 0, offsetY: 0 };\n drawTiles(\n ctx,\n snapshot,\n config,\n width,\n height,\n tileW,\n tileH,\n origin,\n this.drawSize(tileW, tileH, TILE_BLEED_DEVICE_PX / scale),\n );\n ctx.restore();\n }\n\n /** Raster fallback for SVG export — one `<image>` covering the print area. */\n _toSVG(): string[] {\n const { width, height } = this.area;\n if (width <= 0 || height <= 0) return [];\n const el = document.createElement('canvas');\n el.width = Math.max(1, Math.round(width));\n el.height = Math.max(1, Math.round(height));\n const ctx = el.getContext('2d');\n if (!ctx) return [];\n\n const { tileW, tileH } = this.liveTile();\n const snapshot = this.ensureSnapshot(tileW / Math.max(1, this.baseW()));\n if (!snapshot) return [];\n const centre = this.getCenterPoint();\n const angle = this.liveAngle();\n const shift = this.shiftVector(tileW, tileH, angle);\n drawTiles(\n ctx,\n snapshot,\n { ...this.config, angle, offsetX: 0, offsetY: 0 },\n width,\n height,\n tileW,\n tileH,\n { x: centre.x - shift.x, y: centre.y - shift.y },\n // The fallback raster is built at 1:1, so a device pixel is a canvas unit.\n this.drawSize(tileW, tileH, TILE_BLEED_DEVICE_PX),\n );\n\n // Emitted inside the object's own transform, which the raster is not in.\n return [\n `<g transform=\"rotate(${-angle}) translate(${-centre.x} ${-centre.y})\">`,\n `<image x=\"0\" y=\"0\" width=\"${width}\" height=\"${height}\" `,\n `xlink:href=\"${el.toDataURL('image/png')}\"></image></g>\\n`,\n ];\n }\n\n /**\n * The proxy holds a live reference to its source, which would make a\n * serialized canvas circular. Nothing persists this object (only layers are\n * serialized) — this keeps an accidental `canvas.toObject()` from throwing.\n */\n toObject(): Record<string, unknown> {\n const plain = super.toObject() as Record<string, unknown>;\n delete plain.source;\n return plain;\n }\n\n /**\n * Fabric's generic clone round-trips through `toObject()` + the class\n * registry, which cannot carry a live source reference. Export paths clone\n * every canvas object, so without this a print export would silently lose the\n * tiling. The copy shares the source (it only ever reads from it).\n */\n clone(): Promise<this> {\n const copy = new TiledPatternObject(this.source, this.config, this.area);\n copy.set({\n left: this.left,\n top: this.top,\n angle: this.angle,\n scaleX: this.scaleX,\n scaleY: this.scaleY,\n width: this.width,\n height: this.height,\n visible: this.visible,\n opacity: this.opacity,\n });\n return Promise.resolve(copy as this);\n }\n\n /**\n * The source's tile footprint: its bounding box, minus a stroke it reserves\n * room for but never paints.\n *\n * fabric keeps `strokeWidth` inside an object's box whether or not a `stroke`\n * colour paints it, and the built-in shapes arrive with `strokeWidth: 1` and no\n * stroke. Stepping the grid by that box puts a transparent seam between every\n * pair of neighbours at zero spacing: the artwork is a pixel narrower than the\n * box it is stepped by.\n */\n private sourceBox(): { width: number; height: number } {\n const rect = this.source.getBoundingRect();\n if (paintsStroke(this.source)) return { width: rect.width, height: rect.height };\n // The bounding box is the transformed dimensions rotated into an AABB, so\n // re-derive it from dimensions measured without the stroke reserve.\n const dims = this.source._getTransformedDimensions({ strokeWidth: 0 });\n const radians = ((this.source.angle ?? 0) * Math.PI) / 180;\n const cos = Math.abs(Math.cos(radians));\n const sin = Math.abs(Math.sin(radians));\n return {\n width: dims.x * cos + dims.y * sin,\n height: dims.x * sin + dims.y * cos,\n };\n }\n\n /** The source's on-canvas width, before the tile scale. */\n private baseW(): number {\n return Math.max(1, this.sourceBox().width);\n }\n\n /** The source's on-canvas height, before the tile scale. */\n private baseH(): number {\n return Math.max(1, this.sourceBox().height);\n }\n\n /**\n * Size to paint the snapshot at, for a tile of `tileW × tileH`.\n *\n * The snapshot is NOT exactly the source's box: `toCanvasElement` rounds the\n * raster up to whole pixels and pads it further for a shadow. Painting it into\n * the tile step would squeeze the artwork inside that padding — every tile\n * shrinks by up to a pixel and the grid shows transparent seams at zero\n * spacing. So the bitmap is painted at its own footprint, scaled by the same\n * factor the tile is, and the step stays the source's box.\n */\n private drawSize(tileW: number, tileH: number, bleed = 0): TileDrawSize {\n const snapshot = this.snapshotEl;\n if (!snapshot || this.snapshotScale <= 0) {\n return { width: tileW + bleed, height: tileH + bleed };\n }\n return {\n width: (snapshot.width / this.snapshotScale) * (tileW / this.baseW()) + bleed,\n height: (snapshot.height / this.snapshotScale) * (tileH / this.baseH()) + bleed,\n };\n }\n\n /** Tile size from the config alone, ignoring any in-flight gesture. */\n private baseTile(): { tileW: number; tileH: number } {\n const box = this.sourceBox();\n const scale = Math.max(1, this.config.scale ?? 100) / 100;\n const floor = this.tileFloor();\n return {\n tileW: Math.max(floor, box.width * scale),\n tileH: Math.max(floor, box.height * scale),\n };\n }\n\n /** Tile size as drawn right now, including a live scale gesture. */\n private liveTile(): { tileW: number; tileH: number } {\n const base = this.baseTile();\n const floor = this.tileFloor();\n return {\n tileW: Math.max(floor, base.tileW * Math.abs(this.scaleX ?? 1)),\n tileH: Math.max(floor, base.tileH * Math.abs(this.scaleY ?? 1)),\n };\n }\n\n /** Smallest tile the draw loop may use, so a tiny tile can't flood the area. */\n private tileFloor(): number {\n const { width, height } = this.area;\n return Math.max(2, Math.sqrt(width * width + height * height) / 200);\n }\n\n /** Phase shift (`offsetX`/`offsetY`) as a canvas-space vector. */\n private shiftVector(tileW: number, tileH: number, angle: number): Point {\n const dx = tileW * (clampPercent(this.config.offsetX) / 100);\n const dy = tileH * (clampPercent(this.config.offsetY) / 100);\n const radians = (angle * Math.PI) / 180;\n const cos = Math.cos(radians);\n const sin = Math.sin(radians);\n return new Point(dx * cos - dy * sin, dx * sin + dy * cos);\n }\n\n private anchorFromOrigin(origin: Point, tileW: number, tileH: number, angle: number): Point {\n const shift = this.shiftVector(tileW, tileH, angle);\n return new Point(origin.x + shift.x, origin.y + shift.y);\n }\n\n /**\n * Snapshot the source at (at least) `scale`, reusing the cached one while it\n * is still sharp enough and the source has not changed.\n */\n private ensureSnapshot(scale: number): HTMLCanvasElement | null {\n const wanted = this.clampScale(scale);\n const stale =\n this.source.dirty ||\n !this.snapshotEl ||\n this.snapshotScale < wanted ||\n this.snapshotScale > wanted * SNAPSHOT_SHRINK_FACTOR;\n if (!stale) return this.snapshotEl;\n\n // The source is parked at opacity 0 (invisible, still the layer's object);\n // fabric renders nothing at all for it, snapshot included.\n const source = this.source;\n const opacity = source.opacity;\n source.opacity = 1;\n try {\n const el = source.toCanvasElement({ multiplier: wanted, enableRetinaScaling: false });\n if (!el.width || !el.height) return null;\n this.snapshotEl = el;\n this.snapshotScale = wanted;\n } catch {\n // A tainted canvas (cross-origin image without CORS) throws here. Keep the\n // previous snapshot rather than dropping the pattern mid-render.\n return this.snapshotEl;\n } finally {\n source.opacity = opacity;\n // toCanvasElement restores the transform through `set()`, which re-dirties\n // the source; clear it last so the next render reuses this snapshot.\n source.dirty = false;\n }\n return this.snapshotEl;\n }\n\n /** Bound the snapshot by both a linear scale and a total pixel budget. */\n private clampScale(scale: number): number {\n const requested = Math.min(MAX_SNAPSHOT_SCALE, Math.max(0.05, scale));\n const rect = this.source.getBoundingRect();\n const area = Math.max(1, rect.width * rect.height);\n const budgeted = Math.sqrt(MAX_SNAPSHOT_PIXELS / area);\n return Math.max(0.05, Math.min(requested, budgeted));\n }\n}\n\n/** True when the object's stroke actually paints (so its box reserve is artwork). */\nfunction paintsStroke(object: FabricObject): boolean {\n if (!object.strokeWidth || object.strokeWidth <= 0) return false;\n const { stroke } = object;\n if (typeof stroke === 'string') return stroke !== '' && stroke !== 'transparent';\n // A gradient or pattern stroke is an object; only null/undefined paints nothing.\n return stroke !== null && stroke !== undefined;\n}\n\n/** Phase shift percentage, bounded to ±1 tile (0 if not set). */\nfunction clampPercent(value: number | undefined): number {\n if (typeof value !== 'number' || !Number.isFinite(value)) return 0;\n return Math.max(-100, Math.min(100, value));\n}\n\n/**\n * Linear scale of the current 2D transform — 2 on a retina screen, the export\n * multiplier during `toDataURL`. Falls back to 1 where `getTransform` is absent\n * (older node-canvas builds).\n */\nfunction contextScale(ctx: CanvasRenderingContext2D): number {\n if (typeof ctx.getTransform !== 'function') return 1;\n try {\n const t = ctx.getTransform();\n return Math.max(Math.hypot(t.a, t.b), Math.hypot(t.c, t.d), 0.05);\n } catch {\n return 1;\n }\n}\n","import type { PatternConfig } from '../types';\n\n/**\n * Upper bound on tiles per axis. Floors the effective tile size so an extreme\n * `scale` (or a tiny source) can't make the draw loop cover the coverage radius\n * with a runaway number of tiles.\n */\nexport const MAX_TILES_PER_AXIS = 200;\n\n/** Placement of one tile, relative to the (already rotated) pattern origin. */\nexport interface TilePlacement {\n /** Tile-centre offset from the pattern origin, in px. */\n x: number;\n y: number;\n /** Per-tile rotation, in radians. */\n rotation: number;\n}\n\n/** Where the tile grid is anchored inside the target, in target px. */\nexport interface PatternOrigin {\n x: number;\n y: number;\n}\n\n/**\n * Size the tile bitmap is painted at, when that differs from the grid step.\n *\n * A snapshot of the source is not always exactly the source's box: the raster is\n * allocated in whole pixels, and a shadow pads it further. Painting such a bitmap\n * into the step would shrink the artwork inside its own transparent margin and\n * open a hairline gap between neighbours at zero spacing.\n */\nexport interface TileDrawSize {\n width: number;\n height: number;\n}\n\n/**\n * Pure tile geometry: where each tile centre lands and how much it is rotated,\n * for a config + target/base size. Covers every corner of the target from the\n * grid origin, so no rotation or origin can uncover an edge. Extracted for unit\n * testing.\n *\n * `origin` defaults to the centre of the target.\n */\nexport function computeTilePositions(\n config: PatternConfig,\n targetW: number,\n targetH: number,\n baseW: number,\n baseH: number,\n origin?: PatternOrigin,\n): TilePlacement[] {\n const anchor = origin ?? { x: targetW / 2, y: targetH / 2 };\n // Coverage radius: the farthest target corner from the grid origin. Rotation\n // happens around that origin, so a radius is rotation-invariant. With the\n // origin at the centre this is exactly half the diagonal — the value this\n // used to hard-code.\n const radius = cornerRadius(anchor, targetW, targetH);\n const span = radius * 2;\n // Floor the spacing-adjusted tile (as well as the base, floored by the\n // caller): a negative spacing from a hand-crafted config would otherwise\n // collapse the loop tile to ~1px and spawn ~span² draw calls (client-side DoS).\n const minTile = Math.max(1, span / MAX_TILES_PER_AXIS);\n const tileW = Math.max(minTile, baseW * (1 + config.horizontalSpacing / 100));\n const tileH = Math.max(minTile, baseH * (1 + config.verticalSpacing / 100));\n\n const cols = Math.ceil(span / tileW) + 2;\n const rows = Math.ceil(span / tileH) + 2;\n const halfCols = Math.ceil(cols / 2);\n const halfRows = Math.ceil(rows / 2);\n\n // Grid phase shift. Clamped to one tile: the loop only carries one spare tile\n // of margin past the coverage radius, so a larger shift would uncover an edge\n // — the one thing a pattern must not do. A whole-tile shift is a no-op anyway.\n const shiftX = tileW * (clampOffset(config.offsetX) / 100);\n const shiftY = tileH * (clampOffset(config.offsetY) / 100);\n\n const placements: TilePlacement[] = [];\n for (let j = -halfRows; j <= halfRows; j++) {\n for (let i = -halfCols; i <= halfCols; i++) {\n let x = i * tileW + shiftX;\n let y = j * tileH + shiftY;\n\n if (config.mode === 'brick-horizontal' && mod2(j) === 1) {\n x += tileW * (config.horizontalOffset / 100);\n } else if (config.mode === 'brick-vertical' && mod2(i) === 1) {\n y += tileH * (config.horizontalOffset / 100);\n }\n\n const rotation = ((i * config.rotationStepH + j * config.rotationStepV) * Math.PI) / 180;\n placements.push({ x, y, rotation });\n }\n }\n return placements;\n}\n\n/**\n * Draw the tiled pattern onto a 2D context, in target coordinates (0,0 = the\n * target's top-left corner). The geometry lives in {@link computeTilePositions};\n * this just plays it out as canvas calls.\n *\n * `baseW`/`baseH` are the grid STEP. `draw` is the size the bitmap is painted at\n * and defaults to the step — pass it when the bitmap carries padding the step\n * does not (see {@link TileDrawSize}), so the artwork still lands step-sized.\n */\nexport function drawTiles(\n ctx: CanvasRenderingProtocol,\n img: CanvasImageSource,\n config: PatternConfig,\n targetW: number,\n targetH: number,\n baseW: number,\n baseH: number,\n origin?: PatternOrigin,\n draw?: TileDrawSize,\n): void {\n const anchor = origin ?? { x: targetW / 2, y: targetH / 2 };\n const drawW = draw && draw.width > 0 ? draw.width : baseW;\n const drawH = draw && draw.height > 0 ? draw.height : baseH;\n ctx.save();\n // Rotate the whole pattern around the grid origin.\n ctx.translate(anchor.x, anchor.y);\n ctx.rotate((config.angle * Math.PI) / 180);\n\n for (const tile of computeTilePositions(config, targetW, targetH, baseW, baseH, anchor)) {\n ctx.save();\n ctx.translate(tile.x, tile.y);\n ctx.rotate(tile.rotation);\n // Centred on the tile, so any padding grows outward symmetrically and the\n // artwork stays where the step puts it.\n ctx.drawImage(img, -drawW / 2, -drawH / 2, drawW, drawH);\n ctx.restore();\n }\n\n ctx.restore();\n}\n\n/** Distance from `origin` to the farthest corner of a `w × h` box at 0,0. */\nfunction cornerRadius(origin: PatternOrigin, w: number, h: number): number {\n const dx = Math.max(Math.abs(origin.x), Math.abs(w - origin.x));\n const dy = Math.max(Math.abs(origin.y), Math.abs(h - origin.y));\n return Math.sqrt(dx * dx + dy * dy);\n}\n\n/** Grid phase shift, as % of tile size, bounded to ±1 tile (0 if not set). */\nfunction clampOffset(value: number | undefined): number {\n if (typeof value !== 'number' || !Number.isFinite(value)) return 0;\n return Math.max(-100, Math.min(100, value));\n}\n\n/** Non-negative parity (so negative row indices brick-shift consistently). */\nfunction mod2(n: number): number {\n return ((n % 2) + 2) % 2;\n}\n\n/** Minimal 2D-context surface used by {@link drawTiles}; lets tests inject a spy. */\nexport interface CanvasRenderingProtocol {\n save(): void;\n restore(): void;\n translate(x: number, y: number): void;\n rotate(angle: number): void;\n drawImage(image: CanvasImageSource, dx: number, dy: number, dw: number, dh: number): void;\n}\n","import { Path } from 'fabric';\nimport type { Canvas, FabricObject } from 'fabric';\nimport type { Layer, LayerManager } from './layer';\nimport type { HistoryManager } from './history';\nimport type { EditorEvents, TextCurveConfig, TextCurveInput } from './types';\nimport type { EventEmitter } from './events';\nimport { bendsBaseline, buildCurveLinePaths, normalizeTextCurve } from './text-curve-geometry';\nimport type { CurvePath } from './text-curve-geometry';\n\nexport {\n DEFAULT_TEXT_CURVE,\n buildCurvePathData,\n buildCurveLinePaths,\n normalizeTextCurve,\n} from './text-curve-geometry';\nexport type { CurvePath } from './text-curve-geometry';\n\n/** Box width used to measure an unwrapped run; wide enough that nothing wraps. */\nconst MEASURE_WIDTH = 100000;\n/** Extra path length past the measured run, so the last glyph never falls off. */\nconst PATH_SLACK = 0.06;\n/** Line height fabric assumes when the object can't report one. */\nconst FALLBACK_LINE_HEIGHT = 1.16;\n\ninterface CurvableText extends FabricObject {\n fontSize: number;\n text: string;\n lineHeight?: number;\n textAlign?: string;\n path?: FabricObject | null;\n pathAlign?: string;\n pathSide?: string;\n pathStartOffset?: number;\n _textLines?: unknown[];\n calcTextWidth?: () => number;\n getHeightOfLine?: (lineIndex: number) => number;\n initDimensions?: () => void;\n _measureLine?: (lineIndex: number) => { width: number; numOfSpaces: number };\n}\n\n/** The per-line measuring hook this manager installs on a curved text object. */\ninterface LinePatch {\n original: CurvableText['_measureLine'];\n installed: CurvableText['_measureLine'];\n /** Whether the object carried its own hook before, or inherited fabric's. */\n ownedOriginal: boolean;\n}\n\nconst patches = new WeakMap<CurvableText, LinePatch>();\n\n/** `objectCaching` as the object was authored, while a curve overrides it. */\nconst authoredCaching = new WeakMap<CurvableText, boolean>();\n\nfunction isCurvable(object: FabricObject | undefined): object is CurvableText {\n return !!object && typeof (object as CurvableText).text === 'string';\n}\n\n/**\n * Width the run wants on a single line.\n *\n * `calcTextWidth` reports the widest *wrapped* line, which for a Textbox is\n * capped by its box — so it is measured against a box wide enough that nothing\n * wraps, then the authored width is put back.\n */\nfunction measureText(text: CurvableText): number {\n const authored = text.width;\n try {\n text.set({ width: MEASURE_WIDTH });\n text.initDimensions?.();\n return Math.max(1, text.calcTextWidth?.() ?? text.width ?? 1);\n } finally {\n if (authored !== undefined) text.set({ width: authored });\n text.initDimensions?.();\n }\n}\n\nfunction lineCountOf(text: CurvableText): number {\n return Math.max(1, text._textLines?.length ?? 1);\n}\n\nfunction lineHeightOf(text: CurvableText): number {\n const measured = text.getHeightOfLine?.(0);\n if (typeof measured === 'number' && Number.isFinite(measured) && measured > 0) return measured;\n return text.fontSize * (text.lineHeight ?? 1) * FALLBACK_LINE_HEIGHT;\n}\n\nfunction toFabricPath(curve: CurvePath): Path {\n return new Path(curve.data, { visible: false, objectCaching: false });\n}\n\n/**\n * Bends a text layer's baseline along a generated path.\n *\n * The curve lives on the fabric object as a real text path, so it survives\n * export and serialization with no extra machinery. The parameters that\n * produced it are kept in `layer.meta.curve` so the UI can show them and so the\n * path can be rebuilt when the text, font or size changes.\n */\nexport class TextCurveManager {\n /**\n * Typing on the canvas changes the run the paths were built for. Fabric drops\n * a glyph whose centre falls past the end of the path, so without rebuilding\n * here a longer replacement simply vanishes — select-all-and-retype rendered\n * an empty box — and a shorter one piles up on a path built for the old text.\n *\n * No history entry: fabric records the edit when editing exits, and one save\n * per keystroke would bury every earlier step under the typing.\n */\n private readonly onTextChanged = (event: { target?: FabricObject }) => {\n const layer = event.target ? this.layers.findByObject(event.target) : undefined;\n if (!layer?.meta.curve) return;\n this.refresh(layer.id, false);\n };\n\n constructor(\n private canvas: Canvas,\n private layers: LayerManager,\n private history: HistoryManager,\n private events: EventEmitter<EditorEvents>,\n ) {\n this.canvas.on('text:changed', this.onTextChanged);\n }\n\n dispose(): void {\n this.canvas.off('text:changed', this.onTextChanged);\n }\n\n /** Curve parameters for a layer, or null when it is not curved text. */\n get(layerId: string): TextCurveConfig | null {\n const layer = this.layers.get(layerId);\n if (!layer || !isCurvable(layer.fabricObject)) return null;\n // Normalized on the way out: states saved before the shape switch existed\n // carry only `arc` and `wave`.\n return normalizeTextCurve(layer.meta.curve ?? {});\n }\n\n isCurved(layerId: string): boolean {\n const curve = this.get(layerId);\n return !!curve && bendsBaseline(curve);\n }\n\n /** Apply (or update) the curve on a text layer. A straight config clears it. */\n apply(layerId: string, config: TextCurveInput, save = true): boolean {\n const layer = this.layers.get(layerId);\n if (!layer || !isCurvable(layer.fabricObject)) return false;\n\n const next = normalizeTextCurve(config);\n const text = layer.fabricObject;\n const run = measureText(text);\n\n if (!bendsBaseline(next)) {\n this.detach(text, layer.meta.curveWidth);\n delete layer.meta.curveWidth;\n // The parameters stay: a straightened layer keeps the shape it was on and\n // the settings of both, so the panel doesn't reset under the user.\n layer.meta.curve = next;\n } else {\n // A Textbox wraps at its box width; a wrapped run cannot follow a path, so\n // the box is widened to the natural text width for as long as it is\n // curved. The authored width is kept so clearing restores it.\n if (layer.meta.curveWidth === undefined) layer.meta.curveWidth = text.width ?? 0;\n text.set({ width: Math.max(layer.meta.curveWidth, run + 2) });\n // Widening changes where the run wraps, so the line count is only settled\n // once the box is its curved size.\n text.initDimensions?.();\n // Fabric drops (and wraps) a glyph whose centre falls past the end of the\n // path, and the measured run can land a hair over — so the path is built a\n // little longer than the text and the text is centred on it.\n const curves = buildCurveLinePaths(\n next,\n run * (1 + PATH_SLACK),\n text.fontSize,\n lineCountOf(text),\n lineHeightOf(text),\n );\n if (curves) this.attach(text, curves);\n layer.meta.curve = next;\n }\n\n text.initDimensions?.();\n text.setCoords();\n text.dirty = true;\n this.canvas.requestRenderAll();\n this.events.emit('layer:modified', { layerId });\n if (save) this.history.save();\n return true;\n }\n\n /** Remove the curve, restoring the authored text box width. */\n clear(layerId: string, save = true): boolean {\n const layer = this.layers.get(layerId);\n const shape = layer?.meta.curve?.shape;\n // Keep the shape the layer was on: straightening is not a mode switch, and\n // the panel would otherwise jump back to the arc tab.\n return this.apply(layerId, { shape }, save);\n }\n\n /**\n * Rebuild the paths from the stored parameters. Text content, line count,\n * font family and font size all change the geometry the paths are sized to —\n * without this the curve keeps that of the text it was created from.\n */\n refresh(layerId: string, save = false): boolean {\n const curve = this.layers.get(layerId)?.meta.curve;\n if (!curve) return false;\n return this.apply(layerId, curve, save);\n }\n\n /**\n * Rebuild every curved layer — used after a state restore.\n *\n * `getAll` is the canvas stack, so this walks each group's children too:\n * curved text inside a group would otherwise keep the path geometry it was\n * restored with, and stop tracking its own text, font and size.\n */\n refreshAll(): void {\n const visit = (layers: Layer[]): void => {\n for (const layer of layers) {\n if (layer.meta.curve) this.refresh(layer.id);\n if (layer.children.length > 0) visit(layer.children);\n }\n };\n visit(this.layers.getAll());\n }\n\n /**\n * Puts every line's path on the object as one shape, and hooks per-line\n * measuring so each line is laid out on its own.\n *\n * The object's own path is the union of the lines: fabric sizes a curved text\n * object from it, and a single line's path would leave the rest of the block\n * outside the layer's box — where object caching clips it away.\n */\n private attach(text: CurvableText, curves: CurvePath[]): void {\n // A cached object is drawn into a canvas the size of its own box, and a\n // curved run reaches well outside that box — an arc came out with its top\n // sliced flat, on screen and in every export. Uncached, there is nothing to\n // clip it. Only curved text pays the per-frame redraw.\n if (!authoredCaching.has(text)) authoredCaching.set(text, text.objectCaching);\n text.set({ objectCaching: false });\n\n const paths = curves.map(toFabricPath);\n const union =\n paths.length === 1 ? paths[0] : toFabricPath({ data: curves.map((c) => c.data).join(' '), length: 0 });\n text.set({\n path: union,\n pathAlign: 'center',\n pathSide: 'left',\n // Each line is centred on its own path by the measuring hook below, so\n // there is no single offset left to apply.\n pathStartOffset: 0,\n });\n this.patchLineMeasure(text, paths, union);\n }\n\n /**\n * Fabric lays every line of a text object along `this.path`, from one\n * `pathStartOffset` — so a multi-line run piles all its lines on top of each\n * other. Each line is measured against its own path instead, by swapping the\n * path in around fabric's own per-line measure pass.\n *\n * The paths all share the first one's `pathOffset`, which is the origin\n * fabric subtracts to place a glyph in the object — without that each line\n * would be re-centred on its own bounding box and land back in the same spot.\n *\n * `textAlign` is switched to centre for the pass, which is how fabric centres\n * a line on its path; the authored value is restored before anything else\n * reads it.\n */\n private patchLineMeasure(text: CurvableText, paths: Path[], union: Path): void {\n this.unpatchLineMeasure(text);\n const original = text._measureLine;\n // Guard the fabric internal this leans on: without it only line 1 curves,\n // and it lands at the start of its path rather than centred on it.\n if (typeof original !== 'function') return;\n\n for (const path of paths) path.pathOffset = union.pathOffset;\n\n const installed = function (this: CurvableText, lineIndex: number) {\n const path = paths[lineIndex];\n if (!path) return original.call(this, lineIndex);\n const previousPath = this.path;\n const previousAlign = this.textAlign;\n this.path = path;\n this.textAlign = 'center';\n // `setPathInfo` fills in the segment lengths fabric measures along; a\n // swapped-in path has none until it has been the object's own path.\n (this as unknown as { setPathInfo?: () => void }).setPathInfo?.();\n try {\n return original.call(this, lineIndex);\n } finally {\n this.path = previousPath;\n this.textAlign = previousAlign;\n }\n };\n\n const ownedOriginal = Object.prototype.hasOwnProperty.call(text, '_measureLine');\n text._measureLine = installed;\n patches.set(text, { original, installed, ownedOriginal });\n }\n\n /** Restore fabric's own per-line measuring, if this manager replaced it. */\n private unpatchLineMeasure(text: CurvableText): void {\n const patch = patches.get(text);\n if (!patch) return;\n // Only unwind our own hook — anything layered on top since owns the slot.\n if (text._measureLine === patch.installed) {\n // Reassigning the inherited method would leave an own property shadowing\n // the prototype's, which a later fabric version would then never update.\n if (patch.ownedOriginal) text._measureLine = patch.original;\n else delete text._measureLine;\n }\n patches.delete(text);\n }\n\n private detach(text: CurvableText, authoredWidth: number | undefined): void {\n this.unpatchLineMeasure(text);\n const caching = authoredCaching.get(text);\n if (caching !== undefined) {\n text.set({ objectCaching: caching });\n authoredCaching.delete(text);\n }\n text.set({ path: null, pathStartOffset: 0 });\n if (authoredWidth !== undefined && authoredWidth > 0) text.set({ width: authoredWidth });\n }\n}\n","import type { TextCurveConfig, TextCurveInput } from './types';\nimport { clamp } from './utils/clamp';\n\n/** Straight text — the state every text layer starts in. */\nexport const DEFAULT_TEXT_CURVE: TextCurveConfig = {\n shape: 'arc',\n arc: 0,\n wave: 0,\n waveLength: 4.1,\n offset: 0,\n centerOffset: 0,\n};\n\n/** Below this the arc is indistinguishable from a straight baseline. */\nexport const MIN_ARC = 0.5;\n/** `arc` at or above this closes the ring instead of bending an open arc. */\nconst FULL_CIRCLE_ARC = 99.5;\n/** Floor on the sweep so a tiny arc doesn't ask for a near-infinite radius. */\nconst MIN_SWEEP = 0.12;\n/** Wave amplitude at `wave: 100`, in font sizes. */\nconst WAVE_AMPLITUDE_EM = 0.9;\n/** Bounds on the wave period, in font sizes. */\nexport const MIN_WAVE_LENGTH = 1;\nexport const MAX_WAVE_LENGTH = 12;\n/** Sampling step for the wave polyline, in px, and the cap on the sample count. */\nconst WAVE_STEP = 6;\nconst MAX_WAVE_STEPS = 4000;\n\nexport interface CurvePath {\n /** SVG path data the line is laid out along. */\n data: string;\n /** Length of that path. */\n length: number;\n}\n\nfunction round(value: number): number {\n return Math.round(value * 100) / 100;\n}\n\n/**\n * Fills in a partial curve.\n *\n * States saved before the shape switch existed carry only `arc` and `wave`, and\n * held exactly one of them — so the non-zero one names the shape.\n */\nexport function normalizeTextCurve(config: TextCurveInput): TextCurveConfig {\n const arc = clamp(config.arc ?? 0, -100, 100);\n const wave = clamp(config.wave ?? 0, 0, 100);\n const inferred = Math.abs(arc) < MIN_ARC && wave > 0 ? 'wave' : 'arc';\n return {\n shape: config.shape ?? inferred,\n arc,\n wave,\n waveLength: clamp(config.waveLength ?? DEFAULT_TEXT_CURVE.waveLength, MIN_WAVE_LENGTH, MAX_WAVE_LENGTH),\n offset: clamp(config.offset ?? 0, -100, 100),\n centerOffset: clamp(config.centerOffset ?? 0, -100, 100),\n };\n}\n\n/** True when the config actually bends the baseline. */\nexport function bendsBaseline(config: TextCurveConfig): boolean {\n return config.shape === 'arc' ? Math.abs(config.arc) >= MIN_ARC : config.wave > 0;\n}\n\ninterface ArcGeometry {\n /** Radius of the line the run sits on. */\n radius: number;\n /** Angle the arc spans. */\n sweep: number;\n /** +1 bulges the run upward (a rainbow), −1 into a valley. */\n direction: number;\n /** Ring the arc is measured against; the circle centre sits this far away. */\n baseRadius: number;\n}\n\n/**\n * Circle the run is bent around.\n *\n * `arc` fixes the angle the run spans; `centerOffset` then pushes it off that\n * ring — outward the ring grows and the run keeps its sweep, centred in a\n * longer arc; inward the ring shrinks, and the sweep has to open up to keep the\n * whole run on the path instead of dropping its tail.\n */\nfunction arcGeometry(width: number, config: TextCurveConfig): ArcGeometry {\n const magnitude = Math.min(100, Math.abs(config.arc));\n const direction = config.arc < 0 ? -1 : 1;\n const baseSweep =\n magnitude >= FULL_CIRCLE_ARC ? Math.PI * 2 : Math.max(MIN_SWEEP, (magnitude / 100) * Math.PI);\n const baseRadius = width / baseSweep;\n // ±100 halves / doubles the ring, and the ends stay in proportion.\n const radius = baseRadius * Math.pow(2, config.centerOffset / 100);\n const sweep =\n radius >= baseRadius ? baseSweep : Math.min(Math.PI * 2, width / Math.max(radius, 1e-3));\n return { radius, sweep, direction, baseRadius };\n}\n\n/**\n * Arc for one line, drawn in the frame of the whole block.\n *\n * Every line shares one circle centre — `(width / 2, direction · baseRadius)`,\n * which is where the un-offset baseline's centre already was — so the lines\n * come out concentric instead of as copies sitting on top of each other.\n */\nfunction arcLinePath(width: number, geometry: ArcGeometry, radius: number, rotation: number): CurvePath {\n const { sweep, direction, baseRadius } = geometry;\n const full = sweep >= Math.PI * 2 - 1e-6;\n const centerX = width / 2;\n\n // y grows downward, so subtracting `r · cos` from the centre bulges the middle\n // of the run away from it — upward for a positive arc, into a valley for the\n // mirrored one.\n const point = (angle: number): [number, number] => [\n centerX + radius * Math.sin(angle),\n direction * (baseRadius - radius * Math.cos(angle)),\n ];\n // SVG sweep flag: 1 traces the positive (clockwise, y-down) direction, which\n // is what a rainbow does when read left to right. A valley traces the other.\n const sweepFlag = direction > 0 ? 1 : 0;\n const format = ([x, y]: [number, number]) => `${round(x)} ${round(y)}`;\n const r = round(radius);\n\n if (full) {\n // A single arc command cannot close a circle: start and end coincide, which\n // SVG treats as a no-op. Split it at the far side of the ring.\n const start = point(rotation - Math.PI);\n const opposite = point(rotation);\n return {\n data: [\n `M ${format(start)}`,\n `A ${r} ${r} 0 0 ${sweepFlag} ${format(opposite)}`,\n `A ${r} ${r} 0 0 ${sweepFlag} ${format(start)}`,\n ].join(' '),\n length: radius * Math.PI * 2,\n };\n }\n\n const start = point(rotation - sweep / 2);\n const end = point(rotation + sweep / 2);\n const largeArc = sweep > Math.PI ? 1 : 0;\n return {\n data: `M ${format(start)} A ${r} ${r} 0 ${largeArc} ${sweepFlag} ${format(end)}`,\n length: radius * sweep,\n };\n}\n\n/** Sine wave for one line, shifted down the block by `dy`. */\nfunction waveLinePath(width: number, fontSize: number, config: TextCurveConfig, dy: number): CurvePath {\n const amplitude = (config.wave / 100) * fontSize * WAVE_AMPLITUDE_EM;\n const period = Math.max(1, fontSize * config.waveLength);\n // ±100 walks the run through one whole wavelength.\n const phase = (config.offset / 100) * Math.PI * 2;\n // A short wavelength needs denser samples or the crests come out clipped.\n const step = Math.min(WAVE_STEP, period / 8);\n const steps = Math.min(MAX_WAVE_STEPS, Math.max(2, Math.ceil(width / step)));\n const commands: string[] = [];\n let length = 0;\n let previous: [number, number] | null = null;\n for (let index = 0; index <= steps; index++) {\n const x = (width * index) / steps;\n const y = dy + amplitude * Math.sin((x / period) * Math.PI * 2 + phase);\n if (previous) length += Math.hypot(x - previous[0], y - previous[1]);\n previous = [x, y];\n commands.push(`${index === 0 ? 'M' : 'L'} ${round(x)} ${round(y)}`);\n }\n // A wave is longer than the run it spans; the caller centres the text on it.\n return { data: commands.join(' '), length };\n}\n\n/**\n * One path per line of text, in a single shared coordinate frame.\n *\n * Fabric lays every line of a text object along the *same* path, so a\n * multi-line run collapses into one overlapping pile. Each line gets its own\n * path here, and `TextCurveManager` measures each line against its own — arcs\n * concentric around one centre, waves stacked a line-height apart. The block is\n * centred on the single-line baseline so adding a line doesn't shift the design.\n */\nexport function buildCurveLinePaths(\n config: TextCurveInput,\n width: number,\n fontSize: number,\n lineCount = 1,\n lineHeight = 0,\n): CurvePath[] | null {\n const curve = normalizeTextCurve(config);\n if (!bendsBaseline(curve)) return null;\n\n const lines = Math.max(1, Math.floor(lineCount));\n const paths: CurvePath[] = [];\n if (curve.shape === 'wave') {\n for (let index = 0; index < lines; index++) {\n paths.push(waveLinePath(width, fontSize, curve, (index - (lines - 1) / 2) * lineHeight));\n }\n return paths;\n }\n\n const geometry = arcGeometry(width, curve);\n // ±100 walks a closed ring right round; on an open arc it slides the run by\n // its own sweep, which is as far as the shape can carry it.\n const rotation = (curve.offset / 100) * geometry.sweep;\n for (let index = 0; index < lines; index++) {\n // Later lines sit further out, so line 1 is the innermost ring.\n const radius = Math.max(1, geometry.radius + (index - (lines - 1) / 2) * lineHeight);\n paths.push(arcLinePath(width, geometry, radius, rotation));\n }\n return paths;\n}\n\n/** Path the given curve traces for a single-line run, or null when straight. */\nexport function buildCurvePathData(\n config: TextCurveInput,\n width: number,\n fontSize: number,\n): CurvePath | null {\n return buildCurveLinePaths(config, width, fontSize)?.[0] ?? null;\n}\n","import { FabricImage, Path } from 'fabric';\nimport type { Canvas, FabricObject } from 'fabric';\nimport type { LayerManager } from './../layer';\nimport type { HistoryManager } from './../history';\nimport type { EditorEvents, MaskPresetId } from './../types';\nimport type { EventEmitter } from './../events';\nimport { SHAPE_MASK_BOX, isShapeMaskId, shapeMaskPathData } from './shapes';\nimport { TEXTURE_MASK_SIZE, isTextureMaskId, renderTextureMask } from './textures';\n\nexport function isMaskPresetId(value: unknown): value is MaskPresetId {\n return isShapeMaskId(value) || isTextureMaskId(value);\n}\n\n/**\n * Clips a layer to a preset silhouette or soft texture.\n *\n * The preset is installed as the fabric object's `clipPath`, so it renders,\n * exports and serializes through the same path fabric already uses. The chosen\n * id is kept in `layer.meta.maskPreset` so the UI can show the active preset\n * and so the clip can be rebuilt when the layer is resized.\n *\n * A pattern strips and restores the layer's clip while it is enabled (see\n * `PatternManager`), so a mask preset is suspended for the duration of one.\n */\nexport class MaskPresetManager {\n constructor(\n private canvas: Canvas,\n private layers: LayerManager,\n private history: HistoryManager,\n private events: EventEmitter<EditorEvents>,\n ) {}\n\n get(layerId: string): MaskPresetId | null {\n return this.layers.get(layerId)?.meta.maskPreset ?? null;\n }\n\n /** Clip the layer to `id`. Passing null (or an unknown id) clears the clip. */\n apply(layerId: string, id: MaskPresetId | null, save = true): boolean {\n const layer = this.layers.get(layerId);\n if (!layer) return false;\n const object = layer.fabricObject;\n\n if (id === null) {\n if (!layer.meta.maskPreset) return false;\n object.clipPath = undefined;\n delete layer.meta.maskPreset;\n } else {\n if (!isMaskPresetId(id)) return false;\n object.clipPath = this.buildClip(id, object);\n layer.meta.maskPreset = id;\n }\n\n object.dirty = true;\n object.setCoords();\n this.canvas.requestRenderAll();\n this.events.emit('layer:modified', { layerId });\n if (save) this.history.save();\n return true;\n }\n\n clear(layerId: string, save = true): boolean {\n return this.apply(layerId, null, save);\n }\n\n /**\n * Re-fit the clip to the layer's current size. The clip is built for the\n * object's dimensions at the time it was applied; editing text or replacing an\n * image changes them, and a stale clip would crop the wrong region.\n */\n refresh(layerId: string, save = false): boolean {\n const id = this.get(layerId);\n if (!id) return false;\n return this.apply(layerId, id, save);\n }\n\n /** Re-fit every masked layer — used after a state restore. */\n refreshAll(): void {\n for (const layer of this.layers.getAll()) {\n if (layer.meta.maskPreset) this.refresh(layer.id);\n }\n }\n\n private buildClip(id: MaskPresetId, object: FabricObject): FabricObject {\n // clipPath coordinates are the object's own, centred on it, and unaffected\n // by the object's scale — so the clip is sized to the unscaled dimensions.\n const width = Math.max(1, object.width ?? 1);\n const height = Math.max(1, object.height ?? 1);\n const shared = {\n originX: 'center' as const,\n originY: 'center' as const,\n left: 0,\n top: 0,\n objectCaching: false,\n };\n\n if (isShapeMaskId(id)) {\n return new Path(shapeMaskPathData(id), {\n ...shared,\n scaleX: width / SHAPE_MASK_BOX,\n scaleY: height / SHAPE_MASK_BOX,\n });\n }\n\n return new FabricImage(renderTextureMask(id), {\n ...shared,\n scaleX: width / TEXTURE_MASK_SIZE,\n scaleY: height / TEXTURE_MASK_SIZE,\n });\n }\n}\n","import type { ShapeMaskPresetId } from './../types';\n\n/** Silhouette masks, authored on a 0–100 square so they scale to any layer. */\nexport const SHAPE_MASK_IDS = [\n 'circle',\n 'square',\n 'triangle',\n 'star',\n 'heart',\n 'octagram',\n 'arch',\n 'zigzag',\n] as const satisfies readonly ShapeMaskPresetId[];\n\nexport type ShapeMaskId = ShapeMaskPresetId;\n\nexport function isShapeMaskId(value: unknown): value is ShapeMaskId {\n return typeof value === 'string' && (SHAPE_MASK_IDS as readonly string[]).includes(value);\n}\n\n/** Vertices of an `points`-pointed star, alternating outer and inner radius. */\nfunction starPoints(points: number, outer: number, inner: number, start = -Math.PI / 2): string {\n const step = Math.PI / points;\n const coordinates: string[] = [];\n for (let index = 0; index < points * 2; index++) {\n const radius = index % 2 === 0 ? outer : inner;\n const angle = start + index * step;\n const x = 50 + Math.cos(angle) * radius;\n const y = 50 + Math.sin(angle) * radius;\n coordinates.push(`${index === 0 ? 'M' : 'L'} ${round(x)} ${round(y)}`);\n }\n return `${coordinates.join(' ')} Z`;\n}\n\nfunction round(value: number): number {\n return Math.round(value * 100) / 100;\n}\n\nconst SHAPE_PATHS: Record<ShapeMaskId, string> = {\n circle: 'M 96 50 A 46 46 0 1 1 4 50 A 46 46 0 1 1 96 50 Z',\n square: 'M 4 4 H 96 V 96 H 4 Z',\n triangle: 'M 50 4 L 96 96 L 4 96 Z',\n star: starPoints(5, 46, 22),\n heart: 'M 50 96 C -8 55 12 4 50 28 C 88 4 108 55 50 96 Z',\n octagram: starPoints(8, 46, 27),\n arch: 'M 4 96 V 50 A 46 46 0 0 1 96 50 V 96 Z',\n zigzag: starPoints(16, 46, 39),\n};\n\n/** SVG path data for a shape mask, on a 100×100 box. */\nexport function shapeMaskPathData(id: ShapeMaskId): string {\n return SHAPE_PATHS[id];\n}\n\n/** Nominal authoring box every shape mask path is drawn in. */\nexport const SHAPE_MASK_BOX = 100;\n","import type { TextureMaskPresetId } from './../types';\n\n/**\n * Procedural alpha textures used as soft layer masks.\n *\n * Each renders white-on-transparent at a fixed resolution; the opaque parts are\n * what survives masking. They are deterministic (seeded PRNG, no `Math.random`)\n * so a design renders identically on every load and in every export.\n */\nexport const TEXTURE_MASK_IDS = [\n 'vignette',\n 'halftone',\n 'spray',\n 'grunge',\n 'torn',\n 'band',\n] as const satisfies readonly TextureMaskPresetId[];\n\nexport type TextureMaskId = TextureMaskPresetId;\n\nexport function isTextureMaskId(value: unknown): value is TextureMaskId {\n return typeof value === 'string' && (TEXTURE_MASK_IDS as readonly string[]).includes(value);\n}\n\n/** Square resolution every texture is rendered at before being scaled to fit. */\nexport const TEXTURE_MASK_SIZE = 320;\n\nconst cache = new Map<TextureMaskId, HTMLCanvasElement>();\n\n/** Park–Miller PRNG: same seed, same texture, on every machine. */\nfunction seeded(seed: number): () => number {\n let state = seed;\n return () => {\n state = (state * 16807) % 2147483647;\n return (state - 1) / 2147483646;\n };\n}\n\nfunction traceRoughEdge(\n context: CanvasRenderingContext2D,\n random: () => number,\n jitter: number,\n inset: number,\n): void {\n const size = TEXTURE_MASK_SIZE;\n const corners: [number, number][] = [\n [inset, inset],\n [size - inset, inset],\n [size - inset, size - inset],\n [inset, size - inset],\n ];\n context.beginPath();\n for (let corner = 0; corner < corners.length; corner++) {\n const [fromX, fromY] = corners[corner];\n const [toX, toY] = corners[(corner + 1) % corners.length];\n for (let step = 0; step <= 26; step++) {\n const ratio = step / 26;\n const x = fromX + (toX - fromX) * ratio + (random() - 0.5) * jitter;\n const y = fromY + (toY - fromY) * ratio + (random() - 0.5) * jitter;\n if (corner === 0 && step === 0) context.moveTo(x, y);\n else context.lineTo(x, y);\n }\n }\n context.closePath();\n context.fill();\n}\n\nfunction paint(id: TextureMaskId, context: CanvasRenderingContext2D): void {\n const size = TEXTURE_MASK_SIZE;\n const center = size / 2;\n context.fillStyle = '#ffffff';\n\n switch (id) {\n case 'vignette': {\n const gradient = context.createRadialGradient(\n center,\n center,\n size * 0.18,\n center,\n center,\n size * 0.52,\n );\n gradient.addColorStop(0, 'rgba(255,255,255,1)');\n gradient.addColorStop(1, 'rgba(255,255,255,0)');\n context.fillStyle = gradient;\n context.fillRect(0, 0, size, size);\n return;\n }\n case 'band': {\n const gradient = context.createLinearGradient(0, 0, 0, size);\n gradient.addColorStop(0, 'rgba(255,255,255,0)');\n gradient.addColorStop(0.25, 'rgba(255,255,255,1)');\n gradient.addColorStop(0.75, 'rgba(255,255,255,1)');\n gradient.addColorStop(1, 'rgba(255,255,255,0)');\n context.fillStyle = gradient;\n context.fillRect(0, 0, size, size);\n return;\n }\n case 'halftone': {\n const pitch = 16;\n for (let y = pitch / 2; y < size; y += pitch) {\n for (let x = pitch / 2; x < size; x += pitch) {\n const distance = Math.hypot(x - center, y - center) / (size * 0.52);\n const radius = Math.max(0, (pitch / 2) * (1 - distance) * 1.15);\n if (radius < 0.4) continue;\n context.beginPath();\n context.arc(x, y, radius, 0, Math.PI * 2);\n context.fill();\n }\n }\n return;\n }\n case 'spray': {\n const random = seeded(42);\n const core = context.createRadialGradient(center, center, 10, center, center, size * 0.42);\n core.addColorStop(0, 'rgba(255,255,255,1)');\n core.addColorStop(1, 'rgba(255,255,255,0.85)');\n context.fillStyle = core;\n context.beginPath();\n context.arc(center, center, size * 0.42, 0, Math.PI * 2);\n context.fill();\n context.fillStyle = 'rgba(255,255,255,0.9)';\n for (let dot = 0; dot < 900; dot++) {\n const angle = random() * Math.PI * 2;\n const distance = size * (0.3 + random() * 0.24);\n const x = center + Math.cos(angle) * distance;\n const y = center + Math.sin(angle) * distance;\n context.globalAlpha = 1 - (distance / size - 0.3) / 0.24;\n context.beginPath();\n context.arc(x, y, random() * 2.4, 0, Math.PI * 2);\n context.fill();\n }\n context.globalAlpha = 1;\n return;\n }\n case 'grunge': {\n const random = seeded(7);\n traceRoughEdge(context, random, 14, size * 0.06);\n // Punch speckles back out of the frame, concentrated near its edges.\n context.globalCompositeOperation = 'destination-out';\n for (let speckle = 0; speckle < 240; speckle++) {\n const x = random() * size;\n const y = random() * size;\n const nearEdge = Math.min(x, y, size - x, size - y) < size * 0.12;\n if (!nearEdge && random() >= 0.12) continue;\n context.beginPath();\n context.arc(x, y, random() * 6 + 1, 0, Math.PI * 2);\n context.fill();\n }\n context.globalCompositeOperation = 'source-over';\n return;\n }\n case 'torn': {\n traceRoughEdge(context, seeded(99), 10, size * 0.08);\n return;\n }\n }\n}\n\n/** Render (and memoize) a texture mask. Browser-only: needs a 2D canvas. */\nexport function renderTextureMask(id: TextureMaskId): HTMLCanvasElement {\n const cached = cache.get(id);\n if (cached) return cached;\n if (typeof document === 'undefined') {\n throw new Error('Texture masks require a DOM canvas');\n }\n const canvas = document.createElement('canvas');\n canvas.width = TEXTURE_MASK_SIZE;\n canvas.height = TEXTURE_MASK_SIZE;\n const context = canvas.getContext('2d');\n if (!context) throw new Error('Texture masks require a 2D canvas context');\n paint(id, context);\n cache.set(id, canvas);\n return canvas;\n}\n\n/** Drop memoized textures — used by tests and by long-lived editors on dispose. */\nexport function clearTextureMaskCache(): void {\n cache.clear();\n}\n","import { Shadow } from 'fabric';\nimport type { FabricObject } from 'fabric';\nimport type { LayerShadowConfig } from './types';\nimport { isCssColor } from './utils/color';\n\nexport const DEFAULT_LAYER_SHADOW: LayerShadowConfig = {\n enabled: false,\n color: '#000000',\n blur: 12,\n offsetX: 6,\n offsetY: 6,\n};\n\n/**\n * Read a layer's drop shadow back off its fabric object.\n *\n * Fabric serializes `shadow` with the object, so the object — not layer meta —\n * is the source of truth; nothing extra has to round-trip through the editor\n * state for a shadow to survive save/load.\n */\nexport function readLayerShadow(object: FabricObject): LayerShadowConfig {\n const shadow = object.shadow;\n if (!shadow || typeof shadow === 'string') return { ...DEFAULT_LAYER_SHADOW };\n return {\n enabled: true,\n color: typeof shadow.color === 'string' ? shadow.color : DEFAULT_LAYER_SHADOW.color,\n blur: shadow.blur ?? DEFAULT_LAYER_SHADOW.blur,\n offsetX: shadow.offsetX ?? DEFAULT_LAYER_SHADOW.offsetX,\n offsetY: shadow.offsetY ?? DEFAULT_LAYER_SHADOW.offsetY,\n };\n}\n\n/** Install (or remove) a drop shadow on a fabric object. */\nexport function applyLayerShadow(object: FabricObject, config: Partial<LayerShadowConfig>): void {\n const next = { ...readLayerShadow(object), ...config };\n if (!next.enabled) {\n object.set({ shadow: null });\n return;\n }\n // The colour reaches a canvas shadow and an exported SVG filter verbatim, so\n // an unparseable value must not get that far.\n const color = isCssColor(next.color) ? next.color : DEFAULT_LAYER_SHADOW.color;\n object.set({\n shadow: new Shadow({\n color,\n blur: Math.max(0, next.blur),\n offsetX: next.offsetX,\n offsetY: next.offsetY,\n }),\n });\n}\n","// Hex, functional (rgb/rgba/hsl/hsla), or a bare keyword such as `red`.\n// Deliberately conservative: values reach canvas fill styles and are copied\n// verbatim into exported SVG, so anything that is not clearly a colour must be\n// rejected rather than passed through.\nconst CSS_COLOR = /^(?:#[\\da-f]{3,8}|(?:rgb|hsl)a?\\([\\d.%+\\-\\s,/]+\\)|[a-z]+)$/i;\n\n/** True for values safe to use as a canvas/SVG colour. Empty means transparent. */\nexport function isCssColor(value: unknown, allowEmpty = false): value is string {\n if (typeof value !== 'string') return false;\n const trimmed = value.trim();\n if (!trimmed) return allowEmpty;\n return CSS_COLOR.test(trimmed);\n}\n","import type { Canvas, FabricObject } from 'fabric';\n\n/**\n * Look of the selection frame and its resize handles.\n *\n * Every measurement is in **screen** pixels. Zoom is a display transform (the\n * view layer CSS-scales the canvas element), so a handle drawn at its nominal\n * size would grow and shrink with the zoom level; `applySelectionStyle`\n * counter-scales by 1/zoom so the frame stays the same size on screen whatever\n * the zoom.\n */\nexport interface SelectionStyle {\n /** Colour of the frame around the selection. */\n borderColor: string;\n /** Fill of the resize handles. */\n cornerColor: string;\n /** Outline drawn around each handle. */\n cornerStrokeColor: string;\n /** Handle diameter, in screen pixels. */\n cornerSize: number;\n /** Round handles (as in the design tools) or square ones. */\n cornerStyle: 'circle' | 'rect';\n /** Frame line width, in screen pixels. */\n borderWidth: number;\n /** Dash pattern for the frame, in screen pixels. Null = solid. */\n borderDashArray: number[] | null;\n /** Gap between the object bounds and the frame, in screen pixels. */\n padding: number;\n /** Fill of the drag-to-select marquee. */\n marqueeFill: string;\n}\n\nexport const DEFAULT_SELECTION_STYLE: SelectionStyle = {\n borderColor: '#c9a96e',\n cornerColor: '#c9a96e',\n cornerStrokeColor: '#101010',\n cornerSize: 11,\n cornerStyle: 'circle',\n borderWidth: 1,\n borderDashArray: null,\n padding: 0,\n marqueeFill: 'rgba(201, 169, 110, 0.12)',\n};\n\n/** Applies the style to ONE object at the given display zoom. */\nexport function applyObjectSelectionStyle(\n object: FabricObject,\n style: SelectionStyle,\n zoom: number,\n): void {\n const scale = zoom > 0 ? 1 / zoom : 1;\n object.set({\n cornerSize: style.cornerSize * scale,\n cornerStyle: style.cornerStyle,\n cornerColor: style.cornerColor,\n cornerStrokeColor: style.cornerStrokeColor,\n // A filled handle is what makes the stroke colour visible at all.\n transparentCorners: false,\n borderColor: style.borderColor,\n borderScaleFactor: style.borderWidth * scale,\n borderDashArray: style.borderDashArray?.map((segment) => segment * scale) ?? null,\n padding: style.padding * scale,\n });\n}\n\n/**\n * Applies the style to every object on the canvas plus the active selection.\n *\n * The active selection is a transient group that `getObjects()` does not list,\n * so it is styled separately — otherwise a multi-object selection would keep\n * fabric's default blue squares.\n */\nexport function applySelectionStyle(canvas: Canvas, style: SelectionStyle, zoom: number): void {\n for (const object of canvas.getObjects()) applyObjectSelectionStyle(object, style, zoom);\n const active = canvas.getActiveObject();\n if (active) applyObjectSelectionStyle(active, style, zoom);\n canvas.selectionColor = style.marqueeFill;\n canvas.selectionBorderColor = style.borderColor;\n canvas.selectionLineWidth = style.borderWidth * (zoom > 0 ? 1 / zoom : 1);\n canvas.requestRenderAll();\n}\n","import type { FabricObject } from 'fabric';\n\n/** Side handles scale one axis; hiding them is what makes a resize uniform. */\nconst SIDE_CONTROLS = ['ml', 'mr', 'mt', 'mb'] as const;\n\n/**\n * Constrain (or release) a layer's proportions.\n *\n * Fabric already scales uniformly from the corners (`canvas.uniformScaling`),\n * so the lock is enforced by taking away the single-axis handles — every\n * remaining control keeps the ratio.\n */\nexport function applyAspectLock(object: FabricObject, locked: boolean): void {\n for (const control of SIDE_CONTROLS) {\n object.setControlVisible(control, !locked);\n }\n}\n\n/**\n * Undo scaling, rotation, skew and flips, leaving the layer where it sits.\n * Position is deliberately kept: this is \"reset the shape\", not \"move it back\".\n */\nexport function resetTransform(object: FabricObject): void {\n object.set({\n scaleX: 1,\n scaleY: 1,\n angle: 0,\n skewX: 0,\n skewY: 0,\n flipX: false,\n flipY: false,\n });\n object.setCoords();\n}\n","import type { Unit } from '../types';\n\nconst MM_PER_INCH = 25.4;\n\nexport class UnitConverter {\n private unit: Unit;\n private dpi: number;\n\n constructor(unit: Unit = 'px', dpi: number = 72) {\n this.unit = unit;\n this.dpi = 72;\n this.setDpi(dpi);\n }\n\n setUnit(unit: Unit): void {\n this.unit = unit;\n }\n\n setDpi(dpi: number): void {\n if (!Number.isFinite(dpi) || dpi <= 0) throw new Error('DPI must be a positive number');\n this.dpi = dpi;\n }\n\n getUnit(): Unit {\n return this.unit;\n }\n\n getDpi(): number {\n return this.dpi;\n }\n\n toPixels(value: number, fromUnit?: Unit): number {\n const u = fromUnit ?? this.unit;\n switch (u) {\n case 'px':\n return value;\n case 'in':\n return value * this.dpi;\n case 'mm':\n return (value / MM_PER_INCH) * this.dpi;\n }\n }\n\n fromPixels(px: number, toUnit?: Unit): number {\n const u = toUnit ?? this.unit;\n switch (u) {\n case 'px':\n return px;\n case 'in':\n return px / this.dpi;\n case 'mm':\n return (px / this.dpi) * MM_PER_INCH;\n }\n }\n}\n","import { util } from 'fabric';\nimport type { FabricObject } from 'fabric';\nimport type { EditorState, LayerData, SerializedLayer } from './types';\nimport type { CanvasEditor } from './editor';\nimport { Layer } from './layer';\nimport { isCssColor } from './utils/color';\nimport { applyAspectLock } from './transform';\n\nconst VERSION = '2.0.0';\n\nexport function serializeEditor(editor: CanvasEditor): EditorState {\n return {\n version: VERSION,\n canvas: {\n width: editor.canvas.getWidth(),\n height: editor.canvas.getHeight(),\n unit: editor.units.getUnit(),\n dpi: editor.units.getDpi(),\n },\n layers: editor.layers.getAll().map((layer) => layer.serialize()),\n // The configured design background, not the live canvas value (which is\n // forced transparent while a mockup preview is active).\n background: editor.getDesignBackground(),\n backgroundImage: editor.getDesignBackgroundImage()\n ? (editor.getDesignBackgroundImage()!.toObject() as Record<string, unknown>)\n : null,\n backgroundImageOptions: editor.getBackgroundImageOptions(),\n mockup: editor.getMockup(),\n };\n}\n\nexport async function deserializeEditor(editor: CanvasEditor, state: EditorState): Promise<void> {\n if (!state || !state.canvas || !Array.isArray(state.layers)) {\n throw new Error('Invalid editor state');\n }\n if (\n !Number.isFinite(state.canvas.width) ||\n !Number.isFinite(state.canvas.height) ||\n state.canvas.width <= 0 ||\n state.canvas.height <= 0 ||\n (state.canvas.unit !== undefined && !['px', 'mm', 'in'].includes(state.canvas.unit)) ||\n (state.canvas.dpi !== undefined &&\n (!Number.isFinite(state.canvas.dpi) || state.canvas.dpi <= 0))\n ) {\n throw new Error('Invalid editor canvas settings');\n }\n const major = Number.parseInt(state.version?.split('.')[0] ?? '1', 10);\n if (!Number.isFinite(major) || major > 2) {\n throw new Error(`Unsupported editor state version: ${state.version}`);\n }\n // The background is copied verbatim into exported SVG, so an untrusted state\n // must not be able to smuggle markup through it. Empty means transparent.\n if (state.background !== undefined && !isCssColor(state.background, true)) {\n throw new Error('Invalid editor background color');\n }\n\n // Enliven everything before touching the live document. A dead image URL or\n // malformed object must not turn a recoverable load failure into data loss.\n const staged = await Promise.all(\n state.layers.map(async (serialized) => {\n const fabricObject = (await util.enlivenObjects([serialized.fabricObject]))[0] as\n | FabricObject\n | undefined;\n if (!fabricObject) {\n const source = serialized.fabricObject.src;\n if (typeof source === 'string' && source.startsWith('blob:')) {\n throw new Error(`Failed to restore expired object URL: ${source}`);\n }\n throw new Error(`Failed to restore layer: ${serialized.id}`);\n }\n return { serialized, fabricObject };\n }),\n );\n const stagedBackground = state.backgroundImage\n ? ((await util.enlivenObjects([state.backgroundImage]))[0] as FabricObject | undefined)\n : null;\n if (state.backgroundImage && !stagedBackground) {\n const source = state.backgroundImage.src;\n if (typeof source === 'string' && source.startsWith('blob:')) {\n throw new Error(`Failed to restore expired background object URL: ${source}`);\n }\n throw new Error('Failed to restore background image');\n }\n\n editor.crop.cancel();\n editor.masks.detach();\n editor.layers.clear();\n if (state.canvas.unit) editor.units.setUnit(state.canvas.unit);\n if (state.canvas.dpi !== undefined) editor.units.setDpi(state.canvas.dpi);\n editor.canvas.setDimensions({ width: state.canvas.width, height: state.canvas.height });\n\n // setBackground records the design background; history is paused during\n // restore so this does not push a spurious entry. setMockup (below) then\n // applies the correct live canvas background.\n if (state.background !== undefined) {\n editor.setBackground(state.background);\n }\n editor.setBackgroundImageObject(\n stagedBackground ?? null,\n false,\n state.backgroundImageOptions ?? null,\n );\n\n // Missing on legacy states means there was no mockup.\n editor.setMockup(state.mockup ?? null);\n\n for (const item of staged) {\n restoreLayer(editor, item.serialized, item.fabricObject);\n }\n\n editor.canvas.requestRenderAll();\n}\n\nfunction restoreLayer(\n editor: CanvasEditor,\n serialized: SerializedLayer,\n fabricObject: FabricObject,\n): Layer {\n const layer = editor.layers.add(serialized.type, fabricObject, serialized.name, serialized.id);\n\n if (serialized.meta) {\n layer.meta = serialized.meta;\n // Control visibility is view state, not part of the fabric object's data:\n // a restored lock has to be re-applied or the side handles come back.\n if (layer.meta.lockAspect) applyAspectLock(fabricObject, true);\n }\n\n if (!serialized.visible) {\n editor.layers.setVisibility(layer.id, false);\n }\n if (serialized.locked) {\n editor.layers.setLocked(layer.id, true);\n }\n if (serialized.opacity !== 1) {\n editor.layers.setOpacity(layer.id, serialized.opacity);\n }\n\n // The enlivened group already carries its children's geometry; these records\n // re-attach identity (id, name, visibility, meta) to those objects, matched by\n // index. `meta.groupChildren` is the pre-0.6 shape of the same list.\n const childData =\n serialized.children ?? (serialized.meta?.groupChildren as LayerData[] | undefined);\n if (layer.type === 'group' && Array.isArray(childData)) {\n editor.layers.adoptGroupChildren(layer, childData);\n if (layer.meta.groupChildren) delete layer.meta.groupChildren;\n }\n\n return layer;\n}\n","import { StaticCanvas } from 'fabric';\nimport type { Canvas, FabricObject, ImageFormat } from 'fabric';\nimport type { MockupConfig, MockupPrintArea } from './types';\nimport { displaceRgba } from './displacement';\n\nexport interface PngExportOptions {\n multiplier?: number;\n format?: ImageFormat;\n quality?: number;\n}\n\nexport interface CoverPlacement {\n left: number;\n top: number;\n width: number;\n height: number;\n}\n\nexport function computePrintAreaClip(\n area: MockupPrintArea,\n scaleX: number,\n scaleY: number,\n targetWidth: number,\n targetHeight: number,\n): MockupPrintArea {\n const left = Math.max(0, Math.min(targetWidth, area.left * scaleX));\n const top = Math.max(0, Math.min(targetHeight, area.top * scaleY));\n const right = Math.max(left, Math.min(targetWidth, (area.left + area.width) * scaleX));\n const bottom = Math.max(top, Math.min(targetHeight, (area.top + area.height) * scaleY));\n return { left, top, width: right - left, height: bottom - top };\n}\n\n/** Object-fit: cover geometry, exported for deterministic preview/composite tests. */\nexport function computeCoverPlacement(\n sourceWidth: number,\n sourceHeight: number,\n targetWidth: number,\n targetHeight: number,\n): CoverPlacement {\n if (sourceWidth <= 0 || sourceHeight <= 0 || targetWidth <= 0 || targetHeight <= 0) {\n throw new Error('Cover dimensions must be positive');\n }\n const scale = Math.max(targetWidth / sourceWidth, targetHeight / sourceHeight);\n const width = sourceWidth * scale;\n const height = sourceHeight * scale;\n return {\n left: (targetWidth - width) / 2,\n top: (targetHeight - height) / 2,\n width,\n height,\n };\n}\n\nfunction canvasElementToBlob(\n output: HTMLCanvasElement,\n format: ImageFormat,\n quality: number,\n): Promise<Blob> {\n const mime = format === 'jpeg' ? 'image/jpeg' : `image/${format}`;\n return new Promise<Blob>((resolve, reject) => {\n output.toBlob(\n (blob) => (blob ? resolve(blob) : reject(new Error(`Failed to export ${format}`))),\n mime,\n quality,\n );\n });\n}\n\nexport async function exportPNG(canvas: Canvas, options: PngExportOptions = {}): Promise<Blob> {\n const { multiplier = 1, format = 'png' as ImageFormat, quality = 1 } = options;\n const output = canvas.toCanvasElement(multiplier);\n return canvasElementToBlob(output, format, quality);\n}\n\n/** Render cloned objects without mutating the live editor canvas. */\nexport async function exportIsolatedPNG(\n source: Canvas,\n objects: FabricObject[],\n options: PngExportOptions & {\n width?: number;\n height?: number;\n backgroundColor?: string;\n backgroundImage?: FabricObject | null;\n cloneObjects?: boolean;\n } = {},\n): Promise<Blob> {\n const element = source.lowerCanvasEl.ownerDocument.createElement('canvas');\n const canvas = new StaticCanvas(element, {\n width: options.width ?? source.getWidth(),\n height: options.height ?? source.getHeight(),\n backgroundColor: options.backgroundColor || undefined,\n });\n try {\n const clones =\n options.cloneObjects === false\n ? objects\n : await Promise.all(objects.map((object) => object.clone()));\n if (clones.length) canvas.add(...clones);\n if (options.backgroundImage) canvas.backgroundImage = await options.backgroundImage.clone();\n canvas.requestRenderAll();\n // Awaited, not returned: `finally` would otherwise dispose the canvas while\n // the export is still reading from it.\n return await exportPNG(canvas as unknown as Canvas, options);\n } finally {\n canvas.dispose();\n }\n}\n\n/**\n * Render just the print-area rectangle, on transparency.\n *\n * This is the file a print provider receives: the design alone, cropped to the\n * printable rectangle, with no garment behind it and no canvas background baked\n * in — so it is rendered from cloned objects rather than off the live canvas.\n */\nexport async function exportPrintArea(\n source: Canvas,\n area: MockupPrintArea,\n options: PngExportOptions = {},\n): Promise<Blob> {\n const { multiplier = 1, format = 'png' as ImageFormat, quality = 1 } = options;\n const width = source.getWidth();\n const height = source.getHeight();\n const clip = computePrintAreaClip(\n area,\n multiplier,\n multiplier,\n width * multiplier,\n height * multiplier,\n );\n if (clip.width <= 0 || clip.height <= 0) {\n throw new Error('Print area does not overlap the canvas');\n }\n\n const element = source.lowerCanvasEl.ownerDocument.createElement('canvas');\n const canvas = new StaticCanvas(element, { width, height });\n try {\n const clones = await Promise.all(source.getObjects().map((object) => object.clone()));\n if (clones.length) canvas.add(...clones);\n canvas.requestRenderAll();\n const rendered = canvas.toCanvasElement(multiplier);\n const output = rendered.ownerDocument.createElement('canvas');\n output.width = Math.max(1, Math.round(clip.width));\n output.height = Math.max(1, Math.round(clip.height));\n const context = output.getContext('2d');\n if (!context) throw new Error('2D canvas context is unavailable');\n context.drawImage(rendered, -clip.left, -clip.top);\n // Awaited, not returned: `finally` would dispose the canvas mid-read.\n return await canvasElementToBlob(output, format, quality);\n } finally {\n canvas.dispose();\n }\n}\n\n/** Rasterize the browser mockup preview together with the transparent design. */\nexport async function exportMockup(\n canvas: Canvas,\n mockup: MockupConfig,\n options: PngExportOptions = {},\n): Promise<Blob> {\n const { multiplier = 1, format = 'png' as ImageFormat, quality = 1 } = options;\n const design = canvas.toCanvasElement(multiplier);\n const output = design.ownerDocument.createElement('canvas');\n output.width = design.width;\n output.height = design.height;\n const context = output.getContext('2d');\n if (!context) throw new Error('2D canvas context is unavailable');\n\n const loadImage = (url: string) =>\n new Promise<HTMLImageElement>((resolve, reject) => {\n const element = new Image();\n element.crossOrigin = 'anonymous';\n element.onload = () => resolve(element);\n element.onerror = () => reject(new Error(`Failed to load mockup image: ${url}`));\n element.src = url;\n });\n const drawCover = (\n image: HTMLImageElement,\n targetContext: CanvasRenderingContext2D = context,\n ) => {\n const placement = computeCoverPlacement(\n image.naturalWidth || image.width,\n image.naturalHeight || image.height,\n output.width,\n output.height,\n );\n targetContext.drawImage(\n image,\n placement.left,\n placement.top,\n placement.width,\n placement.height,\n );\n };\n\n // Full-size scratch buffers, released explicitly in the finally below: a\n // detached canvas element can hold its backing store well past its last\n // reference, and a 4K mockup allocates three of them per export.\n const scratch: HTMLCanvasElement[] = [design];\n try {\n drawCover(await loadImage(mockup.image));\n let compositedDesign: CanvasImageSource = design;\n if (mockup.displacement) {\n const sourceContext = design.getContext('2d');\n if (!sourceContext) throw new Error('2D design context is unavailable');\n const mapCanvas = design.ownerDocument.createElement('canvas');\n scratch.push(mapCanvas);\n mapCanvas.width = design.width;\n mapCanvas.height = design.height;\n const mapContext = mapCanvas.getContext('2d');\n if (!mapContext) throw new Error('2D displacement-map context is unavailable');\n drawCover(await loadImage(mockup.displacement.image), mapContext);\n\n const warped = design.ownerDocument.createElement('canvas');\n scratch.push(warped);\n warped.width = design.width;\n warped.height = design.height;\n const warpedContext = warped.getContext('2d');\n if (!warpedContext) throw new Error('2D displaced-design context is unavailable');\n let sourcePixels: Uint8ClampedArray;\n let mapPixels: Uint8ClampedArray;\n try {\n sourcePixels = sourceContext.getImageData(0, 0, design.width, design.height).data;\n mapPixels = mapContext.getImageData(0, 0, design.width, design.height).data;\n } catch (error) {\n throw new Error('Failed to apply mockup displacement map; verify image CORS access', {\n cause: error,\n });\n }\n const pixels = displaceRgba(sourcePixels, mapPixels, design.width, design.height, {\n ...mockup.displacement,\n scaleX: (mockup.displacement.scaleX ?? 10) * multiplier,\n scaleY: (mockup.displacement.scaleY ?? 10) * multiplier,\n });\n const imageData = warpedContext.createImageData(design.width, design.height);\n imageData.data.set(pixels);\n warpedContext.putImageData(imageData, 0, 0);\n compositedDesign = warped;\n }\n context.save();\n if (mockup.printArea && mockup.clipToPrintArea !== false) {\n const clip = computePrintAreaClip(\n mockup.printArea,\n output.width / canvas.getWidth(),\n output.height / canvas.getHeight(),\n output.width,\n output.height,\n );\n context.beginPath();\n context.rect(clip.left, clip.top, clip.width, clip.height);\n context.clip();\n }\n context.globalAlpha = Math.max(0, Math.min(1, mockup.designOpacity ?? 1));\n context.globalCompositeOperation =\n !mockup.designBlendMode || mockup.designBlendMode === 'normal'\n ? 'source-over'\n : mockup.designBlendMode;\n context.drawImage(compositedDesign, 0, 0);\n context.restore();\n\n if (mockup.overlay) {\n context.save();\n context.globalAlpha = Math.max(0, Math.min(1, mockup.overlay.opacity ?? 1));\n context.globalCompositeOperation =\n mockup.overlay.blendMode === 'normal'\n ? 'source-over'\n : (mockup.overlay.blendMode ?? 'multiply');\n drawCover(await loadImage(mockup.overlay.image));\n context.restore();\n }\n return await canvasElementToBlob(output, format, quality);\n } finally {\n for (const element of scratch) {\n element.width = 0;\n element.height = 0;\n }\n }\n}\n\nexport function exportSVG(canvas: Canvas): string {\n return canvas.toSVG();\n}\n\nexport function exportDataURL(canvas: Canvas, format: ImageFormat = 'png', multiplier = 1): string {\n return canvas.toDataURL({ format, multiplier });\n}\n","import type { MockupDisplacement, MockupDisplacementChannel } from './types';\n\nconst CHANNEL_INDEX: Record<MockupDisplacementChannel, number> = {\n red: 0,\n green: 1,\n blue: 2,\n alpha: 3,\n};\n\nfunction finiteScale(value: number | undefined, fallback: number, label: string): number {\n const resolved = value ?? fallback;\n if (!Number.isFinite(resolved)) throw new Error(`${label} must be finite`);\n return resolved;\n}\n\nfunction sample(\n source: Uint8ClampedArray,\n width: number,\n height: number,\n x: number,\n y: number,\n channel: number,\n): number {\n const clampedX = Math.max(0, Math.min(width - 1, x));\n const clampedY = Math.max(0, Math.min(height - 1, y));\n const x0 = Math.floor(clampedX);\n const y0 = Math.floor(clampedY);\n const x1 = Math.min(width - 1, x0 + 1);\n const y1 = Math.min(height - 1, y0 + 1);\n const tx = clampedX - x0;\n const ty = clampedY - y0;\n const top =\n source[(y0 * width + x0) * 4 + channel] * (1 - tx) +\n source[(y0 * width + x1) * 4 + channel] * tx;\n const bottom =\n source[(y1 * width + x0) * 4 + channel] * (1 - tx) +\n source[(y1 * width + x1) * 4 + channel] * tx;\n return top * (1 - ty) + bottom * ty;\n}\n\n/**\n * Warp RGBA pixels with an equally sized channel map. A channel value of 128\n * is neutral; 0 and 255 move by the configured negative/positive maximum.\n */\nexport function displaceRgba(\n source: Uint8ClampedArray,\n map: Uint8ClampedArray,\n width: number,\n height: number,\n options: Omit<MockupDisplacement, 'image'>,\n): Uint8ClampedArray {\n if (!Number.isInteger(width) || !Number.isInteger(height) || width <= 0 || height <= 0) {\n throw new Error('Displacement dimensions must be positive integers');\n }\n const expectedLength = width * height * 4;\n if (source.length !== expectedLength || map.length !== expectedLength) {\n throw new Error('Displacement source and map must match the requested dimensions');\n }\n\n const scaleX = finiteScale(options.scaleX, 10, 'Displacement scaleX');\n const scaleY = finiteScale(options.scaleY, 10, 'Displacement scaleY');\n const channelX = CHANNEL_INDEX[options.channelX ?? 'red'];\n const channelY = CHANNEL_INDEX[options.channelY ?? 'green'];\n const output = new Uint8ClampedArray(expectedLength);\n\n for (let y = 0; y < height; y += 1) {\n for (let x = 0; x < width; x += 1) {\n const offset = (y * width + x) * 4;\n const sourceX = x + ((map[offset + channelX] - 128) / 127) * scaleX;\n const sourceY = y + ((map[offset + channelY] - 128) / 127) * scaleY;\n for (let channel = 0; channel < 4; channel += 1) {\n output[offset + channel] = Math.round(\n sample(source, width, height, sourceX, sourceY, channel),\n );\n }\n }\n }\n return output;\n}\n","/** XML text/attribute escaping for values interpolated into an SVG document. */\nexport function escapeXml(value: string | number): string {\n return String(value)\n .replaceAll('&', '&amp;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;')\n .replaceAll('\"', '&quot;')\n .replaceAll(\"'\", '&apos;');\n}\n\n/**\n * Strip active and externally-loaded content from an SVG before it is parsed\n * into canvas objects.\n *\n * This is the single implementation of the control — every path that turns\n * untrusted SVG into layers must call it, so it is exported rather than\n * re-declared per package.\n */\nexport function sanitizeSvg(svg: string): string {\n const document = new DOMParser().parseFromString(svg, 'image/svg+xml');\n if (document.querySelector('parsererror')) throw new Error('Invalid template SVG');\n document\n .querySelectorAll('script, foreignObject, iframe, object, embed, link, style')\n .forEach((node) => node.remove());\n document.querySelectorAll('*').forEach((node) => {\n for (const attribute of [...node.attributes]) {\n const name = attribute.name.toLowerCase();\n const value = attribute.value.trim().toLowerCase();\n const isLink = name === 'href' || name === 'xlink:href' || name === 'src';\n const safeLink =\n value.startsWith('#') || /^data:image\\/(?:png|jpeg|webp|gif);base64,/.test(value);\n if (\n name.startsWith('on') ||\n (isLink && !safeLink) ||\n (/url\\s*\\(/.test(value) && !/url\\s*\\(\\s*['\"]?#/.test(value)) ||\n /(?:javascript:|expression\\s*\\()/.test(value)\n ) {\n node.removeAttribute(attribute.name);\n }\n }\n });\n return new XMLSerializer().serializeToString(document.documentElement);\n}\n","import type { FontDefinition } from './types';\n\nfunction fontSource(source: string): string {\n return /^(?:url|local)\\(/.test(source.trim()) ? source : `url(${JSON.stringify(source)})`;\n}\n\nfunction mimeForSource(source: string): string {\n const path = source.split(/[?#]/)[0].toLowerCase();\n if (path.endsWith('.woff2')) return 'font/woff2';\n if (path.endsWith('.woff')) return 'font/woff';\n if (path.endsWith('.otf')) return 'font/otf';\n return 'font/ttf';\n}\n\nfunction arrayBufferToBase64(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer);\n let binary = '';\n for (let index = 0; index < bytes.length; index += 0x8000) {\n binary += String.fromCharCode(...bytes.subarray(index, index + 0x8000));\n }\n return btoa(binary);\n}\n\n/**\n * Quote a value for a CSS string token. JSON escaping covers quotes and\n * backslashes; `<`/`>`/`&` are additionally emitted as CSS hex escapes so a\n * crafted family name cannot close the `<style>` element when the exported SVG\n * is inlined into an HTML document.\n */\nfunction cssString(value: string): string {\n return JSON.stringify(value).replace(/[<>&]/g, (char) => `\\\\${char.charCodeAt(0).toString(16)} `);\n}\n\nconst SAFE_WEIGHT = /^(?:normal|bold|bolder|lighter|[1-9]\\d{0,2}(?:\\s+[1-9]\\d{0,2})?)$/i;\nconst SAFE_STYLE = /^(?:normal|italic|oblique(?:\\s+-?\\d+(?:\\.\\d+)?deg)?)$/i;\nconst SAFE_DISPLAY = /^(?:auto|block|swap|fallback|optional)$/i;\n\nfunction cssKeyword(value: string | undefined, pattern: RegExp, fallback: string): string {\n const trimmed = value?.trim();\n return trimmed && pattern.test(trimmed) ? trimmed : fallback;\n}\n\nfunction sourceUrl(source: string): string | null {\n const trimmed = source.trim();\n if (trimmed.startsWith('data:')) return trimmed;\n const match = trimmed.match(/^url\\(\\s*(['\"]?)(.*?)\\1\\s*\\)/i);\n if (match) return match[2];\n if (/^local\\(/i.test(trimmed)) return null;\n return trimmed;\n}\n\n/**\n * The font name inside a `local(...)` source, or null for any other form.\n * The name may not contain CSS punctuation, so a source that only *starts*\n * with `local(` cannot smuggle extra declarations through as a \"name\".\n */\nfunction localName(source: string): string | null {\n const match = source.trim().match(/^local\\(\\s*(['\"]?)([^)\"'{};]*)\\1\\s*\\)$/i);\n return match ? match[2].trim() || null : null;\n}\n\n/** Browser font loader and SVG embedding registry. */\nexport class FontRegistry {\n private definitions = new Map<string, FontDefinition>();\n private loads = new Map<string, Promise<FontFace>>();\n\n register(definition: FontDefinition): void {\n if (!definition.family.trim() || !definition.source.trim()) {\n throw new Error('Font family and source are required');\n }\n this.definitions.set(definition.family, { ...definition });\n this.loads.delete(definition.family);\n }\n\n unregister(family: string): boolean {\n this.loads.delete(family);\n return this.definitions.delete(family);\n }\n\n getAll(): FontDefinition[] {\n return [...this.definitions.values()].map((definition) => ({ ...definition }));\n }\n\n load(family: string): Promise<FontFace> {\n const cached = this.loads.get(family);\n if (cached) return cached;\n const definition = this.definitions.get(family);\n if (!definition) return Promise.reject(new Error(`Font is not registered: ${family}`));\n if (typeof FontFace === 'undefined' || typeof document === 'undefined') {\n return Promise.reject(new Error('Font loading requires a browser FontFace API'));\n }\n const promise = new FontFace(definition.family, fontSource(definition.source), {\n weight: definition.weight,\n style: definition.style,\n display: definition.display,\n })\n .load()\n .then((font) => {\n document.fonts.add(font);\n return font;\n });\n promise.catch(() => {\n if (this.loads.get(family) === promise) this.loads.delete(family);\n });\n this.loads.set(family, promise);\n return promise;\n }\n\n async ready(): Promise<void> {\n if (this.definitions.size === 0) return;\n await Promise.all([...this.definitions.keys()].map((family) => this.load(family)));\n await document.fonts.ready;\n }\n\n async getEmbeddedCss(): Promise<string> {\n const rules = await Promise.all(\n this.getAll().map(async (definition) => {\n // Every branch re-quotes the source rather than passing the registered\n // string through, so a definition can never inject raw CSS into the\n // `<style>` block this produces.\n const url = sourceUrl(definition.source);\n let cssSource: string;\n if (url && !url.startsWith('data:')) {\n const response = await fetch(url);\n if (!response.ok) throw new Error(`Failed to fetch font: ${url}`);\n const data = arrayBufferToBase64(await response.arrayBuffer());\n const mime = response.headers.get('content-type') || mimeForSource(url);\n cssSource = `url(${cssString(`data:${mime};base64,${data}`)})`;\n } else if (url) {\n cssSource = `url(${cssString(url)})`;\n } else {\n const name = localName(definition.source);\n if (!name) {\n throw new Error(`Unsupported font source for embedding: ${definition.family}`);\n }\n cssSource = `local(${cssString(name)})`;\n }\n const weight = cssKeyword(definition.weight, SAFE_WEIGHT, 'normal');\n const style = cssKeyword(definition.style, SAFE_STYLE, 'normal');\n const display = cssKeyword(definition.display, SAFE_DISPLAY, 'swap');\n return `@font-face{font-family:${cssString(definition.family)};src:${cssSource};font-weight:${weight};font-style:${style};font-display:${display}}`;\n }),\n );\n return rules.join('\\n');\n }\n}\n","import type { LicenseConfig, LicenseStatus } from './types';\n\nfunction domainMatches(hostname: string, pattern: string): boolean {\n const host = hostname.toLowerCase();\n const expected = pattern.toLowerCase();\n if (expected.startsWith('*.')) {\n const suffix = expected.slice(1);\n return host.endsWith(suffix) && host.length > suffix.length;\n }\n return host === expected;\n}\n\nfunction isLocal(hostname: string): boolean {\n return (\n hostname === 'localhost' ||\n hostname === '127.0.0.1' ||\n hostname === '::1' ||\n hostname.endsWith('.localhost')\n );\n}\n\n/** Inert, honor-system licensing and usage seam; it never performs a network request. */\nexport class LicenseManager {\n private status: LicenseStatus;\n private readyPromise: Promise<LicenseStatus>;\n\n constructor(private config: LicenseConfig = {}) {\n const hostname = config.hostname ?? globalThis.location?.hostname ?? 'localhost';\n const environment = config.environment ?? 'development';\n if (environment !== 'production' || isLocal(hostname)) {\n this.status = { state: 'exempt', payload: null };\n this.readyPromise = Promise.resolve(this.status);\n } else if (!config.key) {\n this.status = { state: 'community', payload: null };\n this.readyPromise = Promise.resolve(this.status);\n } else {\n this.status = { state: 'checking', payload: null };\n this.readyPromise = this.validate(config.key, hostname);\n }\n }\n\n getStatus(): LicenseStatus {\n return this.status;\n }\n\n ready(): Promise<LicenseStatus> {\n return this.readyPromise;\n }\n\n hasFeature(feature: string): boolean {\n return this.status.state === 'valid' && (this.status.payload.features ?? []).includes(feature);\n }\n\n track(name: string): void {\n this.config.onUsage?.({\n name,\n at: new Date().toISOString(),\n licenseId: this.status.state === 'valid' ? this.status.payload.id : undefined,\n });\n }\n\n private async validate(key: string, hostname: string): Promise<LicenseStatus> {\n const payload = (await this.config.verifyOffline?.(key)) ?? null;\n if (!payload) return (this.status = { state: 'invalid', payload: null });\n if (payload.expiresAt && Date.parse(payload.expiresAt) < Date.now()) {\n return (this.status = { state: 'expired', payload });\n }\n if (!payload.domains.some((domain) => domainMatches(hostname, domain))) {\n return (this.status = { state: 'domain-mismatch', payload });\n }\n return (this.status = { state: 'valid', payload });\n }\n}\n","import type { CanvasEditor } from './editor';\nimport type { EditorState, ProjectPage, ProjectState } from './types';\nimport { generateId } from './utils/id';\n\n/** Multi-page document state bound to one live editor canvas. */\nexport class ProjectManager {\n private pages: ProjectPage[];\n private activePageId: string;\n\n constructor(private editor: CanvasEditor) {\n const first = { id: generateId(), name: 'Page 1', state: editor.toJSON() };\n this.pages = [first];\n this.activePageId = first.id;\n }\n\n getAll(): Array<{ id: string; name: string }> {\n return this.pages.map(({ id, name }) => ({ id, name }));\n }\n\n getActivePageId(): string {\n return this.activePageId;\n }\n\n add(name = `Page ${this.pages.length + 1}`, cloneCurrent = false): string {\n this.saveCurrent();\n const source = structuredClone(this.editor.toJSON());\n const state = cloneCurrent ? source : this.blankState(source);\n const page = { id: generateId(), name, state };\n this.pages.push(page);\n this.emitChanged();\n return page.id;\n }\n\n async switchTo(id: string): Promise<boolean> {\n if (id === this.activePageId) return true;\n const page = this.pages.find((candidate) => candidate.id === id);\n if (!page) return false;\n this.saveCurrent();\n await this.editor.fromJSON(structuredClone(page.state));\n this.activePageId = id;\n this.emitChanged();\n return true;\n }\n\n async duplicate(id: string): Promise<string | null> {\n this.saveCurrent();\n const source = this.pages.find((page) => page.id === id);\n if (!source) return null;\n const page = {\n id: generateId(),\n name: `${source.name} copy`,\n state: structuredClone(source.state),\n };\n const index = this.pages.indexOf(source);\n this.pages.splice(index + 1, 0, page);\n this.emitChanged();\n return page.id;\n }\n\n async remove(id: string): Promise<boolean> {\n if (this.pages.length === 1) return false;\n const index = this.pages.findIndex((page) => page.id === id);\n if (index < 0) return false;\n if (id === this.activePageId) {\n const next = this.pages[index + 1] ?? this.pages[index - 1];\n await this.editor.fromJSON(structuredClone(next.state));\n this.activePageId = next.id;\n }\n this.pages.splice(index, 1);\n this.emitChanged();\n return true;\n }\n\n rename(id: string, name: string): boolean {\n const page = this.pages.find((candidate) => candidate.id === id);\n const trimmed = name.trim();\n if (!page || !trimmed || page.name === trimmed) return false;\n page.name = trimmed;\n this.emitChanged();\n return true;\n }\n\n reorder(id: string, newIndex: number): boolean {\n const index = this.pages.findIndex((page) => page.id === id);\n if (index < 0 || !Number.isFinite(newIndex)) return false;\n const target = Math.max(0, Math.min(this.pages.length - 1, Math.round(newIndex)));\n if (target === index) return false;\n const [page] = this.pages.splice(index, 1);\n this.pages.splice(target, 0, page);\n this.emitChanged();\n return true;\n }\n\n toJSON(): ProjectState {\n this.saveCurrent();\n return {\n version: '1.0.0',\n activePageId: this.activePageId,\n pages: structuredClone(this.pages),\n };\n }\n\n async fromJSON(project: ProjectState): Promise<void> {\n if (\n project?.version !== '1.0.0' ||\n !Array.isArray(project.pages) ||\n project.pages.length === 0 ||\n !project.pages.some((page) => page.id === project.activePageId)\n ) {\n throw new Error('Invalid project state');\n }\n const pages = structuredClone(project.pages);\n const active = pages.find((page) => page.id === project.activePageId)!;\n await this.editor.fromJSON(structuredClone(active.state));\n this.pages = pages;\n this.activePageId = active.id;\n this.emitChanged();\n }\n\n private saveCurrent(): void {\n const page = this.pages.find((candidate) => candidate.id === this.activePageId);\n if (page) page.state = structuredClone(this.editor.toJSON());\n }\n\n private blankState(source: EditorState): EditorState {\n return { ...source, layers: [], mockup: null };\n }\n\n private emitChanged(): void {\n this.editor.events.emit('project:changed', {\n activePageId: this.activePageId,\n pages: this.getAll(),\n });\n }\n}\n","import { FabricImage } from 'fabric';\nimport type { CanvasEditor } from './editor';\nimport type {\n MaskBrushOptions,\n MaskPoint,\n MaskRefinementPrompt,\n MaskRefinementProvider,\n MaskRefinementResult,\n} from './types';\nimport type { Layer } from './layer';\nimport { clamp } from './utils/clamp';\n\nexport type MaskRefinementErrorCode = 'not-found' | 'cancelled' | 'provider' | 'invalid-result';\n\nexport class MaskRefinementError extends Error {\n constructor(\n readonly code: MaskRefinementErrorCode,\n message: string,\n readonly cause?: unknown,\n ) {\n super(message);\n this.name = 'MaskRefinementError';\n }\n}\n\nexport interface MaskPerformanceSample {\n width: number;\n height: number;\n backingBytes: number;\n strokeBackupBytes: number;\n estimatedPeakBytes: number;\n historyBytes: number;\n interactionLatencyMs: number;\n usedJsHeapBytes?: number;\n elapsedMs: number;\n}\n\n/** Raster-mask editing without exposing Fabric brush classes in the public contract. */\nexport class MaskController {\n private backing: HTMLCanvasElement | null = null;\n private context: CanvasRenderingContext2D | null = null;\n private layerId: string | null = null;\n private brush: MaskBrushOptions | null = null;\n private previousPoint: MaskPoint | null = null;\n private strokeBackup: ImageData | null = null;\n private strokeStartedAt: number | null = null;\n private lastInteractionLatencyMs = 0;\n private refinement: AbortController | null = null;\n private disposed = false;\n\n constructor(private readonly editor: CanvasEditor) {}\n\n async create(\n width = this.editor.canvas.getWidth(),\n height = this.editor.canvas.getHeight(),\n ): Promise<Layer> {\n this.assertActive();\n if (!Number.isInteger(width) || !Number.isInteger(height) || width <= 0 || height <= 0) {\n throw new Error('Mask dimensions must be positive integers');\n }\n const backing = this.makeCanvas(width, height);\n const image = new FabricImage(backing, {\n left: 0,\n top: 0,\n originX: 'left',\n originY: 'top',\n selectable: false,\n });\n const layer = this.editor.layers.add('mask', image, 'Mask');\n layer.meta.mask = { width, height, revision: 0 };\n this.editor.history.saveImmediate();\n this.attachBacking(layer.id, backing);\n return layer;\n }\n\n attach(layerId: string): void {\n this.assertActive();\n // Swapping the backing store mid-stroke would leave the brush painting into\n // a canvas whose rollback snapshot belongs to the previous attachment.\n this.cancelStroke();\n const layer = this.requireMask(layerId);\n const image = layer.fabricObject as FabricImage;\n const width = layer.meta.mask?.width ?? image.width ?? this.editor.canvas.getWidth();\n const height = layer.meta.mask?.height ?? image.height ?? this.editor.canvas.getHeight();\n const backing = this.makeCanvas(width, height);\n const context = backing.getContext('2d');\n if (!context) throw new Error('2D mask context is unavailable');\n const element = image.getElement();\n if (element) context.drawImage(element, 0, 0, width, height);\n this.attachBacking(layerId, backing);\n }\n\n beginStroke(options: MaskBrushOptions): void {\n this.assertActive();\n if (!this.context || !this.backing || !this.layerId) throw new Error('Attach a mask first');\n if (this.brush) throw new Error('A mask stroke is already active');\n if (!Number.isFinite(options.size) || options.size <= 0) {\n throw new Error('Mask brush size must be positive');\n }\n this.brush = { ...options, hardness: clamp(options.hardness, 0, 1) };\n this.previousPoint = null;\n this.strokeBackup = this.context.getImageData(0, 0, this.backing.width, this.backing.height);\n this.strokeStartedAt = performance.now();\n }\n\n addPoint(point: MaskPoint): void {\n if (!this.brush || !this.context || !this.backing || !this.layerId) {\n throw new Error('No active mask stroke');\n }\n if (!Number.isFinite(point.x) || !Number.isFinite(point.y)) return;\n const previous = this.previousPoint ?? point;\n const distance = Math.hypot(point.x - previous.x, point.y - previous.y);\n const step = Math.max(1, this.brush.size / 4);\n const samples = Math.max(1, Math.ceil(distance / step));\n for (let index = 0; index <= samples; index += 1) {\n const ratio = index / samples;\n this.drawDot({\n x: previous.x + (point.x - previous.x) * ratio,\n y: previous.y + (point.y - previous.y) * ratio,\n });\n }\n this.previousPoint = point;\n (this.requireMask(this.layerId).fabricObject as FabricImage).setElement(this.backing);\n this.editor.canvas.requestRenderAll();\n }\n\n async endStroke(): Promise<void> {\n if (!this.brush || !this.backing || !this.layerId) return;\n const layerId = this.layerId;\n this.brush = null;\n this.previousPoint = null;\n this.strokeBackup = null;\n const dataUrl = this.backing.toDataURL('image/png');\n await this.editor.history.transaction(async () => {\n await this.editor.replaceImageSource(layerId, dataUrl);\n const layer = this.requireMask(layerId);\n if (layer.meta.mask) layer.meta.mask.revision += 1;\n });\n this.attach(layerId);\n if (this.strokeStartedAt !== null) {\n this.lastInteractionLatencyMs = performance.now() - this.strokeStartedAt;\n this.strokeStartedAt = null;\n }\n }\n\n cancelStroke(): void {\n if (this.strokeBackup && this.context && this.backing && this.layerId) {\n this.context.putImageData(this.strokeBackup, 0, 0);\n (this.requireMask(this.layerId).fabricObject as FabricImage).setElement(this.backing);\n this.editor.canvas.requestRenderAll();\n }\n this.brush = null;\n this.previousPoint = null;\n this.strokeBackup = null;\n this.strokeStartedAt = null;\n }\n\n isStrokeActive(): boolean {\n return this.brush !== null;\n }\n\n activeLayerId(): string | null {\n return this.layerId;\n }\n\n detach(layerId?: string): void {\n if (layerId && this.layerId !== layerId) return;\n this.cancelStroke();\n this.cancelRefinement();\n this.backing = null;\n this.context = null;\n this.layerId = null;\n }\n\n async refine(\n layerId: string,\n provider: MaskRefinementProvider,\n prompts: MaskRefinementPrompt[],\n options: { signal?: AbortSignal; onProgress?: (progress: number) => void } = {},\n ): Promise<MaskRefinementResult> {\n this.assertActive();\n const layer = this.editor.layers.get(layerId);\n if (!layer || layer.type !== 'mask') {\n throw new MaskRefinementError('not-found', `Mask layer not found: ${layerId}`);\n }\n this.cancelRefinement();\n const controller = new AbortController();\n this.refinement = controller;\n const abort = () => controller.abort(options.signal?.reason);\n options.signal?.addEventListener('abort', abort, { once: true });\n if (options.signal?.aborted) abort();\n try {\n const image = layer.fabricObject as FabricImage;\n const result = await provider.refine(\n {\n mask: image.getSrc(),\n width: layer.meta.mask?.width ?? image.width ?? 1,\n height: layer.meta.mask?.height ?? image.height ?? 1,\n prompts: structuredClone(prompts),\n },\n { signal: controller.signal, onProgress: options.onProgress },\n );\n if (controller.signal.aborted)\n throw new MaskRefinementError('cancelled', 'Mask refinement cancelled');\n // Raster only: history content-addresses raster data URLs, and a vector\n // result would let a third-party provider inject markup into the document.\n if (!/^data:image\\/(?:png|jpeg|webp);base64,/i.test(result.dataUrl)) {\n throw new MaskRefinementError(\n 'invalid-result',\n 'Mask refinement must return a base64 PNG, JPEG, or WebP data URL',\n );\n }\n await this.editor.history.transaction(async () => {\n await this.editor.replaceImageSource(layerId, result.dataUrl);\n if (layer.meta.mask) layer.meta.mask.revision += 1;\n });\n this.attach(layerId);\n return result;\n } catch (error) {\n if (error instanceof MaskRefinementError) throw error;\n if (controller.signal.aborted) {\n throw new MaskRefinementError('cancelled', 'Mask refinement cancelled', error);\n }\n throw new MaskRefinementError('provider', 'Mask refinement provider failed', error);\n } finally {\n options.signal?.removeEventListener('abort', abort);\n if (this.refinement === controller) this.refinement = null;\n }\n }\n\n cancelRefinement(): void {\n this.refinement?.abort(new DOMException('Cancelled', 'AbortError'));\n this.refinement = null;\n }\n\n measure(): MaskPerformanceSample | null {\n if (!this.backing) return null;\n const started = performance.now();\n this.context?.getImageData(0, 0, 1, 1);\n const backingBytes = this.backing.width * this.backing.height * 4;\n const strokeBackupBytes = this.strokeBackup ? backingBytes : 0;\n const memory = performance as Performance & { memory?: { usedJSHeapSize?: number } };\n return {\n width: this.backing.width,\n height: this.backing.height,\n backingBytes,\n strokeBackupBytes,\n // The backing store and rollback ImageData dominate interactive mask\n // memory. Encoded historical rasters are reported separately below.\n estimatedPeakBytes: backingBytes + strokeBackupBytes,\n historyBytes: this.editor.history.getSnapshotBytes(),\n interactionLatencyMs: this.lastInteractionLatencyMs,\n ...(typeof memory.memory?.usedJSHeapSize === 'number'\n ? { usedJsHeapBytes: memory.memory.usedJSHeapSize }\n : {}),\n elapsedMs: performance.now() - started,\n };\n }\n\n dispose(): void {\n this.detach();\n this.disposed = true;\n }\n\n private drawDot(point: MaskPoint): void {\n const context = this.context!;\n const brush = this.brush!;\n const radius = brush.size / 2;\n context.save();\n context.globalCompositeOperation =\n brush.mode === 'subtract' ? 'destination-out' : 'source-over';\n const gradient = context.createRadialGradient(\n point.x,\n point.y,\n radius * brush.hardness,\n point.x,\n point.y,\n radius,\n );\n const color = brush.mode === 'subtract' ? 'rgba(0,0,0,1)' : 'rgba(255,255,255,1)';\n gradient.addColorStop(0, color);\n gradient.addColorStop(1, 'rgba(255,255,255,0)');\n context.fillStyle = gradient;\n context.beginPath();\n context.arc(point.x, point.y, radius, 0, Math.PI * 2);\n context.fill();\n context.restore();\n }\n\n private makeCanvas(width: number, height: number): HTMLCanvasElement {\n const canvas = this.editor.canvas.lowerCanvasEl.ownerDocument.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n return canvas;\n }\n\n private attachBacking(layerId: string, backing: HTMLCanvasElement): void {\n const context = backing.getContext('2d');\n if (!context) throw new Error('2D mask context is unavailable');\n this.layerId = layerId;\n this.backing = backing;\n this.context = context;\n }\n\n private requireMask(layerId: string): Layer {\n const layer = this.editor.layers.get(layerId);\n if (!layer || layer.type !== 'mask') throw new Error(`Mask layer not found: ${layerId}`);\n return layer;\n }\n\n private assertActive(): void {\n if (this.disposed) throw new Error('Mask controller has been disposed');\n }\n}\n","import { Group } from 'fabric';\nimport type { Canvas, FabricObject } from 'fabric';\nimport type { EditorEvents, LayerMaskEntry, LayerMaskMode } from '../types';\nimport type { EventEmitter } from '../events';\nimport type { HistoryManager } from '../history';\nimport type { LayerManager } from '../layer';\nimport { generateId } from '../utils/id';\nimport { needsAbsoluteSpace } from './compose';\nimport { MaskEditController, type MaskEditTarget } from './edit';\nimport { applyRelativeMatrix, fitToBox, toMatrix } from './space';\nimport type { MaskBox } from './host';\nimport { CANVAS_MASK_TARGET, DEFAULT_ENTRY, MaskStackStore } from './store';\n\nexport interface AddMaskOptions {\n name?: string;\n mode?: LayerMaskMode;\n linked?: boolean;\n /** Host data describing where the geometry came from (preset id, generator…). */\n meta?: Record<string, unknown>;\n /** Scale the geometry to the host's box (a number zooms it); default 1. */\n fit?: number | false;\n /**\n * Fit to this box instead of the host's own, in the stack's coordinate space.\n * The whole-design overlay spans the canvas, but a mask on it usually wants to\n * frame the artwork, which occupies part of it.\n */\n box?: { left: number; top: number; width: number; height: number };\n}\n\n/**\n * Stacked, boolean-composed masks — one ordered list per host, where a host is\n * either a layer or the design as a whole (`CANVAS_MASK_TARGET`). Storage and\n * clip composition live in `MaskStackStore`; this class is what a UI drives.\n */\nexport class LayerMaskManager extends MaskStackStore {\n // Committing mid-drag would recompose the group the handle writes into and\n // leave it pointing at a discarded object; the geometry is settled on endEdit.\n private readonly edits = new MaskEditController(this.canvas, () => this.history.save());\n private readonly onLayersChanged = () => this.pin();\n // Selecting a layer means the user has moved on from the mask they had open;\n // leaving both selected would show mask controls for an unrelated layer.\n private readonly onLayerSelected = () => {\n if (this.selected) this.select(null, null);\n };\n private readonly onObjectModified = (event: { target?: FabricObject }) => {\n const object = event.target;\n if (!object) return;\n const layer = this.layers.findByObject(object);\n if (layer) this.reflow(layer.id);\n };\n\n constructor(\n canvas: Canvas,\n layers: LayerManager,\n history: HistoryManager,\n events: EventEmitter<EditorEvents>,\n ) {\n super(canvas, layers, history, events);\n this.events.on('layers:changed', this.onLayersChanged);\n this.events.on('layer:selected', this.onLayerSelected);\n // A linked mask in a canvas-space stack has to be re-derived after the host\n // moves; fabric only does that for us in host space.\n this.canvas.on('object:modified', this.onObjectModified);\n }\n\n dispose(): void {\n this.edits.dispose();\n this.events.off('layers:changed', this.onLayersChanged);\n this.events.off('layer:selected', this.onLayerSelected);\n this.canvas.off('object:modified', this.onObjectModified);\n this.selected = null;\n }\n\n // ─── Geometry editing ────────────────────────────────\n\n /** The mask currently being dragged on the canvas, if any. */\n editing(): MaskEditTarget | null {\n return this.edits.active();\n }\n\n /**\n * Put drag handles on one mask. The stack is composed in canvas space for the\n * duration — a linked mask would otherwise sit in the host's space, where the\n * handle's own canvas coordinates mean something else entirely. `endEdit`\n * returns it to whichever space its entries call for.\n */\n async beginEdit(target: string, maskId: string): Promise<boolean> {\n const host = this.host(target);\n if (!host) return false;\n const entries = this.list(target);\n const index = entries.findIndex((entry) => entry.id === maskId);\n if (index === -1) return false;\n\n this.endEdit(false);\n this.commit(target, host, [...entries], this.unwrap(target, host), false, true);\n const group = host.clipPath instanceof Group ? host.clipPath : null;\n if (!group) return false;\n const children = group.getObjects();\n // The implicit base child (a stack opening with a cut) shifts every entry.\n const child = children[children.length - entries.length + index];\n if (!child) return false;\n\n this.select(target, maskId);\n return this.edits.begin({ target, maskId }, group, child);\n }\n\n /** Take the handles down and settle the stack back into its own space. */\n endEdit(save = true): void {\n const editing = this.edits.active();\n this.edits.end();\n if (editing) this.rebuild(editing.target, save);\n }\n\n // ─── Selection ───────────────────────────────────────\n\n getSelected(): { target: string; maskId: string } | null {\n return this.selected;\n }\n\n select(target: string | null, maskId: string | null): void {\n this.selected = target && maskId ? { target, maskId } : null;\n this.events.emit('mask:selected', { target, maskId: this.selected ? maskId : null });\n }\n\n // ─── Mutations ───────────────────────────────────────\n\n add(target: string, object: FabricObject, options: AddMaskOptions = {}): LayerMaskEntry | null {\n const host = this.host(target, true);\n if (!host) return null;\n const sources = this.unwrap(target, host);\n const entries = this.entriesFor(target, sources);\n const entry: LayerMaskEntry = {\n ...DEFAULT_ENTRY,\n id: generateId(),\n name: options.name ?? 'Mask',\n ...(options.mode ? { mode: options.mode } : {}),\n ...(options.linked === undefined ? {} : { linked: options.linked }),\n ...(options.meta ? { meta: options.meta } : {}),\n };\n // The canvas stack has no host transform to follow, so \"linked\" is meaningless\n // there — pin it, or a re-fit would fight the overlay's own full-canvas box.\n if (target === CANVAS_MASK_TARGET) entry.linked = false;\n\n if (options.fit !== false) {\n fitToBox(object, options.box ?? this.hostBox(target), options.fit ?? 1);\n }\n sources.push(object);\n entries.push(entry);\n this.commit(target, host, entries, sources);\n return entry;\n }\n\n /** Swap one mask's geometry, keeping its identity, mode and position in the stack. */\n replaceGeometry(\n target: string,\n maskId: string,\n object: FabricObject,\n options: AddMaskOptions = {},\n ): boolean {\n const host = this.host(target);\n if (!host) return false;\n const entries = [...this.list(target)];\n const index = entries.findIndex((entry) => entry.id === maskId);\n if (index === -1) return false;\n const sources = this.unwrap(target, host);\n if (options.fit !== false) {\n fitToBox(object, options.box ?? this.hostBox(target), options.fit ?? 1);\n }\n sources[index] = object;\n entries[index] = {\n ...entries[index],\n ...(options.name ? { name: options.name } : {}),\n ...(options.meta ? { meta: options.meta } : {}),\n };\n this.commit(target, host, entries, sources);\n return true;\n }\n\n /**\n * Re-fit one mask to its host's box (or `box`) at `fit` scale, keeping the\n * geometry it already has. This is what a zoom control drives: re-picking the\n * mask would cost another render of a generated alpha map just to resize it.\n */\n refit(\n target: string,\n maskId: string,\n options: { fit?: number; box?: MaskBox; save?: boolean } = {},\n ): boolean {\n const host = this.host(target);\n if (!host) return false;\n const entries = [...this.list(target)];\n const index = entries.findIndex((entry) => entry.id === maskId);\n if (index === -1) return false;\n const sources = this.unwrap(target, host);\n const source = sources[index];\n if (!source) return false;\n fitToBox(source, options.box ?? this.hostBox(target), options.fit ?? 1);\n this.commit(target, host, entries, sources, options.save ?? true);\n return true;\n }\n\n remove(target: string, maskId: string): boolean {\n const host = this.host(target);\n if (!host) return false;\n const entries = [...this.list(target)];\n const index = entries.findIndex((entry) => entry.id === maskId);\n if (index === -1) return false;\n const sources = this.unwrap(target, host);\n entries.splice(index, 1);\n sources.splice(index, 1);\n if (this.selected?.maskId === maskId) this.select(null, null);\n this.commit(target, host, entries, sources);\n return true;\n }\n\n clear(target: string): boolean {\n const host = this.host(target);\n if (!host) return false;\n if (this.list(target).length === 0) return false;\n if (this.selected?.target === target) this.select(null, null);\n this.commit(target, host, [], []);\n return true;\n }\n\n reorder(target: string, maskId: string, index: number): boolean {\n const host = this.host(target);\n if (!host) return false;\n const entries = [...this.list(target)];\n const from = entries.findIndex((entry) => entry.id === maskId);\n if (from === -1) return false;\n const to = Math.max(0, Math.min(entries.length - 1, Math.round(index)));\n if (from === to) return false;\n const sources = this.unwrap(target, host);\n const [entry] = entries.splice(from, 1);\n const [source] = sources.splice(from, 1);\n entries.splice(to, 0, entry);\n sources.splice(to, 0, source);\n this.commit(target, host, entries, sources);\n return true;\n }\n\n /** Replace a mask's host metadata (which preset or generator produced it). */\n setMeta(target: string, maskId: string, meta: Record<string, unknown>): boolean {\n return this.patch(target, maskId, () => ({ meta }));\n }\n\n setMode(target: string, maskId: string, mode: LayerMaskMode): boolean {\n return this.patch(target, maskId, (entry) => (entry.mode === mode ? null : { mode }));\n }\n\n setVisible(target: string, maskId: string, visible: boolean): boolean {\n return this.patch(target, maskId, (entry) => (entry.visible === visible ? null : { visible }));\n }\n\n setOpacity(target: string, maskId: string, opacity: number): boolean {\n if (!Number.isFinite(opacity)) return false;\n const next = Math.max(0, Math.min(1, opacity));\n return this.patch(target, maskId, (entry) =>\n entry.opacity === next ? null : { opacity: next },\n );\n }\n\n setName(target: string, maskId: string, name: string): boolean {\n const trimmed = name.trim();\n if (!trimmed) return false;\n return this.patch(target, maskId, (entry) =>\n entry.name === trimmed ? null : { name: trimmed },\n );\n }\n\n /**\n * Link or unlink one mask. Unlinking pins it where it currently appears;\n * re-linking records its position relative to the host so later host moves\n * carry it along.\n */\n setLinked(target: string, maskId: string, linked: boolean): boolean {\n if (target === CANVAS_MASK_TARGET) return false;\n const host = this.host(target);\n if (!host) return false;\n const entries = [...this.list(target)];\n const index = entries.findIndex((entry) => entry.id === maskId);\n if (index === -1 || entries[index].linked === linked) return false;\n const sources = this.unwrap(target, host);\n entries[index] = { ...entries[index], linked };\n this.commit(target, host, entries, sources);\n return true;\n }\n\n /**\n * Consume a layer, turning its artwork into a mask. Without an explicit target\n * it masks the layer directly beneath it, and the bottom layer masks the whole\n * design — there is nothing under it to clip.\n */\n convertLayer(layerId: string, target?: string): { target: string; entry: LayerMaskEntry } | null {\n const layer = this.layers.get(layerId);\n if (!layer || layer.meta.canvasMask) return null;\n const ordered = this.layers.getAll();\n const index = ordered.findIndex((candidate) => candidate.id === layerId);\n const below = index > 0 ? ordered[index - 1] : undefined;\n const resolved = target ?? (below && !below.meta.canvasMask ? below.id : CANVAS_MASK_TARGET);\n if (resolved === layerId) return null;\n\n const object = layer.fabricObject;\n // A shape authored with no fill would mask nothing; images and text carry\n // their own alpha, which is exactly what a mask reads.\n if (!object.fill && object.type !== 'image') object.set({ fill: '#000000' });\n\n // One checkpoint for the whole conversion: undoing it has to bring the layer\n // back, not leave the artwork deleted with the mask removed.\n this.history.beginTransaction();\n try {\n // Drop the canvas selection first: removing an active object makes fabric\n // fire `selection:cleared`, which clears the mask selection — including the\n // one this method is about to make.\n if (this.canvas.getActiveObject() === object) this.canvas.discardActiveObject();\n this.canvas.remove(object);\n this.layers.remove(layerId);\n const entry = this.add(resolved, object, { name: layer.name, fit: false });\n return entry ? { target: resolved, entry } : null;\n } finally {\n this.history.endTransaction();\n }\n }\n\n // ─── Rebuild / restore ───────────────────────────────\n\n /** Recompose one stack's clip from the geometry it already holds. */\n rebuild(target: string, save = false): void {\n const host = this.host(target);\n if (!host) return;\n const sources = this.unwrap(target, host);\n if (sources.length === 0) return;\n this.commit(target, host, this.entriesFor(target, sources), sources, save);\n }\n\n /** Re-derive linked masks after the host moved (canvas-space stacks only). */\n private reflow(target: string): void {\n const host = this.host(target);\n if (!host) return;\n const entries = this.list(target);\n if (entries.length === 0 || !needsAbsoluteSpace(entries)) return;\n if (!entries.some((entry) => entry.linked && entry.rel)) return;\n const sources = this.unwrap(target, host);\n entries.forEach((entry, index) => {\n const source = sources[index];\n const rel = toMatrix(entry.rel);\n if (!source || !entry.linked || !rel) return;\n applyRelativeMatrix(source, host, rel);\n });\n this.commit(target, host, [...entries], sources);\n }\n\n /**\n * Adopt a clip this manager did not install — a host's own single `clipPath` —\n * as a one-entry stack, so it shows up in the UI as a mask row before anything\n * is added to it. A mask preset is left alone unless asked for by name: it is\n * still owned by `MaskPresetManager` until a stack operation takes it over.\n */\n adopt(target: string, name?: string): LayerMaskEntry | null {\n const layer = this.hostLayer(target);\n const clip = layer?.fabricObject.clipPath;\n // A pattern strips and restores the layer's clip on its own; that clip is\n // the tiling's, not the user's mask.\n if (!layer || !clip || layer.meta.pattern) return null;\n if ((layer.meta.maskStack ?? []).length > 0) return null;\n const entry: LayerMaskEntry = {\n ...DEFAULT_ENTRY,\n id: generateId(),\n name: name ?? 'Mask',\n linked: target === CANVAS_MASK_TARGET ? false : !clip.absolutePositioned,\n };\n layer.meta.maskStack = [entry];\n delete layer.meta.maskPreset;\n this.rebuild(target);\n return entry;\n }\n\n /** After a state restore: re-pin the design overlay and recompose every stack. */\n refreshAll(): void {\n this.selected = null;\n this.pin();\n for (const layer of this.layers.getAll()) {\n if ((layer.meta.maskStack ?? []).length === 0) continue;\n this.rebuild(layer.meta.canvasMask ? CANVAS_MASK_TARGET : layer.id);\n }\n }\n\n // ─── Internals ───────────────────────────────────────\n\n private patch(\n target: string,\n maskId: string,\n change: (entry: LayerMaskEntry) => Partial<LayerMaskEntry> | null,\n ): boolean {\n const host = this.host(target);\n if (!host) return false;\n const entries = [...this.list(target)];\n const index = entries.findIndex((entry) => entry.id === maskId);\n if (index === -1) return false;\n const patch = change(entries[index]);\n if (!patch) return false;\n const sources = this.unwrap(target, host);\n entries[index] = { ...entries[index], ...patch };\n this.commit(target, host, entries, sources);\n return true;\n }\n}\n","import { Group, Rect } from 'fabric';\nimport type { FabricObject } from 'fabric';\nimport type { LayerMaskEntry, LayerMaskMode } from '../types';\n\n/**\n * Compositing operation each mask mode contributes inside the clip group.\n *\n * The group is cached, so a child's `globalCompositeOperation` applies against\n * the siblings drawn before it — that cache is what turns a flat list of shapes\n * into a boolean stack (verified by the acceptance tests, which read pixels).\n */\nconst MODE_OPERATION: Record<LayerMaskMode, GlobalCompositeOperation> = {\n add: 'source-over',\n subtract: 'destination-out',\n intersect: 'destination-in',\n};\n\n/**\n * A hidden mask still contributes a child, drawn as a no-op: dropping it would\n * shift every following child's index, and the group's children are what gets\n * serialized — a hidden mask would not survive a save/reload.\n */\nfunction neutralize(child: FabricObject): void {\n child.set({ opacity: 0, globalCompositeOperation: 'source-over' });\n}\n\n/**\n * `subtract` and `intersect` cut into what is already drawn, so a stack that\n * opens with one has nothing to cut and would mask everything away. Give it the\n * host's own box to start from — \"the whole layer, minus this hole\".\n */\nfunction baseRect(box: { left: number; top: number; width: number; height: number }): FabricObject {\n return new Rect({\n left: box.left,\n top: box.top,\n width: Math.max(1, box.width),\n height: Math.max(1, box.height),\n originX: 'left',\n originY: 'top',\n fill: '#000000',\n objectCaching: false,\n });\n}\n\nexport interface ComposeOptions {\n /** Host box in the coordinate space the children use, for the implicit base. */\n box: { left: number; top: number; width: number; height: number };\n /**\n * Canvas-space children (an unlinked mask is pinned to the canvas, so the\n * whole group has to leave the host's local space with it).\n */\n absolute: boolean;\n}\n\n/**\n * Build the `clipPath` for one mask stack: one child per entry, in order, each\n * carrying its mode's compositing operation.\n *\n * `children` are consumed — a Group takes ownership of what it is given and\n * rewrites the coordinates, so callers pass clones of their sources rather than\n * the sources themselves.\n */\nexport function composeMaskGroup(\n children: FabricObject[],\n entries: LayerMaskEntry[],\n options: ComposeOptions,\n): Group | undefined {\n if (children.length === 0) return undefined;\n\n children.forEach((child, index) => {\n const entry = entries[index];\n child.set({ objectCaching: false });\n if (!entry || !entry.visible) {\n neutralize(child);\n return;\n }\n child.set({\n opacity: entry.opacity,\n globalCompositeOperation: MODE_OPERATION[entry.mode] ?? 'source-over',\n });\n });\n\n const first = entries.find((entry) => entry.visible);\n const withBase =\n first && first.mode !== 'add' ? [baseRect(options.box), ...children] : [...children];\n\n return new Group(withBase, {\n absolutePositioned: options.absolute,\n // Cached, so the children's compositing operations resolve against each\n // other instead of against the page underneath the mask.\n objectCaching: true,\n subTargetCheck: false,\n interactive: false,\n });\n}\n\n/** True when the stack has to be composed in canvas space rather than host space. */\nexport function needsAbsoluteSpace(entries: LayerMaskEntry[]): boolean {\n return entries.some((entry) => !entry.linked);\n}\n","import { Group, util } from 'fabric';\nimport type { Canvas, FabricObject } from 'fabric';\nimport { applyMatrix, matrixOf } from './space';\n\nexport interface MaskEditTarget {\n target: string;\n maskId: string;\n}\n\n/**\n * Drag-to-edit for one mask's geometry.\n *\n * A mask lives inside the host's clip group, where fabric will not give it\n * selection handles — a `clipPath` is drawn, never hit-tested. So editing works\n * through a **handle**: a clone of the mask placed on the canvas, styled as an\n * outline, whose transform is written back into the real clip child on every\n * move. The clip itself keeps rendering throughout, so the artwork updates live\n * rather than after the drag ends.\n *\n * The stack is composed in canvas space for the duration (`forceAbsolute`),\n * which is what lets the handle's canvas transform map onto the child with one\n * inversion instead of also unwinding the host's transform.\n */\nexport class MaskEditController {\n private handle: FabricObject | null = null;\n private editing: MaskEditTarget | null = null;\n private child: FabricObject | null = null;\n private group: Group | null = null;\n\n constructor(\n private canvas: Canvas,\n private onCommit: () => void,\n ) {}\n\n active(): MaskEditTarget | null {\n return this.editing;\n }\n\n /** Put a handle on the canvas for `child`, an object inside `group`. */\n async begin(edit: MaskEditTarget, group: Group, child: FabricObject): Promise<boolean> {\n this.end();\n const handle = await child.clone();\n applyMatrix(handle, matrixOf(child));\n handle.set({\n // Outline only: the mask's own fill would sit over the artwork it is\n // supposed to be revealing.\n fill: 'rgba(0,0,0,0.001)',\n stroke: '#e0b055',\n strokeWidth: 2,\n strokeDashArray: [6, 4],\n strokeUniform: true,\n opacity: 1,\n selectable: true,\n evented: true,\n hasControls: true,\n hasBorders: true,\n objectCaching: false,\n excludeFromExport: true,\n });\n this.handle = handle;\n this.editing = edit;\n this.child = child;\n this.group = group;\n this.canvas.add(handle);\n this.canvas.setActiveObject(handle);\n this.canvas.on('object:moving', this.onTransform);\n this.canvas.on('object:scaling', this.onTransform);\n this.canvas.on('object:rotating', this.onTransform);\n this.canvas.on('object:modified', this.onModified);\n this.canvas.requestRenderAll();\n return true;\n }\n\n /** Take the handle down. The geometry it wrote is already in the clip. */\n end(): void {\n if (!this.handle) return;\n this.canvas.off('object:moving', this.onTransform);\n this.canvas.off('object:scaling', this.onTransform);\n this.canvas.off('object:rotating', this.onTransform);\n this.canvas.off('object:modified', this.onModified);\n if (this.canvas.getActiveObject() === this.handle) this.canvas.discardActiveObject();\n this.canvas.remove(this.handle);\n this.handle = null;\n this.editing = null;\n this.child = null;\n this.group = null;\n this.canvas.requestRenderAll();\n }\n\n dispose(): void {\n this.end();\n }\n\n private readonly onTransform = (event: { target?: FabricObject }) => {\n if (!this.handle || event.target !== this.handle) return;\n this.write();\n };\n\n private readonly onModified = (event: { target?: FabricObject }) => {\n if (!this.handle || event.target !== this.handle) return;\n this.write();\n // One history entry per drag, not per pointer move.\n this.onCommit();\n };\n\n /** Handle transform (canvas space) → clip child transform (group-relative). */\n private write(): void {\n if (!this.handle || !this.child || !this.group) return;\n applyMatrix(\n this.child,\n util.multiplyTransformMatrices(\n util.invertTransform(matrixOf(this.group)),\n matrixOf(this.handle),\n ),\n );\n this.group.dirty = true;\n this.group.set({ dirty: true });\n this.canvas.requestRenderAll();\n }\n}\n","import { util } from 'fabric';\nimport type { FabricObject, Group, TMat2D } from 'fabric';\n\n/**\n * Coordinate-space plumbing for mask stacks.\n *\n * A fabric `clipPath` lives in one of two spaces, and the mask stack uses both:\n *\n * - **host space** (`absolutePositioned: false`) — the clip is drawn inside the\n * host object's own transform, so it follows every move, scale and rotation\n * of the layer for free. This is what a *linked* mask wants.\n * - **canvas space** (`absolutePositioned: true`) — the clip ignores the host's\n * transform, so the artwork slides underneath a mask that stays put. This is\n * what an *unlinked* mask wants.\n *\n * A stack composes into a single group, so one unlinked mask forces the whole\n * stack into canvas space; the linked entries are then re-fitted from the host's\n * transform. `toCanvasSpace` / `toHostSpace` are the conversions that migration\n * between the two regimes needs, and they are exact for scale, rotation and skew\n * because they compose matrices rather than copying left/top.\n */\n\nexport function matrixOf(object: FabricObject): TMat2D {\n return object.calcTransformMatrix();\n}\n\n/** Overwrite an object's transform with `matrix`, keeping its own dimensions. */\nexport function applyMatrix(object: FabricObject, matrix: TMat2D): void {\n const decomposed = util.qrDecompose(matrix);\n object.set({\n flipX: false,\n flipY: false,\n originX: 'center',\n originY: 'center',\n left: decomposed.translateX,\n top: decomposed.translateY,\n scaleX: decomposed.scaleX,\n scaleY: decomposed.scaleY,\n angle: decomposed.angle,\n skewX: decomposed.skewX,\n skewY: 0,\n });\n object.setCoords();\n}\n\n/** Host-space geometry → canvas-space, for the same on-screen result. */\nexport function toCanvasSpace(object: FabricObject, host: FabricObject): void {\n applyMatrix(object, util.multiplyTransformMatrices(matrixOf(host), matrixOf(object)));\n}\n\n/** Canvas-space geometry → host-space, for the same on-screen result. */\nexport function toHostSpace(object: FabricObject, host: FabricObject): void {\n applyMatrix(\n object,\n util.multiplyTransformMatrices(util.invertTransform(matrixOf(host)), matrixOf(object)),\n );\n}\n\n/**\n * The mask's transform expressed relative to its host, so a linked mask can be\n * re-derived after the host moves. Stored on the entry, not recomputed from the\n * live objects: by the time the host has moved, the old relationship is gone.\n */\nexport function relativeMatrix(object: FabricObject, host: FabricObject): TMat2D {\n return util.multiplyTransformMatrices(util.invertTransform(matrixOf(host)), matrixOf(object));\n}\n\n/** Re-place a linked mask from the host's current transform and a stored `rel`. */\nexport function applyRelativeMatrix(object: FabricObject, host: FabricObject, rel: TMat2D): void {\n applyMatrix(object, util.multiplyTransformMatrices(matrixOf(host), rel));\n}\n\n/**\n * Fabric types `clipPath` with a looser prop set than the objects the editor\n * builds, so reading a clip back out needs a narrowing step. Every clip this\n * module reads is one it composed from real objects in the first place.\n */\nexport function asObject(clip: NonNullable<FabricObject['clipPath']>): FabricObject {\n return clip as FabricObject;\n}\n\n/** Narrow a persisted `rel` array back to a transform matrix. */\nexport function toMatrix(values: number[] | undefined): TMat2D | null {\n if (!values || values.length !== 6 || values.some((value) => !Number.isFinite(value)))\n return null;\n return [values[0], values[1], values[2], values[3], values[4], values[5]];\n}\n\n/** Scale an object so its unrotated box covers `box`, centred on it. */\nexport function fitToBox(\n object: FabricObject,\n box: { left: number; top: number; width: number; height: number },\n zoom = 1,\n): void {\n const width = Math.max(1, box.width) * zoom;\n const height = Math.max(1, box.height) * zoom;\n object.set({\n originX: 'center',\n originY: 'center',\n angle: 0,\n skewX: 0,\n skewY: 0,\n left: box.left + box.width / 2,\n top: box.top + box.height / 2,\n scaleX: width / Math.max(1, object.width ?? 1),\n scaleY: height / Math.max(1, object.height ?? 1),\n });\n object.setCoords();\n}\n\n/**\n * Pull a composed clip group back apart into standalone objects in the space the\n * group itself was in.\n *\n * `removeAll` already restores each child's own transform on the way out — the\n * group rebases children when it takes them in, and reverses that when it lets\n * them go. Folding the group's matrix back in on top (as one would with a v5-era\n * group) double-counts it, which stays invisible while a mask sits at the origin\n * and moves it twice as far as it should the moment one does not.\n *\n * The group passed in is emptied.\n */\nexport function unwrapGroup(group: Group): FabricObject[] {\n const children = group.removeAll();\n for (const child of children) child.setCoords();\n return children;\n}\n","import { Group } from 'fabric';\nimport type { Canvas, FabricObject } from 'fabric';\nimport type { EditorEvents, LayerMaskEntry, LayerMaskMode } from '../types';\nimport type { EventEmitter } from '../events';\nimport type { HistoryManager } from '../history';\nimport type { Layer, LayerManager } from '../layer';\nimport { generateId } from '../utils/id';\nimport { needsAbsoluteSpace } from './compose';\nimport { createCanvasHost, findCanvasHost, hostBoxOf, pinCanvasHost, type MaskBox } from './host';\nimport { convertSpace, installClip, withRelativeTransforms } from './install';\nimport { asObject, unwrapGroup } from './space';\n\n/** Target id for the mask stack that clips the whole design rather than a layer. */\nexport const CANVAS_MASK_TARGET = 'canvas';\n\nexport const DEFAULT_ENTRY = {\n mode: 'add' as LayerMaskMode,\n linked: true,\n visible: true,\n opacity: 1,\n};\n\n/**\n * Storage half of the mask stacks: where a stack lives, how it is read back out\n * of the composed clip, and how a new one is installed. `LayerMaskManager` adds\n * the editing operations on top.\n *\n * Two things are persisted, and each has a job:\n *\n * - the composed `clipPath` on the host's fabric object, which is what actually\n * renders — in the browser, in an export, and in a server-side replay that\n * knows nothing about this class;\n * - `layer.meta.maskStack`, the per-entry list (name, mode, link, visibility)\n * that the UI edits.\n *\n * Geometry is NOT duplicated into the meta: the group's children are the single\n * source of truth for it, unwrapped and recomposed on every mutation, so the two\n * can never drift into disagreeing about where a mask sits. The order of\n * `entries` matches the order of the group's children, minus the implicit base\n * rect a stack that opens with subtract/intersect needs.\n */\nexport abstract class MaskStackStore {\n protected selected: { target: string; maskId: string } | null = null;\n private pinning = false;\n\n constructor(\n protected canvas: Canvas,\n protected layers: LayerManager,\n protected history: HistoryManager,\n protected events: EventEmitter<EditorEvents>,\n ) {}\n\n list(target: string): LayerMaskEntry[] {\n return this.hostLayer(target)?.meta.maskStack ?? [];\n }\n\n get(target: string, maskId: string): LayerMaskEntry | undefined {\n return this.list(target).find((entry) => entry.id === maskId);\n }\n\n /** Every target that currently carries at least one mask. */\n targets(): string[] {\n return this.layers\n .getAll()\n .filter((layer) => (layer.meta.maskStack ?? []).length > 0)\n .map((layer) => (layer.meta.canvasMask ? CANVAS_MASK_TARGET : layer.id));\n }\n\n /** The box a mask is fitted to, in the space the stack is composed in. */\n hostBox(\n target: string,\n absolute = target === CANVAS_MASK_TARGET || needsAbsoluteSpace(this.list(target)),\n ): MaskBox {\n return hostBoxOf(this.canvas, this.host(target), absolute);\n }\n\n /** The host layer of a target, optionally creating the design overlay. */\n protected hostLayer(target: string, create = false): Layer | undefined {\n if (target !== CANVAS_MASK_TARGET) return this.layers.get(target);\n const existing = findCanvasHost(this.layers);\n if (existing || !create) return existing;\n return createCanvasHost(this.canvas, this.layers);\n }\n\n protected host(target: string, create = false): FabricObject | null {\n return this.hostLayer(target, create)?.fabricObject ?? null;\n }\n\n /** Re-pin the design overlay, guarding the reorder that re-triggers this. */\n protected pin(): void {\n if (this.pinning) return;\n this.pinning = true;\n try {\n pinCanvasHost(this.layers);\n } finally {\n this.pinning = false;\n }\n }\n\n /**\n * Take the current geometry back out of the composed clip, entry-aligned.\n *\n * The entry list is the authority on how to read the clip: with no entries the\n * clip predates the stack (a mask preset, or a single `clipPath` an older host\n * installed) and is one mask whole — including when it happens to be a group,\n * which is why this cannot just unwrap anything group-shaped.\n */\n protected unwrap(target: string, host: FabricObject): FabricObject[] {\n const clip = host.clipPath;\n if (!clip) return [];\n const entries = this.list(target);\n if (entries.length === 0 || !(clip instanceof Group)) return [asObject(clip)];\n const children = unwrapGroup(clip);\n // A stack opening with subtract/intersect gets an implicit base child that\n // belongs to no entry; drop it so index N is still entry N's geometry.\n const extra = children.length - entries.length;\n return extra > 0 ? children.slice(extra) : children;\n }\n\n /**\n * Entries for a stack, adopting a pre-stack clip as the first one. Without\n * this, the first `add()` on an already-masked layer would compose a clip it\n * has no entry for and silently throw that mask away.\n */\n protected entriesFor(target: string, sources: FabricObject[]): LayerMaskEntry[] {\n const existing = this.list(target);\n if (existing.length > 0 || sources.length !== 1) return [...existing];\n const layer = this.hostLayer(target);\n const preset = layer?.meta.maskPreset;\n if (layer) {\n // The preset manager rebuilds its clip from this key on refresh, which\n // would overwrite the stack. The stack owns the clip from here on.\n delete layer.meta.maskPreset;\n }\n return [\n {\n ...DEFAULT_ENTRY,\n id: generateId(),\n name: typeof preset === 'string' ? preset : 'Mask',\n linked: target === CANVAS_MASK_TARGET ? false : !sources[0].absolutePositioned,\n },\n ];\n }\n\n /**\n * Install a stack: convert geometry into the space the stack needs, compose the\n * clip, store the entries, and commit one history checkpoint for the lot.\n */\n protected commit(\n target: string,\n host: FabricObject,\n entries: LayerMaskEntry[],\n sources: FabricObject[],\n save = true,\n /** Compose in canvas space regardless of the entries — see `beginEdit`. */\n forceAbsolute = false,\n ): void {\n const layer = this.hostLayer(target);\n if (!layer) return;\n const absolute = forceAbsolute || target === CANVAS_MASK_TARGET || needsAbsoluteSpace(entries);\n\n convertSpace(host, sources, absolute);\n const next = withRelativeTransforms(entries, sources, host, absolute);\n installClip(host, next, sources, this.hostBox(target, absolute), absolute);\n\n if (next.length === 0) {\n delete layer.meta.maskStack;\n // An overlay with no masks would keep destination-in-ing the design away.\n if (layer.meta.canvasMask) this.layers.remove(layer.id);\n } else {\n layer.meta.maskStack = next;\n }\n\n this.canvas.requestRenderAll();\n this.events.emit('masks:changed', { target });\n this.events.emit('layer:modified', { layerId: layer.id });\n if (save) this.history.save();\n }\n}\n","import { Rect } from 'fabric';\nimport type { Canvas, FabricObject } from 'fabric';\nimport type { Layer, LayerManager } from '../layer';\n\nexport interface MaskBox {\n left: number;\n top: number;\n width: number;\n height: number;\n}\n\n/** The overlay layer carrying the whole-design stack, if one exists yet. */\nexport function findCanvasHost(layers: LayerManager): Layer | undefined {\n return layers.getAll().find((layer) => layer.meta.canvasMask);\n}\n\n/**\n * Create the overlay that masks the design: a full-canvas rectangle drawn in\n * `destination-in`, so what it paints is what survives of everything below it.\n * Its clip is a normal mask stack, which makes \"mask the whole design\" the same\n * code path as masking one layer.\n */\nexport function createCanvasHost(canvas: Canvas, layers: LayerManager): Layer {\n const rect = new Rect({\n left: 0,\n top: 0,\n width: canvas.getWidth(),\n height: canvas.getHeight(),\n originX: 'left',\n originY: 'top',\n fill: '#000000',\n globalCompositeOperation: 'destination-in',\n // It is edited from the layer list, never on the canvas: a drag box on\n // something that cannot be dragged only reads as broken.\n selectable: false,\n evented: false,\n hasControls: false,\n hasBorders: false,\n objectCaching: false,\n });\n const layer = layers.add('mask', rect, 'Design mask');\n layer.meta.canvasMask = true;\n layers.setLocked(layer.id, true);\n return layer;\n}\n\n/**\n * Keep the design overlay above everything it masks. Pinning above *content*\n * rather than to the absolute top leaves other mask-type overlays alone, so two\n * \"stay on top\" rules cannot ping-pong against each other.\n *\n * Returns true when a reorder was needed, so the caller can guard re-entry: the\n * reorder itself emits the event that triggered this.\n */\nexport function pinCanvasHost(layers: LayerManager): boolean {\n const all = layers.getAll();\n const hostIndex = all.findIndex((layer) => layer.meta.canvasMask);\n if (hostIndex === -1) return false;\n let lastContent = -1;\n all.forEach((layer, index) => {\n if (layer.type !== 'mask') lastContent = index;\n });\n if (hostIndex >= lastContent) return false;\n layers.reorder(all[hostIndex].id, all.length - 1);\n return true;\n}\n\n/**\n * The box a mask is fitted to, in the space its stack is composed in: the host's\n * bounding rectangle in canvas space, or — in host space, which is centred on\n * the object and ignores its scale — the unscaled size around the origin.\n */\nexport function hostBoxOf(canvas: Canvas, host: FabricObject | null, absolute: boolean): MaskBox {\n if (!host) {\n return { left: 0, top: 0, width: canvas.getWidth(), height: canvas.getHeight() };\n }\n if (absolute) {\n host.setCoords();\n const rect = host.getBoundingRect();\n return { left: rect.left, top: rect.top, width: rect.width, height: rect.height };\n }\n const width = Math.max(1, host.width ?? 1);\n const height = Math.max(1, host.height ?? 1);\n return { left: -width / 2, top: -height / 2, width, height };\n}\n","import { Group } from 'fabric';\nimport type { FabricObject } from 'fabric';\nimport type { LayerMaskEntry } from '../types';\nimport { composeMaskGroup } from './compose';\nimport type { MaskBox } from './host';\nimport { relativeMatrix, toCanvasSpace, toHostSpace } from './space';\n\n/**\n * Move a stack's geometry into the space it is about to be composed in. Called\n * only when the space actually changes (linking or unlinking a mask), and it has\n * to be a no-op on screen — an unlinked mask stays exactly where it looked.\n */\nexport function convertSpace(host: FabricObject, sources: FabricObject[], absolute: boolean): void {\n const wasAbsolute = host.clipPath instanceof Group ? host.clipPath.absolutePositioned : absolute;\n if (absolute === wasAbsolute) return;\n for (const source of sources) {\n if (absolute) toCanvasSpace(source, host);\n else toHostSpace(source, host);\n }\n}\n\n/**\n * Record (or drop) each linked mask's transform relative to its host.\n *\n * Only a canvas-space stack needs it: in host space fabric already carries the\n * clip along with the layer. A stale relationship is worse than none — it would\n * re-place the mask from a transform that no longer describes where it sits.\n */\nexport function withRelativeTransforms(\n entries: LayerMaskEntry[],\n sources: FabricObject[],\n host: FabricObject,\n absolute: boolean,\n): LayerMaskEntry[] {\n return entries.map((entry, index) => {\n const source = sources[index];\n if (absolute && entry.linked && source) {\n return { ...entry, rel: [...relativeMatrix(source, host)] };\n }\n if (!entry.rel) return entry;\n const rest = { ...entry };\n delete rest.rel;\n return rest;\n });\n}\n\n/** Compose the stack and attach it as the host's clip. */\nexport function installClip(\n host: FabricObject,\n entries: LayerMaskEntry[],\n sources: FabricObject[],\n box: MaskBox,\n absolute: boolean,\n): void {\n host.clipPath = composeMaskGroup(sources, entries, { box, absolute });\n host.dirty = true;\n host.setCoords();\n}\n","import type { FabricObject } from 'fabric';\n\n// ─── Units ───────────────────────────────────────────────\n\nexport type Unit = 'px' | 'mm' | 'in';\n\n// ─── Layers ──────────────────────────────────────────────\n\nexport type LayerType = 'image' | 'mask' | 'text' | 'shape' | 'template' | 'group';\n\nexport interface LayerData {\n id: string;\n type: LayerType;\n name: string;\n visible: boolean;\n locked: boolean;\n opacity: number;\n /** Non-fabric metadata persisted with the layer (pattern config, etc). */\n meta?: LayerMeta;\n /** Layers nested inside this one. Only a `group` layer has any. */\n children?: LayerData[];\n}\n\nexport interface LayerMeta {\n pattern?: PatternState;\n mask?: { width: number; height: number; revision: number };\n /** Preset silhouette or texture the layer is clipped to. */\n maskPreset?: MaskPresetId;\n /** Ordered mask stack clipping this layer (see `LayerMaskManager`). */\n maskStack?: LayerMaskEntry[];\n /** Marks the overlay layer that carries the whole-design mask stack. */\n canvasMask?: boolean;\n /** Baseline curve applied to a text layer. States saved before the shape\n * switch existed carry only `arc`/`wave`; reads normalize them. */\n curve?: TextCurveInput;\n /** Text box width authored before a curve widened it, in px. */\n curveWidth?: number;\n /** Layer resizes uniformly: single-axis handles are hidden. */\n lockAspect?: boolean;\n [key: string]: unknown;\n}\n\n// ─── Text curve ──────────────────────────────────────────\n\n/** Shape the baseline follows. The two are alternatives, never combined. */\nexport type TextCurveShape = 'arc' | 'wave';\n\nexport interface TextCurveConfig {\n /**\n * Which of the two shapes is live. The parameters of the other one are kept\n * so switching back and forth does not lose them.\n */\n shape: TextCurveShape;\n /**\n * Baseline bend, −100…100. Positive arcs the run upward (a rainbow),\n * negative into a valley; ±100 closes it into a full ring. 0 is straight.\n */\n arc: number;\n /** Sine-wave amplitude, 0…100, as a share of the font size. */\n wave: number;\n /** Sine-wave period, in font sizes. Lower is a tighter ripple. */\n waveLength: number;\n /**\n * Shift of the run along its baseline, −100…100. On an arc that is a share\n * of the sweep (±100 walks a closed ring right round); on a wave it is a\n * share of one wavelength.\n */\n offset: number;\n /**\n * Pushes the run off the ring it is bent around, −100…100 (±100 halves or\n * doubles the radius). Arc only: outward flattens the letters, inward curls\n * them tighter round a smaller circle.\n */\n centerOffset: number;\n}\n\n/**\n * A curve as authored: every field optional, missing ones fall back to the\n * defaults. Also the shape older saved states are in — they predate `shape`,\n * `waveLength` and `offset`.\n */\nexport type TextCurveInput = Partial<TextCurveConfig>;\n\n// ─── Mask presets ────────────────────────────────────────\n\nexport type ShapeMaskPresetId =\n | 'circle'\n | 'square'\n | 'triangle'\n | 'star'\n | 'heart'\n | 'octagram'\n | 'arch'\n | 'zigzag';\n\nexport type TextureMaskPresetId = 'vignette' | 'halftone' | 'spray' | 'grunge' | 'torn' | 'band';\n\nexport type MaskPresetId = ShapeMaskPresetId | TextureMaskPresetId;\n\n// ─── Mask stacks ─────────────────────────────────────────\n\n/**\n * How one mask combines with the masks under it in the stack:\n * - `add` — keeps what it covers, on top of what earlier masks kept (union)\n * - `subtract` — punches its shape out of what earlier masks kept\n * - `intersect` — keeps only what it and the earlier masks both cover\n */\nexport type LayerMaskMode = 'add' | 'subtract' | 'intersect';\n\nexport interface LayerMaskEntry {\n id: string;\n name: string;\n mode: LayerMaskMode;\n /**\n * A linked mask follows the host layer's transform; an unlinked one is pinned\n * to the canvas, so moving the layer slides the artwork under a static mask.\n * Always false on the whole-design stack, which has no host to follow.\n */\n linked: boolean;\n /** A hidden mask keeps its slot and its geometry, contributing nothing. */\n visible: boolean;\n /** 0…1 — a partly transparent mask reveals its area partly. */\n opacity: number;\n /**\n * The mask's transform relative to its host, recorded only while the stack is\n * composed in canvas space (an unlinked sibling forces that), so a linked mask\n * can be re-derived after the host moves.\n */\n rel?: number[];\n /** Host data describing where the geometry came from (preset id, generator…). */\n meta?: Record<string, unknown>;\n}\n\n// ─── Shadow ──────────────────────────────────────────────\n\nexport interface LayerShadowConfig {\n enabled: boolean;\n color: string;\n blur: number;\n offsetX: number;\n offsetY: number;\n}\n\nexport interface SerializedLayer extends LayerData {\n fabricObject: Record<string, unknown>;\n}\n\n// ─── Editor ──────────────────────────────────────────────\n\nexport interface EditorState {\n version: string;\n canvas: { width: number; height: number; unit?: Unit; dpi?: number };\n layers: SerializedLayer[];\n background?: string;\n backgroundImage?: Record<string, unknown> | null;\n backgroundImageOptions?: SerializedBackgroundImageOptions | null;\n mockup?: MockupConfig | null;\n}\n\nexport interface EditorConfig {\n width: number;\n height: number;\n backgroundColor?: string;\n fileAdapter?: FileAdapter;\n imageProvider?: ImageProvider;\n preserveObjectStacking?: boolean;\n unit?: Unit;\n dpi?: number;\n fonts?: FontDefinition[];\n license?: LicenseConfig;\n}\n\n// ─── Adapters ────────────────────────────────────────────\n\nexport type ExportFormat = 'png' | 'jpeg' | 'webp' | 'svg' | 'json';\n\nexport interface ResizeOptions {\n /** Scale layer positions and dimensions with the canvas. Defaults to true. */\n scaleContent?: boolean;\n}\n\nexport interface BackgroundImageOptions {\n fit?: 'cover' | 'contain' | 'stretch';\n opacity?: number;\n /** Fabric/HTML image loading mode for remote assets. */\n crossOrigin?: '' | 'anonymous' | 'use-credentials' | null;\n /** Cancels the current load; never serialized. */\n signal?: AbortSignal;\n}\n\nexport type SerializedBackgroundImageOptions = Omit<BackgroundImageOptions, 'signal'>;\n\nexport interface SemanticExportOptions extends PngLikeExportOptions {\n /** Document keeps full-canvas coordinates; source returns native image pixels. */\n resolution?: 'document' | 'source';\n}\n\nexport interface MaskPoint {\n x: number;\n y: number;\n}\n\nexport interface MaskBrushOptions {\n mode: 'add' | 'subtract';\n size: number;\n /** Soft-edge inner radius ratio, from 0 (soft) to 1 (hard). */\n hardness: number;\n}\n\nexport type MaskRefinementPrompt =\n | { type: 'point'; x: number; y: number; label: 'foreground' | 'background' }\n | { type: 'rectangle'; left: number; top: number; width: number; height: number }\n | { type: 'text'; value: string };\n\nexport interface MaskRefinementRequest {\n mask: string;\n width: number;\n height: number;\n prompts: MaskRefinementPrompt[];\n}\n\nexport interface MaskRefinementResult {\n dataUrl: string;\n width?: number;\n height?: number;\n metadata?: Record<string, unknown>;\n}\n\nexport interface MaskRefinementProvider {\n refine(\n request: MaskRefinementRequest,\n options?: {\n signal?: AbortSignal;\n onProgress?: (progress: number) => void;\n },\n ): Promise<MaskRefinementResult>;\n}\n\n/** Kept structural to avoid coupling the public types module to export.ts. */\nexport interface PngLikeExportOptions {\n multiplier?: number;\n quality?: number;\n}\n\nexport interface DpiIssue {\n layerId: string;\n layerName: string;\n effectiveDpi: number;\n minimumDpi: number;\n}\n\nexport interface ImageAdjustments {\n /** Range -1 to 1. */\n brightness?: number;\n /** Range -1 to 1. */\n contrast?: number;\n /** Range -1 to 1. */\n saturation?: number;\n /** Range 0 to 1. */\n blur?: number;\n}\n\nexport interface FontDefinition {\n family: string;\n /** URL, data URL, or a complete CSS FontFace source such as `local(...)`. */\n source: string;\n weight?: string;\n style?: string;\n display?: FontDisplay;\n}\n\nexport interface SvgExportOptions {\n /** Embed registered URL/data fonts into the SVG. Defaults to true. */\n embedFonts?: boolean;\n}\n\nexport interface LicensePayload {\n id: string;\n domains: string[];\n expiresAt?: string;\n features?: string[];\n}\n\nexport type LicenseStatus =\n | { state: 'community' | 'exempt' | 'checking'; payload: null }\n | { state: 'valid'; payload: LicensePayload }\n | { state: 'invalid' | 'expired' | 'domain-mismatch'; payload: LicensePayload | null };\n\nexport interface LicenseConfig {\n key?: string;\n /** Offline signature decoder/verifier supplied by the commercial distribution. */\n verifyOffline?: (key: string) => Promise<LicensePayload | null> | LicensePayload | null;\n hostname?: string;\n environment?: 'development' | 'test' | 'production';\n onUsage?: (event: { name: string; at: string; licenseId?: string }) => void;\n}\n\nexport interface CanvasSizePreset {\n id: string;\n name: string;\n width: number;\n height: number;\n unit: Unit;\n dpi: number;\n}\n\nexport interface FileAdapter {\n save(data: Blob | string, filename: string, format: ExportFormat): Promise<string>;\n}\n\nexport interface ImageProviderResult {\n id?: string;\n url: string;\n width: number;\n height: number;\n previewUrl?: string;\n thumbnailUrl?: string;\n alt?: string;\n sourceUrl?: string;\n attribution?: ImageAttribution;\n /** Provider event endpoint retained for use tracking; never render this as an image. */\n trackingUrl?: string;\n}\n\nexport interface ImageAttribution {\n name: string;\n url: string;\n provider?: string;\n}\n\nexport interface ImageSearchOptions {\n page?: number;\n perPage?: number;\n orientation?: 'landscape' | 'portrait' | 'squarish';\n orderBy?: 'relevant' | 'latest';\n contentFilter?: 'low' | 'high';\n}\n\nexport interface ImageSearchResult {\n items: ImageProviderResult[];\n page: number;\n total: number;\n totalPages: number;\n}\n\nexport interface ImageProvider {\n upload?(file: File): Promise<ImageProviderResult>;\n browse?(): Promise<ImageProviderResult | null>;\n search?(query: string, options?: ImageSearchOptions): Promise<ImageSearchResult>;\n /** Called immediately before a provider asset is inserted into the design. */\n trackUse?(image: ImageProviderResult): Promise<void>;\n}\n\n// ─── Plugins ─────────────────────────────────────────────\n\nexport interface ShapePlugin {\n name: string;\n icon: string;\n category?: string;\n create(options?: Record<string, unknown>): FabricObject;\n}\n\nexport interface TemplateParameter {\n key: string;\n label: string;\n type: 'text' | 'color' | 'number' | 'font';\n default?: string | number;\n}\n\nexport interface TemplateDefinition {\n id: string;\n name: string;\n category: string;\n svg: string;\n parameters: TemplateParameter[];\n preview?: string;\n}\n\n// ─── Printify ────────────────────────────────────────────\n\nexport interface PrintifyPositioning {\n x: number;\n y: number;\n scale: number;\n angle: number;\n}\n\nexport interface NormalizedLayerPosition {\n layerId: string;\n name: string;\n type: LayerType;\n centerX: number;\n centerY: number;\n width: number;\n height: number;\n scaleX: number;\n scaleY: number;\n angle: number;\n}\n\nexport interface PositioningAdapter<T> {\n readonly provider: string;\n map(positions: NormalizedLayerPosition[], canvas: { width: number; height: number }): T;\n}\n\nexport interface ProjectPage {\n id: string;\n name: string;\n state: EditorState;\n}\n\nexport interface ProjectState {\n version: '1.0.0';\n activePageId: string;\n pages: ProjectPage[];\n}\n\n// ─── Patterns ────────────────────────────────────────────\n\nexport type TileMode = 'grid' | 'brick-horizontal' | 'brick-vertical';\n\nexport interface PatternConfig {\n mode: TileMode;\n /**\n * Tile size as a % of the source image's on-canvas size (100 = natural).\n * Smaller values pack more repeats across the print area; larger values make\n * fewer, bigger tiles. Independent of how the source layer was placed.\n */\n scale: number;\n /** Extra horizontal gap between tiles, as % of tile width. */\n horizontalSpacing: number;\n /** Extra vertical gap between tiles, as % of tile height. */\n verticalSpacing: number;\n /** Rotation of the whole pattern, in degrees. */\n angle: number;\n /** Brick row/column shift, as % of tile size. */\n horizontalOffset: number;\n /**\n * Phase shift of the whole tile grid inside the print area, as % of tile\n * width. The pattern object itself is pinned to the print area (it can't be\n * dragged — that would expose bare edges), so this is how the tiling is\n * nudged into alignment. Clamped to ±100% so coverage is never broken.\n */\n offsetX: number;\n /** Phase shift of the tile grid, as % of tile height. See {@link offsetX}. */\n offsetY: number;\n /** Added rotation per horizontal step, in degrees. */\n rotationStepH: number;\n /** Added rotation per vertical step, in degrees. */\n rotationStepV: number;\n}\n\n/** Fabric interaction flags frozen while a layer is rendered as a pattern. */\nexport interface PatternLocks {\n lockMovementX: boolean;\n lockMovementY: boolean;\n lockScalingX: boolean;\n lockScalingY: boolean;\n lockRotation: boolean;\n hasControls: boolean;\n}\n\n/**\n * Persisted on a layer's meta while it is tiled across the print area.\n *\n * Current states carry `config` and nothing else: the layer keeps its real\n * object and the tiling is drawn by a render proxy, so there is no \"original\"\n * to remember. The `original*` fields belong to states written by the engine\n * that baked the tiled bitmap into the layer; they are read once, on restore,\n * to put the artwork back (see `PatternManager.rehydrateAll`).\n */\nexport interface PatternState {\n config: PatternConfig;\n /** Legacy: pre-bake image source, as a durable data URL when possible. */\n originalSrc?: string;\n /** Legacy: serialized `clipPath` the image carried before it was baked. */\n originalClip?: Record<string, unknown> | null;\n /** Legacy: interaction flags frozen while the baked bitmap was in place. */\n originalLocks?: PatternLocks;\n /** Legacy: fabric transform to restore when un-baking. */\n original?: {\n left: number;\n top: number;\n scaleX: number;\n scaleY: number;\n width: number;\n height: number;\n angle: number;\n cropX: number;\n cropY: number;\n };\n}\n\nexport const DEFAULT_PATTERN_CONFIG: PatternConfig = {\n mode: 'grid',\n scale: 100,\n horizontalSpacing: 0,\n verticalSpacing: 0,\n angle: 0,\n horizontalOffset: 0,\n offsetX: 0,\n offsetY: 0,\n rotationStepH: 0,\n rotationStepV: 0,\n};\n\n// ─── Mockup ──────────────────────────────────────────────\n\nexport interface MockupPrintArea {\n left: number;\n top: number;\n width: number;\n height: number;\n}\n\nexport type MockupBlendMode =\n | 'normal'\n | 'multiply'\n | 'screen'\n | 'overlay'\n | 'soft-light'\n | 'hard-light';\n\nexport interface MockupOverlay {\n /** Lighting, texture, or shadow image drawn above the design. */\n image: string;\n blendMode?: MockupBlendMode;\n opacity?: number;\n}\n\nexport type MockupDisplacementChannel = 'red' | 'green' | 'blue' | 'alpha';\n\nexport interface MockupDisplacement {\n /** Channel-map image cover-fitted to the mockup canvas. A value of 128 is neutral. */\n image: string;\n /** Maximum horizontal displacement in document pixels. Defaults to 10. */\n scaleX?: number;\n /** Maximum vertical displacement in document pixels. Defaults to 10. */\n scaleY?: number;\n /** Map channel controlling horizontal displacement. Defaults to red. */\n channelX?: MockupDisplacementChannel;\n /** Map channel controlling vertical displacement. Defaults to green. */\n channelY?: MockupDisplacementChannel;\n}\n\nexport interface MockupConfig {\n /** Garment/product image rendered behind the design. */\n image: string;\n /** Print-area rectangle, in canvas pixels. Drawn as a guide. */\n printArea?: MockupPrintArea;\n /** Clip the design to printArea. Defaults to true when printArea exists. */\n clipToPrintArea?: boolean;\n designBlendMode?: MockupBlendMode;\n designOpacity?: number;\n /** Optional channel-map warp applied to the design before compositing. */\n displacement?: MockupDisplacement;\n /** Optional product lighting/shadow pass rendered after the design. */\n overlay?: MockupOverlay;\n}\n\n// ─── Events ──────────────────────────────────────────────\n\nexport interface EditorEvents {\n 'layer:added': { layer: LayerData };\n 'layer:removed': { layerId: string };\n 'layer:selected': { layerId: string | null };\n 'layer:modified': { layerId: string };\n 'layer:reordered': { layerIds: string[] };\n 'layers:changed': { layers: LayerData[] };\n 'masks:changed': { target: string };\n 'mask:selected': { target: string | null; maskId: string | null };\n 'selection:changed': { selected: string[] };\n 'history:changed': { canUndo: boolean; canRedo: boolean };\n 'history:snapshot': { bytes: number; totalBytes: number; entries: number };\n 'zoom:changed': { zoom: number };\n 'snap:changed': { enabled: boolean };\n 'crop:changed': { active: boolean; layerId: string | null };\n 'mockup:changed': { mockup: MockupConfig | null };\n 'canvas:modified': Record<string, never>;\n 'project:changed': { activePageId: string; pages: Array<{ id: string; name: string }> };\n 'export:start': { format: string };\n 'export:complete': { format: string; url?: string };\n error: { message: string; error?: unknown };\n}\n","import type { CanvasSizePreset } from './types';\n\n/** Common print and digital canvas sizes. */\nexport const CANVAS_SIZE_PRESETS: readonly CanvasSizePreset[] = [\n { id: 'a4-portrait', name: 'A4 portrait', width: 210, height: 297, unit: 'mm', dpi: 300 },\n { id: 'a4-landscape', name: 'A4 landscape', width: 297, height: 210, unit: 'mm', dpi: 300 },\n { id: 'us-letter', name: 'US Letter', width: 8.5, height: 11, unit: 'in', dpi: 300 },\n { id: 'shirt-front', name: 'Garment front', width: 12, height: 16, unit: 'in', dpi: 300 },\n { id: 'instagram-square', name: 'Social square', width: 1080, height: 1080, unit: 'px', dpi: 72 },\n { id: 'story', name: 'Story', width: 1080, height: 1920, unit: 'px', dpi: 72 },\n];\n","export type AnnotationPrimitive =\n | { id: string; type: 'point'; x: number; y: number; label?: string }\n | {\n id: string;\n type: 'rectangle';\n left: number;\n top: number;\n width: number;\n height: number;\n label?: string;\n }\n | { id: string; type: 'label'; x: number; y: number; text: string }\n | { id: string; type: 'path'; points: Array<{ x: number; y: number }>; label?: string };\n\nexport interface ViewportTransform {\n zoom: number;\n panX: number;\n panY: number;\n devicePixelRatio?: number;\n}\n\n/** Host-owned annotations that never enter editor layers, history, serialization, or exports. */\nexport class AnnotationOverlay {\n private items = new Map<string, AnnotationPrimitive>();\n private transform: ViewportTransform = { zoom: 1, panX: 0, panY: 0, devicePixelRatio: 1 };\n\n set(annotation: AnnotationPrimitive): void {\n this.items.set(annotation.id, structuredClone(annotation));\n }\n\n remove(id: string): boolean {\n return this.items.delete(id);\n }\n\n clear(): void {\n this.items.clear();\n }\n\n getAll(): AnnotationPrimitive[] {\n return [...this.items.values()].map((item) => structuredClone(item));\n }\n\n setTransform(transform: ViewportTransform): void {\n if (!Number.isFinite(transform.zoom) || transform.zoom <= 0) {\n throw new Error('Annotation zoom must be positive');\n }\n this.transform = { ...transform, devicePixelRatio: transform.devicePixelRatio ?? 1 };\n }\n\n documentToViewport(point: { x: number; y: number }): { x: number; y: number } {\n return {\n x: point.x * this.transform.zoom + this.transform.panX,\n y: point.y * this.transform.zoom + this.transform.panY,\n };\n }\n\n viewportToDocument(point: { x: number; y: number }): { x: number; y: number } {\n return {\n x: (point.x - this.transform.panX) / this.transform.zoom,\n y: (point.y - this.transform.panY) / this.transform.zoom,\n };\n }\n\n documentToDevice(point: { x: number; y: number }): { x: number; y: number } {\n const viewport = this.documentToViewport(point);\n const ratio = this.transform.devicePixelRatio ?? 1;\n return { x: viewport.x * ratio, y: viewport.y * ratio };\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,kBAA6D;;;ACGtD,IAAM,eAAN,MAAiE;AAAA,EAC9D,YAAY,oBAAI,IAA+C;AAAA,EAEvE,GAA4B,OAAU,SAAyC;AAC7E,QAAI,CAAC,KAAK,UAAU,IAAI,KAAK,GAAG;AAC9B,WAAK,UAAU,IAAI,OAAO,oBAAI,IAAI,CAAC;AAAA,IACrC;AACA,SAAK,UAAU,IAAI,KAAK,EAAG,IAAI,OAAgC;AAAA,EACjE;AAAA,EAEA,IAA6B,OAAU,SAAyC;AAC9E,SAAK,UAAU,IAAI,KAAK,GAAG,OAAO,OAAgC;AAAA,EACpE;AAAA,EAEA,KAA8B,OAAU,SAAyC;AAC/E,UAAM,UAAoC,CAAC,SAAS;AAClD,WAAK,IAAI,OAAO,OAAO;AACvB,cAAQ,IAAI;AAAA,IACd;AACA,SAAK,GAAG,OAAO,OAAO;AAAA,EACxB;AAAA,EAEA,KAA8B,OAAU,MAAwB;AAC9D,UAAM,WAAW,KAAK,UAAU,IAAI,KAAK;AACzC,QAAI,CAAC,SAAU;AACf,eAAW,WAAW,UAAU;AAC9B,cAAQ,IAAI;AAAA,IACd;AAAA,EACF;AAAA,EAEA,mBAAmB,OAA6B;AAC9C,QAAI,OAAO;AACT,WAAK,UAAU,OAAO,KAAK;AAAA,IAC7B,OAAO;AACL,WAAK,UAAU,MAAM;AAAA,IACvB;AAAA,EACF;AACF;;;ACxCA,oBAAuC;;;ACAvC,oBAAuB;AAEhB,IAAM,aAAa,UAAc,sBAAO,EAAE;;;ADK1C,IAAM,QAAN,MAAY;AAAA,EACR;AAAA,EACA;AAAA,EACT;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA;AAAA;AAAA,EAEA;AAAA,EAEA,YAAY,MAAiB,cAA4B,MAAe,IAAa;AACnF,SAAK,KAAK,MAAM,WAAW;AAC3B,SAAK,OAAO;AACZ,SAAK,OAAO,QAAQ,GAAG,IAAI,IAAI,KAAK,GAAG,MAAM,GAAG,CAAC,CAAC;AAClD,SAAK,UAAU;AACf,SAAK,SAAS;AACd,SAAK,UAAU;AACf,SAAK,OAAO,CAAC;AACb,SAAK,eAAe;AACpB,SAAK,cAAc;AACnB,SAAK,WAAW,CAAC;AACjB,SAAK,WAAW;AAEhB,IAAC,KAAK,aAAqD,WAAW,KAAK;AAAA,EAC7E;AAAA,EAEQ,UAAmB;AACzB,WAAO,OAAO,KAAK,KAAK,IAAI,EAAE,SAAS;AAAA,EACzC;AAAA,EAEA,SAAoB;AAClB,WAAO;AAAA,MACL,IAAI,KAAK;AAAA,MACT,MAAM,KAAK;AAAA,MACX,MAAM,KAAK;AAAA,MACX,SAAS,KAAK;AAAA,MACd,QAAQ,KAAK;AAAA,MACb,SAAS,KAAK;AAAA,MACd,GAAI,KAAK,QAAQ,IAAI,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;AAAA,MAC5C,GAAI,KAAK,SAAS,SAAS,IAAI,EAAE,UAAU,KAAK,SAAS,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC;AAAA,IACvF;AAAA,EACF;AAAA,EAEA,YAA6B;AAC3B,WAAO;AAAA,MACL,GAAG,KAAK,OAAO;AAAA;AAAA;AAAA,MAGf,cAAc,KAAK,aAAa,SAAS;AAAA,IAC3C;AAAA,EACF;AACF;AAEO,IAAM,eAAN,MAAmB;AAAA,EAIxB,YACU,QACA,QACR;AAFQ;AACA;AAAA,EACP;AAAA,EAFO;AAAA,EACA;AAAA,EALF,SAAkB,CAAC;AAAA,EACnB;AAAA,EAOR,mBAAmB,UAA4B;AAC7C,SAAK,oBAAoB;AAAA,EAC3B;AAAA,EAEA,IAAI,MAAiB,cAA4B,MAAe,IAAoB;AAClF,UAAM,QAAQ,IAAI,MAAM,MAAM,cAAc,MAAM,EAAE;AACpD,SAAK,OAAO,KAAK,KAAK;AACtB,SAAK,OAAO,IAAI,YAAY;AAC5B,SAAK,OAAO,KAAK,eAAe,EAAE,OAAO,MAAM,OAAO,EAAE,CAAC;AACzD,SAAK,YAAY;AACjB,WAAO;AAAA,EACT;AAAA,EAEA,OAAO,IAAqB;AAC1B,UAAM,QAAQ,KAAK,IAAI,EAAE;AACzB,QAAI,CAAC,MAAO,QAAO;AAEnB,QAAI,MAAM,UAAU;AAClB,YAAM,SAAS,KAAK,IAAI,MAAM,QAAQ;AACtC,UAAI,CAAC,OAAQ,QAAO;AACpB,MAAC,OAAO,aAAuB,OAAO,MAAM,YAAY;AACxD,aAAO,WAAW,OAAO,SAAS,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE;AAC3D,YAAM,WAAW;AACjB,WAAK,OAAO,KAAK,iBAAiB,EAAE,SAAS,GAAG,CAAC;AAGjD,UAAI,OAAO,SAAS,SAAS,EAAG,MAAK,SAAS,MAAM;AACpD,WAAK,YAAY;AACjB,WAAK,oBAAoB;AACzB,WAAK,OAAO,iBAAiB;AAC7B,aAAO;AAAA,IACT;AAEA,UAAM,QAAQ,KAAK,OAAO,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE;AACtD,QAAI,UAAU,GAAI,QAAO;AACzB,SAAK,OAAO,OAAO,MAAM,YAAY;AACrC,QAAI,MAAM,YAAa,MAAK,OAAO,OAAO,MAAM,WAAW;AAC3D,SAAK,OAAO,OAAO,OAAO,CAAC;AAC3B,SAAK,OAAO,KAAK,iBAAiB,EAAE,SAAS,GAAG,CAAC;AACjD,SAAK,YAAY;AACjB,SAAK,oBAAoB;AACzB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,IAA+B;AACpC,UAAM,QAAQ,KAAK,OAAO,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE;AACtD,QAAI,UAAU,GAAI,QAAO;AACzB,UAAM,CAAC,KAAK,IAAI,KAAK,OAAO,OAAO,OAAO,CAAC;AAC3C,SAAK,OAAO,OAAO,MAAM,YAAY;AACrC,QAAI,MAAM,YAAa,MAAK,OAAO,OAAO,MAAM,WAAW;AAC3D,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,QAAQ,OAAuB;AAC7B,UAAM,WAAW,CAAC,GAAG,MAAM,QAAQ;AACnC,SAAK,SAAS,KAAK;AACnB,SAAK,OAAO,KAAK,iBAAiB,EAAE,SAAS,MAAM,GAAG,CAAC;AACvD,SAAK,YAAY;AACjB,SAAK,oBAAoB;AACzB,SAAK,OAAO,iBAAiB;AAC7B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,SAAS,OAAoB;AACnC,UAAM,UAAW,MAAM,aAAuB,UAAU;AACxD,UAAM,KAAK,KAAK,OAAO,UAAU,CAAC,MAAM,EAAE,OAAO,MAAM,EAAE;AACzD,UAAM,YAAY,MAAM;AACxB,UAAM,WAAW,CAAC;AAClB,eAAW,CAAC,OAAO,MAAM,KAAK,QAAQ,QAAQ,GAAG;AAC/C,aAAO,UAAU;AACjB,YAAM,QAAQ,UAAU,KAAK;AAC7B,UAAI,CAAC,MAAO;AACZ,YAAM,WAAW;AACjB,WAAK,OAAO,OAAO,KAAK,OAAO,GAAG,KAAK;AACvC,WAAK,OAAO,IAAI,MAAM;AACtB,UAAI,MAAM,YAAa,MAAK,OAAO,IAAI,MAAM,WAAW;AAAA,IAC1D;AACA,SAAK,OAAO,OAAO,MAAM,YAAY;AACrC,SAAK,SAAS,KAAK,OAAO,OAAO,CAAC,MAAM,EAAE,OAAO,MAAM,EAAE;AACzD,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,cAAc,OAAc,UAAyB;AACnD,eAAW,SAAS,SAAU,OAAM,WAAW,MAAM;AACrD,UAAM,WAAW;AACjB,SAAK,YAAY;AACjB,SAAK,oBAAoB;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,mBAAmB,OAAc,MAAyB;AACxD,UAAM,UAAW,MAAM,aAAuB,WAAW;AACzD,UAAM,WAAW,QAAQ,IAAI,CAAC,QAAQ,UAAU;AAC9C,YAAM,SAAS,KAAK,KAAK;AACzB,YAAM,QAAQ,IAAI,MAAM,QAAQ,QAAQ,SAAS,QAAQ,QAAQ,MAAM,QAAQ,EAAE;AACjF,YAAM,WAAW,MAAM;AACvB,UAAI,QAAQ,KAAM,OAAM,OAAO,gBAAgB,OAAO,IAAI;AAC1D,UAAI,UAAU,CAAC,OAAO,SAAS;AAC7B,cAAM,UAAU;AAChB,eAAO,UAAU;AAAA,MACnB;AACA,UAAI,QAAQ,QAAQ;AAClB,cAAM,SAAS;AACf,eAAO,aAAa;AACpB,eAAO,UAAU;AAAA,MACnB;AACA,UAAI,UAAU,OAAO,YAAY,GAAG;AAClC,cAAM,UAAU,OAAO;AACvB,eAAO,UAAU,OAAO;AAAA,MAC1B;AACA,aAAO;AAAA,IACT,CAAC;AACD,SAAK,YAAY;AAAA,EACnB;AAAA;AAAA,EAGA,cAAc,IAAY,cAAqC;AAC7D,UAAM,QAAQ,KAAK,IAAI,EAAE;AACzB,QAAI,CAAC,SAAS,MAAM,iBAAiB,aAAc,QAAO;AAC1D,UAAM,WAAW,MAAM;AACvB,UAAM,aAAa,KAAK,OAAO,WAAW,EAAE,QAAQ,QAAQ;AAC5D,UAAM,YAAY,KAAK,OAAO,gBAAgB,MAAM;AACpD,SAAK,OAAO,OAAO,QAAQ;AAC3B,UAAM,eAAe;AACrB,IAAC,aAAqD,WAAW;AACjE,iBAAa,IAAI;AAAA,MACf,SAAS,MAAM;AAAA,MACf,SAAS,MAAM;AAAA,MACf,YAAY,CAAC,MAAM;AAAA,MACnB,SAAS,CAAC,MAAM;AAAA,IAClB,CAAC;AACD,SAAK,OAAO,SAAS,KAAK,IAAI,GAAG,UAAU,GAAG,YAAY;AAG1D,QAAI,MAAM,aAAa;AACrB,mBAAa,IAAI,EAAE,SAAS,EAAE,CAAC;AAC/B,WAAK,WAAW;AAAA,IAClB;AACA,QAAI,UAAW,MAAK,OAAO,gBAAgB,YAAY;AACvD,SAAK,OAAO,iBAAiB;AAC7B,SAAK,OAAO,KAAK,kBAAkB,EAAE,SAAS,GAAG,CAAC;AAClD,SAAK,YAAY;AACjB,SAAK,oBAAoB;AACzB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,eAAe,IAAY,OAAkC;AAC3D,UAAM,QAAQ,KAAK,IAAI,EAAE;AACzB,QAAI,CAAC,SAAS,MAAM,gBAAgB,MAAO;AAC3C,QAAI,MAAM,YAAa,MAAK,OAAO,OAAO,MAAM,WAAW;AAC3D,UAAM,cAAc;AACpB,QAAI,OAAO;AAGT,MAAC,MAA8C,WAAW;AAC1D,YAAM,IAAI;AAAA,QACR,SAAS,MAAM;AAAA,QACf,SAAS,MAAM;AAAA,QACf,YAAY,CAAC,MAAM;AAAA,QACnB,SAAS,CAAC,MAAM;AAAA,MAClB,CAAC;AACD,WAAK,OAAO,IAAI,KAAK;AACrB,WAAK,WAAW;AAAA,IAClB;AACA,SAAK,OAAO,iBAAiB;AAC7B,SAAK,YAAY;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,aAAmB;AACzB,eAAW,SAAS,KAAK,QAAQ;AAC/B,WAAK,OAAO,mBAAmB,MAAM,YAAY;AACjD,UAAI,MAAM,YAAa,MAAK,OAAO,mBAAmB,MAAM,WAAW;AAAA,IACzE;AAAA,EACF;AAAA;AAAA,EAGQ,WAAW,OAAuB;AACxC,QAAI,CAAC,MAAM,SAAU,QAAO,KAAK;AACjC,WAAO,KAAK,IAAI,MAAM,QAAQ,GAAG,YAAY,KAAK;AAAA,EACpD;AAAA,EAEA,QAAQ,IAAY,UAA2B;AAC7C,UAAM,SAAS,KAAK,IAAI,EAAE;AAC1B,QAAI,CAAC,OAAQ,QAAO;AACpB,UAAM,OAAO,KAAK,WAAW,MAAM;AACnC,UAAM,WAAW,KAAK,QAAQ,MAAM;AACpC,QAAI,aAAa,GAAI,QAAO;AAC5B,QAAI,CAAC,OAAO,SAAS,QAAQ,EAAG,QAAO;AACvC,UAAM,UAAU,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,SAAS,GAAG,KAAK,MAAM,QAAQ,CAAC,CAAC;AAC3E,QAAI,aAAa,QAAS,QAAO;AACjC,UAAM,CAAC,KAAK,IAAI,KAAK,OAAO,UAAU,CAAC;AACvC,SAAK,OAAO,SAAS,GAAG,KAAK;AAC7B,QAAI,MAAM,UAAU;AAGlB,YAAM,QAAQ,KAAK,IAAI,MAAM,QAAQ,GAAG;AACxC,UAAI,OAAO;AACT,cAAM,OAAO,MAAM,YAAY;AAC/B,cAAM,SAAS,SAAS,MAAM,YAAY;AAAA,MAC5C;AAAA,IACF,OAAO;AACL,WAAK,WAAW;AAAA,IAClB;AACA,SAAK,OAAO,KAAK,mBAAmB,EAAE,UAAU,KAAK,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,CAAC;AACvE,SAAK,YAAY;AACjB,SAAK,oBAAoB;AACzB,WAAO;AAAA,EACT;AAAA,EAEA,OAAO,IAAyB;AAC9B,QAAI,OAAO,MAAM;AACf,WAAK,OAAO,oBAAoB;AAChC,WAAK,WAAW;AAAA,IAClB,OAAO;AACL,YAAM,QAAQ,KAAK,IAAI,EAAE;AACzB,UAAI,OAAO;AAIT,YAAI,MAAM,SAAU,MAAK,WAAW,MAAM,QAAQ;AAAA,YAC7C,MAAK,WAAW;AAIrB,aAAK,OAAO,gBAAgB,MAAM,eAAe,MAAM,YAAY;AAAA,MACrE;AAAA,IACF;AACA,SAAK,OAAO,iBAAiB;AAC7B,SAAK,OAAO,KAAK,kBAAkB,EAAE,SAAS,GAAG,CAAC;AAGlD,UAAM,WAAW,MAAM,KAAK,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC;AAC9C,SAAK,OAAO,KAAK,qBAAqB,EAAE,SAAS,CAAC;AAAA,EACpD;AAAA;AAAA,EAGQ,WAAW,SAAuB;AACxC,UAAM,SAAS,KAAK,IAAI,OAAO;AAC/B,QAAI,CAAC,OAAQ;AACb,UAAM,QAAQ,OAAO;AACrB,UAAM,iBAAiB;AACvB,UAAM,cAAc;AAAA,EACtB;AAAA;AAAA,EAGA,aAAmB;AACjB,eAAW,SAAS,KAAK,QAAQ;AAC/B,UAAI,MAAM,SAAS,QAAS;AAC5B,YAAM,QAAQ,MAAM;AACpB,UAAI,MAAM,YAAa,OAAM,cAAc;AAAA,IAC7C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW,KAAqB;AAC9B,UAAM,SAAS,IAAI,QAAQ,CAAC,OAAO;AACjC,YAAM,QAAQ,KAAK,IAAI,EAAE;AACzB,aAAO,SAAS,CAAC,MAAM,WAAW,CAAC,KAAK,IAAI,CAAC;AAAA,IAC/C,CAAC;AACD,QAAI,OAAO,WAAW,EAAG,QAAO,KAAK,OAAO,IAAI;AAChD,QAAI,OAAO,WAAW,EAAG,QAAO,KAAK,OAAO,OAAO,CAAC,EAAE,EAAE;AACxD,SAAK,OAAO,oBAAoB;AAChC,SAAK,WAAW;AAChB,UAAM,YAAY,IAAI;AAAA,MACpB,OAAO,IAAI,CAAC,MAAM,EAAE,eAAe,EAAE,YAAY;AAAA,MACjD,EAAE,QAAQ,KAAK,OAAO;AAAA,IACxB;AACA,SAAK,OAAO,gBAAgB,SAAS;AACrC,SAAK,OAAO,iBAAiB;AAG7B,SAAK,OAAO,KAAK,qBAAqB,EAAE,UAAU,OAAO,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,CAAC;AAAA,EAC7E;AAAA;AAAA,EAGA,CAAS,KAAK,SAAkB,KAAK,QAA0B;AAC7D,eAAW,SAAS,QAAQ;AAC1B,YAAM;AACN,UAAI,MAAM,SAAS,SAAS,EAAG,QAAO,KAAK,KAAK,MAAM,QAAQ;AAAA,IAChE;AAAA,EACF;AAAA,EAEA,IAAI,IAA+B;AACjC,eAAW,SAAS,KAAK,KAAK,EAAG,KAAI,MAAM,OAAO,GAAI,QAAO;AAC7D,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,SAAkB;AAChB,WAAO,CAAC,GAAG,KAAK,MAAM;AAAA,EACxB;AAAA;AAAA,EAGA,UAAuB;AACrB,WAAO,KAAK,OAAO,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC;AAAA,EAC1C;AAAA,EAEA,aAAa,KAAsC;AACjD,UAAM,UAAW,IAA6C;AAC9D,QAAI,QAAS,QAAO,KAAK,IAAI,OAAO;AACpC,eAAW,SAAS,KAAK,KAAK,EAAG,KAAI,MAAM,iBAAiB,IAAK,QAAO;AACxE,WAAO;AAAA,EACT;AAAA,EAEA,cAAc,IAAY,SAAwB;AAChD,UAAM,QAAQ,KAAK,IAAI,EAAE;AACzB,QAAI,CAAC,MAAO;AACZ,QAAI,MAAM,YAAY,QAAS;AAC/B,UAAM,UAAU;AAChB,UAAM,aAAa,UAAU;AAC7B,QAAI,MAAM,YAAa,OAAM,YAAY,UAAU;AACnD,SAAK,OAAO,iBAAiB;AAC7B,SAAK,YAAY;AACjB,SAAK,oBAAoB;AAAA,EAC3B;AAAA,EAEA,UAAU,IAAY,QAAuB;AAC3C,UAAM,QAAQ,KAAK,IAAI,EAAE;AACzB,QAAI,CAAC,MAAO;AACZ,QAAI,MAAM,WAAW,OAAQ;AAC7B,UAAM,SAAS;AAEf,UAAM,SAAS,MAAM,eAAe,MAAM;AAC1C,WAAO,aAAa,CAAC;AACrB,WAAO,UAAU,CAAC;AAClB,SAAK,OAAO,iBAAiB;AAC7B,SAAK,YAAY;AACjB,SAAK,oBAAoB;AAAA,EAC3B;AAAA,EAEA,WAAW,IAAY,SAAuB;AAC5C,UAAM,QAAQ,KAAK,IAAI,EAAE;AACzB,QAAI,CAAC,SAAS,CAAC,OAAO,SAAS,OAAO,EAAG;AACzC,UAAM,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC;AAC7C,QAAI,MAAM,YAAY,KAAM;AAC5B,UAAM,UAAU;AAGhB,QAAI,MAAM,YAAa,OAAM,YAAY,UAAU;AAAA,QAC9C,OAAM,aAAa,UAAU;AAClC,SAAK,OAAO,iBAAiB;AAC7B,SAAK,YAAY;AACjB,SAAK,oBAAoB;AAAA,EAC3B;AAAA,EAEA,QAAQ,IAAY,MAAoB;AACtC,UAAM,QAAQ,KAAK,IAAI,EAAE;AACzB,QAAI,CAAC,MAAO;AACZ,QAAI,MAAM,SAAS,KAAM;AACzB,UAAM,OAAO;AACb,SAAK,YAAY;AACjB,SAAK,oBAAoB;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,QAAQ,IAAY,OAAwB;AAC1C,UAAM,QAAQ,KAAK,IAAI,EAAE;AACzB,QAAI,CAAC,MAAO;AAEZ,UAAM,OAAkB,EAAE,GAAG,MAAM,KAAK;AACxC,QAAI,UAAU;AACd,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,UAAI,UAAU,QAAW;AACvB,YAAI,OAAO,MAAM;AACf,iBAAO,KAAK,GAAG;AACf,oBAAU;AAAA,QACZ;AACA;AAAA,MACF;AACA,UAAI,KAAK,GAAG,MAAM,MAAO,WAAU;AACnC,WAAK,GAAG,IAAI;AAAA,IACd;AACA,QAAI,CAAC,QAAS;AAEd,UAAM,OAAO;AACb,SAAK,YAAY;AACjB,SAAK,oBAAoB;AAAA,EAC3B;AAAA,EAEA,QAAc;AACZ,eAAW,SAAS,KAAK,QAAQ;AAC/B,WAAK,OAAO,OAAO,MAAM,YAAY;AACrC,UAAI,MAAM,YAAa,MAAK,OAAO,OAAO,MAAM,WAAW;AAE3D,YAAM,WAAW,CAAC;AAAA,IACpB;AACA,SAAK,SAAS,CAAC;AACf,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,QAAgB;AACd,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA,EAEQ,cAAoB;AAC1B,SAAK,OAAO,KAAK,kBAAkB;AAAA,MACjC,QAAQ,KAAK,OAAO,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC;AAAA,IAC3C,CAAC;AAAA,EACH;AACF;;;AEjhBA,IAAAC,iBAA2C;AAqB3C,IAAM,WAAW;AAajB,SAAS,OAAO,QAA4C;AAC1D,SAAO,OAAQ,OAA8B,SAAS;AACxD;AASA,SAAS,YACP,UACA,QACqB;AACrB,QAAM,SAAS,IAAI,IAAI,SAAS,WAAW,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;AAChF,QAAM,QAAQ,oBAAI,IAAoB;AACtC,aAAW,SAAS,SAAS,IAAI,SAAS,kCAAkC,GAAG;AAC7E,UAAM,QAAQ,gCAAgC,KAAK,MAAM,CAAC,CAAC;AAC3D,QAAI,CAAC,MAAO;AACZ,UAAM,QAAQ,OAAO,IAAI,MAAM,CAAC,CAAC;AACjC,QAAI,CAAC,MAAO;AACZ,UAAM,WAAW,OAAO,OAAO,MAAM,CAAC,CAAC,KAAK,MAAM,CAAC,KAAK,EAAE,EAAE,KAAK;AACjE,QAAI,SAAU,OAAM,IAAI,UAAU,KAAK;AAAA,EACzC;AACA,SAAO;AACT;AAEA,SAAS,SAAS,KAAa,QAAqC;AAClE,QAAM,UAAU,IAAI,KAAK;AACzB,QAAM,QAAQ,OAAO,IAAI,OAAO;AAChC,MAAI,MAAO,QAAO;AAClB,MAAI,CAAC,QAAS,QAAO;AACrB,SAAO,QAAQ,SAAS,WAAW,GAAG,QAAQ,MAAM,GAAG,WAAW,CAAC,CAAC,WAAM;AAC5E;AAEA,SAAS,UAAU,QAA8B;AAC/C,QAAM,KAAM,OAA4B;AACxC,MAAI,OAAO,OAAO,YAAY,GAAI,QAAO;AACzC,QAAM,OAAO,OAAO,QAAQ;AAC5B,SAAO,KAAK,OAAO,CAAC,EAAE,YAAY,IAAI,KAAK,MAAM,CAAC;AACpD;AASA,SAAS,UAAU,MAAgC;AACjD,QAAM,MAAM,IAAI,uBAAQ,KAAK,MAAM;AAAA,IACjC,MAAM,KAAK;AAAA,IACX,KAAK,KAAK;AAAA,IACV,SAAS,KAAK;AAAA,IACd,SAAS,KAAK;AAAA,IACd,OAAO,KAAK;AAAA,IACZ,QAAQ,KAAK;AAAA,IACb,QAAQ,KAAK;AAAA,IACb,UAAU,KAAK;AAAA,IACf,YAAY,KAAK;AAAA,IACjB,YAAY,KAAK;AAAA,IACjB,WAAW,KAAK;AAAA,IAChB,WAAW,KAAK;AAAA,IAChB,aAAa,KAAK;AAAA,IAClB,YAAY,KAAK;AAAA,IACjB,MAAM,KAAK;AAAA,IACX,QAAQ,KAAK;AAAA,IACb,aAAa,KAAK;AAAA,IAClB,SAAS,KAAK;AAAA;AAAA;AAAA,IAGd,OAAO,KAAK,IAAI,IAAI,KAAK,SAAS,KAAK,CAAC;AAAA,EAC1C,CAAC;AACD,SAAO;AACT;AASO,SAAS,cACd,UACA,QACA,UAC0B;AAE1B,MAAI,SAAS,OAAO,gBAAiB,QAAO,EAAE,KAAK,KAAK,MAAM,EAAE;AAChE,MAAI,SAAS,OAAO,YAAa,QAAO,EAAE,KAAK,GAAG,MAAM,GAAG;AAG3D,QAAM,SAAS,OAAO,OAAO,UAAU,GAAG;AAC1C,MAAI,CAAC,OAAO,SAAS,MAAM,KAAK,UAAU,EAAG,QAAO,EAAE,KAAK,GAAG,MAAM,EAAE;AACtE,QAAM,MAAO,MAAM,YAAa,KAAK,KAAK;AAC1C,SAAO,EAAE,KAAK,KAAK,IAAI,MAAM,KAAK,IAAI,KAAK,GAAG,CAAC,GAAG,MAAM,EAAE;AAC5D;AAGO,SAAS,aACd,UACA,QACmB;AACnB,QAAM,UAAU,OAAO,OAAO,QAAQ,MAAM;AAC5C,QAAM,WAAW,SAAS,OAAO,kBAAkB,KAAK;AACxD,QAAM,MAAM,IAAI,uBAAQ,SAAS;AAAA,IAC/B;AAAA,IACA,YAAY,OAAO,OAAO,QAAQ,OAAO;AAAA,IACzC,YAAY;AAAA,IACZ,MAAM,OAAO,OAAO,SAAS,SAAS;AAAA,IACtC,SAAS;AAAA,IACT,SAAS;AAAA;AAAA,IAET,OAAO,KAAK,IAAI,GAAG,QAAQ,SAAS,WAAW,IAAI;AAAA,EACrD,CAAC;AACD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM,SAAS,WAAW,KAAK,CAAC,MAAM,EAAE,QAAQ,MAAM,GAAG,SAAS;AAAA,IAClE,QAAQ;AAAA,IACR,OAAO,cAAc,UAAU,QAAQ,IAAI,SAAS,CAAC;AAAA,EACvD;AACF;AAMA,eAAsB,mBACpB,UACA,aACA,QAC8B;AAC9B,QAAM,SAAS,YAAY,UAAU,MAAM;AAC3C,QAAM,EAAE,QAAQ,IAAI,UAAM,kCAAkB,WAAW;AACvD,QAAM,QAA6B,CAAC;AACpC,aAAW,UAAU,SAAS;AAC5B,QAAI,WAAW,KAAM;AACrB,QAAI,OAAO,MAAM,GAAG;AAClB,YAAM,KAAK,EAAE,MAAM,QAAQ,MAAM,SAAS,OAAO,MAAM,MAAM,GAAG,QAAQ,UAAU,MAAM,EAAE,CAAC;AAC3F;AAAA,IACF;AACA,UAAM,KAAK,EAAE,MAAM,SAAS,MAAM,UAAU,MAAM,GAAG,OAAO,CAAC;AAAA,EAC/D;AACA,SAAO;AACT;;;ACjLO,IAAM,iBAAN,MAAM,gBAAe;AAAA,EAC1B,OAAwB,YAAY;AAAA,EAC5B,YAAsB,CAAC;AAAA,EACvB,YAAsB,CAAC;AAAA,EACvB,SAAS,oBAAI,IAAoB;AAAA,EACjC,WAAW,oBAAI,IAAoB;AAAA,EACnC,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA,SAAS;AAAA,EACT,gBAAsD;AAAA,EACtD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,mBAAmB;AAAA,EACnB,mBAAmB;AAAA,EAE3B,YAAY,MAOT;AACD,SAAK,WAAW,KAAK;AACrB,SAAK,eAAe,KAAK;AACzB,SAAK,SAAS,KAAK;AACnB,SAAK,UAAU,KAAK,WAAW;AAC/B,SAAK,WAAW,KAAK,YAAY,KAAK,OAAO;AAC7C,SAAK,aAAa,KAAK,cAAc;AAAA,EACvC;AAAA,EAEA,OAAa;AACX,QAAI,KAAK,OAAQ;AACjB,QAAI,KAAK,mBAAmB,GAAG;AAC7B,WAAK,mBAAmB;AACxB;AAAA,IACF;AAEA,QAAI,KAAK,eAAe;AACtB,mBAAa,KAAK,aAAa;AAAA,IACjC;AAEA,SAAK,gBAAgB,WAAW,MAAM;AACpC,WAAK,cAAc;AAAA,IACrB,GAAG,KAAK,UAAU;AAClB,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,gBAAsB;AACpB,QAAI,KAAK,QAAQ;AACf,WAAK,cAAc;AACnB;AAAA,IACF;AACA,QAAI,KAAK,mBAAmB,GAAG;AAC7B,WAAK,mBAAmB;AACxB;AAAA,IACF;AACA,SAAK,cAAc;AACnB,UAAM,WAAW,KAAK,SAAS;AAC/B,UAAM,QAAQ,KAAK,aAAa,QAAQ;AACxC,QAAI,KAAK,UAAU,GAAG,EAAE,MAAM,OAAO;AACnC,WAAK,YAAY;AACjB;AAAA,IACF;AACA,SAAK,UAAU,KAAK,KAAK;AACzB,WAAO,KAAK,UAAU,SAAS,KAAK,SAAS;AAC3C,WAAK,UAAU,MAAM;AAAA,IACvB;AACA,SAAK,YAAY,CAAC;AAClB,SAAK,aAAa;AAClB,SAAK,OAAO,KAAK,oBAAoB;AAAA,MACnC,OAAO,SAAS,SAAS;AAAA,MACzB,YAAY,KAAK,cAAc;AAAA,MAC/B,SAAS,KAAK,UAAU;AAAA,IAC1B,CAAC;AACD,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,mBAAyB;AAEvB,QAAI,KAAK,qBAAqB,KAAK,KAAK,cAAe,MAAK,cAAc;AAC1E,SAAK,oBAAoB;AAAA,EAC3B;AAAA,EAEA,iBAAuB;AACrB,QAAI,KAAK,qBAAqB,EAAG;AACjC,SAAK,oBAAoB;AACzB,QAAI,KAAK,qBAAqB,KAAK,KAAK,kBAAkB;AACxD,WAAK,mBAAmB;AACxB,WAAK,cAAc;AAAA,IACrB;AAAA,EACF;AAAA,EAEA,MAAM,YAAe,WAA6C;AAChE,SAAK,iBAAiB;AACtB,QAAI;AACF,aAAO,MAAM,UAAU;AAAA,IACzB,UAAE;AACA,WAAK,eAAe;AAAA,IACtB;AAAA,EACF;AAAA,EAEA,MAAM,OAAsB;AAG1B,SAAK,cAAc;AACnB,UAAM,YAAY,KAAK,UAAU,GAAG,EAAE;AACtC,QAAI,CAAC,UAAW;AAChB,UAAM,UAAU,KAAK,aAAa,KAAK,SAAS,CAAC;AAIjD,UAAM,qBAAqB,YAAY;AACvC,QAAI,sBAAsB,KAAK,UAAU,SAAS,EAAG;AACrD,UAAM,SAAS,qBAAqB,KAAK,UAAU,KAAK,UAAU,SAAS,CAAC,IAAI;AAEhF,SAAK,SAAS;AACd,QAAI;AACF,YAAM,KAAK,aAAa,KAAK,YAAY,MAAM,CAAC;AAChD,UAAI,mBAAoB,MAAK,UAAU,IAAI;AAC3C,WAAK,UAAU,KAAK,OAAO;AAC3B,WAAK,aAAa;AAAA,IACpB,SAAS,OAAO;AACd,WAAK,OAAO,KAAK,SAAS,EAAE,SAAS,kCAAkC,MAAM,CAAC;AAC9E,YAAM;AAAA,IACR,UAAE;AACA,WAAK,SAAS;AACd,WAAK,YAAY;AAAA,IACnB;AAAA,EACF;AAAA,EAEA,MAAM,OAAsB;AAC1B,SAAK,cAAc;AACnB,UAAM,QAAQ,KAAK,UAAU,GAAG,EAAE;AAClC,QAAI,CAAC,MAAO;AAEZ,SAAK,SAAS;AACd,QAAI;AACF,YAAM,KAAK,aAAa,KAAK,YAAY,KAAK,CAAC;AAC/C,WAAK,UAAU,IAAI;AACnB,UAAI,KAAK,UAAU,GAAG,EAAE,MAAM,MAAO,MAAK,UAAU,KAAK,KAAK;AAC9D,WAAK,aAAa;AAAA,IACpB,SAAS,OAAO;AACd,WAAK,OAAO,KAAK,SAAS,EAAE,SAAS,kCAAkC,MAAM,CAAC;AAC9E,YAAM;AAAA,IACR,UAAE;AACA,WAAK,SAAS;AACd,WAAK,YAAY;AAAA,IACnB;AAAA,EACF;AAAA;AAAA;AAAA,EAIA,cAAuB;AACrB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,QAAc;AACZ,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,SAAe;AACb,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,UAAmB;AACjB,WAAO,KAAK,UAAU,SAAS,KAAK,KAAK,kBAAkB;AAAA,EAC7D;AAAA,EAEA,UAAmB;AACjB,WAAO,KAAK,UAAU,SAAS;AAAA,EACjC;AAAA,EAEA,QAAc;AAGZ,SAAK,cAAc;AACnB,SAAK,YAAY,CAAC;AAClB,SAAK,YAAY,CAAC;AAClB,SAAK,OAAO,MAAM;AAClB,SAAK,SAAS,MAAM;AACpB,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,mBAA2B;AACzB,WAAO,KAAK,cAAc;AAAA,EAC5B;AAAA,EAEQ,gBAAsB;AAC5B,QAAI,KAAK,eAAe;AACtB,mBAAa,KAAK,aAAa;AAC/B,WAAK,gBAAgB;AAAA,IACvB;AAAA,EACF;AAAA,EAEA,UAAgB;AACd,SAAK,cAAc;AACnB,SAAK,mBAAmB;AACxB,SAAK,mBAAmB;AACxB,SAAK,YAAY,CAAC;AAClB,SAAK,YAAY,CAAC;AAClB,SAAK,OAAO,MAAM;AAClB,SAAK,SAAS,MAAM;AAAA,EACtB;AAAA,EAEQ,cAAoB;AAC1B,SAAK,OAAO,KAAK,mBAAmB;AAAA,MAClC,SAAS,KAAK,QAAQ;AAAA,MACtB,SAAS,KAAK,QAAQ;AAAA,IACxB,CAAC;AAAA,EACH;AAAA,EAEQ,gBAAwB;AAC9B,UAAM,aAAa,CAAC,GAAG,KAAK,WAAW,GAAG,KAAK,SAAS,EAAE;AAAA,MACxD,CAAC,OAAO,UAAU,QAAQ,MAAM,SAAS;AAAA,MACzC;AAAA,IACF;AACA,UAAM,aAAa,CAAC,GAAG,KAAK,OAAO,OAAO,CAAC,EAAE;AAAA,MAC3C,CAAC,OAAO,UAAU,QAAQ,MAAM,SAAS;AAAA,MACzC;AAAA,IACF;AACA,WAAO,aAAa;AAAA,EACtB;AAAA,EAEQ,eAAqB;AAI3B,SAAK,YAAY;AACjB,WAAO,KAAK,UAAU,SAAS,KAAK,KAAK,cAAc,IAAI,KAAK,UAAU;AACxE,WAAK,UAAU,MAAM;AACrB,WAAK,YAAY;AAAA,IACnB;AACA,WAAO,KAAK,UAAU,SAAS,KAAK,KAAK,cAAc,IAAI,KAAK,UAAU;AACxE,WAAK,UAAU,MAAM;AACrB,WAAK,YAAY;AAAA,IACnB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,aAAa,OAAuB;AAC1C,QAAI;AACJ,QAAI;AACF,eAAS,KAAK,MAAM,KAAK;AAAA,IAC3B,QAAQ;AACN,aAAO;AAAA,IACT;AACA,UAAM,QAAQ,CAAC,UAA4B;AACzC,UAAI,OAAO,UAAU,YAAY,0CAA0C,KAAK,KAAK,GAAG;AACtF,YAAI,KAAK,KAAK,SAAS,IAAI,KAAK;AAChC,YAAI,CAAC,IAAI;AACP,eAAK,IAAI,KAAK,aAAa;AAC3B,eAAK,SAAS,IAAI,OAAO,EAAE;AAC3B,eAAK,OAAO,IAAI,IAAI,KAAK;AAAA,QAC3B;AACA,eAAO,EAAE,CAAC,gBAAe,SAAS,GAAG,GAAG;AAAA,MAC1C;AACA,UAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,IAAI,KAAK;AAChD,UAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,aAAO,OAAO,YAAY,OAAO,QAAQ,KAAK,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,MAAM,KAAK,CAAC,CAAC,CAAC;AAAA,IAC5F;AACA,WAAO,KAAK,UAAU,MAAM,MAAM,CAAC;AAAA,EACrC;AAAA,EAEQ,YAAY,OAAuB;AACzC,QAAI;AACJ,QAAI;AACF,eAAS,KAAK,MAAM,KAAK;AAAA,IAC3B,QAAQ;AACN,aAAO;AAAA,IACT;AACA,UAAM,QAAQ,CAAC,UAA4B;AACzC,UAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,IAAI,KAAK;AAChD,UAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,YAAM,SAAS;AACf,YAAM,KAAK,OAAO,gBAAe,SAAS;AAC1C,UAAI,OAAO,OAAO,YAAY,OAAO,KAAK,MAAM,EAAE,WAAW,GAAG;AAC9D,cAAM,QAAQ,KAAK,OAAO,IAAI,EAAE;AAChC,YAAI,CAAC,MAAO,OAAM,IAAI,MAAM,iCAAiC,EAAE,EAAE;AACjE,eAAO;AAAA,MACT;AACA,aAAO,OAAO,YAAY,OAAO,QAAQ,MAAM,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,MAAM,KAAK,CAAC,CAAC,CAAC;AAAA,IAC7F;AACA,WAAO,KAAK,UAAU,MAAM,MAAM,CAAC;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,cAAoB;AAC1B,QAAI,KAAK,OAAO,SAAS,EAAG;AAC5B,UAAM,SAAS,CAAC,GAAG,KAAK,WAAW,GAAG,KAAK,SAAS;AACpD,eAAW,CAAC,IAAI,KAAK,KAAK,KAAK,QAAQ;AACrC,YAAM,SAAS,IAAI,gBAAe,SAAS,MAAM,EAAE;AACnD,UAAI,OAAO,KAAK,CAAC,UAAU,MAAM,SAAS,MAAM,CAAC,EAAG;AACpD,WAAK,OAAO,OAAO,EAAE;AACrB,WAAK,SAAS,OAAO,KAAK;AAAA,IAC5B;AAAA,EACF;AACF;;;AC/SA,IAAM,SAAS;AAOR,IAAM,cAAN,MAAkB;AAAA,EASvB,YACU,QACA,QACR;AAFQ;AACA;AAER,SAAK,WAAW,CAAC,MAAM,KAAK,aAAa,EAAE,MAAM;AACjD,SAAK,gBAAgB,MAAM,KAAK,WAAW;AAC3C,SAAK,aAAa,MAAM,KAAK,YAAY;AAEzC,SAAK,OAAO,GAAG,iBAAiB,KAAK,QAAQ;AAC7C,SAAK,OAAO,GAAG,gBAAgB,KAAK,aAAa;AACjD,SAAK,OAAO,GAAG,YAAY,KAAK,UAAU;AAC1C,SAAK,OAAO,GAAG,qBAAqB,KAAK,UAAU;AAAA,EACrD;AAAA,EAXU;AAAA,EACA;AAAA,EAVF,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,SAAsB,CAAC;AAAA,EAEd;AAAA,EACA;AAAA,EACA;AAAA,EAgBjB,WAAW,SAAwB;AACjC,QAAI,KAAK,YAAY,QAAS;AAC9B,SAAK,UAAU;AACf,QAAI,CAAC,QAAS,MAAK,YAAY;AAC/B,SAAK,OAAO,KAAK,gBAAgB,EAAE,QAAQ,CAAC;AAAA,EAC9C;AAAA,EAEA,YAAqB;AACnB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,aAAa,IAAkB;AAC7B,SAAK,YAAY,KAAK,IAAI,GAAG,EAAE;AAAA,EACjC;AAAA,EAEA,UAAgB;AACd,SAAK,OAAO,IAAI,iBAAiB,KAAK,QAAQ;AAC9C,SAAK,OAAO,IAAI,gBAAgB,KAAK,aAAa;AAClD,SAAK,OAAO,IAAI,YAAY,KAAK,UAAU;AAC3C,SAAK,OAAO,IAAI,qBAAqB,KAAK,UAAU;AACpD,SAAK,SAAS,CAAC;AAAA,EACjB;AAAA,EAEQ,aAAa,QAA6B;AAChD,QAAI,CAAC,KAAK,WAAW,CAAC,OAAQ;AAE9B,WAAO,UAAU;AACjB,UAAM,IAAI,OAAO,gBAAgB;AACjC,UAAM,KAAK,KAAK,OAAO,SAAS;AAChC,UAAM,KAAK,KAAK,OAAO,UAAU;AAGjC,UAAM,EAAE,IAAI,GAAG,IAAI,kBAAkB,KAAK,QAAQ,QAAQ,IAAI,EAAE;AAEhE,SAAK,SAAS,CAAC;AAEf,UAAM,KAAK,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,EAAE,OAAO,EAAE,KAAK,GAAG,IAAI,KAAK,SAAS;AACxF,QAAI,OAAO,MAAM;AACf,aAAO,IAAI,SAAS,OAAO,QAAQ,KAAK,GAAG,KAAK;AAChD,WAAK,OAAO,KAAK,EAAE,GAAG,GAAG,KAAK,CAAC;AAAA,IACjC;AAEA,UAAM,KAAK,SAAS,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,GAAG,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,SAAS;AACvF,QAAI,OAAO,MAAM;AACf,aAAO,IAAI,QAAQ,OAAO,OAAO,KAAK,GAAG,KAAK;AAC9C,WAAK,OAAO,KAAK,EAAE,GAAG,GAAG,KAAK,CAAC;AAAA,IACjC;AAEA,WAAO,UAAU;AAAA,EACnB;AAAA,EAEQ,aAAmB;AACzB,QAAI,CAAC,KAAK,WAAW,KAAK,OAAO,WAAW,EAAG;AAC/C,UAAM,MAAM,KAAK,OAAO;AACxB,QAAI,CAAC,IAAK;AAEV,UAAM,SAAS,KAAK,OAAO,iBAAiB;AAC5C,UAAM,KAAK,KAAK,OAAO,SAAS;AAChC,UAAM,KAAK,KAAK,OAAO,UAAU;AAEjC,QAAI,KAAK;AACT,QAAI,aAAa,QAAQ,GAAG,GAAG,QAAQ,GAAG,CAAC;AAC3C,QAAI,YAAY;AAChB,QAAI,cAAc;AAClB,QAAI,YAAY,CAAC,GAAG,CAAC,CAAC;AACtB,QAAI,UAAU;AACd,eAAW,KAAK,KAAK,QAAQ;AAC3B,UAAI,EAAE,MAAM,QAAW;AACrB,YAAI,OAAO,EAAE,GAAG,CAAC;AACjB,YAAI,OAAO,EAAE,GAAG,EAAE;AAAA,MACpB;AACA,UAAI,EAAE,MAAM,QAAW;AACrB,YAAI,OAAO,GAAG,EAAE,CAAC;AACjB,YAAI,OAAO,IAAI,EAAE,CAAC;AAAA,MACpB;AAAA,IACF;AACA,QAAI,OAAO;AACX,QAAI,QAAQ;AAAA,EACd;AAAA,EAEQ,cAAoB;AAC1B,QAAI,KAAK,OAAO,WAAW,EAAG;AAC9B,SAAK,SAAS,CAAC;AACf,SAAK,OAAO,aAAa,KAAK,OAAO,UAAU;AAAA,EACjD;AACF;AAMA,SAAS,kBACP,QACA,QACA,IACA,IACgC;AAChC,QAAM,KAAK,CAAC,GAAG,KAAK,GAAG,EAAE;AACzB,QAAM,KAAK,CAAC,GAAG,KAAK,GAAG,EAAE;AACzB,aAAW,OAAO,OAAO,WAAW,GAAG;AACrC,QAAI,QAAQ,UAAU,CAAC,IAAI,QAAS;AACpC,QAAI,UAAU;AACd,UAAM,IAAI,IAAI,gBAAgB;AAC9B,OAAG,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,EAAE,OAAO,EAAE,KAAK;AACtD,OAAG,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,GAAG,EAAE,MAAM,EAAE,MAAM;AAAA,EACvD;AACA,SAAO,EAAE,IAAI,GAAG;AAClB;AAMA,SAAS,SACP,OACA,YACA,WACwC;AACxC,MAAI,OAA6D;AACjE,aAAW,QAAQ,OAAO;AACxB,eAAW,KAAK,YAAY;AAC1B,YAAM,OAAO,KAAK,IAAI,OAAO,CAAC;AAC9B,UAAI,QAAQ,cAAc,SAAS,QAAQ,OAAO,KAAK,OAAO;AAC5D,eAAO,EAAE,OAAO,IAAI,MAAM,MAAM,GAAG,KAAK;AAAA,MAC1C;AAAA,IACF;AAAA,EACF;AACA,SAAO,OAAO,EAAE,OAAO,KAAK,OAAO,MAAM,KAAK,KAAK,IAAI;AACzD;;;ACxKA,IAAAC,iBAAqB;;;ACAd,SAAS,MAAM,GAAW,KAAa,KAAqB;AACjE,SAAO,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,CAAC,CAAC;AACvC;AAEO,SAAS,OAAO,GAAmB;AACxC,SAAO,KAAK,MAAM,IAAI,GAAG,IAAI;AAC/B;;;ADoBO,IAAM,iBAAN,MAAqB;AAAA,EAI1B,YACU,QACA,SACA,QACR;AAHQ;AACA;AACA;AAER,SAAK,qBAAqB,MAAM;AAE9B,UAAI,KAAK,QAAS,MAAK,OAAO;AAAA,IAChC;AACA,SAAK,OAAO,GAAG,qBAAqB,KAAK,kBAAkB;AAAA,EAC7D;AAAA,EATU;AAAA,EACA;AAAA,EACA;AAAA,EANF,UAA8B;AAAA,EACrB;AAAA,EAcjB,WAAoB;AAClB,WAAO,KAAK,YAAY;AAAA,EAC1B;AAAA,EAEA,gBAA+B;AAC7B,WAAO,KAAK,SAAS,WAAW;AAAA,EAClC;AAAA,EAEA,MAAM,OAAoB;AACxB,QAAI,MAAM,SAAS,QAAS;AAC5B,QAAI,KAAK,QAAS,MAAK,OAAO;AAE9B,UAAM,QAAQ,MAAM;AACpB,UAAM,YAAY,MAAM,SAAS;AACjC,QAAI,UAAW,OAAM,OAAO,CAAC;AAC7B,UAAM,UAAU;AAChB,UAAM,IAAI,MAAM,gBAAgB;AAEhC,UAAM,OAAO,IAAI,oBAAK;AAAA,MACpB,MAAM,EAAE;AAAA,MACR,KAAK,EAAE;AAAA,MACP,OAAO,EAAE;AAAA,MACT,QAAQ,EAAE;AAAA,MACV,SAAS;AAAA,MACT,SAAS;AAAA,MACT,MAAM;AAAA,MACN,QAAQC;AAAA,MACR,aAAa;AAAA,MACb,iBAAiB,CAAC,GAAG,CAAC;AAAA,MACtB,eAAe;AAAA,MACf,cAAc;AAAA,MACd,aAAaA;AAAA,MACb,oBAAoB;AAAA,IACtB,CAAC;AACD,SAAK,sBAAsB,EAAE,KAAK,MAAM,CAAC;AAEzC,UAAM,iBAAiB,MAAM,cAAc;AAC3C,UAAM,cAAc,MAAM,WAAW;AACrC,UAAM,aAAa;AACnB,UAAM,UAAU;AAEhB,SAAK,OAAO,IAAI,IAAI;AACpB,SAAK,OAAO,gBAAgB,IAAI;AAChC,SAAK,OAAO,iBAAiB;AAE7B,SAAK,UAAU,EAAE,SAAS,MAAM,IAAI,OAAO,MAAM,gBAAgB,aAAa,UAAU;AACxF,SAAK,OAAO,KAAK,gBAAgB,EAAE,QAAQ,MAAM,SAAS,MAAM,GAAG,CAAC;AAAA,EACtE;AAAA,EAEA,QAAc;AACZ,UAAM,IAAI,KAAK;AACf,QAAI,CAAC,EAAG;AACR,UAAM,EAAE,OAAO,KAAK,IAAI;AAExB,SAAK,UAAU;AACf,UAAM,UAAU;AAChB,UAAM,SAAS,MAAM,UAAU;AAC/B,UAAM,SAAS,MAAM,UAAU;AAC/B,UAAM,UAAU,MAAM,QAAQ;AAC9B,UAAM,SAAS,MAAM,OAAO;AAE5B,UAAM,KAAK,MAAM,WAAW;AAC5B,UAAM,WAAW,GAAG,gBAAgB,MAAM,SAAS;AACnD,UAAM,WAAW,GAAG,iBAAiB,MAAM,UAAU;AAGrD,QAAI,SAAS,MAAM,SAAS,MAAM,KAAK,OAAQ,WAAW;AAC1D,QAAI,SAAS,MAAM,SAAS,MAAM,KAAK,MAAO,UAAU;AACxD,QAAI,QAAQ,KAAK,eAAe,IAAI;AACpC,QAAI,QAAQ,KAAK,gBAAgB,IAAI;AAGrC,YAAQ,MAAM,OAAO,GAAG,KAAK,IAAI,GAAG,WAAW,CAAC,CAAC;AACjD,YAAQ,MAAM,OAAO,GAAG,KAAK,IAAI,GAAG,WAAW,CAAC,CAAC;AACjD,YAAQ,MAAM,OAAO,GAAG,WAAW,KAAK;AACxC,YAAQ,MAAM,OAAO,GAAG,WAAW,KAAK;AAExC,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA,OAAO;AAAA,MACP,QAAQ;AAAA;AAAA,MAER,MAAM,WAAW,SAAS,MAAM,SAAS,MAAM;AAAA,MAC/C,KAAK,UAAU,SAAS,MAAM,SAAS,MAAM;AAAA,IAC/C,CAAC;AACD,UAAM,UAAU;AAIhB,QAAI,EAAE,WAAW;AACf,YAAM,OAAO,EAAE,SAAS;AACxB,YAAM,UAAU;AAAA,IAClB;AAEA,SAAK,OAAO;AACZ,SAAK,QAAQ,KAAK;AAAA,EACpB;AAAA,EAEA,SAAe;AACb,UAAM,IAAI,KAAK;AACf,QAAI,CAAC,EAAG;AAER,QAAI,EAAE,WAAW;AACf,QAAE,MAAM,OAAO,EAAE,SAAS;AAC1B,QAAE,MAAM,UAAU;AAAA,IACpB;AACA,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,UAAgB;AACd,SAAK,OAAO;AACZ,SAAK,OAAO,IAAI,qBAAqB,KAAK,kBAAkB;AAAA,EAC9D;AAAA,EAEQ,SAAe;AACrB,UAAM,IAAI,KAAK;AACf,QAAI,CAAC,EAAG;AAGR,SAAK,UAAU;AAEf,SAAK,OAAO,OAAO,EAAE,IAAI;AACzB,MAAE,MAAM,aAAa,EAAE;AACvB,MAAE,MAAM,UAAU,EAAE;AACpB,SAAK,OAAO,gBAAgB,EAAE,KAAK;AACnC,SAAK,OAAO,iBAAiB;AAE7B,SAAK,OAAO,KAAK,gBAAgB,EAAE,QAAQ,OAAO,SAAS,KAAK,CAAC;AAAA,EACnE;AACF;AAEA,IAAMA,UAAS;;;AE9Kf,IAAAC,iBAAqB;;;ACArB,IAAAC,iBAAoC;;;ACO7B,IAAM,qBAAqB;AAsC3B,SAAS,qBACd,QACA,SACA,SACA,OACA,OACA,QACiB;AACjB,QAAM,SAAS,UAAU,EAAE,GAAG,UAAU,GAAG,GAAG,UAAU,EAAE;AAK1D,QAAM,SAAS,aAAa,QAAQ,SAAS,OAAO;AACpD,QAAM,OAAO,SAAS;AAItB,QAAM,UAAU,KAAK,IAAI,GAAG,OAAO,kBAAkB;AACrD,QAAM,QAAQ,KAAK,IAAI,SAAS,SAAS,IAAI,OAAO,oBAAoB,IAAI;AAC5E,QAAM,QAAQ,KAAK,IAAI,SAAS,SAAS,IAAI,OAAO,kBAAkB,IAAI;AAE1E,QAAM,OAAO,KAAK,KAAK,OAAO,KAAK,IAAI;AACvC,QAAM,OAAO,KAAK,KAAK,OAAO,KAAK,IAAI;AACvC,QAAM,WAAW,KAAK,KAAK,OAAO,CAAC;AACnC,QAAM,WAAW,KAAK,KAAK,OAAO,CAAC;AAKnC,QAAM,SAAS,SAAS,YAAY,OAAO,OAAO,IAAI;AACtD,QAAM,SAAS,SAAS,YAAY,OAAO,OAAO,IAAI;AAEtD,QAAM,aAA8B,CAAC;AACrC,WAAS,IAAI,CAAC,UAAU,KAAK,UAAU,KAAK;AAC1C,aAAS,IAAI,CAAC,UAAU,KAAK,UAAU,KAAK;AAC1C,UAAI,IAAI,IAAI,QAAQ;AACpB,UAAI,IAAI,IAAI,QAAQ;AAEpB,UAAI,OAAO,SAAS,sBAAsB,KAAK,CAAC,MAAM,GAAG;AACvD,aAAK,SAAS,OAAO,mBAAmB;AAAA,MAC1C,WAAW,OAAO,SAAS,oBAAoB,KAAK,CAAC,MAAM,GAAG;AAC5D,aAAK,SAAS,OAAO,mBAAmB;AAAA,MAC1C;AAEA,YAAM,YAAa,IAAI,OAAO,gBAAgB,IAAI,OAAO,iBAAiB,KAAK,KAAM;AACrF,iBAAW,KAAK,EAAE,GAAG,GAAG,SAAS,CAAC;AAAA,IACpC;AAAA,EACF;AACA,SAAO;AACT;AAWO,SAAS,UACd,KACA,KACA,QACA,SACA,SACA,OACA,OACA,QACA,MACM;AACN,QAAM,SAAS,UAAU,EAAE,GAAG,UAAU,GAAG,GAAG,UAAU,EAAE;AAC1D,QAAM,QAAQ,QAAQ,KAAK,QAAQ,IAAI,KAAK,QAAQ;AACpD,QAAM,QAAQ,QAAQ,KAAK,SAAS,IAAI,KAAK,SAAS;AACtD,MAAI,KAAK;AAET,MAAI,UAAU,OAAO,GAAG,OAAO,CAAC;AAChC,MAAI,OAAQ,OAAO,QAAQ,KAAK,KAAM,GAAG;AAEzC,aAAW,QAAQ,qBAAqB,QAAQ,SAAS,SAAS,OAAO,OAAO,MAAM,GAAG;AACvF,QAAI,KAAK;AACT,QAAI,UAAU,KAAK,GAAG,KAAK,CAAC;AAC5B,QAAI,OAAO,KAAK,QAAQ;AAGxB,QAAI,UAAU,KAAK,CAAC,QAAQ,GAAG,CAAC,QAAQ,GAAG,OAAO,KAAK;AACvD,QAAI,QAAQ;AAAA,EACd;AAEA,MAAI,QAAQ;AACd;AAGA,SAAS,aAAa,QAAuB,GAAW,GAAmB;AACzE,QAAM,KAAK,KAAK,IAAI,KAAK,IAAI,OAAO,CAAC,GAAG,KAAK,IAAI,IAAI,OAAO,CAAC,CAAC;AAC9D,QAAM,KAAK,KAAK,IAAI,KAAK,IAAI,OAAO,CAAC,GAAG,KAAK,IAAI,IAAI,OAAO,CAAC,CAAC;AAC9D,SAAO,KAAK,KAAK,KAAK,KAAK,KAAK,EAAE;AACpC;AAGA,SAAS,YAAY,OAAmC;AACtD,MAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,EAAG,QAAO;AACjE,SAAO,KAAK,IAAI,MAAM,KAAK,IAAI,KAAK,KAAK,CAAC;AAC5C;AAGA,SAAS,KAAK,GAAmB;AAC/B,UAAS,IAAI,IAAK,KAAK;AACzB;;;ADjJA,IAAM,sBAAsB;AAE5B,IAAM,qBAAqB;AAE3B,IAAM,yBAAyB;AAW/B,IAAM,uBAAuB;AAwBtB,IAAM,qBAAN,MAAM,4BAA2B,4BAAa;AAAA,EACnD,OAAO,OAAO;AAAA;AAAA,EAGd;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EAEQ,aAAuC;AAAA,EACvC,gBAAgB;AAAA,EAExB,YAAY,QAAsB,QAAuB,MAAmB;AAC1E,UAAM;AAAA;AAAA,MAEJ,SAAS;AAAA,MACT,SAAS;AAAA,MACT,eAAe;AAAA;AAAA,MAEf,iBAAiB;AAAA,IACnB,CAAC;AACD,SAAK,SAAS;AACd,SAAK,SAAS;AACd,SAAK,OAAO;AACZ,SAAK,sBAAsB,EAAE,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,MAAM,CAAC;AACzE,SAAK,QAAQ;AAAA,EACf;AAAA;AAAA,EAGA,UAAU,QAA6B;AACrC,SAAK,SAAS;AACd,SAAK,QAAQ;AAAA,EACf;AAAA;AAAA,EAGA,QAAQ,MAAyB;AAC/B,SAAK,OAAO;AACZ,SAAK,WAAW;AAChB,SAAK,QAAQ;AAAA,EACf;AAAA;AAAA,EAGA,aAAmB;AACjB,SAAK,aAAa;AAClB,SAAK,gBAAgB;AACrB,SAAK,QAAQ;AAAA,EACf;AAAA;AAAA,EAGA,UAAgB;AACd,SAAK,aAAa;AAClB,SAAK,gBAAgB;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,UAAgB;AACd,UAAM,EAAE,OAAO,MAAM,IAAI,KAAK,SAAS;AACvC,UAAM,SAAS,KAAK,OAAO,eAAe;AAC1C,UAAM,SAAS,KAAK,iBAAiB,QAAQ,OAAO,OAAO,KAAK,OAAO,KAAK;AAC5E,SAAK,IAAI;AAAA,MACP,MAAM,OAAO;AAAA,MACb,KAAK,OAAO;AAAA,MACZ,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,OAAO,KAAK,OAAO;AAAA,IACrB,CAAC;AACD,SAAK,UAAU;AACf,SAAK,QAAQ;AAAA,EACf;AAAA;AAAA,EAGA,YAAoB;AAClB,WAAO,KAAK,SAAS;AAAA,EACvB;AAAA;AAAA,EAGA,YAAoB;AAClB,YAAQ,KAAK,OAAO,SAAS,OAAO,KAAK,IAAI,KAAK,UAAU,CAAC;AAAA,EAC/D;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAoB;AAClB,UAAM,EAAE,OAAO,MAAM,IAAI,KAAK,SAAS;AACvC,UAAM,SAAS,KAAK,eAAe;AACnC,UAAM,QAAQ,KAAK,YAAY,OAAO,OAAO,KAAK,UAAU,CAAC;AAC7D,WAAO,IAAI,qBAAM,OAAO,IAAI,MAAM,GAAG,OAAO,IAAI,MAAM,CAAC;AAAA,EACzD;AAAA,EAEA,QAAQ,KAAqC;AAC3C,UAAM,EAAE,OAAO,OAAO,IAAI,KAAK;AAC/B,QAAI,SAAS,KAAK,UAAU,EAAG;AAE/B,UAAM,EAAE,OAAO,MAAM,IAAI,KAAK,SAAS;AACvC,UAAM,QAAQ,aAAa,GAAG;AAC9B,UAAM,WAAW,KAAK,eAAe,SAAS,QAAQ,KAAK,IAAI,GAAG,KAAK,MAAM,CAAC,EAAE;AAChF,QAAI,CAAC,SAAU;AAEf,UAAM,SAAS,KAAK,eAAe;AACnC,UAAM,QAAQ,KAAK,UAAU;AAC7B,QAAI,KAAK;AAGT,QAAI,MAAM,KAAK,KAAK,UAAU,IAAI,KAAK,KAAK,UAAU,EAAE;AACxD,QAAI,OAAQ,CAAC,QAAQ,KAAK,KAAM,GAAG;AACnC,QAAI,UAAU,CAAC,OAAO,GAAG,CAAC,OAAO,CAAC;AAElC,UAAM,QAAQ,KAAK,YAAY,OAAO,OAAO,KAAK;AAClD,UAAM,SAAwB,EAAE,GAAG,OAAO,IAAI,MAAM,GAAG,GAAG,OAAO,IAAI,MAAM,EAAE;AAG7E,UAAM,SAAS,EAAE,GAAG,KAAK,QAAQ,OAAO,SAAS,GAAG,SAAS,EAAE;AAC/D;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,KAAK,SAAS,OAAO,OAAO,uBAAuB,KAAK;AAAA,IAC1D;AACA,QAAI,QAAQ;AAAA,EACd;AAAA;AAAA,EAGA,SAAmB;AACjB,UAAM,EAAE,OAAO,OAAO,IAAI,KAAK;AAC/B,QAAI,SAAS,KAAK,UAAU,EAAG,QAAO,CAAC;AACvC,UAAM,KAAK,SAAS,cAAc,QAAQ;AAC1C,OAAG,QAAQ,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,CAAC;AACxC,OAAG,SAAS,KAAK,IAAI,GAAG,KAAK,MAAM,MAAM,CAAC;AAC1C,UAAM,MAAM,GAAG,WAAW,IAAI;AAC9B,QAAI,CAAC,IAAK,QAAO,CAAC;AAElB,UAAM,EAAE,OAAO,MAAM,IAAI,KAAK,SAAS;AACvC,UAAM,WAAW,KAAK,eAAe,QAAQ,KAAK,IAAI,GAAG,KAAK,MAAM,CAAC,CAAC;AACtE,QAAI,CAAC,SAAU,QAAO,CAAC;AACvB,UAAM,SAAS,KAAK,eAAe;AACnC,UAAM,QAAQ,KAAK,UAAU;AAC7B,UAAM,QAAQ,KAAK,YAAY,OAAO,OAAO,KAAK;AAClD;AAAA,MACE;AAAA,MACA;AAAA,MACA,EAAE,GAAG,KAAK,QAAQ,OAAO,SAAS,GAAG,SAAS,EAAE;AAAA,MAChD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,EAAE,GAAG,OAAO,IAAI,MAAM,GAAG,GAAG,OAAO,IAAI,MAAM,EAAE;AAAA;AAAA,MAE/C,KAAK,SAAS,OAAO,OAAO,oBAAoB;AAAA,IAClD;AAGA,WAAO;AAAA,MACL,wBAAwB,CAAC,KAAK,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC;AAAA,MACnE,6BAA6B,KAAK,aAAa,MAAM;AAAA,MACrD,eAAe,GAAG,UAAU,WAAW,CAAC;AAAA;AAAA,IAC1C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,WAAoC;AAClC,UAAM,QAAQ,MAAM,SAAS;AAC7B,WAAO,MAAM;AACb,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,QAAuB;AACrB,UAAM,OAAO,IAAI,oBAAmB,KAAK,QAAQ,KAAK,QAAQ,KAAK,IAAI;AACvE,SAAK,IAAI;AAAA,MACP,MAAM,KAAK;AAAA,MACX,KAAK,KAAK;AAAA,MACV,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,MACb,QAAQ,KAAK;AAAA,MACb,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,MACb,SAAS,KAAK;AAAA,MACd,SAAS,KAAK;AAAA,IAChB,CAAC;AACD,WAAO,QAAQ,QAAQ,IAAY;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYQ,YAA+C;AACrD,UAAM,OAAO,KAAK,OAAO,gBAAgB;AACzC,QAAI,aAAa,KAAK,MAAM,EAAG,QAAO,EAAE,OAAO,KAAK,OAAO,QAAQ,KAAK,OAAO;AAG/E,UAAM,OAAO,KAAK,OAAO,0BAA0B,EAAE,aAAa,EAAE,CAAC;AACrE,UAAM,WAAY,KAAK,OAAO,SAAS,KAAK,KAAK,KAAM;AACvD,UAAM,MAAM,KAAK,IAAI,KAAK,IAAI,OAAO,CAAC;AACtC,UAAM,MAAM,KAAK,IAAI,KAAK,IAAI,OAAO,CAAC;AACtC,WAAO;AAAA,MACL,OAAO,KAAK,IAAI,MAAM,KAAK,IAAI;AAAA,MAC/B,QAAQ,KAAK,IAAI,MAAM,KAAK,IAAI;AAAA,IAClC;AAAA,EACF;AAAA;AAAA,EAGQ,QAAgB;AACtB,WAAO,KAAK,IAAI,GAAG,KAAK,UAAU,EAAE,KAAK;AAAA,EAC3C;AAAA;AAAA,EAGQ,QAAgB;AACtB,WAAO,KAAK,IAAI,GAAG,KAAK,UAAU,EAAE,MAAM;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYQ,SAAS,OAAe,OAAe,QAAQ,GAAiB;AACtE,UAAM,WAAW,KAAK;AACtB,QAAI,CAAC,YAAY,KAAK,iBAAiB,GAAG;AACxC,aAAO,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,MAAM;AAAA,IACvD;AACA,WAAO;AAAA,MACL,OAAQ,SAAS,QAAQ,KAAK,iBAAkB,QAAQ,KAAK,MAAM,KAAK;AAAA,MACxE,QAAS,SAAS,SAAS,KAAK,iBAAkB,QAAQ,KAAK,MAAM,KAAK;AAAA,IAC5E;AAAA,EACF;AAAA;AAAA,EAGQ,WAA6C;AACnD,UAAM,MAAM,KAAK,UAAU;AAC3B,UAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,OAAO,SAAS,GAAG,IAAI;AACtD,UAAM,QAAQ,KAAK,UAAU;AAC7B,WAAO;AAAA,MACL,OAAO,KAAK,IAAI,OAAO,IAAI,QAAQ,KAAK;AAAA,MACxC,OAAO,KAAK,IAAI,OAAO,IAAI,SAAS,KAAK;AAAA,IAC3C;AAAA,EACF;AAAA;AAAA,EAGQ,WAA6C;AACnD,UAAM,OAAO,KAAK,SAAS;AAC3B,UAAM,QAAQ,KAAK,UAAU;AAC7B,WAAO;AAAA,MACL,OAAO,KAAK,IAAI,OAAO,KAAK,QAAQ,KAAK,IAAI,KAAK,UAAU,CAAC,CAAC;AAAA,MAC9D,OAAO,KAAK,IAAI,OAAO,KAAK,QAAQ,KAAK,IAAI,KAAK,UAAU,CAAC,CAAC;AAAA,IAChE;AAAA,EACF;AAAA;AAAA,EAGQ,YAAoB;AAC1B,UAAM,EAAE,OAAO,OAAO,IAAI,KAAK;AAC/B,WAAO,KAAK,IAAI,GAAG,KAAK,KAAK,QAAQ,QAAQ,SAAS,MAAM,IAAI,GAAG;AAAA,EACrE;AAAA;AAAA,EAGQ,YAAY,OAAe,OAAe,OAAsB;AACtE,UAAM,KAAK,SAAS,aAAa,KAAK,OAAO,OAAO,IAAI;AACxD,UAAM,KAAK,SAAS,aAAa,KAAK,OAAO,OAAO,IAAI;AACxD,UAAM,UAAW,QAAQ,KAAK,KAAM;AACpC,UAAM,MAAM,KAAK,IAAI,OAAO;AAC5B,UAAM,MAAM,KAAK,IAAI,OAAO;AAC5B,WAAO,IAAI,qBAAM,KAAK,MAAM,KAAK,KAAK,KAAK,MAAM,KAAK,GAAG;AAAA,EAC3D;AAAA,EAEQ,iBAAiB,QAAe,OAAe,OAAe,OAAsB;AAC1F,UAAM,QAAQ,KAAK,YAAY,OAAO,OAAO,KAAK;AAClD,WAAO,IAAI,qBAAM,OAAO,IAAI,MAAM,GAAG,OAAO,IAAI,MAAM,CAAC;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,eAAe,OAAyC;AAC9D,UAAM,SAAS,KAAK,WAAW,KAAK;AACpC,UAAM,QACJ,KAAK,OAAO,SACZ,CAAC,KAAK,cACN,KAAK,gBAAgB,UACrB,KAAK,gBAAgB,SAAS;AAChC,QAAI,CAAC,MAAO,QAAO,KAAK;AAIxB,UAAM,SAAS,KAAK;AACpB,UAAM,UAAU,OAAO;AACvB,WAAO,UAAU;AACjB,QAAI;AACF,YAAM,KAAK,OAAO,gBAAgB,EAAE,YAAY,QAAQ,qBAAqB,MAAM,CAAC;AACpF,UAAI,CAAC,GAAG,SAAS,CAAC,GAAG,OAAQ,QAAO;AACpC,WAAK,aAAa;AAClB,WAAK,gBAAgB;AAAA,IACvB,QAAQ;AAGN,aAAO,KAAK;AAAA,IACd,UAAE;AACA,aAAO,UAAU;AAGjB,aAAO,QAAQ;AAAA,IACjB;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGQ,WAAW,OAAuB;AACxC,UAAM,YAAY,KAAK,IAAI,oBAAoB,KAAK,IAAI,MAAM,KAAK,CAAC;AACpE,UAAM,OAAO,KAAK,OAAO,gBAAgB;AACzC,UAAM,OAAO,KAAK,IAAI,GAAG,KAAK,QAAQ,KAAK,MAAM;AACjD,UAAM,WAAW,KAAK,KAAK,sBAAsB,IAAI;AACrD,WAAO,KAAK,IAAI,MAAM,KAAK,IAAI,WAAW,QAAQ,CAAC;AAAA,EACrD;AACF;AAGA,SAAS,aAAa,QAA+B;AACnD,MAAI,CAAC,OAAO,eAAe,OAAO,eAAe,EAAG,QAAO;AAC3D,QAAM,EAAE,OAAO,IAAI;AACnB,MAAI,OAAO,WAAW,SAAU,QAAO,WAAW,MAAM,WAAW;AAEnE,SAAO,WAAW,QAAQ,WAAW;AACvC;AAGA,SAAS,aAAa,OAAmC;AACvD,MAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,EAAG,QAAO;AACjE,SAAO,KAAK,IAAI,MAAM,KAAK,IAAI,KAAK,KAAK,CAAC;AAC5C;AAOA,SAAS,aAAa,KAAuC;AAC3D,MAAI,OAAO,IAAI,iBAAiB,WAAY,QAAO;AACnD,MAAI;AACF,UAAM,IAAI,IAAI,aAAa;AAC3B,WAAO,KAAK,IAAI,KAAK,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,KAAK,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,IAAI;AAAA,EAClE,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AD9ZA,IAAM,iBAAiB;AACvB,IAAM,iBAAiB;AAYhB,IAAM,iBAAN,MAAqB;AAAA,EAmB1B,YACU,QACA,QACA,SACA,QACR;AAJQ;AACA;AACA;AACA;AAKR,SAAK,OAAO,GAAG,mBAAmB,KAAK,gBAAgB;AACvD,SAAK,OAAO,GAAG,gBAAgB,KAAK,gBAAgB;AACpD,SAAK,OAAO,GAAG,iBAAiB,KAAK,cAAc;AAAA,EACrD;AAAA,EAXU;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAtBF,UAAU,oBAAI,IAAgC;AAAA,EACrC,mBAAmB,CAAC,UAAqC;AACxE,UAAM,SAAS,MAAM;AACrB,QAAI,kBAAkB,mBAAoB,MAAK,cAAc,MAAM;AAAA,QAC9D,MAAK,cAAc,MAAM;AAAA,EAChC;AAAA,EACiB,mBAAmB,CAAC,UAAqC;AACxE,SAAK,cAAc,MAAM,MAAM;AAAA,EACjC;AAAA,EACiB,iBAAiB,CAAC,EAAE,QAAQ,MAA2B;AAGtE,UAAM,QAAQ,KAAK,QAAQ,IAAI,OAAO;AACtC,QAAI,CAAC,MAAO;AACZ,UAAM,QAAQ;AACd,SAAK,QAAQ,OAAO,OAAO;AAAA,EAC7B;AAAA,EAgBA,UAAU,SAA0B;AAClC,WAAO,CAAC,CAAC,KAAK,OAAO,IAAI,OAAO,GAAG,KAAK;AAAA,EAC1C;AAAA,EAEA,UAAU,SAAuC;AAC/C,WAAO,KAAK,OAAO,IAAI,OAAO,GAAG,KAAK,SAAS,UAAU;AAAA,EAC3D;AAAA;AAAA,EAGA,MAAM,MAAM,SAAiB,QAAsC;AACjE,UAAM,QAAQ,KAAK,OAAO,IAAI,OAAO;AACrC,QAAI,CAAC,MAAO;AACZ,QAAI;AACF,WAAK,OAAO,QAAQ,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;AACpD,YAAM,QAAQ,KAAK,QAAQ,IAAI,OAAO;AACtC,UAAI,OAAO;AACT,cAAM,UAAU,MAAM;AACtB,aAAK,OAAO,iBAAiB;AAAA,MAC/B,OAAO;AACL,aAAK,OAAO,OAAO,MAAM;AAAA,MAC3B;AACA,WAAK,QAAQ,KAAK;AAAA,IACpB,SAAS,OAAO;AACd,WAAK,OAAO,KAAK,SAAS,EAAE,SAAS,2BAA2B,MAAM,CAAC;AACvE,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,QAAQ,SAAgC;AAC5C,UAAM,QAAQ,KAAK,OAAO,IAAI,OAAO;AACrC,QAAI,CAAC,OAAO,KAAK,QAAS;AAC1B,QAAI;AACF,WAAK,OAAO,OAAO;AAGnB,mBAAa,MAAM,cAAc,MAAM,KAAK,QAAQ,aAAa;AAEjE,YAAM,aAAa,IAAI;AAAA,QACrB,SAAS,MAAM;AAAA,QACf,YAAY,CAAC,MAAM;AAAA,QACnB,SAAS,CAAC,MAAM;AAAA,MAClB,CAAC;AACD,WAAK,OAAO,QAAQ,SAAS,EAAE,SAAS,OAAU,CAAC;AACnD,WAAK,OAAO,iBAAiB;AAC7B,WAAK,QAAQ,KAAK;AAAA,IACpB,SAAS,OAAO;AACd,WAAK,OAAO,KAAK,SAAS,EAAE,SAAS,2BAA2B,MAAM,CAAC;AACvE,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,eAA8B;AAGlC,SAAK,aAAa;AAClB,eAAW,SAAS,KAAK,OAAO,OAAO,GAAG;AACxC,YAAM,QAAQ,MAAM,KAAK;AACzB,UAAI,CAAC,MAAO;AACZ,UAAI;AACF,YAAI,cAAc,KAAK,GAAG;AACxB,gBAAM,kBAAkB,OAAO,KAAK;AAGpC,eAAK,OAAO,QAAQ,MAAM,IAAI,EAAE,SAAS,EAAE,QAAQ,MAAM,OAAO,EAAE,CAAC;AAAA,QACrE;AACA,aAAK,OAAO,OAAO,MAAM,MAAM;AAAA,MACjC,SAAS,OAAO;AACd,aAAK,OAAO,KAAK,SAAS,EAAE,SAAS,mCAAmC,MAAM,CAAC;AAAA,MACjF;AAAA,IACF;AACA,SAAK,OAAO,iBAAiB;AAAA,EAC/B;AAAA;AAAA,EAGA,WAAiB;AACf,UAAM,OAAO,KAAK,KAAK;AACvB,eAAW,SAAS,KAAK,QAAQ,OAAO,EAAG,OAAM,QAAQ,IAAI;AAC7D,QAAI,KAAK,QAAQ,OAAO,EAAG,MAAK,OAAO,iBAAiB;AAAA,EAC1D;AAAA;AAAA,EAGA,WAAW,SAAuB;AAChC,UAAM,QAAQ,KAAK,QAAQ,IAAI,OAAO;AACtC,QAAI,CAAC,MAAO;AACZ,UAAM,WAAW;AAEjB,UAAM,QAAQ;AACd,SAAK,OAAO,iBAAiB;AAAA,EAC/B;AAAA;AAAA,EAGA,SAAS,OAAoB;AAC3B,UAAM,QAAQ,MAAM,KAAK;AACzB,QAAI,CAAC,SAAS,KAAK,QAAQ,IAAI,MAAM,EAAE,EAAG;AAC1C,SAAK,OAAO,OAAO,MAAM,MAAM;AAAA,EACjC;AAAA,EAEA,UAAgB;AACd,SAAK,OAAO,IAAI,mBAAmB,KAAK,gBAAgB;AACxD,SAAK,OAAO,IAAI,gBAAgB,KAAK,gBAAgB;AACrD,SAAK,OAAO,IAAI,iBAAiB,KAAK,cAAc;AACpD,SAAK,aAAa;AAAA,EACpB;AAAA;AAAA,EAGQ,eAAqB;AAC3B,eAAW,SAAS,KAAK,QAAQ,OAAO,EAAG,OAAM,QAAQ;AACzD,SAAK,QAAQ,MAAM;AAAA,EACrB;AAAA,EAEQ,OAAO,OAAc,QAA6B;AACxD,UAAM,QAAQ,IAAI,mBAAmB,MAAM,cAAc,QAAQ,KAAK,KAAK,CAAC;AAK5E,UAAM,YAAY,KAAK,OAAO,gBAAgB,MAAM,MAAM;AAC1D,UAAM,aAAa,IAAI,EAAE,SAAS,GAAG,YAAY,OAAO,SAAS,MAAM,CAAC;AACxE,SAAK,QAAQ,IAAI,MAAM,IAAI,KAAK;AAChC,SAAK,OAAO,eAAe,MAAM,IAAI,KAAK;AAG1C,QAAI,UAAW,MAAK,OAAO,gBAAgB,KAAK;AAChD,SAAK,OAAO,iBAAiB;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,cAAc,OAAiC;AACrD,UAAM,QAAQ,KAAK,OAAO,aAAa,KAAK;AAC5C,UAAM,QAAQ,OAAO,KAAK;AAC1B,QAAI,CAAC,SAAS,CAAC,MAAO;AAEtB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,QAAQC,OAAM,MAAM,UAAU,GAAG,gBAAgB,cAAc;AACrE,UAAM,QAAQ,eAAe,MAAM,UAAU,CAAC;AAE9C,UAAM,aAAa,oBAAoB,QAAQ,UAAU,QAAQ;AACjE,UAAM,aAAa,UAAU;AAE7B,UAAM,SAAwB,EAAE,GAAG,MAAM,QAAQ,OAAO,MAAM;AAC9D,SAAK,OAAO,QAAQ,MAAM,IAAI,EAAE,SAAS,EAAE,GAAG,OAAO,OAAO,EAAE,CAAC;AAC/D,UAAM,UAAU,MAAM;AACtB,SAAK,OAAO,iBAAiB;AAC7B,SAAK,QAAQ,KAAK;AAAA,EACpB;AAAA,EAEQ,OAAoB;AAC1B,WAAO,EAAE,OAAO,KAAK,OAAO,SAAS,GAAG,QAAQ,KAAK,OAAO,UAAU,EAAE;AAAA,EAC1E;AAAA,EAEQ,OAAO,SAAuB;AACpC,UAAM,QAAQ,KAAK,QAAQ,IAAI,OAAO;AACtC,QAAI,CAAC,OAAO;AACV,WAAK,OAAO,eAAe,SAAS,IAAI;AACxC;AAAA,IACF;AACA,SAAK,OAAO,eAAe,SAAS,IAAI;AACxC,UAAM,QAAQ;AACd,SAAK,QAAQ,OAAO,OAAO;AAAA,EAC7B;AAAA,EAEQ,cAAc,QAAwC;AAC5D,QAAI,CAAC,OAAQ;AACb,UAAM,QAAQ,KAAK,OAAO,aAAa,MAAM;AAC7C,QAAI,MAAO,MAAK,WAAW,MAAM,EAAE;AAAA,EACrC;AACF;AAEA,SAASA,OAAM,OAAe,KAAa,KAAqB;AAC9D,MAAI,CAAC,OAAO,SAAS,KAAK,EAAG,QAAO;AACpC,SAAO,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,KAAK,CAAC;AAC3C;AAGA,SAAS,eAAe,OAAuB;AAC7C,MAAI,CAAC,OAAO,SAAS,KAAK,EAAG,QAAO;AACpC,QAAM,WAAY,QAAQ,MAAO,OAAO;AACxC,SAAO,KAAK,MAAM,UAAU,MAAM,UAAU,MAAM,OAAO;AAC3D;AAGA,SAAS,cAAc,OAA8B;AACnD,SAAO,OAAO,MAAM,gBAAgB,YAAY,MAAM,YAAY,SAAS;AAC7E;AAUA,eAAe,kBAAkB,OAAc,OAAoC;AACjF,QAAM,QAAQ,MAAM;AACpB,MAAI,OAAO,MAAM,WAAW,cAAc,CAAC,MAAM,SAAU;AAE3D,QAAM,MAAM,OAAO,MAAM,WAAqB;AAG9C,QAAM,IAAI;AAAA,IACR,MAAM,MAAM,SAAS;AAAA,IACrB,KAAK,MAAM,SAAS;AAAA,IACpB,QAAQ,MAAM,SAAS;AAAA,IACvB,QAAQ,MAAM,SAAS;AAAA,IACvB,OAAO,MAAM,SAAS;AAAA,IACtB,QAAQ,MAAM,SAAS;AAAA,IACvB,OAAO,MAAM,SAAS;AAAA,IACtB,OAAO,MAAM,SAAS;AAAA,IACtB,OAAO,MAAM,SAAS;AAAA,EACxB,CAAC;AACD,QAAM,WAAW,MAAM,gBACjB,MAAM,oBAAK,eAAe,CAAC,MAAM,YAAY,CAAC,GAAG,CAAC,IACpD;AACJ,eAAa,OAAO,MAAM,aAAa;AACvC,QAAM,UAAU;AAClB;AAOO,SAAS,aAAa,KAAmB,OAAuC;AACrF,MAAI;AAAA,IACF,SAAS;AAAA,MACP,eAAe;AAAA,MACf,eAAe;AAAA,MACf,cAAc;AAAA,MACd,cAAc;AAAA,MACd,cAAc;AAAA,MACd,aAAa;AAAA,IACf;AAAA,EACF;AACF;;;AG5SA,IAAAC,iBAAqB;;;ACId,IAAM,qBAAsC;AAAA,EACjD,OAAO;AAAA,EACP,KAAK;AAAA,EACL,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,cAAc;AAChB;AAGO,IAAM,UAAU;AAEvB,IAAM,kBAAkB;AAExB,IAAM,YAAY;AAElB,IAAM,oBAAoB;AAEnB,IAAM,kBAAkB;AACxB,IAAM,kBAAkB;AAE/B,IAAM,YAAY;AAClB,IAAM,iBAAiB;AASvB,SAAS,MAAM,OAAuB;AACpC,SAAO,KAAK,MAAM,QAAQ,GAAG,IAAI;AACnC;AAQO,SAAS,mBAAmB,QAAyC;AAC1E,QAAM,MAAM,MAAM,OAAO,OAAO,GAAG,MAAM,GAAG;AAC5C,QAAM,OAAO,MAAM,OAAO,QAAQ,GAAG,GAAG,GAAG;AAC3C,QAAM,WAAW,KAAK,IAAI,GAAG,IAAI,WAAW,OAAO,IAAI,SAAS;AAChE,SAAO;AAAA,IACL,OAAO,OAAO,SAAS;AAAA,IACvB;AAAA,IACA;AAAA,IACA,YAAY,MAAM,OAAO,cAAc,mBAAmB,YAAY,iBAAiB,eAAe;AAAA,IACtG,QAAQ,MAAM,OAAO,UAAU,GAAG,MAAM,GAAG;AAAA,IAC3C,cAAc,MAAM,OAAO,gBAAgB,GAAG,MAAM,GAAG;AAAA,EACzD;AACF;AAGO,SAAS,cAAc,QAAkC;AAC9D,SAAO,OAAO,UAAU,QAAQ,KAAK,IAAI,OAAO,GAAG,KAAK,UAAU,OAAO,OAAO;AAClF;AAqBA,SAAS,YAAY,OAAe,QAAsC;AACxE,QAAM,YAAY,KAAK,IAAI,KAAK,KAAK,IAAI,OAAO,GAAG,CAAC;AACpD,QAAM,YAAY,OAAO,MAAM,IAAI,KAAK;AACxC,QAAM,YACJ,aAAa,kBAAkB,KAAK,KAAK,IAAI,KAAK,IAAI,WAAY,YAAY,MAAO,KAAK,EAAE;AAC9F,QAAM,aAAa,QAAQ;AAE3B,QAAM,SAAS,aAAa,KAAK,IAAI,GAAG,OAAO,eAAe,GAAG;AACjE,QAAM,QACJ,UAAU,aAAa,YAAY,KAAK,IAAI,KAAK,KAAK,GAAG,QAAQ,KAAK,IAAI,QAAQ,IAAI,CAAC;AACzF,SAAO,EAAE,QAAQ,OAAO,WAAW,WAAW;AAChD;AASA,SAAS,YAAY,OAAe,UAAuB,QAAgB,UAA6B;AACtG,QAAM,EAAE,OAAO,WAAW,WAAW,IAAI;AACzC,QAAM,OAAO,SAAS,KAAK,KAAK,IAAI;AACpC,QAAM,UAAU,QAAQ;AAKxB,QAAM,QAAQ,CAAC,UAAoC;AAAA,IACjD,UAAU,SAAS,KAAK,IAAI,KAAK;AAAA,IACjC,aAAa,aAAa,SAAS,KAAK,IAAI,KAAK;AAAA,EACnD;AAGA,QAAM,YAAY,YAAY,IAAI,IAAI;AACtC,QAAM,SAAS,CAAC,CAAC,GAAG,CAAC,MAAwB,GAAG,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC;AACpE,QAAM,IAAI,MAAM,MAAM;AAEtB,MAAI,MAAM;AAGR,UAAMC,SAAQ,MAAM,WAAW,KAAK,EAAE;AACtC,UAAM,WAAW,MAAM,QAAQ;AAC/B,WAAO;AAAA,MACL,MAAM;AAAA,QACJ,KAAK,OAAOA,MAAK,CAAC;AAAA,QAClB,KAAK,CAAC,IAAI,CAAC,QAAQ,SAAS,IAAI,OAAO,QAAQ,CAAC;AAAA,QAChD,KAAK,CAAC,IAAI,CAAC,QAAQ,SAAS,IAAI,OAAOA,MAAK,CAAC;AAAA,MAC/C,EAAE,KAAK,GAAG;AAAA,MACV,QAAQ,SAAS,KAAK,KAAK;AAAA,IAC7B;AAAA,EACF;AAEA,QAAM,QAAQ,MAAM,WAAW,QAAQ,CAAC;AACxC,QAAM,MAAM,MAAM,WAAW,QAAQ,CAAC;AACtC,QAAM,WAAW,QAAQ,KAAK,KAAK,IAAI;AACvC,SAAO;AAAA,IACL,MAAM,KAAK,OAAO,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,QAAQ,IAAI,SAAS,IAAI,OAAO,GAAG,CAAC;AAAA,IAC9E,QAAQ,SAAS;AAAA,EACnB;AACF;AAGA,SAAS,aAAa,OAAe,UAAkB,QAAyB,IAAuB;AACrG,QAAM,YAAa,OAAO,OAAO,MAAO,WAAW;AACnD,QAAM,SAAS,KAAK,IAAI,GAAG,WAAW,OAAO,UAAU;AAEvD,QAAM,QAAS,OAAO,SAAS,MAAO,KAAK,KAAK;AAEhD,QAAM,OAAO,KAAK,IAAI,WAAW,SAAS,CAAC;AAC3C,QAAM,QAAQ,KAAK,IAAI,gBAAgB,KAAK,IAAI,GAAG,KAAK,KAAK,QAAQ,IAAI,CAAC,CAAC;AAC3E,QAAM,WAAqB,CAAC;AAC5B,MAAI,SAAS;AACb,MAAI,WAAoC;AACxC,WAAS,QAAQ,GAAG,SAAS,OAAO,SAAS;AAC3C,UAAM,IAAK,QAAQ,QAAS;AAC5B,UAAM,IAAI,KAAK,YAAY,KAAK,IAAK,IAAI,SAAU,KAAK,KAAK,IAAI,KAAK;AACtE,QAAI,SAAU,WAAU,KAAK,MAAM,IAAI,SAAS,CAAC,GAAG,IAAI,SAAS,CAAC,CAAC;AACnE,eAAW,CAAC,GAAG,CAAC;AAChB,aAAS,KAAK,GAAG,UAAU,IAAI,MAAM,GAAG,IAAI,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,EAAE;AAAA,EACpE;AAEA,SAAO,EAAE,MAAM,SAAS,KAAK,GAAG,GAAG,OAAO;AAC5C;AAWO,SAAS,oBACd,QACA,OACA,UACA,YAAY,GACZ,aAAa,GACO;AACpB,QAAM,QAAQ,mBAAmB,MAAM;AACvC,MAAI,CAAC,cAAc,KAAK,EAAG,QAAO;AAElC,QAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,MAAM,SAAS,CAAC;AAC/C,QAAM,QAAqB,CAAC;AAC5B,MAAI,MAAM,UAAU,QAAQ;AAC1B,aAAS,QAAQ,GAAG,QAAQ,OAAO,SAAS;AAC1C,YAAM,KAAK,aAAa,OAAO,UAAU,QAAQ,SAAS,QAAQ,KAAK,KAAK,UAAU,CAAC;AAAA,IACzF;AACA,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,YAAY,OAAO,KAAK;AAGzC,QAAM,WAAY,MAAM,SAAS,MAAO,SAAS;AACjD,WAAS,QAAQ,GAAG,QAAQ,OAAO,SAAS;AAE1C,UAAM,SAAS,KAAK,IAAI,GAAG,SAAS,UAAU,SAAS,QAAQ,KAAK,KAAK,UAAU;AACnF,UAAM,KAAK,YAAY,OAAO,UAAU,QAAQ,QAAQ,CAAC;AAAA,EAC3D;AACA,SAAO;AACT;AAGO,SAAS,mBACd,QACA,OACA,UACkB;AAClB,SAAO,oBAAoB,QAAQ,OAAO,QAAQ,IAAI,CAAC,KAAK;AAC9D;;;ADrMA,IAAM,gBAAgB;AAEtB,IAAM,aAAa;AAEnB,IAAM,uBAAuB;AA0B7B,IAAM,UAAU,oBAAI,QAAiC;AAGrD,IAAM,kBAAkB,oBAAI,QAA+B;AAE3D,SAAS,WAAW,QAA0D;AAC5E,SAAO,CAAC,CAAC,UAAU,OAAQ,OAAwB,SAAS;AAC9D;AASA,SAAS,YAAY,MAA4B;AAC/C,QAAM,WAAW,KAAK;AACtB,MAAI;AACF,SAAK,IAAI,EAAE,OAAO,cAAc,CAAC;AACjC,SAAK,iBAAiB;AACtB,WAAO,KAAK,IAAI,GAAG,KAAK,gBAAgB,KAAK,KAAK,SAAS,CAAC;AAAA,EAC9D,UAAE;AACA,QAAI,aAAa,OAAW,MAAK,IAAI,EAAE,OAAO,SAAS,CAAC;AACxD,SAAK,iBAAiB;AAAA,EACxB;AACF;AAEA,SAAS,YAAY,MAA4B;AAC/C,SAAO,KAAK,IAAI,GAAG,KAAK,YAAY,UAAU,CAAC;AACjD;AAEA,SAAS,aAAa,MAA4B;AAChD,QAAM,WAAW,KAAK,kBAAkB,CAAC;AACzC,MAAI,OAAO,aAAa,YAAY,OAAO,SAAS,QAAQ,KAAK,WAAW,EAAG,QAAO;AACtF,SAAO,KAAK,YAAY,KAAK,cAAc,KAAK;AAClD;AAEA,SAAS,aAAa,OAAwB;AAC5C,SAAO,IAAI,oBAAK,MAAM,MAAM,EAAE,SAAS,OAAO,eAAe,MAAM,CAAC;AACtE;AAUO,IAAM,mBAAN,MAAuB;AAAA,EAgB5B,YACU,QACA,QACA,SACA,QACR;AAJQ;AACA;AACA;AACA;AAER,SAAK,OAAO,GAAG,gBAAgB,KAAK,aAAa;AAAA,EACnD;AAAA,EANU;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAVO,gBAAgB,CAAC,UAAqC;AACrE,UAAM,QAAQ,MAAM,SAAS,KAAK,OAAO,aAAa,MAAM,MAAM,IAAI;AACtE,QAAI,CAAC,OAAO,KAAK,MAAO;AACxB,SAAK,QAAQ,MAAM,IAAI,KAAK;AAAA,EAC9B;AAAA,EAWA,UAAgB;AACd,SAAK,OAAO,IAAI,gBAAgB,KAAK,aAAa;AAAA,EACpD;AAAA;AAAA,EAGA,IAAI,SAAyC;AAC3C,UAAM,QAAQ,KAAK,OAAO,IAAI,OAAO;AACrC,QAAI,CAAC,SAAS,CAAC,WAAW,MAAM,YAAY,EAAG,QAAO;AAGtD,WAAO,mBAAmB,MAAM,KAAK,SAAS,CAAC,CAAC;AAAA,EAClD;AAAA,EAEA,SAAS,SAA0B;AACjC,UAAM,QAAQ,KAAK,IAAI,OAAO;AAC9B,WAAO,CAAC,CAAC,SAAS,cAAc,KAAK;AAAA,EACvC;AAAA;AAAA,EAGA,MAAM,SAAiB,QAAwB,OAAO,MAAe;AACnE,UAAM,QAAQ,KAAK,OAAO,IAAI,OAAO;AACrC,QAAI,CAAC,SAAS,CAAC,WAAW,MAAM,YAAY,EAAG,QAAO;AAEtD,UAAM,OAAO,mBAAmB,MAAM;AACtC,UAAM,OAAO,MAAM;AACnB,UAAM,MAAM,YAAY,IAAI;AAE5B,QAAI,CAAC,cAAc,IAAI,GAAG;AACxB,WAAK,OAAO,MAAM,MAAM,KAAK,UAAU;AACvC,aAAO,MAAM,KAAK;AAGlB,YAAM,KAAK,QAAQ;AAAA,IACrB,OAAO;AAIL,UAAI,MAAM,KAAK,eAAe,OAAW,OAAM,KAAK,aAAa,KAAK,SAAS;AAC/E,WAAK,IAAI,EAAE,OAAO,KAAK,IAAI,MAAM,KAAK,YAAY,MAAM,CAAC,EAAE,CAAC;AAG5D,WAAK,iBAAiB;AAItB,YAAM,SAAS;AAAA,QACb;AAAA,QACA,OAAO,IAAI;AAAA,QACX,KAAK;AAAA,QACL,YAAY,IAAI;AAAA,QAChB,aAAa,IAAI;AAAA,MACnB;AACA,UAAI,OAAQ,MAAK,OAAO,MAAM,MAAM;AACpC,YAAM,KAAK,QAAQ;AAAA,IACrB;AAEA,SAAK,iBAAiB;AACtB,SAAK,UAAU;AACf,SAAK,QAAQ;AACb,SAAK,OAAO,iBAAiB;AAC7B,SAAK,OAAO,KAAK,kBAAkB,EAAE,QAAQ,CAAC;AAC9C,QAAI,KAAM,MAAK,QAAQ,KAAK;AAC5B,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAM,SAAiB,OAAO,MAAe;AAC3C,UAAM,QAAQ,KAAK,OAAO,IAAI,OAAO;AACrC,UAAM,QAAQ,OAAO,KAAK,OAAO;AAGjC,WAAO,KAAK,MAAM,SAAS,EAAE,MAAM,GAAG,IAAI;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,QAAQ,SAAiB,OAAO,OAAgB;AAC9C,UAAM,QAAQ,KAAK,OAAO,IAAI,OAAO,GAAG,KAAK;AAC7C,QAAI,CAAC,MAAO,QAAO;AACnB,WAAO,KAAK,MAAM,SAAS,OAAO,IAAI;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,aAAmB;AACjB,UAAM,QAAQ,CAAC,WAA0B;AACvC,iBAAW,SAAS,QAAQ;AAC1B,YAAI,MAAM,KAAK,MAAO,MAAK,QAAQ,MAAM,EAAE;AAC3C,YAAI,MAAM,SAAS,SAAS,EAAG,OAAM,MAAM,QAAQ;AAAA,MACrD;AAAA,IACF;AACA,UAAM,KAAK,OAAO,OAAO,CAAC;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUQ,OAAO,MAAoB,QAA2B;AAK5D,QAAI,CAAC,gBAAgB,IAAI,IAAI,EAAG,iBAAgB,IAAI,MAAM,KAAK,aAAa;AAC5E,SAAK,IAAI,EAAE,eAAe,MAAM,CAAC;AAEjC,UAAM,QAAQ,OAAO,IAAI,YAAY;AACrC,UAAM,QACJ,MAAM,WAAW,IAAI,MAAM,CAAC,IAAI,aAAa,EAAE,MAAM,OAAO,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,GAAG,GAAG,QAAQ,EAAE,CAAC;AACvG,SAAK,IAAI;AAAA,MACP,MAAM;AAAA,MACN,WAAW;AAAA,MACX,UAAU;AAAA;AAAA;AAAA,MAGV,iBAAiB;AAAA,IACnB,CAAC;AACD,SAAK,iBAAiB,MAAM,OAAO,KAAK;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBQ,iBAAiB,MAAoB,OAAe,OAAmB;AAC7E,SAAK,mBAAmB,IAAI;AAC5B,UAAM,WAAW,KAAK;AAGtB,QAAI,OAAO,aAAa,WAAY;AAEpC,eAAW,QAAQ,MAAO,MAAK,aAAa,MAAM;AAElD,UAAM,YAAY,SAA8B,WAAmB;AACjE,YAAM,OAAO,MAAM,SAAS;AAC5B,UAAI,CAAC,KAAM,QAAO,SAAS,KAAK,MAAM,SAAS;AAC/C,YAAM,eAAe,KAAK;AAC1B,YAAM,gBAAgB,KAAK;AAC3B,WAAK,OAAO;AACZ,WAAK,YAAY;AAGjB,MAAC,KAAiD,cAAc;AAChE,UAAI;AACF,eAAO,SAAS,KAAK,MAAM,SAAS;AAAA,MACtC,UAAE;AACA,aAAK,OAAO;AACZ,aAAK,YAAY;AAAA,MACnB;AAAA,IACF;AAEA,UAAM,gBAAgB,OAAO,UAAU,eAAe,KAAK,MAAM,cAAc;AAC/E,SAAK,eAAe;AACpB,YAAQ,IAAI,MAAM,EAAE,UAAU,WAAW,cAAc,CAAC;AAAA,EAC1D;AAAA;AAAA,EAGQ,mBAAmB,MAA0B;AACnD,UAAM,QAAQ,QAAQ,IAAI,IAAI;AAC9B,QAAI,CAAC,MAAO;AAEZ,QAAI,KAAK,iBAAiB,MAAM,WAAW;AAGzC,UAAI,MAAM,cAAe,MAAK,eAAe,MAAM;AAAA,UAC9C,QAAO,KAAK;AAAA,IACnB;AACA,YAAQ,OAAO,IAAI;AAAA,EACrB;AAAA,EAEQ,OAAO,MAAoB,eAAyC;AAC1E,SAAK,mBAAmB,IAAI;AAC5B,UAAM,UAAU,gBAAgB,IAAI,IAAI;AACxC,QAAI,YAAY,QAAW;AACzB,WAAK,IAAI,EAAE,eAAe,QAAQ,CAAC;AACnC,sBAAgB,OAAO,IAAI;AAAA,IAC7B;AACA,SAAK,IAAI,EAAE,MAAM,MAAM,iBAAiB,EAAE,CAAC;AAC3C,QAAI,kBAAkB,UAAa,gBAAgB,EAAG,MAAK,IAAI,EAAE,OAAO,cAAc,CAAC;AAAA,EACzF;AACF;;;AErUA,IAAAC,iBAAkC;;;ACG3B,IAAM,iBAAiB;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAIO,SAAS,cAAc,OAAsC;AAClE,SAAO,OAAO,UAAU,YAAa,eAAqC,SAAS,KAAK;AAC1F;AAGA,SAAS,WAAW,QAAgB,OAAe,OAAe,QAAQ,CAAC,KAAK,KAAK,GAAW;AAC9F,QAAM,OAAO,KAAK,KAAK;AACvB,QAAM,cAAwB,CAAC;AAC/B,WAAS,QAAQ,GAAG,QAAQ,SAAS,GAAG,SAAS;AAC/C,UAAM,SAAS,QAAQ,MAAM,IAAI,QAAQ;AACzC,UAAM,QAAQ,QAAQ,QAAQ;AAC9B,UAAM,IAAI,KAAK,KAAK,IAAI,KAAK,IAAI;AACjC,UAAM,IAAI,KAAK,KAAK,IAAI,KAAK,IAAI;AACjC,gBAAY,KAAK,GAAG,UAAU,IAAI,MAAM,GAAG,IAAIC,OAAM,CAAC,CAAC,IAAIA,OAAM,CAAC,CAAC,EAAE;AAAA,EACvE;AACA,SAAO,GAAG,YAAY,KAAK,GAAG,CAAC;AACjC;AAEA,SAASA,OAAM,OAAuB;AACpC,SAAO,KAAK,MAAM,QAAQ,GAAG,IAAI;AACnC;AAEA,IAAM,cAA2C;AAAA,EAC/C,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,MAAM,WAAW,GAAG,IAAI,EAAE;AAAA,EAC1B,OAAO;AAAA,EACP,UAAU,WAAW,GAAG,IAAI,EAAE;AAAA,EAC9B,MAAM;AAAA,EACN,QAAQ,WAAW,IAAI,IAAI,EAAE;AAC/B;AAGO,SAAS,kBAAkB,IAAyB;AACzD,SAAO,YAAY,EAAE;AACvB;AAGO,IAAM,iBAAiB;;;AC9CvB,IAAM,mBAAmB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAIO,SAAS,gBAAgB,OAAwC;AACtE,SAAO,OAAO,UAAU,YAAa,iBAAuC,SAAS,KAAK;AAC5F;AAGO,IAAM,oBAAoB;AAEjC,IAAM,QAAQ,oBAAI,IAAsC;AAGxD,SAAS,OAAO,MAA4B;AAC1C,MAAI,QAAQ;AACZ,SAAO,MAAM;AACX,YAAS,QAAQ,QAAS;AAC1B,YAAQ,QAAQ,KAAK;AAAA,EACvB;AACF;AAEA,SAAS,eACP,SACA,QACA,QACA,OACM;AACN,QAAM,OAAO;AACb,QAAM,UAA8B;AAAA,IAClC,CAAC,OAAO,KAAK;AAAA,IACb,CAAC,OAAO,OAAO,KAAK;AAAA,IACpB,CAAC,OAAO,OAAO,OAAO,KAAK;AAAA,IAC3B,CAAC,OAAO,OAAO,KAAK;AAAA,EACtB;AACA,UAAQ,UAAU;AAClB,WAAS,SAAS,GAAG,SAAS,QAAQ,QAAQ,UAAU;AACtD,UAAM,CAAC,OAAO,KAAK,IAAI,QAAQ,MAAM;AACrC,UAAM,CAAC,KAAK,GAAG,IAAI,SAAS,SAAS,KAAK,QAAQ,MAAM;AACxD,aAAS,OAAO,GAAG,QAAQ,IAAI,QAAQ;AACrC,YAAM,QAAQ,OAAO;AACrB,YAAM,IAAI,SAAS,MAAM,SAAS,SAAS,OAAO,IAAI,OAAO;AAC7D,YAAM,IAAI,SAAS,MAAM,SAAS,SAAS,OAAO,IAAI,OAAO;AAC7D,UAAI,WAAW,KAAK,SAAS,EAAG,SAAQ,OAAO,GAAG,CAAC;AAAA,UAC9C,SAAQ,OAAO,GAAG,CAAC;AAAA,IAC1B;AAAA,EACF;AACA,UAAQ,UAAU;AAClB,UAAQ,KAAK;AACf;AAEA,SAAS,MAAM,IAAmB,SAAyC;AACzE,QAAM,OAAO;AACb,QAAM,SAAS,OAAO;AACtB,UAAQ,YAAY;AAEpB,UAAQ,IAAI;AAAA,IACV,KAAK,YAAY;AACf,YAAM,WAAW,QAAQ;AAAA,QACvB;AAAA,QACA;AAAA,QACA,OAAO;AAAA,QACP;AAAA,QACA;AAAA,QACA,OAAO;AAAA,MACT;AACA,eAAS,aAAa,GAAG,qBAAqB;AAC9C,eAAS,aAAa,GAAG,qBAAqB;AAC9C,cAAQ,YAAY;AACpB,cAAQ,SAAS,GAAG,GAAG,MAAM,IAAI;AACjC;AAAA,IACF;AAAA,IACA,KAAK,QAAQ;AACX,YAAM,WAAW,QAAQ,qBAAqB,GAAG,GAAG,GAAG,IAAI;AAC3D,eAAS,aAAa,GAAG,qBAAqB;AAC9C,eAAS,aAAa,MAAM,qBAAqB;AACjD,eAAS,aAAa,MAAM,qBAAqB;AACjD,eAAS,aAAa,GAAG,qBAAqB;AAC9C,cAAQ,YAAY;AACpB,cAAQ,SAAS,GAAG,GAAG,MAAM,IAAI;AACjC;AAAA,IACF;AAAA,IACA,KAAK,YAAY;AACf,YAAM,QAAQ;AACd,eAAS,IAAI,QAAQ,GAAG,IAAI,MAAM,KAAK,OAAO;AAC5C,iBAAS,IAAI,QAAQ,GAAG,IAAI,MAAM,KAAK,OAAO;AAC5C,gBAAM,WAAW,KAAK,MAAM,IAAI,QAAQ,IAAI,MAAM,KAAK,OAAO;AAC9D,gBAAM,SAAS,KAAK,IAAI,GAAI,QAAQ,KAAM,IAAI,YAAY,IAAI;AAC9D,cAAI,SAAS,IAAK;AAClB,kBAAQ,UAAU;AAClB,kBAAQ,IAAI,GAAG,GAAG,QAAQ,GAAG,KAAK,KAAK,CAAC;AACxC,kBAAQ,KAAK;AAAA,QACf;AAAA,MACF;AACA;AAAA,IACF;AAAA,IACA,KAAK,SAAS;AACZ,YAAM,SAAS,OAAO,EAAE;AACxB,YAAM,OAAO,QAAQ,qBAAqB,QAAQ,QAAQ,IAAI,QAAQ,QAAQ,OAAO,IAAI;AACzF,WAAK,aAAa,GAAG,qBAAqB;AAC1C,WAAK,aAAa,GAAG,wBAAwB;AAC7C,cAAQ,YAAY;AACpB,cAAQ,UAAU;AAClB,cAAQ,IAAI,QAAQ,QAAQ,OAAO,MAAM,GAAG,KAAK,KAAK,CAAC;AACvD,cAAQ,KAAK;AACb,cAAQ,YAAY;AACpB,eAAS,MAAM,GAAG,MAAM,KAAK,OAAO;AAClC,cAAM,QAAQ,OAAO,IAAI,KAAK,KAAK;AACnC,cAAM,WAAW,QAAQ,MAAM,OAAO,IAAI;AAC1C,cAAM,IAAI,SAAS,KAAK,IAAI,KAAK,IAAI;AACrC,cAAM,IAAI,SAAS,KAAK,IAAI,KAAK,IAAI;AACrC,gBAAQ,cAAc,KAAK,WAAW,OAAO,OAAO;AACpD,gBAAQ,UAAU;AAClB,gBAAQ,IAAI,GAAG,GAAG,OAAO,IAAI,KAAK,GAAG,KAAK,KAAK,CAAC;AAChD,gBAAQ,KAAK;AAAA,MACf;AACA,cAAQ,cAAc;AACtB;AAAA,IACF;AAAA,IACA,KAAK,UAAU;AACb,YAAM,SAAS,OAAO,CAAC;AACvB,qBAAe,SAAS,QAAQ,IAAI,OAAO,IAAI;AAE/C,cAAQ,2BAA2B;AACnC,eAAS,UAAU,GAAG,UAAU,KAAK,WAAW;AAC9C,cAAM,IAAI,OAAO,IAAI;AACrB,cAAM,IAAI,OAAO,IAAI;AACrB,cAAM,WAAW,KAAK,IAAI,GAAG,GAAG,OAAO,GAAG,OAAO,CAAC,IAAI,OAAO;AAC7D,YAAI,CAAC,YAAY,OAAO,KAAK,KAAM;AACnC,gBAAQ,UAAU;AAClB,gBAAQ,IAAI,GAAG,GAAG,OAAO,IAAI,IAAI,GAAG,GAAG,KAAK,KAAK,CAAC;AAClD,gBAAQ,KAAK;AAAA,MACf;AACA,cAAQ,2BAA2B;AACnC;AAAA,IACF;AAAA,IACA,KAAK,QAAQ;AACX,qBAAe,SAAS,OAAO,EAAE,GAAG,IAAI,OAAO,IAAI;AACnD;AAAA,IACF;AAAA,EACF;AACF;AAGO,SAAS,kBAAkB,IAAsC;AACtE,QAAM,SAAS,MAAM,IAAI,EAAE;AAC3B,MAAI,OAAQ,QAAO;AACnB,MAAI,OAAO,aAAa,aAAa;AACnC,UAAM,IAAI,MAAM,oCAAoC;AAAA,EACtD;AACA,QAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,SAAO,QAAQ;AACf,SAAO,SAAS;AAChB,QAAM,UAAU,OAAO,WAAW,IAAI;AACtC,MAAI,CAAC,QAAS,OAAM,IAAI,MAAM,2CAA2C;AACzE,QAAM,IAAI,OAAO;AACjB,QAAM,IAAI,IAAI,MAAM;AACpB,SAAO;AACT;AAGO,SAAS,wBAA8B;AAC5C,QAAM,MAAM;AACd;;;AF1KO,SAAS,eAAe,OAAuC;AACpE,SAAO,cAAc,KAAK,KAAK,gBAAgB,KAAK;AACtD;AAaO,IAAM,oBAAN,MAAwB;AAAA,EAC7B,YACU,QACA,QACA,SACA,QACR;AAJQ;AACA;AACA;AACA;AAAA,EACP;AAAA,EAJO;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAGV,IAAI,SAAsC;AACxC,WAAO,KAAK,OAAO,IAAI,OAAO,GAAG,KAAK,cAAc;AAAA,EACtD;AAAA;AAAA,EAGA,MAAM,SAAiB,IAAyB,OAAO,MAAe;AACpE,UAAM,QAAQ,KAAK,OAAO,IAAI,OAAO;AACrC,QAAI,CAAC,MAAO,QAAO;AACnB,UAAM,SAAS,MAAM;AAErB,QAAI,OAAO,MAAM;AACf,UAAI,CAAC,MAAM,KAAK,WAAY,QAAO;AACnC,aAAO,WAAW;AAClB,aAAO,MAAM,KAAK;AAAA,IACpB,OAAO;AACL,UAAI,CAAC,eAAe,EAAE,EAAG,QAAO;AAChC,aAAO,WAAW,KAAK,UAAU,IAAI,MAAM;AAC3C,YAAM,KAAK,aAAa;AAAA,IAC1B;AAEA,WAAO,QAAQ;AACf,WAAO,UAAU;AACjB,SAAK,OAAO,iBAAiB;AAC7B,SAAK,OAAO,KAAK,kBAAkB,EAAE,QAAQ,CAAC;AAC9C,QAAI,KAAM,MAAK,QAAQ,KAAK;AAC5B,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,SAAiB,OAAO,MAAe;AAC3C,WAAO,KAAK,MAAM,SAAS,MAAM,IAAI;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,QAAQ,SAAiB,OAAO,OAAgB;AAC9C,UAAM,KAAK,KAAK,IAAI,OAAO;AAC3B,QAAI,CAAC,GAAI,QAAO;AAChB,WAAO,KAAK,MAAM,SAAS,IAAI,IAAI;AAAA,EACrC;AAAA;AAAA,EAGA,aAAmB;AACjB,eAAW,SAAS,KAAK,OAAO,OAAO,GAAG;AACxC,UAAI,MAAM,KAAK,WAAY,MAAK,QAAQ,MAAM,EAAE;AAAA,IAClD;AAAA,EACF;AAAA,EAEQ,UAAU,IAAkB,QAAoC;AAGtE,UAAM,QAAQ,KAAK,IAAI,GAAG,OAAO,SAAS,CAAC;AAC3C,UAAM,SAAS,KAAK,IAAI,GAAG,OAAO,UAAU,CAAC;AAC7C,UAAM,SAAS;AAAA,MACb,SAAS;AAAA,MACT,SAAS;AAAA,MACT,MAAM;AAAA,MACN,KAAK;AAAA,MACL,eAAe;AAAA,IACjB;AAEA,QAAI,cAAc,EAAE,GAAG;AACrB,aAAO,IAAI,oBAAK,kBAAkB,EAAE,GAAG;AAAA,QACrC,GAAG;AAAA,QACH,QAAQ,QAAQ;AAAA,QAChB,QAAQ,SAAS;AAAA,MACnB,CAAC;AAAA,IACH;AAEA,WAAO,IAAI,2BAAY,kBAAkB,EAAE,GAAG;AAAA,MAC5C,GAAG;AAAA,MACH,QAAQ,QAAQ;AAAA,MAChB,QAAQ,SAAS;AAAA,IACnB,CAAC;AAAA,EACH;AACF;;;AG7GA,IAAAC,iBAAuB;;;ACIvB,IAAM,YAAY;AAGX,SAAS,WAAW,OAAgB,aAAa,OAAwB;AAC9E,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,CAAC,QAAS,QAAO;AACrB,SAAO,UAAU,KAAK,OAAO;AAC/B;;;ADPO,IAAM,uBAA0C;AAAA,EACrD,SAAS;AAAA,EACT,OAAO;AAAA,EACP,MAAM;AAAA,EACN,SAAS;AAAA,EACT,SAAS;AACX;AASO,SAAS,gBAAgB,QAAyC;AACvE,QAAM,SAAS,OAAO;AACtB,MAAI,CAAC,UAAU,OAAO,WAAW,SAAU,QAAO,EAAE,GAAG,qBAAqB;AAC5E,SAAO;AAAA,IACL,SAAS;AAAA,IACT,OAAO,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ,qBAAqB;AAAA,IAC9E,MAAM,OAAO,QAAQ,qBAAqB;AAAA,IAC1C,SAAS,OAAO,WAAW,qBAAqB;AAAA,IAChD,SAAS,OAAO,WAAW,qBAAqB;AAAA,EAClD;AACF;AAGO,SAAS,iBAAiB,QAAsB,QAA0C;AAC/F,QAAM,OAAO,EAAE,GAAG,gBAAgB,MAAM,GAAG,GAAG,OAAO;AACrD,MAAI,CAAC,KAAK,SAAS;AACjB,WAAO,IAAI,EAAE,QAAQ,KAAK,CAAC;AAC3B;AAAA,EACF;AAGA,QAAM,QAAQ,WAAW,KAAK,KAAK,IAAI,KAAK,QAAQ,qBAAqB;AACzE,SAAO,IAAI;AAAA,IACT,QAAQ,IAAI,sBAAO;AAAA,MACjB;AAAA,MACA,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI;AAAA,MAC3B,SAAS,KAAK;AAAA,MACd,SAAS,KAAK;AAAA,IAChB,CAAC;AAAA,EACH,CAAC;AACH;;;AElBO,IAAM,0BAA0C;AAAA,EACrD,aAAa;AAAA,EACb,aAAa;AAAA,EACb,mBAAmB;AAAA,EACnB,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,aAAa;AAAA,EACb,iBAAiB;AAAA,EACjB,SAAS;AAAA,EACT,aAAa;AACf;AAGO,SAAS,0BACd,QACA,OACA,MACM;AACN,QAAM,QAAQ,OAAO,IAAI,IAAI,OAAO;AACpC,SAAO,IAAI;AAAA,IACT,YAAY,MAAM,aAAa;AAAA,IAC/B,aAAa,MAAM;AAAA,IACnB,aAAa,MAAM;AAAA,IACnB,mBAAmB,MAAM;AAAA;AAAA,IAEzB,oBAAoB;AAAA,IACpB,aAAa,MAAM;AAAA,IACnB,mBAAmB,MAAM,cAAc;AAAA,IACvC,iBAAiB,MAAM,iBAAiB,IAAI,CAAC,YAAY,UAAU,KAAK,KAAK;AAAA,IAC7E,SAAS,MAAM,UAAU;AAAA,EAC3B,CAAC;AACH;AASO,SAAS,oBAAoB,QAAgB,OAAuB,MAAoB;AAC7F,aAAW,UAAU,OAAO,WAAW,EAAG,2BAA0B,QAAQ,OAAO,IAAI;AACvF,QAAM,SAAS,OAAO,gBAAgB;AACtC,MAAI,OAAQ,2BAA0B,QAAQ,OAAO,IAAI;AACzD,SAAO,iBAAiB,MAAM;AAC9B,SAAO,uBAAuB,MAAM;AACpC,SAAO,qBAAqB,MAAM,eAAe,OAAO,IAAI,IAAI,OAAO;AACvE,SAAO,iBAAiB;AAC1B;;;AC7EA,IAAM,gBAAgB,CAAC,MAAM,MAAM,MAAM,IAAI;AAStC,SAAS,gBAAgB,QAAsB,QAAuB;AAC3E,aAAW,WAAW,eAAe;AACnC,WAAO,kBAAkB,SAAS,CAAC,MAAM;AAAA,EAC3C;AACF;AAMO,SAAS,eAAe,QAA4B;AACzD,SAAO,IAAI;AAAA,IACT,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,EACT,CAAC;AACD,SAAO,UAAU;AACnB;;;AC/BA,IAAM,cAAc;AAEb,IAAM,gBAAN,MAAoB;AAAA,EACjB;AAAA,EACA;AAAA,EAER,YAAY,OAAa,MAAM,MAAc,IAAI;AAC/C,SAAK,OAAO;AACZ,SAAK,MAAM;AACX,SAAK,OAAO,GAAG;AAAA,EACjB;AAAA,EAEA,QAAQ,MAAkB;AACxB,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,OAAO,KAAmB;AACxB,QAAI,CAAC,OAAO,SAAS,GAAG,KAAK,OAAO,EAAG,OAAM,IAAI,MAAM,+BAA+B;AACtF,SAAK,MAAM;AAAA,EACb;AAAA,EAEA,UAAgB;AACd,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,SAAiB;AACf,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,SAAS,OAAe,UAAyB;AAC/C,UAAM,IAAI,YAAY,KAAK;AAC3B,YAAQ,GAAG;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO,QAAQ,KAAK;AAAA,MACtB,KAAK;AACH,eAAQ,QAAQ,cAAe,KAAK;AAAA,IACxC;AAAA,EACF;AAAA,EAEA,WAAW,IAAY,QAAuB;AAC5C,UAAM,IAAI,UAAU,KAAK;AACzB,YAAQ,GAAG;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO,KAAK,KAAK;AAAA,MACnB,KAAK;AACH,eAAQ,KAAK,KAAK,MAAO;AAAA,IAC7B;AAAA,EACF;AACF;;;ACtDA,IAAAC,iBAAqB;AAQrB,IAAM,UAAU;AAET,SAAS,gBAAgB,QAAmC;AACjE,SAAO;AAAA,IACL,SAAS;AAAA,IACT,QAAQ;AAAA,MACN,OAAO,OAAO,OAAO,SAAS;AAAA,MAC9B,QAAQ,OAAO,OAAO,UAAU;AAAA,MAChC,MAAM,OAAO,MAAM,QAAQ;AAAA,MAC3B,KAAK,OAAO,MAAM,OAAO;AAAA,IAC3B;AAAA,IACA,QAAQ,OAAO,OAAO,OAAO,EAAE,IAAI,CAAC,UAAU,MAAM,UAAU,CAAC;AAAA;AAAA;AAAA,IAG/D,YAAY,OAAO,oBAAoB;AAAA,IACvC,iBAAiB,OAAO,yBAAyB,IAC5C,OAAO,yBAAyB,EAAG,SAAS,IAC7C;AAAA,IACJ,wBAAwB,OAAO,0BAA0B;AAAA,IACzD,QAAQ,OAAO,UAAU;AAAA,EAC3B;AACF;AAEA,eAAsB,kBAAkB,QAAsB,OAAmC;AAC/F,MAAI,CAAC,SAAS,CAAC,MAAM,UAAU,CAAC,MAAM,QAAQ,MAAM,MAAM,GAAG;AAC3D,UAAM,IAAI,MAAM,sBAAsB;AAAA,EACxC;AACA,MACE,CAAC,OAAO,SAAS,MAAM,OAAO,KAAK,KACnC,CAAC,OAAO,SAAS,MAAM,OAAO,MAAM,KACpC,MAAM,OAAO,SAAS,KACtB,MAAM,OAAO,UAAU,KACtB,MAAM,OAAO,SAAS,UAAa,CAAC,CAAC,MAAM,MAAM,IAAI,EAAE,SAAS,MAAM,OAAO,IAAI,KACjF,MAAM,OAAO,QAAQ,WACnB,CAAC,OAAO,SAAS,MAAM,OAAO,GAAG,KAAK,MAAM,OAAO,OAAO,IAC7D;AACA,UAAM,IAAI,MAAM,gCAAgC;AAAA,EAClD;AACA,QAAM,QAAQ,OAAO,SAAS,MAAM,SAAS,MAAM,GAAG,EAAE,CAAC,KAAK,KAAK,EAAE;AACrE,MAAI,CAAC,OAAO,SAAS,KAAK,KAAK,QAAQ,GAAG;AACxC,UAAM,IAAI,MAAM,qCAAqC,MAAM,OAAO,EAAE;AAAA,EACtE;AAGA,MAAI,MAAM,eAAe,UAAa,CAAC,WAAW,MAAM,YAAY,IAAI,GAAG;AACzE,UAAM,IAAI,MAAM,iCAAiC;AAAA,EACnD;AAIA,QAAM,SAAS,MAAM,QAAQ;AAAA,IAC3B,MAAM,OAAO,IAAI,OAAO,eAAe;AACrC,YAAM,gBAAgB,MAAM,oBAAK,eAAe,CAAC,WAAW,YAAY,CAAC,GAAG,CAAC;AAG7E,UAAI,CAAC,cAAc;AACjB,cAAM,SAAS,WAAW,aAAa;AACvC,YAAI,OAAO,WAAW,YAAY,OAAO,WAAW,OAAO,GAAG;AAC5D,gBAAM,IAAI,MAAM,yCAAyC,MAAM,EAAE;AAAA,QACnE;AACA,cAAM,IAAI,MAAM,4BAA4B,WAAW,EAAE,EAAE;AAAA,MAC7D;AACA,aAAO,EAAE,YAAY,aAAa;AAAA,IACpC,CAAC;AAAA,EACH;AACA,QAAM,mBAAmB,MAAM,mBACzB,MAAM,oBAAK,eAAe,CAAC,MAAM,eAAe,CAAC,GAAG,CAAC,IACvD;AACJ,MAAI,MAAM,mBAAmB,CAAC,kBAAkB;AAC9C,UAAM,SAAS,MAAM,gBAAgB;AACrC,QAAI,OAAO,WAAW,YAAY,OAAO,WAAW,OAAO,GAAG;AAC5D,YAAM,IAAI,MAAM,oDAAoD,MAAM,EAAE;AAAA,IAC9E;AACA,UAAM,IAAI,MAAM,oCAAoC;AAAA,EACtD;AAEA,SAAO,KAAK,OAAO;AACnB,SAAO,MAAM,OAAO;AACpB,SAAO,OAAO,MAAM;AACpB,MAAI,MAAM,OAAO,KAAM,QAAO,MAAM,QAAQ,MAAM,OAAO,IAAI;AAC7D,MAAI,MAAM,OAAO,QAAQ,OAAW,QAAO,MAAM,OAAO,MAAM,OAAO,GAAG;AACxE,SAAO,OAAO,cAAc,EAAE,OAAO,MAAM,OAAO,OAAO,QAAQ,MAAM,OAAO,OAAO,CAAC;AAKtF,MAAI,MAAM,eAAe,QAAW;AAClC,WAAO,cAAc,MAAM,UAAU;AAAA,EACvC;AACA,SAAO;AAAA,IACL,oBAAoB;AAAA,IACpB;AAAA,IACA,MAAM,0BAA0B;AAAA,EAClC;AAGA,SAAO,UAAU,MAAM,UAAU,IAAI;AAErC,aAAW,QAAQ,QAAQ;AACzB,iBAAa,QAAQ,KAAK,YAAY,KAAK,YAAY;AAAA,EACzD;AAEA,SAAO,OAAO,iBAAiB;AACjC;AAEA,SAAS,aACP,QACA,YACA,cACO;AACP,QAAM,QAAQ,OAAO,OAAO,IAAI,WAAW,MAAM,cAAc,WAAW,MAAM,WAAW,EAAE;AAE7F,MAAI,WAAW,MAAM;AACnB,UAAM,OAAO,WAAW;AAGxB,QAAI,MAAM,KAAK,WAAY,iBAAgB,cAAc,IAAI;AAAA,EAC/D;AAEA,MAAI,CAAC,WAAW,SAAS;AACvB,WAAO,OAAO,cAAc,MAAM,IAAI,KAAK;AAAA,EAC7C;AACA,MAAI,WAAW,QAAQ;AACrB,WAAO,OAAO,UAAU,MAAM,IAAI,IAAI;AAAA,EACxC;AACA,MAAI,WAAW,YAAY,GAAG;AAC5B,WAAO,OAAO,WAAW,MAAM,IAAI,WAAW,OAAO;AAAA,EACvD;AAKA,QAAM,YACJ,WAAW,YAAa,WAAW,MAAM;AAC3C,MAAI,MAAM,SAAS,WAAW,MAAM,QAAQ,SAAS,GAAG;AACtD,WAAO,OAAO,mBAAmB,OAAO,SAAS;AACjD,QAAI,MAAM,KAAK,cAAe,QAAO,MAAM,KAAK;AAAA,EAClD;AAEA,SAAO;AACT;;;ACpJA,IAAAC,kBAA6B;;;ACE7B,IAAM,gBAA2D;AAAA,EAC/D,KAAK;AAAA,EACL,OAAO;AAAA,EACP,MAAM;AAAA,EACN,OAAO;AACT;AAEA,SAAS,YAAY,OAA2B,UAAkB,OAAuB;AACvF,QAAM,WAAW,SAAS;AAC1B,MAAI,CAAC,OAAO,SAAS,QAAQ,EAAG,OAAM,IAAI,MAAM,GAAG,KAAK,iBAAiB;AACzE,SAAO;AACT;AAEA,SAAS,OACP,QACA,OACA,QACA,GACA,GACA,SACQ;AACR,QAAM,WAAW,KAAK,IAAI,GAAG,KAAK,IAAI,QAAQ,GAAG,CAAC,CAAC;AACnD,QAAM,WAAW,KAAK,IAAI,GAAG,KAAK,IAAI,SAAS,GAAG,CAAC,CAAC;AACpD,QAAM,KAAK,KAAK,MAAM,QAAQ;AAC9B,QAAM,KAAK,KAAK,MAAM,QAAQ;AAC9B,QAAM,KAAK,KAAK,IAAI,QAAQ,GAAG,KAAK,CAAC;AACrC,QAAM,KAAK,KAAK,IAAI,SAAS,GAAG,KAAK,CAAC;AACtC,QAAM,KAAK,WAAW;AACtB,QAAM,KAAK,WAAW;AACtB,QAAM,MACJ,QAAQ,KAAK,QAAQ,MAAM,IAAI,OAAO,KAAK,IAAI,MAC/C,QAAQ,KAAK,QAAQ,MAAM,IAAI,OAAO,IAAI;AAC5C,QAAM,SACJ,QAAQ,KAAK,QAAQ,MAAM,IAAI,OAAO,KAAK,IAAI,MAC/C,QAAQ,KAAK,QAAQ,MAAM,IAAI,OAAO,IAAI;AAC5C,SAAO,OAAO,IAAI,MAAM,SAAS;AACnC;AAMO,SAAS,aACd,QACA,KACA,OACA,QACA,SACmB;AACnB,MAAI,CAAC,OAAO,UAAU,KAAK,KAAK,CAAC,OAAO,UAAU,MAAM,KAAK,SAAS,KAAK,UAAU,GAAG;AACtF,UAAM,IAAI,MAAM,mDAAmD;AAAA,EACrE;AACA,QAAM,iBAAiB,QAAQ,SAAS;AACxC,MAAI,OAAO,WAAW,kBAAkB,IAAI,WAAW,gBAAgB;AACrE,UAAM,IAAI,MAAM,iEAAiE;AAAA,EACnF;AAEA,QAAM,SAAS,YAAY,QAAQ,QAAQ,IAAI,qBAAqB;AACpE,QAAM,SAAS,YAAY,QAAQ,QAAQ,IAAI,qBAAqB;AACpE,QAAM,WAAW,cAAc,QAAQ,YAAY,KAAK;AACxD,QAAM,WAAW,cAAc,QAAQ,YAAY,OAAO;AAC1D,QAAM,SAAS,IAAI,kBAAkB,cAAc;AAEnD,WAAS,IAAI,GAAG,IAAI,QAAQ,KAAK,GAAG;AAClC,aAAS,IAAI,GAAG,IAAI,OAAO,KAAK,GAAG;AACjC,YAAM,UAAU,IAAI,QAAQ,KAAK;AACjC,YAAM,UAAU,KAAM,IAAI,SAAS,QAAQ,IAAI,OAAO,MAAO;AAC7D,YAAM,UAAU,KAAM,IAAI,SAAS,QAAQ,IAAI,OAAO,MAAO;AAC7D,eAAS,UAAU,GAAG,UAAU,GAAG,WAAW,GAAG;AAC/C,eAAO,SAAS,OAAO,IAAI,KAAK;AAAA,UAC9B,OAAO,QAAQ,OAAO,QAAQ,SAAS,SAAS,OAAO;AAAA,QACzD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;;;AD5DO,SAAS,qBACd,MACA,QACA,QACA,aACA,cACiB;AACjB,QAAM,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,aAAa,KAAK,OAAO,MAAM,CAAC;AAClE,QAAM,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,cAAc,KAAK,MAAM,MAAM,CAAC;AACjE,QAAM,QAAQ,KAAK,IAAI,MAAM,KAAK,IAAI,cAAc,KAAK,OAAO,KAAK,SAAS,MAAM,CAAC;AACrF,QAAM,SAAS,KAAK,IAAI,KAAK,KAAK,IAAI,eAAe,KAAK,MAAM,KAAK,UAAU,MAAM,CAAC;AACtF,SAAO,EAAE,MAAM,KAAK,OAAO,QAAQ,MAAM,QAAQ,SAAS,IAAI;AAChE;AAGO,SAAS,sBACd,aACA,cACA,aACA,cACgB;AAChB,MAAI,eAAe,KAAK,gBAAgB,KAAK,eAAe,KAAK,gBAAgB,GAAG;AAClF,UAAM,IAAI,MAAM,mCAAmC;AAAA,EACrD;AACA,QAAM,QAAQ,KAAK,IAAI,cAAc,aAAa,eAAe,YAAY;AAC7E,QAAM,QAAQ,cAAc;AAC5B,QAAM,SAAS,eAAe;AAC9B,SAAO;AAAA,IACL,OAAO,cAAc,SAAS;AAAA,IAC9B,MAAM,eAAe,UAAU;AAAA,IAC/B;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,oBACP,QACA,QACA,SACe;AACf,QAAM,OAAO,WAAW,SAAS,eAAe,SAAS,MAAM;AAC/D,SAAO,IAAI,QAAc,CAAC,SAAS,WAAW;AAC5C,WAAO;AAAA,MACL,CAAC,SAAU,OAAO,QAAQ,IAAI,IAAI,OAAO,IAAI,MAAM,oBAAoB,MAAM,EAAE,CAAC;AAAA,MAChF;AAAA,MACA;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,eAAsB,UAAU,QAAgB,UAA4B,CAAC,GAAkB;AAC7F,QAAM,EAAE,aAAa,GAAG,SAAS,OAAsB,UAAU,EAAE,IAAI;AACvE,QAAM,SAAS,OAAO,gBAAgB,UAAU;AAChD,SAAO,oBAAoB,QAAQ,QAAQ,OAAO;AACpD;AAGA,eAAsB,kBACpB,QACA,SACA,UAMI,CAAC,GACU;AACf,QAAM,UAAU,OAAO,cAAc,cAAc,cAAc,QAAQ;AACzE,QAAM,SAAS,IAAI,6BAAa,SAAS;AAAA,IACvC,OAAO,QAAQ,SAAS,OAAO,SAAS;AAAA,IACxC,QAAQ,QAAQ,UAAU,OAAO,UAAU;AAAA,IAC3C,iBAAiB,QAAQ,mBAAmB;AAAA,EAC9C,CAAC;AACD,MAAI;AACF,UAAM,SACJ,QAAQ,iBAAiB,QACrB,UACA,MAAM,QAAQ,IAAI,QAAQ,IAAI,CAAC,WAAW,OAAO,MAAM,CAAC,CAAC;AAC/D,QAAI,OAAO,OAAQ,QAAO,IAAI,GAAG,MAAM;AACvC,QAAI,QAAQ,gBAAiB,QAAO,kBAAkB,MAAM,QAAQ,gBAAgB,MAAM;AAC1F,WAAO,iBAAiB;AAGxB,WAAO,MAAM,UAAU,QAA6B,OAAO;AAAA,EAC7D,UAAE;AACA,WAAO,QAAQ;AAAA,EACjB;AACF;AASA,eAAsB,gBACpB,QACA,MACA,UAA4B,CAAC,GACd;AACf,QAAM,EAAE,aAAa,GAAG,SAAS,OAAsB,UAAU,EAAE,IAAI;AACvE,QAAM,QAAQ,OAAO,SAAS;AAC9B,QAAM,SAAS,OAAO,UAAU;AAChC,QAAM,OAAO;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,SAAS;AAAA,EACX;AACA,MAAI,KAAK,SAAS,KAAK,KAAK,UAAU,GAAG;AACvC,UAAM,IAAI,MAAM,wCAAwC;AAAA,EAC1D;AAEA,QAAM,UAAU,OAAO,cAAc,cAAc,cAAc,QAAQ;AACzE,QAAM,SAAS,IAAI,6BAAa,SAAS,EAAE,OAAO,OAAO,CAAC;AAC1D,MAAI;AACF,UAAM,SAAS,MAAM,QAAQ,IAAI,OAAO,WAAW,EAAE,IAAI,CAAC,WAAW,OAAO,MAAM,CAAC,CAAC;AACpF,QAAI,OAAO,OAAQ,QAAO,IAAI,GAAG,MAAM;AACvC,WAAO,iBAAiB;AACxB,UAAM,WAAW,OAAO,gBAAgB,UAAU;AAClD,UAAM,SAAS,SAAS,cAAc,cAAc,QAAQ;AAC5D,WAAO,QAAQ,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,KAAK,CAAC;AACjD,WAAO,SAAS,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,MAAM,CAAC;AACnD,UAAM,UAAU,OAAO,WAAW,IAAI;AACtC,QAAI,CAAC,QAAS,OAAM,IAAI,MAAM,kCAAkC;AAChE,YAAQ,UAAU,UAAU,CAAC,KAAK,MAAM,CAAC,KAAK,GAAG;AAEjD,WAAO,MAAM,oBAAoB,QAAQ,QAAQ,OAAO;AAAA,EAC1D,UAAE;AACA,WAAO,QAAQ;AAAA,EACjB;AACF;AAGA,eAAsB,aACpB,QACA,QACA,UAA4B,CAAC,GACd;AACf,QAAM,EAAE,aAAa,GAAG,SAAS,OAAsB,UAAU,EAAE,IAAI;AACvE,QAAM,SAAS,OAAO,gBAAgB,UAAU;AAChD,QAAM,SAAS,OAAO,cAAc,cAAc,QAAQ;AAC1D,SAAO,QAAQ,OAAO;AACtB,SAAO,SAAS,OAAO;AACvB,QAAM,UAAU,OAAO,WAAW,IAAI;AACtC,MAAI,CAAC,QAAS,OAAM,IAAI,MAAM,kCAAkC;AAEhE,QAAM,YAAY,CAAC,QACjB,IAAI,QAA0B,CAAC,SAAS,WAAW;AACjD,UAAM,UAAU,IAAI,MAAM;AAC1B,YAAQ,cAAc;AACtB,YAAQ,SAAS,MAAM,QAAQ,OAAO;AACtC,YAAQ,UAAU,MAAM,OAAO,IAAI,MAAM,gCAAgC,GAAG,EAAE,CAAC;AAC/E,YAAQ,MAAM;AAAA,EAChB,CAAC;AACH,QAAM,YAAY,CAChB,OACA,gBAA0C,YACvC;AACH,UAAM,YAAY;AAAA,MAChB,MAAM,gBAAgB,MAAM;AAAA,MAC5B,MAAM,iBAAiB,MAAM;AAAA,MAC7B,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AACA,kBAAc;AAAA,MACZ;AAAA,MACA,UAAU;AAAA,MACV,UAAU;AAAA,MACV,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,EACF;AAKA,QAAM,UAA+B,CAAC,MAAM;AAC5C,MAAI;AACF,cAAU,MAAM,UAAU,OAAO,KAAK,CAAC;AACvC,QAAI,mBAAsC;AAC1C,QAAI,OAAO,cAAc;AACvB,YAAM,gBAAgB,OAAO,WAAW,IAAI;AAC5C,UAAI,CAAC,cAAe,OAAM,IAAI,MAAM,kCAAkC;AACtE,YAAM,YAAY,OAAO,cAAc,cAAc,QAAQ;AAC7D,cAAQ,KAAK,SAAS;AACtB,gBAAU,QAAQ,OAAO;AACzB,gBAAU,SAAS,OAAO;AAC1B,YAAM,aAAa,UAAU,WAAW,IAAI;AAC5C,UAAI,CAAC,WAAY,OAAM,IAAI,MAAM,4CAA4C;AAC7E,gBAAU,MAAM,UAAU,OAAO,aAAa,KAAK,GAAG,UAAU;AAEhE,YAAM,SAAS,OAAO,cAAc,cAAc,QAAQ;AAC1D,cAAQ,KAAK,MAAM;AACnB,aAAO,QAAQ,OAAO;AACtB,aAAO,SAAS,OAAO;AACvB,YAAM,gBAAgB,OAAO,WAAW,IAAI;AAC5C,UAAI,CAAC,cAAe,OAAM,IAAI,MAAM,4CAA4C;AAChF,UAAI;AACJ,UAAI;AACJ,UAAI;AACF,uBAAe,cAAc,aAAa,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM,EAAE;AAC7E,oBAAY,WAAW,aAAa,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM,EAAE;AAAA,MACzE,SAAS,OAAO;AACd,cAAM,IAAI,MAAM,qEAAqE;AAAA,UACnF,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AACA,YAAM,SAAS,aAAa,cAAc,WAAW,OAAO,OAAO,OAAO,QAAQ;AAAA,QAChF,GAAG,OAAO;AAAA,QACV,SAAS,OAAO,aAAa,UAAU,MAAM;AAAA,QAC7C,SAAS,OAAO,aAAa,UAAU,MAAM;AAAA,MAC/C,CAAC;AACD,YAAM,YAAY,cAAc,gBAAgB,OAAO,OAAO,OAAO,MAAM;AAC3E,gBAAU,KAAK,IAAI,MAAM;AACzB,oBAAc,aAAa,WAAW,GAAG,CAAC;AAC1C,yBAAmB;AAAA,IACrB;AACA,YAAQ,KAAK;AACb,QAAI,OAAO,aAAa,OAAO,oBAAoB,OAAO;AACxD,YAAM,OAAO;AAAA,QACX,OAAO;AAAA,QACP,OAAO,QAAQ,OAAO,SAAS;AAAA,QAC/B,OAAO,SAAS,OAAO,UAAU;AAAA,QACjC,OAAO;AAAA,QACP,OAAO;AAAA,MACT;AACA,cAAQ,UAAU;AAClB,cAAQ,KAAK,KAAK,MAAM,KAAK,KAAK,KAAK,OAAO,KAAK,MAAM;AACzD,cAAQ,KAAK;AAAA,IACf;AACA,YAAQ,cAAc,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,OAAO,iBAAiB,CAAC,CAAC;AACxE,YAAQ,2BACN,CAAC,OAAO,mBAAmB,OAAO,oBAAoB,WAClD,gBACA,OAAO;AACb,YAAQ,UAAU,kBAAkB,GAAG,CAAC;AACxC,YAAQ,QAAQ;AAEhB,QAAI,OAAO,SAAS;AAClB,cAAQ,KAAK;AACb,cAAQ,cAAc,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,OAAO,QAAQ,WAAW,CAAC,CAAC;AAC1E,cAAQ,2BACN,OAAO,QAAQ,cAAc,WACzB,gBACC,OAAO,QAAQ,aAAa;AACnC,gBAAU,MAAM,UAAU,OAAO,QAAQ,KAAK,CAAC;AAC/C,cAAQ,QAAQ;AAAA,IAClB;AACA,WAAO,MAAM,oBAAoB,QAAQ,QAAQ,OAAO;AAAA,EAC1D,UAAE;AACA,eAAW,WAAW,SAAS;AAC7B,cAAQ,QAAQ;AAChB,cAAQ,SAAS;AAAA,IACnB;AAAA,EACF;AACF;AAEO,SAAS,UAAU,QAAwB;AAChD,SAAO,OAAO,MAAM;AACtB;AAEO,SAAS,cAAc,QAAgB,SAAsB,OAAO,aAAa,GAAW;AACjG,SAAO,OAAO,UAAU,EAAE,QAAQ,WAAW,CAAC;AAChD;;;AE5RO,SAAS,UAAU,OAAgC;AACxD,SAAO,OAAO,KAAK,EAChB,WAAW,KAAK,OAAO,EACvB,WAAW,KAAK,MAAM,EACtB,WAAW,KAAK,MAAM,EACtB,WAAW,KAAK,QAAQ,EACxB,WAAW,KAAK,QAAQ;AAC7B;AAUO,SAAS,YAAY,KAAqB;AAC/C,QAAMC,YAAW,IAAI,UAAU,EAAE,gBAAgB,KAAK,eAAe;AACrE,MAAIA,UAAS,cAAc,aAAa,EAAG,OAAM,IAAI,MAAM,sBAAsB;AACjF,EAAAA,UACG,iBAAiB,2DAA2D,EAC5E,QAAQ,CAAC,SAAS,KAAK,OAAO,CAAC;AAClC,EAAAA,UAAS,iBAAiB,GAAG,EAAE,QAAQ,CAAC,SAAS;AAC/C,eAAW,aAAa,CAAC,GAAG,KAAK,UAAU,GAAG;AAC5C,YAAM,OAAO,UAAU,KAAK,YAAY;AACxC,YAAM,QAAQ,UAAU,MAAM,KAAK,EAAE,YAAY;AACjD,YAAM,SAAS,SAAS,UAAU,SAAS,gBAAgB,SAAS;AACpE,YAAM,WACJ,MAAM,WAAW,GAAG,KAAK,6CAA6C,KAAK,KAAK;AAClF,UACE,KAAK,WAAW,IAAI,KACnB,UAAU,CAAC,YACX,WAAW,KAAK,KAAK,KAAK,CAAC,oBAAoB,KAAK,KAAK,KAC1D,kCAAkC,KAAK,KAAK,GAC5C;AACA,aAAK,gBAAgB,UAAU,IAAI;AAAA,MACrC;AAAA,IACF;AAAA,EACF,CAAC;AACD,SAAO,IAAI,cAAc,EAAE,kBAAkBA,UAAS,eAAe;AACvE;;;ACxCA,SAAS,WAAW,QAAwB;AAC1C,SAAO,mBAAmB,KAAK,OAAO,KAAK,CAAC,IAAI,SAAS,OAAO,KAAK,UAAU,MAAM,CAAC;AACxF;AAEA,SAAS,cAAc,QAAwB;AAC7C,QAAM,OAAO,OAAO,MAAM,MAAM,EAAE,CAAC,EAAE,YAAY;AACjD,MAAI,KAAK,SAAS,QAAQ,EAAG,QAAO;AACpC,MAAI,KAAK,SAAS,OAAO,EAAG,QAAO;AACnC,MAAI,KAAK,SAAS,MAAM,EAAG,QAAO;AAClC,SAAO;AACT;AAEA,SAAS,oBAAoB,QAA6B;AACxD,QAAM,QAAQ,IAAI,WAAW,MAAM;AACnC,MAAI,SAAS;AACb,WAAS,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS,OAAQ;AACzD,cAAU,OAAO,aAAa,GAAG,MAAM,SAAS,OAAO,QAAQ,KAAM,CAAC;AAAA,EACxE;AACA,SAAO,KAAK,MAAM;AACpB;AAQA,SAAS,UAAU,OAAuB;AACxC,SAAO,KAAK,UAAU,KAAK,EAAE,QAAQ,UAAU,CAAC,SAAS,KAAK,KAAK,WAAW,CAAC,EAAE,SAAS,EAAE,CAAC,GAAG;AAClG;AAEA,IAAM,cAAc;AACpB,IAAM,aAAa;AACnB,IAAM,eAAe;AAErB,SAAS,WAAW,OAA2B,SAAiB,UAA0B;AACxF,QAAM,UAAU,OAAO,KAAK;AAC5B,SAAO,WAAW,QAAQ,KAAK,OAAO,IAAI,UAAU;AACtD;AAEA,SAAS,UAAU,QAA+B;AAChD,QAAM,UAAU,OAAO,KAAK;AAC5B,MAAI,QAAQ,WAAW,OAAO,EAAG,QAAO;AACxC,QAAM,QAAQ,QAAQ,MAAM,+BAA+B;AAC3D,MAAI,MAAO,QAAO,MAAM,CAAC;AACzB,MAAI,YAAY,KAAK,OAAO,EAAG,QAAO;AACtC,SAAO;AACT;AAOA,SAAS,UAAU,QAA+B;AAChD,QAAM,QAAQ,OAAO,KAAK,EAAE,MAAM,yCAAyC;AAC3E,SAAO,QAAQ,MAAM,CAAC,EAAE,KAAK,KAAK,OAAO;AAC3C;AAGO,IAAM,eAAN,MAAmB;AAAA,EAChB,cAAc,oBAAI,IAA4B;AAAA,EAC9C,QAAQ,oBAAI,IAA+B;AAAA,EAEnD,SAAS,YAAkC;AACzC,QAAI,CAAC,WAAW,OAAO,KAAK,KAAK,CAAC,WAAW,OAAO,KAAK,GAAG;AAC1D,YAAM,IAAI,MAAM,qCAAqC;AAAA,IACvD;AACA,SAAK,YAAY,IAAI,WAAW,QAAQ,EAAE,GAAG,WAAW,CAAC;AACzD,SAAK,MAAM,OAAO,WAAW,MAAM;AAAA,EACrC;AAAA,EAEA,WAAW,QAAyB;AAClC,SAAK,MAAM,OAAO,MAAM;AACxB,WAAO,KAAK,YAAY,OAAO,MAAM;AAAA,EACvC;AAAA,EAEA,SAA2B;AACzB,WAAO,CAAC,GAAG,KAAK,YAAY,OAAO,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,GAAG,WAAW,EAAE;AAAA,EAC/E;AAAA,EAEA,KAAK,QAAmC;AACtC,UAAM,SAAS,KAAK,MAAM,IAAI,MAAM;AACpC,QAAI,OAAQ,QAAO;AACnB,UAAM,aAAa,KAAK,YAAY,IAAI,MAAM;AAC9C,QAAI,CAAC,WAAY,QAAO,QAAQ,OAAO,IAAI,MAAM,2BAA2B,MAAM,EAAE,CAAC;AACrF,QAAI,OAAO,aAAa,eAAe,OAAO,aAAa,aAAa;AACtE,aAAO,QAAQ,OAAO,IAAI,MAAM,8CAA8C,CAAC;AAAA,IACjF;AACA,UAAM,UAAU,IAAI,SAAS,WAAW,QAAQ,WAAW,WAAW,MAAM,GAAG;AAAA,MAC7E,QAAQ,WAAW;AAAA,MACnB,OAAO,WAAW;AAAA,MAClB,SAAS,WAAW;AAAA,IACtB,CAAC,EACE,KAAK,EACL,KAAK,CAAC,SAAS;AACd,eAAS,MAAM,IAAI,IAAI;AACvB,aAAO;AAAA,IACT,CAAC;AACH,YAAQ,MAAM,MAAM;AAClB,UAAI,KAAK,MAAM,IAAI,MAAM,MAAM,QAAS,MAAK,MAAM,OAAO,MAAM;AAAA,IAClE,CAAC;AACD,SAAK,MAAM,IAAI,QAAQ,OAAO;AAC9B,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAuB;AAC3B,QAAI,KAAK,YAAY,SAAS,EAAG;AACjC,UAAM,QAAQ,IAAI,CAAC,GAAG,KAAK,YAAY,KAAK,CAAC,EAAE,IAAI,CAAC,WAAW,KAAK,KAAK,MAAM,CAAC,CAAC;AACjF,UAAM,SAAS,MAAM;AAAA,EACvB;AAAA,EAEA,MAAM,iBAAkC;AACtC,UAAM,QAAQ,MAAM,QAAQ;AAAA,MAC1B,KAAK,OAAO,EAAE,IAAI,OAAO,eAAe;AAItC,cAAM,MAAM,UAAU,WAAW,MAAM;AACvC,YAAI;AACJ,YAAI,OAAO,CAAC,IAAI,WAAW,OAAO,GAAG;AACnC,gBAAM,WAAW,MAAM,MAAM,GAAG;AAChC,cAAI,CAAC,SAAS,GAAI,OAAM,IAAI,MAAM,yBAAyB,GAAG,EAAE;AAChE,gBAAM,OAAO,oBAAoB,MAAM,SAAS,YAAY,CAAC;AAC7D,gBAAM,OAAO,SAAS,QAAQ,IAAI,cAAc,KAAK,cAAc,GAAG;AACtE,sBAAY,OAAO,UAAU,QAAQ,IAAI,WAAW,IAAI,EAAE,CAAC;AAAA,QAC7D,WAAW,KAAK;AACd,sBAAY,OAAO,UAAU,GAAG,CAAC;AAAA,QACnC,OAAO;AACL,gBAAM,OAAO,UAAU,WAAW,MAAM;AACxC,cAAI,CAAC,MAAM;AACT,kBAAM,IAAI,MAAM,0CAA0C,WAAW,MAAM,EAAE;AAAA,UAC/E;AACA,sBAAY,SAAS,UAAU,IAAI,CAAC;AAAA,QACtC;AACA,cAAM,SAAS,WAAW,WAAW,QAAQ,aAAa,QAAQ;AAClE,cAAM,QAAQ,WAAW,WAAW,OAAO,YAAY,QAAQ;AAC/D,cAAM,UAAU,WAAW,WAAW,SAAS,cAAc,MAAM;AACnE,eAAO,0BAA0B,UAAU,WAAW,MAAM,CAAC,QAAQ,SAAS,gBAAgB,MAAM,eAAe,KAAK,iBAAiB,OAAO;AAAA,MAClJ,CAAC;AAAA,IACH;AACA,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AACF;;;AC/IA,SAAS,cAAc,UAAkB,SAA0B;AACjE,QAAM,OAAO,SAAS,YAAY;AAClC,QAAM,WAAW,QAAQ,YAAY;AACrC,MAAI,SAAS,WAAW,IAAI,GAAG;AAC7B,UAAM,SAAS,SAAS,MAAM,CAAC;AAC/B,WAAO,KAAK,SAAS,MAAM,KAAK,KAAK,SAAS,OAAO;AAAA,EACvD;AACA,SAAO,SAAS;AAClB;AAEA,SAAS,QAAQ,UAA2B;AAC1C,SACE,aAAa,eACb,aAAa,eACb,aAAa,SACb,SAAS,SAAS,YAAY;AAElC;AAGO,IAAM,iBAAN,MAAqB;AAAA,EAI1B,YAAoB,SAAwB,CAAC,GAAG;AAA5B;AAClB,UAAM,WAAW,OAAO,YAAY,WAAW,UAAU,YAAY;AACrE,UAAM,cAAc,OAAO,eAAe;AAC1C,QAAI,gBAAgB,gBAAgB,QAAQ,QAAQ,GAAG;AACrD,WAAK,SAAS,EAAE,OAAO,UAAU,SAAS,KAAK;AAC/C,WAAK,eAAe,QAAQ,QAAQ,KAAK,MAAM;AAAA,IACjD,WAAW,CAAC,OAAO,KAAK;AACtB,WAAK,SAAS,EAAE,OAAO,aAAa,SAAS,KAAK;AAClD,WAAK,eAAe,QAAQ,QAAQ,KAAK,MAAM;AAAA,IACjD,OAAO;AACL,WAAK,SAAS,EAAE,OAAO,YAAY,SAAS,KAAK;AACjD,WAAK,eAAe,KAAK,SAAS,OAAO,KAAK,QAAQ;AAAA,IACxD;AAAA,EACF;AAAA,EAboB;AAAA,EAHZ;AAAA,EACA;AAAA,EAiBR,YAA2B;AACzB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,QAAgC;AAC9B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,WAAW,SAA0B;AACnC,WAAO,KAAK,OAAO,UAAU,YAAY,KAAK,OAAO,QAAQ,YAAY,CAAC,GAAG,SAAS,OAAO;AAAA,EAC/F;AAAA,EAEA,MAAM,MAAoB;AACxB,SAAK,OAAO,UAAU;AAAA,MACpB;AAAA,MACA,KAAI,oBAAI,KAAK,GAAE,YAAY;AAAA,MAC3B,WAAW,KAAK,OAAO,UAAU,UAAU,KAAK,OAAO,QAAQ,KAAK;AAAA,IACtE,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,SAAS,KAAa,UAA0C;AAC5E,UAAM,UAAW,MAAM,KAAK,OAAO,gBAAgB,GAAG,KAAM;AAC5D,QAAI,CAAC,QAAS,QAAQ,KAAK,SAAS,EAAE,OAAO,WAAW,SAAS,KAAK;AACtE,QAAI,QAAQ,aAAa,KAAK,MAAM,QAAQ,SAAS,IAAI,KAAK,IAAI,GAAG;AACnE,aAAQ,KAAK,SAAS,EAAE,OAAO,WAAW,QAAQ;AAAA,IACpD;AACA,QAAI,CAAC,QAAQ,QAAQ,KAAK,CAAC,WAAW,cAAc,UAAU,MAAM,CAAC,GAAG;AACtE,aAAQ,KAAK,SAAS,EAAE,OAAO,mBAAmB,QAAQ;AAAA,IAC5D;AACA,WAAQ,KAAK,SAAS,EAAE,OAAO,SAAS,QAAQ;AAAA,EAClD;AACF;;;ACnEO,IAAM,iBAAN,MAAqB;AAAA,EAI1B,YAAoB,QAAsB;AAAtB;AAClB,UAAM,QAAQ,EAAE,IAAI,WAAW,GAAG,MAAM,UAAU,OAAO,OAAO,OAAO,EAAE;AACzE,SAAK,QAAQ,CAAC,KAAK;AACnB,SAAK,eAAe,MAAM;AAAA,EAC5B;AAAA,EAJoB;AAAA,EAHZ;AAAA,EACA;AAAA,EAQR,SAA8C;AAC5C,WAAO,KAAK,MAAM,IAAI,CAAC,EAAE,IAAI,KAAK,OAAO,EAAE,IAAI,KAAK,EAAE;AAAA,EACxD;AAAA,EAEA,kBAA0B;AACxB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,OAAO,QAAQ,KAAK,MAAM,SAAS,CAAC,IAAI,eAAe,OAAe;AACxE,SAAK,YAAY;AACjB,UAAM,SAAS,gBAAgB,KAAK,OAAO,OAAO,CAAC;AACnD,UAAM,QAAQ,eAAe,SAAS,KAAK,WAAW,MAAM;AAC5D,UAAM,OAAO,EAAE,IAAI,WAAW,GAAG,MAAM,MAAM;AAC7C,SAAK,MAAM,KAAK,IAAI;AACpB,SAAK,YAAY;AACjB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,SAAS,IAA8B;AAC3C,QAAI,OAAO,KAAK,aAAc,QAAO;AACrC,UAAM,OAAO,KAAK,MAAM,KAAK,CAAC,cAAc,UAAU,OAAO,EAAE;AAC/D,QAAI,CAAC,KAAM,QAAO;AAClB,SAAK,YAAY;AACjB,UAAM,KAAK,OAAO,SAAS,gBAAgB,KAAK,KAAK,CAAC;AACtD,SAAK,eAAe;AACpB,SAAK,YAAY;AACjB,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,UAAU,IAAoC;AAClD,SAAK,YAAY;AACjB,UAAM,SAAS,KAAK,MAAM,KAAK,CAACC,UAASA,MAAK,OAAO,EAAE;AACvD,QAAI,CAAC,OAAQ,QAAO;AACpB,UAAM,OAAO;AAAA,MACX,IAAI,WAAW;AAAA,MACf,MAAM,GAAG,OAAO,IAAI;AAAA,MACpB,OAAO,gBAAgB,OAAO,KAAK;AAAA,IACrC;AACA,UAAM,QAAQ,KAAK,MAAM,QAAQ,MAAM;AACvC,SAAK,MAAM,OAAO,QAAQ,GAAG,GAAG,IAAI;AACpC,SAAK,YAAY;AACjB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,OAAO,IAA8B;AACzC,QAAI,KAAK,MAAM,WAAW,EAAG,QAAO;AACpC,UAAM,QAAQ,KAAK,MAAM,UAAU,CAAC,SAAS,KAAK,OAAO,EAAE;AAC3D,QAAI,QAAQ,EAAG,QAAO;AACtB,QAAI,OAAO,KAAK,cAAc;AAC5B,YAAM,OAAO,KAAK,MAAM,QAAQ,CAAC,KAAK,KAAK,MAAM,QAAQ,CAAC;AAC1D,YAAM,KAAK,OAAO,SAAS,gBAAgB,KAAK,KAAK,CAAC;AACtD,WAAK,eAAe,KAAK;AAAA,IAC3B;AACA,SAAK,MAAM,OAAO,OAAO,CAAC;AAC1B,SAAK,YAAY;AACjB,WAAO;AAAA,EACT;AAAA,EAEA,OAAO,IAAY,MAAuB;AACxC,UAAM,OAAO,KAAK,MAAM,KAAK,CAAC,cAAc,UAAU,OAAO,EAAE;AAC/D,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,CAAC,QAAQ,CAAC,WAAW,KAAK,SAAS,QAAS,QAAO;AACvD,SAAK,OAAO;AACZ,SAAK,YAAY;AACjB,WAAO;AAAA,EACT;AAAA,EAEA,QAAQ,IAAY,UAA2B;AAC7C,UAAM,QAAQ,KAAK,MAAM,UAAU,CAACA,UAASA,MAAK,OAAO,EAAE;AAC3D,QAAI,QAAQ,KAAK,CAAC,OAAO,SAAS,QAAQ,EAAG,QAAO;AACpD,UAAM,SAAS,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,MAAM,SAAS,GAAG,KAAK,MAAM,QAAQ,CAAC,CAAC;AAChF,QAAI,WAAW,MAAO,QAAO;AAC7B,UAAM,CAAC,IAAI,IAAI,KAAK,MAAM,OAAO,OAAO,CAAC;AACzC,SAAK,MAAM,OAAO,QAAQ,GAAG,IAAI;AACjC,SAAK,YAAY;AACjB,WAAO;AAAA,EACT;AAAA,EAEA,SAAuB;AACrB,SAAK,YAAY;AACjB,WAAO;AAAA,MACL,SAAS;AAAA,MACT,cAAc,KAAK;AAAA,MACnB,OAAO,gBAAgB,KAAK,KAAK;AAAA,IACnC;AAAA,EACF;AAAA,EAEA,MAAM,SAAS,SAAsC;AACnD,QACE,SAAS,YAAY,WACrB,CAAC,MAAM,QAAQ,QAAQ,KAAK,KAC5B,QAAQ,MAAM,WAAW,KACzB,CAAC,QAAQ,MAAM,KAAK,CAAC,SAAS,KAAK,OAAO,QAAQ,YAAY,GAC9D;AACA,YAAM,IAAI,MAAM,uBAAuB;AAAA,IACzC;AACA,UAAM,QAAQ,gBAAgB,QAAQ,KAAK;AAC3C,UAAM,SAAS,MAAM,KAAK,CAAC,SAAS,KAAK,OAAO,QAAQ,YAAY;AACpE,UAAM,KAAK,OAAO,SAAS,gBAAgB,OAAO,KAAK,CAAC;AACxD,SAAK,QAAQ;AACb,SAAK,eAAe,OAAO;AAC3B,SAAK,YAAY;AAAA,EACnB;AAAA,EAEQ,cAAoB;AAC1B,UAAM,OAAO,KAAK,MAAM,KAAK,CAAC,cAAc,UAAU,OAAO,KAAK,YAAY;AAC9E,QAAI,KAAM,MAAK,QAAQ,gBAAgB,KAAK,OAAO,OAAO,CAAC;AAAA,EAC7D;AAAA,EAEQ,WAAW,QAAkC;AACnD,WAAO,EAAE,GAAG,QAAQ,QAAQ,CAAC,GAAG,QAAQ,KAAK;AAAA,EAC/C;AAAA,EAEQ,cAAoB;AAC1B,SAAK,OAAO,OAAO,KAAK,mBAAmB;AAAA,MACzC,cAAc,KAAK;AAAA,MACnB,OAAO,KAAK,OAAO;AAAA,IACrB,CAAC;AAAA,EACH;AACF;;;ACtIA,IAAAC,kBAA4B;AAcrB,IAAM,sBAAN,cAAkC,MAAM;AAAA,EAC7C,YACW,MACT,SACS,OACT;AACA,UAAM,OAAO;AAJJ;AAEA;AAGT,SAAK,OAAO;AAAA,EACd;AAAA,EANW;AAAA,EAEA;AAKb;AAeO,IAAM,iBAAN,MAAqB;AAAA,EAY1B,YAA6B,QAAsB;AAAtB;AAAA,EAAuB;AAAA,EAAvB;AAAA,EAXrB,UAAoC;AAAA,EACpC,UAA2C;AAAA,EAC3C,UAAyB;AAAA,EACzB,QAAiC;AAAA,EACjC,gBAAkC;AAAA,EAClC,eAAiC;AAAA,EACjC,kBAAiC;AAAA,EACjC,2BAA2B;AAAA,EAC3B,aAAqC;AAAA,EACrC,WAAW;AAAA,EAInB,MAAM,OACJ,QAAQ,KAAK,OAAO,OAAO,SAAS,GACpC,SAAS,KAAK,OAAO,OAAO,UAAU,GACtB;AAChB,SAAK,aAAa;AAClB,QAAI,CAAC,OAAO,UAAU,KAAK,KAAK,CAAC,OAAO,UAAU,MAAM,KAAK,SAAS,KAAK,UAAU,GAAG;AACtF,YAAM,IAAI,MAAM,2CAA2C;AAAA,IAC7D;AACA,UAAM,UAAU,KAAK,WAAW,OAAO,MAAM;AAC7C,UAAM,QAAQ,IAAI,4BAAY,SAAS;AAAA,MACrC,MAAM;AAAA,MACN,KAAK;AAAA,MACL,SAAS;AAAA,MACT,SAAS;AAAA,MACT,YAAY;AAAA,IACd,CAAC;AACD,UAAM,QAAQ,KAAK,OAAO,OAAO,IAAI,QAAQ,OAAO,MAAM;AAC1D,UAAM,KAAK,OAAO,EAAE,OAAO,QAAQ,UAAU,EAAE;AAC/C,SAAK,OAAO,QAAQ,cAAc;AAClC,SAAK,cAAc,MAAM,IAAI,OAAO;AACpC,WAAO;AAAA,EACT;AAAA,EAEA,OAAO,SAAuB;AAC5B,SAAK,aAAa;AAGlB,SAAK,aAAa;AAClB,UAAM,QAAQ,KAAK,YAAY,OAAO;AACtC,UAAM,QAAQ,MAAM;AACpB,UAAM,QAAQ,MAAM,KAAK,MAAM,SAAS,MAAM,SAAS,KAAK,OAAO,OAAO,SAAS;AACnF,UAAM,SAAS,MAAM,KAAK,MAAM,UAAU,MAAM,UAAU,KAAK,OAAO,OAAO,UAAU;AACvF,UAAM,UAAU,KAAK,WAAW,OAAO,MAAM;AAC7C,UAAM,UAAU,QAAQ,WAAW,IAAI;AACvC,QAAI,CAAC,QAAS,OAAM,IAAI,MAAM,gCAAgC;AAC9D,UAAM,UAAU,MAAM,WAAW;AACjC,QAAI,QAAS,SAAQ,UAAU,SAAS,GAAG,GAAG,OAAO,MAAM;AAC3D,SAAK,cAAc,SAAS,OAAO;AAAA,EACrC;AAAA,EAEA,YAAY,SAAiC;AAC3C,SAAK,aAAa;AAClB,QAAI,CAAC,KAAK,WAAW,CAAC,KAAK,WAAW,CAAC,KAAK,QAAS,OAAM,IAAI,MAAM,qBAAqB;AAC1F,QAAI,KAAK,MAAO,OAAM,IAAI,MAAM,iCAAiC;AACjE,QAAI,CAAC,OAAO,SAAS,QAAQ,IAAI,KAAK,QAAQ,QAAQ,GAAG;AACvD,YAAM,IAAI,MAAM,kCAAkC;AAAA,IACpD;AACA,SAAK,QAAQ,EAAE,GAAG,SAAS,UAAU,MAAM,QAAQ,UAAU,GAAG,CAAC,EAAE;AACnE,SAAK,gBAAgB;AACrB,SAAK,eAAe,KAAK,QAAQ,aAAa,GAAG,GAAG,KAAK,QAAQ,OAAO,KAAK,QAAQ,MAAM;AAC3F,SAAK,kBAAkB,YAAY,IAAI;AAAA,EACzC;AAAA,EAEA,SAAS,OAAwB;AAC/B,QAAI,CAAC,KAAK,SAAS,CAAC,KAAK,WAAW,CAAC,KAAK,WAAW,CAAC,KAAK,SAAS;AAClE,YAAM,IAAI,MAAM,uBAAuB;AAAA,IACzC;AACA,QAAI,CAAC,OAAO,SAAS,MAAM,CAAC,KAAK,CAAC,OAAO,SAAS,MAAM,CAAC,EAAG;AAC5D,UAAM,WAAW,KAAK,iBAAiB;AACvC,UAAM,WAAW,KAAK,MAAM,MAAM,IAAI,SAAS,GAAG,MAAM,IAAI,SAAS,CAAC;AACtE,UAAM,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,OAAO,CAAC;AAC5C,UAAM,UAAU,KAAK,IAAI,GAAG,KAAK,KAAK,WAAW,IAAI,CAAC;AACtD,aAAS,QAAQ,GAAG,SAAS,SAAS,SAAS,GAAG;AAChD,YAAM,QAAQ,QAAQ;AACtB,WAAK,QAAQ;AAAA,QACX,GAAG,SAAS,KAAK,MAAM,IAAI,SAAS,KAAK;AAAA,QACzC,GAAG,SAAS,KAAK,MAAM,IAAI,SAAS,KAAK;AAAA,MAC3C,CAAC;AAAA,IACH;AACA,SAAK,gBAAgB;AACrB,IAAC,KAAK,YAAY,KAAK,OAAO,EAAE,aAA6B,WAAW,KAAK,OAAO;AACpF,SAAK,OAAO,OAAO,iBAAiB;AAAA,EACtC;AAAA,EAEA,MAAM,YAA2B;AAC/B,QAAI,CAAC,KAAK,SAAS,CAAC,KAAK,WAAW,CAAC,KAAK,QAAS;AACnD,UAAM,UAAU,KAAK;AACrB,SAAK,QAAQ;AACb,SAAK,gBAAgB;AACrB,SAAK,eAAe;AACpB,UAAM,UAAU,KAAK,QAAQ,UAAU,WAAW;AAClD,UAAM,KAAK,OAAO,QAAQ,YAAY,YAAY;AAChD,YAAM,KAAK,OAAO,mBAAmB,SAAS,OAAO;AACrD,YAAM,QAAQ,KAAK,YAAY,OAAO;AACtC,UAAI,MAAM,KAAK,KAAM,OAAM,KAAK,KAAK,YAAY;AAAA,IACnD,CAAC;AACD,SAAK,OAAO,OAAO;AACnB,QAAI,KAAK,oBAAoB,MAAM;AACjC,WAAK,2BAA2B,YAAY,IAAI,IAAI,KAAK;AACzD,WAAK,kBAAkB;AAAA,IACzB;AAAA,EACF;AAAA,EAEA,eAAqB;AACnB,QAAI,KAAK,gBAAgB,KAAK,WAAW,KAAK,WAAW,KAAK,SAAS;AACrE,WAAK,QAAQ,aAAa,KAAK,cAAc,GAAG,CAAC;AACjD,MAAC,KAAK,YAAY,KAAK,OAAO,EAAE,aAA6B,WAAW,KAAK,OAAO;AACpF,WAAK,OAAO,OAAO,iBAAiB;AAAA,IACtC;AACA,SAAK,QAAQ;AACb,SAAK,gBAAgB;AACrB,SAAK,eAAe;AACpB,SAAK,kBAAkB;AAAA,EACzB;AAAA,EAEA,iBAA0B;AACxB,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA,EAEA,gBAA+B;AAC7B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,OAAO,SAAwB;AAC7B,QAAI,WAAW,KAAK,YAAY,QAAS;AACzC,SAAK,aAAa;AAClB,SAAK,iBAAiB;AACtB,SAAK,UAAU;AACf,SAAK,UAAU;AACf,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,MAAM,OACJ,SACA,UACA,SACA,UAA6E,CAAC,GAC/C;AAC/B,SAAK,aAAa;AAClB,UAAM,QAAQ,KAAK,OAAO,OAAO,IAAI,OAAO;AAC5C,QAAI,CAAC,SAAS,MAAM,SAAS,QAAQ;AACnC,YAAM,IAAI,oBAAoB,aAAa,yBAAyB,OAAO,EAAE;AAAA,IAC/E;AACA,SAAK,iBAAiB;AACtB,UAAM,aAAa,IAAI,gBAAgB;AACvC,SAAK,aAAa;AAClB,UAAM,QAAQ,MAAM,WAAW,MAAM,QAAQ,QAAQ,MAAM;AAC3D,YAAQ,QAAQ,iBAAiB,SAAS,OAAO,EAAE,MAAM,KAAK,CAAC;AAC/D,QAAI,QAAQ,QAAQ,QAAS,OAAM;AACnC,QAAI;AACF,YAAM,QAAQ,MAAM;AACpB,YAAM,SAAS,MAAM,SAAS;AAAA,QAC5B;AAAA,UACE,MAAM,MAAM,OAAO;AAAA,UACnB,OAAO,MAAM,KAAK,MAAM,SAAS,MAAM,SAAS;AAAA,UAChD,QAAQ,MAAM,KAAK,MAAM,UAAU,MAAM,UAAU;AAAA,UACnD,SAAS,gBAAgB,OAAO;AAAA,QAClC;AAAA,QACA,EAAE,QAAQ,WAAW,QAAQ,YAAY,QAAQ,WAAW;AAAA,MAC9D;AACA,UAAI,WAAW,OAAO;AACpB,cAAM,IAAI,oBAAoB,aAAa,2BAA2B;AAGxE,UAAI,CAAC,0CAA0C,KAAK,OAAO,OAAO,GAAG;AACnE,cAAM,IAAI;AAAA,UACR;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,YAAM,KAAK,OAAO,QAAQ,YAAY,YAAY;AAChD,cAAM,KAAK,OAAO,mBAAmB,SAAS,OAAO,OAAO;AAC5D,YAAI,MAAM,KAAK,KAAM,OAAM,KAAK,KAAK,YAAY;AAAA,MACnD,CAAC;AACD,WAAK,OAAO,OAAO;AACnB,aAAO;AAAA,IACT,SAAS,OAAO;AACd,UAAI,iBAAiB,oBAAqB,OAAM;AAChD,UAAI,WAAW,OAAO,SAAS;AAC7B,cAAM,IAAI,oBAAoB,aAAa,6BAA6B,KAAK;AAAA,MAC/E;AACA,YAAM,IAAI,oBAAoB,YAAY,mCAAmC,KAAK;AAAA,IACpF,UAAE;AACA,cAAQ,QAAQ,oBAAoB,SAAS,KAAK;AAClD,UAAI,KAAK,eAAe,WAAY,MAAK,aAAa;AAAA,IACxD;AAAA,EACF;AAAA,EAEA,mBAAyB;AACvB,SAAK,YAAY,MAAM,IAAI,aAAa,aAAa,YAAY,CAAC;AAClE,SAAK,aAAa;AAAA,EACpB;AAAA,EAEA,UAAwC;AACtC,QAAI,CAAC,KAAK,QAAS,QAAO;AAC1B,UAAM,UAAU,YAAY,IAAI;AAChC,SAAK,SAAS,aAAa,GAAG,GAAG,GAAG,CAAC;AACrC,UAAM,eAAe,KAAK,QAAQ,QAAQ,KAAK,QAAQ,SAAS;AAChE,UAAM,oBAAoB,KAAK,eAAe,eAAe;AAC7D,UAAM,SAAS;AACf,WAAO;AAAA,MACL,OAAO,KAAK,QAAQ;AAAA,MACpB,QAAQ,KAAK,QAAQ;AAAA,MACrB;AAAA,MACA;AAAA;AAAA;AAAA,MAGA,oBAAoB,eAAe;AAAA,MACnC,cAAc,KAAK,OAAO,QAAQ,iBAAiB;AAAA,MACnD,sBAAsB,KAAK;AAAA,MAC3B,GAAI,OAAO,OAAO,QAAQ,mBAAmB,WACzC,EAAE,iBAAiB,OAAO,OAAO,eAAe,IAChD,CAAC;AAAA,MACL,WAAW,YAAY,IAAI,IAAI;AAAA,IACjC;AAAA,EACF;AAAA,EAEA,UAAgB;AACd,SAAK,OAAO;AACZ,SAAK,WAAW;AAAA,EAClB;AAAA,EAEQ,QAAQ,OAAwB;AACtC,UAAM,UAAU,KAAK;AACrB,UAAM,QAAQ,KAAK;AACnB,UAAM,SAAS,MAAM,OAAO;AAC5B,YAAQ,KAAK;AACb,YAAQ,2BACN,MAAM,SAAS,aAAa,oBAAoB;AAClD,UAAM,WAAW,QAAQ;AAAA,MACvB,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,MAAM;AAAA,MACf,MAAM;AAAA,MACN,MAAM;AAAA,MACN;AAAA,IACF;AACA,UAAM,QAAQ,MAAM,SAAS,aAAa,kBAAkB;AAC5D,aAAS,aAAa,GAAG,KAAK;AAC9B,aAAS,aAAa,GAAG,qBAAqB;AAC9C,YAAQ,YAAY;AACpB,YAAQ,UAAU;AAClB,YAAQ,IAAI,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,KAAK,CAAC;AACpD,YAAQ,KAAK;AACb,YAAQ,QAAQ;AAAA,EAClB;AAAA,EAEQ,WAAW,OAAe,QAAmC;AACnE,UAAM,SAAS,KAAK,OAAO,OAAO,cAAc,cAAc,cAAc,QAAQ;AACpF,WAAO,QAAQ;AACf,WAAO,SAAS;AAChB,WAAO;AAAA,EACT;AAAA,EAEQ,cAAc,SAAiB,SAAkC;AACvE,UAAM,UAAU,QAAQ,WAAW,IAAI;AACvC,QAAI,CAAC,QAAS,OAAM,IAAI,MAAM,gCAAgC;AAC9D,SAAK,UAAU;AACf,SAAK,UAAU;AACf,SAAK,UAAU;AAAA,EACjB;AAAA,EAEQ,YAAY,SAAwB;AAC1C,UAAM,QAAQ,KAAK,OAAO,OAAO,IAAI,OAAO;AAC5C,QAAI,CAAC,SAAS,MAAM,SAAS,OAAQ,OAAM,IAAI,MAAM,yBAAyB,OAAO,EAAE;AACvF,WAAO;AAAA,EACT;AAAA,EAEQ,eAAqB;AAC3B,QAAI,KAAK,SAAU,OAAM,IAAI,MAAM,mCAAmC;AAAA,EACxE;AACF;;;ACzTA,IAAAC,kBAAsB;;;ACAtB,IAAAC,kBAA4B;AAW5B,IAAM,iBAAkE;AAAA,EACtE,KAAK;AAAA,EACL,UAAU;AAAA,EACV,WAAW;AACb;AAOA,SAAS,WAAW,OAA2B;AAC7C,QAAM,IAAI,EAAE,SAAS,GAAG,0BAA0B,cAAc,CAAC;AACnE;AAOA,SAAS,SAAS,KAAiF;AACjG,SAAO,IAAI,qBAAK;AAAA,IACd,MAAM,IAAI;AAAA,IACV,KAAK,IAAI;AAAA,IACT,OAAO,KAAK,IAAI,GAAG,IAAI,KAAK;AAAA,IAC5B,QAAQ,KAAK,IAAI,GAAG,IAAI,MAAM;AAAA,IAC9B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,MAAM;AAAA,IACN,eAAe;AAAA,EACjB,CAAC;AACH;AAoBO,SAAS,iBACd,UACA,SACA,SACmB;AACnB,MAAI,SAAS,WAAW,EAAG,QAAO;AAElC,WAAS,QAAQ,CAAC,OAAO,UAAU;AACjC,UAAM,QAAQ,QAAQ,KAAK;AAC3B,UAAM,IAAI,EAAE,eAAe,MAAM,CAAC;AAClC,QAAI,CAAC,SAAS,CAAC,MAAM,SAAS;AAC5B,iBAAW,KAAK;AAChB;AAAA,IACF;AACA,UAAM,IAAI;AAAA,MACR,SAAS,MAAM;AAAA,MACf,0BAA0B,eAAe,MAAM,IAAI,KAAK;AAAA,IAC1D,CAAC;AAAA,EACH,CAAC;AAED,QAAM,QAAQ,QAAQ,KAAK,CAAC,UAAU,MAAM,OAAO;AACnD,QAAM,WACJ,SAAS,MAAM,SAAS,QAAQ,CAAC,SAAS,QAAQ,GAAG,GAAG,GAAG,QAAQ,IAAI,CAAC,GAAG,QAAQ;AAErF,SAAO,IAAI,sBAAM,UAAU;AAAA,IACzB,oBAAoB,QAAQ;AAAA;AAAA;AAAA,IAG5B,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,aAAa;AAAA,EACf,CAAC;AACH;AAGO,SAAS,mBAAmB,SAAoC;AACrE,SAAO,QAAQ,KAAK,CAAC,UAAU,CAAC,MAAM,MAAM;AAC9C;;;ACnGA,IAAAC,kBAA4B;;;ACA5B,IAAAC,kBAAqB;AAsBd,SAAS,SAAS,QAA8B;AACrD,SAAO,OAAO,oBAAoB;AACpC;AAGO,SAAS,YAAY,QAAsB,QAAsB;AACtE,QAAM,aAAa,qBAAK,YAAY,MAAM;AAC1C,SAAO,IAAI;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,SAAS;AAAA,IACT,SAAS;AAAA,IACT,MAAM,WAAW;AAAA,IACjB,KAAK,WAAW;AAAA,IAChB,QAAQ,WAAW;AAAA,IACnB,QAAQ,WAAW;AAAA,IACnB,OAAO,WAAW;AAAA,IAClB,OAAO,WAAW;AAAA,IAClB,OAAO;AAAA,EACT,CAAC;AACD,SAAO,UAAU;AACnB;AAGO,SAAS,cAAc,QAAsB,MAA0B;AAC5E,cAAY,QAAQ,qBAAK,0BAA0B,SAAS,IAAI,GAAG,SAAS,MAAM,CAAC,CAAC;AACtF;AAGO,SAAS,YAAY,QAAsB,MAA0B;AAC1E;AAAA,IACE;AAAA,IACA,qBAAK,0BAA0B,qBAAK,gBAAgB,SAAS,IAAI,CAAC,GAAG,SAAS,MAAM,CAAC;AAAA,EACvF;AACF;AAOO,SAAS,eAAe,QAAsB,MAA4B;AAC/E,SAAO,qBAAK,0BAA0B,qBAAK,gBAAgB,SAAS,IAAI,CAAC,GAAG,SAAS,MAAM,CAAC;AAC9F;AAGO,SAAS,oBAAoB,QAAsB,MAAoB,KAAmB;AAC/F,cAAY,QAAQ,qBAAK,0BAA0B,SAAS,IAAI,GAAG,GAAG,CAAC;AACzE;AAOO,SAAS,SAAS,MAA2D;AAClF,SAAO;AACT;AAGO,SAAS,SAAS,QAA6C;AACpE,MAAI,CAAC,UAAU,OAAO,WAAW,KAAK,OAAO,KAAK,CAAC,UAAU,CAAC,OAAO,SAAS,KAAK,CAAC;AAClF,WAAO;AACT,SAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,GAAG,OAAO,CAAC,GAAG,OAAO,CAAC,GAAG,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC;AAC1E;AAGO,SAAS,SACd,QACA,KACA,OAAO,GACD;AACN,QAAM,QAAQ,KAAK,IAAI,GAAG,IAAI,KAAK,IAAI;AACvC,QAAM,SAAS,KAAK,IAAI,GAAG,IAAI,MAAM,IAAI;AACzC,SAAO,IAAI;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM,IAAI,OAAO,IAAI,QAAQ;AAAA,IAC7B,KAAK,IAAI,MAAM,IAAI,SAAS;AAAA,IAC5B,QAAQ,QAAQ,KAAK,IAAI,GAAG,OAAO,SAAS,CAAC;AAAA,IAC7C,QAAQ,SAAS,KAAK,IAAI,GAAG,OAAO,UAAU,CAAC;AAAA,EACjD,CAAC;AACD,SAAO,UAAU;AACnB;AAcO,SAAS,YAAY,OAA8B;AACxD,QAAM,WAAW,MAAM,UAAU;AACjC,aAAW,SAAS,SAAU,OAAM,UAAU;AAC9C,SAAO;AACT;;;ADvGO,IAAM,qBAAN,MAAyB;AAAA,EAM9B,YACU,QACA,UACR;AAFQ;AACA;AAAA,EACP;AAAA,EAFO;AAAA,EACA;AAAA,EAPF,SAA8B;AAAA,EAC9B,UAAiC;AAAA,EACjC,QAA6B;AAAA,EAC7B,QAAsB;AAAA,EAO9B,SAAgC;AAC9B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,MAAM,MAAM,MAAsB,OAAc,OAAuC;AACrF,SAAK,IAAI;AACT,UAAM,SAAS,MAAM,MAAM,MAAM;AACjC,gBAAY,QAAQ,SAAS,KAAK,CAAC;AACnC,WAAO,IAAI;AAAA;AAAA;AAAA,MAGT,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,iBAAiB,CAAC,GAAG,CAAC;AAAA,MACtB,eAAe;AAAA,MACf,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,SAAS;AAAA,MACT,aAAa;AAAA,MACb,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,mBAAmB;AAAA,IACrB,CAAC;AACD,SAAK,SAAS;AACd,SAAK,UAAU;AACf,SAAK,QAAQ;AACb,SAAK,QAAQ;AACb,SAAK,OAAO,IAAI,MAAM;AACtB,SAAK,OAAO,gBAAgB,MAAM;AAClC,SAAK,OAAO,GAAG,iBAAiB,KAAK,WAAW;AAChD,SAAK,OAAO,GAAG,kBAAkB,KAAK,WAAW;AACjD,SAAK,OAAO,GAAG,mBAAmB,KAAK,WAAW;AAClD,SAAK,OAAO,GAAG,mBAAmB,KAAK,UAAU;AACjD,SAAK,OAAO,iBAAiB;AAC7B,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAY;AACV,QAAI,CAAC,KAAK,OAAQ;AAClB,SAAK,OAAO,IAAI,iBAAiB,KAAK,WAAW;AACjD,SAAK,OAAO,IAAI,kBAAkB,KAAK,WAAW;AAClD,SAAK,OAAO,IAAI,mBAAmB,KAAK,WAAW;AACnD,SAAK,OAAO,IAAI,mBAAmB,KAAK,UAAU;AAClD,QAAI,KAAK,OAAO,gBAAgB,MAAM,KAAK,OAAQ,MAAK,OAAO,oBAAoB;AACnF,SAAK,OAAO,OAAO,KAAK,MAAM;AAC9B,SAAK,SAAS;AACd,SAAK,UAAU;AACf,SAAK,QAAQ;AACb,SAAK,QAAQ;AACb,SAAK,OAAO,iBAAiB;AAAA,EAC/B;AAAA,EAEA,UAAgB;AACd,SAAK,IAAI;AAAA,EACX;AAAA,EAEiB,cAAc,CAAC,UAAqC;AACnE,QAAI,CAAC,KAAK,UAAU,MAAM,WAAW,KAAK,OAAQ;AAClD,SAAK,MAAM;AAAA,EACb;AAAA,EAEiB,aAAa,CAAC,UAAqC;AAClE,QAAI,CAAC,KAAK,UAAU,MAAM,WAAW,KAAK,OAAQ;AAClD,SAAK,MAAM;AAEX,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA,EAGQ,QAAc;AACpB,QAAI,CAAC,KAAK,UAAU,CAAC,KAAK,SAAS,CAAC,KAAK,MAAO;AAChD;AAAA,MACE,KAAK;AAAA,MACL,qBAAK;AAAA,QACH,qBAAK,gBAAgB,SAAS,KAAK,KAAK,CAAC;AAAA,QACzC,SAAS,KAAK,MAAM;AAAA,MACtB;AAAA,IACF;AACA,SAAK,MAAM,QAAQ;AACnB,SAAK,MAAM,IAAI,EAAE,OAAO,KAAK,CAAC;AAC9B,SAAK,OAAO,iBAAiB;AAAA,EAC/B;AACF;;;AEvHA,IAAAC,kBAAsB;;;ACAtB,IAAAC,kBAAqB;AAYd,SAAS,eAAe,QAAyC;AACtE,SAAO,OAAO,OAAO,EAAE,KAAK,CAAC,UAAU,MAAM,KAAK,UAAU;AAC9D;AAQO,SAAS,iBAAiB,QAAgB,QAA6B;AAC5E,QAAM,OAAO,IAAI,qBAAK;AAAA,IACpB,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO,OAAO,SAAS;AAAA,IACvB,QAAQ,OAAO,UAAU;AAAA,IACzB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,MAAM;AAAA,IACN,0BAA0B;AAAA;AAAA;AAAA,IAG1B,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,eAAe;AAAA,EACjB,CAAC;AACD,QAAM,QAAQ,OAAO,IAAI,QAAQ,MAAM,aAAa;AACpD,QAAM,KAAK,aAAa;AACxB,SAAO,UAAU,MAAM,IAAI,IAAI;AAC/B,SAAO;AACT;AAUO,SAAS,cAAc,QAA+B;AAC3D,QAAM,MAAM,OAAO,OAAO;AAC1B,QAAM,YAAY,IAAI,UAAU,CAAC,UAAU,MAAM,KAAK,UAAU;AAChE,MAAI,cAAc,GAAI,QAAO;AAC7B,MAAI,cAAc;AAClB,MAAI,QAAQ,CAAC,OAAO,UAAU;AAC5B,QAAI,MAAM,SAAS,OAAQ,eAAc;AAAA,EAC3C,CAAC;AACD,MAAI,aAAa,YAAa,QAAO;AACrC,SAAO,QAAQ,IAAI,SAAS,EAAE,IAAI,IAAI,SAAS,CAAC;AAChD,SAAO;AACT;AAOO,SAAS,UAAU,QAAgB,MAA2B,UAA4B;AAC/F,MAAI,CAAC,MAAM;AACT,WAAO,EAAE,MAAM,GAAG,KAAK,GAAG,OAAO,OAAO,SAAS,GAAG,QAAQ,OAAO,UAAU,EAAE;AAAA,EACjF;AACA,MAAI,UAAU;AACZ,SAAK,UAAU;AACf,UAAM,OAAO,KAAK,gBAAgB;AAClC,WAAO,EAAE,MAAM,KAAK,MAAM,KAAK,KAAK,KAAK,OAAO,KAAK,OAAO,QAAQ,KAAK,OAAO;AAAA,EAClF;AACA,QAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,SAAS,CAAC;AACzC,QAAM,SAAS,KAAK,IAAI,GAAG,KAAK,UAAU,CAAC;AAC3C,SAAO,EAAE,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAC,SAAS,GAAG,OAAO,OAAO;AAC7D;;;ACpFA,IAAAC,kBAAsB;AAYf,SAAS,aAAa,MAAoB,SAAyB,UAAyB;AACjG,QAAM,cAAc,KAAK,oBAAoB,wBAAQ,KAAK,SAAS,qBAAqB;AACxF,MAAI,aAAa,YAAa;AAC9B,aAAW,UAAU,SAAS;AAC5B,QAAI,SAAU,eAAc,QAAQ,IAAI;AAAA,QACnC,aAAY,QAAQ,IAAI;AAAA,EAC/B;AACF;AASO,SAAS,uBACd,SACA,SACA,MACA,UACkB;AAClB,SAAO,QAAQ,IAAI,CAAC,OAAO,UAAU;AACnC,UAAM,SAAS,QAAQ,KAAK;AAC5B,QAAI,YAAY,MAAM,UAAU,QAAQ;AACtC,aAAO,EAAE,GAAG,OAAO,KAAK,CAAC,GAAG,eAAe,QAAQ,IAAI,CAAC,EAAE;AAAA,IAC5D;AACA,QAAI,CAAC,MAAM,IAAK,QAAO;AACvB,UAAM,OAAO,EAAE,GAAG,MAAM;AACxB,WAAO,KAAK;AACZ,WAAO;AAAA,EACT,CAAC;AACH;AAGO,SAAS,YACd,MACA,SACA,SACA,KACA,UACM;AACN,OAAK,WAAW,iBAAiB,SAAS,SAAS,EAAE,KAAK,SAAS,CAAC;AACpE,OAAK,QAAQ;AACb,OAAK,UAAU;AACjB;;;AF5CO,IAAM,qBAAqB;AAE3B,IAAM,gBAAgB;AAAA,EAC3B,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AACX;AAqBO,IAAe,iBAAf,MAA8B;AAAA,EAInC,YACY,QACA,QACA,SACA,QACV;AAJU;AACA;AACA;AACA;AAAA,EACT;AAAA,EAJS;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAPF,WAAsD;AAAA,EACxD,UAAU;AAAA,EASlB,KAAK,QAAkC;AACrC,WAAO,KAAK,UAAU,MAAM,GAAG,KAAK,aAAa,CAAC;AAAA,EACpD;AAAA,EAEA,IAAI,QAAgB,QAA4C;AAC9D,WAAO,KAAK,KAAK,MAAM,EAAE,KAAK,CAAC,UAAU,MAAM,OAAO,MAAM;AAAA,EAC9D;AAAA;AAAA,EAGA,UAAoB;AAClB,WAAO,KAAK,OACT,OAAO,EACP,OAAO,CAAC,WAAW,MAAM,KAAK,aAAa,CAAC,GAAG,SAAS,CAAC,EACzD,IAAI,CAAC,UAAW,MAAM,KAAK,aAAa,qBAAqB,MAAM,EAAG;AAAA,EAC3E;AAAA;AAAA,EAGA,QACE,QACA,WAAW,WAAW,sBAAsB,mBAAmB,KAAK,KAAK,MAAM,CAAC,GACvE;AACT,WAAO,UAAU,KAAK,QAAQ,KAAK,KAAK,MAAM,GAAG,QAAQ;AAAA,EAC3D;AAAA;AAAA,EAGU,UAAU,QAAgB,SAAS,OAA0B;AACrE,QAAI,WAAW,mBAAoB,QAAO,KAAK,OAAO,IAAI,MAAM;AAChE,UAAM,WAAW,eAAe,KAAK,MAAM;AAC3C,QAAI,YAAY,CAAC,OAAQ,QAAO;AAChC,WAAO,iBAAiB,KAAK,QAAQ,KAAK,MAAM;AAAA,EAClD;AAAA,EAEU,KAAK,QAAgB,SAAS,OAA4B;AAClE,WAAO,KAAK,UAAU,QAAQ,MAAM,GAAG,gBAAgB;AAAA,EACzD;AAAA;AAAA,EAGU,MAAY;AACpB,QAAI,KAAK,QAAS;AAClB,SAAK,UAAU;AACf,QAAI;AACF,oBAAc,KAAK,MAAM;AAAA,IAC3B,UAAE;AACA,WAAK,UAAU;AAAA,IACjB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUU,OAAO,QAAgB,MAAoC;AACnE,UAAM,OAAO,KAAK;AAClB,QAAI,CAAC,KAAM,QAAO,CAAC;AACnB,UAAM,UAAU,KAAK,KAAK,MAAM;AAChC,QAAI,QAAQ,WAAW,KAAK,EAAE,gBAAgB,uBAAQ,QAAO,CAAC,SAAS,IAAI,CAAC;AAC5E,UAAM,WAAW,YAAY,IAAI;AAGjC,UAAM,QAAQ,SAAS,SAAS,QAAQ;AACxC,WAAO,QAAQ,IAAI,SAAS,MAAM,KAAK,IAAI;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,WAAW,QAAgB,SAA2C;AAC9E,UAAM,WAAW,KAAK,KAAK,MAAM;AACjC,QAAI,SAAS,SAAS,KAAK,QAAQ,WAAW,EAAG,QAAO,CAAC,GAAG,QAAQ;AACpE,UAAM,QAAQ,KAAK,UAAU,MAAM;AACnC,UAAM,SAAS,OAAO,KAAK;AAC3B,QAAI,OAAO;AAGT,aAAO,MAAM,KAAK;AAAA,IACpB;AACA,WAAO;AAAA,MACL;AAAA,QACE,GAAG;AAAA,QACH,IAAI,WAAW;AAAA,QACf,MAAM,OAAO,WAAW,WAAW,SAAS;AAAA,QAC5C,QAAQ,WAAW,qBAAqB,QAAQ,CAAC,QAAQ,CAAC,EAAE;AAAA,MAC9D;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMU,OACR,QACA,MACA,SACA,SACA,OAAO,MAEP,gBAAgB,OACV;AACN,UAAM,QAAQ,KAAK,UAAU,MAAM;AACnC,QAAI,CAAC,MAAO;AACZ,UAAM,WAAW,iBAAiB,WAAW,sBAAsB,mBAAmB,OAAO;AAE7F,iBAAa,MAAM,SAAS,QAAQ;AACpC,UAAM,OAAO,uBAAuB,SAAS,SAAS,MAAM,QAAQ;AACpE,gBAAY,MAAM,MAAM,SAAS,KAAK,QAAQ,QAAQ,QAAQ,GAAG,QAAQ;AAEzE,QAAI,KAAK,WAAW,GAAG;AACrB,aAAO,MAAM,KAAK;AAElB,UAAI,MAAM,KAAK,WAAY,MAAK,OAAO,OAAO,MAAM,EAAE;AAAA,IACxD,OAAO;AACL,YAAM,KAAK,YAAY;AAAA,IACzB;AAEA,SAAK,OAAO,iBAAiB;AAC7B,SAAK,OAAO,KAAK,iBAAiB,EAAE,OAAO,CAAC;AAC5C,SAAK,OAAO,KAAK,kBAAkB,EAAE,SAAS,MAAM,GAAG,CAAC;AACxD,QAAI,KAAM,MAAK,QAAQ,KAAK;AAAA,EAC9B;AACF;;;AJhJO,IAAM,mBAAN,cAA+B,eAAe;AAAA;AAAA;AAAA,EAGlC,QAAQ,IAAI,mBAAmB,KAAK,QAAQ,MAAM,KAAK,QAAQ,KAAK,CAAC;AAAA,EACrE,kBAAkB,MAAM,KAAK,IAAI;AAAA;AAAA;AAAA,EAGjC,kBAAkB,MAAM;AACvC,QAAI,KAAK,SAAU,MAAK,OAAO,MAAM,IAAI;AAAA,EAC3C;AAAA,EACiB,mBAAmB,CAAC,UAAqC;AACxE,UAAM,SAAS,MAAM;AACrB,QAAI,CAAC,OAAQ;AACb,UAAM,QAAQ,KAAK,OAAO,aAAa,MAAM;AAC7C,QAAI,MAAO,MAAK,OAAO,MAAM,EAAE;AAAA,EACjC;AAAA,EAEA,YACE,QACA,QACA,SACA,QACA;AACA,UAAM,QAAQ,QAAQ,SAAS,MAAM;AACrC,SAAK,OAAO,GAAG,kBAAkB,KAAK,eAAe;AACrD,SAAK,OAAO,GAAG,kBAAkB,KAAK,eAAe;AAGrD,SAAK,OAAO,GAAG,mBAAmB,KAAK,gBAAgB;AAAA,EACzD;AAAA,EAEA,UAAgB;AACd,SAAK,MAAM,QAAQ;AACnB,SAAK,OAAO,IAAI,kBAAkB,KAAK,eAAe;AACtD,SAAK,OAAO,IAAI,kBAAkB,KAAK,eAAe;AACtD,SAAK,OAAO,IAAI,mBAAmB,KAAK,gBAAgB;AACxD,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA;AAAA,EAKA,UAAiC;AAC/B,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,UAAU,QAAgB,QAAkC;AAChE,UAAM,OAAO,KAAK,KAAK,MAAM;AAC7B,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,UAAU,KAAK,KAAK,MAAM;AAChC,UAAM,QAAQ,QAAQ,UAAU,CAAC,UAAU,MAAM,OAAO,MAAM;AAC9D,QAAI,UAAU,GAAI,QAAO;AAEzB,SAAK,QAAQ,KAAK;AAClB,SAAK,OAAO,QAAQ,MAAM,CAAC,GAAG,OAAO,GAAG,KAAK,OAAO,QAAQ,IAAI,GAAG,OAAO,IAAI;AAC9E,UAAM,QAAQ,KAAK,oBAAoB,wBAAQ,KAAK,WAAW;AAC/D,QAAI,CAAC,MAAO,QAAO;AACnB,UAAM,WAAW,MAAM,WAAW;AAElC,UAAM,QAAQ,SAAS,SAAS,SAAS,QAAQ,SAAS,KAAK;AAC/D,QAAI,CAAC,MAAO,QAAO;AAEnB,SAAK,OAAO,QAAQ,MAAM;AAC1B,WAAO,KAAK,MAAM,MAAM,EAAE,QAAQ,OAAO,GAAG,OAAO,KAAK;AAAA,EAC1D;AAAA;AAAA,EAGA,QAAQ,OAAO,MAAY;AACzB,UAAM,UAAU,KAAK,MAAM,OAAO;AAClC,SAAK,MAAM,IAAI;AACf,QAAI,QAAS,MAAK,QAAQ,QAAQ,QAAQ,IAAI;AAAA,EAChD;AAAA;AAAA,EAIA,cAAyD;AACvD,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,OAAO,QAAuB,QAA6B;AACzD,SAAK,WAAW,UAAU,SAAS,EAAE,QAAQ,OAAO,IAAI;AACxD,SAAK,OAAO,KAAK,iBAAiB,EAAE,QAAQ,QAAQ,KAAK,WAAW,SAAS,KAAK,CAAC;AAAA,EACrF;AAAA;AAAA,EAIA,IAAI,QAAgB,QAAsB,UAA0B,CAAC,GAA0B;AAC7F,UAAM,OAAO,KAAK,KAAK,QAAQ,IAAI;AACnC,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,UAAU,KAAK,OAAO,QAAQ,IAAI;AACxC,UAAM,UAAU,KAAK,WAAW,QAAQ,OAAO;AAC/C,UAAM,QAAwB;AAAA,MAC5B,GAAG;AAAA,MACH,IAAI,WAAW;AAAA,MACf,MAAM,QAAQ,QAAQ;AAAA,MACtB,GAAI,QAAQ,OAAO,EAAE,MAAM,QAAQ,KAAK,IAAI,CAAC;AAAA,MAC7C,GAAI,QAAQ,WAAW,SAAY,CAAC,IAAI,EAAE,QAAQ,QAAQ,OAAO;AAAA,MACjE,GAAI,QAAQ,OAAO,EAAE,MAAM,QAAQ,KAAK,IAAI,CAAC;AAAA,IAC/C;AAGA,QAAI,WAAW,mBAAoB,OAAM,SAAS;AAElD,QAAI,QAAQ,QAAQ,OAAO;AACzB,eAAS,QAAQ,QAAQ,OAAO,KAAK,QAAQ,MAAM,GAAG,QAAQ,OAAO,CAAC;AAAA,IACxE;AACA,YAAQ,KAAK,MAAM;AACnB,YAAQ,KAAK,KAAK;AAClB,SAAK,OAAO,QAAQ,MAAM,SAAS,OAAO;AAC1C,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,gBACE,QACA,QACA,QACA,UAA0B,CAAC,GAClB;AACT,UAAM,OAAO,KAAK,KAAK,MAAM;AAC7B,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,UAAU,CAAC,GAAG,KAAK,KAAK,MAAM,CAAC;AACrC,UAAM,QAAQ,QAAQ,UAAU,CAAC,UAAU,MAAM,OAAO,MAAM;AAC9D,QAAI,UAAU,GAAI,QAAO;AACzB,UAAM,UAAU,KAAK,OAAO,QAAQ,IAAI;AACxC,QAAI,QAAQ,QAAQ,OAAO;AACzB,eAAS,QAAQ,QAAQ,OAAO,KAAK,QAAQ,MAAM,GAAG,QAAQ,OAAO,CAAC;AAAA,IACxE;AACA,YAAQ,KAAK,IAAI;AACjB,YAAQ,KAAK,IAAI;AAAA,MACf,GAAG,QAAQ,KAAK;AAAA,MAChB,GAAI,QAAQ,OAAO,EAAE,MAAM,QAAQ,KAAK,IAAI,CAAC;AAAA,MAC7C,GAAI,QAAQ,OAAO,EAAE,MAAM,QAAQ,KAAK,IAAI,CAAC;AAAA,IAC/C;AACA,SAAK,OAAO,QAAQ,MAAM,SAAS,OAAO;AAC1C,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MACE,QACA,QACA,UAA2D,CAAC,GACnD;AACT,UAAM,OAAO,KAAK,KAAK,MAAM;AAC7B,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,UAAU,CAAC,GAAG,KAAK,KAAK,MAAM,CAAC;AACrC,UAAM,QAAQ,QAAQ,UAAU,CAAC,UAAU,MAAM,OAAO,MAAM;AAC9D,QAAI,UAAU,GAAI,QAAO;AACzB,UAAM,UAAU,KAAK,OAAO,QAAQ,IAAI;AACxC,UAAM,SAAS,QAAQ,KAAK;AAC5B,QAAI,CAAC,OAAQ,QAAO;AACpB,aAAS,QAAQ,QAAQ,OAAO,KAAK,QAAQ,MAAM,GAAG,QAAQ,OAAO,CAAC;AACtE,SAAK,OAAO,QAAQ,MAAM,SAAS,SAAS,QAAQ,QAAQ,IAAI;AAChE,WAAO;AAAA,EACT;AAAA,EAEA,OAAO,QAAgB,QAAyB;AAC9C,UAAM,OAAO,KAAK,KAAK,MAAM;AAC7B,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,UAAU,CAAC,GAAG,KAAK,KAAK,MAAM,CAAC;AACrC,UAAM,QAAQ,QAAQ,UAAU,CAAC,UAAU,MAAM,OAAO,MAAM;AAC9D,QAAI,UAAU,GAAI,QAAO;AACzB,UAAM,UAAU,KAAK,OAAO,QAAQ,IAAI;AACxC,YAAQ,OAAO,OAAO,CAAC;AACvB,YAAQ,OAAO,OAAO,CAAC;AACvB,QAAI,KAAK,UAAU,WAAW,OAAQ,MAAK,OAAO,MAAM,IAAI;AAC5D,SAAK,OAAO,QAAQ,MAAM,SAAS,OAAO;AAC1C,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAyB;AAC7B,UAAM,OAAO,KAAK,KAAK,MAAM;AAC7B,QAAI,CAAC,KAAM,QAAO;AAClB,QAAI,KAAK,KAAK,MAAM,EAAE,WAAW,EAAG,QAAO;AAC3C,QAAI,KAAK,UAAU,WAAW,OAAQ,MAAK,OAAO,MAAM,IAAI;AAC5D,SAAK,OAAO,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC;AAChC,WAAO;AAAA,EACT;AAAA,EAEA,QAAQ,QAAgB,QAAgB,OAAwB;AAC9D,UAAM,OAAO,KAAK,KAAK,MAAM;AAC7B,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,UAAU,CAAC,GAAG,KAAK,KAAK,MAAM,CAAC;AACrC,UAAM,OAAO,QAAQ,UAAU,CAACC,WAAUA,OAAM,OAAO,MAAM;AAC7D,QAAI,SAAS,GAAI,QAAO;AACxB,UAAM,KAAK,KAAK,IAAI,GAAG,KAAK,IAAI,QAAQ,SAAS,GAAG,KAAK,MAAM,KAAK,CAAC,CAAC;AACtE,QAAI,SAAS,GAAI,QAAO;AACxB,UAAM,UAAU,KAAK,OAAO,QAAQ,IAAI;AACxC,UAAM,CAAC,KAAK,IAAI,QAAQ,OAAO,MAAM,CAAC;AACtC,UAAM,CAAC,MAAM,IAAI,QAAQ,OAAO,MAAM,CAAC;AACvC,YAAQ,OAAO,IAAI,GAAG,KAAK;AAC3B,YAAQ,OAAO,IAAI,GAAG,MAAM;AAC5B,SAAK,OAAO,QAAQ,MAAM,SAAS,OAAO;AAC1C,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,QAAQ,QAAgB,QAAgB,MAAwC;AAC9E,WAAO,KAAK,MAAM,QAAQ,QAAQ,OAAO,EAAE,KAAK,EAAE;AAAA,EACpD;AAAA,EAEA,QAAQ,QAAgB,QAAgB,MAA8B;AACpE,WAAO,KAAK,MAAM,QAAQ,QAAQ,CAAC,UAAW,MAAM,SAAS,OAAO,OAAO,EAAE,KAAK,CAAE;AAAA,EACtF;AAAA,EAEA,WAAW,QAAgB,QAAgB,SAA2B;AACpE,WAAO,KAAK,MAAM,QAAQ,QAAQ,CAAC,UAAW,MAAM,YAAY,UAAU,OAAO,EAAE,QAAQ,CAAE;AAAA,EAC/F;AAAA,EAEA,WAAW,QAAgB,QAAgB,SAA0B;AACnE,QAAI,CAAC,OAAO,SAAS,OAAO,EAAG,QAAO;AACtC,UAAM,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC;AAC7C,WAAO,KAAK;AAAA,MAAM;AAAA,MAAQ;AAAA,MAAQ,CAAC,UACjC,MAAM,YAAY,OAAO,OAAO,EAAE,SAAS,KAAK;AAAA,IAClD;AAAA,EACF;AAAA,EAEA,QAAQ,QAAgB,QAAgB,MAAuB;AAC7D,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,CAAC,QAAS,QAAO;AACrB,WAAO,KAAK;AAAA,MAAM;AAAA,MAAQ;AAAA,MAAQ,CAAC,UACjC,MAAM,SAAS,UAAU,OAAO,EAAE,MAAM,QAAQ;AAAA,IAClD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,UAAU,QAAgB,QAAgB,QAA0B;AAClE,QAAI,WAAW,mBAAoB,QAAO;AAC1C,UAAM,OAAO,KAAK,KAAK,MAAM;AAC7B,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,UAAU,CAAC,GAAG,KAAK,KAAK,MAAM,CAAC;AACrC,UAAM,QAAQ,QAAQ,UAAU,CAAC,UAAU,MAAM,OAAO,MAAM;AAC9D,QAAI,UAAU,MAAM,QAAQ,KAAK,EAAE,WAAW,OAAQ,QAAO;AAC7D,UAAM,UAAU,KAAK,OAAO,QAAQ,IAAI;AACxC,YAAQ,KAAK,IAAI,EAAE,GAAG,QAAQ,KAAK,GAAG,OAAO;AAC7C,SAAK,OAAO,QAAQ,MAAM,SAAS,OAAO;AAC1C,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAa,SAAiB,QAAmE;AAC/F,UAAM,QAAQ,KAAK,OAAO,IAAI,OAAO;AACrC,QAAI,CAAC,SAAS,MAAM,KAAK,WAAY,QAAO;AAC5C,UAAM,UAAU,KAAK,OAAO,OAAO;AACnC,UAAM,QAAQ,QAAQ,UAAU,CAAC,cAAc,UAAU,OAAO,OAAO;AACvE,UAAM,QAAQ,QAAQ,IAAI,QAAQ,QAAQ,CAAC,IAAI;AAC/C,UAAM,WAAW,WAAW,SAAS,CAAC,MAAM,KAAK,aAAa,MAAM,KAAK;AACzE,QAAI,aAAa,QAAS,QAAO;AAEjC,UAAM,SAAS,MAAM;AAGrB,QAAI,CAAC,OAAO,QAAQ,OAAO,SAAS,QAAS,QAAO,IAAI,EAAE,MAAM,UAAU,CAAC;AAI3E,SAAK,QAAQ,iBAAiB;AAC9B,QAAI;AAIF,UAAI,KAAK,OAAO,gBAAgB,MAAM,OAAQ,MAAK,OAAO,oBAAoB;AAC9E,WAAK,OAAO,OAAO,MAAM;AACzB,WAAK,OAAO,OAAO,OAAO;AAC1B,YAAM,QAAQ,KAAK,IAAI,UAAU,QAAQ,EAAE,MAAM,MAAM,MAAM,KAAK,MAAM,CAAC;AACzE,aAAO,QAAQ,EAAE,QAAQ,UAAU,MAAM,IAAI;AAAA,IAC/C,UAAE;AACA,WAAK,QAAQ,eAAe;AAAA,IAC9B;AAAA,EACF;AAAA;AAAA;AAAA,EAKA,QAAQ,QAAgB,OAAO,OAAa;AAC1C,UAAM,OAAO,KAAK,KAAK,MAAM;AAC7B,QAAI,CAAC,KAAM;AACX,UAAM,UAAU,KAAK,OAAO,QAAQ,IAAI;AACxC,QAAI,QAAQ,WAAW,EAAG;AAC1B,SAAK,OAAO,QAAQ,MAAM,KAAK,WAAW,QAAQ,OAAO,GAAG,SAAS,IAAI;AAAA,EAC3E;AAAA;AAAA,EAGQ,OAAO,QAAsB;AACnC,UAAM,OAAO,KAAK,KAAK,MAAM;AAC7B,QAAI,CAAC,KAAM;AACX,UAAM,UAAU,KAAK,KAAK,MAAM;AAChC,QAAI,QAAQ,WAAW,KAAK,CAAC,mBAAmB,OAAO,EAAG;AAC1D,QAAI,CAAC,QAAQ,KAAK,CAAC,UAAU,MAAM,UAAU,MAAM,GAAG,EAAG;AACzD,UAAM,UAAU,KAAK,OAAO,QAAQ,IAAI;AACxC,YAAQ,QAAQ,CAAC,OAAO,UAAU;AAChC,YAAM,SAAS,QAAQ,KAAK;AAC5B,YAAM,MAAM,SAAS,MAAM,GAAG;AAC9B,UAAI,CAAC,UAAU,CAAC,MAAM,UAAU,CAAC,IAAK;AACtC,0BAAoB,QAAQ,MAAM,GAAG;AAAA,IACvC,CAAC;AACD,SAAK,OAAO,QAAQ,MAAM,CAAC,GAAG,OAAO,GAAG,OAAO;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,QAAgB,MAAsC;AAC1D,UAAM,QAAQ,KAAK,UAAU,MAAM;AACnC,UAAM,OAAO,OAAO,aAAa;AAGjC,QAAI,CAAC,SAAS,CAAC,QAAQ,MAAM,KAAK,QAAS,QAAO;AAClD,SAAK,MAAM,KAAK,aAAa,CAAC,GAAG,SAAS,EAAG,QAAO;AACpD,UAAM,QAAwB;AAAA,MAC5B,GAAG;AAAA,MACH,IAAI,WAAW;AAAA,MACf,MAAM,QAAQ;AAAA,MACd,QAAQ,WAAW,qBAAqB,QAAQ,CAAC,KAAK;AAAA,IACxD;AACA,UAAM,KAAK,YAAY,CAAC,KAAK;AAC7B,WAAO,MAAM,KAAK;AAClB,SAAK,QAAQ,MAAM;AACnB,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,aAAmB;AACjB,SAAK,WAAW;AAChB,SAAK,IAAI;AACT,eAAW,SAAS,KAAK,OAAO,OAAO,GAAG;AACxC,WAAK,MAAM,KAAK,aAAa,CAAC,GAAG,WAAW,EAAG;AAC/C,WAAK,QAAQ,MAAM,KAAK,aAAa,qBAAqB,MAAM,EAAE;AAAA,IACpE;AAAA,EACF;AAAA;AAAA,EAIQ,MACN,QACA,QACA,QACS;AACT,UAAM,OAAO,KAAK,KAAK,MAAM;AAC7B,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,UAAU,CAAC,GAAG,KAAK,KAAK,MAAM,CAAC;AACrC,UAAM,QAAQ,QAAQ,UAAU,CAAC,UAAU,MAAM,OAAO,MAAM;AAC9D,QAAI,UAAU,GAAI,QAAO;AACzB,UAAM,QAAQ,OAAO,QAAQ,KAAK,CAAC;AACnC,QAAI,CAAC,MAAO,QAAO;AACnB,UAAM,UAAU,KAAK,OAAO,QAAQ,IAAI;AACxC,YAAQ,KAAK,IAAI,EAAE,GAAG,QAAQ,KAAK,GAAG,GAAG,MAAM;AAC/C,SAAK,OAAO,QAAQ,MAAM,SAAS,OAAO;AAC1C,WAAO;AAAA,EACT;AACF;;;A9BpVA,IAAM,WAAW;AACjB,IAAM,WAAW;AAEjB,SAAS,qBAAqB,OAAyB;AACrD,SACG,iBAAiB,gBAAgB,MAAM,SAAS,mBAChD,iBAAiB,SAAS,+BAA+B,KAAK,MAAM,OAAO;AAEhF;AAEO,IAAM,eAAN,MAAmB;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAED;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,iBAAiC,EAAE,GAAG,wBAAwB;AAAA,EAC9D,SAA8B;AAAA;AAAA;AAAA;AAAA,EAI9B;AAAA,EACA,wBAA6C;AAAA,EAC7C,yBAAkE;AAAA,EAE1E,YAAY,eAAkC,QAAsB;AAClE,SAAK,SAAS,IAAI,aAA2B;AAC7C,SAAK,QAAQ,IAAI,aAAa;AAC9B,WAAO,OAAO,QAAQ,CAAC,SAAS,KAAK,MAAM,SAAS,IAAI,CAAC;AACzD,SAAK,YAAY,IAAI,eAAe,OAAO,OAAO;AAClD,SAAK,QAAQ,IAAI,cAAc,OAAO,QAAQ,MAAM,OAAO,OAAO,EAAE;AAEpE,UAAM,UAAU,KAAK,MAAM,SAAS,OAAO,KAAK;AAChD,UAAM,WAAW,KAAK,MAAM,SAAS,OAAO,MAAM;AAClD,SAAK,mBAAmB,OAAO,mBAAmB;AAElD,SAAK,SAAS,IAAI,uBAAO,eAAe;AAAA,MACtC,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,iBAAiB,KAAK;AAAA,MACtB,wBAAwB,OAAO,0BAA0B;AAAA,MACzD,WAAW;AAAA,IACb,CAAC;AAED,SAAK,SAAS,IAAI,aAAa,KAAK,QAAQ,KAAK,MAAM;AACvD,SAAK,cAAc,OAAO;AAC1B,SAAK,gBAAgB,OAAO;AAE5B,SAAK,UAAU,IAAI,eAAe;AAAA,MAChC,UAAU,MAAM,KAAK,UAAU,KAAK,OAAO,CAAC;AAAA,MAC5C,cAAc,OAAO,UAAkB;AACrC,cAAM,SAAS,KAAK,MAAM,KAAK;AAC/B,cAAM,KAAK,SAAS,MAAM;AAAA,MAC5B;AAAA,MACA,QAAQ,KAAK;AAAA,IACf,CAAC;AACD,SAAK,OAAO,mBAAmB,MAAM,KAAK,QAAQ,KAAK,CAAC;AAExD,SAAK,WAAW,IAAI,YAAY,KAAK,QAAQ,KAAK,MAAM;AACxD,SAAK,OAAO,IAAI,eAAe,KAAK,QAAQ,KAAK,SAAS,KAAK,MAAM;AACrE,SAAK,WAAW,IAAI,eAAe,KAAK,QAAQ,KAAK,QAAQ,KAAK,SAAS,KAAK,MAAM;AACtF,SAAK,SAAS,IAAI,iBAAiB,KAAK,QAAQ,KAAK,QAAQ,KAAK,SAAS,KAAK,MAAM;AACtF,SAAK,cAAc,IAAI,kBAAkB,KAAK,QAAQ,KAAK,QAAQ,KAAK,SAAS,KAAK,MAAM;AAC5F,SAAK,aAAa,IAAI,iBAAiB,KAAK,QAAQ,KAAK,QAAQ,KAAK,SAAS,KAAK,MAAM;AAE1F,SAAK,kBAAkB;AACvB,SAAK,sBAAsB;AAC3B,SAAK,QAAQ,cAAc;AAC3B,SAAK,QAAQ,IAAI,eAAe,IAAI;AACpC,SAAK,QAAQ,IAAI,eAAe,IAAI;AAAA,EACtC;AAAA;AAAA,EAIA,MAAM,SAAS,KAAa,SAA4D;AAMtF,QAAI;AACF,YAAM,MAAM,MAAM,4BAAY;AAAA,QAC5B;AAAA,QACA,CAAC;AAAA,QACD,EAAE,SAAS,QAAQ,SAAS,OAAO,GAAG,QAAQ;AAAA,MAChD;AACA,YAAM,QAAQ,KAAK,OAAO,IAAI,SAAS,GAAG;AAG1C,WAAK,OAAO,OAAO,MAAM,EAAE;AAC3B,WAAK,QAAQ,KAAK;AAClB,aAAO;AAAA,IACT,SAAS,OAAO;AACd,WAAK,OAAO,KAAK,SAAS,EAAE,SAAS,uBAAuB,MAAM,CAAC;AACnE,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,mBAAmB,SAAiB,KAA6B;AACrE,UAAM,QAAQ,KAAK,OAAO,IAAI,OAAO;AACrC,QAAI,CAAC,SAAU,MAAM,SAAS,WAAW,MAAM,SAAS,QAAS;AAC/D,YAAM,IAAI,MAAM,kCAAkC,OAAO,EAAE;AAAA,IAC7D;AACA,QAAI,MAAM,KAAK,SAAS;AACtB,YAAM,IAAI,MAAM,qDAAqD;AAAA,IACvE;AACA,QAAI,KAAK,KAAK,cAAc,MAAM,QAAS,MAAK,KAAK,OAAO;AAC5D,UAAM,WAAW,MAAM;AACvB,QAAI;AACF,YAAM,cAAc,MAAM,4BAAY,QAAQ,KAAK,CAAC,GAAG,EAAE,SAAS,QAAQ,SAAS,MAAM,CAAC;AAC1F,kBAAY,IAAI;AAAA,QACd,MAAM,SAAS;AAAA,QACf,KAAK,SAAS;AAAA,QACd,SAAS,SAAS;AAAA,QAClB,SAAS,SAAS;AAAA,QAClB,OAAO,SAAS;AAAA,QAChB,QAAQ,SAAS;AAAA,QACjB,OAAO,SAAS;AAAA,QAChB,OAAO,SAAS;AAAA,QAChB,QAAQ,SAAS;AAAA,QACjB,QAAQ,SAAS;AAAA,QACjB,OAAO,SAAS;AAAA,QAChB,OAAO,SAAS;AAAA,QAChB,OAAO,SAAS;AAAA,QAChB,OAAO,SAAS;AAAA,QAChB,OAAO,SAAS;AAAA,MAClB,CAAC;AACD,kBAAY,UAAU,CAAC,GAAG,SAAS,OAAO;AAC1C,kBAAY,aAAa;AACzB,kBAAY,UAAU;AACtB,WAAK,OAAO,cAAc,SAAS,WAAW;AAC9C,aAAO;AAAA,IACT,SAAS,OAAO;AACd,WAAK,OAAO,KAAK,SAAS,EAAE,SAAS,kCAAkC,MAAM,CAAC;AAC9E,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,QAAQ,MAAc,SAAmD;AACvE,UAAM,UAAU,IAAI,wBAAQ,MAAM;AAAA,MAChC,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,MAAM;AAAA,MACN,OAAO;AAAA;AAAA,MAEP,SAAS;AAAA,MACT,SAAS;AAAA,MACT,GAAG;AAAA,IACL,CAAC;AACD,UAAM,QAAQ,KAAK,OAAO,IAAI,QAAQ,OAAkC;AACxE,SAAK,OAAO,OAAO,MAAM,EAAE;AAC3B,SAAK,QAAQ,KAAK;AAClB,WAAO;AAAA,EACT;AAAA,EAEA,SAAS,QAAqB,SAA0C;AACtE,UAAM,MAAM,OAAO,OAAO,OAAO;AACjC,UAAM,QAAQ,KAAK,OAAO,IAAI,SAAS,KAAK,OAAO,IAAI;AACvD,SAAK,OAAO,OAAO,MAAM,EAAE;AAC3B,SAAK,QAAQ,KAAK;AAClB,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,YACJ,UACA,QACgB;AAChB,UAAM,SAA0C,CAAC;AACjD,eAAW,aAAa,SAAS,YAAY;AAC3C,YAAM,QAAQ,OAAO,UAAU,GAAG,KAAK,UAAU;AACjD,UAAI,UAAU,OAAW,OAAM,IAAI,MAAM,+BAA+B,UAAU,GAAG,EAAE;AACvF,UAAI,UAAU,SAAS,YAAY,CAAC,OAAO,SAAS,OAAO,KAAK,CAAC,GAAG;AAClE,cAAM,IAAI,MAAM,0CAA0C,UAAU,GAAG,EAAE;AAAA,MAC3E;AACA,UAAI,UAAU,SAAS,WAAW,CAAC,WAAW,KAAK,GAAG;AACpD,cAAM,IAAI,MAAM,yCAAyC,UAAU,GAAG,EAAE;AAAA,MAC1E;AACA,aAAO,UAAU,GAAG,IAAI;AAAA,IAC1B;AACA,UAAM,WAAW;AAAA,MACf,SAAS,IAAI,QAAQ,kCAAkC,CAAC,OAAO,KAAa,aAAa;AACvF,cAAM,QAAQ,OAAO,GAAG,KAAK;AAC7B,eAAO,UAAU,SAAY,QAAQ,UAAU,KAAK;AAAA,MACtD,CAAC;AAAA,IACH;AAKA,UAAM,QAAQ,SAAS,SAAS,WAAW,IACvC,CAAC,aAAa,UAAU,MAAM,CAAC,IAC/B,MAAM,mBAAmB,UAAU,UAAU,MAAM;AACvD,QAAI,MAAM,WAAW,EAAG,OAAM,IAAI,MAAM,6CAA6C;AAIrF,WAAO,KAAK,QAAQ,YAAY,YAAY;AAC1C,YAAM,UAAU,MAAM,IAAI,CAAC,SAAS;AAClC,cAAMC,SAAQ,KAAK,OAAO,IAAI,KAAK,MAAM,KAAK,QAAQ,KAAK,IAAI;AAE/D,YAAI,KAAK,MAAO,MAAK,OAAO,MAAMA,OAAM,IAAI,KAAK,OAAO,KAAK;AAC7D,eAAOA;AAAA,MACT,CAAC;AAGD,YAAM,QACJ,QAAQ,WAAW,IACf,QAAQ,CAAC,IACP,MAAM,KAAK;AAAA,QACX,QAAQ,IAAI,CAAC,MAAM,EAAE,EAAE;AAAA,QACvB,SAAS;AAAA,MACX,KAAM,QAAQ,CAAC;AAErB,YAAM,aAAa,IAAI;AAAA,QACrB,MAAM,KAAK,OAAO,SAAS,IAAI;AAAA,QAC/B,KAAK,KAAK,OAAO,UAAU,IAAI;AAAA,QAC/B,SAAS;AAAA,QACT,SAAS;AAAA,MACX,CAAC;AACD,YAAM,aAAa,UAAU;AAC7B,WAAK,OAAO,OAAO,MAAM,EAAE;AAC3B,WAAK,OAAO,iBAAiB;AAC7B,WAAK,QAAQ,KAAK;AAClB,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAAA,EAEA,YAAY,IAAkB;AAC5B,QAAI,KAAK,KAAK,cAAc,MAAM,GAAI,MAAK,KAAK,OAAO;AACvD,QAAI,KAAK,MAAM,cAAc,MAAM,IAAI;AACrC,WAAK,MAAM,OAAO,EAAE;AAAA,IACtB;AACA,QAAI,KAAK,OAAO,OAAO,EAAE,EAAG,MAAK,QAAQ,KAAK;AAAA,EAChD;AAAA,EAEA,YAAY,IAAyB;AACnC,SAAK,OAAO,OAAO,EAAE;AAAA,EACvB;AAAA;AAAA,EAGA,aAAa,KAAqB;AAChC,SAAK,OAAO,WAAW,GAAG;AAAA,EAC5B;AAAA,EAEA,mBAAiC;AAC/B,UAAM,SAAS,KAAK,OAAO,gBAAgB;AAC3C,QAAI,CAAC,OAAQ,QAAO;AACpB,WAAO,KAAK,OAAO,aAAa,MAAM,KAAK;AAAA,EAC7C;AAAA;AAAA,EAGA,UAAU,IAAY,MAAuC;AAC3D,UAAM,QAAQ,KAAK,OAAO,IAAI,EAAE;AAChC,QAAI,CAAC,MAAO;AACZ,UAAM,MAAM,MAAM;AAClB,QAAI,SAAS,cAAc;AACzB,UAAI,IAAI,SAAS,CAAC,IAAI,KAAK;AAAA,IAC7B,OAAO;AACL,UAAI,IAAI,SAAS,CAAC,IAAI,KAAK;AAAA,IAC7B;AACA,QAAI,UAAU;AACd,SAAK,OAAO,iBAAiB;AAC7B,SAAK,QAAQ,KAAK;AAAA,EACpB;AAAA;AAAA,EAGA,MAAM,eAAe,IAAmC;AACtD,UAAM,QAAQ,KAAK,OAAO,IAAI,EAAE;AAChC,QAAI,CAAC,MAAO,QAAO;AAEnB,UAAM,QAAQ,MAAM,MAAM,aAAa,MAAM;AAC7C,UAAM,IAAI,EAAE,OAAO,MAAM,QAAQ,KAAK,IAAI,MAAM,MAAM,OAAO,KAAK,GAAG,CAAC;AACtE,UAAM,UAAU;AAEhB,UAAM,OAAO,KAAK,OAAO,IAAI,MAAM,MAAM,OAAO,GAAG,MAAM,IAAI,OAAO;AAEpE,SAAK,OAAO,gBAAgB,MAAM,IAAI;AACtC,SAAK,UAAU,MAAM;AACrB,SAAK,SAAS,MAAM;AACpB,SAAK,UAAU,MAAM;AACrB,UAAM,IAAI;AAAA,MACR,SAAS,MAAM;AAAA,MACf,YAAY,CAAC,MAAM;AAAA,MACnB,SAAS,CAAC,MAAM;AAAA,MAChB,SAAS,MAAM;AAAA,IACjB,CAAC;AAGD,SAAK,SAAS,SAAS,IAAI;AAK3B,SAAK,OAAO,OAAO,KAAK,EAAE;AAC1B,SAAK,OAAO,iBAAiB;AAC7B,SAAK,QAAQ,KAAK;AAClB,WAAO;AAAA,EACT;AAAA,EAEA,sBAAsB,SAAiB,aAAwC;AAC7E,UAAM,QAAQ,KAAK,OAAO,IAAI,OAAO;AACrC,QAAI,CAAC,SAAS,MAAM,SAAS,QAAS,QAAO;AAC7C,UAAM,QAAQ,MAAM;AACpB,UAAM,WAAY,MAAM,KAAK,oBAAoB,CAAC;AAClD,UAAM,OAAO,EAAE,GAAG,UAAU,GAAG,YAAY;AAC3C,UAAM,kBAAkB,CAAC,OAA2B,MAAM,OAAO,MAAM,SAAS,GAAG,KAAK,CAAC;AACzF,UAAM,UAAU;AAAA,MACd,IAAI,wBAAQ,WAAW,EAAE,YAAY,gBAAgB,KAAK,UAAU,EAAE,CAAC;AAAA,MACvE,IAAI,wBAAQ,SAAS,EAAE,UAAU,gBAAgB,KAAK,QAAQ,EAAE,CAAC;AAAA,MACjE,IAAI,wBAAQ,WAAW,EAAE,YAAY,gBAAgB,KAAK,UAAU,EAAE,CAAC;AAAA,MACvE,IAAI,wBAAQ,KAAK,EAAE,MAAM,gBAAgB,KAAK,MAAM,CAAC,EAAE,CAAC;AAAA,IAC1D;AACA,UAAM,KAAK,mBAAmB;AAC9B,UAAM,aAAa;AACnB,SAAK,OAAO,iBAAiB;AAC7B,SAAK,QAAQ,KAAK;AAClB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,YAAY,KAAe,OAAO,SAAgC;AACtE,UAAM,YAAY,CAAC,GAAG,IAAI,IAAI,GAAG,CAAC;AAClC,UAAM,SAAS,UACZ,IAAI,CAAC,OAAO,KAAK,OAAO,IAAI,EAAE,CAAC,EAC/B,OAAO,CAAC,UAA0B,UAAU,UAAa,MAAM,aAAa,IAAI;AACnF,QAAI,OAAO,SAAS,KAAK,OAAO,WAAW,UAAU,OAAQ,QAAO;AAKpE,UAAM,QAAQ,KAAK,OAAO,OAAO;AACjC,UAAM,WAAW,KAAK,IAAI,GAAG,OAAO,IAAI,CAAC,UAAU,MAAM,QAAQ,KAAK,CAAC,CAAC;AACxE,UAAM,cAAc,MAAM,MAAM,GAAG,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,SAAS,KAAK,CAAC,EAAE;AAExF,WAAO,KAAK,QAAQ,YAAY,MAAM;AACpC,YAAM,WAAoB,CAAC;AAC3B,YAAM,UAA0B,CAAC;AACjC,iBAAW,SAAS,QAAQ;AAC1B,YAAI,MAAM,SAAS,WAAW,MAAM,SAAS,SAAS,GAAG;AAGvD,gBAAM,QAAS,MAAM,aAAuB,UAAU;AACtD,qBAAW,CAAC,OAAO,MAAM,KAAK,MAAM,QAAQ,GAAG;AAC7C,mBAAO,UAAU;AACjB,kBAAM,QAAQ,MAAM,SAAS,KAAK;AAClC,gBAAI,CAAC,MAAO;AACZ,qBAAS,KAAK,KAAK;AACnB,oBAAQ,KAAK,MAAM;AAAA,UACrB;AACA,gBAAM,WAAW,CAAC;AAClB,eAAK,OAAO,OAAO,MAAM,EAAE;AAAA,QAC7B,OAAO;AACL,mBAAS,KAAK,KAAK;AACnB,kBAAQ,KAAK,MAAM,YAAY;AAC/B,eAAK,OAAO,OAAO,MAAM,EAAE;AAAA,QAC7B;AAAA,MACF;AAEA,YAAM,QAAQ,IAAI,sBAAM,OAAO;AAC/B,YAAM,UAAU,KAAK,OAAO,IAAI,SAAS,OAAO,IAAI;AACpD,WAAK,OAAO,cAAc,SAAS,QAAQ;AAC3C,WAAK,OAAO,QAAQ,QAAQ,IAAI,WAAW;AAC3C,WAAK,OAAO,OAAO,QAAQ,EAAE;AAC7B,WAAK,QAAQ,KAAK;AAClB,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,aAAa,IAA8B;AAC/C,UAAM,UAAU,KAAK,OAAO,IAAI,EAAE;AAClC,QAAI,CAAC,WAAW,QAAQ,SAAS,WAAW,QAAQ,SAAS,WAAW,EAAG,QAAO,CAAC;AAEnF,WAAO,KAAK,QAAQ,YAAY,MAAM;AACpC,YAAM,WAAW,KAAK,OAAO,QAAQ,OAAO;AAC5C,WAAK,QAAQ,KAAK;AAClB,WAAK,OAAO,OAAO,SAAS,CAAC,GAAG,MAAM,IAAI;AAC1C,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAAA;AAAA,EAIA,SAAsB;AACpB,WAAO,gBAAgB,IAAI;AAAA,EAC7B;AAAA,EAEA,MAAM,SAAS,OAAmC;AAChD,UAAM,mBAAmB,KAAK,QAAQ,YAAY;AAClD,QAAI,CAAC,kBAAkB;AACrB,WAAK,QAAQ,cAAc;AAC3B,WAAK,QAAQ,MAAM;AAAA,IACrB;AACA,QAAI;AACF,YAAM,kBAAkB,MAAM,KAAK;AAInC,YAAM,KAAK,SAAS,aAAa;AAGjC,WAAK,WAAW,WAAW;AAAA,IAC7B,SAAS,OAAO;AACd,UAAI,CAAC,kBAAkB;AACrB,aAAK,OAAO,KAAK,SAAS,EAAE,SAAS,+BAA+B,MAAM,CAAC;AAAA,MAC7E;AACA,YAAM;AAAA,IACR,UAAE;AACA,UAAI,CAAC,iBAAkB,MAAK,QAAQ,OAAO;AAAA,IAC7C;AACA,QAAI,CAAC,kBAAkB;AACrB,WAAK,QAAQ,MAAM;AACnB,WAAK,QAAQ,cAAc;AAAA,IAC7B;AAAA,EACF;AAAA;AAAA,EAIA,MAAM,MAAM,SAA2C;AACrD,WAAO,KAAK,SAAU,SAAS,UAAU,OAAmC,OAAO;AAAA,EACrF;AAAA,EAEA,MAAM,OAAO,SAA2D;AACtE,WAAO,KAAK,SAAS,QAAQ,OAAO;AAAA,EACtC;AAAA,EAEA,MAAM,OAAO,SAA2D;AACtE,WAAO,KAAK,SAAS,QAAQ,OAAO;AAAA,EACtC;AAAA;AAAA,EAGA,MAAM,YAAY,IAAY,UAAiC,CAAC,GAAkB;AAChF,UAAM,QAAQ,KAAK,OAAO,IAAI,EAAE;AAChC,QAAI,CAAC,MAAO,OAAM,IAAI,MAAM,oBAAoB,EAAE,EAAE;AACpD,QAAI;AACF,UAAI,QAAQ,eAAe,YAAY,MAAM,wBAAwB,6BAAa;AAChF,cAAM,QAAQ,MAAM,MAAM,aAAa,MAAM;AAC7C,cAAM,IAAI;AAAA,UACR,MAAM;AAAA,UACN,KAAK;AAAA,UACL,SAAS;AAAA,UACT,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,OAAO;AAAA,UACP,OAAO;AAAA,UACP,OAAO;AAAA,QACT,CAAC;AACD,eAAO,MAAM,kBAAkB,KAAK,QAAQ,CAAC,KAAK,GAAG;AAAA,UACnD,GAAG;AAAA,UACH,OAAO,MAAM,SAAS;AAAA,UACtB,QAAQ,MAAM,UAAU;AAAA,UACxB,cAAc;AAAA,QAChB,CAAC;AAAA,MACH;AAEA,aAAO,MAAM;AAAA,QACX,KAAK;AAAA,QACL,CAAC,MAAM,eAAe,MAAM,YAAY;AAAA,QACxC;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,WAAK,OAAO,KAAK,SAAS,EAAE,SAAS,2BAA2B,EAAE,IAAI,MAAM,CAAC;AAC7E,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,iBAAiB,UAAiC,CAAC,GAAkB;AACzE,QAAI;AACF,aAAO,MAAM,kBAAkB,KAAK,QAAQ,CAAC,GAAG;AAAA,QAC9C,GAAG;AAAA,QACH,iBAAiB,KAAK;AAAA,QACtB,iBAAiB,KAAK;AAAA,MACxB,CAAC;AAAA,IACH,SAAS,OAAO;AACd,WAAK,OAAO,KAAK,SAAS,EAAE,SAAS,+BAA+B,MAAM,CAAC;AAC3E,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAc,SACZ,QACA,SACe;AACf,SAAK,OAAO,KAAK,gBAAgB,EAAE,OAAO,CAAC;AAC3C,QAAI;AACF,YAAM,KAAK,MAAM,MAAM;AACvB,YAAM,OAAO,MAAM,KAAK;AAAA,QAAqB,MAC3C,UAAU,KAAK,QAAQ,EAAE,GAAG,SAAS,OAAO,CAAC;AAAA,MAC/C;AACA,WAAK,OAAO,KAAK,mBAAmB,EAAE,OAAO,CAAC;AAC9C,WAAK,UAAU,MAAM,UAAU,MAAM,EAAE;AACvC,aAAO;AAAA,IACT,SAAS,OAAO;AACd,WAAK,OAAO,KAAK,SAAS;AAAA,QACxB,SAAS,qBAAqB,KAAK,IAC/B,+FACA,oBAAoB,OAAO,YAAY,CAAC;AAAA,QAC5C;AAAA,MACF,CAAC;AACD,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,QAAgB;AACd,SAAK,OAAO,KAAK,gBAAgB,EAAE,QAAQ,MAAM,CAAC;AAClD,QAAI;AACF,YAAM,MAAM,KAAK,qBAAqB,MAAM,UAAU,KAAK,MAAM,CAAC;AAClE,WAAK,OAAO,KAAK,mBAAmB,EAAE,QAAQ,MAAM,CAAC;AACrD,WAAK,UAAU,MAAM,YAAY;AACjC,aAAO;AAAA,IACT,SAAS,OAAO;AACd,WAAK,OAAO,KAAK,SAAS,EAAE,SAAS,wBAAwB,MAAM,CAAC;AACpE,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,WAAW,UAA4B,CAAC,GAAoB;AAChE,UAAM,KAAK,MAAM,MAAM;AACvB,UAAM,MAAM,KAAK,MAAM;AACvB,QAAI,QAAQ,eAAe,SAAS,KAAK,MAAM,OAAO,EAAE,WAAW,EAAG,QAAO;AAC7E,QAAI;AACF,YAAM,MAAM,MAAM,KAAK,MAAM,eAAe;AAC5C,aAAO,IAAI,QAAQ,mBAAmB,kBAAkB,GAAG,iBAAiB;AAAA,IAC9E,SAAS,OAAO;AACd,WAAK,OAAO,KAAK,SAAS,EAAE,SAAS,gCAAgC,MAAM,CAAC;AAC5E,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,UAAU,SAAsB,OAAO,aAAa,GAAW;AAC7D,WAAO,KAAK,qBAAqB,MAAM,cAAc,KAAK,QAAQ,QAAQ,UAAU,CAAC;AAAA,EACvF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,YAAY,UAA4B,CAAC,GAAkB;AAC/D,UAAM,KAAK,MAAM,MAAM;AACvB,QAAI;AACF,YAAM,OAAO,KAAK,QAAQ;AAC1B,YAAM,OAAO,OACT,MAAM,gBAAgB,KAAK,QAAQ,MAAM,OAAO,IAChD,MAAM,kBAAkB,KAAK,QAAQ,KAAK,OAAO,WAAW,GAAG,OAAO;AAC1E,WAAK,UAAU,MAAM,gBAAgB,QAAQ,UAAU,KAAK,EAAE;AAC9D,aAAO;AAAA,IACT,SAAS,OAAO;AACd,WAAK,OAAO,KAAK,SAAS,EAAE,SAAS,+BAA+B,MAAM,CAAC;AAC3E,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,cAAc,UAA4B,CAAC,GAAkB;AACjE,QAAI,CAAC,KAAK,OAAQ,OAAM,IAAI,MAAM,yBAAyB;AAC3D,UAAM,KAAK,MAAM,MAAM;AACvB,QAAI;AACF,YAAM,OAAO,MAAM,aAAa,KAAK,QAAQ,KAAK,QAAQ,OAAO;AACjE,WAAK,UAAU,MAAM,iBAAiB,QAAQ,UAAU,KAAK,EAAE;AAC/D,aAAO;AAAA,IACT,SAAS,OAAO;AACd,WAAK,OAAO,KAAK,SAAS,EAAE,SAAS,2BAA2B,MAAM,CAAC;AACvE,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,qBAAwB,IAAgB;AAC9C,QAAI,CAAC,KAAK,OAAQ,QAAO,GAAG;AAC5B,UAAM,YAAY,KAAK,OAAO;AAC9B,UAAM,eAAe,KAAK,OAAO;AACjC,SAAK,OAAO,kBAAkB,KAAK;AACnC,SAAK,OAAO,kBAAkB,KAAK,yBAAyB;AAC5D,QAAI;AACF,aAAO,GAAG;AAAA,IACZ,UAAE;AACA,WAAK,OAAO,kBAAkB;AAC9B,WAAK,OAAO,kBAAkB;AAAA,IAChC;AAAA,EACF;AAAA,EAEA,wBAA6D;AAC3D,UAAM,SAA8C,CAAC;AACrD,UAAM,UAAU,KAAK,OAAO,SAAS;AACrC,UAAM,UAAU,KAAK,OAAO,UAAU;AAEtC,UAAM,cAAc,KAAK,OAAO,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,OAAO;AAEzE,QAAI,YAAY,WAAW,GAAG;AAC5B,aAAO,OAAO,IAAI,EAAE,GAAG,KAAK,GAAG,KAAK,OAAO,GAAG,OAAO,EAAE;AACvD,aAAO;AAAA,IACT;AAEA,eAAW,SAAS,aAAa;AAC/B,YAAM,MAAM,MAAM;AAClB,YAAM,SAAS,IAAI,eAAe;AAClC,YAAM,MAAM,OAAO,MAAM,IAAI,IAAI,GAAG,MAAM,IAAI,IAAI,MAAM,EAAE,KAAK,MAAM;AACrE,aAAO,GAAG,IAAI;AAAA,QACZ,GAAG,OAAO,OAAO,IAAI,OAAO;AAAA,QAC5B,GAAG,OAAO,OAAO,IAAI,OAAO;AAAA,QAC5B,OAAO,OAAO,IAAI,UAAU,CAAC;AAAA,QAC7B,OAAO,OAAO,IAAI,SAAS,CAAC;AAAA,MAC9B;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,0BAAqD;AACnD,UAAM,cAAc,KAAK,OAAO,SAAS;AACzC,UAAM,eAAe,KAAK,OAAO,UAAU;AAC3C,WAAO,KAAK,OAAO,OAAO,EAAE,IAAI,CAAC,UAAU;AACzC,YAAM,SAAS,MAAM;AACrB,YAAM,SAAS,OAAO,eAAe;AACrC,YAAM,SAAS,OAAO,gBAAgB;AACtC,aAAO;AAAA,QACL,SAAS,MAAM;AAAA,QACf,MAAM,MAAM;AAAA,QACZ,MAAM,MAAM;AAAA,QACZ,SAAS,OAAO,OAAO,IAAI,WAAW;AAAA,QACtC,SAAS,OAAO,OAAO,IAAI,YAAY;AAAA,QACvC,OAAO,OAAO,OAAO,QAAQ,WAAW;AAAA,QACxC,QAAQ,OAAO,OAAO,SAAS,YAAY;AAAA,QAC3C,QAAQ,OAAO,OAAO,UAAU,CAAC;AAAA,QACjC,QAAQ,OAAO,OAAO,UAAU,CAAC;AAAA,QACjC,OAAO,OAAO,OAAO,SAAS,CAAC;AAAA,MACjC;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,sBAAyB,SAAmC;AAC1D,WAAO,QAAQ,IAAI,KAAK,wBAAwB,GAAG;AAAA,MACjD,OAAO,KAAK,OAAO,SAAS;AAAA,MAC5B,QAAQ,KAAK,OAAO,UAAU;AAAA,IAChC,CAAC;AAAA,EACH;AAAA;AAAA,EAIA,MAAM,KACJ,UACA,QAC6B;AAC7B,QAAI,CAAC,KAAK,YAAa,QAAO;AAE9B,QAAI;AACJ,QAAI,WAAW,OAAO;AACpB,aAAO,MAAM,KAAK,MAAM;AAAA,IAC1B,WAAW,WAAW,QAAQ;AAC5B,aAAO,MAAM,KAAK,OAAO;AAAA,IAC3B,WAAW,WAAW,QAAQ;AAC5B,aAAO,MAAM,KAAK,OAAO;AAAA,IAC3B,WAAW,WAAW,OAAO;AAC3B,aAAO,MAAM,KAAK,WAAW;AAAA,IAC/B,OAAO;AACL,aAAO,KAAK,UAAU,KAAK,OAAO,GAAG,MAAM,CAAC;AAAA,IAC9C;AAEA,QAAI;AACF,aAAO,MAAM,KAAK,YAAY,KAAK,MAAM,UAAU,MAAM;AAAA,IAC3D,SAAS,OAAO;AACd,WAAK,OAAO,KAAK,SAAS,EAAE,SAAS,kBAAkB,MAAM,IAAI,MAAM,CAAC;AACxE,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,YAAY,MAAsD;AACtE,QAAI,CAAC,KAAK,eAAe,OAAQ,QAAO;AACxC,QAAI;AACF,aAAO,MAAM,KAAK,cAAc,OAAO,IAAI;AAAA,IAC7C,SAAS,OAAO;AACd,WAAK,OAAO,KAAK,SAAS,EAAE,SAAS,0BAA0B,MAAM,CAAC;AACtE,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,eAAoD;AACxD,QAAI,CAAC,KAAK,eAAe,OAAQ,QAAO;AACxC,QAAI;AACF,aAAO,MAAM,KAAK,cAAc,OAAO;AAAA,IACzC,SAAS,OAAO;AACd,WAAK,OAAO,KAAK,SAAS,EAAE,SAAS,2BAA2B,MAAM,CAAC;AACvE,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,aACJ,OACA,SACmC;AACnC,QAAI,CAAC,KAAK,eAAe,OAAQ,QAAO;AACxC,QAAI;AACF,aAAO,MAAM,KAAK,cAAc,OAAO,OAAO,OAAO;AAAA,IACvD,SAAS,OAAO;AACd,WAAK,OAAO,KAAK,SAAS,EAAE,SAAS,2BAA2B,MAAM,CAAC;AACvE,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,iBACJ,OACA,SACgB;AAChB,QAAI;AACF,YAAM,KAAK,eAAe,WAAW,KAAK;AAAA,IAC5C,SAAS,OAAO;AACd,WAAK,OAAO,KAAK,SAAS,EAAE,SAAS,8BAA8B,MAAM,CAAC;AAC1E,YAAM;AAAA,IACR;AACA,WAAO,KAAK,SAAS,MAAM,KAAK,OAAO;AAAA,EACzC;AAAA,EAEA,eAAe,SAA4B;AACzC,SAAK,cAAc;AAAA,EACrB;AAAA,EAEA,iBAAiB,UAA+B;AAC9C,SAAK,gBAAgB;AAAA,EACvB;AAAA;AAAA,EAIA,cAAc,OAAqB;AACjC,SAAK,mBAAmB;AAGxB,QAAI,CAAC,KAAK,QAAQ;AAChB,WAAK,OAAO,kBAAkB;AAC9B,WAAK,OAAO,iBAAiB;AAAA,IAC/B;AACA,SAAK,QAAQ,KAAK;AAClB,SAAK,OAAO,KAAK,mBAAmB,CAAC,CAAC;AAAA,EACxC;AAAA,EAEA,sBAA8B;AAC5B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,2BAAgD;AAC9C,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,4BAAqE;AACnE,WAAO,KAAK,yBAAyB,EAAE,GAAG,KAAK,uBAAuB,IAAI;AAAA,EAC5E;AAAA,EAEA,MAAM,mBACJ,KACA,UAAkC,CAAC,GACpB;AACf,QAAI,QAAQ,MAAM;AAChB,WAAK,yBAAyB,IAAI;AAClC;AAAA,IACF;AACA,QAAI;AACF,YAAM,QAAQ,MAAM,4BAAY;AAAA,QAC9B;AAAA,QACA,EAAE,aAAa,QAAQ,eAAe,MAAM,QAAQ,QAAQ,OAAO;AAAA,QACnE,EAAE,SAAS,QAAQ,SAAS,MAAM;AAAA,MACpC;AACA,YAAM,QAAQ,MAAM,SAAS;AAC7B,YAAM,SAAS,MAAM,UAAU;AAC/B,YAAM,cAAc,KAAK,OAAO,SAAS;AACzC,YAAM,eAAe,KAAK,OAAO,UAAU;AAC3C,YAAM,MAAM,QAAQ,OAAO;AAC3B,YAAM,KAAK,cAAc;AACzB,YAAM,KAAK,eAAe;AAC1B,YAAM,SACJ,QAAQ,YAAY,KAAK,QAAQ,YAAY,KAAK,IAAI,IAAI,EAAE,IAAI,KAAK,IAAI,IAAI,EAAE;AACjF,YAAM,SAAS,QAAQ,YAAY,KAAK;AACxC,YAAM,IAAI;AAAA,QACR,OAAO,cAAc,QAAQ,UAAU;AAAA,QACvC,MAAM,eAAe,SAAS,UAAU;AAAA,QACxC;AAAA,QACA;AAAA,QACA,SAAS,MAAM,QAAQ,WAAW,GAAG,GAAG,CAAC;AAAA,QACzC,YAAY;AAAA,QACZ,SAAS;AAAA,MACX,CAAC;AACD,YAAM,sBAAsB,EAAE,GAAG,QAAQ;AACzC,aAAO,oBAAoB;AAC3B,WAAK,yBAAyB,OAAO,MAAM,mBAAmB;AAAA,IAChE,SAAS,OAAO;AACd,WAAK,OAAO,KAAK,SAAS,EAAE,SAAS,kCAAkC,MAAM,CAAC;AAC9E,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA,EAGA,yBACE,OACA,OAAO,MACP,UAAmD,MAC7C;AACN,SAAK,wBAAwB;AAC7B,SAAK,yBAAyB,QAAQ,UAAU;AAChD,SAAK,OAAO,kBAAkB,KAAK,SAAS,SAAa,SAAS;AAClE,SAAK,OAAO,iBAAiB;AAC7B,QAAI,KAAM,MAAK,QAAQ,KAAK;AAC5B,SAAK,OAAO,KAAK,mBAAmB,CAAC,CAAC;AAAA,EACxC;AAAA,EAEA,2BAAiC;AAC/B,SAAK,cAAc,EAAE;AAAA,EACvB;AAAA,EAEA,OAAO,OAAe,QAAgB,UAAyB,CAAC,GAAS;AACvE,UAAM,UAAU,KAAK,MAAM,SAAS,KAAK;AACzC,UAAM,WAAW,KAAK,MAAM,SAAS,MAAM;AAC3C,UAAM,WAAW,KAAK,OAAO,SAAS;AACtC,UAAM,YAAY,KAAK,OAAO,UAAU;AACxC,UAAM,eAAe,QAAQ,gBAAgB;AAC7C,QAAI,gBAAgB,WAAW,KAAK,YAAY,GAAG;AACjD,YAAM,KAAK,UAAU;AACrB,YAAM,KAAK,WAAW;AACtB,iBAAW,SAAS,KAAK,OAAO,OAAO,GAAG;AACxC,cAAM,SAAS,MAAM;AACrB,eAAO,IAAI;AAAA,UACT,OAAO,OAAO,QAAQ,KAAK;AAAA,UAC3B,MAAM,OAAO,OAAO,KAAK;AAAA,UACzB,SAAS,OAAO,UAAU,KAAK;AAAA,UAC/B,SAAS,OAAO,UAAU,KAAK;AAAA,QACjC,CAAC;AACD,eAAO,UAAU;AAAA,MACnB;AACA,UAAI,KAAK,uBAAuB;AAC9B,aAAK,sBAAsB,IAAI;AAAA,UAC7B,OAAO,KAAK,sBAAsB,QAAQ,KAAK;AAAA,UAC/C,MAAM,KAAK,sBAAsB,OAAO,KAAK;AAAA,UAC7C,SAAS,KAAK,sBAAsB,UAAU,KAAK;AAAA,UACnD,SAAS,KAAK,sBAAsB,UAAU,KAAK;AAAA,QACrD,CAAC;AACD,aAAK,sBAAsB,UAAU;AAAA,MACvC;AAAA,IACF;AACA,SAAK,OAAO,cAAc,EAAE,OAAO,SAAS,QAAQ,SAAS,CAAC;AAC9D,SAAK,SAAS,SAAS;AACvB,SAAK,OAAO,iBAAiB;AAC7B,SAAK,QAAQ,KAAK;AAClB,SAAK,OAAO,KAAK,mBAAmB,CAAC,CAAC;AAAA,EACxC;AAAA;AAAA,EAGA,YAAY,SAAgC;AAC1C,UAAM,QAAQ,KAAK,OAAO,IAAI,OAAO;AACrC,QAAI,CAAC,SAAS,MAAM,SAAS,QAAS,QAAO;AAC7C,UAAM,QAAQ,MAAM;AACpB,UAAM,eAAe,MAAM,SAAS;AACpC,UAAM,kBAAkB,MAAM,eAAe;AAC7C,QAAI,gBAAgB,KAAK,mBAAmB,EAAG,QAAO;AACtD,WAAO,OAAO,gBAAgB,kBAAkB,KAAK,MAAM,OAAO,EAAE;AAAA,EACtE;AAAA,EAEA,iBAAiB,aAAa,KAAiB;AAC7C,WAAO,KAAK,OACT,OAAO,EACP,OAAO,CAAC,UAAU,MAAM,SAAS,WAAW,CAAC,MAAM,KAAK,OAAO,EAC/D,QAAQ,CAAC,UAAU;AAClB,YAAM,eAAe,KAAK,YAAY,MAAM,EAAE;AAC9C,aAAO,iBAAiB,QAAQ,eAAe,aAC3C,CAAC,EAAE,SAAS,MAAM,IAAI,WAAW,MAAM,MAAM,cAAc,WAAW,CAAC,IACvE,CAAC;AAAA,IACP,CAAC;AAAA,EACL;AAAA;AAAA,EAGA,YAAY,WAAW,KAAK,YAAY,KAAK,SAAsB,OAAe;AAChF,UAAM,aAAa,KAAK;AAAA,MACtB;AAAA,MACA,WAAW,KAAK,OAAO,SAAS;AAAA,MAChC,YAAY,KAAK,OAAO,UAAU;AAAA,IACpC;AACA,WAAO,KAAK,UAAU,QAAQ,UAAU;AAAA,EAC1C;AAAA,EAEA,aAAa,IAAqB;AAChC,WAAO,KAAK,OAAO,QAAQ,IAAI,KAAK,OAAO,MAAM,IAAI,CAAC;AAAA,EACxD;AAAA,EAEA,WAAW,IAAqB;AAC9B,WAAO,KAAK,OAAO,QAAQ,IAAI,CAAC;AAAA,EAClC;AAAA,EAEA,aAAa,IAAqB;AAChC,UAAM,QAAQ,KAAK,OAAO,OAAO,EAAE,UAAU,CAAC,UAAU,MAAM,OAAO,EAAE;AACvE,WAAO,SAAS,KAAK,KAAK,OAAO,QAAQ,IAAI,QAAQ,CAAC;AAAA,EACxD;AAAA,EAEA,aAAa,IAAqB;AAChC,UAAM,QAAQ,KAAK,OAAO,OAAO,EAAE,UAAU,CAAC,UAAU,MAAM,OAAO,EAAE;AACvE,WAAO,SAAS,KAAK,KAAK,OAAO,QAAQ,IAAI,QAAQ,CAAC;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,QAAQ,OAAqB;AAC3B,UAAM,OAAO,MAAM,OAAO,KAAK,GAAG,UAAU,QAAQ;AACpD,QAAI,SAAS,KAAK,UAAW;AAC7B,SAAK,YAAY;AAGjB,SAAK,sBAAsB;AAC3B,SAAK,OAAO,KAAK,gBAAgB,EAAE,MAAM,KAAK,CAAC;AAAA,EACjD;AAAA;AAAA,EAGA,KAAK,OAAqB;AACxB,SAAK,QAAQ,KAAK;AAAA,EACpB;AAAA,EAEA,UAAkB;AAChB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,OAAO,OAAO,KAAW;AACvB,SAAK,QAAQ,KAAK,YAAY,IAAI;AAAA,EACpC;AAAA,EAEA,QAAQ,OAAO,KAAW;AACxB,SAAK,QAAQ,KAAK,YAAY,IAAI;AAAA,EACpC;AAAA,EAEA,YAAkB;AAChB,SAAK,QAAQ,CAAC;AAAA,EAChB;AAAA;AAAA,EAGA,UAAU,eAAuB,gBAAwB,UAAU,GAAS;AAC1E,UAAM,IAAI,KAAK,OAAO,SAAS;AAC/B,UAAM,IAAI,KAAK,OAAO,UAAU;AAChC,QAAI,KAAK,KAAK,KAAK,EAAG;AACtB,UAAM,MAAM,gBAAgB,UAAU,KAAK;AAC3C,UAAM,MAAM,iBAAiB,UAAU,KAAK;AAC5C,SAAK,QAAQ,KAAK,IAAI,IAAI,EAAE,CAAC;AAAA,EAC/B;AAAA;AAAA,EAGA,gBAAgB,UAAU,IAAU;AAClC,UAAM,SAAS,KAAK,OAAO,gBAAgB;AAC3C,QAAI,CAAC,OAAQ;AACb,WAAO,UAAU;AACjB,UAAM,SAAS,OAAO,gBAAgB;AACtC,QAAI,OAAO,SAAS,KAAK,OAAO,UAAU,EAAG;AAC7C,SAAK;AAAA,MACH,KAAK;AAAA,SACF,KAAK,OAAO,SAAS,IAAI,UAAU,KAAK,OAAO;AAAA,SAC/C,KAAK,OAAO,UAAU,IAAI,UAAU,KAAK,OAAO;AAAA,MACnD;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAIA,aAAa,SAAiB,QAAsC;AAClE,WAAO,KAAK,SAAS,MAAM,SAAS,MAAM;AAAA,EAC5C;AAAA,EAEA,aAAa,SAAgC;AAC3C,WAAO,KAAK,SAAS,QAAQ,OAAO;AAAA,EACtC;AAAA;AAAA,EAIA,eAAe,SAAiB,QAA2C;AACzE,WAAO,KAAK,OAAO,MAAM,SAAS,MAAM;AAAA,EAC1C;AAAA,EAEA,eAAe,SAA0B;AACvC,WAAO,KAAK,OAAO,MAAM,OAAO;AAAA,EAClC;AAAA,EAEA,aAAa,SAAyC;AACpD,WAAO,KAAK,OAAO,IAAI,OAAO;AAAA,EAChC;AAAA;AAAA,EAIA,gBAAgB,SAAiB,IAAkC;AACjE,WAAO,KAAK,YAAY,MAAM,SAAS,EAAE;AAAA,EAC3C;AAAA,EAEA,gBAAgB,SAA0B;AACxC,WAAO,KAAK,YAAY,MAAM,OAAO;AAAA,EACvC;AAAA,EAEA,cAAc,SAAsC;AAClD,WAAO,KAAK,YAAY,IAAI,OAAO;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,mBAAmB,SAAiB,QAA0B;AAC5D,UAAM,QAAQ,KAAK,OAAO,IAAI,OAAO;AACrC,QAAI,CAAC,MAAO,QAAO;AACnB,oBAAgB,MAAM,cAAc,MAAM;AAC1C,QAAI,OAAQ,OAAM,KAAK,aAAa;AAAA,QAC/B,QAAO,MAAM,KAAK;AACvB,SAAK,OAAO,iBAAiB;AAC7B,SAAK,OAAO,KAAK,kBAAkB,EAAE,QAAQ,CAAC;AAC9C,SAAK,QAAQ,KAAK;AAClB,WAAO;AAAA,EACT;AAAA,EAEA,mBAAmB,SAA0B;AAC3C,WAAO,KAAK,OAAO,IAAI,OAAO,GAAG,KAAK,eAAe;AAAA,EACvD;AAAA;AAAA,EAGA,qBAA2B;AACzB,eAAW,SAAS,KAAK,OAAO,OAAO,GAAG;AACxC,UAAI,MAAM,KAAK,WAAY,iBAAgB,MAAM,cAAc,IAAI;AAAA,IACrE;AAAA,EACF;AAAA;AAAA,EAGA,oBAAoB,SAA0B;AAC5C,UAAM,QAAQ,KAAK,OAAO,IAAI,OAAO;AACrC,QAAI,CAAC,MAAO,QAAO;AACnB,mBAAe,MAAM,YAAY;AACjC,SAAK,OAAO,iBAAiB;AAC7B,SAAK,OAAO,KAAK,kBAAkB,EAAE,QAAQ,CAAC;AAC9C,SAAK,QAAQ,KAAK;AAClB,WAAO;AAAA,EACT;AAAA;AAAA,EAIA,eAAe,SAAiB,QAA6C;AAC3E,UAAM,QAAQ,KAAK,OAAO,IAAI,OAAO;AACrC,QAAI,CAAC,MAAO,QAAO;AACnB,qBAAiB,MAAM,cAAc,MAAM;AAC3C,UAAM,aAAa,QAAQ;AAC3B,SAAK,OAAO,iBAAiB;AAC7B,SAAK,OAAO,KAAK,kBAAkB,EAAE,QAAQ,CAAC;AAC9C,SAAK,QAAQ,KAAK;AAClB,WAAO;AAAA,EACT;AAAA,EAEA,eAAe,SAA2C;AACxD,UAAM,QAAQ,KAAK,OAAO,IAAI,OAAO;AACrC,WAAO,QAAQ,gBAAgB,MAAM,YAAY,IAAI;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,UAAU,QAA6B,UAAiC,CAAC,GAAS;AAChF,SAAK,SAAS;AAGd,SAAK,OAAO,kBAAkB,SAAS,KAAK,KAAK;AACjD,SAAK,OAAO,kBAAkB,SAAS,SAAa,KAAK,yBAAyB;AAClF,SAAK,OAAO,iBAAiB;AAC7B,SAAK,OAAO,KAAK,kBAAkB,EAAE,OAAO,CAAC;AAC7C,QAAI,QAAQ,YAAY,MAAO,MAAK,QAAQ,KAAK;AAAA,EACnD;AAAA,EAEA,cAAoB;AAClB,SAAK,UAAU,IAAI;AAAA,EACrB;AAAA,EAEA,YAAiC;AAC/B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAIA,UAAgB;AACd,SAAK,MAAM,QAAQ;AACnB,SAAK,WAAW,QAAQ;AACxB,SAAK,SAAS,QAAQ;AACtB,SAAK,KAAK,QAAQ;AAClB,SAAK,QAAQ,QAAQ;AACrB,SAAK,SAAS,QAAQ;AACtB,SAAK,OAAO,QAAQ;AACpB,SAAK,OAAO,mBAAmB;AAC/B,SAAK,OAAO,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA,EAKA,oBAAoC;AAClC,WAAO,EAAE,GAAG,KAAK,eAAe;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,kBAAkB,OAAsC;AACtD,SAAK,iBAAiB,EAAE,GAAG,KAAK,gBAAgB,GAAG,MAAM;AACzD,SAAK,sBAAsB;AAAA,EAC7B;AAAA,EAEQ,wBAA8B;AACpC,wBAAoB,KAAK,QAAQ,KAAK,gBAAgB,KAAK,SAAS;AAAA,EACtE;AAAA;AAAA,EAIQ,oBAA0B;AAGhC,SAAK,OAAO,GAAG,gBAAgB,CAAC,MAAM;AACpC,UAAI,EAAE,OAAQ,2BAA0B,EAAE,QAAQ,KAAK,gBAAgB,KAAK,SAAS;AAAA,IACvF,CAAC;AAID,UAAM,cAAc,MAAM;AACxB,YAAM,SAAS,KAAK,OAAO,gBAAgB;AAC3C,UAAI,OAAQ,2BAA0B,QAAQ,KAAK,gBAAgB,KAAK,SAAS;AAAA,IACnF;AAEA,SAAK,OAAO,GAAG,mBAAmB,CAAC,MAAM;AACvC,UAAI,CAAC,EAAE,OAAQ;AACf,YAAM,QAAQ,KAAK,OAAO,aAAa,EAAE,MAAM;AAC/C,UAAI,OAAO;AACT,aAAK,OAAO,KAAK,kBAAkB,EAAE,SAAS,MAAM,GAAG,CAAC;AACxD,aAAK,QAAQ,KAAK;AAAA,MACpB;AAAA,IACF,CAAC;AAED,SAAK,OAAO,GAAG,qBAAqB,CAAC,MAAM;AACzC,kBAAY;AACZ,YAAM,YAAY,EAAE,YAAY,CAAC,GAC9B,IAAI,CAAC,QAAQ,KAAK,OAAO,aAAa,GAAG,GAAG,EAAE,EAC9C,OAAO,CAAC,OAAqB,OAAO,MAAS;AAChD,WAAK,OAAO,KAAK,qBAAqB,EAAE,SAAS,CAAC;AAAA,IACpD,CAAC;AAED,SAAK,OAAO,GAAG,qBAAqB,CAAC,MAAM;AACzC,kBAAY;AACZ,YAAM,YAAY,EAAE,YAAY,CAAC,GAC9B,IAAI,CAAC,QAAQ,KAAK,OAAO,aAAa,GAAG,GAAG,EAAE,EAC9C,OAAO,CAAC,OAAqB,OAAO,MAAS;AAChD,WAAK,OAAO,KAAK,qBAAqB,EAAE,SAAS,CAAC;AAAA,IACpD,CAAC;AAED,SAAK,OAAO,GAAG,qBAAqB,MAAM;AACxC,WAAK,OAAO,KAAK,qBAAqB,EAAE,UAAU,CAAC,EAAE,CAAC;AAAA,IACxD,CAAC;AAAA,EACH;AACF;;;AqCtvBO,IAAM,yBAAwC;AAAA,EACnD,MAAM;AAAA,EACN,OAAO;AAAA,EACP,mBAAmB;AAAA,EACnB,iBAAiB;AAAA,EACjB,OAAO;AAAA,EACP,kBAAkB;AAAA,EAClB,SAAS;AAAA,EACT,SAAS;AAAA,EACT,eAAe;AAAA,EACf,eAAe;AACjB;;;ACrfO,IAAM,sBAAmD;AAAA,EAC9D,EAAE,IAAI,eAAe,MAAM,eAAe,OAAO,KAAK,QAAQ,KAAK,MAAM,MAAM,KAAK,IAAI;AAAA,EACxF,EAAE,IAAI,gBAAgB,MAAM,gBAAgB,OAAO,KAAK,QAAQ,KAAK,MAAM,MAAM,KAAK,IAAI;AAAA,EAC1F,EAAE,IAAI,aAAa,MAAM,aAAa,OAAO,KAAK,QAAQ,IAAI,MAAM,MAAM,KAAK,IAAI;AAAA,EACnF,EAAE,IAAI,eAAe,MAAM,iBAAiB,OAAO,IAAI,QAAQ,IAAI,MAAM,MAAM,KAAK,IAAI;AAAA,EACxF,EAAE,IAAI,oBAAoB,MAAM,iBAAiB,OAAO,MAAM,QAAQ,MAAM,MAAM,MAAM,KAAK,GAAG;AAAA,EAChG,EAAE,IAAI,SAAS,MAAM,SAAS,OAAO,MAAM,QAAQ,MAAM,MAAM,MAAM,KAAK,GAAG;AAC/E;;;ACYO,IAAM,oBAAN,MAAwB;AAAA,EACrB,QAAQ,oBAAI,IAAiC;AAAA,EAC7C,YAA+B,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,kBAAkB,EAAE;AAAA,EAExF,IAAI,YAAuC;AACzC,SAAK,MAAM,IAAI,WAAW,IAAI,gBAAgB,UAAU,CAAC;AAAA,EAC3D;AAAA,EAEA,OAAO,IAAqB;AAC1B,WAAO,KAAK,MAAM,OAAO,EAAE;AAAA,EAC7B;AAAA,EAEA,QAAc;AACZ,SAAK,MAAM,MAAM;AAAA,EACnB;AAAA,EAEA,SAAgC;AAC9B,WAAO,CAAC,GAAG,KAAK,MAAM,OAAO,CAAC,EAAE,IAAI,CAAC,SAAS,gBAAgB,IAAI,CAAC;AAAA,EACrE;AAAA,EAEA,aAAa,WAAoC;AAC/C,QAAI,CAAC,OAAO,SAAS,UAAU,IAAI,KAAK,UAAU,QAAQ,GAAG;AAC3D,YAAM,IAAI,MAAM,kCAAkC;AAAA,IACpD;AACA,SAAK,YAAY,EAAE,GAAG,WAAW,kBAAkB,UAAU,oBAAoB,EAAE;AAAA,EACrF;AAAA,EAEA,mBAAmB,OAA2D;AAC5E,WAAO;AAAA,MACL,GAAG,MAAM,IAAI,KAAK,UAAU,OAAO,KAAK,UAAU;AAAA,MAClD,GAAG,MAAM,IAAI,KAAK,UAAU,OAAO,KAAK,UAAU;AAAA,IACpD;AAAA,EACF;AAAA,EAEA,mBAAmB,OAA2D;AAC5E,WAAO;AAAA,MACL,IAAI,MAAM,IAAI,KAAK,UAAU,QAAQ,KAAK,UAAU;AAAA,MACpD,IAAI,MAAM,IAAI,KAAK,UAAU,QAAQ,KAAK,UAAU;AAAA,IACtD;AAAA,EACF;AAAA,EAEA,iBAAiB,OAA2D;AAC1E,UAAM,WAAW,KAAK,mBAAmB,KAAK;AAC9C,UAAM,QAAQ,KAAK,UAAU,oBAAoB;AACjD,WAAO,EAAE,GAAG,SAAS,IAAI,OAAO,GAAG,SAAS,IAAI,MAAM;AAAA,EACxD;AACF;","names":["import_fabric","import_fabric","import_fabric","STROKE","import_fabric","import_fabric","clamp","import_fabric","start","import_fabric","round","import_fabric","import_fabric","import_fabric","document","page","import_fabric","import_fabric","import_fabric","import_fabric","import_fabric","import_fabric","import_fabric","import_fabric","entry","layer"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/editor.ts","../src/events.ts","../src/layer.ts","../src/utils/id.ts","../src/template-explode.ts","../src/history.ts","../src/snapping.ts","../src/crop.ts","../src/utils/clamp.ts","../src/pattern/pattern-manager.ts","../src/pattern/tiled-pattern-object.ts","../src/text-fit.ts","../src/pattern/tile-geometry.ts","../src/text-curve.ts","../src/text-curve-geometry.ts","../src/mask-presets/manager.ts","../src/mask-presets/shapes.ts","../src/mask-presets/textures.ts","../src/shadow.ts","../src/utils/color.ts","../src/selection-style.ts","../src/transform.ts","../src/utils/units.ts","../src/serialization.ts","../src/export.ts","../src/displacement.ts","../src/utils/svg.ts","../src/fonts.ts","../src/licensing.ts","../src/project.ts","../src/mask.ts","../src/masks/manager.ts","../src/masks/compose.ts","../src/masks/edit.ts","../src/masks/space.ts","../src/masks/store.ts","../src/masks/host.ts","../src/masks/install.ts","../src/types.ts","../src/presets.ts","../src/annotations.ts"],"sourcesContent":["export { CanvasEditor } from './editor';\nexport { Layer, LayerManager } from './layer';\nexport { HistoryManager } from './history';\nexport { SnapManager } from './snapping';\nexport { CropController } from './crop';\nexport {\n PatternManager,\n TiledPatternObject,\n drawTiles,\n computeTilePositions,\n restoreLocks,\n} from './pattern';\nexport type {\n CanvasRenderingProtocol,\n PatternOrigin,\n TileDrawSize,\n TilePlacement,\n} from './pattern';\nexport {\n TextCurveManager,\n DEFAULT_TEXT_CURVE,\n buildCurvePathData,\n buildCurveLinePaths,\n normalizeTextCurve,\n} from './text-curve';\nexport type { CurvePath } from './text-curve';\n// Only the operation is public; the measurement helpers behind it are shared\n// with the pattern engine through a direct import, not through the API surface.\nexport { fitTextWidth } from './text-fit';\nexport { explodeTemplateSvg, textPathSpec, textPathCurve } from './template-explode';\nexport type { TemplateLayerSpec } from './template-explode';\nexport {\n MaskPresetManager,\n isMaskPresetId,\n isShapeMaskId,\n isTextureMaskId,\n shapeMaskPathData,\n renderTextureMask,\n clearTextureMaskCache,\n SHAPE_MASK_IDS,\n SHAPE_MASK_BOX,\n TEXTURE_MASK_IDS,\n TEXTURE_MASK_SIZE,\n} from './mask-presets';\nexport {\n LayerMaskManager,\n CANVAS_MASK_TARGET,\n composeMaskGroup,\n needsAbsoluteSpace,\n fitToBox,\n toCanvasSpace,\n toHostSpace,\n unwrapGroup,\n} from './masks';\nexport type { AddMaskOptions } from './masks';\nexport { applyLayerShadow, readLayerShadow, DEFAULT_LAYER_SHADOW } from './shadow';\nexport {\n applyObjectSelectionStyle,\n applySelectionStyle,\n DEFAULT_SELECTION_STYLE,\n} from './selection-style';\nexport type { SelectionStyle } from './selection-style';\nexport { applyAspectLock, resetTransform } from './transform';\nexport { EventEmitter } from './events';\nexport { UnitConverter } from './utils/units';\nexport { generateId } from './utils/id';\nexport { clamp, round2 } from './utils/clamp';\nexport { escapeXml, sanitizeSvg } from './utils/svg';\nexport { isCssColor } from './utils/color';\nexport { serializeEditor, deserializeEditor } from './serialization';\nexport {\n exportPNG,\n exportSVG,\n exportDataURL,\n exportMockup,\n exportPrintArea,\n computeCoverPlacement,\n computePrintAreaClip,\n} from './export';\nexport { DEFAULT_PATTERN_CONFIG } from './types';\nexport { CANVAS_SIZE_PRESETS } from './presets';\nexport { FontRegistry } from './fonts';\nexport { LicenseManager } from './licensing';\nexport { ProjectManager } from './project';\nexport { MaskController, MaskRefinementError } from './mask';\nexport type { MaskRefinementErrorCode, MaskPerformanceSample } from './mask';\nexport { AnnotationOverlay } from './annotations';\nexport type { AnnotationPrimitive, ViewportTransform } from './annotations';\nexport { displaceRgba } from './displacement';\n\nexport type {\n LayerType,\n LayerData,\n LayerMeta,\n SerializedLayer,\n EditorState,\n EditorConfig,\n FileAdapter,\n ImageProvider,\n ImageProviderResult,\n ImageAttribution,\n ImageSearchOptions,\n ImageSearchResult,\n ExportFormat,\n ShapePlugin,\n TemplateDefinition,\n TemplateParameter,\n PrintifyPositioning,\n TileMode,\n PatternConfig,\n PatternState,\n PatternLocks,\n MockupConfig,\n MockupPrintArea,\n MockupBlendMode,\n MockupOverlay,\n MockupDisplacement,\n MockupDisplacementChannel,\n EditorEvents,\n Unit,\n ResizeOptions,\n DpiIssue,\n ImageAdjustments,\n CanvasSizePreset,\n BackgroundImageOptions,\n SerializedBackgroundImageOptions,\n SemanticExportOptions,\n MaskPoint,\n MaskBrushOptions,\n MaskRefinementPrompt,\n MaskRefinementRequest,\n MaskRefinementResult,\n MaskRefinementProvider,\n MaskPresetId,\n ShapeMaskPresetId,\n TextureMaskPresetId,\n LayerMaskEntry,\n LayerMaskMode,\n TextCurveConfig,\n TextCurveInput,\n TextCurveShape,\n LayerShadowConfig,\n FontDefinition,\n SvgExportOptions,\n LicenseConfig,\n LicensePayload,\n LicenseStatus,\n NormalizedLayerPosition,\n PositioningAdapter,\n ProjectPage,\n ProjectState,\n} from './types';\n\nexport type { PngExportOptions, CoverPlacement } from './export';\n","import { Canvas, FabricImage, Group, Textbox, filters } from 'fabric';\nimport type { FabricObject, ImageFormat } from 'fabric';\nimport type {\n EditorConfig,\n DpiIssue,\n BackgroundImageOptions,\n SemanticExportOptions,\n SerializedBackgroundImageOptions,\n SvgExportOptions,\n EditorEvents,\n EditorState,\n FileAdapter,\n ImageProvider,\n ImageProviderResult,\n ImageSearchOptions,\n ImageSearchResult,\n ImageAdjustments,\n LayerShadowConfig,\n MaskPresetId,\n MockupConfig,\n PatternConfig,\n PrintifyPositioning,\n TextCurveConfig,\n ResizeOptions,\n NormalizedLayerPosition,\n PositioningAdapter,\n ShapePlugin,\n TemplateDefinition,\n} from './types';\nimport { EventEmitter } from './events';\nimport { Layer, LayerManager } from './layer';\nimport { explodeTemplateSvg, textPathSpec } from './template-explode';\nimport { HistoryManager } from './history';\nimport { SnapManager } from './snapping';\nimport { CropController } from './crop';\nimport { PatternManager } from './pattern';\nimport { TextCurveManager } from './text-curve';\nimport { MaskPresetManager } from './mask-presets';\nimport { applyLayerShadow, readLayerShadow } from './shadow';\nimport {\n DEFAULT_SELECTION_STYLE,\n applyObjectSelectionStyle,\n applySelectionStyle,\n} from './selection-style';\nimport type { SelectionStyle } from './selection-style';\nimport { applyAspectLock, resetTransform } from './transform';\nimport { UnitConverter } from './utils/units';\nimport { serializeEditor, deserializeEditor } from './serialization';\nimport {\n exportPNG,\n exportSVG,\n exportDataURL,\n exportMockup,\n exportIsolatedPNG,\n exportPrintArea,\n} from './export';\nimport type { PngExportOptions } from './export';\nimport { clamp, round2 } from './utils/clamp';\nimport { escapeXml, sanitizeSvg } from './utils/svg';\nimport { isCssColor } from './utils/color';\nimport { FontRegistry } from './fonts';\nimport { LicenseManager } from './licensing';\nimport { ProjectManager } from './project';\nimport { MaskController } from './mask';\nimport { LayerMaskManager } from './masks';\n\nconst MIN_ZOOM = 0.1;\nconst MAX_ZOOM = 8;\n\nfunction isTaintedCanvasError(error: unknown): boolean {\n return (\n (error instanceof DOMException && error.name === 'SecurityError') ||\n (error instanceof Error && /taint|cross-origin|insecure/i.test(error.message))\n );\n}\n\nexport class CanvasEditor {\n readonly canvas: Canvas;\n readonly layers: LayerManager;\n readonly history: HistoryManager;\n readonly events: EventEmitter<EditorEvents>;\n readonly units: UnitConverter;\n readonly snapping: SnapManager;\n readonly crop: CropController;\n readonly patterns: PatternManager;\n readonly curves: TextCurveManager;\n readonly maskPresets: MaskPresetManager;\n /** Stacked boolean masks, per layer and for the design as a whole. */\n readonly layerMasks: LayerMaskManager;\n readonly fonts: FontRegistry;\n readonly licensing: LicenseManager;\n readonly pages: ProjectManager;\n readonly masks: MaskController;\n\n private fileAdapter?: FileAdapter;\n private imageProvider?: ImageProvider;\n private zoomLevel = 1;\n private selectionStyle: SelectionStyle = { ...DEFAULT_SELECTION_STYLE };\n private mockup: MockupConfig | null = null;\n // The design's configured background. The live canvas background is forced\n // transparent while a mockup preview is shown, so this is the source of truth\n // for serialization and export — not the (possibly transient) canvas value.\n private designBackground: string;\n private designBackgroundImage: FabricObject | null = null;\n private backgroundImageOptions: SerializedBackgroundImageOptions | null = null;\n\n constructor(canvasElement: HTMLCanvasElement, config: EditorConfig) {\n this.events = new EventEmitter<EditorEvents>();\n this.fonts = new FontRegistry();\n config.fonts?.forEach((font) => this.fonts.register(font));\n this.licensing = new LicenseManager(config.license);\n this.units = new UnitConverter(config.unit ?? 'px', config.dpi ?? 72);\n\n const widthPx = this.units.toPixels(config.width);\n const heightPx = this.units.toPixels(config.height);\n this.designBackground = config.backgroundColor ?? '#ffffff';\n\n this.canvas = new Canvas(canvasElement, {\n width: widthPx,\n height: heightPx,\n backgroundColor: this.designBackground,\n preserveObjectStacking: config.preserveObjectStacking ?? true,\n selection: true,\n });\n\n this.layers = new LayerManager(this.canvas, this.events);\n this.fileAdapter = config.fileAdapter;\n this.imageProvider = config.imageProvider;\n\n this.history = new HistoryManager({\n getState: () => JSON.stringify(this.toJSON()),\n restoreState: async (state: string) => {\n const parsed = JSON.parse(state) as EditorState;\n await this.fromJSON(parsed);\n },\n events: this.events,\n });\n this.layers.setHistoryCallback(() => this.history.save());\n\n this.snapping = new SnapManager(this.canvas, this.events);\n this.crop = new CropController(this.canvas, this.history, this.events);\n this.patterns = new PatternManager(this.canvas, this.layers, this.history, this.events);\n this.curves = new TextCurveManager(this.canvas, this.layers, this.history, this.events);\n this.maskPresets = new MaskPresetManager(this.canvas, this.layers, this.history, this.events);\n this.layerMasks = new LayerMaskManager(this.canvas, this.layers, this.history, this.events);\n\n this.setupCanvasEvents();\n this.refreshSelectionStyle();\n this.history.saveImmediate();\n this.pages = new ProjectManager(this);\n this.masks = new MaskController(this);\n }\n\n // ─── Layer Operations ────────────────────────────────\n\n async addImage(url: string, options?: Partial<Record<string, unknown>>): Promise<Layer> {\n // Don't force crossOrigin here: a remote image whose host sends no CORS\n // header would then fail to load at all. The pattern engine requests its own\n // crossOrigin copy when it needs an untainted canvas (see pattern.ts).\n // Fabric v7 defaults originX/originY to 'center'; pin top-left so images\n // land at their left/top like the rest of the editor's coordinate model.\n try {\n const img = await FabricImage.fromURL(\n url,\n {},\n { originX: 'left', originY: 'top', ...options },\n );\n const layer = this.layers.add('image', img);\n // Select what was just created: the panel highlights it, and the property\n // sections open on it, without a second click on the canvas.\n this.layers.select(layer.id);\n this.history.save();\n return layer;\n } catch (error) {\n this.events.emit('error', { message: 'Failed to add image', error });\n throw error;\n }\n }\n\n /** Replace an image source without changing its layer identity or visual transform. */\n async replaceImageSource(layerId: string, url: string): Promise<Layer> {\n const layer = this.layers.get(layerId);\n if (!layer || (layer.type !== 'image' && layer.type !== 'mask')) {\n throw new Error(`Image or mask layer not found: ${layerId}`);\n }\n if (layer.meta.pattern) {\n throw new Error('Clear the pattern before replacing the image source');\n }\n if (this.crop.activeLayerId() === layerId) this.crop.cancel();\n const previous = layer.fabricObject as FabricImage;\n try {\n const replacement = await FabricImage.fromURL(url, {}, { originX: 'left', originY: 'top' });\n replacement.set({\n left: previous.left,\n top: previous.top,\n originX: previous.originX,\n originY: previous.originY,\n width: previous.width,\n height: previous.height,\n cropX: previous.cropX,\n cropY: previous.cropY,\n scaleX: previous.scaleX,\n scaleY: previous.scaleY,\n angle: previous.angle,\n skewX: previous.skewX,\n skewY: previous.skewY,\n flipX: previous.flipX,\n flipY: previous.flipY,\n });\n replacement.filters = [...previous.filters];\n replacement.applyFilters();\n replacement.setCoords();\n this.layers.replaceObject(layerId, replacement);\n return layer;\n } catch (error) {\n this.events.emit('error', { message: 'Failed to replace image source', error });\n throw error;\n }\n }\n\n addText(text: string, options?: Partial<Record<string, unknown>>): Layer {\n const textbox = new Textbox(text, {\n fontSize: 32,\n fontFamily: 'Arial',\n fill: '#000000',\n width: 200,\n // v7 defaults origin to center; keep top-left placement.\n originX: 'left',\n originY: 'top',\n ...options,\n });\n const layer = this.layers.add('text', textbox as unknown as FabricObject);\n this.layers.select(layer.id);\n this.history.save();\n return layer;\n }\n\n addShape(plugin: ShapePlugin, options?: Record<string, unknown>): Layer {\n const obj = plugin.create(options);\n const layer = this.layers.add('shape', obj, plugin.name);\n this.layers.select(layer.id);\n this.history.save();\n return layer;\n }\n\n async addTemplate(\n template: TemplateDefinition,\n params: Record<string, string | number>,\n ): Promise<Layer> {\n const values: Record<string, string | number> = {};\n for (const parameter of template.parameters) {\n const value = params[parameter.key] ?? parameter.default;\n if (value === undefined) throw new Error(`Missing template parameter: ${parameter.key}`);\n if (parameter.type === 'number' && !Number.isFinite(Number(value))) {\n throw new Error(`Invalid number for template parameter: ${parameter.key}`);\n }\n if (parameter.type === 'color' && !isCssColor(value)) {\n throw new Error(`Invalid color for template parameter: ${parameter.key}`);\n }\n values[parameter.key] = value;\n }\n const resolved = sanitizeSvg(\n template.svg.replace(/\\{\\{(\\w+)(?:[|:]([^}]*))?\\}\\}/g, (token, key: string, fallback) => {\n const value = values[key] ?? fallback;\n return value === undefined ? token : escapeXml(value);\n }),\n );\n // A template is a starting point: it lands as the layers it is drawn from,\n // grouped, so its copy can be retyped instead of being a frozen picture.\n // `<textPath>` is unparseable by fabric, so those are rebuilt from their\n // parameters as one curved text layer.\n const specs = resolved.includes('<textPath')\n ? [textPathSpec(template, values)]\n : await explodeTemplateSvg(template, resolved, values);\n if (specs.length === 0) throw new Error('Template SVG contains no renderable objects');\n\n // One checkpoint for the whole insert: undo takes the template back out in\n // a single step, not layer by layer.\n return this.history.transaction(async () => {\n const created = specs.map((spec) => {\n const layer = this.layers.add(spec.type, spec.object, spec.name);\n // `false`: the transaction owns the history entry.\n if (spec.curve) this.curves.apply(layer.id, spec.curve, false);\n return layer;\n });\n\n // A one-layer template needs no group; two or more move as a unit.\n const layer =\n created.length === 1\n ? created[0]\n : ((await this.groupLayers(\n created.map((l) => l.id),\n template.name,\n )) ?? created[0]);\n\n layer.fabricObject.set({\n left: this.canvas.getWidth() / 2,\n top: this.canvas.getHeight() / 2,\n originX: 'center',\n originY: 'center',\n });\n layer.fabricObject.setCoords();\n this.layers.select(layer.id);\n this.canvas.requestRenderAll();\n this.history.save();\n return layer;\n });\n }\n\n removeLayer(id: string): void {\n if (this.crop.activeLayerId() === id) this.crop.cancel();\n if (this.masks.activeLayerId() === id) {\n this.masks.detach(id);\n }\n if (this.layers.remove(id)) this.history.save();\n }\n\n selectLayer(id: string | null): void {\n this.layers.select(id);\n }\n\n /** Select several layers at once — what a panel's shift/⌘ click drives. */\n selectLayers(ids: string[]): void {\n this.layers.selectMany(ids);\n }\n\n getSelectedLayer(): Layer | null {\n const active = this.canvas.getActiveObject();\n if (!active) return null;\n return this.layers.findByObject(active) ?? null;\n }\n\n /** Mirror a layer along the given axis. */\n flipLayer(id: string, axis: 'horizontal' | 'vertical'): void {\n const layer = this.layers.get(id);\n if (!layer) return;\n const obj = layer.fabricObject;\n if (axis === 'horizontal') {\n obj.set('flipX', !obj.flipX);\n } else {\n obj.set('flipY', !obj.flipY);\n }\n obj.setCoords();\n this.canvas.requestRenderAll();\n this.history.save();\n }\n\n /** Clone a layer (offset slightly) and select the copy. */\n async duplicateLayer(id: string): Promise<Layer | null> {\n const layer = this.layers.get(id);\n if (!layer) return null;\n\n const clone = await layer.fabricObject.clone();\n clone.set({ left: (clone.left ?? 0) + 15, top: (clone.top ?? 0) + 15 });\n clone.setCoords();\n\n const copy = this.layers.add(layer.type, clone, `${layer.name} copy`);\n // Carry non-fabric metadata (e.g. pattern config) onto the copy.\n copy.meta = structuredClone(layer.meta);\n copy.visible = layer.visible;\n copy.locked = layer.locked;\n copy.opacity = layer.opacity;\n clone.set({\n visible: layer.visible,\n selectable: !layer.locked,\n evented: !layer.locked,\n opacity: layer.opacity,\n });\n // The copy carries the pattern config, so it needs its own tiling proxy —\n // the meta alone would leave a duplicated pattern rendering nothing.\n this.patterns.attachTo(copy);\n\n // Through the layer manager, not the canvas: fabric only emits selection\n // events for user interaction, so a panel would not follow a bare\n // `setActiveObject` and the copy would look unselected.\n this.layers.select(copy.id);\n this.canvas.requestRenderAll();\n this.history.save();\n return copy;\n }\n\n applyImageAdjustments(layerId: string, adjustments: ImageAdjustments): boolean {\n const layer = this.layers.get(layerId);\n if (!layer || layer.type !== 'image') return false;\n const image = layer.fabricObject as FabricImage;\n const previous = (layer.meta.imageAdjustments ?? {}) as ImageAdjustments;\n const next = { ...previous, ...adjustments };\n const clampAdjustment = (value: number | undefined, min = -1) => clamp(value ?? 0, min, 1);\n image.filters = [\n new filters.Brightness({ brightness: clampAdjustment(next.brightness) }),\n new filters.Contrast({ contrast: clampAdjustment(next.contrast) }),\n new filters.Saturation({ saturation: clampAdjustment(next.saturation) }),\n new filters.Blur({ blur: clampAdjustment(next.blur, 0) }),\n ];\n layer.meta.imageAdjustments = next;\n image.applyFilters();\n this.canvas.requestRenderAll();\n this.history.save();\n return true;\n }\n\n /**\n * Combine two or more layers into one group layer. Picking a group among them\n * **absorbs** it — its children join the new group and the old group record is\n * dropped — because groups are exactly one level deep.\n */\n async groupLayers(ids: string[], name = 'Group'): Promise<Layer | null> {\n const uniqueIds = [...new Set(ids)];\n const picked = uniqueIds\n .map((id) => this.layers.get(id))\n .filter((layer): layer is Layer => layer !== undefined && layer.parentId === null);\n if (picked.length < 2 || picked.length !== uniqueIds.length) return null;\n\n // Where the group belongs in the stack: exactly where its topmost member\n // sat. Appending instead would lift grouped background art above artwork it\n // was deliberately behind.\n const stack = this.layers.getAll();\n const topIndex = Math.max(...picked.map((layer) => stack.indexOf(layer)));\n const insertIndex = stack.slice(0, topIndex).filter((layer) => !picked.includes(layer)).length;\n\n return this.history.transaction(() => {\n const children: Layer[] = [];\n const objects: FabricObject[] = [];\n for (const layer of picked) {\n if (layer.type === 'group' && layer.children.length > 0) {\n // `removeAll` hands back objects with their absolute transform already\n // restored, so they can be re-grouped as they are.\n const inner = (layer.fabricObject as Group).removeAll();\n for (const [index, object] of inner.entries()) {\n object.setCoords();\n const child = layer.children[index];\n if (!child) continue;\n children.push(child);\n objects.push(object);\n }\n layer.children = [];\n this.layers.detach(layer.id);\n } else {\n children.push(layer);\n objects.push(layer.fabricObject);\n this.layers.detach(layer.id);\n }\n }\n\n const group = new Group(objects);\n const grouped = this.layers.add('group', group, name);\n this.layers.adoptChildren(grouped, children);\n this.layers.reorder(grouped.id, insertIndex);\n this.layers.select(grouped.id);\n this.history.save();\n return grouped;\n });\n }\n\n /** Split a group back into the layers it holds, in place. */\n async ungroupLayer(id: string): Promise<Layer[]> {\n const grouped = this.layers.get(id);\n if (!grouped || grouped.type !== 'group' || grouped.children.length === 0) return [];\n\n return this.history.transaction(() => {\n const restored = this.layers.explode(grouped);\n this.history.save();\n this.layers.select(restored[0]?.id ?? null);\n return restored;\n });\n }\n\n // ─── Serialization ──────────────────────────────────\n\n toJSON(): EditorState {\n return serializeEditor(this);\n }\n\n async fromJSON(state: EditorState): Promise<void> {\n const managedByHistory = this.history.isRestoring();\n if (!managedByHistory) {\n this.history.saveImmediate();\n this.history.pause();\n }\n try {\n await deserializeEditor(this, state);\n // Tiling is drawn by a render proxy, which is never serialized: rebuild\n // one per pattern layer. This also migrates states written by the old\n // engine, which baked the tiled bitmap into the layer itself.\n await this.patterns.rehydrateAll();\n // Mask stacks restore as plain clip groups; this re-pins the design overlay\n // and adopts any clip written before stacks existed.\n this.layerMasks.refreshAll();\n } catch (error) {\n if (!managedByHistory) {\n this.events.emit('error', { message: 'Failed to load editor state', error });\n }\n throw error;\n } finally {\n if (!managedByHistory) this.history.resume();\n }\n if (!managedByHistory) {\n this.history.clear();\n this.history.saveImmediate();\n }\n }\n\n // ─── Export ──────────────────────────────────────────\n\n async toPNG(options?: PngExportOptions): Promise<Blob> {\n return this.toRaster((options?.format ?? 'png') as 'png' | 'jpeg' | 'webp', options);\n }\n\n async toJPEG(options?: Omit<PngExportOptions, 'format'>): Promise<Blob> {\n return this.toRaster('jpeg', options);\n }\n\n async toWebP(options?: Omit<PngExportOptions, 'format'>): Promise<Blob> {\n return this.toRaster('webp', options);\n }\n\n /** Export one layer in document coordinates or at its native image resolution. */\n async exportLayer(id: string, options: SemanticExportOptions = {}): Promise<Blob> {\n const layer = this.layers.get(id);\n if (!layer) throw new Error(`Layer not found: ${id}`);\n try {\n if (options.resolution === 'source' && layer.fabricObject instanceof FabricImage) {\n const image = await layer.fabricObject.clone();\n image.set({\n left: 0,\n top: 0,\n originX: 'left',\n originY: 'top',\n scaleX: 1,\n scaleY: 1,\n angle: 0,\n flipX: false,\n flipY: false,\n });\n return await exportIsolatedPNG(this.canvas, [image], {\n ...options,\n width: image.width || 1,\n height: image.height || 1,\n cloneObjects: false,\n });\n }\n // A tiled layer draws through its proxy; its own object is invisible.\n return await exportIsolatedPNG(\n this.canvas,\n [layer.renderProxy ?? layer.fabricObject],\n options,\n );\n } catch (error) {\n this.events.emit('error', { message: `Failed to export layer: ${id}`, error });\n throw error;\n }\n }\n\n /** Export only the configured document background, excluding design layers. */\n async exportBackground(options: SemanticExportOptions = {}): Promise<Blob> {\n try {\n return await exportIsolatedPNG(this.canvas, [], {\n ...options,\n backgroundColor: this.designBackground,\n backgroundImage: this.designBackgroundImage,\n });\n } catch (error) {\n this.events.emit('error', { message: 'Failed to export background', error });\n throw error;\n }\n }\n\n private async toRaster(\n format: 'png' | 'jpeg' | 'webp',\n options?: PngExportOptions,\n ): Promise<Blob> {\n this.events.emit('export:start', { format });\n try {\n await this.fonts.ready();\n const blob = await this.withDesignBackground(() =>\n exportPNG(this.canvas, { ...options, format }),\n );\n this.events.emit('export:complete', { format });\n this.licensing.track(`export:${format}`);\n return blob;\n } catch (error) {\n this.events.emit('error', {\n message: isTaintedCanvasError(error)\n ? 'Canvas export was blocked by cross-origin image data; load remote images with CORS enabled'\n : `Failed to export ${format.toUpperCase()}`,\n error,\n });\n throw error;\n }\n }\n\n toSVG(): string {\n this.events.emit('export:start', { format: 'svg' });\n try {\n const svg = this.withDesignBackground(() => exportSVG(this.canvas));\n this.events.emit('export:complete', { format: 'svg' });\n this.licensing.track('export:svg');\n return svg;\n } catch (error) {\n this.events.emit('error', { message: 'Failed to export SVG', error });\n throw error;\n }\n }\n\n async toSVGAsync(options: SvgExportOptions = {}): Promise<string> {\n await this.fonts.ready();\n const svg = this.toSVG();\n if (options.embedFonts === false || this.fonts.getAll().length === 0) return svg;\n try {\n const css = await this.fonts.getEmbeddedCss();\n return svg.replace(/(<svg\\b[^>]*>)/i, `$1<defs><style>${css}</style></defs>`);\n } catch (error) {\n this.events.emit('error', { message: 'Failed to embed fonts in SVG', error });\n throw error;\n }\n }\n\n toDataURL(format: ImageFormat = 'png', multiplier = 1): string {\n return this.withDesignBackground(() => exportDataURL(this.canvas, format, multiplier));\n }\n\n /**\n * Export the print file: the design cropped to the mockup's print area, on\n * transparency. Without a print area this is the whole canvas, still\n * transparent — a print file never carries the design background.\n */\n async toPrintFile(options: PngExportOptions = {}): Promise<Blob> {\n await this.fonts.ready();\n try {\n const area = this.mockup?.printArea;\n const blob = area\n ? await exportPrintArea(this.canvas, area, options)\n : await exportIsolatedPNG(this.canvas, this.canvas.getObjects(), options);\n this.licensing.track(`export:print:${options.format ?? 'png'}`);\n return blob;\n } catch (error) {\n this.events.emit('error', { message: 'Failed to export print file', error });\n throw error;\n }\n }\n\n /** Export the current product-preview composite. Advanced warping is host-defined. */\n async toMockupImage(options: PngExportOptions = {}): Promise<Blob> {\n if (!this.mockup) throw new Error('No mockup is configured');\n await this.fonts.ready();\n try {\n const blob = await exportMockup(this.canvas, this.mockup, options);\n this.licensing.track(`export:mockup:${options.format ?? 'png'}`);\n return blob;\n } catch (error) {\n this.events.emit('error', { message: 'Failed to export mockup', error });\n throw error;\n }\n }\n\n /**\n * Run an export with the configured design background applied, even when a\n * mockup preview has forced the live canvas transparent — so exports reflect\n * the design, not the preview. Restores the preview state afterwards.\n */\n private withDesignBackground<T>(fn: () => T): T {\n if (!this.mockup) return fn();\n const previewBg = this.canvas.backgroundColor;\n const previewImage = this.canvas.backgroundImage;\n this.canvas.backgroundColor = this.designBackground;\n this.canvas.backgroundImage = this.designBackgroundImage ?? undefined;\n try {\n return fn();\n } finally {\n this.canvas.backgroundColor = previewBg;\n this.canvas.backgroundImage = previewImage;\n }\n }\n\n toPrintifyPositioning(): Record<string, PrintifyPositioning> {\n const result: Record<string, PrintifyPositioning> = {};\n const canvasW = this.canvas.getWidth();\n const canvasH = this.canvas.getHeight();\n\n const imageLayers = this.layers.getAll().filter((l) => l.type === 'image');\n\n if (imageLayers.length === 0) {\n result['front'] = { x: 0.5, y: 0.5, scale: 1, angle: 0 };\n return result;\n }\n\n for (const layer of imageLayers) {\n const obj = layer.fabricObject;\n const center = obj.getCenterPoint();\n const key = result[layer.name] ? `${layer.name}-${layer.id}` : layer.name;\n result[key] = {\n x: round2(center.x / canvasW),\n y: round2(center.y / canvasH),\n scale: round2(obj.scaleX ?? 1),\n angle: round2(obj.angle ?? 0),\n };\n }\n\n return result;\n }\n\n /** Provider-neutral, ID-stable placement data in 0..1 canvas coordinates. */\n toNormalizedPositioning(): NormalizedLayerPosition[] {\n const canvasWidth = this.canvas.getWidth();\n const canvasHeight = this.canvas.getHeight();\n return this.layers.getAll().map((layer) => {\n const object = layer.fabricObject;\n const center = object.getCenterPoint();\n const bounds = object.getBoundingRect();\n return {\n layerId: layer.id,\n name: layer.name,\n type: layer.type,\n centerX: round2(center.x / canvasWidth),\n centerY: round2(center.y / canvasHeight),\n width: round2(bounds.width / canvasWidth),\n height: round2(bounds.height / canvasHeight),\n scaleX: round2(object.scaleX ?? 1),\n scaleY: round2(object.scaleY ?? 1),\n angle: round2(object.angle ?? 0),\n };\n });\n }\n\n toProviderPositioning<T>(adapter: PositioningAdapter<T>): T {\n return adapter.map(this.toNormalizedPositioning(), {\n width: this.canvas.getWidth(),\n height: this.canvas.getHeight(),\n });\n }\n\n // ─── File Operations ────────────────────────────────\n\n async save(\n filename: string,\n format: 'png' | 'jpeg' | 'webp' | 'svg' | 'json',\n ): Promise<string | undefined> {\n if (!this.fileAdapter) return undefined;\n\n let data: Blob | string;\n if (format === 'png') {\n data = await this.toPNG();\n } else if (format === 'jpeg') {\n data = await this.toJPEG();\n } else if (format === 'webp') {\n data = await this.toWebP();\n } else if (format === 'svg') {\n data = await this.toSVGAsync();\n } else {\n data = JSON.stringify(this.toJSON(), null, 2);\n }\n\n try {\n return await this.fileAdapter.save(data, filename, format);\n } catch (error) {\n this.events.emit('error', { message: `Failed to save ${format}`, error });\n throw error;\n }\n }\n\n async uploadImage(file: File): Promise<ImageProviderResult | undefined> {\n if (!this.imageProvider?.upload) return undefined;\n try {\n return await this.imageProvider.upload(file);\n } catch (error) {\n this.events.emit('error', { message: 'Failed to upload image', error });\n throw error;\n }\n }\n\n async browseImages(): Promise<ImageProviderResult | null> {\n if (!this.imageProvider?.browse) return null;\n try {\n return await this.imageProvider.browse();\n } catch (error) {\n this.events.emit('error', { message: 'Failed to browse images', error });\n throw error;\n }\n }\n\n async searchImages(\n query: string,\n options?: ImageSearchOptions,\n ): Promise<ImageSearchResult | null> {\n if (!this.imageProvider?.search) return null;\n try {\n return await this.imageProvider.search(query, options);\n } catch (error) {\n this.events.emit('error', { message: 'Failed to search images', error });\n throw error;\n }\n }\n\n /** Track provider usage, then insert its hotlinked image as a normal layer. */\n async addProviderImage(\n image: ImageProviderResult,\n options?: Partial<Record<string, unknown>>,\n ): Promise<Layer> {\n try {\n await this.imageProvider?.trackUse?.(image);\n } catch (error) {\n this.events.emit('error', { message: 'Failed to record image use', error });\n throw error;\n }\n return this.addImage(image.url, options);\n }\n\n setFileAdapter(adapter: FileAdapter): void {\n this.fileAdapter = adapter;\n }\n\n setImageProvider(provider: ImageProvider): void {\n this.imageProvider = provider;\n }\n\n // ─── Canvas Operations ──────────────────────────────\n\n setBackground(color: string): void {\n this.designBackground = color;\n // Don't override the mockup's transparent preview; it will pick up the new\n // colour when the mockup is cleared.\n if (!this.mockup) {\n this.canvas.backgroundColor = color;\n this.canvas.requestRenderAll();\n }\n this.history.save();\n this.events.emit('canvas:modified', {});\n }\n\n getDesignBackground(): string {\n return this.designBackground;\n }\n\n getDesignBackgroundImage(): FabricObject | null {\n return this.designBackgroundImage;\n }\n\n getBackgroundImageOptions(): SerializedBackgroundImageOptions | null {\n return this.backgroundImageOptions ? { ...this.backgroundImageOptions } : null;\n }\n\n async setBackgroundImage(\n url: string | null,\n options: BackgroundImageOptions = {},\n ): Promise<void> {\n if (url === null) {\n this.setBackgroundImageObject(null);\n return;\n }\n try {\n const image = await FabricImage.fromURL(\n url,\n { crossOrigin: options.crossOrigin ?? null, signal: options.signal },\n { originX: 'left', originY: 'top' },\n );\n const width = image.width || 1;\n const height = image.height || 1;\n const canvasWidth = this.canvas.getWidth();\n const canvasHeight = this.canvas.getHeight();\n const fit = options.fit ?? 'cover';\n const sx = canvasWidth / width;\n const sy = canvasHeight / height;\n const scaleX =\n fit === 'stretch' ? sx : fit === 'contain' ? Math.min(sx, sy) : Math.max(sx, sy);\n const scaleY = fit === 'stretch' ? sy : scaleX;\n image.set({\n left: (canvasWidth - width * scaleX) / 2,\n top: (canvasHeight - height * scaleY) / 2,\n scaleX,\n scaleY,\n opacity: clamp(options.opacity ?? 1, 0, 1),\n selectable: false,\n evented: false,\n });\n const serializableOptions = { ...options };\n delete serializableOptions.signal;\n this.setBackgroundImageObject(image, true, serializableOptions);\n } catch (error) {\n this.events.emit('error', { message: 'Failed to set background image', error });\n throw error;\n }\n }\n\n /** Used by state restoration and advanced integrations with an existing Fabric object. */\n setBackgroundImageObject(\n image: FabricObject | null,\n save = true,\n options: SerializedBackgroundImageOptions | null = null,\n ): void {\n this.designBackgroundImage = image;\n this.backgroundImageOptions = image ? options : null;\n this.canvas.backgroundImage = this.mockup ? undefined : (image ?? undefined);\n this.canvas.requestRenderAll();\n if (save) this.history.save();\n this.events.emit('canvas:modified', {});\n }\n\n setTransparentBackground(): void {\n this.setBackground('');\n }\n\n resize(width: number, height: number, options: ResizeOptions = {}): void {\n const widthPx = this.units.toPixels(width);\n const heightPx = this.units.toPixels(height);\n const oldWidth = this.canvas.getWidth();\n const oldHeight = this.canvas.getHeight();\n const scaleContent = options.scaleContent ?? true;\n if (scaleContent && oldWidth > 0 && oldHeight > 0) {\n const sx = widthPx / oldWidth;\n const sy = heightPx / oldHeight;\n for (const layer of this.layers.getAll()) {\n const object = layer.fabricObject;\n object.set({\n left: (object.left ?? 0) * sx,\n top: (object.top ?? 0) * sy,\n scaleX: (object.scaleX ?? 1) * sx,\n scaleY: (object.scaleY ?? 1) * sy,\n });\n object.setCoords();\n }\n if (this.designBackgroundImage) {\n this.designBackgroundImage.set({\n left: (this.designBackgroundImage.left ?? 0) * sx,\n top: (this.designBackgroundImage.top ?? 0) * sy,\n scaleX: (this.designBackgroundImage.scaleX ?? 1) * sx,\n scaleY: (this.designBackgroundImage.scaleY ?? 1) * sy,\n });\n this.designBackgroundImage.setCoords();\n }\n }\n this.canvas.setDimensions({ width: widthPx, height: heightPx });\n this.patterns.syncArea();\n this.canvas.requestRenderAll();\n this.history.save();\n this.events.emit('canvas:modified', {});\n }\n\n /** Effective source resolution for an image at its current physical size. */\n getImageDpi(layerId: string): number | null {\n const layer = this.layers.get(layerId);\n if (!layer || layer.type !== 'image') return null;\n const image = layer.fabricObject as FabricImage;\n const sourcePixels = image.width ?? 0;\n const displayedPixels = image.getScaledWidth();\n if (sourcePixels <= 0 || displayedPixels <= 0) return null;\n return round2(sourcePixels / (displayedPixels / this.units.getDpi()));\n }\n\n validateImageDpi(minimumDpi = 300): DpiIssue[] {\n return this.layers\n .getAll()\n .filter((layer) => layer.type === 'image' && !layer.meta.pattern)\n .flatMap((layer) => {\n const effectiveDpi = this.getImageDpi(layer.id);\n return effectiveDpi !== null && effectiveDpi < minimumDpi\n ? [{ layerId: layer.id, layerName: layer.name, effectiveDpi, minimumDpi }]\n : [];\n });\n }\n\n /** Render a small data-URL preview without changing document dimensions. */\n toThumbnail(maxWidth = 320, maxHeight = 320, format: ImageFormat = 'png'): string {\n const multiplier = Math.min(\n 1,\n maxWidth / this.canvas.getWidth(),\n maxHeight / this.canvas.getHeight(),\n );\n return this.toDataURL(format, multiplier);\n }\n\n bringToFront(id: string): boolean {\n return this.layers.reorder(id, this.layers.count() - 1);\n }\n\n sendToBack(id: string): boolean {\n return this.layers.reorder(id, 0);\n }\n\n bringForward(id: string): boolean {\n const index = this.layers.getAll().findIndex((layer) => layer.id === id);\n return index >= 0 && this.layers.reorder(id, index + 1);\n }\n\n sendBackward(id: string): boolean {\n const index = this.layers.getAll().findIndex((layer) => layer.id === id);\n return index >= 0 && this.layers.reorder(id, index - 1);\n }\n\n // ─── Zoom ───────────────────────────────────────────\n //\n // Zoom is a *display* transform (the view layer CSS-scales the canvas), not a\n // fabric viewport zoom — fabric's setZoom bakes into toDataURL/toSVG and would\n // corrupt exports. The editor only tracks the level and emits an event.\n\n setZoom(level: number): void {\n const next = clamp(round2(level), MIN_ZOOM, MAX_ZOOM);\n if (next === this.zoomLevel) return;\n this.zoomLevel = next;\n // Handles are sized in screen pixels — re-counter-scale them for the new\n // display zoom, or they would grow and shrink with the artwork.\n this.refreshSelectionStyle();\n this.events.emit('zoom:changed', { zoom: next });\n }\n\n /** @deprecated use setZoom — kept for backward compatibility. */\n zoom(level: number): void {\n this.setZoom(level);\n }\n\n getZoom(): number {\n return this.zoomLevel;\n }\n\n zoomIn(step = 0.1): void {\n this.setZoom(this.zoomLevel + step);\n }\n\n zoomOut(step = 0.1): void {\n this.setZoom(this.zoomLevel - step);\n }\n\n resetZoom(): void {\n this.setZoom(1);\n }\n\n /** Fit the canvas inside a viewport (in px), accounting for padding. */\n zoomToFit(viewportWidth: number, viewportHeight: number, padding = 0): void {\n const w = this.canvas.getWidth();\n const h = this.canvas.getHeight();\n if (w <= 0 || h <= 0) return;\n const sx = (viewportWidth - padding * 2) / w;\n const sy = (viewportHeight - padding * 2) / h;\n this.setZoom(Math.min(sx, sy));\n }\n\n /** Zoom until the current selection fills the artboard viewport. */\n zoomToSelection(padding = 24): void {\n const active = this.canvas.getActiveObject();\n if (!active) return;\n active.setCoords();\n const bounds = active.getBoundingRect();\n if (bounds.width <= 0 || bounds.height <= 0) return;\n this.setZoom(\n Math.min(\n (this.canvas.getWidth() - padding * 2) / bounds.width,\n (this.canvas.getHeight() - padding * 2) / bounds.height,\n ),\n );\n }\n\n // ─── Patterns ───────────────────────────────────────\n\n applyPattern(layerId: string, config: PatternConfig): Promise<void> {\n return this.patterns.apply(layerId, config);\n }\n\n clearPattern(layerId: string): Promise<void> {\n return this.patterns.disable(layerId);\n }\n\n // ─── Text curve ─────────────────────────────────────\n\n applyTextCurve(layerId: string, config: Partial<TextCurveConfig>): boolean {\n return this.curves.apply(layerId, config);\n }\n\n clearTextCurve(layerId: string): boolean {\n return this.curves.clear(layerId);\n }\n\n getTextCurve(layerId: string): TextCurveConfig | null {\n return this.curves.get(layerId);\n }\n\n // ─── Mask presets ───────────────────────────────────\n\n applyMaskPreset(layerId: string, id: MaskPresetId | null): boolean {\n return this.maskPresets.apply(layerId, id);\n }\n\n clearMaskPreset(layerId: string): boolean {\n return this.maskPresets.clear(layerId);\n }\n\n getMaskPreset(layerId: string): MaskPresetId | null {\n return this.maskPresets.get(layerId);\n }\n\n // ─── Layer transform ────────────────────────────────\n\n /**\n * Constrain a layer to its current proportions. Persisted on the layer so a\n * reopened design still resizes the way it was set up to.\n */\n setLayerAspectLock(layerId: string, locked: boolean): boolean {\n const layer = this.layers.get(layerId);\n if (!layer) return false;\n applyAspectLock(layer.fabricObject, locked);\n if (locked) layer.meta.lockAspect = true;\n else delete layer.meta.lockAspect;\n this.canvas.requestRenderAll();\n this.events.emit('layer:modified', { layerId });\n this.history.save();\n return true;\n }\n\n getLayerAspectLock(layerId: string): boolean {\n return this.layers.get(layerId)?.meta.lockAspect === true;\n }\n\n /** Re-apply every stored aspect lock — control visibility is not serialized. */\n restoreAspectLocks(): void {\n for (const layer of this.layers.getAll()) {\n if (layer.meta.lockAspect) applyAspectLock(layer.fabricObject, true);\n }\n }\n\n /** Drop scale, rotation, skew and flips; the layer stays where it is. */\n resetLayerTransform(layerId: string): boolean {\n const layer = this.layers.get(layerId);\n if (!layer) return false;\n resetTransform(layer.fabricObject);\n this.canvas.requestRenderAll();\n this.events.emit('layer:modified', { layerId });\n this.history.save();\n return true;\n }\n\n // ─── Shadow ─────────────────────────────────────────\n\n setLayerShadow(layerId: string, config: Partial<LayerShadowConfig>): boolean {\n const layer = this.layers.get(layerId);\n if (!layer) return false;\n applyLayerShadow(layer.fabricObject, config);\n layer.fabricObject.dirty = true;\n this.canvas.requestRenderAll();\n this.events.emit('layer:modified', { layerId });\n this.history.save();\n return true;\n }\n\n getLayerShadow(layerId: string): LayerShadowConfig | null {\n const layer = this.layers.get(layerId);\n return layer ? readLayerShadow(layer.fabricObject) : null;\n }\n\n // ─── Mockup (preview-only) ──────────────────────────\n\n /**\n * Show (or clear) the product preview. Pass `history: false` for preview-only\n * changes such as swapping a colourway — those are not design edits and\n * should not fill the undo stack.\n */\n setMockup(mockup: MockupConfig | null, options: { history?: boolean } = {}): void {\n this.mockup = mockup;\n // The mockup renders behind the design, so the canvas must be transparent\n // while it is shown; restore the configured background when it is cleared.\n this.canvas.backgroundColor = mockup ? '' : this.designBackground;\n this.canvas.backgroundImage = mockup ? undefined : (this.designBackgroundImage ?? undefined);\n this.canvas.requestRenderAll();\n this.events.emit('mockup:changed', { mockup });\n if (options.history !== false) this.history.save();\n }\n\n clearMockup(): void {\n this.setMockup(null);\n }\n\n getMockup(): MockupConfig | null {\n return this.mockup;\n }\n\n // ─── Cleanup ────────────────────────────────────────\n\n dispose(): void {\n this.masks.dispose();\n this.layerMasks.dispose();\n this.snapping.dispose();\n this.crop.dispose();\n this.history.dispose();\n this.patterns.dispose();\n this.curves.dispose();\n this.events.removeAllListeners();\n this.canvas.dispose();\n }\n\n // ─── Selection style ────────────────────────────────\n\n /** Current look of the selection frame and its handles. */\n getSelectionStyle(): SelectionStyle {\n return { ...this.selectionStyle };\n }\n\n /**\n * Restyles the selection frame and resize handles. Sizes are in screen\n * pixels and stay constant across zoom levels (see `SelectionStyle`).\n */\n setSelectionStyle(style: Partial<SelectionStyle>): void {\n this.selectionStyle = { ...this.selectionStyle, ...style };\n this.refreshSelectionStyle();\n }\n\n private refreshSelectionStyle(): void {\n applySelectionStyle(this.canvas, this.selectionStyle, this.zoomLevel);\n }\n\n // ─── Private ────────────────────────────────────────\n\n private setupCanvasEvents(): void {\n // Objects arrive from adds, restores and undo alike — style them here so\n // there is a single place that can't be forgotten.\n this.canvas.on('object:added', (e) => {\n if (e.target) applyObjectSelectionStyle(e.target, this.selectionStyle, this.zoomLevel);\n });\n\n // The active selection is a transient group fabric creates on the fly; it\n // never passes through 'object:added'.\n const styleActive = () => {\n const active = this.canvas.getActiveObject();\n if (active) applyObjectSelectionStyle(active, this.selectionStyle, this.zoomLevel);\n };\n\n this.canvas.on('object:modified', (e) => {\n if (!e.target) return;\n const layer = this.layers.findByObject(e.target);\n if (layer) {\n this.events.emit('layer:modified', { layerId: layer.id });\n this.history.save();\n }\n });\n\n this.canvas.on('selection:created', (e) => {\n styleActive();\n const selected = (e.selected ?? [])\n .map((obj) => this.layers.findByObject(obj)?.id)\n .filter((id): id is string => id !== undefined);\n this.events.emit('selection:changed', { selected });\n });\n\n this.canvas.on('selection:updated', (e) => {\n styleActive();\n const selected = (e.selected ?? [])\n .map((obj) => this.layers.findByObject(obj)?.id)\n .filter((id): id is string => id !== undefined);\n this.events.emit('selection:changed', { selected });\n });\n\n this.canvas.on('selection:cleared', () => {\n this.events.emit('selection:changed', { selected: [] });\n });\n }\n}\n","type EventHandler<T> = (data: T) => void;\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport class EventEmitter<TEvents extends {} = Record<string, unknown>> {\n private listeners = new Map<keyof TEvents, Set<EventHandler<unknown>>>();\n\n on<K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(handler as EventHandler<unknown>);\n }\n\n off<K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>): void {\n this.listeners.get(event)?.delete(handler as EventHandler<unknown>);\n }\n\n once<K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>): void {\n const wrapped: EventHandler<TEvents[K]> = (data) => {\n this.off(event, wrapped);\n handler(data);\n };\n this.on(event, wrapped);\n }\n\n emit<K extends keyof TEvents>(event: K, data: TEvents[K]): void {\n const handlers = this.listeners.get(event);\n if (!handlers) return;\n for (const handler of handlers) {\n handler(data);\n }\n }\n\n removeAllListeners(event?: keyof TEvents): void {\n if (event) {\n this.listeners.delete(event);\n } else {\n this.listeners.clear();\n }\n }\n}\n","import { ActiveSelection, Group } from 'fabric';\nimport type { Canvas, FabricObject } from 'fabric';\nimport type { LayerData, LayerMeta, LayerType, SerializedLayer } from './types';\nimport type { EditorEvents } from './types';\nimport type { EventEmitter } from './events';\nimport { generateId } from './utils/id';\n\nexport class Layer {\n readonly id: string;\n readonly type: LayerType;\n name: string;\n visible: boolean;\n locked: boolean;\n opacity: number;\n /** Non-fabric data (e.g. pattern config) that must persist with the layer. */\n meta: LayerMeta;\n fabricObject: FabricObject;\n /**\n * Stand-in object drawn in place of `fabricObject` (the tiled pattern). It is\n * part of the canvas but never part of the document: it is not serialized, and\n * the layer's real object stays the one every editor API talks to.\n */\n renderProxy: FabricObject | null;\n /**\n * Layers nested inside this one, in draw order. Only a `group` layer has any:\n * their fabric objects live inside this layer's fabric `Group`, not on the\n * canvas, which is why the manager keeps them off the canvas stack.\n */\n children: Layer[];\n /** Group this layer sits inside, or null when it is on the canvas stack. */\n parentId: string | null;\n\n constructor(type: LayerType, fabricObject: FabricObject, name?: string, id?: string) {\n this.id = id ?? generateId();\n this.type = type;\n this.name = name ?? `${type}-${this.id.slice(0, 4)}`;\n this.visible = true;\n this.locked = false;\n this.opacity = 1;\n this.meta = {};\n this.fabricObject = fabricObject;\n this.renderProxy = null;\n this.children = [];\n this.parentId = null;\n\n (this.fabricObject as FabricObject & { _layerId: string })._layerId = this.id;\n }\n\n private hasMeta(): boolean {\n return Object.keys(this.meta).length > 0;\n }\n\n toData(): LayerData {\n return {\n id: this.id,\n type: this.type,\n name: this.name,\n visible: this.visible,\n locked: this.locked,\n opacity: this.opacity,\n ...(this.hasMeta() ? { meta: this.meta } : {}),\n ...(this.children.length > 0 ? { children: this.children.map((c) => c.toData()) } : {}),\n };\n }\n\n serialize(): SerializedLayer {\n return {\n ...this.toData(),\n // A group's own object already carries its children's geometry, so the\n // child records in `toData` stay identity-only — nothing is duplicated.\n fabricObject: this.fabricObject.toObject() as Record<string, unknown>,\n };\n }\n}\n\nexport class LayerManager {\n private layers: Layer[] = [];\n private onPropertyChanged?: () => void;\n\n constructor(\n private canvas: Canvas,\n private events: EventEmitter<EditorEvents>,\n ) {}\n\n setHistoryCallback(callback: () => void): void {\n this.onPropertyChanged = callback;\n }\n\n add(type: LayerType, fabricObject: FabricObject, name?: string, id?: string): Layer {\n const layer = new Layer(type, fabricObject, name, id);\n this.layers.push(layer);\n this.canvas.add(fabricObject);\n this.events.emit('layer:added', { layer: layer.toData() });\n this.emitChanged();\n return layer;\n }\n\n remove(id: string): boolean {\n const layer = this.get(id);\n if (!layer) return false;\n\n if (layer.parentId) {\n const parent = this.get(layer.parentId);\n if (!parent) return false;\n (parent.fabricObject as Group).remove(layer.fabricObject);\n parent.children = parent.children.filter((c) => c.id !== id);\n layer.parentId = null;\n this.events.emit('layer:removed', { layerId: id });\n // A group of one lies in the panel and traps transforms: the survivor\n // goes back on the canvas stack instead of sitting alone in a group.\n if (parent.children.length < 2) this.dissolve(parent);\n this.emitChanged();\n this.onPropertyChanged?.();\n this.canvas.requestRenderAll();\n return true;\n }\n\n const index = this.layers.findIndex((l) => l.id === id);\n if (index === -1) return false;\n this.canvas.remove(layer.fabricObject);\n if (layer.renderProxy) this.canvas.remove(layer.renderProxy);\n this.layers.splice(index, 1);\n this.events.emit('layer:removed', { layerId: id });\n this.emitChanged();\n this.onPropertyChanged?.();\n return true;\n }\n\n /**\n * Take a top-level layer off the canvas stack **without** disposing it — it is\n * about to become a group's child, so its object has to stay alive.\n */\n detach(id: string): Layer | undefined {\n const index = this.layers.findIndex((l) => l.id === id);\n if (index === -1) return undefined;\n const [layer] = this.layers.splice(index, 1);\n this.canvas.remove(layer.fabricObject);\n if (layer.renderProxy) this.canvas.remove(layer.renderProxy);\n return layer;\n }\n\n /** Put a group's children back on the canvas stack and drop the group. */\n explode(group: Layer): Layer[] {\n const children = [...group.children];\n this.dissolve(group);\n this.events.emit('layer:removed', { layerId: group.id });\n this.emitChanged();\n this.onPropertyChanged?.();\n this.canvas.requestRenderAll();\n return children;\n }\n\n /**\n * Empty a group onto the canvas stack, in the group's own place, and drop the\n * group record. `removeAll` restores each child's absolute transform, so the\n * group's matrix must NOT be re-applied on top of it.\n */\n private dissolve(group: Layer): void {\n const objects = (group.fabricObject as Group).removeAll();\n const at = this.layers.findIndex((l) => l.id === group.id);\n const survivors = group.children;\n group.children = [];\n for (const [index, object] of objects.entries()) {\n object.setCoords();\n const child = survivors[index];\n if (!child) continue;\n child.parentId = null;\n this.layers.splice(at + index, 0, child);\n this.canvas.add(object);\n if (child.renderProxy) this.canvas.add(child.renderProxy);\n }\n this.canvas.remove(group.fabricObject);\n this.layers = this.layers.filter((l) => l.id !== group.id);\n this.syncZOrder();\n }\n\n /**\n * Move existing layer records under a group, and announce the new tree.\n * Assigning `group.children` directly emits nothing, and the reorder that\n * follows a grouping is a no-op whenever the group already sits where it\n * belongs — leaving `layers:changed` describing a childless group, so a panel\n * built on it renders the group with nothing inside.\n */\n adoptChildren(group: Layer, children: Layer[]): void {\n for (const child of children) child.parentId = group.id;\n group.children = children;\n this.emitChanged();\n this.onPropertyChanged?.();\n }\n\n /**\n * Re-attach child records to an enlivened group. `data[i]` describes\n * `group._objects[i]` — the order fabric serializes and restores them in. A\n * missing record still becomes a child, so a hand-edited state cannot drop\n * artwork off the canvas.\n */\n adoptGroupChildren(group: Layer, data: LayerData[]): void {\n const objects = (group.fabricObject as Group).getObjects();\n group.children = objects.map((object, index) => {\n const record = data[index];\n const child = new Layer(record?.type ?? 'shape', object, record?.name, record?.id);\n child.parentId = group.id;\n if (record?.meta) child.meta = structuredClone(record.meta);\n if (record && !record.visible) {\n child.visible = false;\n object.visible = false;\n }\n if (record?.locked) {\n child.locked = true;\n object.selectable = false;\n object.evented = false;\n }\n if (record && record.opacity !== 1) {\n child.opacity = record.opacity;\n object.opacity = record.opacity;\n }\n return child;\n });\n this.emitChanged();\n }\n\n /** Replace a layer's render object while preserving its immutable ID and panel state. */\n replaceObject(id: string, fabricObject: FabricObject): boolean {\n const layer = this.get(id);\n if (!layer || layer.fabricObject === fabricObject) return false;\n const previous = layer.fabricObject;\n const stackIndex = this.canvas.getObjects().indexOf(previous);\n const wasActive = this.canvas.getActiveObject() === previous;\n this.canvas.remove(previous);\n layer.fabricObject = fabricObject;\n (fabricObject as FabricObject & { _layerId: string })._layerId = id;\n fabricObject.set({\n visible: layer.visible,\n opacity: layer.opacity,\n selectable: !layer.locked,\n evented: !layer.locked,\n });\n this.canvas.insertAt(Math.max(0, stackIndex), fabricObject);\n // A proxied layer draws through its proxy; the replacement takes the\n // source's place — invisible, but still the thing the panels talk to.\n if (layer.renderProxy) {\n fabricObject.set({ opacity: 0 });\n this.syncZOrder();\n }\n if (wasActive) this.canvas.setActiveObject(fabricObject);\n this.canvas.requestRenderAll();\n this.events.emit('layer:modified', { layerId: id });\n this.emitChanged();\n this.onPropertyChanged?.();\n return true;\n }\n\n /**\n * Attach (or clear) the object drawn in place of a layer's own object. The\n * proxy tracks the layer's stacking position, visibility and opacity, and is\n * removed with the layer — it must never outlive or drift from its source.\n */\n setRenderProxy(id: string, proxy: FabricObject | null): void {\n const layer = this.get(id);\n if (!layer || layer.renderProxy === proxy) return;\n if (layer.renderProxy) this.canvas.remove(layer.renderProxy);\n layer.renderProxy = proxy;\n if (proxy) {\n // Tagged with the layer id so canvas selection resolves to this layer —\n // the proxy is what the user clicks and drags once it is in place.\n (proxy as FabricObject & { _layerId: string })._layerId = id;\n proxy.set({\n visible: layer.visible,\n opacity: layer.opacity,\n selectable: !layer.locked,\n evented: !layer.locked,\n });\n this.canvas.add(proxy);\n this.syncZOrder();\n }\n this.canvas.requestRenderAll();\n this.emitChanged();\n }\n\n /**\n * Re-stack every canvas object to match layer order, keeping each proxy\n * directly above the source it stands in for. Canvas indices can't be derived\n * from layer indices once proxies are in the array, so the order is rebuilt\n * front-to-back instead of computed.\n */\n private syncZOrder(): void {\n for (const layer of this.layers) {\n this.canvas.bringObjectToFront(layer.fabricObject);\n if (layer.renderProxy) this.canvas.bringObjectToFront(layer.renderProxy);\n }\n }\n\n /** The list a layer lives in: its group's children, or the canvas stack. */\n private siblingsOf(layer: Layer): Layer[] {\n if (!layer.parentId) return this.layers;\n return this.get(layer.parentId)?.children ?? this.layers;\n }\n\n reorder(id: string, newIndex: number): boolean {\n const target = this.get(id);\n if (!target) return false;\n const list = this.siblingsOf(target);\n const oldIndex = list.indexOf(target);\n if (oldIndex === -1) return false;\n if (!Number.isFinite(newIndex)) return false;\n const clamped = Math.max(0, Math.min(list.length - 1, Math.round(newIndex)));\n if (oldIndex === clamped) return false;\n const [layer] = list.splice(oldIndex, 1);\n list.splice(clamped, 0, layer);\n if (layer.parentId) {\n // Inside a group the draw order is the group's own object order; the\n // canvas stack has no say in it.\n const group = this.get(layer.parentId)?.fabricObject as Group | undefined;\n if (group) {\n group.remove(layer.fabricObject);\n group.insertAt(clamped, layer.fabricObject);\n }\n } else {\n this.syncZOrder();\n }\n this.events.emit('layer:reordered', { layerIds: list.map((l) => l.id) });\n this.emitChanged();\n this.onPropertyChanged?.();\n return true;\n }\n\n select(id: string | null): void {\n if (id === null) {\n this.canvas.discardActiveObject();\n this.exitGroups();\n } else {\n const layer = this.get(id);\n if (layer) {\n // A child is only selectable while its group is interactive: fabric\n // otherwise routes every hit to the group and `setActiveObject` on the\n // child leaves the handles on nothing.\n if (layer.parentId) this.enterGroup(layer.parentId);\n else this.exitGroups();\n // Select what the user can actually grab: a proxied layer's own object\n // is invisible and inert, and framing it would put the handles on\n // nothing. See `LayerManager.setRenderProxy`.\n this.canvas.setActiveObject(layer.renderProxy ?? layer.fabricObject);\n }\n }\n this.canvas.requestRenderAll();\n this.events.emit('layer:selected', { layerId: id });\n // Fabric only fires selection:* on user interaction; mirror programmatic\n // selection so React selection state (useSelection) stays in sync.\n const selected = id && this.get(id) ? [id] : [];\n this.events.emit('selection:changed', { selected });\n }\n\n /** Drill into a group so its children can be selected and clicked. */\n private enterGroup(groupId: string): void {\n const parent = this.get(groupId);\n if (!parent) return;\n const group = parent.fabricObject as Group & { interactive: boolean };\n group.subTargetCheck = true;\n group.interactive = true;\n }\n\n /** Leave every entered group — selecting anything else is done drilling in. */\n exitGroups(): void {\n for (const layer of this.layers) {\n if (layer.type !== 'group') continue;\n const group = layer.fabricObject as Group & { interactive: boolean };\n if (group.interactive) group.interactive = false;\n }\n }\n\n /**\n * Select several layers at once, as one fabric `ActiveSelection`. Children are\n * skipped: a selection spanning in and out of a group has no single transform.\n */\n selectMany(ids: string[]): void {\n const layers = ids.flatMap((id) => {\n const layer = this.get(id);\n return layer && !layer.parentId ? [layer] : [];\n });\n if (layers.length === 0) return this.select(null);\n if (layers.length === 1) return this.select(layers[0].id);\n this.canvas.discardActiveObject();\n this.exitGroups();\n const selection = new ActiveSelection(\n layers.map((l) => l.renderProxy ?? l.fabricObject),\n { canvas: this.canvas },\n );\n this.canvas.setActiveObject(selection);\n this.canvas.requestRenderAll();\n // Fabric emits selection events for user interaction only; a programmatic\n // multi-select has to mirror its own, like `select` does.\n this.events.emit('selection:changed', { selected: layers.map((l) => l.id) });\n }\n\n /** Depth-first over the whole tree, each layer before its children. */\n private *walk(layers: Layer[] = this.layers): Generator<Layer> {\n for (const layer of layers) {\n yield layer;\n if (layer.children.length > 0) yield* this.walk(layer.children);\n }\n }\n\n get(id: string): Layer | undefined {\n for (const layer of this.walk()) if (layer.id === id) return layer;\n return undefined;\n }\n\n /** Top-level layers only — the canvas stack. Children hang off their group. */\n getAll(): Layer[] {\n return [...this.layers];\n }\n\n /** Top-level layers, each carrying its children: what the layer panel renders. */\n getTree(): LayerData[] {\n return this.layers.map((l) => l.toData());\n }\n\n findByObject(obj: FabricObject): Layer | undefined {\n const layerId = (obj as FabricObject & { _layerId?: string })._layerId;\n if (layerId) return this.get(layerId);\n for (const layer of this.walk()) if (layer.fabricObject === obj) return layer;\n return undefined;\n }\n\n setVisibility(id: string, visible: boolean): void {\n const layer = this.get(id);\n if (!layer) return;\n if (layer.visible === visible) return;\n layer.visible = visible;\n layer.fabricObject.visible = visible;\n if (layer.renderProxy) layer.renderProxy.visible = visible;\n this.canvas.requestRenderAll();\n this.emitChanged();\n this.onPropertyChanged?.();\n }\n\n setLocked(id: string, locked: boolean): void {\n const layer = this.get(id);\n if (!layer) return;\n if (layer.locked === locked) return;\n layer.locked = locked;\n // A proxied layer interacts through its proxy; its own object stays inert.\n const target = layer.renderProxy ?? layer.fabricObject;\n target.selectable = !locked;\n target.evented = !locked;\n this.canvas.requestRenderAll();\n this.emitChanged();\n this.onPropertyChanged?.();\n }\n\n setOpacity(id: string, opacity: number): void {\n const layer = this.get(id);\n if (!layer || !Number.isFinite(opacity)) return;\n const next = Math.max(0, Math.min(1, opacity));\n if (layer.opacity === next) return;\n layer.opacity = next;\n // A proxied layer's own object is parked at opacity 0 (invisible, still\n // selectable) — the opacity the user set belongs to what is actually drawn.\n if (layer.renderProxy) layer.renderProxy.opacity = next;\n else layer.fabricObject.opacity = next;\n this.canvas.requestRenderAll();\n this.emitChanged();\n this.onPropertyChanged?.();\n }\n\n setName(id: string, name: string): void {\n const layer = this.get(id);\n if (!layer) return;\n if (layer.name === name) return;\n layer.name = name;\n this.emitChanged();\n this.onPropertyChanged?.();\n }\n\n /**\n * Patch a layer's host metadata. A key whose value is `undefined` is removed.\n *\n * `meta` is part of `LayerData` and is serialized, so a host that assigns\n * `layer.meta.x` directly gets neither of the two things every other setter\n * here provides: `layers:changed` (so `useLayers()` keeps returning the old\n * meta) and the history checkpoint (so an undo silently reverts the write —\n * the state IS versioned, it was just never committed at the moment it\n * changed). Going through this method is what makes metadata behave like\n * every other layer property.\n */\n setMeta(id: string, patch: LayerMeta): void {\n const layer = this.get(id);\n if (!layer) return;\n\n const next: LayerMeta = { ...layer.meta };\n let changed = false;\n for (const [key, value] of Object.entries(patch)) {\n if (value === undefined) {\n if (key in next) {\n delete next[key];\n changed = true;\n }\n continue;\n }\n if (next[key] !== value) changed = true;\n next[key] = value;\n }\n if (!changed) return;\n\n layer.meta = next;\n this.emitChanged();\n this.onPropertyChanged?.();\n }\n\n clear(): void {\n for (const layer of this.layers) {\n this.canvas.remove(layer.fabricObject);\n if (layer.renderProxy) this.canvas.remove(layer.renderProxy);\n // Children go with their group; a stale record would survive a restore.\n layer.children = [];\n }\n this.layers = [];\n this.emitChanged();\n }\n\n count(): number {\n return this.layers.length;\n }\n\n private emitChanged(): void {\n this.events.emit('layers:changed', {\n layers: this.layers.map((l) => l.toData()),\n });\n }\n}\n","import { nanoid } from 'nanoid';\n\nexport const generateId = (): string => nanoid(12);\n","import { Textbox, loadSVGFromString } from 'fabric';\nimport type { FabricObject } from 'fabric';\nimport type { TemplateDefinition, TextCurveConfig } from './types';\n\n/**\n * A template is a bootstrap, not a frozen picture: it is taken apart into the\n * layers it is drawn from, so every run of copy stays editable afterwards.\n */\nexport interface TemplateLayerSpec {\n type: 'text' | 'shape';\n name: string;\n object: FabricObject;\n /**\n * Baseline curve to apply once the layer exists (`<textPath>` templates).\n * Partial on purpose: a template states only the parameters it cares about\n * and `TextCurveManager.apply` normalizes the rest.\n */\n curve?: Partial<TextCurveConfig>;\n}\n\n/** Longest layer name taken from a literal run before it is elided. */\nconst NAME_MAX = 24;\n\ninterface ParsedText extends FabricObject {\n text: string;\n fontSize: number;\n fontFamily: string;\n fontWeight: string | number;\n fontStyle: Textbox['fontStyle'];\n textAlign: Textbox['textAlign'];\n charSpacing: number;\n lineHeight: number;\n}\n\nfunction isText(object: FabricObject): object is ParsedText {\n return typeof (object as { text?: unknown }).text === 'string';\n}\n\n/**\n * Resolved run → parameter label, read off the template's own source.\n *\n * The label is what makes a layer say \"Title\" instead of \"text-8fa1\"; matching\n * on the *resolved* value (not the placeholder) is what keeps it working when\n * the caller supplies its own parameter values.\n */\nfunction labelsByRun(\n template: TemplateDefinition,\n values: Record<string, string | number>,\n): Map<string, string> {\n const labels = new Map(template.parameters.map((p) => [p.key, p.label || p.key]));\n const byRun = new Map<string, string>();\n for (const match of template.svg.matchAll(/<text\\b[^>]*>([\\s\\S]*?)<\\/text>/g)) {\n const token = /\\{\\{(\\w+)(?:[|:]([^}]*))?\\}\\}/.exec(match[1]);\n if (!token) continue;\n const label = labels.get(token[1]);\n if (!label) continue;\n const resolved = String(values[token[1]] ?? token[2] ?? '').trim();\n if (resolved) byRun.set(resolved, label);\n }\n return byRun;\n}\n\nfunction textName(run: string, labels: Map<string, string>): string {\n const trimmed = run.trim();\n const label = labels.get(trimmed);\n if (label) return label;\n if (!trimmed) return 'Text';\n return trimmed.length > NAME_MAX ? `${trimmed.slice(0, NAME_MAX - 1)}…` : trimmed;\n}\n\nfunction shapeName(object: FabricObject): string {\n const id = (object as { id?: unknown }).id;\n if (typeof id === 'string' && id) return id;\n const type = object.type || 'shape';\n return type.charAt(0).toUpperCase() + type.slice(1);\n}\n\n/**\n * Rebuild a parsed `<text>` as the `Textbox` `addText` produces.\n *\n * Fabric parses SVG text into a `FabricText`, which the studio's text panel,\n * font picker and curve controls do not drive — a template's copy would look\n * editable and refuse to be edited. Placement, styling and glyphs carry over.\n */\nfunction toTextbox(text: ParsedText): FabricObject {\n const box = new Textbox(text.text, {\n left: text.left,\n top: text.top,\n originX: text.originX,\n originY: text.originY,\n angle: text.angle,\n scaleX: text.scaleX,\n scaleY: text.scaleY,\n fontSize: text.fontSize,\n fontFamily: text.fontFamily,\n fontWeight: text.fontWeight,\n fontStyle: text.fontStyle,\n textAlign: text.textAlign,\n charSpacing: text.charSpacing,\n lineHeight: text.lineHeight,\n fill: text.fill,\n stroke: text.stroke,\n strokeWidth: text.strokeWidth,\n opacity: text.opacity,\n // A Textbox wraps at its box width; size it to the run the template drew so\n // the authored copy never comes in pre-wrapped.\n width: Math.max(1, (text.width ?? 0) + 2),\n });\n return box as unknown as FabricObject;\n}\n\n/**\n * Curve a `<textPath>` template asks for.\n *\n * Fabric's SVG parser cannot read `<textPath>` at all, so these templates are\n * rebuilt from their parameters instead of parsed — the curve is the engine's\n * own, which keeps the text editable rather than rasterized.\n */\nexport function textPathCurve(\n template: TemplateDefinition,\n values: Record<string, string | number>,\n runWidth: number,\n): Partial<TextCurveConfig> {\n // `arc: 100` is the closed ring (see FULL_CIRCLE_ARC in text-curve.ts).\n if (template.id === 'circular-text') return { arc: 100, wave: 0 };\n if (template.id === 'wave-text') return { arc: 0, wave: 50 };\n // arcPathData builds its path with radius = width / sweep and\n // sweep = (arc / 100) · π, so this inverts the template's own radius.\n const radius = Number(values.radius ?? 200);\n if (!Number.isFinite(radius) || radius <= 0) return { arc: 0, wave: 0 };\n const arc = (100 * runWidth) / (Math.PI * radius);\n return { arc: Math.max(-100, Math.min(100, arc)), wave: 0 };\n}\n\n/** The single text layer a `<textPath>` template stands for. */\nexport function textPathSpec(\n template: TemplateDefinition,\n values: Record<string, string | number>,\n): TemplateLayerSpec {\n const content = String(values.text ?? 'Text');\n const fontSize = template.id === 'circular-text' ? 28 : 40;\n const box = new Textbox(content, {\n fontSize,\n fontFamily: String(values.font ?? 'Arial'),\n fontWeight: 'bold',\n fill: String(values.color ?? '#000000'),\n originX: 'left',\n originY: 'top',\n // Wide enough that the run stays on one line before the curve widens it.\n width: Math.max(1, content.length * fontSize * 0.62),\n });\n return {\n type: 'text',\n name: template.parameters.find((p) => p.key === 'text')?.label || 'Text',\n object: box as unknown as FabricObject,\n curve: textPathCurve(template, values, box.width ?? 0),\n };\n}\n\n/**\n * The layers a resolved template SVG is made of, in draw order: every `<text>`\n * an editable text layer, every other top-level element a vector layer.\n */\nexport async function explodeTemplateSvg(\n template: TemplateDefinition,\n resolvedSvg: string,\n values: Record<string, string | number>,\n): Promise<TemplateLayerSpec[]> {\n const labels = labelsByRun(template, values);\n const { objects } = await loadSVGFromString(resolvedSvg);\n const specs: TemplateLayerSpec[] = [];\n for (const object of objects) {\n if (object === null) continue;\n if (isText(object)) {\n specs.push({ type: 'text', name: textName(object.text, labels), object: toTextbox(object) });\n continue;\n }\n specs.push({ type: 'shape', name: shapeName(object), object });\n }\n return specs;\n}\n","import type { EditorEvents } from './types';\nimport type { EventEmitter } from './events';\n\nexport class HistoryManager {\n private static readonly ASSET_KEY = '__canvasEditorHistoryAsset';\n private undoStack: string[] = [];\n private redoStack: string[] = [];\n private assets = new Map<string, string>();\n private assetIds = new Map<string, string>();\n private nextAssetId = 1;\n private maxSize: number;\n private maxBytes: number;\n private paused = false;\n private debounceTimer: ReturnType<typeof setTimeout> | null = null;\n private debounceMs: number;\n private getState: () => string;\n private restoreState: (state: string) => Promise<void>;\n private events: EventEmitter<EditorEvents>;\n private transactionDepth = 0;\n private transactionDirty = false;\n\n constructor(opts: {\n getState: () => string;\n restoreState: (state: string) => Promise<void>;\n events: EventEmitter<EditorEvents>;\n maxSize?: number;\n maxBytes?: number;\n debounceMs?: number;\n }) {\n this.getState = opts.getState;\n this.restoreState = opts.restoreState;\n this.events = opts.events;\n this.maxSize = opts.maxSize ?? 50;\n this.maxBytes = opts.maxBytes ?? 50 * 1024 * 1024;\n this.debounceMs = opts.debounceMs ?? 300;\n }\n\n save(): void {\n if (this.paused) return;\n if (this.transactionDepth > 0) {\n this.transactionDirty = true;\n return;\n }\n\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n }\n\n this.debounceTimer = setTimeout(() => {\n this.saveImmediate();\n }, this.debounceMs);\n this.emitChanged();\n }\n\n saveImmediate(): void {\n if (this.paused) {\n this.cancelPending();\n return;\n }\n if (this.transactionDepth > 0) {\n this.transactionDirty = true;\n return;\n }\n this.cancelPending();\n const rawState = this.getState();\n const state = this.compactState(rawState);\n if (this.undoStack.at(-1) === state) {\n this.emitChanged();\n return;\n }\n this.undoStack.push(state);\n while (this.undoStack.length > this.maxSize) {\n this.undoStack.shift();\n }\n this.redoStack = [];\n this.trimToBudget();\n this.events.emit('history:snapshot', {\n bytes: rawState.length * 2,\n totalBytes: this.snapshotBytes(),\n entries: this.undoStack.length,\n });\n this.emitChanged();\n }\n\n beginTransaction(): void {\n // Commit any prior debounced edit as the transaction's undo baseline.\n if (this.transactionDepth === 0 && this.debounceTimer) this.saveImmediate();\n this.transactionDepth += 1;\n }\n\n endTransaction(): void {\n if (this.transactionDepth === 0) return;\n this.transactionDepth -= 1;\n if (this.transactionDepth === 0 && this.transactionDirty) {\n this.transactionDirty = false;\n this.saveImmediate();\n }\n }\n\n async transaction<T>(operation: () => T | Promise<T>): Promise<T> {\n this.beginTransaction();\n try {\n return await operation();\n } finally {\n this.endTransaction();\n }\n }\n\n async undo(): Promise<void> {\n // Drop any debounced save still pending from an in-progress edit, otherwise\n // its timer would fire after restore completes and clobber the redo stack.\n this.cancelPending();\n const committed = this.undoStack.at(-1);\n if (!committed) return;\n const current = this.compactState(this.getState());\n\n // The stack's top is the current committed state. If a debounced edit is\n // still dirty, restore that top; otherwise step back to the previous item.\n const currentIsCommitted = current === committed;\n if (currentIsCommitted && this.undoStack.length < 2) return;\n const target = currentIsCommitted ? this.undoStack[this.undoStack.length - 2] : committed;\n\n this.paused = true;\n try {\n await this.restoreState(this.expandState(target));\n if (currentIsCommitted) this.undoStack.pop();\n this.redoStack.push(current);\n this.trimToBudget();\n } catch (error) {\n this.events.emit('error', { message: 'Failed to undo the last change', error });\n throw error;\n } finally {\n this.paused = false;\n this.emitChanged();\n }\n }\n\n async redo(): Promise<void> {\n this.cancelPending();\n const state = this.redoStack.at(-1);\n if (!state) return;\n\n this.paused = true;\n try {\n await this.restoreState(this.expandState(state));\n this.redoStack.pop();\n if (this.undoStack.at(-1) !== state) this.undoStack.push(state);\n this.trimToBudget();\n } catch (error) {\n this.events.emit('error', { message: 'Failed to redo the last change', error });\n throw error;\n } finally {\n this.paused = false;\n this.emitChanged();\n }\n }\n\n /** True while a restore (undo/redo/deserialize) is in flight. Managers that\n * react to canvas events should skip mutating history during this window. */\n isRestoring(): boolean {\n return this.paused;\n }\n\n pause(): void {\n this.paused = true;\n }\n\n resume(): void {\n this.paused = false;\n }\n\n canUndo(): boolean {\n return this.undoStack.length > 1 || this.debounceTimer !== null;\n }\n\n canRedo(): boolean {\n return this.redoStack.length > 0;\n }\n\n clear(): void {\n // Drop any debounced save too, otherwise its timer fires after the clear\n // and pushes a snapshot into what the caller believes is empty history.\n this.cancelPending();\n this.undoStack = [];\n this.redoStack = [];\n this.assets.clear();\n this.assetIds.clear();\n this.emitChanged();\n }\n\n getSnapshotBytes(): number {\n return this.snapshotBytes();\n }\n\n private cancelPending(): void {\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n this.debounceTimer = null;\n }\n }\n\n dispose(): void {\n this.cancelPending();\n this.transactionDepth = 0;\n this.transactionDirty = false;\n this.undoStack = [];\n this.redoStack = [];\n this.assets.clear();\n this.assetIds.clear();\n }\n\n private emitChanged(): void {\n this.events.emit('history:changed', {\n canUndo: this.canUndo(),\n canRedo: this.canRedo(),\n });\n }\n\n private snapshotBytes(): number {\n const stackBytes = [...this.undoStack, ...this.redoStack].reduce(\n (total, state) => total + state.length * 2,\n 0,\n );\n const assetBytes = [...this.assets.values()].reduce(\n (total, asset) => total + asset.length * 2,\n 0,\n );\n return stackBytes + assetBytes;\n }\n\n private trimToBudget(): void {\n // Prune first: entries dropped by the size cap, and every state discarded\n // with the redo stack, orphan their rasters. Without this the orphans stay\n // resident and inflate snapshotBytes until they evict live undo entries.\n this.pruneAssets();\n while (this.undoStack.length > 1 && this.snapshotBytes() > this.maxBytes) {\n this.undoStack.shift();\n this.pruneAssets();\n }\n while (this.redoStack.length > 1 && this.snapshotBytes() > this.maxBytes) {\n this.redoStack.shift();\n this.pruneAssets();\n }\n }\n\n /**\n * History is internal and can content-address large raster strings without\n * changing the public EditorState wire format. Unchanged images are retained\n * once even when dozens of snapshots reference them.\n */\n private compactState(state: string): string {\n let parsed: unknown;\n try {\n parsed = JSON.parse(state);\n } catch {\n return state;\n }\n const visit = (value: unknown): unknown => {\n if (typeof value === 'string' && /^data:image\\/(?:png|jpeg|webp);base64,/i.test(value)) {\n let id = this.assetIds.get(value);\n if (!id) {\n id = `a${this.nextAssetId++}`;\n this.assetIds.set(value, id);\n this.assets.set(id, value);\n }\n return { [HistoryManager.ASSET_KEY]: id };\n }\n if (Array.isArray(value)) return value.map(visit);\n if (!value || typeof value !== 'object') return value;\n return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, visit(entry)]));\n };\n return JSON.stringify(visit(parsed));\n }\n\n private expandState(state: string): string {\n let parsed: unknown;\n try {\n parsed = JSON.parse(state);\n } catch {\n return state;\n }\n const visit = (value: unknown): unknown => {\n if (Array.isArray(value)) return value.map(visit);\n if (!value || typeof value !== 'object') return value;\n const record = value as Record<string, unknown>;\n const id = record[HistoryManager.ASSET_KEY];\n if (typeof id === 'string' && Object.keys(record).length === 1) {\n const asset = this.assets.get(id);\n if (!asset) throw new Error(`Missing history raster asset: ${id}`);\n return asset;\n }\n return Object.fromEntries(Object.entries(record).map(([key, entry]) => [key, visit(entry)]));\n };\n return JSON.stringify(visit(parsed));\n }\n\n /**\n * Runs on every commit, so it scans for the serialized reference marker\n * instead of re-parsing every snapshot — parsing multi-megabyte raster states\n * per save would cost more than the retention it reclaims. `JSON.stringify`\n * emits the marker verbatim; the same text inside user data is escaped and\n * therefore cannot match.\n */\n private pruneAssets(): void {\n if (this.assets.size === 0) return;\n const states = [...this.undoStack, ...this.redoStack];\n for (const [id, asset] of this.assets) {\n const marker = `\"${HistoryManager.ASSET_KEY}\":\"${id}\"`;\n if (states.some((state) => state.includes(marker))) continue;\n this.assets.delete(id);\n this.assetIds.delete(asset);\n }\n }\n}\n","import type { Canvas, FabricObject, TPointerEvent } from 'fabric';\nimport type { EventEmitter } from './events';\nimport type { EditorEvents } from './types';\n\ninterface SnapGuide {\n /** Vertical guide at this x (canvas px), or undefined for a horizontal one. */\n x?: number;\n y?: number;\n}\n\nconst STROKE = '#22c55e';\n\n/**\n * Snaps a dragged object's edges and centre to the canvas edges/centre and to\n * other objects, drawing transient guide lines while it does. Switchable via\n * {@link setEnabled}; inert (zero overhead beyond a flag check) when disabled.\n */\nexport class SnapManager {\n private enabled = false;\n private threshold = 8;\n private guides: SnapGuide[] = [];\n\n private readonly onMoving: (e: { target?: FabricObject; e: TPointerEvent }) => void;\n private readonly onAfterRender: () => void;\n private readonly onModified: () => void;\n\n constructor(\n private canvas: Canvas,\n private events: EventEmitter<EditorEvents>,\n ) {\n this.onMoving = (e) => this.handleMoving(e.target);\n this.onAfterRender = () => this.drawGuides();\n this.onModified = () => this.clearGuides();\n\n this.canvas.on('object:moving', this.onMoving);\n this.canvas.on('after:render', this.onAfterRender);\n this.canvas.on('mouse:up', this.onModified);\n this.canvas.on('selection:cleared', this.onModified);\n }\n\n setEnabled(enabled: boolean): void {\n if (this.enabled === enabled) return;\n this.enabled = enabled;\n if (!enabled) this.clearGuides();\n this.events.emit('snap:changed', { enabled });\n }\n\n isEnabled(): boolean {\n return this.enabled;\n }\n\n setThreshold(px: number): void {\n this.threshold = Math.max(0, px);\n }\n\n dispose(): void {\n this.canvas.off('object:moving', this.onMoving);\n this.canvas.off('after:render', this.onAfterRender);\n this.canvas.off('mouse:up', this.onModified);\n this.canvas.off('selection:cleared', this.onModified);\n this.guides = [];\n }\n\n private handleMoving(target?: FabricObject): void {\n if (!this.enabled || !target) return;\n\n target.setCoords();\n const r = target.getBoundingRect();\n const cw = this.canvas.getWidth();\n const ch = this.canvas.getHeight();\n\n // Candidate lines for both axes, collected in a single pass over the objects.\n const { xs, ys } = collectCandidates(this.canvas, target, cw, ch);\n\n this.guides = [];\n\n const dx = bestSnap([r.left, r.left + r.width / 2, r.left + r.width], xs, this.threshold);\n if (dx !== null) {\n target.set('left', (target.left ?? 0) + dx.delta);\n this.guides.push({ x: dx.line });\n }\n\n const dy = bestSnap([r.top, r.top + r.height / 2, r.top + r.height], ys, this.threshold);\n if (dy !== null) {\n target.set('top', (target.top ?? 0) + dy.delta);\n this.guides.push({ y: dy.line });\n }\n\n target.setCoords();\n }\n\n private drawGuides(): void {\n if (!this.enabled || this.guides.length === 0) return;\n const ctx = this.canvas.contextTop;\n if (!ctx) return;\n\n const retina = this.canvas.getRetinaScaling();\n const cw = this.canvas.getWidth();\n const ch = this.canvas.getHeight();\n\n ctx.save();\n ctx.setTransform(retina, 0, 0, retina, 0, 0);\n ctx.lineWidth = 1;\n ctx.strokeStyle = STROKE;\n ctx.setLineDash([4, 4]);\n ctx.beginPath();\n for (const g of this.guides) {\n if (g.x !== undefined) {\n ctx.moveTo(g.x, 0);\n ctx.lineTo(g.x, ch);\n }\n if (g.y !== undefined) {\n ctx.moveTo(0, g.y);\n ctx.lineTo(cw, g.y);\n }\n }\n ctx.stroke();\n ctx.restore();\n }\n\n private clearGuides(): void {\n if (this.guides.length === 0) return;\n this.guides = [];\n this.canvas.clearContext(this.canvas.contextTop);\n }\n}\n\n/**\n * Snap candidate lines (edges + centre) for the canvas and every other object,\n * for both axes, computed in one pass so each object's bounds are read once.\n */\nfunction collectCandidates(\n canvas: Canvas,\n moving: FabricObject,\n cw: number,\n ch: number,\n): { xs: number[]; ys: number[] } {\n const xs = [0, cw / 2, cw];\n const ys = [0, ch / 2, ch];\n for (const obj of canvas.getObjects()) {\n if (obj === moving || !obj.visible) continue;\n obj.setCoords();\n const r = obj.getBoundingRect();\n xs.push(r.left, r.left + r.width / 2, r.left + r.width);\n ys.push(r.top, r.top + r.height / 2, r.top + r.height);\n }\n return { xs, ys };\n}\n\n/**\n * Find the closest (edge, candidate) pair within threshold. Returns the delta\n * to apply and the guide line to draw, or null if nothing is close enough.\n */\nfunction bestSnap(\n edges: number[],\n candidates: number[],\n threshold: number,\n): { delta: number; line: number } | null {\n let best: { delta: number; line: number; dist: number } | null = null;\n for (const edge of edges) {\n for (const c of candidates) {\n const dist = Math.abs(edge - c);\n if (dist <= threshold && (best === null || dist < best.dist)) {\n best = { delta: c - edge, line: c, dist };\n }\n }\n }\n return best ? { delta: best.delta, line: best.line } : null;\n}\n\nexport { bestSnap as _bestSnap };\n","import { Rect } from 'fabric';\nimport type { Canvas, FabricImage } from 'fabric';\nimport type { Layer } from './layer';\nimport type { HistoryManager } from './history';\nimport type { EventEmitter } from './events';\nimport type { EditorEvents } from './types';\nimport { clamp } from './utils/clamp';\n\ninterface CropSession {\n layerId: string;\n image: FabricImage;\n rect: Rect;\n prevSelectable: boolean;\n prevEvented: boolean;\n /** Angle before crop normalised it to 0; restored if the crop is cancelled. */\n prevAngle: number;\n}\n\n/**\n * Interactive crop for image layers. {@link start} drops a draggable/resizable\n * rectangle over the image; {@link apply} converts it into fabric crop props\n * (cropX/cropY/width/height in element pixels) and keeps the displayed size in\n * sync with the rectangle.\n *\n * Rotation is unsupported: an angled image is normalised to 0° on start.\n */\nexport class CropController {\n private session: CropSession | null = null;\n private readonly onSelectionCleared: () => void;\n\n constructor(\n private canvas: Canvas,\n private history: HistoryManager,\n private events: EventEmitter<EditorEvents>,\n ) {\n this.onSelectionCleared = () => {\n // Clicking away from the crop rect abandons the crop.\n if (this.session) this.cancel();\n };\n this.canvas.on('selection:cleared', this.onSelectionCleared);\n }\n\n isActive(): boolean {\n return this.session !== null;\n }\n\n activeLayerId(): string | null {\n return this.session?.layerId ?? null;\n }\n\n start(layer: Layer): void {\n if (layer.type !== 'image') return;\n if (this.session) this.cancel();\n\n const image = layer.fabricObject as FabricImage;\n const prevAngle = image.angle ?? 0;\n if (prevAngle) image.rotate(0);\n image.setCoords();\n const b = image.getBoundingRect();\n\n const rect = new Rect({\n left: b.left,\n top: b.top,\n width: b.width,\n height: b.height,\n originX: 'left',\n originY: 'top',\n fill: 'rgba(34,197,94,0.12)',\n stroke: STROKE,\n strokeWidth: 1,\n strokeDashArray: [4, 4],\n strokeUniform: true,\n lockRotation: true,\n cornerColor: STROKE,\n transparentCorners: false,\n });\n rect.setControlsVisibility({ mtr: false });\n\n const prevSelectable = image.selectable ?? true;\n const prevEvented = image.evented ?? true;\n image.selectable = false;\n image.evented = false;\n\n this.canvas.add(rect);\n this.canvas.setActiveObject(rect);\n this.canvas.requestRenderAll();\n\n this.session = { layerId: layer.id, image, rect, prevSelectable, prevEvented, prevAngle };\n this.events.emit('crop:changed', { active: true, layerId: layer.id });\n }\n\n apply(): void {\n const s = this.session;\n if (!s) return;\n const { image, rect } = s;\n\n rect.setCoords();\n image.setCoords();\n const scaleX = image.scaleX ?? 1;\n const scaleY = image.scaleY ?? 1;\n const imgLeft = image.left ?? 0;\n const imgTop = image.top ?? 0;\n\n const el = image.getElement() as HTMLImageElement;\n const naturalW = el.naturalWidth || image.width || 0;\n const naturalH = el.naturalHeight || image.height || 0;\n\n // Map the rect (canvas px) into the image's element-pixel space.\n let cropX = (image.cropX ?? 0) + (rect.left! - imgLeft) / scaleX;\n let cropY = (image.cropY ?? 0) + (rect.top! - imgTop) / scaleY;\n let cropW = rect.getScaledWidth() / scaleX;\n let cropH = rect.getScaledHeight() / scaleY;\n\n // Keep the crop window inside the source element.\n cropX = clamp(cropX, 0, Math.max(0, naturalW - 1));\n cropY = clamp(cropY, 0, Math.max(0, naturalH - 1));\n cropW = clamp(cropW, 1, naturalW - cropX);\n cropH = clamp(cropH, 1, naturalH - cropY);\n\n image.set({\n cropX,\n cropY,\n width: cropW,\n height: cropH,\n // Anchor the displayed result where the rect sits.\n left: imgLeft + (cropX - (image.cropX ?? 0)) * scaleX,\n top: imgTop + (cropY - (image.cropY ?? 0)) * scaleY,\n });\n image.setCoords();\n\n // Cropping is calculated in the normalized frame, then the original\n // orientation is restored so applying a crop never silently un-rotates it.\n if (s.prevAngle) {\n image.rotate(s.prevAngle);\n image.setCoords();\n }\n\n this.finish();\n this.history.save();\n }\n\n cancel(): void {\n const s = this.session;\n if (!s) return;\n // Cancelling discards the crop, so restore the rotation start() zeroed out.\n if (s.prevAngle) {\n s.image.rotate(s.prevAngle);\n s.image.setCoords();\n }\n this.finish();\n }\n\n dispose(): void {\n this.cancel();\n this.canvas.off('selection:cleared', this.onSelectionCleared);\n }\n\n private finish(): void {\n const s = this.session;\n if (!s) return;\n // Null the session first so the selection:cleared fired by removing the\n // rect / re-selecting does not re-enter cancel().\n this.session = null;\n\n this.canvas.remove(s.rect);\n s.image.selectable = s.prevSelectable;\n s.image.evented = s.prevEvented;\n this.canvas.setActiveObject(s.image);\n this.canvas.requestRenderAll();\n\n this.events.emit('crop:changed', { active: false, layerId: null });\n }\n}\n\nconst STROKE = '#22c55e';\n","export function clamp(v: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, v));\n}\n\nexport function round2(v: number): number {\n return Math.round(v * 100) / 100;\n}\n","import { util } from 'fabric';\nimport type { Canvas, FabricImage, FabricObject } from 'fabric';\nimport type { Layer, LayerManager } from '../layer';\nimport type { HistoryManager } from '../history';\nimport type { EditorEvents, PatternConfig, PatternLocks, PatternState } from '../types';\nimport type { EventEmitter } from '../events';\nimport { TiledPatternObject } from './tiled-pattern-object';\nimport type { PatternArea } from './tiled-pattern-object';\n\n/** Tile-scale bounds, matching the panel slider. */\nconst MIN_TILE_SCALE = 10;\nconst MAX_TILE_SCALE = 300;\n\n/**\n * Repeats a layer's own object across the print area.\n *\n * The layer keeps its real fabric object as the tile *source*: it stays in the\n * document, stays selectable and stays editable, and is simply parked at\n * `opacity: 0` while a {@link TiledPatternObject} render proxy draws the tiling\n * over the print area. Nothing is baked into the layer, so a source edit (text,\n * font, colour, drag, scale) shows up on the very next render, and the saved\n * state stores a `Textbox` rather than a screenshot of one.\n */\nexport class PatternManager {\n private proxies = new Map<string, TiledPatternObject>();\n private readonly onObjectModified = (event: { target?: FabricObject }) => {\n const target = event.target;\n if (target instanceof TiledPatternObject) this.commitGesture(target);\n else this.invalidateFor(target);\n };\n private readonly onSourceModified = (event: { target?: FabricObject }) => {\n this.invalidateFor(event.target);\n };\n private readonly onLayerRemoved = ({ layerId }: { layerId: string }) => {\n // LayerManager already took the proxy off the canvas; drop our reference and\n // its offscreen snapshot too, or a long session leaks one canvas per delete.\n const proxy = this.proxies.get(layerId);\n if (!proxy) return;\n proxy.dispose();\n this.proxies.delete(layerId);\n };\n\n constructor(\n private canvas: Canvas,\n private layers: LayerManager,\n private history: HistoryManager,\n private events: EventEmitter<EditorEvents>,\n ) {\n // A source edit only invalidates the cached snapshot. A gesture on the proxy\n // is a pattern edit: fabric renders it live off the proxy's own transform,\n // and the drop folds that transform back into the config.\n this.canvas.on('object:modified', this.onObjectModified);\n this.canvas.on('text:changed', this.onSourceModified);\n this.events.on('layer:removed', this.onLayerRemoved);\n }\n\n isPattern(layerId: string): boolean {\n return !!this.layers.get(layerId)?.meta.pattern;\n }\n\n getConfig(layerId: string): PatternConfig | null {\n return this.layers.get(layerId)?.meta.pattern?.config ?? null;\n }\n\n /** Turn a layer into a repeating pattern, or update an existing one. */\n async apply(layerId: string, config: PatternConfig): Promise<void> {\n const layer = this.layers.get(layerId);\n if (!layer) return;\n try {\n this.layers.setMeta(layerId, { pattern: { config } });\n const proxy = this.proxies.get(layerId);\n if (proxy) {\n proxy.setConfig(config);\n this.canvas.requestRenderAll();\n } else {\n this.attach(layer, config);\n }\n this.history.save();\n } catch (error) {\n this.events.emit('error', { message: 'Failed to apply pattern', error });\n throw error;\n }\n }\n\n /** Drop the tiling and show the source again. */\n async disable(layerId: string): Promise<void> {\n const layer = this.layers.get(layerId);\n if (!layer?.meta.pattern) return;\n try {\n this.detach(layerId);\n // Legacy states froze the source's handles while it was baked; hand them\n // back rather than leaving the layer un-draggable forever.\n restoreLocks(layer.fabricObject, layer.meta.pattern.originalLocks);\n // Hand interaction back to the layer's own object.\n layer.fabricObject.set({\n opacity: layer.opacity,\n selectable: !layer.locked,\n evented: !layer.locked,\n });\n this.layers.setMeta(layerId, { pattern: undefined });\n this.canvas.requestRenderAll();\n this.history.save();\n } catch (error) {\n this.events.emit('error', { message: 'Failed to clear pattern', error });\n throw error;\n }\n }\n\n /**\n * Rebuild every proxy after a state restore, migrating any layer that was\n * saved by the old bake-into-the-layer engine.\n */\n async rehydrateAll(): Promise<void> {\n // Every restore (including each undo step) replaces the whole layer set, so\n // the proxies from the previous one are dead the moment we are called.\n this.clearProxies();\n for (const layer of this.layers.getAll()) {\n const state = layer.meta.pattern;\n if (!state) continue;\n try {\n if (isLegacyState(state)) {\n await unbakeLegacyLayer(layer, state);\n // The bake is gone for good; drop the fields that described it so the\n // next save writes a clean, source-native state.\n this.layers.setMeta(layer.id, { pattern: { config: state.config } });\n }\n this.attach(layer, state.config);\n } catch (error) {\n this.events.emit('error', { message: 'Failed to restore pattern layer', error });\n }\n }\n this.canvas.requestRenderAll();\n }\n\n /** Re-fit every proxy to the print area (canvas resize). */\n syncArea(): void {\n const area = this.area();\n for (const proxy of this.proxies.values()) proxy.setArea(area);\n if (this.proxies.size > 0) this.canvas.requestRenderAll();\n }\n\n /** Drop a layer's cached source snapshot (its content changed). */\n invalidate(layerId: string): void {\n const proxy = this.proxies.get(layerId);\n if (!proxy) return;\n proxy.invalidate();\n // The source's own size is the tile's size, so an edit re-fits the box.\n proxy.syncBox();\n this.canvas.requestRenderAll();\n }\n\n /** Give a freshly cloned layer its own proxy (duplicating a pattern layer). */\n attachTo(layer: Layer): void {\n const state = layer.meta.pattern;\n if (!state || this.proxies.has(layer.id)) return;\n this.attach(layer, state.config);\n }\n\n dispose(): void {\n this.canvas.off('object:modified', this.onObjectModified);\n this.canvas.off('text:changed', this.onSourceModified);\n this.events.off('layer:removed', this.onLayerRemoved);\n this.clearProxies();\n }\n\n /** Release every proxy and the offscreen snapshot it holds. */\n private clearProxies(): void {\n for (const proxy of this.proxies.values()) proxy.dispose();\n this.proxies.clear();\n }\n\n private attach(layer: Layer, config: PatternConfig): void {\n const proxy = new TiledPatternObject(layer.fabricObject, config, this.area());\n // The source stays in the document (it is still the layer's object, still\n // what panels edit and what gets serialized) but hands over interaction: the\n // proxy's box IS the anchor tile, so the frame the user grabs sits on\n // artwork they can see. Two hit targets for one layer would fight.\n const wasActive = this.canvas.getActiveObject() === layer.fabricObject;\n layer.fabricObject.set({ opacity: 0, selectable: false, evented: false });\n this.proxies.set(layer.id, proxy);\n this.layers.setRenderProxy(layer.id, proxy);\n // Turning tiling on with the layer selected must hand the frame over too,\n // or the handles stay on the object that just went invisible and inert.\n if (wasActive) this.canvas.setActiveObject(proxy);\n this.canvas.requestRenderAll();\n }\n\n /**\n * Fold a finished drag / scale / rotate on the proxy back into the pattern:\n * position becomes the grid origin (carried by the source), scale becomes the\n * tile scale, rotation becomes the pattern angle. Read the live transform\n * first — writing the config re-fits the box and destroys it.\n */\n private commitGesture(proxy: TiledPatternObject): void {\n const layer = this.layers.findByObject(proxy);\n const state = layer?.meta.pattern;\n if (!layer || !state) return;\n\n const origin = proxy.liveOrigin();\n const scale = clamp(proxy.liveScale(), MIN_TILE_SCALE, MAX_TILE_SCALE);\n const angle = normalizeAngle(proxy.liveAngle());\n\n layer.fabricObject.setPositionByOrigin(origin, 'center', 'center');\n layer.fabricObject.setCoords();\n\n const config: PatternConfig = { ...state.config, scale, angle };\n this.layers.setMeta(layer.id, { pattern: { ...state, config } });\n proxy.setConfig(config);\n this.canvas.requestRenderAll();\n this.history.save();\n }\n\n private area(): PatternArea {\n return { width: this.canvas.getWidth(), height: this.canvas.getHeight() };\n }\n\n private detach(layerId: string): void {\n const proxy = this.proxies.get(layerId);\n if (!proxy) {\n this.layers.setRenderProxy(layerId, null);\n return;\n }\n this.layers.setRenderProxy(layerId, null);\n proxy.dispose();\n this.proxies.delete(layerId);\n }\n\n private invalidateFor(target: FabricObject | undefined): void {\n if (!target) return;\n const layer = this.layers.findByObject(target);\n if (layer) this.invalidate(layer.id);\n }\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n if (!Number.isFinite(value)) return min;\n return Math.max(min, Math.min(max, value));\n}\n\n/** Fold an angle into (−180, 180], the range the pattern panel offers. */\nfunction normalizeAngle(angle: number): number {\n if (!Number.isFinite(angle)) return 0;\n const wrapped = ((angle % 360) + 360) % 360;\n return Math.round(wrapped > 180 ? wrapped - 360 : wrapped);\n}\n\n/** A state written by the pre-proxy engine, which baked the tiling into the layer. */\nfunction isLegacyState(state: PatternState): boolean {\n return typeof state.originalSrc === 'string' && state.originalSrc.length > 0;\n}\n\n/**\n * Put a legacy pattern layer back the way it was before it was baked: the\n * layer's object currently holds the *tiled bitmap*, and the real artwork is\n * parked in `meta.pattern.originalSrc`.\n *\n * `left`/`top` are restored raw, exactly as they were captured — the object's\n * origin never changed, so re-deriving a position here would move it.\n */\nasync function unbakeLegacyLayer(layer: Layer, state: PatternState): Promise<void> {\n const image = layer.fabricObject as FabricImage;\n if (typeof image.setSrc !== 'function' || !state.original) return;\n\n await image.setSrc(state.originalSrc as string);\n // setSrc resets width/height to the full element size, so the captured crop\n // window has to go back on too.\n image.set({\n left: state.original.left,\n top: state.original.top,\n scaleX: state.original.scaleX,\n scaleY: state.original.scaleY,\n width: state.original.width,\n height: state.original.height,\n cropX: state.original.cropX,\n cropY: state.original.cropY,\n angle: state.original.angle,\n });\n image.clipPath = state.originalClip\n ? ((await util.enlivenObjects([state.originalClip]))[0] as FabricObject)\n : undefined;\n restoreLocks(image, state.originalLocks);\n image.setCoords();\n}\n\n/**\n * Restore pre-pattern interaction flags. Only legacy states carry a snapshot —\n * the live-source engine never freezes anything — so a missing snapshot means\n * \"fully interactive\", not \"leave it frozen\".\n */\nexport function restoreLocks(obj: FabricObject, locks: PatternLocks | undefined): void {\n obj.set(\n locks ?? {\n lockMovementX: false,\n lockMovementY: false,\n lockScalingX: false,\n lockScalingY: false,\n lockRotation: false,\n hasControls: true,\n },\n );\n}\n","import { FabricObject, Point } from 'fabric';\nimport type { PatternConfig } from '../types';\nimport { TEXT_FIT_SLACK, asText, textInk } from '../text-fit';\nimport { drawTiles } from './tile-geometry';\nimport type { PatternOrigin, TileDrawSize } from './tile-geometry';\n\n/**\n * Hard ceiling on the source snapshot, in pixels. A huge source tiled at a huge\n * export multiplier would otherwise allocate an unbounded offscreen canvas.\n */\nconst MAX_SNAPSHOT_PIXELS = 16_000_000;\n/** Ceiling on the snapshot's linear scale, independent of the pixel budget. */\nconst MAX_SNAPSHOT_SCALE = 8;\n/** Rebuild a snapshot this many times too big for what is being drawn. */\nconst SNAPSHOT_SHRINK_FACTOR = 2;\n/**\n * Overlap between neighbouring tiles, in device pixels of whatever is being\n * drawn to (screen or export raster).\n *\n * Tiles abut on fractional pixel boundaries, so each edge is antialiased: two\n * touching tiles leave the shared pixel at ~80% alpha, which reads as a hairline\n * grid over the artwork. Each edge's ramp covers about a pixel, so a pixel of\n * bleed per side is what actually closes it — half a pixel only lifts the seam to\n * ~93%. It scales the tile art by well under a percent, so nothing visibly grows.\n */\nconst TILE_BLEED_DEVICE_PX = 2;\n\nexport interface PatternArea {\n width: number;\n height: number;\n}\n\n/**\n * Renders a layer's source object repeated across the print area.\n *\n * This is a *render proxy*, not a layer: it is attached to the layer that owns\n * the source (see `LayerManager.setRenderProxy`) and never serialized. The\n * document keeps the real object — a `Textbox` stays a `Textbox` — so tiling is\n * non-destructive and every source edit shows up on the next render.\n *\n * **Its box is one tile, its drawing is the whole area.** The object's own\n * width/height/angle/position track the tile drawn at the grid origin (the\n * \"anchor\" tile), so the selection frame the user grabs sits exactly on a tile\n * they can see, while `_render` paints the full print area outside those bounds.\n * That also makes the transform handles meaningful: dragging moves the grid,\n * scaling is the tile scale, rotating is the pattern angle. The live transform\n * is the truth during a gesture; `PatternManager` folds it back into the config\n * when the gesture ends.\n */\nexport class TiledPatternObject extends FabricObject {\n static type = 'TiledPattern';\n\n /** The layer's real object. Never rendered directly (it is kept at opacity 0). */\n source: FabricObject;\n config: PatternConfig;\n /** The print area this pattern fills, in canvas units. */\n area: PatternArea;\n\n private snapshotEl: HTMLCanvasElement | null = null;\n private snapshotScale = 0;\n\n constructor(source: FabricObject, config: PatternConfig, area: PatternArea) {\n super({\n // Centre origin: the box tracks a tile, and a tile is placed by its centre.\n originX: 'center',\n originY: 'center',\n objectCaching: false,\n // Side handles would imply a non-uniform tile scale; the config has one.\n lockScalingFlip: true,\n });\n this.source = source;\n this.config = config;\n this.area = area;\n this.setControlsVisibility({ ml: false, mr: false, mt: false, mb: false });\n this.syncBox();\n }\n\n /** Swap in a new config and re-fit the box to the tile it now describes. */\n setConfig(config: PatternConfig): void {\n this.config = config;\n this.syncBox();\n }\n\n /** Re-fit to a new print area (canvas resize). */\n setArea(area: PatternArea): void {\n this.area = area;\n this.invalidate();\n this.syncBox();\n }\n\n /** Drop the cached source snapshot (the source was edited). */\n invalidate(): void {\n this.snapshotEl = null;\n this.snapshotScale = 0;\n this.dirty = true;\n }\n\n /** Free the offscreen snapshot. */\n dispose(): void {\n this.snapshotEl = null;\n this.snapshotScale = 0;\n }\n\n /**\n * Put the box back on the anchor tile: the tile's size, the pattern angle, and\n * the grid origin displaced by the configured phase shift. Resets any live\n * gesture scale, so it must run only once that gesture has been folded in.\n */\n syncBox(): void {\n const { tileW, tileH } = this.baseTile();\n const origin = this.source.getCenterPoint().add(this.inkOffset());\n const anchor = this.anchorFromOrigin(origin, tileW, tileH, this.config.angle);\n this.set({\n left: anchor.x,\n top: anchor.y,\n width: tileW,\n height: tileH,\n scaleX: 1,\n scaleY: 1,\n angle: this.config.angle,\n });\n this.setCoords();\n this.dirty = true;\n }\n\n /** Grid rotation in play right now — the live handle during a rotate gesture. */\n liveAngle(): number {\n return this.angle ?? 0;\n }\n\n /** Tile scale in play right now, as a config percentage. */\n liveScale(): number {\n return (this.config.scale ?? 100) * Math.abs(this.scaleX ?? 1);\n }\n\n /**\n * Where the source's centre would have to sit for the box to stay put — i.e.\n * the grid origin implied by a drag. `PatternManager` moves the source there.\n */\n liveOrigin(): Point {\n const { tileW, tileH } = this.liveTile();\n const centre = this.getCenterPoint();\n const shift = this.shiftVector(tileW, tileH, this.liveAngle());\n const ink = this.inkOffset();\n return new Point(centre.x - shift.x - ink.x, centre.y - shift.y - ink.y);\n }\n\n _render(ctx: CanvasRenderingContext2D): void {\n const { width, height } = this.area;\n if (width <= 0 || height <= 0) return;\n\n const { tileW, tileH } = this.liveTile();\n const scale = contextScale(ctx);\n const snapshot = this.ensureSnapshot(scale * (tileW / Math.max(1, this.baseW())));\n if (!snapshot) return;\n\n const centre = this.getCenterPoint();\n const angle = this.liveAngle();\n ctx.save();\n // Undo this object's own transform: the tile grid is laid out in canvas\n // coordinates, and the box only describes where one tile sits.\n ctx.scale(1 / (this.scaleX || 1), 1 / (this.scaleY || 1));\n ctx.rotate((-angle * Math.PI) / 180);\n ctx.translate(-centre.x, -centre.y);\n\n // The anchor tile IS a tile of the shifted grid — `syncBox` already put the\n // box on it — so the box centre is the grid origin and the phase shift must\n // not be applied a second time here. Subtracting it back off (which is what\n // this used to do) cancelled the shift exactly: moving Shift X/Y slid the\n // selection frame and left the tiling where it was.\n const origin: PatternOrigin = { x: centre.x, y: centre.y };\n const config = { ...this.config, angle, offsetX: 0, offsetY: 0 };\n drawTiles(\n ctx,\n snapshot,\n config,\n width,\n height,\n tileW,\n tileH,\n origin,\n this.drawSize(tileW, tileH, TILE_BLEED_DEVICE_PX / scale),\n );\n ctx.restore();\n }\n\n /** Raster fallback for SVG export — one `<image>` covering the print area. */\n _toSVG(): string[] {\n const { width, height } = this.area;\n if (width <= 0 || height <= 0) return [];\n const el = document.createElement('canvas');\n el.width = Math.max(1, Math.round(width));\n el.height = Math.max(1, Math.round(height));\n const ctx = el.getContext('2d');\n if (!ctx) return [];\n\n const { tileW, tileH } = this.liveTile();\n const snapshot = this.ensureSnapshot(tileW / Math.max(1, this.baseW()));\n if (!snapshot) return [];\n const centre = this.getCenterPoint();\n const angle = this.liveAngle();\n drawTiles(\n ctx,\n snapshot,\n { ...this.config, angle, offsetX: 0, offsetY: 0 },\n width,\n height,\n tileW,\n tileH,\n { x: centre.x, y: centre.y },\n // The fallback raster is built at 1:1, so a device pixel is a canvas unit.\n this.drawSize(tileW, tileH, TILE_BLEED_DEVICE_PX),\n );\n\n // Emitted inside the object's own transform, which the raster is not in.\n return [\n `<g transform=\"rotate(${-angle}) translate(${-centre.x} ${-centre.y})\">`,\n `<image x=\"0\" y=\"0\" width=\"${width}\" height=\"${height}\" `,\n `xlink:href=\"${el.toDataURL('image/png')}\"></image></g>\\n`,\n ];\n }\n\n /**\n * The proxy holds a live reference to its source, which would make a\n * serialized canvas circular. Nothing persists this object (only layers are\n * serialized) — this keeps an accidental `canvas.toObject()` from throwing.\n */\n toObject(): Record<string, unknown> {\n const plain = super.toObject() as Record<string, unknown>;\n delete plain.source;\n return plain;\n }\n\n /**\n * Fabric's generic clone round-trips through `toObject()` + the class\n * registry, which cannot carry a live source reference. Export paths clone\n * every canvas object, so without this a print export would silently lose the\n * tiling. The copy shares the source (it only ever reads from it).\n */\n clone(): Promise<this> {\n const copy = new TiledPatternObject(this.source, this.config, this.area);\n copy.set({\n left: this.left,\n top: this.top,\n angle: this.angle,\n scaleX: this.scaleX,\n scaleY: this.scaleY,\n width: this.width,\n height: this.height,\n visible: this.visible,\n opacity: this.opacity,\n });\n return Promise.resolve(copy as this);\n }\n\n /**\n * The source's tile footprint: the art it paints, minus a stroke it reserves\n * room for but never paints.\n *\n * fabric keeps `strokeWidth` inside an object's box whether or not a `stroke`\n * colour paints it, and the built-in shapes arrive with `strokeWidth: 1` and no\n * stroke. Stepping the grid by that box puts a transparent seam between every\n * pair of neighbours at zero spacing: the artwork is a pixel narrower than the\n * box it is stepped by.\n *\n * Text is the same problem an order of magnitude larger — see {@link textInk}.\n */\n private sourceBox(): { width: number; height: number } {\n const text = asText(this.source);\n const paints = paintsStroke(this.source);\n const rect = this.source.getBoundingRect();\n if (paints && !text) return { width: rect.width, height: rect.height };\n // The bounding box is the transformed dimensions rotated into an AABB, so\n // re-derive it from dimensions measured without the stroke reserve, and (for\n // text) against the run rather than the box it is free to wrap in.\n const options: Record<string, number> = {};\n if (!paints) options.strokeWidth = 0;\n if (text) options.width = textInk(text).width;\n const dims = this.source._getTransformedDimensions(options);\n const radians = ((this.source.angle ?? 0) * Math.PI) / 180;\n const cos = Math.abs(Math.cos(radians));\n const sin = Math.abs(Math.sin(radians));\n return {\n width: dims.x * cos + dims.y * sin,\n height: dims.x * sin + dims.y * cos,\n };\n }\n\n /**\n * Vector from the source's centre to the centre of the art it paints.\n *\n * Zero for everything except text that does not fill its box: the tile has to\n * sit on the glyphs, or the frame the user drags frames empty space and the\n * grid registers off the run by half the padding.\n */\n private inkOffset(): Point {\n const text = asText(this.source);\n if (!text) return new Point(0, 0);\n const { dx } = textInk(text);\n if (!dx) return new Point(0, 0);\n const scaled = dx * (this.source.scaleX ?? 1);\n const radians = ((this.source.angle ?? 0) * Math.PI) / 180;\n return new Point(scaled * Math.cos(radians), scaled * Math.sin(radians));\n }\n\n /** The source's on-canvas width, before the tile scale. */\n private baseW(): number {\n return Math.max(1, this.sourceBox().width);\n }\n\n /** The source's on-canvas height, before the tile scale. */\n private baseH(): number {\n return Math.max(1, this.sourceBox().height);\n }\n\n /**\n * Size to paint the snapshot at, for a tile of `tileW × tileH`.\n *\n * The snapshot is NOT exactly the source's box: `toCanvasElement` rounds the\n * raster up to whole pixels and pads it further for a shadow. Painting it into\n * the tile step would squeeze the artwork inside that padding — every tile\n * shrinks by up to a pixel and the grid shows transparent seams at zero\n * spacing. So the bitmap is painted at its own footprint, scaled by the same\n * factor the tile is, and the step stays the source's box.\n */\n private drawSize(tileW: number, tileH: number, bleed = 0): TileDrawSize {\n const snapshot = this.snapshotEl;\n if (!snapshot || this.snapshotScale <= 0) {\n return { width: tileW + bleed, height: tileH + bleed };\n }\n return {\n width: (snapshot.width / this.snapshotScale) * (tileW / this.baseW()) + bleed,\n height: (snapshot.height / this.snapshotScale) * (tileH / this.baseH()) + bleed,\n };\n }\n\n /** Tile size from the config alone, ignoring any in-flight gesture. */\n private baseTile(): { tileW: number; tileH: number } {\n const box = this.sourceBox();\n const scale = Math.max(1, this.config.scale ?? 100) / 100;\n const floor = this.tileFloor();\n return {\n tileW: Math.max(floor, box.width * scale),\n tileH: Math.max(floor, box.height * scale),\n };\n }\n\n /** Tile size as drawn right now, including a live scale gesture. */\n private liveTile(): { tileW: number; tileH: number } {\n const base = this.baseTile();\n const floor = this.tileFloor();\n return {\n tileW: Math.max(floor, base.tileW * Math.abs(this.scaleX ?? 1)),\n tileH: Math.max(floor, base.tileH * Math.abs(this.scaleY ?? 1)),\n };\n }\n\n /** Smallest tile the draw loop may use, so a tiny tile can't flood the area. */\n private tileFloor(): number {\n const { width, height } = this.area;\n return Math.max(2, Math.sqrt(width * width + height * height) / 200);\n }\n\n /** Phase shift (`offsetX`/`offsetY`) as a canvas-space vector. */\n private shiftVector(tileW: number, tileH: number, angle: number): Point {\n const dx = tileW * (clampPercent(this.config.offsetX) / 100);\n const dy = tileH * (clampPercent(this.config.offsetY) / 100);\n const radians = (angle * Math.PI) / 180;\n const cos = Math.cos(radians);\n const sin = Math.sin(radians);\n return new Point(dx * cos - dy * sin, dx * sin + dy * cos);\n }\n\n private anchorFromOrigin(origin: Point, tileW: number, tileH: number, angle: number): Point {\n const shift = this.shiftVector(tileW, tileH, angle);\n return new Point(origin.x + shift.x, origin.y + shift.y);\n }\n\n /**\n * Snapshot the source at (at least) `scale`, reusing the cached one while it\n * is still sharp enough and the source has not changed.\n */\n private ensureSnapshot(scale: number): HTMLCanvasElement | null {\n const wanted = this.clampScale(scale);\n const stale =\n this.source.dirty ||\n !this.snapshotEl ||\n this.snapshotScale < wanted ||\n this.snapshotScale > wanted * SNAPSHOT_SHRINK_FACTOR;\n if (!stale) return this.snapshotEl;\n\n // The source is parked at opacity 0 (invisible, still the layer's object);\n // fabric renders nothing at all for it, snapshot included.\n const source = this.source;\n const opacity = source.opacity;\n source.opacity = 1;\n // The bitmap IS the tile, so text is rasterised at the width of its run, not\n // of the box it may wrap in. Snapshotting the box would centre the glyphs\n // inside transparent padding and the grid would step by the padding too.\n const text = asText(source);\n const authoredWidth = text?.width;\n const fitted = text ? textInk(text).width + TEXT_FIT_SLACK : 0;\n const hug = text !== null && authoredWidth !== undefined && fitted < authoredWidth;\n try {\n if (hug && text) {\n text.set({ width: fitted });\n text.initDimensions?.();\n }\n const el = source.toCanvasElement({ multiplier: wanted, enableRetinaScaling: false });\n if (!el.width || !el.height) return null;\n this.snapshotEl = el;\n this.snapshotScale = wanted;\n } catch {\n // A tainted canvas (cross-origin image without CORS) throws here. Keep the\n // previous snapshot rather than dropping the pattern mid-render.\n return this.snapshotEl;\n } finally {\n source.opacity = opacity;\n if (hug && text && authoredWidth !== undefined) {\n // The authored wrap width is the document's, not ours — it goes back\n // whatever happened above, so tiling never edits the layer.\n text.set({ width: authoredWidth });\n text.initDimensions?.();\n }\n // toCanvasElement restores the transform through `set()`, which re-dirties\n // the source; clear it last so the next render reuses this snapshot.\n source.dirty = false;\n }\n return this.snapshotEl;\n }\n\n /** Bound the snapshot by both a linear scale and a total pixel budget. */\n private clampScale(scale: number): number {\n const requested = Math.min(MAX_SNAPSHOT_SCALE, Math.max(0.05, scale));\n const rect = this.source.getBoundingRect();\n const area = Math.max(1, rect.width * rect.height);\n const budgeted = Math.sqrt(MAX_SNAPSHOT_PIXELS / area);\n return Math.max(0.05, Math.min(requested, budgeted));\n }\n}\n\n/** True when the object's stroke actually paints (so its box reserve is artwork). */\nfunction paintsStroke(object: FabricObject): boolean {\n if (!object.strokeWidth || object.strokeWidth <= 0) return false;\n const { stroke } = object;\n if (typeof stroke === 'string') return stroke !== '' && stroke !== 'transparent';\n // A gradient or pattern stroke is an object; only null/undefined paints nothing.\n return stroke !== null && stroke !== undefined;\n}\n\n/** Phase shift percentage, bounded to ±1 tile (0 if not set). */\nfunction clampPercent(value: number | undefined): number {\n if (typeof value !== 'number' || !Number.isFinite(value)) return 0;\n return Math.max(-100, Math.min(100, value));\n}\n\n/**\n * Linear scale of the current 2D transform — 2 on a retina screen, the export\n * multiplier during `toDataURL`. Falls back to 1 where `getTransform` is absent\n * (older node-canvas builds).\n */\nfunction contextScale(ctx: CanvasRenderingContext2D): number {\n if (typeof ctx.getTransform !== 'function') return 1;\n try {\n const t = ctx.getTransform();\n return Math.max(Math.hypot(t.a, t.b), Math.hypot(t.c, t.d), 0.05);\n } catch {\n return 1;\n }\n}\n","import { Point } from 'fabric';\nimport type { FabricObject } from 'fabric';\n\n/**\n * Fitting a text layer's box to the letters inside it.\n *\n * A `Textbox`'s `width` is a **wrap width** somebody authored, not the width of\n * the glyphs, and fabric is explicit that it stays that way: \"Unlike superclass's\n * version of this function, Textbox does not update its width.\" So the box only\n * ever ratchets *up*, and only when a word physically cannot fit — raise a 48px\n * font to 96px inside a 200px box and the selection frame does not move, and\n * dropping the size back leaves the box at whatever width it grew to.\n *\n * Two things need the same measurement: this, and the pattern engine (a tile\n * stepped by the box rather than the run leaves transparent padding between\n * every repeat).\n */\n\n/**\n * Slack left when a box is measured down to its run, so a float rounding error\n * cannot push the widest line into a new wrap on the next layout pass.\n */\nexport const TEXT_FIT_SLACK = 0.5;\n\n/** Box width used to measure a run that is not allowed to wrap. */\nconst MEASURE_WIDTH = 100_000;\n\n/** The text-shaped surface of an object whose box can be wider than its art. */\nexport interface TextSource extends FabricObject {\n text: string;\n width: number;\n textAlign?: string;\n calcTextWidth?: () => number;\n initDimensions?: () => void;\n /** Set while the run follows a curve, which owns the box instead. */\n path?: FabricObject | null;\n}\n\n/** Width the run wants on one line, measured against a box wide enough not to wrap. */\nfunction unwrappedWidth(text: TextSource): number {\n const authored = text.width;\n try {\n text.set({ width: MEASURE_WIDTH });\n text.initDimensions?.();\n const measured = text.calcTextWidth?.() ?? authored;\n return Number.isFinite(measured) && measured > 0 ? measured : authored;\n } finally {\n text.set({ width: authored });\n text.initDimensions?.();\n }\n}\n\n/** The object as text, or null. Only text carries a box wider than what it paints. */\nexport function asText(object: FabricObject | null | undefined): TextSource | null {\n if (!object) return null;\n const text = object as TextSource;\n return typeof text.text === 'string' && typeof text.calcTextWidth === 'function' ? text : null;\n}\n\n/**\n * What a text object paints inside its box, unscaled: the run's width, and how\n * far the run's centre sits from the box's.\n *\n * `calcTextWidth` reports the widest wrapped line — the run's real footprint —\n * and `textAlign` says where in the box that run sits.\n */\nexport function textInk(text: TextSource): { width: number; dx: number } {\n const boxWidth = Math.max(0, text.width ?? 0);\n const measured = text.calcTextWidth?.() ?? boxWidth;\n const width = Math.max(1, Math.min(boxWidth, Number.isFinite(measured) ? measured : boxWidth));\n const slack = (boxWidth - width) / 2;\n const align = text.textAlign ?? 'left';\n if (align.includes('center')) return { width, dx: 0 };\n const flip = text.flipX ? -1 : 1;\n // Right-aligned text hugs the right edge, so its centre is right of the box's;\n // left and justify both start at the left edge.\n return { width, dx: flip * (align.includes('right') ? slack : -slack) };\n}\n\n/**\n * Fit a text layer's box to the run it holds, leaving the letters where they\n * were on screen.\n *\n * The box becomes **auto-width**: it follows the run in both directions, so\n * raising the font size or opening up the letter spacing widens the frame\n * instead of silently breaking the line, and lowering them again takes the width\n * back — which fabric never does on its own, since `Textbox` only ratchets its\n * width up and only when a word cannot fit at all.\n *\n * Line breaks stay under the author's control through the text itself: the run\n * is measured per hard newline, so `One\\nTwo` stays two lines. What goes away is\n * *soft* wrapping, which in an editor whose text tool opens at a fixed 200px box\n * was mostly accidental anyway.\n *\n * Curved text is skipped — `TextCurveManager` owns that box and sizes it to the\n * glyphs along the path, which this would fight.\n *\n * Returns whether anything changed, so a caller can skip a history checkpoint.\n */\nexport function fitTextWidth(object: FabricObject | null | undefined): boolean {\n const text = asText(object);\n if (!text || text.path) return false;\n\n const before = textInk(text);\n const fitted = unwrappedWidth(text) + TEXT_FIT_SLACK;\n // A hair either way is the slack itself, not an edit worth a history step.\n if (Math.abs(fitted - text.width) < TEXT_FIT_SLACK) return false;\n\n // Keep the run put: shrinking the box moves its centre, and with it every\n // alignment except centre. The ink offset is what that move has to cancel.\n const centre = text.getCenterPoint();\n text.set({ width: fitted });\n text.initDimensions?.();\n const after = textInk(text);\n const shift = (before.dx - after.dx) * (text.scaleX ?? 1);\n const radians = ((text.angle ?? 0) * Math.PI) / 180;\n const moved = new Point(\n centre.x + shift * Math.cos(radians),\n centre.y + shift * Math.sin(radians),\n );\n text.setPositionByOrigin(moved, 'center', 'center');\n text.setCoords();\n text.dirty = true;\n return true;\n}\n","import type { PatternConfig } from '../types';\n\n/**\n * Upper bound on tiles per axis. Floors the effective tile size so an extreme\n * `scale` (or a tiny source) can't make the draw loop cover the coverage radius\n * with a runaway number of tiles.\n */\nexport const MAX_TILES_PER_AXIS = 200;\n\n/** Placement of one tile, relative to the (already rotated) pattern origin. */\nexport interface TilePlacement {\n /** Tile-centre offset from the pattern origin, in px. */\n x: number;\n y: number;\n /** Per-tile rotation, in radians. */\n rotation: number;\n}\n\n/** Where the tile grid is anchored inside the target, in target px. */\nexport interface PatternOrigin {\n x: number;\n y: number;\n}\n\n/**\n * Size the tile bitmap is painted at, when that differs from the grid step.\n *\n * A snapshot of the source is not always exactly the source's box: the raster is\n * allocated in whole pixels, and a shadow pads it further. Painting such a bitmap\n * into the step would shrink the artwork inside its own transparent margin and\n * open a hairline gap between neighbours at zero spacing.\n */\nexport interface TileDrawSize {\n width: number;\n height: number;\n}\n\n/**\n * Pure tile geometry: where each tile centre lands and how much it is rotated,\n * for a config + target/base size. Covers every corner of the target from the\n * grid origin, so no rotation or origin can uncover an edge. Extracted for unit\n * testing.\n *\n * `origin` defaults to the centre of the target.\n */\nexport function computeTilePositions(\n config: PatternConfig,\n targetW: number,\n targetH: number,\n baseW: number,\n baseH: number,\n origin?: PatternOrigin,\n): TilePlacement[] {\n const anchor = origin ?? { x: targetW / 2, y: targetH / 2 };\n // Coverage radius: the farthest target corner from the grid origin. Rotation\n // happens around that origin, so a radius is rotation-invariant. With the\n // origin at the centre this is exactly half the diagonal — the value this\n // used to hard-code.\n const radius = cornerRadius(anchor, targetW, targetH);\n const span = radius * 2;\n // Floor the spacing-adjusted tile (as well as the base, floored by the\n // caller): a negative spacing from a hand-crafted config would otherwise\n // collapse the loop tile to ~1px and spawn ~span² draw calls (client-side DoS).\n const minTile = Math.max(1, span / MAX_TILES_PER_AXIS);\n const tileW = Math.max(minTile, baseW * (1 + config.horizontalSpacing / 100));\n const tileH = Math.max(minTile, baseH * (1 + config.verticalSpacing / 100));\n\n const cols = Math.ceil(span / tileW) + 2;\n const rows = Math.ceil(span / tileH) + 2;\n // A limit counts tiles, so it replaces the coverage range outright: the grid\n // stops being a fill and becomes a block of exactly that many repeats,\n // centred on the anchor tile.\n const [colFrom, colTo] = axisRange(config.horizontalLimit, Math.ceil(cols / 2));\n const [rowFrom, rowTo] = axisRange(config.verticalLimit, Math.ceil(rows / 2));\n\n // Grid phase shift. Clamped to one tile: the loop only carries one spare tile\n // of margin past the coverage radius, so a larger shift would uncover an edge\n // — the one thing a pattern must not do. A whole-tile shift is a no-op anyway.\n const shiftX = tileW * (clampOffset(config.offsetX) / 100);\n const shiftY = tileH * (clampOffset(config.offsetY) / 100);\n\n const placements: TilePlacement[] = [];\n for (let j = rowFrom; j <= rowTo; j++) {\n for (let i = colFrom; i <= colTo; i++) {\n let x = i * tileW + shiftX;\n let y = j * tileH + shiftY;\n\n if (config.mode === 'brick-horizontal' && mod2(j) === 1) {\n x += tileW * (config.horizontalOffset / 100);\n } else if (config.mode === 'brick-vertical' && mod2(i) === 1) {\n y += tileH * (config.horizontalOffset / 100);\n }\n\n const rotation = ((i * config.rotationStepH + j * config.rotationStepV) * Math.PI) / 180;\n placements.push({ x, y, rotation });\n }\n }\n return placements;\n}\n\n/**\n * Draw the tiled pattern onto a 2D context, in target coordinates (0,0 = the\n * target's top-left corner). The geometry lives in {@link computeTilePositions};\n * this just plays it out as canvas calls.\n *\n * `baseW`/`baseH` are the grid STEP. `draw` is the size the bitmap is painted at\n * and defaults to the step — pass it when the bitmap carries padding the step\n * does not (see {@link TileDrawSize}), so the artwork still lands step-sized.\n */\nexport function drawTiles(\n ctx: CanvasRenderingProtocol,\n img: CanvasImageSource,\n config: PatternConfig,\n targetW: number,\n targetH: number,\n baseW: number,\n baseH: number,\n origin?: PatternOrigin,\n draw?: TileDrawSize,\n): void {\n const anchor = origin ?? { x: targetW / 2, y: targetH / 2 };\n const drawW = draw && draw.width > 0 ? draw.width : baseW;\n const drawH = draw && draw.height > 0 ? draw.height : baseH;\n ctx.save();\n // Rotate the whole pattern around the grid origin.\n ctx.translate(anchor.x, anchor.y);\n ctx.rotate((config.angle * Math.PI) / 180);\n\n for (const tile of computeTilePositions(config, targetW, targetH, baseW, baseH, anchor)) {\n ctx.save();\n ctx.translate(tile.x, tile.y);\n ctx.rotate(tile.rotation);\n // Centred on the tile, so any padding grows outward symmetrically and the\n // artwork stays where the step puts it.\n ctx.drawImage(img, -drawW / 2, -drawH / 2, drawW, drawH);\n ctx.restore();\n }\n\n ctx.restore();\n}\n\n/**\n * Tile indices to lay along one axis: the full coverage range `±half`, or\n * exactly `limit` tiles around index 0 when a limit is set.\n *\n * An even limit cannot be symmetric about the anchor, so the extra tile goes on\n * the positive side — 4 across is `-1 … 2`.\n */\nfunction axisRange(limit: number | undefined, half: number): [number, number] {\n const count = Number.isFinite(limit) ? Math.floor(limit as number) : 0;\n if (!count || count <= 0) return [-half, half];\n const from = -Math.floor((count - 1) / 2);\n return [from, from + count - 1];\n}\n\n/** Distance from `origin` to the farthest corner of a `w × h` box at 0,0. */\nfunction cornerRadius(origin: PatternOrigin, w: number, h: number): number {\n const dx = Math.max(Math.abs(origin.x), Math.abs(w - origin.x));\n const dy = Math.max(Math.abs(origin.y), Math.abs(h - origin.y));\n return Math.sqrt(dx * dx + dy * dy);\n}\n\n/** Grid phase shift, as % of tile size, bounded to ±1 tile (0 if not set). */\nfunction clampOffset(value: number | undefined): number {\n if (typeof value !== 'number' || !Number.isFinite(value)) return 0;\n return Math.max(-100, Math.min(100, value));\n}\n\n/** Non-negative parity (so negative row indices brick-shift consistently). */\nfunction mod2(n: number): number {\n return ((n % 2) + 2) % 2;\n}\n\n/** Minimal 2D-context surface used by {@link drawTiles}; lets tests inject a spy. */\nexport interface CanvasRenderingProtocol {\n save(): void;\n restore(): void;\n translate(x: number, y: number): void;\n rotate(angle: number): void;\n drawImage(image: CanvasImageSource, dx: number, dy: number, dw: number, dh: number): void;\n}\n","import { Path } from 'fabric';\nimport type { Canvas, FabricObject } from 'fabric';\nimport type { Layer, LayerManager } from './layer';\nimport type { HistoryManager } from './history';\nimport type { EditorEvents, TextCurveConfig, TextCurveInput } from './types';\nimport type { EventEmitter } from './events';\nimport { bendsBaseline, buildCurveLinePaths, normalizeTextCurve } from './text-curve-geometry';\nimport type { CurvePath } from './text-curve-geometry';\n\nexport {\n DEFAULT_TEXT_CURVE,\n buildCurvePathData,\n buildCurveLinePaths,\n normalizeTextCurve,\n} from './text-curve-geometry';\nexport type { CurvePath } from './text-curve-geometry';\n\n/** Box width used to measure an unwrapped run; wide enough that nothing wraps. */\nconst MEASURE_WIDTH = 100000;\n/** Extra path length past the measured run, so the last glyph never falls off. */\nconst PATH_SLACK = 0.06;\n/** Line height fabric assumes when the object can't report one. */\nconst FALLBACK_LINE_HEIGHT = 1.16;\n\ninterface CurvableText extends FabricObject {\n fontSize: number;\n text: string;\n lineHeight?: number;\n textAlign?: string;\n path?: FabricObject | null;\n pathAlign?: string;\n pathSide?: string;\n pathStartOffset?: number;\n _textLines?: unknown[];\n calcTextWidth?: () => number;\n getHeightOfLine?: (lineIndex: number) => number;\n getLineWidth?: (lineIndex: number) => number;\n initDimensions?: () => void;\n _measureLine?: (lineIndex: number) => { width: number; numOfSpaces: number };\n}\n\n/** The per-line measuring hook this manager installs on a curved text object. */\ninterface LinePatch {\n original: CurvableText['_measureLine'];\n installed: CurvableText['_measureLine'];\n /** Whether the object carried its own hook before, or inherited fabric's. */\n ownedOriginal: boolean;\n}\n\nconst patches = new WeakMap<CurvableText, LinePatch>();\n\n/** The `initDimensions` hook that grows a curved object's box to its glyphs. */\ninterface DimensionPatch {\n original: () => void;\n installed: () => void;\n ownedOriginal: boolean;\n}\n\nconst dimensionPatches = new WeakMap<CurvableText, DimensionPatch>();\n\n/** `objectCaching` as the object was authored, while a curve overrides it. */\nconst authoredCaching = new WeakMap<CurvableText, boolean>();\n\n/**\n * Half of a glyph's ink height, as a share of the font size. A glyph on a path\n * is drawn from its vertical middle (`pathAlign: 'center'` → `textBaseline:\n * 'middle'`), so this covers the ascender above and the descender below it.\n */\nconst GLYPH_HALF_HEIGHT = 0.7;\n\n/** One glyph's placement, as fabric records it for text on a path. */\ninterface CurvedCharBox {\n renderLeft?: number;\n renderTop?: number;\n angle?: number;\n kernedWidth?: number;\n width?: number;\n height?: number;\n}\n\n/**\n * Size of the box the curved run actually inks, measured about the object's\n * centre (which is where fabric anchors path text: a glyph is placed at its\n * point on the path, minus the path's own `pathOffset`).\n *\n * Returned as a full width/height rather than per-side extents because an\n * object's box is symmetric around its centre — the larger side has to set both.\n */\nfunction curvedInkSize(text: CurvableText): { width: number; height: number } | null {\n // Fabric measures a line lazily — on the first render or width query — so\n // right after `initDimensions` the glyph boxes are either absent or those of\n // the previous layout. Asking for each line's width fills them in.\n const lineCount = text._textLines?.length ?? 0;\n for (let index = 0; index < lineCount; index += 1) text.getLineWidth?.(index);\n\n const lines = (text as unknown as { __charBounds?: CurvedCharBox[][] }).__charBounds;\n if (!lines?.length) return null;\n\n let halfWidth = 0;\n let halfHeight = 0;\n for (const line of lines) {\n for (const box of line ?? []) {\n const { renderLeft, renderTop } = box;\n // Set only for glyphs placed along a path; a straight line has none.\n if (typeof renderLeft !== 'number' || typeof renderTop !== 'number') continue;\n const halfGlyphWidth = (box.kernedWidth ?? box.width ?? 0) / 2;\n const halfGlyphHeight = (box.height ?? text.fontSize) * GLYPH_HALF_HEIGHT;\n // The glyph is drawn rotated to the path's tangent, so its own box\n // contributes to both axes.\n const angle = box.angle ?? 0;\n const cos = Math.abs(Math.cos(angle));\n const sin = Math.abs(Math.sin(angle));\n halfWidth = Math.max(\n halfWidth,\n Math.abs(renderLeft) + halfGlyphWidth * cos + halfGlyphHeight * sin,\n );\n halfHeight = Math.max(\n halfHeight,\n Math.abs(renderTop) + halfGlyphWidth * sin + halfGlyphHeight * cos,\n );\n }\n }\n if (halfWidth === 0 && halfHeight === 0) return null;\n return { width: halfWidth * 2, height: halfHeight * 2 };\n}\n\n/**\n * Grow a curved object's box until it holds the glyphs.\n *\n * With a path, fabric sizes the object from the PATH's bounding box — which is\n * the bare baseline. The run itself reaches a font-size above and below that\n * line, so an arc's letters stood outside their own layer: the selection box cut\n * through them, snapping and alignment worked off a box the artwork overflowed,\n * and every consumer that reads a layer's bounds (fit-to-print-area, the\n * whole-design mask, content bounds) saw the wrong rectangle.\n */\nfunction growBoxToInk(text: CurvableText): void {\n const ink = curvedInkSize(text);\n if (!ink) return;\n if (ink.width > (text.width ?? 0)) text.width = ink.width;\n if (ink.height > (text.height ?? 0)) text.height = ink.height;\n}\n\nfunction isCurvable(object: FabricObject | undefined): object is CurvableText {\n return !!object && typeof (object as CurvableText).text === 'string';\n}\n\n/**\n * Width the run wants on a single line.\n *\n * `calcTextWidth` reports the widest *wrapped* line, which for a Textbox is\n * capped by its box — so it is measured against a box wide enough that nothing\n * wraps, then the authored width is put back.\n */\nfunction measureText(text: CurvableText): number {\n const authored = text.width;\n try {\n text.set({ width: MEASURE_WIDTH });\n text.initDimensions?.();\n return Math.max(1, text.calcTextWidth?.() ?? text.width ?? 1);\n } finally {\n if (authored !== undefined) text.set({ width: authored });\n text.initDimensions?.();\n }\n}\n\nfunction lineCountOf(text: CurvableText): number {\n return Math.max(1, text._textLines?.length ?? 1);\n}\n\nfunction lineHeightOf(text: CurvableText): number {\n const measured = text.getHeightOfLine?.(0);\n if (typeof measured === 'number' && Number.isFinite(measured) && measured > 0) return measured;\n return text.fontSize * (text.lineHeight ?? 1) * FALLBACK_LINE_HEIGHT;\n}\n\nfunction toFabricPath(curve: CurvePath): Path {\n return new Path(curve.data, { visible: false, objectCaching: false });\n}\n\n/**\n * Bends a text layer's baseline along a generated path.\n *\n * The curve lives on the fabric object as a real text path, so it survives\n * export and serialization with no extra machinery. The parameters that\n * produced it are kept in `layer.meta.curve` so the UI can show them and so the\n * path can be rebuilt when the text, font or size changes.\n */\nexport class TextCurveManager {\n /**\n * Typing on the canvas changes the run the paths were built for. Fabric drops\n * a glyph whose centre falls past the end of the path, so without rebuilding\n * here a longer replacement simply vanishes — select-all-and-retype rendered\n * an empty box — and a shorter one piles up on a path built for the old text.\n *\n * No history entry: fabric records the edit when editing exits, and one save\n * per keystroke would bury every earlier step under the typing.\n */\n private readonly onTextChanged = (event: { target?: FabricObject }) => {\n const layer = event.target ? this.layers.findByObject(event.target) : undefined;\n if (!layer?.meta.curve) return;\n this.refresh(layer.id, false);\n };\n\n constructor(\n private canvas: Canvas,\n private layers: LayerManager,\n private history: HistoryManager,\n private events: EventEmitter<EditorEvents>,\n ) {\n this.canvas.on('text:changed', this.onTextChanged);\n }\n\n dispose(): void {\n this.canvas.off('text:changed', this.onTextChanged);\n }\n\n /** Curve parameters for a layer, or null when it is not curved text. */\n get(layerId: string): TextCurveConfig | null {\n const layer = this.layers.get(layerId);\n if (!layer || !isCurvable(layer.fabricObject)) return null;\n // Normalized on the way out: states saved before the shape switch existed\n // carry only `arc` and `wave`.\n return normalizeTextCurve(layer.meta.curve ?? {});\n }\n\n isCurved(layerId: string): boolean {\n const curve = this.get(layerId);\n return !!curve && bendsBaseline(curve);\n }\n\n /** Apply (or update) the curve on a text layer. A straight config clears it. */\n apply(layerId: string, config: TextCurveInput, save = true): boolean {\n const layer = this.layers.get(layerId);\n if (!layer || !isCurvable(layer.fabricObject)) return false;\n\n const next = normalizeTextCurve(config);\n const text = layer.fabricObject;\n const run = measureText(text);\n\n if (!bendsBaseline(next)) {\n this.detach(text, layer.meta.curveWidth);\n delete layer.meta.curveWidth;\n // The parameters stay: a straightened layer keeps the shape it was on and\n // the settings of both, so the panel doesn't reset under the user.\n layer.meta.curve = next;\n } else {\n // A Textbox wraps at its box width; a wrapped run cannot follow a path, so\n // the box is widened to the natural text width for as long as it is\n // curved. The authored width is kept so clearing restores it.\n if (layer.meta.curveWidth === undefined) layer.meta.curveWidth = text.width ?? 0;\n text.set({ width: Math.max(layer.meta.curveWidth, run + 2) });\n // Widening changes where the run wraps, so the line count is only settled\n // once the box is its curved size.\n text.initDimensions?.();\n // Fabric drops (and wraps) a glyph whose centre falls past the end of the\n // path, and the measured run can land a hair over — so the path is built a\n // little longer than the text and the text is centred on it.\n const curves = buildCurveLinePaths(\n next,\n run * (1 + PATH_SLACK),\n text.fontSize,\n lineCountOf(text),\n lineHeightOf(text),\n );\n if (curves) this.attach(text, curves);\n layer.meta.curve = next;\n }\n\n text.initDimensions?.();\n text.setCoords();\n text.dirty = true;\n this.canvas.requestRenderAll();\n this.events.emit('layer:modified', { layerId });\n if (save) this.history.save();\n return true;\n }\n\n /** Remove the curve, restoring the authored text box width. */\n clear(layerId: string, save = true): boolean {\n const layer = this.layers.get(layerId);\n const shape = layer?.meta.curve?.shape;\n // Keep the shape the layer was on: straightening is not a mode switch, and\n // the panel would otherwise jump back to the arc tab.\n return this.apply(layerId, { shape }, save);\n }\n\n /**\n * Rebuild the paths from the stored parameters. Text content, line count,\n * font family and font size all change the geometry the paths are sized to —\n * without this the curve keeps that of the text it was created from.\n */\n refresh(layerId: string, save = false): boolean {\n const curve = this.layers.get(layerId)?.meta.curve;\n if (!curve) return false;\n return this.apply(layerId, curve, save);\n }\n\n /**\n * Rebuild every curved layer — used after a state restore.\n *\n * `getAll` is the canvas stack, so this walks each group's children too:\n * curved text inside a group would otherwise keep the path geometry it was\n * restored with, and stop tracking its own text, font and size.\n */\n refreshAll(): void {\n const visit = (layers: Layer[]): void => {\n for (const layer of layers) {\n if (layer.meta.curve) this.refresh(layer.id);\n if (layer.children.length > 0) visit(layer.children);\n }\n };\n visit(this.layers.getAll());\n }\n\n /**\n * Puts every line's path on the object as one shape, and hooks per-line\n * measuring so each line is laid out on its own.\n *\n * The object's own path is the union of the lines: fabric sizes a curved text\n * object from it, and a single line's path would leave the rest of the block\n * outside the layer's box — where object caching clips it away.\n */\n private attach(text: CurvableText, curves: CurvePath[]): void {\n // A cached object is drawn into a canvas the size of its own box, and a\n // curved run reaches well outside that box — an arc came out with its top\n // sliced flat, on screen and in every export. Uncached, there is nothing to\n // clip it. Only curved text pays the per-frame redraw.\n if (!authoredCaching.has(text)) authoredCaching.set(text, text.objectCaching);\n text.set({ objectCaching: false });\n\n const paths = curves.map(toFabricPath);\n const union =\n paths.length === 1\n ? paths[0]\n : toFabricPath({ data: curves.map((c) => c.data).join(' '), length: 0 });\n text.set({\n path: union,\n pathAlign: 'center',\n pathSide: 'left',\n // Each line is centred on its own path by the measuring hook below, so\n // there is no single offset left to apply.\n pathStartOffset: 0,\n });\n this.patchLineMeasure(text, paths, union);\n this.patchDimensions(text);\n }\n\n /**\n * Re-apply {@link growBoxToInk} after every one of fabric's own dimension\n * passes. Typing, a font change, a style edit and a state restore all call\n * `initDimensions`, and each one puts the box back to the path's bounding box\n * — so growing it once, here, would hold only until the next keystroke.\n */\n private patchDimensions(text: CurvableText): void {\n // Idempotent: `apply` re-attaches on every parameter change, and re-wrapping\n // our own hook would stack a chain of them on the object.\n if (dimensionPatches.has(text)) return;\n const original = text.initDimensions;\n if (typeof original !== 'function') return;\n\n const installed = function (this: CurvableText) {\n original.call(this);\n growBoxToInk(this);\n };\n\n const ownedOriginal = Object.prototype.hasOwnProperty.call(text, 'initDimensions');\n text.initDimensions = installed;\n dimensionPatches.set(text, { original, installed, ownedOriginal });\n }\n\n /** Restore fabric's own dimension pass, if this manager replaced it. */\n private unpatchDimensions(text: CurvableText): void {\n const patch = dimensionPatches.get(text);\n if (!patch) return;\n // Only unwind our own hook — anything layered on top since owns the slot.\n if (text.initDimensions === patch.installed) {\n // Reassigning the inherited method would leave an own property shadowing\n // the prototype's, which a later fabric version would then never update.\n if (patch.ownedOriginal) text.initDimensions = patch.original;\n else delete text.initDimensions;\n }\n dimensionPatches.delete(text);\n }\n\n /**\n * Fabric lays every line of a text object along `this.path`, from one\n * `pathStartOffset` — so a multi-line run piles all its lines on top of each\n * other. Each line is measured against its own path instead, by swapping the\n * path in around fabric's own per-line measure pass.\n *\n * The paths all share the first one's `pathOffset`, which is the origin\n * fabric subtracts to place a glyph in the object — without that each line\n * would be re-centred on its own bounding box and land back in the same spot.\n *\n * `textAlign` is switched to centre for the pass, which is how fabric centres\n * a line on its path; the authored value is restored before anything else\n * reads it.\n */\n private patchLineMeasure(text: CurvableText, paths: Path[], union: Path): void {\n this.unpatchLineMeasure(text);\n const original = text._measureLine;\n // Guard the fabric internal this leans on: without it only line 1 curves,\n // and it lands at the start of its path rather than centred on it.\n if (typeof original !== 'function') return;\n\n for (const path of paths) path.pathOffset = union.pathOffset;\n\n const installed = function (this: CurvableText, lineIndex: number) {\n const path = paths[lineIndex];\n if (!path) return original.call(this, lineIndex);\n const previousPath = this.path;\n const previousAlign = this.textAlign;\n this.path = path;\n this.textAlign = 'center';\n // `setPathInfo` fills in the segment lengths fabric measures along; a\n // swapped-in path has none until it has been the object's own path.\n (this as unknown as { setPathInfo?: () => void }).setPathInfo?.();\n try {\n return original.call(this, lineIndex);\n } finally {\n this.path = previousPath;\n this.textAlign = previousAlign;\n }\n };\n\n const ownedOriginal = Object.prototype.hasOwnProperty.call(text, '_measureLine');\n text._measureLine = installed;\n patches.set(text, { original, installed, ownedOriginal });\n }\n\n /** Restore fabric's own per-line measuring, if this manager replaced it. */\n private unpatchLineMeasure(text: CurvableText): void {\n const patch = patches.get(text);\n if (!patch) return;\n // Only unwind our own hook — anything layered on top since owns the slot.\n if (text._measureLine === patch.installed) {\n // Reassigning the inherited method would leave an own property shadowing\n // the prototype's, which a later fabric version would then never update.\n if (patch.ownedOriginal) text._measureLine = patch.original;\n else delete text._measureLine;\n }\n patches.delete(text);\n }\n\n private detach(text: CurvableText, authoredWidth: number | undefined): void {\n this.unpatchLineMeasure(text);\n this.unpatchDimensions(text);\n const caching = authoredCaching.get(text);\n if (caching !== undefined) {\n text.set({ objectCaching: caching });\n authoredCaching.delete(text);\n }\n text.set({ path: null, pathStartOffset: 0 });\n if (authoredWidth !== undefined && authoredWidth > 0) text.set({ width: authoredWidth });\n }\n}\n","import type { TextCurveConfig, TextCurveInput } from './types';\nimport { clamp } from './utils/clamp';\n\n/** Straight text — the state every text layer starts in. */\nexport const DEFAULT_TEXT_CURVE: TextCurveConfig = {\n shape: 'arc',\n arc: 0,\n wave: 0,\n waveLength: 4.1,\n offset: 0,\n centerOffset: 0,\n};\n\n/** Below this the arc is indistinguishable from a straight baseline. */\nexport const MIN_ARC = 0.5;\n/** `arc` at or above this closes the ring instead of bending an open arc. */\nconst FULL_CIRCLE_ARC = 99.5;\n/** Floor on the sweep so a tiny arc doesn't ask for a near-infinite radius. */\nconst MIN_SWEEP = 0.12;\n/** Wave amplitude at `wave: 100`, in font sizes. */\nconst WAVE_AMPLITUDE_EM = 0.9;\n/** Bounds on the wave period, in font sizes. */\nexport const MIN_WAVE_LENGTH = 1;\nexport const MAX_WAVE_LENGTH = 12;\n/** Sampling step for the wave polyline, in px, and the cap on the sample count. */\nconst WAVE_STEP = 6;\nconst MAX_WAVE_STEPS = 4000;\n\nexport interface CurvePath {\n /** SVG path data the line is laid out along. */\n data: string;\n /** Length of that path. */\n length: number;\n}\n\nfunction round(value: number): number {\n return Math.round(value * 100) / 100;\n}\n\n/**\n * Fills in a partial curve.\n *\n * States saved before the shape switch existed carry only `arc` and `wave`, and\n * held exactly one of them — so the non-zero one names the shape.\n */\nexport function normalizeTextCurve(config: TextCurveInput): TextCurveConfig {\n const arc = clamp(config.arc ?? 0, -100, 100);\n const wave = clamp(config.wave ?? 0, 0, 100);\n const inferred = Math.abs(arc) < MIN_ARC && wave > 0 ? 'wave' : 'arc';\n return {\n shape: config.shape ?? inferred,\n arc,\n wave,\n waveLength: clamp(\n config.waveLength ?? DEFAULT_TEXT_CURVE.waveLength,\n MIN_WAVE_LENGTH,\n MAX_WAVE_LENGTH,\n ),\n offset: clamp(config.offset ?? 0, -100, 100),\n centerOffset: clamp(config.centerOffset ?? 0, -100, 100),\n };\n}\n\n/** True when the config actually bends the baseline. */\nexport function bendsBaseline(config: TextCurveConfig): boolean {\n return config.shape === 'arc' ? Math.abs(config.arc) >= MIN_ARC : config.wave > 0;\n}\n\ninterface ArcGeometry {\n /** Radius of the line the run sits on. */\n radius: number;\n /** Angle the arc spans. */\n sweep: number;\n /** +1 bulges the run upward (a rainbow), −1 into a valley. */\n direction: number;\n /** Ring the arc is measured against; the circle centre sits this far away. */\n baseRadius: number;\n}\n\n/**\n * Circle the run is bent around.\n *\n * `arc` fixes the angle the run spans; `centerOffset` then pushes it off that\n * ring — outward the ring grows and the run keeps its sweep, centred in a\n * longer arc; inward the ring shrinks, and the sweep has to open up to keep the\n * whole run on the path instead of dropping its tail.\n */\nfunction arcGeometry(width: number, config: TextCurveConfig): ArcGeometry {\n const magnitude = Math.min(100, Math.abs(config.arc));\n const direction = config.arc < 0 ? -1 : 1;\n const baseSweep =\n magnitude >= FULL_CIRCLE_ARC ? Math.PI * 2 : Math.max(MIN_SWEEP, (magnitude / 100) * Math.PI);\n const baseRadius = width / baseSweep;\n // ±100 halves / doubles the ring, and the ends stay in proportion.\n const radius = baseRadius * Math.pow(2, config.centerOffset / 100);\n const sweep =\n radius >= baseRadius ? baseSweep : Math.min(Math.PI * 2, width / Math.max(radius, 1e-3));\n return { radius, sweep, direction, baseRadius };\n}\n\n/**\n * Arc for one line, drawn in the frame of the whole block.\n *\n * Every line shares one circle centre — `(width / 2, direction · baseRadius)`,\n * which is where the un-offset baseline's centre already was — so the lines\n * come out concentric instead of as copies sitting on top of each other.\n */\nfunction arcLinePath(\n width: number,\n geometry: ArcGeometry,\n radius: number,\n rotation: number,\n): CurvePath {\n const { sweep, direction, baseRadius } = geometry;\n const full = sweep >= Math.PI * 2 - 1e-6;\n const centerX = width / 2;\n\n // y grows downward, so subtracting `r · cos` from the centre bulges the middle\n // of the run away from it — upward for a positive arc, into a valley for the\n // mirrored one.\n const point = (angle: number): [number, number] => [\n centerX + radius * Math.sin(angle),\n direction * (baseRadius - radius * Math.cos(angle)),\n ];\n // SVG sweep flag: 1 traces the positive (clockwise, y-down) direction, which\n // is what a rainbow does when read left to right. A valley traces the other.\n const sweepFlag = direction > 0 ? 1 : 0;\n const format = ([x, y]: [number, number]) => `${round(x)} ${round(y)}`;\n const r = round(radius);\n\n if (full) {\n // A single arc command cannot close a circle: start and end coincide, which\n // SVG treats as a no-op. Split it at the far side of the ring.\n const start = point(rotation - Math.PI);\n const opposite = point(rotation);\n return {\n data: [\n `M ${format(start)}`,\n `A ${r} ${r} 0 0 ${sweepFlag} ${format(opposite)}`,\n `A ${r} ${r} 0 0 ${sweepFlag} ${format(start)}`,\n ].join(' '),\n length: radius * Math.PI * 2,\n };\n }\n\n const start = point(rotation - sweep / 2);\n const end = point(rotation + sweep / 2);\n const largeArc = sweep > Math.PI ? 1 : 0;\n return {\n data: `M ${format(start)} A ${r} ${r} 0 ${largeArc} ${sweepFlag} ${format(end)}`,\n length: radius * sweep,\n };\n}\n\n/** Sine wave for one line, shifted down the block by `dy`. */\nfunction waveLinePath(\n width: number,\n fontSize: number,\n config: TextCurveConfig,\n dy: number,\n): CurvePath {\n const amplitude = (config.wave / 100) * fontSize * WAVE_AMPLITUDE_EM;\n const period = Math.max(1, fontSize * config.waveLength);\n // ±100 walks the run through one whole wavelength.\n const phase = (config.offset / 100) * Math.PI * 2;\n // A short wavelength needs denser samples or the crests come out clipped.\n const step = Math.min(WAVE_STEP, period / 8);\n const steps = Math.min(MAX_WAVE_STEPS, Math.max(2, Math.ceil(width / step)));\n const commands: string[] = [];\n let length = 0;\n let previous: [number, number] | null = null;\n for (let index = 0; index <= steps; index++) {\n const x = (width * index) / steps;\n const y = dy + amplitude * Math.sin((x / period) * Math.PI * 2 + phase);\n if (previous) length += Math.hypot(x - previous[0], y - previous[1]);\n previous = [x, y];\n commands.push(`${index === 0 ? 'M' : 'L'} ${round(x)} ${round(y)}`);\n }\n // A wave is longer than the run it spans; the caller centres the text on it.\n return { data: commands.join(' '), length };\n}\n\n/**\n * One path per line of text, in a single shared coordinate frame.\n *\n * Fabric lays every line of a text object along the *same* path, so a\n * multi-line run collapses into one overlapping pile. Each line gets its own\n * path here, and `TextCurveManager` measures each line against its own — arcs\n * concentric around one centre, waves stacked a line-height apart. The block is\n * centred on the single-line baseline so adding a line doesn't shift the design.\n */\nexport function buildCurveLinePaths(\n config: TextCurveInput,\n width: number,\n fontSize: number,\n lineCount = 1,\n lineHeight = 0,\n): CurvePath[] | null {\n const curve = normalizeTextCurve(config);\n if (!bendsBaseline(curve)) return null;\n\n const lines = Math.max(1, Math.floor(lineCount));\n const paths: CurvePath[] = [];\n if (curve.shape === 'wave') {\n for (let index = 0; index < lines; index++) {\n paths.push(waveLinePath(width, fontSize, curve, (index - (lines - 1) / 2) * lineHeight));\n }\n return paths;\n }\n\n const geometry = arcGeometry(width, curve);\n // ±100 walks a closed ring right round; on an open arc it slides the run by\n // its own sweep, which is as far as the shape can carry it.\n const rotation = (curve.offset / 100) * geometry.sweep;\n for (let index = 0; index < lines; index++) {\n // Later lines sit further out, so line 1 is the innermost ring.\n const radius = Math.max(1, geometry.radius + (index - (lines - 1) / 2) * lineHeight);\n paths.push(arcLinePath(width, geometry, radius, rotation));\n }\n return paths;\n}\n\n/** Path the given curve traces for a single-line run, or null when straight. */\nexport function buildCurvePathData(\n config: TextCurveInput,\n width: number,\n fontSize: number,\n): CurvePath | null {\n return buildCurveLinePaths(config, width, fontSize)?.[0] ?? null;\n}\n","import { FabricImage, Path } from 'fabric';\nimport type { Canvas, FabricObject } from 'fabric';\nimport type { LayerManager } from './../layer';\nimport type { HistoryManager } from './../history';\nimport type { EditorEvents, MaskPresetId } from './../types';\nimport type { EventEmitter } from './../events';\nimport { SHAPE_MASK_BOX, isShapeMaskId, shapeMaskPathData } from './shapes';\nimport { TEXTURE_MASK_SIZE, isTextureMaskId, renderTextureMask } from './textures';\n\nexport function isMaskPresetId(value: unknown): value is MaskPresetId {\n return isShapeMaskId(value) || isTextureMaskId(value);\n}\n\n/**\n * Clips a layer to a preset silhouette or soft texture.\n *\n * The preset is installed as the fabric object's `clipPath`, so it renders,\n * exports and serializes through the same path fabric already uses. The chosen\n * id is kept in `layer.meta.maskPreset` so the UI can show the active preset\n * and so the clip can be rebuilt when the layer is resized.\n *\n * A pattern strips and restores the layer's clip while it is enabled (see\n * `PatternManager`), so a mask preset is suspended for the duration of one.\n */\nexport class MaskPresetManager {\n constructor(\n private canvas: Canvas,\n private layers: LayerManager,\n private history: HistoryManager,\n private events: EventEmitter<EditorEvents>,\n ) {}\n\n get(layerId: string): MaskPresetId | null {\n return this.layers.get(layerId)?.meta.maskPreset ?? null;\n }\n\n /** Clip the layer to `id`. Passing null (or an unknown id) clears the clip. */\n apply(layerId: string, id: MaskPresetId | null, save = true): boolean {\n const layer = this.layers.get(layerId);\n if (!layer) return false;\n const object = layer.fabricObject;\n\n if (id === null) {\n if (!layer.meta.maskPreset) return false;\n object.clipPath = undefined;\n delete layer.meta.maskPreset;\n } else {\n if (!isMaskPresetId(id)) return false;\n object.clipPath = this.buildClip(id, object);\n layer.meta.maskPreset = id;\n }\n\n object.dirty = true;\n object.setCoords();\n this.canvas.requestRenderAll();\n this.events.emit('layer:modified', { layerId });\n if (save) this.history.save();\n return true;\n }\n\n clear(layerId: string, save = true): boolean {\n return this.apply(layerId, null, save);\n }\n\n /**\n * Re-fit the clip to the layer's current size. The clip is built for the\n * object's dimensions at the time it was applied; editing text or replacing an\n * image changes them, and a stale clip would crop the wrong region.\n */\n refresh(layerId: string, save = false): boolean {\n const id = this.get(layerId);\n if (!id) return false;\n return this.apply(layerId, id, save);\n }\n\n /** Re-fit every masked layer — used after a state restore. */\n refreshAll(): void {\n for (const layer of this.layers.getAll()) {\n if (layer.meta.maskPreset) this.refresh(layer.id);\n }\n }\n\n private buildClip(id: MaskPresetId, object: FabricObject): FabricObject {\n // clipPath coordinates are the object's own, centred on it, and unaffected\n // by the object's scale — so the clip is sized to the unscaled dimensions.\n const width = Math.max(1, object.width ?? 1);\n const height = Math.max(1, object.height ?? 1);\n const shared = {\n originX: 'center' as const,\n originY: 'center' as const,\n left: 0,\n top: 0,\n objectCaching: false,\n };\n\n if (isShapeMaskId(id)) {\n return new Path(shapeMaskPathData(id), {\n ...shared,\n scaleX: width / SHAPE_MASK_BOX,\n scaleY: height / SHAPE_MASK_BOX,\n });\n }\n\n return new FabricImage(renderTextureMask(id), {\n ...shared,\n scaleX: width / TEXTURE_MASK_SIZE,\n scaleY: height / TEXTURE_MASK_SIZE,\n });\n }\n}\n","import type { ShapeMaskPresetId } from './../types';\n\n/** Silhouette masks, authored on a 0–100 square so they scale to any layer. */\nexport const SHAPE_MASK_IDS = [\n 'circle',\n 'square',\n 'triangle',\n 'star',\n 'heart',\n 'octagram',\n 'arch',\n 'zigzag',\n] as const satisfies readonly ShapeMaskPresetId[];\n\nexport type ShapeMaskId = ShapeMaskPresetId;\n\nexport function isShapeMaskId(value: unknown): value is ShapeMaskId {\n return typeof value === 'string' && (SHAPE_MASK_IDS as readonly string[]).includes(value);\n}\n\n/** Vertices of an `points`-pointed star, alternating outer and inner radius. */\nfunction starPoints(points: number, outer: number, inner: number, start = -Math.PI / 2): string {\n const step = Math.PI / points;\n const coordinates: string[] = [];\n for (let index = 0; index < points * 2; index++) {\n const radius = index % 2 === 0 ? outer : inner;\n const angle = start + index * step;\n const x = 50 + Math.cos(angle) * radius;\n const y = 50 + Math.sin(angle) * radius;\n coordinates.push(`${index === 0 ? 'M' : 'L'} ${round(x)} ${round(y)}`);\n }\n return `${coordinates.join(' ')} Z`;\n}\n\nfunction round(value: number): number {\n return Math.round(value * 100) / 100;\n}\n\nconst SHAPE_PATHS: Record<ShapeMaskId, string> = {\n circle: 'M 96 50 A 46 46 0 1 1 4 50 A 46 46 0 1 1 96 50 Z',\n square: 'M 4 4 H 96 V 96 H 4 Z',\n triangle: 'M 50 4 L 96 96 L 4 96 Z',\n star: starPoints(5, 46, 22),\n heart: 'M 50 96 C -8 55 12 4 50 28 C 88 4 108 55 50 96 Z',\n octagram: starPoints(8, 46, 27),\n arch: 'M 4 96 V 50 A 46 46 0 0 1 96 50 V 96 Z',\n zigzag: starPoints(16, 46, 39),\n};\n\n/** SVG path data for a shape mask, on a 100×100 box. */\nexport function shapeMaskPathData(id: ShapeMaskId): string {\n return SHAPE_PATHS[id];\n}\n\n/** Nominal authoring box every shape mask path is drawn in. */\nexport const SHAPE_MASK_BOX = 100;\n","import type { TextureMaskPresetId } from './../types';\n\n/**\n * Procedural alpha textures used as soft layer masks.\n *\n * Each renders white-on-transparent at a fixed resolution; the opaque parts are\n * what survives masking. They are deterministic (seeded PRNG, no `Math.random`)\n * so a design renders identically on every load and in every export.\n */\nexport const TEXTURE_MASK_IDS = [\n 'vignette',\n 'halftone',\n 'spray',\n 'grunge',\n 'torn',\n 'band',\n] as const satisfies readonly TextureMaskPresetId[];\n\nexport type TextureMaskId = TextureMaskPresetId;\n\nexport function isTextureMaskId(value: unknown): value is TextureMaskId {\n return typeof value === 'string' && (TEXTURE_MASK_IDS as readonly string[]).includes(value);\n}\n\n/** Square resolution every texture is rendered at before being scaled to fit. */\nexport const TEXTURE_MASK_SIZE = 320;\n\nconst cache = new Map<TextureMaskId, HTMLCanvasElement>();\n\n/** Park–Miller PRNG: same seed, same texture, on every machine. */\nfunction seeded(seed: number): () => number {\n let state = seed;\n return () => {\n state = (state * 16807) % 2147483647;\n return (state - 1) / 2147483646;\n };\n}\n\nfunction traceRoughEdge(\n context: CanvasRenderingContext2D,\n random: () => number,\n jitter: number,\n inset: number,\n): void {\n const size = TEXTURE_MASK_SIZE;\n const corners: [number, number][] = [\n [inset, inset],\n [size - inset, inset],\n [size - inset, size - inset],\n [inset, size - inset],\n ];\n context.beginPath();\n for (let corner = 0; corner < corners.length; corner++) {\n const [fromX, fromY] = corners[corner];\n const [toX, toY] = corners[(corner + 1) % corners.length];\n for (let step = 0; step <= 26; step++) {\n const ratio = step / 26;\n const x = fromX + (toX - fromX) * ratio + (random() - 0.5) * jitter;\n const y = fromY + (toY - fromY) * ratio + (random() - 0.5) * jitter;\n if (corner === 0 && step === 0) context.moveTo(x, y);\n else context.lineTo(x, y);\n }\n }\n context.closePath();\n context.fill();\n}\n\nfunction paint(id: TextureMaskId, context: CanvasRenderingContext2D): void {\n const size = TEXTURE_MASK_SIZE;\n const center = size / 2;\n context.fillStyle = '#ffffff';\n\n switch (id) {\n case 'vignette': {\n const gradient = context.createRadialGradient(\n center,\n center,\n size * 0.18,\n center,\n center,\n size * 0.52,\n );\n gradient.addColorStop(0, 'rgba(255,255,255,1)');\n gradient.addColorStop(1, 'rgba(255,255,255,0)');\n context.fillStyle = gradient;\n context.fillRect(0, 0, size, size);\n return;\n }\n case 'band': {\n const gradient = context.createLinearGradient(0, 0, 0, size);\n gradient.addColorStop(0, 'rgba(255,255,255,0)');\n gradient.addColorStop(0.25, 'rgba(255,255,255,1)');\n gradient.addColorStop(0.75, 'rgba(255,255,255,1)');\n gradient.addColorStop(1, 'rgba(255,255,255,0)');\n context.fillStyle = gradient;\n context.fillRect(0, 0, size, size);\n return;\n }\n case 'halftone': {\n const pitch = 16;\n for (let y = pitch / 2; y < size; y += pitch) {\n for (let x = pitch / 2; x < size; x += pitch) {\n const distance = Math.hypot(x - center, y - center) / (size * 0.52);\n const radius = Math.max(0, (pitch / 2) * (1 - distance) * 1.15);\n if (radius < 0.4) continue;\n context.beginPath();\n context.arc(x, y, radius, 0, Math.PI * 2);\n context.fill();\n }\n }\n return;\n }\n case 'spray': {\n const random = seeded(42);\n const core = context.createRadialGradient(center, center, 10, center, center, size * 0.42);\n core.addColorStop(0, 'rgba(255,255,255,1)');\n core.addColorStop(1, 'rgba(255,255,255,0.85)');\n context.fillStyle = core;\n context.beginPath();\n context.arc(center, center, size * 0.42, 0, Math.PI * 2);\n context.fill();\n context.fillStyle = 'rgba(255,255,255,0.9)';\n for (let dot = 0; dot < 900; dot++) {\n const angle = random() * Math.PI * 2;\n const distance = size * (0.3 + random() * 0.24);\n const x = center + Math.cos(angle) * distance;\n const y = center + Math.sin(angle) * distance;\n context.globalAlpha = 1 - (distance / size - 0.3) / 0.24;\n context.beginPath();\n context.arc(x, y, random() * 2.4, 0, Math.PI * 2);\n context.fill();\n }\n context.globalAlpha = 1;\n return;\n }\n case 'grunge': {\n const random = seeded(7);\n traceRoughEdge(context, random, 14, size * 0.06);\n // Punch speckles back out of the frame, concentrated near its edges.\n context.globalCompositeOperation = 'destination-out';\n for (let speckle = 0; speckle < 240; speckle++) {\n const x = random() * size;\n const y = random() * size;\n const nearEdge = Math.min(x, y, size - x, size - y) < size * 0.12;\n if (!nearEdge && random() >= 0.12) continue;\n context.beginPath();\n context.arc(x, y, random() * 6 + 1, 0, Math.PI * 2);\n context.fill();\n }\n context.globalCompositeOperation = 'source-over';\n return;\n }\n case 'torn': {\n traceRoughEdge(context, seeded(99), 10, size * 0.08);\n return;\n }\n }\n}\n\n/** Render (and memoize) a texture mask. Browser-only: needs a 2D canvas. */\nexport function renderTextureMask(id: TextureMaskId): HTMLCanvasElement {\n const cached = cache.get(id);\n if (cached) return cached;\n if (typeof document === 'undefined') {\n throw new Error('Texture masks require a DOM canvas');\n }\n const canvas = document.createElement('canvas');\n canvas.width = TEXTURE_MASK_SIZE;\n canvas.height = TEXTURE_MASK_SIZE;\n const context = canvas.getContext('2d');\n if (!context) throw new Error('Texture masks require a 2D canvas context');\n paint(id, context);\n cache.set(id, canvas);\n return canvas;\n}\n\n/** Drop memoized textures — used by tests and by long-lived editors on dispose. */\nexport function clearTextureMaskCache(): void {\n cache.clear();\n}\n","import { Shadow } from 'fabric';\nimport type { FabricObject } from 'fabric';\nimport type { LayerShadowConfig } from './types';\nimport { isCssColor } from './utils/color';\n\nexport const DEFAULT_LAYER_SHADOW: LayerShadowConfig = {\n enabled: false,\n color: '#000000',\n blur: 12,\n offsetX: 6,\n offsetY: 6,\n};\n\n/**\n * Read a layer's drop shadow back off its fabric object.\n *\n * Fabric serializes `shadow` with the object, so the object — not layer meta —\n * is the source of truth; nothing extra has to round-trip through the editor\n * state for a shadow to survive save/load.\n */\nexport function readLayerShadow(object: FabricObject): LayerShadowConfig {\n const shadow = object.shadow;\n if (!shadow || typeof shadow === 'string') return { ...DEFAULT_LAYER_SHADOW };\n return {\n enabled: true,\n color: typeof shadow.color === 'string' ? shadow.color : DEFAULT_LAYER_SHADOW.color,\n blur: shadow.blur ?? DEFAULT_LAYER_SHADOW.blur,\n offsetX: shadow.offsetX ?? DEFAULT_LAYER_SHADOW.offsetX,\n offsetY: shadow.offsetY ?? DEFAULT_LAYER_SHADOW.offsetY,\n };\n}\n\n/** Install (or remove) a drop shadow on a fabric object. */\nexport function applyLayerShadow(object: FabricObject, config: Partial<LayerShadowConfig>): void {\n const next = { ...readLayerShadow(object), ...config };\n if (!next.enabled) {\n object.set({ shadow: null });\n return;\n }\n // The colour reaches a canvas shadow and an exported SVG filter verbatim, so\n // an unparseable value must not get that far.\n const color = isCssColor(next.color) ? next.color : DEFAULT_LAYER_SHADOW.color;\n object.set({\n shadow: new Shadow({\n color,\n blur: Math.max(0, next.blur),\n offsetX: next.offsetX,\n offsetY: next.offsetY,\n }),\n });\n}\n","// Hex, functional (rgb/rgba/hsl/hsla), or a bare keyword such as `red`.\n// Deliberately conservative: values reach canvas fill styles and are copied\n// verbatim into exported SVG, so anything that is not clearly a colour must be\n// rejected rather than passed through.\nconst CSS_COLOR = /^(?:#[\\da-f]{3,8}|(?:rgb|hsl)a?\\([\\d.%+\\-\\s,/]+\\)|[a-z]+)$/i;\n\n/** True for values safe to use as a canvas/SVG colour. Empty means transparent. */\nexport function isCssColor(value: unknown, allowEmpty = false): value is string {\n if (typeof value !== 'string') return false;\n const trimmed = value.trim();\n if (!trimmed) return allowEmpty;\n return CSS_COLOR.test(trimmed);\n}\n","import type { Canvas, FabricObject } from 'fabric';\n\n/**\n * Look of the selection frame and its resize handles.\n *\n * Every measurement is in **screen** pixels. Zoom is a display transform (the\n * view layer CSS-scales the canvas element), so a handle drawn at its nominal\n * size would grow and shrink with the zoom level; `applySelectionStyle`\n * counter-scales by 1/zoom so the frame stays the same size on screen whatever\n * the zoom.\n */\nexport interface SelectionStyle {\n /** Colour of the frame around the selection. */\n borderColor: string;\n /** Fill of the resize handles. */\n cornerColor: string;\n /** Outline drawn around each handle. */\n cornerStrokeColor: string;\n /** Handle diameter, in screen pixels. */\n cornerSize: number;\n /** Round handles (as in the design tools) or square ones. */\n cornerStyle: 'circle' | 'rect';\n /** Frame line width, in screen pixels. */\n borderWidth: number;\n /** Dash pattern for the frame, in screen pixels. Null = solid. */\n borderDashArray: number[] | null;\n /** Gap between the object bounds and the frame, in screen pixels. */\n padding: number;\n /** Fill of the drag-to-select marquee. */\n marqueeFill: string;\n}\n\nexport const DEFAULT_SELECTION_STYLE: SelectionStyle = {\n borderColor: '#c9a96e',\n cornerColor: '#c9a96e',\n cornerStrokeColor: '#101010',\n cornerSize: 11,\n cornerStyle: 'circle',\n borderWidth: 1,\n borderDashArray: null,\n padding: 0,\n marqueeFill: 'rgba(201, 169, 110, 0.12)',\n};\n\n/** Applies the style to ONE object at the given display zoom. */\nexport function applyObjectSelectionStyle(\n object: FabricObject,\n style: SelectionStyle,\n zoom: number,\n): void {\n const scale = zoom > 0 ? 1 / zoom : 1;\n object.set({\n cornerSize: style.cornerSize * scale,\n cornerStyle: style.cornerStyle,\n cornerColor: style.cornerColor,\n cornerStrokeColor: style.cornerStrokeColor,\n // A filled handle is what makes the stroke colour visible at all.\n transparentCorners: false,\n borderColor: style.borderColor,\n borderScaleFactor: style.borderWidth * scale,\n borderDashArray: style.borderDashArray?.map((segment) => segment * scale) ?? null,\n padding: style.padding * scale,\n });\n}\n\n/**\n * Applies the style to every object on the canvas plus the active selection.\n *\n * The active selection is a transient group that `getObjects()` does not list,\n * so it is styled separately — otherwise a multi-object selection would keep\n * fabric's default blue squares.\n */\nexport function applySelectionStyle(canvas: Canvas, style: SelectionStyle, zoom: number): void {\n for (const object of canvas.getObjects()) applyObjectSelectionStyle(object, style, zoom);\n const active = canvas.getActiveObject();\n if (active) applyObjectSelectionStyle(active, style, zoom);\n canvas.selectionColor = style.marqueeFill;\n canvas.selectionBorderColor = style.borderColor;\n canvas.selectionLineWidth = style.borderWidth * (zoom > 0 ? 1 / zoom : 1);\n canvas.requestRenderAll();\n}\n","import type { FabricObject } from 'fabric';\n\n/** Side handles scale one axis; hiding them is what makes a resize uniform. */\nconst SIDE_CONTROLS = ['ml', 'mr', 'mt', 'mb'] as const;\n\n/**\n * Constrain (or release) a layer's proportions.\n *\n * Fabric already scales uniformly from the corners (`canvas.uniformScaling`),\n * so the lock is enforced by taking away the single-axis handles — every\n * remaining control keeps the ratio.\n */\nexport function applyAspectLock(object: FabricObject, locked: boolean): void {\n for (const control of SIDE_CONTROLS) {\n object.setControlVisible(control, !locked);\n }\n}\n\n/**\n * Undo scaling, rotation, skew and flips, leaving the layer where it sits.\n * Position is deliberately kept: this is \"reset the shape\", not \"move it back\".\n */\nexport function resetTransform(object: FabricObject): void {\n object.set({\n scaleX: 1,\n scaleY: 1,\n angle: 0,\n skewX: 0,\n skewY: 0,\n flipX: false,\n flipY: false,\n });\n object.setCoords();\n}\n","import type { Unit } from '../types';\n\nconst MM_PER_INCH = 25.4;\n\nexport class UnitConverter {\n private unit: Unit;\n private dpi: number;\n\n constructor(unit: Unit = 'px', dpi: number = 72) {\n this.unit = unit;\n this.dpi = 72;\n this.setDpi(dpi);\n }\n\n setUnit(unit: Unit): void {\n this.unit = unit;\n }\n\n setDpi(dpi: number): void {\n if (!Number.isFinite(dpi) || dpi <= 0) throw new Error('DPI must be a positive number');\n this.dpi = dpi;\n }\n\n getUnit(): Unit {\n return this.unit;\n }\n\n getDpi(): number {\n return this.dpi;\n }\n\n toPixels(value: number, fromUnit?: Unit): number {\n const u = fromUnit ?? this.unit;\n switch (u) {\n case 'px':\n return value;\n case 'in':\n return value * this.dpi;\n case 'mm':\n return (value / MM_PER_INCH) * this.dpi;\n }\n }\n\n fromPixels(px: number, toUnit?: Unit): number {\n const u = toUnit ?? this.unit;\n switch (u) {\n case 'px':\n return px;\n case 'in':\n return px / this.dpi;\n case 'mm':\n return (px / this.dpi) * MM_PER_INCH;\n }\n }\n}\n","import { util } from 'fabric';\nimport type { FabricObject } from 'fabric';\nimport type { EditorState, LayerData, SerializedLayer } from './types';\nimport type { CanvasEditor } from './editor';\nimport { Layer } from './layer';\nimport { isCssColor } from './utils/color';\nimport { applyAspectLock } from './transform';\n\nconst VERSION = '2.0.0';\n\nexport function serializeEditor(editor: CanvasEditor): EditorState {\n return {\n version: VERSION,\n canvas: {\n width: editor.canvas.getWidth(),\n height: editor.canvas.getHeight(),\n unit: editor.units.getUnit(),\n dpi: editor.units.getDpi(),\n },\n layers: editor.layers.getAll().map((layer) => layer.serialize()),\n // The configured design background, not the live canvas value (which is\n // forced transparent while a mockup preview is active).\n background: editor.getDesignBackground(),\n backgroundImage: editor.getDesignBackgroundImage()\n ? (editor.getDesignBackgroundImage()!.toObject() as Record<string, unknown>)\n : null,\n backgroundImageOptions: editor.getBackgroundImageOptions(),\n mockup: editor.getMockup(),\n };\n}\n\nexport async function deserializeEditor(editor: CanvasEditor, state: EditorState): Promise<void> {\n if (!state || !state.canvas || !Array.isArray(state.layers)) {\n throw new Error('Invalid editor state');\n }\n if (\n !Number.isFinite(state.canvas.width) ||\n !Number.isFinite(state.canvas.height) ||\n state.canvas.width <= 0 ||\n state.canvas.height <= 0 ||\n (state.canvas.unit !== undefined && !['px', 'mm', 'in'].includes(state.canvas.unit)) ||\n (state.canvas.dpi !== undefined &&\n (!Number.isFinite(state.canvas.dpi) || state.canvas.dpi <= 0))\n ) {\n throw new Error('Invalid editor canvas settings');\n }\n const major = Number.parseInt(state.version?.split('.')[0] ?? '1', 10);\n if (!Number.isFinite(major) || major > 2) {\n throw new Error(`Unsupported editor state version: ${state.version}`);\n }\n // The background is copied verbatim into exported SVG, so an untrusted state\n // must not be able to smuggle markup through it. Empty means transparent.\n if (state.background !== undefined && !isCssColor(state.background, true)) {\n throw new Error('Invalid editor background color');\n }\n\n // Enliven everything before touching the live document. A dead image URL or\n // malformed object must not turn a recoverable load failure into data loss.\n const staged = await Promise.all(\n state.layers.map(async (serialized) => {\n const fabricObject = (await util.enlivenObjects([serialized.fabricObject]))[0] as\n | FabricObject\n | undefined;\n if (!fabricObject) {\n const source = serialized.fabricObject.src;\n if (typeof source === 'string' && source.startsWith('blob:')) {\n throw new Error(`Failed to restore expired object URL: ${source}`);\n }\n throw new Error(`Failed to restore layer: ${serialized.id}`);\n }\n return { serialized, fabricObject };\n }),\n );\n const stagedBackground = state.backgroundImage\n ? ((await util.enlivenObjects([state.backgroundImage]))[0] as FabricObject | undefined)\n : null;\n if (state.backgroundImage && !stagedBackground) {\n const source = state.backgroundImage.src;\n if (typeof source === 'string' && source.startsWith('blob:')) {\n throw new Error(`Failed to restore expired background object URL: ${source}`);\n }\n throw new Error('Failed to restore background image');\n }\n\n editor.crop.cancel();\n editor.masks.detach();\n editor.layers.clear();\n if (state.canvas.unit) editor.units.setUnit(state.canvas.unit);\n if (state.canvas.dpi !== undefined) editor.units.setDpi(state.canvas.dpi);\n editor.canvas.setDimensions({ width: state.canvas.width, height: state.canvas.height });\n\n // setBackground records the design background; history is paused during\n // restore so this does not push a spurious entry. setMockup (below) then\n // applies the correct live canvas background.\n if (state.background !== undefined) {\n editor.setBackground(state.background);\n }\n editor.setBackgroundImageObject(\n stagedBackground ?? null,\n false,\n state.backgroundImageOptions ?? null,\n );\n\n // Missing on legacy states means there was no mockup.\n editor.setMockup(state.mockup ?? null);\n\n for (const item of staged) {\n restoreLayer(editor, item.serialized, item.fabricObject);\n }\n\n editor.canvas.requestRenderAll();\n}\n\nfunction restoreLayer(\n editor: CanvasEditor,\n serialized: SerializedLayer,\n fabricObject: FabricObject,\n): Layer {\n const layer = editor.layers.add(serialized.type, fabricObject, serialized.name, serialized.id);\n\n if (serialized.meta) {\n layer.meta = serialized.meta;\n // Control visibility is view state, not part of the fabric object's data:\n // a restored lock has to be re-applied or the side handles come back.\n if (layer.meta.lockAspect) applyAspectLock(fabricObject, true);\n }\n\n if (!serialized.visible) {\n editor.layers.setVisibility(layer.id, false);\n }\n if (serialized.locked) {\n editor.layers.setLocked(layer.id, true);\n }\n if (serialized.opacity !== 1) {\n editor.layers.setOpacity(layer.id, serialized.opacity);\n }\n\n // The enlivened group already carries its children's geometry; these records\n // re-attach identity (id, name, visibility, meta) to those objects, matched by\n // index. `meta.groupChildren` is the pre-0.6 shape of the same list.\n const childData =\n serialized.children ?? (serialized.meta?.groupChildren as LayerData[] | undefined);\n if (layer.type === 'group' && Array.isArray(childData)) {\n editor.layers.adoptGroupChildren(layer, childData);\n if (layer.meta.groupChildren) delete layer.meta.groupChildren;\n }\n\n return layer;\n}\n","import { StaticCanvas } from 'fabric';\nimport type { Canvas, FabricObject, ImageFormat } from 'fabric';\nimport type { MockupConfig, MockupPrintArea } from './types';\nimport { displaceRgba } from './displacement';\n\nexport interface PngExportOptions {\n multiplier?: number;\n format?: ImageFormat;\n quality?: number;\n}\n\nexport interface CoverPlacement {\n left: number;\n top: number;\n width: number;\n height: number;\n}\n\nexport function computePrintAreaClip(\n area: MockupPrintArea,\n scaleX: number,\n scaleY: number,\n targetWidth: number,\n targetHeight: number,\n): MockupPrintArea {\n const left = Math.max(0, Math.min(targetWidth, area.left * scaleX));\n const top = Math.max(0, Math.min(targetHeight, area.top * scaleY));\n const right = Math.max(left, Math.min(targetWidth, (area.left + area.width) * scaleX));\n const bottom = Math.max(top, Math.min(targetHeight, (area.top + area.height) * scaleY));\n return { left, top, width: right - left, height: bottom - top };\n}\n\n/** Object-fit: cover geometry, exported for deterministic preview/composite tests. */\nexport function computeCoverPlacement(\n sourceWidth: number,\n sourceHeight: number,\n targetWidth: number,\n targetHeight: number,\n): CoverPlacement {\n if (sourceWidth <= 0 || sourceHeight <= 0 || targetWidth <= 0 || targetHeight <= 0) {\n throw new Error('Cover dimensions must be positive');\n }\n const scale = Math.max(targetWidth / sourceWidth, targetHeight / sourceHeight);\n const width = sourceWidth * scale;\n const height = sourceHeight * scale;\n return {\n left: (targetWidth - width) / 2,\n top: (targetHeight - height) / 2,\n width,\n height,\n };\n}\n\nfunction canvasElementToBlob(\n output: HTMLCanvasElement,\n format: ImageFormat,\n quality: number,\n): Promise<Blob> {\n const mime = format === 'jpeg' ? 'image/jpeg' : `image/${format}`;\n return new Promise<Blob>((resolve, reject) => {\n output.toBlob(\n (blob) => (blob ? resolve(blob) : reject(new Error(`Failed to export ${format}`))),\n mime,\n quality,\n );\n });\n}\n\nexport async function exportPNG(canvas: Canvas, options: PngExportOptions = {}): Promise<Blob> {\n const { multiplier = 1, format = 'png' as ImageFormat, quality = 1 } = options;\n const output = canvas.toCanvasElement(multiplier);\n return canvasElementToBlob(output, format, quality);\n}\n\n/** Render cloned objects without mutating the live editor canvas. */\nexport async function exportIsolatedPNG(\n source: Canvas,\n objects: FabricObject[],\n options: PngExportOptions & {\n width?: number;\n height?: number;\n backgroundColor?: string;\n backgroundImage?: FabricObject | null;\n cloneObjects?: boolean;\n } = {},\n): Promise<Blob> {\n const element = source.lowerCanvasEl.ownerDocument.createElement('canvas');\n const canvas = new StaticCanvas(element, {\n width: options.width ?? source.getWidth(),\n height: options.height ?? source.getHeight(),\n backgroundColor: options.backgroundColor || undefined,\n });\n try {\n const clones =\n options.cloneObjects === false\n ? objects\n : await Promise.all(objects.map((object) => object.clone()));\n if (clones.length) canvas.add(...clones);\n if (options.backgroundImage) canvas.backgroundImage = await options.backgroundImage.clone();\n canvas.requestRenderAll();\n // Awaited, not returned: `finally` would otherwise dispose the canvas while\n // the export is still reading from it.\n return await exportPNG(canvas as unknown as Canvas, options);\n } finally {\n canvas.dispose();\n }\n}\n\n/**\n * Render just the print-area rectangle, on transparency.\n *\n * This is the file a print provider receives: the design alone, cropped to the\n * printable rectangle, with no garment behind it and no canvas background baked\n * in — so it is rendered from cloned objects rather than off the live canvas.\n */\nexport async function exportPrintArea(\n source: Canvas,\n area: MockupPrintArea,\n options: PngExportOptions = {},\n): Promise<Blob> {\n const { multiplier = 1, format = 'png' as ImageFormat, quality = 1 } = options;\n const width = source.getWidth();\n const height = source.getHeight();\n const clip = computePrintAreaClip(\n area,\n multiplier,\n multiplier,\n width * multiplier,\n height * multiplier,\n );\n if (clip.width <= 0 || clip.height <= 0) {\n throw new Error('Print area does not overlap the canvas');\n }\n\n const element = source.lowerCanvasEl.ownerDocument.createElement('canvas');\n const canvas = new StaticCanvas(element, { width, height });\n try {\n const clones = await Promise.all(source.getObjects().map((object) => object.clone()));\n if (clones.length) canvas.add(...clones);\n canvas.requestRenderAll();\n const rendered = canvas.toCanvasElement(multiplier);\n const output = rendered.ownerDocument.createElement('canvas');\n output.width = Math.max(1, Math.round(clip.width));\n output.height = Math.max(1, Math.round(clip.height));\n const context = output.getContext('2d');\n if (!context) throw new Error('2D canvas context is unavailable');\n context.drawImage(rendered, -clip.left, -clip.top);\n // Awaited, not returned: `finally` would dispose the canvas mid-read.\n return await canvasElementToBlob(output, format, quality);\n } finally {\n canvas.dispose();\n }\n}\n\n/** Rasterize the browser mockup preview together with the transparent design. */\nexport async function exportMockup(\n canvas: Canvas,\n mockup: MockupConfig,\n options: PngExportOptions = {},\n): Promise<Blob> {\n const { multiplier = 1, format = 'png' as ImageFormat, quality = 1 } = options;\n const design = canvas.toCanvasElement(multiplier);\n const output = design.ownerDocument.createElement('canvas');\n output.width = design.width;\n output.height = design.height;\n const context = output.getContext('2d');\n if (!context) throw new Error('2D canvas context is unavailable');\n\n const loadImage = (url: string) =>\n new Promise<HTMLImageElement>((resolve, reject) => {\n const element = new Image();\n element.crossOrigin = 'anonymous';\n element.onload = () => resolve(element);\n element.onerror = () => reject(new Error(`Failed to load mockup image: ${url}`));\n element.src = url;\n });\n const drawCover = (\n image: HTMLImageElement,\n targetContext: CanvasRenderingContext2D = context,\n ) => {\n const placement = computeCoverPlacement(\n image.naturalWidth || image.width,\n image.naturalHeight || image.height,\n output.width,\n output.height,\n );\n targetContext.drawImage(\n image,\n placement.left,\n placement.top,\n placement.width,\n placement.height,\n );\n };\n\n // Full-size scratch buffers, released explicitly in the finally below: a\n // detached canvas element can hold its backing store well past its last\n // reference, and a 4K mockup allocates three of them per export.\n const scratch: HTMLCanvasElement[] = [design];\n try {\n drawCover(await loadImage(mockup.image));\n let compositedDesign: CanvasImageSource = design;\n if (mockup.displacement) {\n const sourceContext = design.getContext('2d');\n if (!sourceContext) throw new Error('2D design context is unavailable');\n const mapCanvas = design.ownerDocument.createElement('canvas');\n scratch.push(mapCanvas);\n mapCanvas.width = design.width;\n mapCanvas.height = design.height;\n const mapContext = mapCanvas.getContext('2d');\n if (!mapContext) throw new Error('2D displacement-map context is unavailable');\n drawCover(await loadImage(mockup.displacement.image), mapContext);\n\n const warped = design.ownerDocument.createElement('canvas');\n scratch.push(warped);\n warped.width = design.width;\n warped.height = design.height;\n const warpedContext = warped.getContext('2d');\n if (!warpedContext) throw new Error('2D displaced-design context is unavailable');\n let sourcePixels: Uint8ClampedArray;\n let mapPixels: Uint8ClampedArray;\n try {\n sourcePixels = sourceContext.getImageData(0, 0, design.width, design.height).data;\n mapPixels = mapContext.getImageData(0, 0, design.width, design.height).data;\n } catch (error) {\n throw new Error('Failed to apply mockup displacement map; verify image CORS access', {\n cause: error,\n });\n }\n const pixels = displaceRgba(sourcePixels, mapPixels, design.width, design.height, {\n ...mockup.displacement,\n scaleX: (mockup.displacement.scaleX ?? 10) * multiplier,\n scaleY: (mockup.displacement.scaleY ?? 10) * multiplier,\n });\n const imageData = warpedContext.createImageData(design.width, design.height);\n imageData.data.set(pixels);\n warpedContext.putImageData(imageData, 0, 0);\n compositedDesign = warped;\n }\n context.save();\n if (mockup.printArea && mockup.clipToPrintArea !== false) {\n const clip = computePrintAreaClip(\n mockup.printArea,\n output.width / canvas.getWidth(),\n output.height / canvas.getHeight(),\n output.width,\n output.height,\n );\n context.beginPath();\n context.rect(clip.left, clip.top, clip.width, clip.height);\n context.clip();\n }\n context.globalAlpha = Math.max(0, Math.min(1, mockup.designOpacity ?? 1));\n context.globalCompositeOperation =\n !mockup.designBlendMode || mockup.designBlendMode === 'normal'\n ? 'source-over'\n : mockup.designBlendMode;\n context.drawImage(compositedDesign, 0, 0);\n context.restore();\n\n if (mockup.overlay) {\n context.save();\n context.globalAlpha = Math.max(0, Math.min(1, mockup.overlay.opacity ?? 1));\n context.globalCompositeOperation =\n mockup.overlay.blendMode === 'normal'\n ? 'source-over'\n : (mockup.overlay.blendMode ?? 'multiply');\n drawCover(await loadImage(mockup.overlay.image));\n context.restore();\n }\n return await canvasElementToBlob(output, format, quality);\n } finally {\n for (const element of scratch) {\n element.width = 0;\n element.height = 0;\n }\n }\n}\n\nexport function exportSVG(canvas: Canvas): string {\n return canvas.toSVG();\n}\n\nexport function exportDataURL(canvas: Canvas, format: ImageFormat = 'png', multiplier = 1): string {\n return canvas.toDataURL({ format, multiplier });\n}\n","import type { MockupDisplacement, MockupDisplacementChannel } from './types';\n\nconst CHANNEL_INDEX: Record<MockupDisplacementChannel, number> = {\n red: 0,\n green: 1,\n blue: 2,\n alpha: 3,\n};\n\nfunction finiteScale(value: number | undefined, fallback: number, label: string): number {\n const resolved = value ?? fallback;\n if (!Number.isFinite(resolved)) throw new Error(`${label} must be finite`);\n return resolved;\n}\n\nfunction sample(\n source: Uint8ClampedArray,\n width: number,\n height: number,\n x: number,\n y: number,\n channel: number,\n): number {\n const clampedX = Math.max(0, Math.min(width - 1, x));\n const clampedY = Math.max(0, Math.min(height - 1, y));\n const x0 = Math.floor(clampedX);\n const y0 = Math.floor(clampedY);\n const x1 = Math.min(width - 1, x0 + 1);\n const y1 = Math.min(height - 1, y0 + 1);\n const tx = clampedX - x0;\n const ty = clampedY - y0;\n const top =\n source[(y0 * width + x0) * 4 + channel] * (1 - tx) +\n source[(y0 * width + x1) * 4 + channel] * tx;\n const bottom =\n source[(y1 * width + x0) * 4 + channel] * (1 - tx) +\n source[(y1 * width + x1) * 4 + channel] * tx;\n return top * (1 - ty) + bottom * ty;\n}\n\n/**\n * Warp RGBA pixels with an equally sized channel map. A channel value of 128\n * is neutral; 0 and 255 move by the configured negative/positive maximum.\n */\nexport function displaceRgba(\n source: Uint8ClampedArray,\n map: Uint8ClampedArray,\n width: number,\n height: number,\n options: Omit<MockupDisplacement, 'image'>,\n): Uint8ClampedArray {\n if (!Number.isInteger(width) || !Number.isInteger(height) || width <= 0 || height <= 0) {\n throw new Error('Displacement dimensions must be positive integers');\n }\n const expectedLength = width * height * 4;\n if (source.length !== expectedLength || map.length !== expectedLength) {\n throw new Error('Displacement source and map must match the requested dimensions');\n }\n\n const scaleX = finiteScale(options.scaleX, 10, 'Displacement scaleX');\n const scaleY = finiteScale(options.scaleY, 10, 'Displacement scaleY');\n const channelX = CHANNEL_INDEX[options.channelX ?? 'red'];\n const channelY = CHANNEL_INDEX[options.channelY ?? 'green'];\n const output = new Uint8ClampedArray(expectedLength);\n\n for (let y = 0; y < height; y += 1) {\n for (let x = 0; x < width; x += 1) {\n const offset = (y * width + x) * 4;\n const sourceX = x + ((map[offset + channelX] - 128) / 127) * scaleX;\n const sourceY = y + ((map[offset + channelY] - 128) / 127) * scaleY;\n for (let channel = 0; channel < 4; channel += 1) {\n output[offset + channel] = Math.round(\n sample(source, width, height, sourceX, sourceY, channel),\n );\n }\n }\n }\n return output;\n}\n","/** XML text/attribute escaping for values interpolated into an SVG document. */\nexport function escapeXml(value: string | number): string {\n return String(value)\n .replaceAll('&', '&amp;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;')\n .replaceAll('\"', '&quot;')\n .replaceAll(\"'\", '&apos;');\n}\n\n/**\n * Strip active and externally-loaded content from an SVG before it is parsed\n * into canvas objects.\n *\n * This is the single implementation of the control — every path that turns\n * untrusted SVG into layers must call it, so it is exported rather than\n * re-declared per package.\n */\nexport function sanitizeSvg(svg: string): string {\n const document = new DOMParser().parseFromString(svg, 'image/svg+xml');\n if (document.querySelector('parsererror')) throw new Error('Invalid template SVG');\n document\n .querySelectorAll('script, foreignObject, iframe, object, embed, link, style')\n .forEach((node) => node.remove());\n document.querySelectorAll('*').forEach((node) => {\n for (const attribute of [...node.attributes]) {\n const name = attribute.name.toLowerCase();\n const value = attribute.value.trim().toLowerCase();\n const isLink = name === 'href' || name === 'xlink:href' || name === 'src';\n const safeLink =\n value.startsWith('#') || /^data:image\\/(?:png|jpeg|webp|gif);base64,/.test(value);\n if (\n name.startsWith('on') ||\n (isLink && !safeLink) ||\n (/url\\s*\\(/.test(value) && !/url\\s*\\(\\s*['\"]?#/.test(value)) ||\n /(?:javascript:|expression\\s*\\()/.test(value)\n ) {\n node.removeAttribute(attribute.name);\n }\n }\n });\n return new XMLSerializer().serializeToString(document.documentElement);\n}\n","import type { FontDefinition } from './types';\n\nfunction fontSource(source: string): string {\n return /^(?:url|local)\\(/.test(source.trim()) ? source : `url(${JSON.stringify(source)})`;\n}\n\nfunction mimeForSource(source: string): string {\n const path = source.split(/[?#]/)[0].toLowerCase();\n if (path.endsWith('.woff2')) return 'font/woff2';\n if (path.endsWith('.woff')) return 'font/woff';\n if (path.endsWith('.otf')) return 'font/otf';\n return 'font/ttf';\n}\n\nfunction arrayBufferToBase64(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer);\n let binary = '';\n for (let index = 0; index < bytes.length; index += 0x8000) {\n binary += String.fromCharCode(...bytes.subarray(index, index + 0x8000));\n }\n return btoa(binary);\n}\n\n/**\n * Quote a value for a CSS string token. JSON escaping covers quotes and\n * backslashes; `<`/`>`/`&` are additionally emitted as CSS hex escapes so a\n * crafted family name cannot close the `<style>` element when the exported SVG\n * is inlined into an HTML document.\n */\nfunction cssString(value: string): string {\n return JSON.stringify(value).replace(/[<>&]/g, (char) => `\\\\${char.charCodeAt(0).toString(16)} `);\n}\n\nconst SAFE_WEIGHT = /^(?:normal|bold|bolder|lighter|[1-9]\\d{0,2}(?:\\s+[1-9]\\d{0,2})?)$/i;\nconst SAFE_STYLE = /^(?:normal|italic|oblique(?:\\s+-?\\d+(?:\\.\\d+)?deg)?)$/i;\nconst SAFE_DISPLAY = /^(?:auto|block|swap|fallback|optional)$/i;\n\nfunction cssKeyword(value: string | undefined, pattern: RegExp, fallback: string): string {\n const trimmed = value?.trim();\n return trimmed && pattern.test(trimmed) ? trimmed : fallback;\n}\n\nfunction sourceUrl(source: string): string | null {\n const trimmed = source.trim();\n if (trimmed.startsWith('data:')) return trimmed;\n const match = trimmed.match(/^url\\(\\s*(['\"]?)(.*?)\\1\\s*\\)/i);\n if (match) return match[2];\n if (/^local\\(/i.test(trimmed)) return null;\n return trimmed;\n}\n\n/**\n * The font name inside a `local(...)` source, or null for any other form.\n * The name may not contain CSS punctuation, so a source that only *starts*\n * with `local(` cannot smuggle extra declarations through as a \"name\".\n */\nfunction localName(source: string): string | null {\n const match = source.trim().match(/^local\\(\\s*(['\"]?)([^)\"'{};]*)\\1\\s*\\)$/i);\n return match ? match[2].trim() || null : null;\n}\n\n/** Browser font loader and SVG embedding registry. */\nexport class FontRegistry {\n private definitions = new Map<string, FontDefinition>();\n private loads = new Map<string, Promise<FontFace>>();\n\n register(definition: FontDefinition): void {\n if (!definition.family.trim() || !definition.source.trim()) {\n throw new Error('Font family and source are required');\n }\n this.definitions.set(definition.family, { ...definition });\n this.loads.delete(definition.family);\n }\n\n unregister(family: string): boolean {\n this.loads.delete(family);\n return this.definitions.delete(family);\n }\n\n getAll(): FontDefinition[] {\n return [...this.definitions.values()].map((definition) => ({ ...definition }));\n }\n\n load(family: string): Promise<FontFace> {\n const cached = this.loads.get(family);\n if (cached) return cached;\n const definition = this.definitions.get(family);\n if (!definition) return Promise.reject(new Error(`Font is not registered: ${family}`));\n if (typeof FontFace === 'undefined' || typeof document === 'undefined') {\n return Promise.reject(new Error('Font loading requires a browser FontFace API'));\n }\n const promise = new FontFace(definition.family, fontSource(definition.source), {\n weight: definition.weight,\n style: definition.style,\n display: definition.display,\n })\n .load()\n .then((font) => {\n document.fonts.add(font);\n return font;\n });\n promise.catch(() => {\n if (this.loads.get(family) === promise) this.loads.delete(family);\n });\n this.loads.set(family, promise);\n return promise;\n }\n\n async ready(): Promise<void> {\n if (this.definitions.size === 0) return;\n await Promise.all([...this.definitions.keys()].map((family) => this.load(family)));\n await document.fonts.ready;\n }\n\n async getEmbeddedCss(): Promise<string> {\n const rules = await Promise.all(\n this.getAll().map(async (definition) => {\n // Every branch re-quotes the source rather than passing the registered\n // string through, so a definition can never inject raw CSS into the\n // `<style>` block this produces.\n const url = sourceUrl(definition.source);\n let cssSource: string;\n if (url && !url.startsWith('data:')) {\n const response = await fetch(url);\n if (!response.ok) throw new Error(`Failed to fetch font: ${url}`);\n const data = arrayBufferToBase64(await response.arrayBuffer());\n const mime = response.headers.get('content-type') || mimeForSource(url);\n cssSource = `url(${cssString(`data:${mime};base64,${data}`)})`;\n } else if (url) {\n cssSource = `url(${cssString(url)})`;\n } else {\n const name = localName(definition.source);\n if (!name) {\n throw new Error(`Unsupported font source for embedding: ${definition.family}`);\n }\n cssSource = `local(${cssString(name)})`;\n }\n const weight = cssKeyword(definition.weight, SAFE_WEIGHT, 'normal');\n const style = cssKeyword(definition.style, SAFE_STYLE, 'normal');\n const display = cssKeyword(definition.display, SAFE_DISPLAY, 'swap');\n return `@font-face{font-family:${cssString(definition.family)};src:${cssSource};font-weight:${weight};font-style:${style};font-display:${display}}`;\n }),\n );\n return rules.join('\\n');\n }\n}\n","import type { LicenseConfig, LicenseStatus } from './types';\n\nfunction domainMatches(hostname: string, pattern: string): boolean {\n const host = hostname.toLowerCase();\n const expected = pattern.toLowerCase();\n if (expected.startsWith('*.')) {\n const suffix = expected.slice(1);\n return host.endsWith(suffix) && host.length > suffix.length;\n }\n return host === expected;\n}\n\nfunction isLocal(hostname: string): boolean {\n return (\n hostname === 'localhost' ||\n hostname === '127.0.0.1' ||\n hostname === '::1' ||\n hostname.endsWith('.localhost')\n );\n}\n\n/** Inert, honor-system licensing and usage seam; it never performs a network request. */\nexport class LicenseManager {\n private status: LicenseStatus;\n private readyPromise: Promise<LicenseStatus>;\n\n constructor(private config: LicenseConfig = {}) {\n const hostname = config.hostname ?? globalThis.location?.hostname ?? 'localhost';\n const environment = config.environment ?? 'development';\n if (environment !== 'production' || isLocal(hostname)) {\n this.status = { state: 'exempt', payload: null };\n this.readyPromise = Promise.resolve(this.status);\n } else if (!config.key) {\n this.status = { state: 'community', payload: null };\n this.readyPromise = Promise.resolve(this.status);\n } else {\n this.status = { state: 'checking', payload: null };\n this.readyPromise = this.validate(config.key, hostname);\n }\n }\n\n getStatus(): LicenseStatus {\n return this.status;\n }\n\n ready(): Promise<LicenseStatus> {\n return this.readyPromise;\n }\n\n hasFeature(feature: string): boolean {\n return this.status.state === 'valid' && (this.status.payload.features ?? []).includes(feature);\n }\n\n track(name: string): void {\n this.config.onUsage?.({\n name,\n at: new Date().toISOString(),\n licenseId: this.status.state === 'valid' ? this.status.payload.id : undefined,\n });\n }\n\n private async validate(key: string, hostname: string): Promise<LicenseStatus> {\n const payload = (await this.config.verifyOffline?.(key)) ?? null;\n if (!payload) return (this.status = { state: 'invalid', payload: null });\n if (payload.expiresAt && Date.parse(payload.expiresAt) < Date.now()) {\n return (this.status = { state: 'expired', payload });\n }\n if (!payload.domains.some((domain) => domainMatches(hostname, domain))) {\n return (this.status = { state: 'domain-mismatch', payload });\n }\n return (this.status = { state: 'valid', payload });\n }\n}\n","import type { CanvasEditor } from './editor';\nimport type { EditorState, ProjectPage, ProjectState } from './types';\nimport { generateId } from './utils/id';\n\n/** Multi-page document state bound to one live editor canvas. */\nexport class ProjectManager {\n private pages: ProjectPage[];\n private activePageId: string;\n\n constructor(private editor: CanvasEditor) {\n const first = { id: generateId(), name: 'Page 1', state: editor.toJSON() };\n this.pages = [first];\n this.activePageId = first.id;\n }\n\n getAll(): Array<{ id: string; name: string }> {\n return this.pages.map(({ id, name }) => ({ id, name }));\n }\n\n getActivePageId(): string {\n return this.activePageId;\n }\n\n add(name = `Page ${this.pages.length + 1}`, cloneCurrent = false): string {\n this.saveCurrent();\n const source = structuredClone(this.editor.toJSON());\n const state = cloneCurrent ? source : this.blankState(source);\n const page = { id: generateId(), name, state };\n this.pages.push(page);\n this.emitChanged();\n return page.id;\n }\n\n async switchTo(id: string): Promise<boolean> {\n if (id === this.activePageId) return true;\n const page = this.pages.find((candidate) => candidate.id === id);\n if (!page) return false;\n this.saveCurrent();\n await this.editor.fromJSON(structuredClone(page.state));\n this.activePageId = id;\n this.emitChanged();\n return true;\n }\n\n async duplicate(id: string): Promise<string | null> {\n this.saveCurrent();\n const source = this.pages.find((page) => page.id === id);\n if (!source) return null;\n const page = {\n id: generateId(),\n name: `${source.name} copy`,\n state: structuredClone(source.state),\n };\n const index = this.pages.indexOf(source);\n this.pages.splice(index + 1, 0, page);\n this.emitChanged();\n return page.id;\n }\n\n async remove(id: string): Promise<boolean> {\n if (this.pages.length === 1) return false;\n const index = this.pages.findIndex((page) => page.id === id);\n if (index < 0) return false;\n if (id === this.activePageId) {\n const next = this.pages[index + 1] ?? this.pages[index - 1];\n await this.editor.fromJSON(structuredClone(next.state));\n this.activePageId = next.id;\n }\n this.pages.splice(index, 1);\n this.emitChanged();\n return true;\n }\n\n rename(id: string, name: string): boolean {\n const page = this.pages.find((candidate) => candidate.id === id);\n const trimmed = name.trim();\n if (!page || !trimmed || page.name === trimmed) return false;\n page.name = trimmed;\n this.emitChanged();\n return true;\n }\n\n reorder(id: string, newIndex: number): boolean {\n const index = this.pages.findIndex((page) => page.id === id);\n if (index < 0 || !Number.isFinite(newIndex)) return false;\n const target = Math.max(0, Math.min(this.pages.length - 1, Math.round(newIndex)));\n if (target === index) return false;\n const [page] = this.pages.splice(index, 1);\n this.pages.splice(target, 0, page);\n this.emitChanged();\n return true;\n }\n\n toJSON(): ProjectState {\n this.saveCurrent();\n return {\n version: '1.0.0',\n activePageId: this.activePageId,\n pages: structuredClone(this.pages),\n };\n }\n\n async fromJSON(project: ProjectState): Promise<void> {\n if (\n project?.version !== '1.0.0' ||\n !Array.isArray(project.pages) ||\n project.pages.length === 0 ||\n !project.pages.some((page) => page.id === project.activePageId)\n ) {\n throw new Error('Invalid project state');\n }\n const pages = structuredClone(project.pages);\n const active = pages.find((page) => page.id === project.activePageId)!;\n await this.editor.fromJSON(structuredClone(active.state));\n this.pages = pages;\n this.activePageId = active.id;\n this.emitChanged();\n }\n\n private saveCurrent(): void {\n const page = this.pages.find((candidate) => candidate.id === this.activePageId);\n if (page) page.state = structuredClone(this.editor.toJSON());\n }\n\n private blankState(source: EditorState): EditorState {\n return { ...source, layers: [], mockup: null };\n }\n\n private emitChanged(): void {\n this.editor.events.emit('project:changed', {\n activePageId: this.activePageId,\n pages: this.getAll(),\n });\n }\n}\n","import { FabricImage } from 'fabric';\nimport type { CanvasEditor } from './editor';\nimport type {\n MaskBrushOptions,\n MaskPoint,\n MaskRefinementPrompt,\n MaskRefinementProvider,\n MaskRefinementResult,\n} from './types';\nimport type { Layer } from './layer';\nimport { clamp } from './utils/clamp';\n\nexport type MaskRefinementErrorCode = 'not-found' | 'cancelled' | 'provider' | 'invalid-result';\n\nexport class MaskRefinementError extends Error {\n constructor(\n readonly code: MaskRefinementErrorCode,\n message: string,\n readonly cause?: unknown,\n ) {\n super(message);\n this.name = 'MaskRefinementError';\n }\n}\n\nexport interface MaskPerformanceSample {\n width: number;\n height: number;\n backingBytes: number;\n strokeBackupBytes: number;\n estimatedPeakBytes: number;\n historyBytes: number;\n interactionLatencyMs: number;\n usedJsHeapBytes?: number;\n elapsedMs: number;\n}\n\n/** Raster-mask editing without exposing Fabric brush classes in the public contract. */\nexport class MaskController {\n private backing: HTMLCanvasElement | null = null;\n private context: CanvasRenderingContext2D | null = null;\n private layerId: string | null = null;\n private brush: MaskBrushOptions | null = null;\n private previousPoint: MaskPoint | null = null;\n private strokeBackup: ImageData | null = null;\n private strokeStartedAt: number | null = null;\n private lastInteractionLatencyMs = 0;\n private refinement: AbortController | null = null;\n private disposed = false;\n\n constructor(private readonly editor: CanvasEditor) {}\n\n async create(\n width = this.editor.canvas.getWidth(),\n height = this.editor.canvas.getHeight(),\n ): Promise<Layer> {\n this.assertActive();\n if (!Number.isInteger(width) || !Number.isInteger(height) || width <= 0 || height <= 0) {\n throw new Error('Mask dimensions must be positive integers');\n }\n const backing = this.makeCanvas(width, height);\n const image = new FabricImage(backing, {\n left: 0,\n top: 0,\n originX: 'left',\n originY: 'top',\n selectable: false,\n });\n const layer = this.editor.layers.add('mask', image, 'Mask');\n layer.meta.mask = { width, height, revision: 0 };\n this.editor.history.saveImmediate();\n this.attachBacking(layer.id, backing);\n return layer;\n }\n\n attach(layerId: string): void {\n this.assertActive();\n // Swapping the backing store mid-stroke would leave the brush painting into\n // a canvas whose rollback snapshot belongs to the previous attachment.\n this.cancelStroke();\n const layer = this.requireMask(layerId);\n const image = layer.fabricObject as FabricImage;\n const width = layer.meta.mask?.width ?? image.width ?? this.editor.canvas.getWidth();\n const height = layer.meta.mask?.height ?? image.height ?? this.editor.canvas.getHeight();\n const backing = this.makeCanvas(width, height);\n const context = backing.getContext('2d');\n if (!context) throw new Error('2D mask context is unavailable');\n const element = image.getElement();\n if (element) context.drawImage(element, 0, 0, width, height);\n this.attachBacking(layerId, backing);\n }\n\n beginStroke(options: MaskBrushOptions): void {\n this.assertActive();\n if (!this.context || !this.backing || !this.layerId) throw new Error('Attach a mask first');\n if (this.brush) throw new Error('A mask stroke is already active');\n if (!Number.isFinite(options.size) || options.size <= 0) {\n throw new Error('Mask brush size must be positive');\n }\n this.brush = { ...options, hardness: clamp(options.hardness, 0, 1) };\n this.previousPoint = null;\n this.strokeBackup = this.context.getImageData(0, 0, this.backing.width, this.backing.height);\n this.strokeStartedAt = performance.now();\n }\n\n addPoint(point: MaskPoint): void {\n if (!this.brush || !this.context || !this.backing || !this.layerId) {\n throw new Error('No active mask stroke');\n }\n if (!Number.isFinite(point.x) || !Number.isFinite(point.y)) return;\n const previous = this.previousPoint ?? point;\n const distance = Math.hypot(point.x - previous.x, point.y - previous.y);\n const step = Math.max(1, this.brush.size / 4);\n const samples = Math.max(1, Math.ceil(distance / step));\n for (let index = 0; index <= samples; index += 1) {\n const ratio = index / samples;\n this.drawDot({\n x: previous.x + (point.x - previous.x) * ratio,\n y: previous.y + (point.y - previous.y) * ratio,\n });\n }\n this.previousPoint = point;\n (this.requireMask(this.layerId).fabricObject as FabricImage).setElement(this.backing);\n this.editor.canvas.requestRenderAll();\n }\n\n async endStroke(): Promise<void> {\n if (!this.brush || !this.backing || !this.layerId) return;\n const layerId = this.layerId;\n this.brush = null;\n this.previousPoint = null;\n this.strokeBackup = null;\n const dataUrl = this.backing.toDataURL('image/png');\n await this.editor.history.transaction(async () => {\n await this.editor.replaceImageSource(layerId, dataUrl);\n const layer = this.requireMask(layerId);\n if (layer.meta.mask) layer.meta.mask.revision += 1;\n });\n this.attach(layerId);\n if (this.strokeStartedAt !== null) {\n this.lastInteractionLatencyMs = performance.now() - this.strokeStartedAt;\n this.strokeStartedAt = null;\n }\n }\n\n cancelStroke(): void {\n if (this.strokeBackup && this.context && this.backing && this.layerId) {\n this.context.putImageData(this.strokeBackup, 0, 0);\n (this.requireMask(this.layerId).fabricObject as FabricImage).setElement(this.backing);\n this.editor.canvas.requestRenderAll();\n }\n this.brush = null;\n this.previousPoint = null;\n this.strokeBackup = null;\n this.strokeStartedAt = null;\n }\n\n isStrokeActive(): boolean {\n return this.brush !== null;\n }\n\n activeLayerId(): string | null {\n return this.layerId;\n }\n\n detach(layerId?: string): void {\n if (layerId && this.layerId !== layerId) return;\n this.cancelStroke();\n this.cancelRefinement();\n this.backing = null;\n this.context = null;\n this.layerId = null;\n }\n\n async refine(\n layerId: string,\n provider: MaskRefinementProvider,\n prompts: MaskRefinementPrompt[],\n options: { signal?: AbortSignal; onProgress?: (progress: number) => void } = {},\n ): Promise<MaskRefinementResult> {\n this.assertActive();\n const layer = this.editor.layers.get(layerId);\n if (!layer || layer.type !== 'mask') {\n throw new MaskRefinementError('not-found', `Mask layer not found: ${layerId}`);\n }\n this.cancelRefinement();\n const controller = new AbortController();\n this.refinement = controller;\n const abort = () => controller.abort(options.signal?.reason);\n options.signal?.addEventListener('abort', abort, { once: true });\n if (options.signal?.aborted) abort();\n try {\n const image = layer.fabricObject as FabricImage;\n const result = await provider.refine(\n {\n mask: image.getSrc(),\n width: layer.meta.mask?.width ?? image.width ?? 1,\n height: layer.meta.mask?.height ?? image.height ?? 1,\n prompts: structuredClone(prompts),\n },\n { signal: controller.signal, onProgress: options.onProgress },\n );\n if (controller.signal.aborted)\n throw new MaskRefinementError('cancelled', 'Mask refinement cancelled');\n // Raster only: history content-addresses raster data URLs, and a vector\n // result would let a third-party provider inject markup into the document.\n if (!/^data:image\\/(?:png|jpeg|webp);base64,/i.test(result.dataUrl)) {\n throw new MaskRefinementError(\n 'invalid-result',\n 'Mask refinement must return a base64 PNG, JPEG, or WebP data URL',\n );\n }\n await this.editor.history.transaction(async () => {\n await this.editor.replaceImageSource(layerId, result.dataUrl);\n if (layer.meta.mask) layer.meta.mask.revision += 1;\n });\n this.attach(layerId);\n return result;\n } catch (error) {\n if (error instanceof MaskRefinementError) throw error;\n if (controller.signal.aborted) {\n throw new MaskRefinementError('cancelled', 'Mask refinement cancelled', error);\n }\n throw new MaskRefinementError('provider', 'Mask refinement provider failed', error);\n } finally {\n options.signal?.removeEventListener('abort', abort);\n if (this.refinement === controller) this.refinement = null;\n }\n }\n\n cancelRefinement(): void {\n this.refinement?.abort(new DOMException('Cancelled', 'AbortError'));\n this.refinement = null;\n }\n\n measure(): MaskPerformanceSample | null {\n if (!this.backing) return null;\n const started = performance.now();\n this.context?.getImageData(0, 0, 1, 1);\n const backingBytes = this.backing.width * this.backing.height * 4;\n const strokeBackupBytes = this.strokeBackup ? backingBytes : 0;\n const memory = performance as Performance & { memory?: { usedJSHeapSize?: number } };\n return {\n width: this.backing.width,\n height: this.backing.height,\n backingBytes,\n strokeBackupBytes,\n // The backing store and rollback ImageData dominate interactive mask\n // memory. Encoded historical rasters are reported separately below.\n estimatedPeakBytes: backingBytes + strokeBackupBytes,\n historyBytes: this.editor.history.getSnapshotBytes(),\n interactionLatencyMs: this.lastInteractionLatencyMs,\n ...(typeof memory.memory?.usedJSHeapSize === 'number'\n ? { usedJsHeapBytes: memory.memory.usedJSHeapSize }\n : {}),\n elapsedMs: performance.now() - started,\n };\n }\n\n dispose(): void {\n this.detach();\n this.disposed = true;\n }\n\n private drawDot(point: MaskPoint): void {\n const context = this.context!;\n const brush = this.brush!;\n const radius = brush.size / 2;\n context.save();\n context.globalCompositeOperation =\n brush.mode === 'subtract' ? 'destination-out' : 'source-over';\n const gradient = context.createRadialGradient(\n point.x,\n point.y,\n radius * brush.hardness,\n point.x,\n point.y,\n radius,\n );\n const color = brush.mode === 'subtract' ? 'rgba(0,0,0,1)' : 'rgba(255,255,255,1)';\n gradient.addColorStop(0, color);\n gradient.addColorStop(1, 'rgba(255,255,255,0)');\n context.fillStyle = gradient;\n context.beginPath();\n context.arc(point.x, point.y, radius, 0, Math.PI * 2);\n context.fill();\n context.restore();\n }\n\n private makeCanvas(width: number, height: number): HTMLCanvasElement {\n const canvas = this.editor.canvas.lowerCanvasEl.ownerDocument.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n return canvas;\n }\n\n private attachBacking(layerId: string, backing: HTMLCanvasElement): void {\n const context = backing.getContext('2d');\n if (!context) throw new Error('2D mask context is unavailable');\n this.layerId = layerId;\n this.backing = backing;\n this.context = context;\n }\n\n private requireMask(layerId: string): Layer {\n const layer = this.editor.layers.get(layerId);\n if (!layer || layer.type !== 'mask') throw new Error(`Mask layer not found: ${layerId}`);\n return layer;\n }\n\n private assertActive(): void {\n if (this.disposed) throw new Error('Mask controller has been disposed');\n }\n}\n","import { Group } from 'fabric';\nimport type { Canvas, FabricObject } from 'fabric';\nimport type { EditorEvents, LayerMaskEntry, LayerMaskMode } from '../types';\nimport type { EventEmitter } from '../events';\nimport type { HistoryManager } from '../history';\nimport type { LayerManager } from '../layer';\nimport { generateId } from '../utils/id';\nimport { needsAbsoluteSpace } from './compose';\nimport { MaskEditController, type MaskEditTarget } from './edit';\nimport { applyRelativeMatrix, fitToBox, toHostSpace, toMatrix } from './space';\nimport type { MaskBox } from './host';\nimport { CANVAS_MASK_TARGET, DEFAULT_ENTRY, MaskStackStore } from './store';\n\nexport interface AddMaskOptions {\n name?: string;\n mode?: LayerMaskMode;\n linked?: boolean;\n /** Host data describing where the geometry came from (preset id, generator…). */\n meta?: Record<string, unknown>;\n /** Scale the geometry to the host's box (a number zooms it); default 1. */\n fit?: number | false;\n /**\n * Fit to this box instead of the host's own, in the stack's coordinate space.\n * The whole-design overlay spans the canvas, but a mask on it usually wants to\n * frame the artwork, which occupies part of it.\n */\n box?: { left: number; top: number; width: number; height: number };\n}\n\n/**\n * Stacked, boolean-composed masks — one ordered list per host, where a host is\n * either a layer or the design as a whole (`CANVAS_MASK_TARGET`). Storage and\n * clip composition live in `MaskStackStore`; this class is what a UI drives.\n */\nexport class LayerMaskManager extends MaskStackStore {\n // Committing mid-drag would recompose the group the handle writes into and\n // leave it pointing at a discarded object; the geometry is settled on endEdit.\n private readonly edits = new MaskEditController(this.canvas, () => this.history.save());\n private readonly onLayersChanged = () => this.pin();\n // Selecting a layer means the user has moved on from the mask they had open;\n // leaving both selected would show mask controls for an unrelated layer.\n private readonly onLayerSelected = ({ layerId }: { layerId: string | null }) => {\n // Only a real layer takes the focus away. `select(null)` is also what THIS\n // class calls to hand the focus the other way, and clearing on it would undo\n // the mask selection that triggered it.\n if (layerId && this.selected) this.select(null, null);\n };\n private readonly onObjectModified = (event: { target?: FabricObject }) => {\n const object = event.target;\n if (!object) return;\n const layer = this.layers.findByObject(object);\n if (layer) this.reflow(layer.id);\n };\n\n constructor(\n canvas: Canvas,\n layers: LayerManager,\n history: HistoryManager,\n events: EventEmitter<EditorEvents>,\n ) {\n super(canvas, layers, history, events);\n this.events.on('layers:changed', this.onLayersChanged);\n this.events.on('layer:selected', this.onLayerSelected);\n // A linked mask in a canvas-space stack has to be re-derived after the host\n // moves; fabric only does that for us in host space.\n this.canvas.on('object:modified', this.onObjectModified);\n }\n\n dispose(): void {\n this.edits.dispose();\n this.events.off('layers:changed', this.onLayersChanged);\n this.events.off('layer:selected', this.onLayerSelected);\n this.canvas.off('object:modified', this.onObjectModified);\n this.selected = null;\n }\n\n // ─── Geometry editing ────────────────────────────────\n\n /** The mask currently being dragged on the canvas, if any. */\n editing(): MaskEditTarget | null {\n return this.edits.active();\n }\n\n /**\n * Put drag handles on one mask. The stack is composed in canvas space for the\n * duration — a linked mask would otherwise sit in the host's space, where the\n * handle's own canvas coordinates mean something else entirely. `endEdit`\n * returns it to whichever space its entries call for.\n */\n async beginEdit(target: string, maskId: string): Promise<boolean> {\n const host = this.host(target);\n if (!host) return false;\n const entries = this.list(target);\n const index = entries.findIndex((entry) => entry.id === maskId);\n if (index === -1) return false;\n\n this.endEdit(false);\n this.commit(target, host, [...entries], this.unwrap(target, host), false, true);\n const group = host.clipPath instanceof Group ? host.clipPath : null;\n if (!group) return false;\n const children = group.getObjects();\n // The implicit base child (a stack opening with a cut) shifts every entry.\n const child = children[children.length - entries.length + index];\n if (!child) return false;\n\n this.select(target, maskId);\n return this.edits.begin({ target, maskId }, group, child);\n }\n\n /** Take the handles down and settle the stack back into its own space. */\n endEdit(save = true): void {\n const editing = this.edits.active();\n this.edits.end();\n if (editing) this.rebuild(editing.target, save);\n }\n\n // ─── Selection ───────────────────────────────────────\n\n getSelected(): { target: string; maskId: string } | null {\n return this.selected;\n }\n\n select(target: string | null, maskId: string | null): void {\n this.selected = target && maskId ? { target, maskId } : null;\n // Picking a mask moves the focus onto it. Leaving the layer selected too\n // left its row lit and its handles on the canvas, so two rows claimed to be\n // the selection and the property panels showed the wrong one's controls.\n if (this.selected) this.layers.select(null);\n this.events.emit('mask:selected', { target, maskId: this.selected ? maskId : null });\n }\n\n // ─── Mutations ───────────────────────────────────────\n\n add(target: string, object: FabricObject, options: AddMaskOptions = {}): LayerMaskEntry | null {\n const host = this.host(target, true);\n if (!host) return null;\n const sources = this.unwrap(target, host);\n const entries = this.entriesFor(target, sources);\n const entry: LayerMaskEntry = {\n ...DEFAULT_ENTRY,\n id: generateId(),\n name: options.name ?? 'Mask',\n ...(options.mode ? { mode: options.mode } : {}),\n ...(options.linked === undefined ? {} : { linked: options.linked }),\n ...(options.meta ? { meta: options.meta } : {}),\n };\n // The canvas stack has no host transform to follow, so \"linked\" is meaningless\n // there — pin it, or a re-fit would fight the overlay's own full-canvas box.\n if (target === CANVAS_MASK_TARGET) entry.linked = false;\n\n if (options.fit !== false) {\n fitToBox(object, options.box ?? this.hostBox(target), options.fit ?? 1);\n }\n sources.push(object);\n entries.push(entry);\n this.commit(target, host, entries, sources);\n return entry;\n }\n\n /** Swap one mask's geometry, keeping its identity, mode and position in the stack. */\n replaceGeometry(\n target: string,\n maskId: string,\n object: FabricObject,\n options: AddMaskOptions = {},\n ): boolean {\n const host = this.host(target);\n if (!host) return false;\n const entries = [...this.list(target)];\n const index = entries.findIndex((entry) => entry.id === maskId);\n if (index === -1) return false;\n const sources = this.unwrap(target, host);\n if (options.fit !== false) {\n fitToBox(object, options.box ?? this.hostBox(target), options.fit ?? 1);\n }\n sources[index] = object;\n entries[index] = {\n ...entries[index],\n ...(options.name ? { name: options.name } : {}),\n ...(options.meta ? { meta: options.meta } : {}),\n };\n this.commit(target, host, entries, sources);\n return true;\n }\n\n /**\n * Re-fit one mask to its host's box (or `box`) at `fit` scale, keeping the\n * geometry it already has. This is what a zoom control drives: re-picking the\n * mask would cost another render of a generated alpha map just to resize it.\n */\n refit(\n target: string,\n maskId: string,\n options: { fit?: number; box?: MaskBox; save?: boolean } = {},\n ): boolean {\n const host = this.host(target);\n if (!host) return false;\n const entries = [...this.list(target)];\n const index = entries.findIndex((entry) => entry.id === maskId);\n if (index === -1) return false;\n const sources = this.unwrap(target, host);\n const source = sources[index];\n if (!source) return false;\n fitToBox(source, options.box ?? this.hostBox(target), options.fit ?? 1);\n this.commit(target, host, entries, sources, options.save ?? true);\n return true;\n }\n\n remove(target: string, maskId: string): boolean {\n const host = this.host(target);\n if (!host) return false;\n const entries = [...this.list(target)];\n const index = entries.findIndex((entry) => entry.id === maskId);\n if (index === -1) return false;\n const sources = this.unwrap(target, host);\n entries.splice(index, 1);\n sources.splice(index, 1);\n if (this.selected?.maskId === maskId) this.select(null, null);\n this.commit(target, host, entries, sources);\n return true;\n }\n\n clear(target: string): boolean {\n const host = this.host(target);\n if (!host) return false;\n if (this.list(target).length === 0) return false;\n if (this.selected?.target === target) this.select(null, null);\n this.commit(target, host, [], []);\n return true;\n }\n\n reorder(target: string, maskId: string, index: number): boolean {\n const host = this.host(target);\n if (!host) return false;\n const entries = [...this.list(target)];\n const from = entries.findIndex((entry) => entry.id === maskId);\n if (from === -1) return false;\n const to = Math.max(0, Math.min(entries.length - 1, Math.round(index)));\n if (from === to) return false;\n const sources = this.unwrap(target, host);\n const [entry] = entries.splice(from, 1);\n const [source] = sources.splice(from, 1);\n entries.splice(to, 0, entry);\n sources.splice(to, 0, source);\n this.commit(target, host, entries, sources);\n return true;\n }\n\n /** Replace a mask's host metadata (which preset or generator produced it). */\n setMeta(target: string, maskId: string, meta: Record<string, unknown>): boolean {\n return this.patch(target, maskId, () => ({ meta }));\n }\n\n setMode(target: string, maskId: string, mode: LayerMaskMode): boolean {\n return this.patch(target, maskId, (entry) => (entry.mode === mode ? null : { mode }));\n }\n\n setVisible(target: string, maskId: string, visible: boolean): boolean {\n return this.patch(target, maskId, (entry) => (entry.visible === visible ? null : { visible }));\n }\n\n setOpacity(target: string, maskId: string, opacity: number): boolean {\n if (!Number.isFinite(opacity)) return false;\n const next = Math.max(0, Math.min(1, opacity));\n return this.patch(target, maskId, (entry) =>\n entry.opacity === next ? null : { opacity: next },\n );\n }\n\n setName(target: string, maskId: string, name: string): boolean {\n const trimmed = name.trim();\n if (!trimmed) return false;\n return this.patch(target, maskId, (entry) =>\n entry.name === trimmed ? null : { name: trimmed },\n );\n }\n\n /**\n * Link or unlink one mask. Unlinking pins it where it currently appears;\n * re-linking records its position relative to the host so later host moves\n * carry it along.\n */\n setLinked(target: string, maskId: string, linked: boolean): boolean {\n if (target === CANVAS_MASK_TARGET) return false;\n const host = this.host(target);\n if (!host) return false;\n const entries = [...this.list(target)];\n const index = entries.findIndex((entry) => entry.id === maskId);\n if (index === -1 || entries[index].linked === linked) return false;\n const sources = this.unwrap(target, host);\n entries[index] = { ...entries[index], linked };\n this.commit(target, host, entries, sources);\n return true;\n }\n\n /**\n * Consume a layer, turning its artwork into a mask. Without an explicit target\n * it masks the layer directly beneath it, and the bottom layer masks the whole\n * design — there is nothing under it to clip.\n */\n convertLayer(layerId: string, target?: string): { target: string; entry: LayerMaskEntry } | null {\n const layer = this.layers.get(layerId);\n if (!layer || layer.meta.canvasMask) return null;\n const ordered = this.layers.getAll();\n const index = ordered.findIndex((candidate) => candidate.id === layerId);\n const below = index > 0 ? ordered[index - 1] : undefined;\n const resolved = target ?? (below && !below.meta.canvasMask ? below.id : CANVAS_MASK_TARGET);\n if (resolved === layerId) return null;\n\n const object = layer.fabricObject;\n // A shape authored with no fill would mask nothing; images and text carry\n // their own alpha, which is exactly what a mask reads.\n if (!object.fill && object.type !== 'image') object.set({ fill: '#000000' });\n\n // The layer's geometry is in CANVAS space — it was standing on the canvas a\n // moment ago — but a linked stack composes in HOST space, whose origin is the\n // host's centre. Handed over unconverted, the mask is displaced by the whole\n // of the host's transform: far enough, on any host that is not sitting at the\n // origin, that the clip covers none of it and the layer disappears outright.\n // `add(fit: false)` is what keeps it where the user put it, so the conversion\n // has to happen here, where the source space is still known.\n const stackHost = this.host(resolved);\n const absolute = resolved === CANVAS_MASK_TARGET || needsAbsoluteSpace(this.list(resolved));\n if (!absolute && stackHost) toHostSpace(object, stackHost);\n\n // One checkpoint for the whole conversion: undoing it has to bring the layer\n // back, not leave the artwork deleted with the mask removed.\n this.history.beginTransaction();\n try {\n // Drop the canvas selection first: removing an active object makes fabric\n // fire `selection:cleared`, which clears the mask selection — including the\n // one this method is about to make.\n if (this.canvas.getActiveObject() === object) this.canvas.discardActiveObject();\n this.canvas.remove(object);\n this.layers.remove(layerId);\n const entry = this.add(resolved, object, { name: layer.name, fit: false });\n return entry ? { target: resolved, entry } : null;\n } finally {\n this.history.endTransaction();\n }\n }\n\n // ─── Rebuild / restore ───────────────────────────────\n\n /** Recompose one stack's clip from the geometry it already holds. */\n rebuild(target: string, save = false): void {\n const host = this.host(target);\n if (!host) return;\n const sources = this.unwrap(target, host);\n if (sources.length === 0) return;\n this.commit(target, host, this.entriesFor(target, sources), sources, save);\n }\n\n /** Re-derive linked masks after the host moved (canvas-space stacks only). */\n private reflow(target: string): void {\n const host = this.host(target);\n if (!host) return;\n const entries = this.list(target);\n if (entries.length === 0 || !needsAbsoluteSpace(entries)) return;\n if (!entries.some((entry) => entry.linked && entry.rel)) return;\n const sources = this.unwrap(target, host);\n entries.forEach((entry, index) => {\n const source = sources[index];\n const rel = toMatrix(entry.rel);\n if (!source || !entry.linked || !rel) return;\n applyRelativeMatrix(source, host, rel);\n });\n this.commit(target, host, [...entries], sources);\n }\n\n /**\n * Adopt a clip this manager did not install — a host's own single `clipPath` —\n * as a one-entry stack, so it shows up in the UI as a mask row before anything\n * is added to it. A mask preset is left alone unless asked for by name: it is\n * still owned by `MaskPresetManager` until a stack operation takes it over.\n */\n adopt(target: string, name?: string): LayerMaskEntry | null {\n const layer = this.hostLayer(target);\n const clip = layer?.fabricObject.clipPath;\n // A pattern strips and restores the layer's clip on its own; that clip is\n // the tiling's, not the user's mask.\n if (!layer || !clip || layer.meta.pattern) return null;\n if ((layer.meta.maskStack ?? []).length > 0) return null;\n const entry: LayerMaskEntry = {\n ...DEFAULT_ENTRY,\n id: generateId(),\n name: name ?? 'Mask',\n linked: target === CANVAS_MASK_TARGET ? false : !clip.absolutePositioned,\n };\n layer.meta.maskStack = [entry];\n delete layer.meta.maskPreset;\n this.rebuild(target);\n return entry;\n }\n\n /** After a state restore: re-pin the design overlay and recompose every stack. */\n refreshAll(): void {\n this.selected = null;\n this.pin();\n for (const layer of this.layers.getAll()) {\n if ((layer.meta.maskStack ?? []).length === 0) continue;\n this.rebuild(layer.meta.canvasMask ? CANVAS_MASK_TARGET : layer.id);\n }\n }\n\n // ─── Internals ───────────────────────────────────────\n\n private patch(\n target: string,\n maskId: string,\n change: (entry: LayerMaskEntry) => Partial<LayerMaskEntry> | null,\n ): boolean {\n const host = this.host(target);\n if (!host) return false;\n const entries = [...this.list(target)];\n const index = entries.findIndex((entry) => entry.id === maskId);\n if (index === -1) return false;\n const patch = change(entries[index]);\n if (!patch) return false;\n const sources = this.unwrap(target, host);\n entries[index] = { ...entries[index], ...patch };\n this.commit(target, host, entries, sources);\n return true;\n }\n}\n","import { Group, Rect } from 'fabric';\nimport type { FabricObject } from 'fabric';\nimport type { LayerMaskEntry, LayerMaskMode } from '../types';\n\n/**\n * Compositing operation each mask mode contributes inside the clip group.\n *\n * The group is cached, so a child's `globalCompositeOperation` applies against\n * the siblings drawn before it — that cache is what turns a flat list of shapes\n * into a boolean stack (verified by the acceptance tests, which read pixels).\n */\nconst MODE_OPERATION: Record<LayerMaskMode, GlobalCompositeOperation> = {\n add: 'source-over',\n subtract: 'destination-out',\n intersect: 'destination-in',\n};\n\n/**\n * A hidden mask still contributes a child, drawn as a no-op: dropping it would\n * shift every following child's index, and the group's children are what gets\n * serialized — a hidden mask would not survive a save/reload.\n */\nfunction neutralize(child: FabricObject): void {\n child.set({ opacity: 0, globalCompositeOperation: 'source-over' });\n}\n\n/**\n * `subtract` and `intersect` cut into what is already drawn, so a stack that\n * opens with one has nothing to cut and would mask everything away. Give it the\n * host's own box to start from — \"the whole layer, minus this hole\".\n */\nfunction baseRect(box: { left: number; top: number; width: number; height: number }): FabricObject {\n return new Rect({\n left: box.left,\n top: box.top,\n width: Math.max(1, box.width),\n height: Math.max(1, box.height),\n originX: 'left',\n originY: 'top',\n fill: '#000000',\n objectCaching: false,\n });\n}\n\nexport interface ComposeOptions {\n /** Host box in the coordinate space the children use, for the implicit base. */\n box: { left: number; top: number; width: number; height: number };\n /**\n * Canvas-space children (an unlinked mask is pinned to the canvas, so the\n * whole group has to leave the host's local space with it).\n */\n absolute: boolean;\n}\n\n/**\n * Build the `clipPath` for one mask stack: one child per entry, in order, each\n * carrying its mode's compositing operation.\n *\n * `children` are consumed — a Group takes ownership of what it is given and\n * rewrites the coordinates, so callers pass clones of their sources rather than\n * the sources themselves.\n */\nexport function composeMaskGroup(\n children: FabricObject[],\n entries: LayerMaskEntry[],\n options: ComposeOptions,\n): Group | undefined {\n if (children.length === 0) return undefined;\n\n children.forEach((child, index) => {\n const entry = entries[index];\n child.set({ objectCaching: false });\n if (!entry || !entry.visible) {\n neutralize(child);\n return;\n }\n child.set({\n opacity: entry.opacity,\n globalCompositeOperation: MODE_OPERATION[entry.mode] ?? 'source-over',\n });\n });\n\n const first = entries.find((entry) => entry.visible);\n const withBase =\n first && first.mode !== 'add' ? [baseRect(options.box), ...children] : [...children];\n\n return new Group(withBase, {\n absolutePositioned: options.absolute,\n // Cached, so the children's compositing operations resolve against each\n // other instead of against the page underneath the mask.\n objectCaching: true,\n subTargetCheck: false,\n interactive: false,\n });\n}\n\n/** True when the stack has to be composed in canvas space rather than host space. */\nexport function needsAbsoluteSpace(entries: LayerMaskEntry[]): boolean {\n return entries.some((entry) => !entry.linked);\n}\n","import { Group, util } from 'fabric';\nimport type { Canvas, FabricObject } from 'fabric';\nimport { applyMatrix, matrixOf } from './space';\n\nexport interface MaskEditTarget {\n target: string;\n maskId: string;\n}\n\n/**\n * Drag-to-edit for one mask's geometry.\n *\n * A mask lives inside the host's clip group, where fabric will not give it\n * selection handles — a `clipPath` is drawn, never hit-tested. So editing works\n * through a **handle**: a clone of the mask placed on the canvas, styled as an\n * outline, whose transform is written back into the real clip child on every\n * move. The clip itself keeps rendering throughout, so the artwork updates live\n * rather than after the drag ends.\n *\n * The stack is composed in canvas space for the duration (`forceAbsolute`),\n * which is what lets the handle's canvas transform map onto the child with one\n * inversion instead of also unwinding the host's transform.\n */\nexport class MaskEditController {\n private handle: FabricObject | null = null;\n private editing: MaskEditTarget | null = null;\n private child: FabricObject | null = null;\n private group: Group | null = null;\n\n constructor(\n private canvas: Canvas,\n private onCommit: () => void,\n ) {}\n\n active(): MaskEditTarget | null {\n return this.editing;\n }\n\n /** Put a handle on the canvas for `child`, an object inside `group`. */\n async begin(edit: MaskEditTarget, group: Group, child: FabricObject): Promise<boolean> {\n this.end();\n const handle = await child.clone();\n applyMatrix(handle, matrixOf(child));\n handle.set({\n // Outline only: the mask's own fill would sit over the artwork it is\n // supposed to be revealing.\n fill: 'rgba(0,0,0,0.001)',\n stroke: '#e0b055',\n strokeWidth: 2,\n strokeDashArray: [6, 4],\n strokeUniform: true,\n opacity: 1,\n selectable: true,\n evented: true,\n hasControls: true,\n hasBorders: true,\n objectCaching: false,\n excludeFromExport: true,\n });\n this.handle = handle;\n this.editing = edit;\n this.child = child;\n this.group = group;\n this.canvas.add(handle);\n this.canvas.setActiveObject(handle);\n this.canvas.on('object:moving', this.onTransform);\n this.canvas.on('object:scaling', this.onTransform);\n this.canvas.on('object:rotating', this.onTransform);\n this.canvas.on('object:modified', this.onModified);\n this.canvas.requestRenderAll();\n return true;\n }\n\n /** Take the handle down. The geometry it wrote is already in the clip. */\n end(): void {\n if (!this.handle) return;\n this.canvas.off('object:moving', this.onTransform);\n this.canvas.off('object:scaling', this.onTransform);\n this.canvas.off('object:rotating', this.onTransform);\n this.canvas.off('object:modified', this.onModified);\n if (this.canvas.getActiveObject() === this.handle) this.canvas.discardActiveObject();\n this.canvas.remove(this.handle);\n this.handle = null;\n this.editing = null;\n this.child = null;\n this.group = null;\n this.canvas.requestRenderAll();\n }\n\n dispose(): void {\n this.end();\n }\n\n private readonly onTransform = (event: { target?: FabricObject }) => {\n if (!this.handle || event.target !== this.handle) return;\n this.write();\n };\n\n private readonly onModified = (event: { target?: FabricObject }) => {\n if (!this.handle || event.target !== this.handle) return;\n this.write();\n // One history entry per drag, not per pointer move.\n this.onCommit();\n };\n\n /** Handle transform (canvas space) → clip child transform (group-relative). */\n private write(): void {\n if (!this.handle || !this.child || !this.group) return;\n applyMatrix(\n this.child,\n util.multiplyTransformMatrices(\n util.invertTransform(matrixOf(this.group)),\n matrixOf(this.handle),\n ),\n );\n this.group.dirty = true;\n this.group.set({ dirty: true });\n this.canvas.requestRenderAll();\n }\n}\n","import { util } from 'fabric';\nimport type { FabricObject, Group, TMat2D } from 'fabric';\n\n/**\n * Coordinate-space plumbing for mask stacks.\n *\n * A fabric `clipPath` lives in one of two spaces, and the mask stack uses both:\n *\n * - **host space** (`absolutePositioned: false`) — the clip is drawn inside the\n * host object's own transform, so it follows every move, scale and rotation\n * of the layer for free. This is what a *linked* mask wants.\n * - **canvas space** (`absolutePositioned: true`) — the clip ignores the host's\n * transform, so the artwork slides underneath a mask that stays put. This is\n * what an *unlinked* mask wants.\n *\n * A stack composes into a single group, so one unlinked mask forces the whole\n * stack into canvas space; the linked entries are then re-fitted from the host's\n * transform. `toCanvasSpace` / `toHostSpace` are the conversions that migration\n * between the two regimes needs, and they are exact for scale, rotation and skew\n * because they compose matrices rather than copying left/top.\n */\n\nexport function matrixOf(object: FabricObject): TMat2D {\n return object.calcTransformMatrix();\n}\n\n/** Overwrite an object's transform with `matrix`, keeping its own dimensions. */\nexport function applyMatrix(object: FabricObject, matrix: TMat2D): void {\n const decomposed = util.qrDecompose(matrix);\n object.set({\n flipX: false,\n flipY: false,\n originX: 'center',\n originY: 'center',\n left: decomposed.translateX,\n top: decomposed.translateY,\n scaleX: decomposed.scaleX,\n scaleY: decomposed.scaleY,\n angle: decomposed.angle,\n skewX: decomposed.skewX,\n skewY: 0,\n });\n object.setCoords();\n}\n\n/** Host-space geometry → canvas-space, for the same on-screen result. */\nexport function toCanvasSpace(object: FabricObject, host: FabricObject): void {\n applyMatrix(object, util.multiplyTransformMatrices(matrixOf(host), matrixOf(object)));\n}\n\n/** Canvas-space geometry → host-space, for the same on-screen result. */\nexport function toHostSpace(object: FabricObject, host: FabricObject): void {\n applyMatrix(\n object,\n util.multiplyTransformMatrices(util.invertTransform(matrixOf(host)), matrixOf(object)),\n );\n}\n\n/**\n * The mask's transform expressed relative to its host, so a linked mask can be\n * re-derived after the host moves. Stored on the entry, not recomputed from the\n * live objects: by the time the host has moved, the old relationship is gone.\n */\nexport function relativeMatrix(object: FabricObject, host: FabricObject): TMat2D {\n return util.multiplyTransformMatrices(util.invertTransform(matrixOf(host)), matrixOf(object));\n}\n\n/** Re-place a linked mask from the host's current transform and a stored `rel`. */\nexport function applyRelativeMatrix(object: FabricObject, host: FabricObject, rel: TMat2D): void {\n applyMatrix(object, util.multiplyTransformMatrices(matrixOf(host), rel));\n}\n\n/**\n * Fabric types `clipPath` with a looser prop set than the objects the editor\n * builds, so reading a clip back out needs a narrowing step. Every clip this\n * module reads is one it composed from real objects in the first place.\n */\nexport function asObject(clip: NonNullable<FabricObject['clipPath']>): FabricObject {\n return clip as FabricObject;\n}\n\n/** Narrow a persisted `rel` array back to a transform matrix. */\nexport function toMatrix(values: number[] | undefined): TMat2D | null {\n if (!values || values.length !== 6 || values.some((value) => !Number.isFinite(value)))\n return null;\n return [values[0], values[1], values[2], values[3], values[4], values[5]];\n}\n\n/** Scale an object so its unrotated box covers `box`, centred on it. */\nexport function fitToBox(\n object: FabricObject,\n box: { left: number; top: number; width: number; height: number },\n zoom = 1,\n): void {\n const width = Math.max(1, box.width) * zoom;\n const height = Math.max(1, box.height) * zoom;\n object.set({\n originX: 'center',\n originY: 'center',\n angle: 0,\n skewX: 0,\n skewY: 0,\n left: box.left + box.width / 2,\n top: box.top + box.height / 2,\n scaleX: width / Math.max(1, object.width ?? 1),\n scaleY: height / Math.max(1, object.height ?? 1),\n });\n object.setCoords();\n}\n\n/**\n * Pull a composed clip group back apart into standalone objects in the space the\n * group itself was in.\n *\n * `removeAll` already restores each child's own transform on the way out — the\n * group rebases children when it takes them in, and reverses that when it lets\n * them go. Folding the group's matrix back in on top (as one would with a v5-era\n * group) double-counts it, which stays invisible while a mask sits at the origin\n * and moves it twice as far as it should the moment one does not.\n *\n * The group passed in is emptied.\n */\nexport function unwrapGroup(group: Group): FabricObject[] {\n const children = group.removeAll();\n for (const child of children) child.setCoords();\n return children;\n}\n","import { Group } from 'fabric';\nimport type { Canvas, FabricObject } from 'fabric';\nimport type { EditorEvents, LayerMaskEntry, LayerMaskMode } from '../types';\nimport type { EventEmitter } from '../events';\nimport type { HistoryManager } from '../history';\nimport type { Layer, LayerManager } from '../layer';\nimport { generateId } from '../utils/id';\nimport { needsAbsoluteSpace } from './compose';\nimport { createCanvasHost, findCanvasHost, hostBoxOf, pinCanvasHost, type MaskBox } from './host';\nimport { convertSpace, installClip, withRelativeTransforms } from './install';\nimport { asObject, unwrapGroup } from './space';\n\n/** Target id for the mask stack that clips the whole design rather than a layer. */\nexport const CANVAS_MASK_TARGET = 'canvas';\n\nexport const DEFAULT_ENTRY = {\n mode: 'add' as LayerMaskMode,\n linked: true,\n visible: true,\n opacity: 1,\n};\n\n/**\n * Storage half of the mask stacks: where a stack lives, how it is read back out\n * of the composed clip, and how a new one is installed. `LayerMaskManager` adds\n * the editing operations on top.\n *\n * Two things are persisted, and each has a job:\n *\n * - the composed `clipPath` on the host's fabric object, which is what actually\n * renders — in the browser, in an export, and in a server-side replay that\n * knows nothing about this class;\n * - `layer.meta.maskStack`, the per-entry list (name, mode, link, visibility)\n * that the UI edits.\n *\n * Geometry is NOT duplicated into the meta: the group's children are the single\n * source of truth for it, unwrapped and recomposed on every mutation, so the two\n * can never drift into disagreeing about where a mask sits. The order of\n * `entries` matches the order of the group's children, minus the implicit base\n * rect a stack that opens with subtract/intersect needs.\n */\nexport abstract class MaskStackStore {\n protected selected: { target: string; maskId: string } | null = null;\n private pinning = false;\n\n constructor(\n protected canvas: Canvas,\n protected layers: LayerManager,\n protected history: HistoryManager,\n protected events: EventEmitter<EditorEvents>,\n ) {}\n\n list(target: string): LayerMaskEntry[] {\n return this.hostLayer(target)?.meta.maskStack ?? [];\n }\n\n get(target: string, maskId: string): LayerMaskEntry | undefined {\n return this.list(target).find((entry) => entry.id === maskId);\n }\n\n /** Every target that currently carries at least one mask. */\n targets(): string[] {\n return this.layers\n .getAll()\n .filter((layer) => (layer.meta.maskStack ?? []).length > 0)\n .map((layer) => (layer.meta.canvasMask ? CANVAS_MASK_TARGET : layer.id));\n }\n\n /** The box a mask is fitted to, in the space the stack is composed in. */\n hostBox(\n target: string,\n absolute = target === CANVAS_MASK_TARGET || needsAbsoluteSpace(this.list(target)),\n ): MaskBox {\n return hostBoxOf(this.canvas, this.host(target), absolute);\n }\n\n /** The host layer of a target, optionally creating the design overlay. */\n protected hostLayer(target: string, create = false): Layer | undefined {\n if (target !== CANVAS_MASK_TARGET) return this.layers.get(target);\n const existing = findCanvasHost(this.layers);\n if (existing || !create) return existing;\n return createCanvasHost(this.canvas, this.layers);\n }\n\n protected host(target: string, create = false): FabricObject | null {\n return this.hostLayer(target, create)?.fabricObject ?? null;\n }\n\n /** Re-pin the design overlay, guarding the reorder that re-triggers this. */\n protected pin(): void {\n if (this.pinning) return;\n this.pinning = true;\n try {\n pinCanvasHost(this.layers);\n } finally {\n this.pinning = false;\n }\n }\n\n /**\n * Take the current geometry back out of the composed clip, entry-aligned.\n *\n * The entry list is the authority on how to read the clip: with no entries the\n * clip predates the stack (a mask preset, or a single `clipPath` an older host\n * installed) and is one mask whole — including when it happens to be a group,\n * which is why this cannot just unwrap anything group-shaped.\n */\n protected unwrap(target: string, host: FabricObject): FabricObject[] {\n const clip = host.clipPath;\n if (!clip) return [];\n const entries = this.list(target);\n if (entries.length === 0 || !(clip instanceof Group)) return [asObject(clip)];\n const children = unwrapGroup(clip);\n // A stack opening with subtract/intersect gets an implicit base child that\n // belongs to no entry; drop it so index N is still entry N's geometry.\n const extra = children.length - entries.length;\n return extra > 0 ? children.slice(extra) : children;\n }\n\n /**\n * Entries for a stack, adopting a pre-stack clip as the first one. Without\n * this, the first `add()` on an already-masked layer would compose a clip it\n * has no entry for and silently throw that mask away.\n */\n protected entriesFor(target: string, sources: FabricObject[]): LayerMaskEntry[] {\n const existing = this.list(target);\n if (existing.length > 0 || sources.length !== 1) return [...existing];\n const layer = this.hostLayer(target);\n const preset = layer?.meta.maskPreset;\n if (layer) {\n // The preset manager rebuilds its clip from this key on refresh, which\n // would overwrite the stack. The stack owns the clip from here on.\n delete layer.meta.maskPreset;\n }\n return [\n {\n ...DEFAULT_ENTRY,\n id: generateId(),\n name: typeof preset === 'string' ? preset : 'Mask',\n linked: target === CANVAS_MASK_TARGET ? false : !sources[0].absolutePositioned,\n },\n ];\n }\n\n /**\n * Install a stack: convert geometry into the space the stack needs, compose the\n * clip, store the entries, and commit one history checkpoint for the lot.\n */\n protected commit(\n target: string,\n host: FabricObject,\n entries: LayerMaskEntry[],\n sources: FabricObject[],\n save = true,\n /** Compose in canvas space regardless of the entries — see `beginEdit`. */\n forceAbsolute = false,\n ): void {\n const layer = this.hostLayer(target);\n if (!layer) return;\n const absolute = forceAbsolute || target === CANVAS_MASK_TARGET || needsAbsoluteSpace(entries);\n\n convertSpace(host, sources, absolute);\n const next = withRelativeTransforms(entries, sources, host, absolute);\n installClip(host, next, sources, this.hostBox(target, absolute), absolute);\n\n if (next.length === 0) {\n delete layer.meta.maskStack;\n // An overlay with no masks would keep destination-in-ing the design away.\n if (layer.meta.canvasMask) this.layers.remove(layer.id);\n } else {\n layer.meta.maskStack = next;\n }\n\n this.canvas.requestRenderAll();\n this.events.emit('masks:changed', { target });\n this.events.emit('layer:modified', { layerId: layer.id });\n if (save) this.history.save();\n }\n}\n","import { Rect } from 'fabric';\nimport type { Canvas, FabricObject } from 'fabric';\nimport type { Layer, LayerManager } from '../layer';\n\nexport interface MaskBox {\n left: number;\n top: number;\n width: number;\n height: number;\n}\n\n/** The overlay layer carrying the whole-design stack, if one exists yet. */\nexport function findCanvasHost(layers: LayerManager): Layer | undefined {\n return layers.getAll().find((layer) => layer.meta.canvasMask);\n}\n\n/**\n * Create the overlay that masks the design: a full-canvas rectangle drawn in\n * `destination-in`, so what it paints is what survives of everything below it.\n * Its clip is a normal mask stack, which makes \"mask the whole design\" the same\n * code path as masking one layer.\n */\nexport function createCanvasHost(canvas: Canvas, layers: LayerManager): Layer {\n const rect = new Rect({\n left: 0,\n top: 0,\n width: canvas.getWidth(),\n height: canvas.getHeight(),\n originX: 'left',\n originY: 'top',\n fill: '#000000',\n globalCompositeOperation: 'destination-in',\n // It is edited from the layer list, never on the canvas: a drag box on\n // something that cannot be dragged only reads as broken.\n selectable: false,\n evented: false,\n hasControls: false,\n hasBorders: false,\n objectCaching: false,\n });\n const layer = layers.add('mask', rect, 'Design mask');\n layer.meta.canvasMask = true;\n layers.setLocked(layer.id, true);\n return layer;\n}\n\n/**\n * Keep the design overlay above everything it masks. Pinning above *content*\n * rather than to the absolute top leaves other mask-type overlays alone, so two\n * \"stay on top\" rules cannot ping-pong against each other.\n *\n * Returns true when a reorder was needed, so the caller can guard re-entry: the\n * reorder itself emits the event that triggered this.\n */\nexport function pinCanvasHost(layers: LayerManager): boolean {\n const all = layers.getAll();\n const hostIndex = all.findIndex((layer) => layer.meta.canvasMask);\n if (hostIndex === -1) return false;\n let lastContent = -1;\n all.forEach((layer, index) => {\n if (layer.type !== 'mask') lastContent = index;\n });\n if (hostIndex >= lastContent) return false;\n layers.reorder(all[hostIndex].id, all.length - 1);\n return true;\n}\n\n/**\n * The box a mask is fitted to, in the space its stack is composed in: the host's\n * bounding rectangle in canvas space, or — in host space, which is centred on\n * the object and ignores its scale — the unscaled size around the origin.\n */\nexport function hostBoxOf(canvas: Canvas, host: FabricObject | null, absolute: boolean): MaskBox {\n if (!host) {\n return { left: 0, top: 0, width: canvas.getWidth(), height: canvas.getHeight() };\n }\n if (absolute) {\n host.setCoords();\n const rect = host.getBoundingRect();\n return { left: rect.left, top: rect.top, width: rect.width, height: rect.height };\n }\n const width = Math.max(1, host.width ?? 1);\n const height = Math.max(1, host.height ?? 1);\n return { left: -width / 2, top: -height / 2, width, height };\n}\n","import { Group } from 'fabric';\nimport type { FabricObject } from 'fabric';\nimport type { LayerMaskEntry } from '../types';\nimport { composeMaskGroup } from './compose';\nimport type { MaskBox } from './host';\nimport { relativeMatrix, toCanvasSpace, toHostSpace } from './space';\n\n/**\n * Move a stack's geometry into the space it is about to be composed in. Called\n * only when the space actually changes (linking or unlinking a mask), and it has\n * to be a no-op on screen — an unlinked mask stays exactly where it looked.\n */\nexport function convertSpace(host: FabricObject, sources: FabricObject[], absolute: boolean): void {\n const wasAbsolute = host.clipPath instanceof Group ? host.clipPath.absolutePositioned : absolute;\n if (absolute === wasAbsolute) return;\n for (const source of sources) {\n if (absolute) toCanvasSpace(source, host);\n else toHostSpace(source, host);\n }\n}\n\n/**\n * Record (or drop) each linked mask's transform relative to its host.\n *\n * Only a canvas-space stack needs it: in host space fabric already carries the\n * clip along with the layer. A stale relationship is worse than none — it would\n * re-place the mask from a transform that no longer describes where it sits.\n */\nexport function withRelativeTransforms(\n entries: LayerMaskEntry[],\n sources: FabricObject[],\n host: FabricObject,\n absolute: boolean,\n): LayerMaskEntry[] {\n return entries.map((entry, index) => {\n const source = sources[index];\n if (absolute && entry.linked && source) {\n return { ...entry, rel: [...relativeMatrix(source, host)] };\n }\n if (!entry.rel) return entry;\n const rest = { ...entry };\n delete rest.rel;\n return rest;\n });\n}\n\n/** Compose the stack and attach it as the host's clip. */\nexport function installClip(\n host: FabricObject,\n entries: LayerMaskEntry[],\n sources: FabricObject[],\n box: MaskBox,\n absolute: boolean,\n): void {\n host.clipPath = composeMaskGroup(sources, entries, { box, absolute });\n host.dirty = true;\n host.setCoords();\n}\n","import type { FabricObject } from 'fabric';\n\n// ─── Units ───────────────────────────────────────────────\n\nexport type Unit = 'px' | 'mm' | 'in';\n\n// ─── Layers ──────────────────────────────────────────────\n\nexport type LayerType = 'image' | 'mask' | 'text' | 'shape' | 'template' | 'group';\n\nexport interface LayerData {\n id: string;\n type: LayerType;\n name: string;\n visible: boolean;\n locked: boolean;\n opacity: number;\n /** Non-fabric metadata persisted with the layer (pattern config, etc). */\n meta?: LayerMeta;\n /** Layers nested inside this one. Only a `group` layer has any. */\n children?: LayerData[];\n}\n\nexport interface LayerMeta {\n pattern?: PatternState;\n mask?: { width: number; height: number; revision: number };\n /** Preset silhouette or texture the layer is clipped to. */\n maskPreset?: MaskPresetId;\n /** Ordered mask stack clipping this layer (see `LayerMaskManager`). */\n maskStack?: LayerMaskEntry[];\n /** Marks the overlay layer that carries the whole-design mask stack. */\n canvasMask?: boolean;\n /** Baseline curve applied to a text layer. States saved before the shape\n * switch existed carry only `arc`/`wave`; reads normalize them. */\n curve?: TextCurveInput;\n /** Text box width authored before a curve widened it, in px. */\n curveWidth?: number;\n /** Layer resizes uniformly: single-axis handles are hidden. */\n lockAspect?: boolean;\n [key: string]: unknown;\n}\n\n// ─── Text curve ──────────────────────────────────────────\n\n/** Shape the baseline follows. The two are alternatives, never combined. */\nexport type TextCurveShape = 'arc' | 'wave';\n\nexport interface TextCurveConfig {\n /**\n * Which of the two shapes is live. The parameters of the other one are kept\n * so switching back and forth does not lose them.\n */\n shape: TextCurveShape;\n /**\n * Baseline bend, −100…100. Positive arcs the run upward (a rainbow),\n * negative into a valley; ±100 closes it into a full ring. 0 is straight.\n */\n arc: number;\n /** Sine-wave amplitude, 0…100, as a share of the font size. */\n wave: number;\n /** Sine-wave period, in font sizes. Lower is a tighter ripple. */\n waveLength: number;\n /**\n * Shift of the run along its baseline, −100…100. On an arc that is a share\n * of the sweep (±100 walks a closed ring right round); on a wave it is a\n * share of one wavelength.\n */\n offset: number;\n /**\n * Pushes the run off the ring it is bent around, −100…100 (±100 halves or\n * doubles the radius). Arc only: outward flattens the letters, inward curls\n * them tighter round a smaller circle.\n */\n centerOffset: number;\n}\n\n/**\n * A curve as authored: every field optional, missing ones fall back to the\n * defaults. Also the shape older saved states are in — they predate `shape`,\n * `waveLength` and `offset`.\n */\nexport type TextCurveInput = Partial<TextCurveConfig>;\n\n// ─── Mask presets ────────────────────────────────────────\n\nexport type ShapeMaskPresetId =\n | 'circle'\n | 'square'\n | 'triangle'\n | 'star'\n | 'heart'\n | 'octagram'\n | 'arch'\n | 'zigzag';\n\nexport type TextureMaskPresetId = 'vignette' | 'halftone' | 'spray' | 'grunge' | 'torn' | 'band';\n\nexport type MaskPresetId = ShapeMaskPresetId | TextureMaskPresetId;\n\n// ─── Mask stacks ─────────────────────────────────────────\n\n/**\n * How one mask combines with the masks under it in the stack:\n * - `add` — keeps what it covers, on top of what earlier masks kept (union)\n * - `subtract` — punches its shape out of what earlier masks kept\n * - `intersect` — keeps only what it and the earlier masks both cover\n */\nexport type LayerMaskMode = 'add' | 'subtract' | 'intersect';\n\nexport interface LayerMaskEntry {\n id: string;\n name: string;\n mode: LayerMaskMode;\n /**\n * A linked mask follows the host layer's transform; an unlinked one is pinned\n * to the canvas, so moving the layer slides the artwork under a static mask.\n * Always false on the whole-design stack, which has no host to follow.\n */\n linked: boolean;\n /** A hidden mask keeps its slot and its geometry, contributing nothing. */\n visible: boolean;\n /** 0…1 — a partly transparent mask reveals its area partly. */\n opacity: number;\n /**\n * The mask's transform relative to its host, recorded only while the stack is\n * composed in canvas space (an unlinked sibling forces that), so a linked mask\n * can be re-derived after the host moves.\n */\n rel?: number[];\n /** Host data describing where the geometry came from (preset id, generator…). */\n meta?: Record<string, unknown>;\n}\n\n// ─── Shadow ──────────────────────────────────────────────\n\nexport interface LayerShadowConfig {\n enabled: boolean;\n color: string;\n blur: number;\n offsetX: number;\n offsetY: number;\n}\n\nexport interface SerializedLayer extends LayerData {\n fabricObject: Record<string, unknown>;\n}\n\n// ─── Editor ──────────────────────────────────────────────\n\nexport interface EditorState {\n version: string;\n canvas: { width: number; height: number; unit?: Unit; dpi?: number };\n layers: SerializedLayer[];\n background?: string;\n backgroundImage?: Record<string, unknown> | null;\n backgroundImageOptions?: SerializedBackgroundImageOptions | null;\n mockup?: MockupConfig | null;\n}\n\nexport interface EditorConfig {\n width: number;\n height: number;\n backgroundColor?: string;\n fileAdapter?: FileAdapter;\n imageProvider?: ImageProvider;\n preserveObjectStacking?: boolean;\n unit?: Unit;\n dpi?: number;\n fonts?: FontDefinition[];\n license?: LicenseConfig;\n}\n\n// ─── Adapters ────────────────────────────────────────────\n\nexport type ExportFormat = 'png' | 'jpeg' | 'webp' | 'svg' | 'json';\n\nexport interface ResizeOptions {\n /** Scale layer positions and dimensions with the canvas. Defaults to true. */\n scaleContent?: boolean;\n}\n\nexport interface BackgroundImageOptions {\n fit?: 'cover' | 'contain' | 'stretch';\n opacity?: number;\n /** Fabric/HTML image loading mode for remote assets. */\n crossOrigin?: '' | 'anonymous' | 'use-credentials' | null;\n /** Cancels the current load; never serialized. */\n signal?: AbortSignal;\n}\n\nexport type SerializedBackgroundImageOptions = Omit<BackgroundImageOptions, 'signal'>;\n\nexport interface SemanticExportOptions extends PngLikeExportOptions {\n /** Document keeps full-canvas coordinates; source returns native image pixels. */\n resolution?: 'document' | 'source';\n}\n\nexport interface MaskPoint {\n x: number;\n y: number;\n}\n\nexport interface MaskBrushOptions {\n mode: 'add' | 'subtract';\n size: number;\n /** Soft-edge inner radius ratio, from 0 (soft) to 1 (hard). */\n hardness: number;\n}\n\nexport type MaskRefinementPrompt =\n | { type: 'point'; x: number; y: number; label: 'foreground' | 'background' }\n | { type: 'rectangle'; left: number; top: number; width: number; height: number }\n | { type: 'text'; value: string };\n\nexport interface MaskRefinementRequest {\n mask: string;\n width: number;\n height: number;\n prompts: MaskRefinementPrompt[];\n}\n\nexport interface MaskRefinementResult {\n dataUrl: string;\n width?: number;\n height?: number;\n metadata?: Record<string, unknown>;\n}\n\nexport interface MaskRefinementProvider {\n refine(\n request: MaskRefinementRequest,\n options?: {\n signal?: AbortSignal;\n onProgress?: (progress: number) => void;\n },\n ): Promise<MaskRefinementResult>;\n}\n\n/** Kept structural to avoid coupling the public types module to export.ts. */\nexport interface PngLikeExportOptions {\n multiplier?: number;\n quality?: number;\n}\n\nexport interface DpiIssue {\n layerId: string;\n layerName: string;\n effectiveDpi: number;\n minimumDpi: number;\n}\n\nexport interface ImageAdjustments {\n /** Range -1 to 1. */\n brightness?: number;\n /** Range -1 to 1. */\n contrast?: number;\n /** Range -1 to 1. */\n saturation?: number;\n /** Range 0 to 1. */\n blur?: number;\n}\n\nexport interface FontDefinition {\n family: string;\n /** URL, data URL, or a complete CSS FontFace source such as `local(...)`. */\n source: string;\n weight?: string;\n style?: string;\n display?: FontDisplay;\n}\n\nexport interface SvgExportOptions {\n /** Embed registered URL/data fonts into the SVG. Defaults to true. */\n embedFonts?: boolean;\n}\n\nexport interface LicensePayload {\n id: string;\n domains: string[];\n expiresAt?: string;\n features?: string[];\n}\n\nexport type LicenseStatus =\n | { state: 'community' | 'exempt' | 'checking'; payload: null }\n | { state: 'valid'; payload: LicensePayload }\n | { state: 'invalid' | 'expired' | 'domain-mismatch'; payload: LicensePayload | null };\n\nexport interface LicenseConfig {\n key?: string;\n /** Offline signature decoder/verifier supplied by the commercial distribution. */\n verifyOffline?: (key: string) => Promise<LicensePayload | null> | LicensePayload | null;\n hostname?: string;\n environment?: 'development' | 'test' | 'production';\n onUsage?: (event: { name: string; at: string; licenseId?: string }) => void;\n}\n\nexport interface CanvasSizePreset {\n id: string;\n name: string;\n width: number;\n height: number;\n unit: Unit;\n dpi: number;\n}\n\nexport interface FileAdapter {\n save(data: Blob | string, filename: string, format: ExportFormat): Promise<string>;\n}\n\nexport interface ImageProviderResult {\n id?: string;\n url: string;\n width: number;\n height: number;\n previewUrl?: string;\n thumbnailUrl?: string;\n alt?: string;\n sourceUrl?: string;\n attribution?: ImageAttribution;\n /** Provider event endpoint retained for use tracking; never render this as an image. */\n trackingUrl?: string;\n}\n\nexport interface ImageAttribution {\n name: string;\n url: string;\n provider?: string;\n}\n\nexport interface ImageSearchOptions {\n page?: number;\n perPage?: number;\n orientation?: 'landscape' | 'portrait' | 'squarish';\n orderBy?: 'relevant' | 'latest';\n contentFilter?: 'low' | 'high';\n}\n\nexport interface ImageSearchResult {\n items: ImageProviderResult[];\n page: number;\n total: number;\n totalPages: number;\n}\n\nexport interface ImageProvider {\n upload?(file: File): Promise<ImageProviderResult>;\n browse?(): Promise<ImageProviderResult | null>;\n search?(query: string, options?: ImageSearchOptions): Promise<ImageSearchResult>;\n /** Called immediately before a provider asset is inserted into the design. */\n trackUse?(image: ImageProviderResult): Promise<void>;\n}\n\n// ─── Plugins ─────────────────────────────────────────────\n\nexport interface ShapePlugin {\n name: string;\n icon: string;\n category?: string;\n create(options?: Record<string, unknown>): FabricObject;\n}\n\nexport interface TemplateParameter {\n key: string;\n label: string;\n type: 'text' | 'color' | 'number' | 'font';\n default?: string | number;\n}\n\nexport interface TemplateDefinition {\n id: string;\n name: string;\n category: string;\n svg: string;\n parameters: TemplateParameter[];\n preview?: string;\n}\n\n// ─── Printify ────────────────────────────────────────────\n\nexport interface PrintifyPositioning {\n x: number;\n y: number;\n scale: number;\n angle: number;\n}\n\nexport interface NormalizedLayerPosition {\n layerId: string;\n name: string;\n type: LayerType;\n centerX: number;\n centerY: number;\n width: number;\n height: number;\n scaleX: number;\n scaleY: number;\n angle: number;\n}\n\nexport interface PositioningAdapter<T> {\n readonly provider: string;\n map(positions: NormalizedLayerPosition[], canvas: { width: number; height: number }): T;\n}\n\nexport interface ProjectPage {\n id: string;\n name: string;\n state: EditorState;\n}\n\nexport interface ProjectState {\n version: '1.0.0';\n activePageId: string;\n pages: ProjectPage[];\n}\n\n// ─── Patterns ────────────────────────────────────────────\n\nexport type TileMode = 'grid' | 'brick-horizontal' | 'brick-vertical';\n\nexport interface PatternConfig {\n mode: TileMode;\n /**\n * Tile size as a % of the source image's on-canvas size (100 = natural).\n * Smaller values pack more repeats across the print area; larger values make\n * fewer, bigger tiles. Independent of how the source layer was placed.\n */\n scale: number;\n /** Extra horizontal gap between tiles, as % of tile width. */\n horizontalSpacing: number;\n /** Extra vertical gap between tiles, as % of tile height. */\n verticalSpacing: number;\n /** Rotation of the whole pattern, in degrees. */\n angle: number;\n /** Brick row/column shift, as % of tile size. */\n horizontalOffset: number;\n /**\n * Phase shift of the whole tile grid inside the print area, as % of tile\n * width. The pattern object itself is pinned to the print area (it can't be\n * dragged — that would expose bare edges), so this is how the tiling is\n * nudged into alignment. Clamped to ±100% so coverage is never broken.\n */\n offsetX: number;\n /** Phase shift of the tile grid, as % of tile height. See {@link offsetX}. */\n offsetY: number;\n /** Added rotation per horizontal step, in degrees. */\n rotationStepH: number;\n /** Added rotation per vertical step, in degrees. */\n rotationStepV: number;\n /**\n * Cap on how many tiles the grid lays across, counting the anchor tile. `0`\n * (the default) fills the whole area — the cap is for a finite block of\n * repeats, e.g. a three-across strip, rather than a full-bleed pattern.\n */\n horizontalLimit?: number;\n /** Cap on how many tiles the grid lays down the area. See {@link horizontalLimit}. */\n verticalLimit?: number;\n}\n\n/** Fabric interaction flags frozen while a layer is rendered as a pattern. */\nexport interface PatternLocks {\n lockMovementX: boolean;\n lockMovementY: boolean;\n lockScalingX: boolean;\n lockScalingY: boolean;\n lockRotation: boolean;\n hasControls: boolean;\n}\n\n/**\n * Persisted on a layer's meta while it is tiled across the print area.\n *\n * Current states carry `config` and nothing else: the layer keeps its real\n * object and the tiling is drawn by a render proxy, so there is no \"original\"\n * to remember. The `original*` fields belong to states written by the engine\n * that baked the tiled bitmap into the layer; they are read once, on restore,\n * to put the artwork back (see `PatternManager.rehydrateAll`).\n */\nexport interface PatternState {\n config: PatternConfig;\n /** Legacy: pre-bake image source, as a durable data URL when possible. */\n originalSrc?: string;\n /** Legacy: serialized `clipPath` the image carried before it was baked. */\n originalClip?: Record<string, unknown> | null;\n /** Legacy: interaction flags frozen while the baked bitmap was in place. */\n originalLocks?: PatternLocks;\n /** Legacy: fabric transform to restore when un-baking. */\n original?: {\n left: number;\n top: number;\n scaleX: number;\n scaleY: number;\n width: number;\n height: number;\n angle: number;\n cropX: number;\n cropY: number;\n };\n}\n\nexport const DEFAULT_PATTERN_CONFIG: PatternConfig = {\n mode: 'grid',\n scale: 100,\n horizontalSpacing: 0,\n verticalSpacing: 0,\n angle: 0,\n // Half a tile: the offset only bites in the brick modes, and a brick course\n // that is not half-shifted is just a grid with extra steps.\n horizontalOffset: 50,\n offsetX: 0,\n offsetY: 0,\n rotationStepH: 0,\n rotationStepV: 0,\n horizontalLimit: 0,\n verticalLimit: 0,\n};\n\n// ─── Mockup ──────────────────────────────────────────────\n\nexport interface MockupPrintArea {\n left: number;\n top: number;\n width: number;\n height: number;\n}\n\nexport type MockupBlendMode =\n | 'normal'\n | 'multiply'\n | 'screen'\n | 'overlay'\n | 'soft-light'\n | 'hard-light';\n\nexport interface MockupOverlay {\n /** Lighting, texture, or shadow image drawn above the design. */\n image: string;\n blendMode?: MockupBlendMode;\n opacity?: number;\n}\n\nexport type MockupDisplacementChannel = 'red' | 'green' | 'blue' | 'alpha';\n\nexport interface MockupDisplacement {\n /** Channel-map image cover-fitted to the mockup canvas. A value of 128 is neutral. */\n image: string;\n /** Maximum horizontal displacement in document pixels. Defaults to 10. */\n scaleX?: number;\n /** Maximum vertical displacement in document pixels. Defaults to 10. */\n scaleY?: number;\n /** Map channel controlling horizontal displacement. Defaults to red. */\n channelX?: MockupDisplacementChannel;\n /** Map channel controlling vertical displacement. Defaults to green. */\n channelY?: MockupDisplacementChannel;\n}\n\nexport interface MockupConfig {\n /** Garment/product image rendered behind the design. */\n image: string;\n /** Print-area rectangle, in canvas pixels. Drawn as a guide. */\n printArea?: MockupPrintArea;\n /** Clip the design to printArea. Defaults to true when printArea exists. */\n clipToPrintArea?: boolean;\n designBlendMode?: MockupBlendMode;\n designOpacity?: number;\n /** Optional channel-map warp applied to the design before compositing. */\n displacement?: MockupDisplacement;\n /** Optional product lighting/shadow pass rendered after the design. */\n overlay?: MockupOverlay;\n}\n\n// ─── Events ──────────────────────────────────────────────\n\nexport interface EditorEvents {\n 'layer:added': { layer: LayerData };\n 'layer:removed': { layerId: string };\n 'layer:selected': { layerId: string | null };\n 'layer:modified': { layerId: string };\n 'layer:reordered': { layerIds: string[] };\n 'layers:changed': { layers: LayerData[] };\n 'masks:changed': { target: string };\n 'mask:selected': { target: string | null; maskId: string | null };\n 'selection:changed': { selected: string[] };\n 'history:changed': { canUndo: boolean; canRedo: boolean };\n 'history:snapshot': { bytes: number; totalBytes: number; entries: number };\n 'zoom:changed': { zoom: number };\n 'snap:changed': { enabled: boolean };\n 'crop:changed': { active: boolean; layerId: string | null };\n 'mockup:changed': { mockup: MockupConfig | null };\n 'canvas:modified': Record<string, never>;\n 'project:changed': { activePageId: string; pages: Array<{ id: string; name: string }> };\n 'export:start': { format: string };\n 'export:complete': { format: string; url?: string };\n error: { message: string; error?: unknown };\n}\n","import type { CanvasSizePreset } from './types';\n\n/** Common print and digital canvas sizes. */\nexport const CANVAS_SIZE_PRESETS: readonly CanvasSizePreset[] = [\n { id: 'a4-portrait', name: 'A4 portrait', width: 210, height: 297, unit: 'mm', dpi: 300 },\n { id: 'a4-landscape', name: 'A4 landscape', width: 297, height: 210, unit: 'mm', dpi: 300 },\n { id: 'us-letter', name: 'US Letter', width: 8.5, height: 11, unit: 'in', dpi: 300 },\n { id: 'shirt-front', name: 'Garment front', width: 12, height: 16, unit: 'in', dpi: 300 },\n { id: 'instagram-square', name: 'Social square', width: 1080, height: 1080, unit: 'px', dpi: 72 },\n { id: 'story', name: 'Story', width: 1080, height: 1920, unit: 'px', dpi: 72 },\n];\n","export type AnnotationPrimitive =\n | { id: string; type: 'point'; x: number; y: number; label?: string }\n | {\n id: string;\n type: 'rectangle';\n left: number;\n top: number;\n width: number;\n height: number;\n label?: string;\n }\n | { id: string; type: 'label'; x: number; y: number; text: string }\n | { id: string; type: 'path'; points: Array<{ x: number; y: number }>; label?: string };\n\nexport interface ViewportTransform {\n zoom: number;\n panX: number;\n panY: number;\n devicePixelRatio?: number;\n}\n\n/** Host-owned annotations that never enter editor layers, history, serialization, or exports. */\nexport class AnnotationOverlay {\n private items = new Map<string, AnnotationPrimitive>();\n private transform: ViewportTransform = { zoom: 1, panX: 0, panY: 0, devicePixelRatio: 1 };\n\n set(annotation: AnnotationPrimitive): void {\n this.items.set(annotation.id, structuredClone(annotation));\n }\n\n remove(id: string): boolean {\n return this.items.delete(id);\n }\n\n clear(): void {\n this.items.clear();\n }\n\n getAll(): AnnotationPrimitive[] {\n return [...this.items.values()].map((item) => structuredClone(item));\n }\n\n setTransform(transform: ViewportTransform): void {\n if (!Number.isFinite(transform.zoom) || transform.zoom <= 0) {\n throw new Error('Annotation zoom must be positive');\n }\n this.transform = { ...transform, devicePixelRatio: transform.devicePixelRatio ?? 1 };\n }\n\n documentToViewport(point: { x: number; y: number }): { x: number; y: number } {\n return {\n x: point.x * this.transform.zoom + this.transform.panX,\n y: point.y * this.transform.zoom + this.transform.panY,\n };\n }\n\n viewportToDocument(point: { x: number; y: number }): { x: number; y: number } {\n return {\n x: (point.x - this.transform.panX) / this.transform.zoom,\n y: (point.y - this.transform.panY) / this.transform.zoom,\n };\n }\n\n documentToDevice(point: { x: number; y: number }): { x: number; y: number } {\n const viewport = this.documentToViewport(point);\n const ratio = this.transform.devicePixelRatio ?? 1;\n return { x: viewport.x * ratio, y: viewport.y * ratio };\n }\n}\n"],"mappings":"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","names":["import_fabric","import_fabric","import_fabric","STROKE","import_fabric","import_fabric","import_fabric","clamp","import_fabric","start","MEASURE_WIDTH","import_fabric","round","import_fabric","import_fabric","import_fabric","document","page","import_fabric","import_fabric","import_fabric","import_fabric","import_fabric","import_fabric","import_fabric","import_fabric","entry","layer"]}