@weasel-js/font 1.3.0-pre.0 → 1.4.0-pre.0

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.
@@ -661,10 +661,11 @@ function registerFontOutlines(family, variant, source, opts = {}) {
661
661
  face: null,
662
662
  glyphs: /* @__PURE__ */ new Map()
663
663
  });
664
+ notifyGlyphReady();
664
665
  }
665
666
  function unregisterFontOutlines(family, variant = {}) {
666
667
  const { weight, style } = normalize(variant);
667
- slots.delete(slotKey(family, weight, style));
668
+ if (slots.delete(slotKey(family, weight, style))) notifyGlyphReady();
668
669
  }
669
670
  function hasFontOutlines(family, weight = 400, style = "normal") {
670
671
  return slots.has(slotKey(family, weight, style));
@@ -1040,5 +1041,5 @@ function resolveFontVariantInternal(family, weight, style, suppressWarn) {
1040
1041
  }
1041
1042
 
1042
1043
  export { DEFAULT_BAKE_BUDGET, FIXTURE_FONT, __setGlyphRasterizerForTests, _getPagesForTests, _resetDynamicFontsForTests, _resetFallbackForTests, _resetFontOutlinesForTests, _resetFontRegistryForTests, createOpenTypeParser, dynamicPageTextureId, ensureFontTexture, getDefaultFontFamily, getFont, getFontFallbackPolicy, glyphGeneration, glyphOutline, hasFontOutlines, isCanvasFont, listCanvasFonts, listFontOutlines, listFonts, markAllFontsNotUploaded, outlineMetrics, outlineStatus, parseBmFont, registerCanvasFont, registerFont, registerFontOutlines, resetBakeBudget, resolveFontVariant, resolveGlyphFallback, setDefaultFontFamily, setFontFallbackPolicy, subscribeGlyphReady, syncDynamicPageTexture, textureCacheKey, unregisterCanvasFont, unregisterFontOutlines };
1043
- //# sourceMappingURL=chunk-XK73IOFB.js.map
1044
- //# sourceMappingURL=chunk-XK73IOFB.js.map
1044
+ //# sourceMappingURL=chunk-NRVRDX3F.js.map
1045
+ //# sourceMappingURL=chunk-NRVRDX3F.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/FontAtlas.ts","../src/glyphReady.ts","../src/fallback.ts","../src/dynamic/shelfPack.ts","../src/dynamic/distanceTransform.ts","../src/dynamic/glyphRasterizer.ts","../src/dynamic/dynamicAtlas.ts","../src/outline/OutlineFace.ts","../src/outline/sfnt.ts","../src/outline/opentypeParser.ts","../src/outline/outlineRegistry.ts","../src/registerFont.ts"],"names":["policy"],"mappings":"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","file":"chunk-NRVRDX3F.js","sourcesContent":["/**\n * BmFont JSON types and parser for the MSDF atlas format produced by\n * msdf-bmfont-xml. The parser builds accelerator maps (charMap, kerningMap)\n * for O(1) glyph and kerning lookup during layout.\n */\n\nexport interface BmFontInfo {\n face: string;\n size: number;\n}\n\n/** Font-wide vertical metrics and the atlas page dimensions, in pixels. */\nexport interface BmFontCommon {\n lineHeight: number;\n base: number;\n scaleW: number;\n scaleH: number;\n}\n\n/** One glyph: where it sits in the atlas page (`x`/`y`/`width`/`height`),\n * where to draw it relative to the pen (`xoffset`/`yoffset`), and how far the\n * pen then advances. */\nexport interface BmFontChar {\n id: number;\n x: number;\n y: number;\n width: number;\n height: number;\n xoffset: number;\n yoffset: number;\n xadvance: number;\n page: number;\n}\n\n/** A kerning pair: `amount` px to add to the advance when `second` follows\n * `first`. Codepoints, not glyph indices. */\nexport interface BmFontKerning {\n first: number;\n second: number;\n amount: number;\n}\n\n/** A parsed MSDF atlas: the BmFont record plus the `charMap` / `kerningMap`\n * accelerators layout reads per glyph. */\nexport interface BmFont {\n info: BmFontInfo;\n common: BmFontCommon;\n chars: BmFontChar[];\n kernings: BmFontKerning[];\n charMap: Map<number, BmFontChar>;\n kerningMap: Map<number, Map<number, number>>;\n}\n\n/** Two-glyph fixture for unit tests. */\nexport const FIXTURE_FONT = {\n info: { face: 'Inter', size: 32 },\n common: { lineHeight: 38, base: 29, scaleW: 512, scaleH: 512 },\n chars: [\n { id: 65, x: 0, y: 0, width: 22, height: 28, xoffset: 1, yoffset: 4, xadvance: 23, page: 0 },\n { id: 66, x: 24, y: 0, width: 20, height: 28, xoffset: 2, yoffset: 4, xadvance: 22, page: 0 },\n ],\n kernings: [\n { first: 65, second: 66, amount: -1 },\n ],\n};\n\n/** Validate a BmFont JSON document and build its lookup maps. Throws with the\n * missing or malformed field named. */\nexport function parseBmFont(raw: unknown): BmFont {\n if (typeof raw !== 'object' || raw === null) throw new Error('parseBmFont: expected object');\n const r = raw as Record<string, unknown>;\n\n if (!r.info || typeof r.info !== 'object') throw new Error('parseBmFont: missing info');\n if (!r.common || typeof r.common !== 'object') throw new Error('parseBmFont: missing common');\n if (!Array.isArray(r.chars)) throw new Error('parseBmFont: chars must be an array');\n\n const info = r.info as BmFontInfo;\n const common = r.common as BmFontCommon;\n const chars = r.chars as BmFontChar[];\n const kernings: BmFontKerning[] = Array.isArray(r.kernings)\n ? (r.kernings as BmFontKerning[])\n : [];\n\n const charMap = new Map<number, BmFontChar>();\n for (const ch of chars) charMap.set(ch.id, ch);\n\n const kerningMap = new Map<number, Map<number, number>>();\n for (const k of kernings) {\n let inner = kerningMap.get(k.first);\n if (!inner) { inner = new Map(); kerningMap.set(k.first, inner); }\n inner.set(k.second, k.amount);\n }\n\n return { info, common, chars, kernings, charMap, kerningMap };\n}\n","/**\n * \"A glyph the renderer asked for can now paint\" — the redraw signal shared\n * by every asynchronous glyph source.\n *\n * Both lazy tiers land their work *after* the frame that asked for it: the\n * dynamic canvas-SDF atlas defers bakes past a per-frame budget, and the\n * outline tier has to fetch and parse font bytes. Neither can paint anything\n * on the frame that first requests a glyph, so both have to tell the canvas\n * to draw again.\n *\n * One subscriber set, not one per tier: a consumer wiring \"redraw when text\n * becomes drawable\" should not have to know how many tiers exist, or grow a\n * second subscription every time one is added. `<SceneCanvas>` subscribes\n * once and both tiers reach it.\n */\n\nconst subscribers = new Set<() => void>();\n\n/** Advanced by every `notifyGlyphReady`, so state can be checked rather than\n * listened for. See {@link glyphGeneration}. */\nlet generation = 0;\n\n/**\n * How many times glyph availability has changed — the pull-based companion to\n * {@link subscribeGlyphReady}.\n *\n * For caches that cannot hold a subscription. Subscribing at module load is a\n * side effect that reaches across a package boundary: it makes importing the\n * module that holds the cache require this package's whole surface, so a\n * consumer partially mocking `@weasel-js/font` breaks at import rather than at\n * use, and import order starts to matter. Comparing a counter has neither\n * problem, and costs a field read on a path that was going to check a cache\n * key anyway.\n *\n * Callers keep the last value they saw and compare; any difference means\n * anything derived from font metrics is stale. The absolute value carries no\n * meaning and may wrap in principle — compare with `!==`, not `<`.\n */\nexport function glyphGeneration(): number {\n return generation;\n}\n\n/**\n * Subscribe to glyph availability. Fires after a batch of deferred SDF bakes\n * completes, and when an outline face finishes loading — in both cases, text\n * that painted nothing (or painted from a lower tier) can now paint. Returns\n * an unsubscribe.\n */\nexport function subscribeGlyphReady(cb: () => void): () => void {\n subscribers.add(cb);\n return () => {\n subscribers.delete(cb);\n };\n}\n\n/** @internal Fired by a glyph source once newly-available glyphs can paint. */\nexport function notifyGlyphReady(): void {\n generation++;\n for (const cb of subscribers) cb();\n}\n\n/** @internal Test seam — the subscriber set is module state. */\nexport function _clearGlyphReadySubscribers(): void {\n subscribers.clear();\n}\n","/**\n * Cross-family fallback policy. The per-family chain in `resolveFontVariant`\n * (weight → style → synthetic) has always been rich; what was missing is what\n * happens when the family itself was never registered. That case used to\n * render nothing at all, which is the single most common cause of \"my text is\n * invisible\".\n */\n\n/**\n * What happens when a requested family has no baked atlas:\n * - `'substitute'` — render with the default family (see\n * `setDefaultFontFamily`), reporting the swap on `ResolveResult.substituted`.\n * - `'canvas'` — auto-enroll the family with the dynamic canvas-SDF\n * rasterizer. The consumer gets the *real* typeface if the browser has it,\n * at canvas-SDF quality rather than baked-MSDF quality.\n * - `'none'` — hard miss; the run renders nothing.\n */\nexport type FontFallbackPolicy = 'substitute' | 'canvas' | 'none';\n\nlet policy: FontFallbackPolicy = 'substitute';\nlet defaultFamily: string | null = null;\n\n/** Set what happens when text asks for a family that was never registered.\n * Process-wide; defaults to `'substitute'`. */\nexport function setFontFallbackPolicy(next: FontFallbackPolicy): void {\n policy = next;\n}\n\n/** The cross-family fallback policy currently in force. */\nexport function getFontFallbackPolicy(): FontFallbackPolicy {\n return policy;\n}\n\n/** Explicit default family for `'substitute'`. When unset, the first\n * registered family wins — the right answer for the common case of an app\n * that registers exactly one. */\nexport function setDefaultFontFamily(family: string): void {\n defaultFamily = family;\n}\n\n/** The family `setDefaultFontFamily` named, or `null` if none was set — in\n * which case `'substitute'` falls back to the first registered family. */\nexport function getDefaultFontFamily(): string | null {\n return defaultFamily;\n}\n\n/**\n * Warn-once gate for the cross-family fallback warnings. The messages are\n * built in `registerFont.ts` (they read the registry to name the actual gap),\n * but the dedup state lives here so `_resetFallbackForTests` clears it —\n * warnings about a fallback are fallback state. While it sat in\n * `registerFont.ts`, only a registry reset cleared it, and a test that reset\n * just the policy silently swallowed its next warning.\n */\nconst warnedFallbacks = new Set<string>();\n\n/** @internal Claim `key` for a one-time warning; true the first time only. */\nexport function claimFallbackWarning(key: string): boolean {\n if (warnedFallbacks.has(key)) return false;\n warnedFallbacks.add(key);\n return true;\n}\n\n/** @internal Also called by `_resetFontRegistryForTests`: dropping the fonts\n * a warning was about has to drop the warning too. */\nexport function _clearFallbackWarnings(): void {\n warnedFallbacks.clear();\n}\n\n/** Test helper. Do not call from product code. */\nexport function _resetFallbackForTests(): void {\n policy = 'substitute';\n defaultFamily = null;\n warnedFallbacks.clear();\n}\n","/**\n * Shelf packer for the dynamic glyph atlas: fixed-size square pages, rows\n * (\"shelves\") of same-ish-height rects filled left to right. Simple and\n * good enough for glyph rects; no rotation, no eviction (v1).\n */\n\nexport interface ShelfAlloc {\n page: number;\n x: number;\n y: number;\n}\n\ninterface Shelf { y: number; height: number; x: number; }\ninterface Page { shelves: Shelf[]; nextY: number; }\n\nexport class ShelfPacker {\n private pages: Page[] = [];\n private warned = false;\n\n constructor(\n private readonly pageSize: number,\n private readonly maxPages: number,\n ) {}\n\n get pageCount(): number {\n return this.pages.length;\n }\n\n /** Allocate a w×h rect. Returns null (warning once) when capacity is out. */\n alloc(w: number, h: number): ShelfAlloc | null {\n if (w > this.pageSize || h > this.pageSize) return this.fail();\n for (let p = 0; p < this.pages.length; p++) {\n const spot = this.allocInPage(this.pages[p], w, h);\n if (spot) return { page: p, ...spot };\n }\n if (this.pages.length < this.maxPages) {\n const page: Page = { shelves: [], nextY: 0 };\n this.pages.push(page);\n const spot = this.allocInPage(page, w, h);\n if (spot) return { page: this.pages.length - 1, ...spot };\n }\n return this.fail();\n }\n\n private allocInPage(page: Page, w: number, h: number): { x: number; y: number } | null {\n for (const shelf of page.shelves) {\n if (h <= shelf.height && shelf.x + w <= this.pageSize) {\n const x = shelf.x;\n shelf.x += w;\n return { x, y: shelf.y };\n }\n }\n if (page.nextY + h <= this.pageSize) {\n const shelf: Shelf = { y: page.nextY, height: h, x: w };\n page.shelves.push(shelf);\n page.nextY += h;\n return { x: 0, y: shelf.y };\n }\n return null;\n }\n\n private fail(): null {\n if (!this.warned) {\n this.warned = true;\n console.warn(\n `weasel DynamicGlyphAtlas: glyph pages full (${this.maxPages} × ${this.pageSize}²); ` +\n 'further dynamic glyphs will not render.',\n );\n }\n return null;\n }\n}\n","/**\n * Euclidean distance transform for runtime SDF glyph baking (the TinySDF\n * technique): antialiased canvas coverage in → single-channel SDF bytes out.\n *\n * Uses Felzenszwalb & Huttenlocher's 1D squared-distance transform applied\n * along columns then rows. Pure JS, no dependencies, no allocation beyond\n * the work arrays sized to the input.\n */\n\nconst INF = 1e20;\n\n/** One 1D pass of the squared EDT (Felzenszwalb & Huttenlocher 2012, §2). */\nfunction edt1d(\n f: Float64Array, d: Float64Array, v: Int32Array, z: Float64Array, n: number,\n): void {\n v[0] = 0;\n z[0] = -INF;\n z[1] = INF;\n let k = 0;\n for (let q = 1; q < n; q++) {\n let s = (f[q] + q * q - (f[v[k]] + v[k] * v[k])) / (2 * q - 2 * v[k]);\n while (s <= z[k]) {\n k--;\n s = (f[q] + q * q - (f[v[k]] + v[k] * v[k])) / (2 * q - 2 * v[k]);\n }\n k++;\n v[k] = q;\n z[k] = s;\n z[k + 1] = INF;\n }\n k = 0;\n for (let q = 0; q < n; q++) {\n while (z[k + 1] < q) k++;\n d[q] = (q - v[k]) * (q - v[k]) + f[v[k]];\n }\n}\n\n/** In-place 2D squared EDT over `grid` (width × height): columns, then rows. */\nfunction edt2d(\n grid: Float64Array, width: number, height: number,\n f: Float64Array, d: Float64Array, v: Int32Array, z: Float64Array,\n): void {\n for (let x = 0; x < width; x++) {\n for (let y = 0; y < height; y++) f[y] = grid[y * width + x];\n edt1d(f, d, v, z, height);\n for (let y = 0; y < height; y++) grid[y * width + x] = d[y];\n }\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) f[x] = grid[y * width + x];\n edt1d(f, d, v, z, width);\n for (let x = 0; x < width; x++) grid[y * width + x] = d[x];\n }\n}\n\n/**\n * Convert an alpha-coverage bitmap (0–255) to single-channel SDF bytes.\n * Signed distance is positive outside the shape; the output maps it as\n * `255 − 255·(dist/radius + cutoff)` clamped to [0,255], so with\n * cutoff 0.5 the shape edge lands at byte ~128 (shader threshold 0.5).\n */\nexport function alphaToSdf(\n alpha: Uint8ClampedArray | Uint8Array,\n width: number,\n height: number,\n radius: number,\n cutoff: number,\n): Uint8Array {\n const n = width * height;\n const gridOuter = new Float64Array(n);\n const gridInner = new Float64Array(n);\n const size = Math.max(width, height);\n const f = new Float64Array(size);\n const d = new Float64Array(size);\n const v = new Int32Array(size);\n const z = new Float64Array(size + 1);\n\n for (let i = 0; i < n; i++) {\n const a = alpha[i] / 255;\n gridOuter[i] = a === 1 ? 0 : a === 0 ? INF : Math.max(0, 0.5 - a) ** 2;\n gridInner[i] = a === 1 ? INF : a === 0 ? 0 : Math.max(0, a - 0.5) ** 2;\n }\n edt2d(gridOuter, width, height, f, d, v, z);\n edt2d(gridInner, width, height, f, d, v, z);\n\n const out = new Uint8Array(n);\n for (let i = 0; i < n; i++) {\n const dist = Math.sqrt(gridOuter[i]) - Math.sqrt(gridInner[i]);\n const byte = Math.round(255 - 255 * (dist / radius + cutoff));\n out[i] = byte < 0 ? 0 : byte > 255 ? 255 : byte;\n }\n return out;\n}\n","/**\n * Canvas-2D glyph rasterizer for the dynamic SDF atlas. `fillText` is the\n * only web-platform route to *installed* machine fonts (no outline access),\n * which is exactly why this tier exists.\n *\n * Coordinate contract (all values in bake-size px, i.e. at BAKE_SIZE):\n * bitmap left = penX + left (left is negative: pad + left bearing)\n * bitmap top = baseline − top (top is positive above the baseline)\n * pen advance = advance\n * The bitmap includes a PAD border on all four sides so the SDF field has\n * room to fall off. Blank glyphs (e.g. space) return width/height 0.\n *\n * On BAKE_SIZE — measured 2026-07-29, comparing the reconstructed field\n * against a direct `fillText` of the same glyph at each display size, with\n * sub-pixel registration searched out so it measures fidelity and not\n * alignment. Mean per-pixel coverage error, averaged over A/S/e/W/8:\n *\n * display px 12 16 24 32 48 64 96 128\n * error .096 .083 .059 .039 .024 .023 .037 .049\n *\n * Two things follow, both of them counterintuitive enough to be worth\n * writing down. The error is minimized *at* the bake size, so raising\n * BAKE_SIZE does not improve small text — it moves the sweet spot away from\n * the 12–32px range where UI text actually lives and makes it worse. And the\n * magnification side is the mild one: 128px costs about twice the floor,\n * which is the corner rounding the shader header already owns.\n *\n * The 12–16px end is the largest divergence, and it is not undersampling —\n * 3×3 supersampling the reconstruction roughly halves the error at 24–48px\n * but recovers almost nothing at 12–16px (.096 → .089, .083 → .068). What is\n * left there is a hinted rasterizer placing stems on the pixel grid, which no\n * size-independent field can encode. So there is nothing to buy with more\n * taps, a bigger bake, or mipmaps (which a packed atlas cannot have anyway —\n * mip levels blend across glyph rects).\n */\n\nexport const BAKE_SIZE = 48;\nexport const PAD = 8;\n\nexport interface FaceMetrics {\n ascent: number;\n descent: number;\n}\n\nexport interface RasterizedGlyph {\n width: number;\n height: number;\n alpha: Uint8ClampedArray;\n left: number;\n top: number;\n advance: number;\n}\n\nexport interface GlyphRasterizer {\n faceMetrics(family: string, weight: number, style: 'normal' | 'italic'): FaceMetrics;\n rasterize(\n family: string, weight: number, style: 'normal' | 'italic', codepoint: number,\n ): RasterizedGlyph;\n}\n\ntype Canvas2D = OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D;\n\nfunction cssFontString(weight: number, style: 'normal' | 'italic', family: string): string {\n return `${style === 'italic' ? 'italic ' : ''}${weight} ${BAKE_SIZE}px ${JSON.stringify(family)}`;\n}\n\nexport function createCanvasRasterizer(): GlyphRasterizer {\n let canvas: OffscreenCanvas | HTMLCanvasElement;\n if (typeof OffscreenCanvas !== 'undefined') {\n canvas = new OffscreenCanvas(BAKE_SIZE * 3, BAKE_SIZE * 3);\n } else if (typeof document !== 'undefined') {\n canvas = document.createElement('canvas');\n canvas.width = BAKE_SIZE * 3;\n canvas.height = BAKE_SIZE * 3;\n } else {\n throw new Error('weasel DynamicGlyphAtlas: no canvas available for glyph rasterization');\n }\n const ctx = canvas.getContext('2d', { willReadFrequently: true }) as Canvas2D | null;\n if (!ctx) throw new Error('weasel DynamicGlyphAtlas: 2D context unavailable');\n\n function setFont(family: string, weight: number, style: 'normal' | 'italic'): void {\n ctx!.font = cssFontString(weight, style, family);\n ctx!.textBaseline = 'alphabetic';\n ctx!.textAlign = 'left';\n }\n\n return {\n faceMetrics(family, weight, style) {\n setFont(family, weight, style);\n const m = ctx!.measureText('Hg');\n return {\n ascent: m.fontBoundingBoxAscent ?? BAKE_SIZE * 0.8,\n descent: m.fontBoundingBoxDescent ?? BAKE_SIZE * 0.2,\n };\n },\n\n rasterize(family, weight, style, codepoint) {\n setFont(family, weight, style);\n const chStr = String.fromCodePoint(codepoint);\n const m = ctx!.measureText(chStr);\n const advance = m.width;\n const inkLeft = Math.ceil(m.actualBoundingBoxLeft ?? 0);\n const inkRight = Math.ceil(m.actualBoundingBoxRight ?? advance);\n const inkAscent = Math.ceil(m.actualBoundingBoxAscent ?? BAKE_SIZE * 0.8);\n const inkDescent = Math.ceil(m.actualBoundingBoxDescent ?? BAKE_SIZE * 0.2);\n const inkW = inkLeft + inkRight;\n const inkH = inkAscent + inkDescent;\n if (inkW <= 0 || inkH <= 0) {\n return { width: 0, height: 0, alpha: new Uint8ClampedArray(0), left: 0, top: 0, advance };\n }\n const w = inkW + 2 * PAD;\n const h = inkH + 2 * PAD;\n if (canvas.width < w || canvas.height < h) {\n canvas.width = Math.max(canvas.width, w);\n canvas.height = Math.max(canvas.height, h);\n setFont(family, weight, style); // resizing resets 2D state\n }\n ctx!.clearRect(0, 0, w, h);\n ctx!.fillStyle = '#fff';\n ctx!.fillText(chStr, PAD + inkLeft, PAD + inkAscent);\n const img = ctx!.getImageData(0, 0, w, h);\n const alpha = new Uint8ClampedArray(w * h);\n for (let i = 0; i < alpha.length; i++) alpha[i] = img.data[i * 4 + 3];\n return {\n width: w,\n height: h,\n alpha,\n left: -(inkLeft + PAD),\n top: inkAscent + PAD,\n advance,\n };\n },\n };\n}\n","/**\n * DynamicGlyphAtlas — runtime single-channel SDF glyphs for canvas-sourced\n * (installed machine) fonts. TinySDF technique: canvas fillText at 48 px →\n * Euclidean distance transform → shelf-packed R8 pages (1024², max 4).\n *\n * Baked MSDF atlases always win: this tier only serves families registered\n * via `registerCanvasFont` that have no baked entry (see resolveFontVariant).\n *\n * Faces expose a BmFont-shaped `font` whose charMap grows as glyphs are\n * requested, so `layoutRuns` consumes them through the same code path as\n * baked atlases. A char's advance is valid immediately (measureText); its\n * atlas rect fills in when the bake lands (width 0 / page -1 until then, so\n * layout advances the pen but emits no quad).\n */\n\nimport type { BmFont, BmFontChar } from '../FontAtlas';\nimport type { GlyphTextureSink } from '../textureSink';\n// `fallback.ts` imports nothing, so this edge cannot close a cycle; keep it\n// that way. (registerFont.ts imports both this module and fallback.ts.)\nimport { getFontFallbackPolicy } from '../fallback';\nimport { notifyGlyphReady, _clearGlyphReadySubscribers } from '../glyphReady';\nimport { ShelfPacker } from './shelfPack';\nimport { alphaToSdf } from './distanceTransform';\nimport {\n createCanvasRasterizer, BAKE_SIZE,\n type GlyphRasterizer, type RasterizedGlyph,\n} from './glyphRasterizer';\n\nexport const PAGE_SIZE = 1024;\nexport const MAX_PAGES = 4;\nexport const SDF_RADIUS = 8;\nexport const SDF_CUTOFF = 0.5;\n/** How many glyphs the dynamic atlas will rasterize synchronously before\n * deferring the rest to a later flush. Caps the frame cost of text that\n * suddenly needs many new glyphs; the leftovers arrive a tick later and\n * notify through `onGlyphReady`. */\nexport const DEFAULT_BAKE_BUDGET = 16;\n\nexport interface DynamicFace {\n family: string;\n weight: number;\n style: 'normal' | 'italic';\n /** BmFont-shaped view consumed by layoutRuns; charMap grows lazily. */\n font: BmFont;\n /** Char record for `cp`, measured on first request (advance always valid\n * immediately; atlas rect fills in when the bake lands). */\n requestGlyph(cp: number): BmFontChar;\n}\n\ninterface DynamicPage {\n data: Uint8Array;\n /** Bumps on every glyph blit; each blit appends a patch with seq = version. */\n version: number;\n patches: { seq: number; x: number; y: number; w: number; h: number }[];\n}\n\ninterface PendingBake { char: BmFontChar; raster: RasterizedGlyph; }\n\n/** One family served by the dynamic canvas-SDF tier. See `listCanvasFonts`. */\nexport interface CanvasFontEntry {\n family: string;\n /** `'explicit'` — a `registerCanvasFont` call; `'auto'` — the `'canvas'`\n * fallback policy enrolled it on a miss, and the enrollment lapses if\n * that policy changes. */\n enrollment: 'explicit' | 'auto';\n}\n\nconst canvasFamilies = new Set<string>();\n// Enrollment provenance. A family the `'canvas'` fallback policy enrolled on\n// its own is only canvas-served while that policy is in force; one a consumer\n// named via registerCanvasFont outranks every policy. Tracked here rather\n// than in fallback.ts so the two sets can only ever be mutated together —\n// every register / unregister / reset path is in this file.\nconst autoEnrolledFamilies = new Set<string>();\nlet faces = new Map<string, DynamicFace>();\nlet pages: DynamicPage[] = [];\nlet packer = new ShelfPacker(PAGE_SIZE, MAX_PAGES);\nlet pending: PendingBake[] = [];\nlet flushScheduled = false;\nlet budget = DEFAULT_BAKE_BUDGET;\nlet rasterizer: GlyphRasterizer | null = null;\n\nfunction getRasterizer(): GlyphRasterizer {\n if (!rasterizer) rasterizer = createCanvasRasterizer();\n return rasterizer;\n}\n\n/** Mark `family` as canvas-sourced: when no baked atlas covers it,\n * resolveFontVariant serves it from this dynamic atlas. */\nexport function registerCanvasFont(family: string): void {\n canvasFamilies.add(family);\n // An explicit call promotes a previously auto-enrolled family for good.\n autoEnrolledFamilies.delete(family);\n}\n\n/**\n * Will `family` be served by the dynamic canvas-SDF tier *right now*?\n *\n * Service, not membership — the answer depends on the fallback policy in\n * force and can change without any enrollment call:\n * - explicitly enrolled via `registerCanvasFont` → `true` under every\n * policy; a consumer naming a family outranks the policy.\n * - auto-enrolled by the `'canvas'` policy → `true` only while that policy\n * is still in force. The enrollment lapses rather than being discarded,\n * so returning to `'canvas'` makes it `true` again.\n * - never enrolled → `false`, including under `'canvas'` (that policy\n * enrolls lazily, on the first miss).\n *\n * The membership reading would answer `true` for an auto-enrolled family\n * under `'substitute'` / `'none'`, where nothing routes to this tier — a\n * caller predicting what renders would be told the opposite of the truth.\n * Mirrors `listFonts`, which reports the baked registry alone for the same\n * reason: \"enrolled\" is not \"will render\".\n */\nexport function isCanvasFont(family: string): boolean {\n if (!canvasFamilies.has(family)) return false;\n return !autoEnrolledFamilies.has(family) || getFontFallbackPolicy() === 'canvas';\n}\n\n/**\n * Every family the dynamic canvas-SDF tier will serve *right now* — the\n * enumeration companion to `isCanvasFont`, which answers one family at a\n * time. Same \"service, not membership\" rule: an auto-enrolled family appears\n * only while the `'canvas'` policy is in force.\n *\n * Exists so a consumer can offer these families in a font picker.\n * `listFonts` reports the baked registry alone, so without this the only\n * ways to present canvas-served families were to hard-code a list beside the\n * `registerCanvasFont` calls or to omit them — a UI inventing its own answer\n * about what will render.\n *\n * `enrollment` distinguishes a consumer's explicit `registerCanvasFont` from\n * a lazy enrollment the policy made on a miss; both render identically, but\n * only the explicit one survives a policy change.\n */\nexport function listCanvasFonts(): readonly CanvasFontEntry[] {\n const out: CanvasFontEntry[] = [];\n for (const family of canvasFamilies) {\n if (!isCanvasFont(family)) continue;\n out.push({ family, enrollment: autoEnrolledFamilies.has(family) ? 'auto' : 'explicit' });\n }\n return out.sort((a, b) => a.family.localeCompare(b.family));\n}\n\n/**\n * @internal Enroll `family` on behalf of the `'canvas'` fallback policy.\n * Distinct from `registerCanvasFont` only in provenance: the enrollment\n * lapses (see `isExplicitCanvasFont`) if the policy later changes.\n */\nexport function autoEnrollCanvasFont(family: string): void {\n if (canvasFamilies.has(family) && !autoEnrolledFamilies.has(family)) return;\n canvasFamilies.add(family);\n autoEnrolledFamilies.add(family);\n}\n\n/**\n * @internal Enrolled by a consumer's own `registerCanvasFont` call rather than\n * by the `'canvas'` policy. Only these are served by the dynamic tier\n * regardless of the policy in force; an auto-enrolled family falls back to\n * whatever the current policy says once that policy is no longer `'canvas'`.\n */\nexport function isExplicitCanvasFont(family: string): boolean {\n return canvasFamilies.has(family) && !autoEnrolledFamilies.has(family);\n}\n\n/** Remove a canvas family. Its faces are dropped; already-baked glyph\n * pixels stay in their pages (no eviction in v1). */\nexport function unregisterCanvasFont(family: string): void {\n canvasFamilies.delete(family);\n autoEnrolledFamilies.delete(family);\n for (const key of [...faces.keys()]) {\n if (faces.get(key)!.family === family) faces.delete(key);\n }\n}\n\n/**\n * Internal resolver helper — not part of the public barrel; consumers go\n * through registerCanvasFont + resolveFontVariant.\n */\nexport function getDynamicFace(\n family: string, weight: number, style: 'normal' | 'italic',\n): DynamicFace {\n const key = `${family}|${weight}|${style}`;\n const existing = faces.get(key);\n if (existing) return existing;\n\n const r = getRasterizer();\n const metrics = r.faceMetrics(family, weight, style);\n const base = Math.round(metrics.ascent);\n const font: BmFont = {\n info: { face: family, size: BAKE_SIZE },\n common: {\n lineHeight: Math.round(metrics.ascent + metrics.descent),\n base,\n scaleW: PAGE_SIZE,\n scaleH: PAGE_SIZE,\n },\n chars: [],\n kernings: [], // no kerning in v1 (measured-pair kerning is future work)\n charMap: new Map(),\n kerningMap: new Map(),\n };\n\n const face: DynamicFace = {\n family, weight, style, font,\n requestGlyph(cp: number): BmFontChar {\n const cached = font.charMap.get(cp);\n if (cached) return cached;\n const raster = r.rasterize(family, weight, style, cp);\n const char: BmFontChar = {\n id: cp, x: 0, y: 0, width: 0, height: 0,\n xoffset: raster.left,\n yoffset: base - raster.top,\n xadvance: raster.advance,\n page: -1,\n };\n font.charMap.set(cp, char);\n font.chars.push(char);\n if (raster.width === 0 || raster.height === 0) {\n char.page = 0; // blank glyph (space): nothing to bake\n return char;\n }\n if (budget > 0) {\n budget--;\n bake(char, raster);\n } else {\n pending.push({ char, raster });\n scheduleFlush();\n }\n return char;\n },\n };\n faces.set(key, face);\n return face;\n}\n\nfunction bake(char: BmFontChar, raster: RasterizedGlyph): void {\n const spot = packer.alloc(raster.width, raster.height);\n if (!spot) return; // pages full — packer warned once; glyph stays invisible\n const sdf = alphaToSdf(raster.alpha, raster.width, raster.height, SDF_RADIUS, SDF_CUTOFF);\n while (pages.length <= spot.page) {\n pages.push({ data: new Uint8Array(PAGE_SIZE * PAGE_SIZE), version: 0, patches: [] });\n }\n const page = pages[spot.page];\n for (let row = 0; row < raster.height; row++) {\n page.data.set(\n sdf.subarray(row * raster.width, (row + 1) * raster.width),\n (spot.y + row) * PAGE_SIZE + spot.x,\n );\n }\n page.version++;\n page.patches.push({ seq: page.version, x: spot.x, y: spot.y, w: raster.width, h: raster.height });\n char.x = spot.x;\n char.y = spot.y;\n char.width = raster.width;\n char.height = raster.height;\n char.page = spot.page;\n}\n\nfunction scheduleFlush(): void {\n if (flushScheduled) return;\n flushScheduled = true;\n setTimeout(flushPending, 0);\n}\n\nfunction flushPending(): void {\n flushScheduled = false;\n let n = 0;\n while (pending.length > 0 && n < DEFAULT_BAKE_BUDGET) {\n const job = pending.shift()!;\n if (job.char.page !== -1) continue; // already baked\n bake(job.char, job.raster);\n n++;\n }\n if (pending.length > 0) scheduleFlush();\n notifyGlyphReady();\n}\n\n/** Reset the per-frame synchronous bake budget. Called by\n * `WeaselRenderer.render()` at frame start; the headless\n * `renderSceneToPixels` path passes Infinity so print never defers. */\nexport function resetBakeBudget(n: number = DEFAULT_BAKE_BUDGET): void {\n budget = n;\n}\n\n/* ------------------------------------------------------------------ */\n/* GPU sync */\n/* ------------------------------------------------------------------ */\n\n/** Texture-cache key for a dynamic page (parallel to `textureCacheKey`). */\nexport function dynamicPageTextureId(page: number): string {\n return `weasel-dyn-sdf-page-${page}`;\n}\n\n// Per-GL-cache upload progress: last page version each cache has seen.\n// WeakMap-keyed so disposed renderers don't pin anything.\nconst uploadedVersions = new WeakMap<GlyphTextureSink, Map<number, number>>();\n\n/** Bring `cache`'s copy of page `pageIndex` up to date: full R8 upload the\n * first time, `texSubImage2D` patches after. Returns false if the page\n * doesn't exist yet. */\nexport function syncDynamicPageTexture(cache: GlyphTextureSink, pageIndex: number): boolean {\n const page = pages[pageIndex];\n if (!page) return false;\n const id = dynamicPageTextureId(pageIndex);\n let seen = uploadedVersions.get(cache);\n if (!seen) {\n seen = new Map();\n uploadedVersions.set(cache, seen);\n }\n if (!cache.has(id)) {\n cache.uploadR8(id, PAGE_SIZE, PAGE_SIZE, page.data);\n seen.set(pageIndex, page.version);\n return true;\n }\n const last = seen.get(pageIndex) ?? 0;\n if (last >= page.version) return true;\n for (const patch of page.patches) {\n if (patch.seq <= last) continue;\n const tight = new Uint8Array(patch.w * patch.h);\n for (let row = 0; row < patch.h; row++) {\n const src = (patch.y + row) * PAGE_SIZE + patch.x;\n tight.set(page.data.subarray(src, src + patch.w), row * patch.w);\n }\n cache.subImageR8(id, patch.x, patch.y, patch.w, patch.h, tight);\n }\n seen.set(pageIndex, page.version);\n return true;\n}\n\n/* ------------------------------------------------------------------ */\n/* Test seams */\n/* ------------------------------------------------------------------ */\n\n/** @internal test seam — inject a fake rasterizer (jsdom has no canvas\n * metrics). Pass null to restore the lazy default. */\nexport function __setGlyphRasterizerForTests(r: GlyphRasterizer | null): void {\n rasterizer = r;\n}\n\n/** @internal test seam — inspect CPU-side pages. */\nexport function _getPagesForTests(): readonly DynamicPage[] {\n return pages;\n}\n\n/** @internal test seam — clear all dynamic-font state. */\nexport function _resetDynamicFontsForTests(): void {\n canvasFamilies.clear();\n autoEnrolledFamilies.clear();\n faces = new Map();\n pages = [];\n packer = new ShelfPacker(PAGE_SIZE, MAX_PAGES);\n pending = [];\n flushScheduled = false;\n budget = DEFAULT_BAKE_BUDGET;\n _clearGlyphReadySubscribers();\n rasterizer = null;\n}\n","/**\n * The parsed-font seam for the outline tier.\n *\n * A face answers exactly one question — \"what does codepoint N look like?\" —\n * and answers it as **SVG path data in em space**: one unit is one em, y\n * grows downward, and the origin sits on the baseline at the glyph's pen\n * position. That is a complete description of the glyph independent of size,\n * zoom, and position, which is the whole reason the tier exists: tessellate\n * once, transform per instance.\n *\n * ### Why `d` and not a command stream\n *\n * `@weasel-js/font` is a Tier A leaf — `@weasel-js/core` depends on it and\n * never the reverse (see `leaf-purity.test.ts`), so this package cannot name\n * core's `PolygonPath`. The alternative to a string would be re-declaring\n * core's `PATH_M`/`PATH_L`/… opcodes over here and trusting two packages to\n * keep the same numbering forever. SVG `d` is the kit's documented language\n * for geometry crossing a boundary (`docs/conventions.md`), core already\n * ships `pathFromD`, and a glyph outline is exactly the case it describes.\n *\n * The string is also a natural cache key and costs nothing to hold: the\n * parse happens once per glyph, and core caches the *tessellation*, not the\n * text.\n */\n\n/** Weight/style pair identifying one face within a family. */\nexport type OutlineFontStyle = 'normal' | 'italic';\n\n/** A parsed font face, viewed only as a source of glyph outlines. See the\n * module comment for the em-space contract `glyphD` returns. */\nexport interface OutlineFace {\n /** Font design units per em. Reported for diagnostics; `glyphD` has already\n * divided by it, so callers never need to. */\n unitsPerEm: number;\n /**\n * Distance from the line top to the baseline, in em units — the outline\n * tier's analogue of a `BmFont`'s `common.base`.\n *\n * Read from `hhea`, which is what `msdf-bmfont-xml` bakes, so a face used\n * for metrics puts text on the same baseline as an atlas of the same font.\n * `docs/TODO.md` tracks the wider disagreement with `sTypoAscender`.\n */\n ascender: number;\n /**\n * Em-space SVG path data for `cp`, or `null` when this face has no glyph\n * for the codepoint *or* the glyph has no contours (a space). Both answers\n * mean the same thing to a caller: there is nothing here to tessellate, so\n * fall through to whatever tier would have drawn it.\n */\n glyphD(cp: number): string | null;\n /**\n * Advance width for `cp` in em units, or `null` when the face has no glyph\n * for it. Distinct from `glyphD` answering `null`: a space has an advance\n * and no contours, and layout needs the advance either way.\n */\n advanceOf(cp: number): number | null;\n /** Kerning adjustment between two codepoints, in em units — negative pulls\n * them together. `0` when the face kerns neither this pair nor at all. */\n kernOf(left: number, right: number): number;\n}\n\n/**\n * Turn font file bytes into a face. Async because the default implementation\n * dynamically imports its parser — see `opentypeParser.ts` for why that\n * matters — and because a caller may want to hand back a face that finishes\n * initializing off-thread.\n */\nexport type OutlineParser = (bytes: ArrayBuffer) => OutlineFace | Promise<OutlineFace>;\n\n/**\n * Decimal places kept when serializing em-space coordinates.\n *\n * Five is chosen against two constraints, not by taste. Below: 1e-5 em is\n * 0.01px on a 1000px-tall glyph, an order of magnitude under anything a\n * display can show. Above: `pathFromD`'s tokenizer splits argument runs on\n * *letters*, so a coordinate that JavaScript chooses to print in exponential\n * form (`1e-7`) would tokenize as the command `e`. Numbers stay in\n * positional notation down to 1e-6, so five decimals cannot produce one.\n */\nexport const OUTLINE_PRECISION = 5;\n","/**\n * TrueType/OpenType **collection** unpacking.\n *\n * `queryLocalFonts()` hands back the font *file* behind a face, and on macOS\n * a large share of the interesting ones — Helvetica, Times, Courier, Menlo —\n * are `.ttc` collections holding every weight and style in a single file with\n * one shared glyph store. A collection is not a font: its header is `ttcf`\n * rather than an sfnt version, so every parser worth using rejects it, and\n * opentype.js is no exception (it recognizes `\\0\\1\\0\\0`, `true`, `typ1`,\n * `OTTO`, `wOFF` and throws on anything else).\n *\n * The fix is mechanical, because a collection is just N table directories\n * over one pool of tables: pick the directory whose PostScript name matches\n * the face we were asked for, then re-emit it as a standalone sfnt with the\n * tables copied and the offsets rewritten. Nothing is re-encoded — the table\n * bytes are the same bytes — so the result parses identically to a font that\n * had shipped on its own.\n *\n * Kept separate from `opentypeParser.ts` so the collection handling is\n * testable without a parser, and so swapping the parser later doesn't drag\n * this along.\n *\n * ### Why this lives here rather than upstream or in a bigger library\n *\n * Decided 2026-07-31, after looking at both alternatives — recorded so this\n * doesn't get \"tidied up\" into one of them later.\n *\n * The upstream fix is genuinely small: `parseOpenTypeTableEntries` hardcodes\n * `p = 12`, so the only thing opentype.js cannot do is be *told* the table\n * directory starts somewhere other than byte zero. Table records already\n * carry absolute offsets and the parser already reads them from a\n * whole-buffer view, so a `dirOffset` parameter and a `ttcf` branch would be\n * about ten lines. (Typr takes an offset in `readFONT` and gets collections\n * for free — same capability, one better-chosen signature.) It would make a\n * good PR. It would also not help for a while: opentype.js sat untouched from\n * 2021 to 2026, and we would carry this file until a release landed anyway.\n *\n * fontkit handles `.ttc` and `.dfont` natively, and WOFF2 besides — but it is\n * ~5.6 MB unpacked across nine dependencies (brotli, unicode-trie, dfa, …).\n * That is a shaping engine, and all this tier wants is a glyph outline.\n *\n * This version has an advantage over both: it runs *before* anything parses,\n * so it is parser-agnostic and survives swapping opentype.js out.\n *\n * **Known gap: `.dfont`** (Datafork TrueType) is not unpacked — its sfnt\n * tables live inside a Macintosh resource map, which is a second container\n * format on top of the one above. `isDataForkFont` recognizes it and\n * `sfntFromCollection` throws by name, so the face degrades to the SDF tier\n * saying why; the registry's `warnOnce` carries the message. Not currently\n * reachable on macOS, whose system font directories are 204 `.ttf` / 128\n * `.ttc` / 38 `.otf` and no `.dfont`; it is a real format on older systems.\n */\n\nconst SFNT_HEADER_BYTES = 12;\nconst TABLE_RECORD_BYTES = 16;\n\nfunction tagAt(view: DataView, offset: number): string {\n return String.fromCharCode(\n view.getUint8(offset), view.getUint8(offset + 1),\n view.getUint8(offset + 2), view.getUint8(offset + 3),\n );\n}\n\n/** Is `bytes` a font collection rather than a single font? */\nexport function isFontCollection(bytes: ArrayBuffer): boolean {\n if (bytes.byteLength < 4) return false;\n return tagAt(new DataView(bytes), 0) === 'ttcf';\n}\n\n/** Every signature that opens a font file this tier can hand to a parser. */\nconst FONT_SIGNATURES: ReadonlySet<string> = new Set([\n '\\x00\\x01\\x00\\x00', 'true', 'typ1', 'OTTO', 'ttcf', 'wOFF', 'wOF2',\n]);\n\nconst RESOURCE_HEADER_BYTES = 16;\n\n/**\n * Is `bytes` a Datafork TrueType file (`.dfont`)?\n *\n * A `.dfont` is a bare Macintosh resource fork written to the data fork, so\n * unlike every other font format it opens with no signature — just the\n * resource header's four big-endian offsets. It is recognized by those\n * adding up, which is why the signature check has to run first: an sfnt's\n * header bytes are numbers too, and nothing stops them from coincidentally\n * being consistent.\n *\n * Detection only. Reading the `sfnt` resources out of the map is the rest of\n * the job and is not implemented — the point is that the face declines the\n * outline tier by name instead of dying on an unrecognized-signature message\n * that never mentions the format.\n */\nexport function isDataForkFont(bytes: ArrayBuffer): boolean {\n if (bytes.byteLength < RESOURCE_HEADER_BYTES) return false;\n const view = new DataView(bytes);\n if (FONT_SIGNATURES.has(tagAt(view, 0))) return false;\n const dataOffset = view.getUint32(0);\n const mapOffset = view.getUint32(4);\n const dataLength = view.getUint32(8);\n const mapLength = view.getUint32(12);\n return dataOffset >= RESOURCE_HEADER_BYTES\n && dataOffset + dataLength === mapOffset\n && mapOffset + mapLength <= bytes.byteLength;\n}\n\ninterface TableRecord { tag: string; offset: number; length: number; checksum: number }\n\nfunction readTableDirectory(view: DataView, dirOffset: number): TableRecord[] {\n const numTables = view.getUint16(dirOffset + 4);\n const records: TableRecord[] = [];\n for (let i = 0; i < numTables; i++) {\n const at = dirOffset + SFNT_HEADER_BYTES + i * TABLE_RECORD_BYTES;\n records.push({\n tag: tagAt(view, at),\n checksum: view.getUint32(at + 4),\n offset: view.getUint32(at + 8),\n length: view.getUint32(at + 12),\n });\n }\n return records;\n}\n\n/**\n * PostScript name (`name` table, nameID 6) of the sub-font at `dirOffset`,\n * or `null` when it carries none.\n *\n * A deliberately minimal reader: identifying which member of a collection to\n * unpack is the only thing needed here, and a full `name` parser would be a\n * second implementation of something the real parser does properly once the\n * font is standalone. PostScript names are ASCII by specification, so both\n * the Macintosh (single-byte) and Windows (UTF-16BE) encodings reduce to\n * \"take every byte that isn't a zero pad\".\n */\nfunction postScriptNameAt(view: DataView, records: readonly TableRecord[]): string | null {\n const name = records.find((r) => r.tag === 'name');\n if (!name) return null;\n const base = name.offset;\n const count = view.getUint16(base + 2);\n const stringOffset = view.getUint16(base + 4);\n for (let i = 0; i < count; i++) {\n const rec = base + 6 + i * 12;\n if (view.getUint16(rec + 6) !== 6) continue; // nameID 6 === PostScript name\n const length = view.getUint16(rec + 8);\n const offset = view.getUint16(rec + 10);\n let out = '';\n for (let b = 0; b < length; b++) {\n const code = view.getUint8(base + stringOffset + offset + b);\n if (code !== 0) out += String.fromCharCode(code);\n }\n if (out.length > 0) return out;\n }\n return null;\n}\n\n/** Re-emit the table directory at `dirOffset` as a standalone sfnt buffer. */\nfunction extractFont(source: ArrayBuffer, view: DataView, dirOffset: number): ArrayBuffer {\n const records = readTableDirectory(view, dirOffset);\n // Tables are copied 4-byte aligned, which is what the format requires and\n // what every checksum in the directory was computed over.\n const padded = (n: number): number => (n + 3) & ~3;\n let total = SFNT_HEADER_BYTES + records.length * TABLE_RECORD_BYTES;\n for (const r of records) total += padded(r.length);\n\n const out = new ArrayBuffer(total);\n const dst = new DataView(out);\n const dstBytes = new Uint8Array(out);\n const srcBytes = new Uint8Array(source);\n\n dst.setUint32(0, view.getUint32(dirOffset)); // sfntVersion\n dst.setUint16(4, records.length);\n // searchRange / entrySelector / rangeShift are a binary-search hint over the\n // table records. Recomputed rather than copied: the member directory's\n // values describe its own table count, which is usually but not always the\n // same, and a wrong hint is a parser walking off the end of the directory.\n const entrySelector = Math.floor(Math.log2(records.length));\n const searchRange = 2 ** entrySelector * 16;\n dst.setUint16(6, searchRange);\n dst.setUint16(8, entrySelector);\n dst.setUint16(10, records.length * 16 - searchRange);\n\n let cursor = SFNT_HEADER_BYTES + records.length * TABLE_RECORD_BYTES;\n records.forEach((r, i) => {\n const at = SFNT_HEADER_BYTES + i * TABLE_RECORD_BYTES;\n for (let b = 0; b < 4; b++) dst.setUint8(at + b, r.tag.charCodeAt(b));\n dst.setUint32(at + 4, r.checksum);\n dst.setUint32(at + 8, cursor);\n dst.setUint32(at + 12, r.length);\n dstBytes.set(srcBytes.subarray(r.offset, r.offset + r.length), cursor);\n cursor += padded(r.length);\n });\n return out;\n}\n\n/**\n * Standalone font bytes for one member of a collection.\n *\n * `postScriptName` selects the member; when it is absent or matches nothing,\n * the first member is returned. Falling back rather than failing is\n * deliberate — the name comes from `FontData.postscriptName`, and a browser\n * that reports it differently from the `name` table should degrade to \"some\n * weight of the right family\", not to no text at all. The caller sees which\n * it got via the returned `matched` flag.\n *\n * Passing a single font through is a no-op, so this is safe to call on any\n * bytes.\n */\nexport function sfntFromCollection(\n bytes: ArrayBuffer,\n postScriptName?: string,\n): { bytes: ArrayBuffer; matched: boolean } {\n if (isDataForkFont(bytes)) {\n throw new Error(\n 'Datafork TrueType (.dfont) is not supported — the outline tier reads sfnt '\n + 'tables and a .dfont holds them inside a Macintosh resource map.',\n );\n }\n if (!isFontCollection(bytes)) return { bytes, matched: true };\n\n const view = new DataView(bytes);\n const numFonts = view.getUint32(8);\n if (numFonts === 0) throw new Error('font collection contains no fonts');\n\n const offsets: number[] = [];\n for (let i = 0; i < numFonts; i++) offsets.push(view.getUint32(12 + i * 4));\n\n if (postScriptName) {\n for (const dirOffset of offsets) {\n const records = readTableDirectory(view, dirOffset);\n if (postScriptNameAt(view, records) === postScriptName) {\n return { bytes: extractFont(bytes, view, dirOffset), matched: true };\n }\n }\n }\n return { bytes: extractFont(bytes, view, offsets[0]), matched: !postScriptName };\n}\n","/**\n * The default `OutlineParser`: opentype.js, loaded on demand.\n *\n * ### Why the dynamic import\n *\n * opentype.js is ~49 kB gzipped and it is the *only* runtime dependency this\n * package has. Charging that to every consumer of `@weasel-js/font` — most of\n * whom render text through a baked atlas and never touch an outline — would\n * be a poor trade for a tier that only engages above a size threshold. The\n * tier is inherently asynchronous anyway (font bytes arrive over `fetch` or\n * `queryLocalFonts`), so there is no synchronous path to slow down: the\n * import rides along with the load that was already going to happen, and a\n * bundler splits it into a chunk nobody fetches until large text appears.\n *\n * The other candidate was Typr — smaller, but unmaintained and untyped, and\n * this is a runtime dependency of a published package.\n *\n * ### Coordinate convention\n *\n * `glyph.getPath(0, 0, 1)` already emits exactly what `OutlineFace` promises:\n * font units divided by the em, y flipped to grow downward, and the origin on\n * the baseline at the pen position. That is opentype.js's canvas-rendering\n * convention, and it happens to be the kit's world convention too, so no\n * transform is applied here — a flip would have to be undone downstream.\n */\n\nimport { OUTLINE_PRECISION, type OutlineFace, type OutlineParser } from './OutlineFace';\nimport { sfntFromCollection } from './sfnt';\n\ntype OpenType = typeof import('opentype.js');\n\nlet modulePromise: Promise<OpenType> | null = null;\n\n/** Load (once) and cache the parser module. */\nfunction loadOpenType(): Promise<OpenType> {\n modulePromise ??= import('opentype.js');\n return modulePromise;\n}\n\n/**\n * opentype.js 2.0 publishes ESM under `module` and a UMD bundle under `main`.\n * Only a bundler reads `module`; Node takes the UMD one, whose named exports\n * it cannot detect, so `ns.parse` is `undefined` there and every face fails to\n * load. The registry catches that and degrades to the SDF tier, which is why\n * it looks like nothing is wrong in an app that has an atlas — and why a\n * headless consumer, which has neither, gets no glyphs and no explanation.\n *\n * Exported for the test: the suite resolves through vite, which reads\n * `module` and therefore cannot reproduce the shape that breaks.\n */\nexport function parserOf(ns: OpenType): OpenType['parse'] {\n const interop = ns as OpenType & { default?: OpenType };\n return interop.default?.parse ?? ns.parse;\n}\n\n/**\n * Wrap a parsed opentype.js font.\n *\n * `charToGlyphIndex` reports 0 — `.notdef` — for a codepoint the font does\n * not cover. That is a real glyph (the tofu box) and it renders, so returning\n * its outline would silently substitute a box for a character the atlas tier\n * might have been able to serve. Report the miss instead and let the caller's\n * fallback ladder run.\n */\nfunction faceFor(font: import('opentype.js').Font): OutlineFace {\n const upem = font.unitsPerEm;\n return {\n unitsPerEm: upem,\n ascender: font.ascender / upem,\n advanceOf(cp: number): number | null {\n const index = font.charToGlyphIndex(String.fromCodePoint(cp));\n if (!index) return null;\n return (font.glyphs.get(index).advanceWidth ?? 0) / upem;\n },\n kernOf(left: number, right: number): number {\n const l = font.charToGlyphIndex(String.fromCodePoint(left));\n const r = font.charToGlyphIndex(String.fromCodePoint(right));\n if (!l || !r) return 0;\n return font.getKerningValue(font.glyphs.get(l), font.glyphs.get(r)) / upem;\n },\n glyphD(cp: number): string | null {\n const index = font.charToGlyphIndex(String.fromCodePoint(cp));\n if (!index) return null;\n const d = font.glyphs.get(index).getPath(0, 0, 1).toPathData(OUTLINE_PRECISION);\n // A glyph with no contours (a space) serializes to the empty string.\n // Same answer as a missing glyph from the caller's point of view:\n // nothing to tessellate.\n return d.length > 0 ? d : null;\n },\n };\n}\n\n/**\n * Parse font file bytes into a face. Accepts single fonts and collections\n * (`.ttc`); `postScriptName` picks the member of a collection, and is\n * ignored for a single font.\n */\nexport function createOpenTypeParser(postScriptName?: string): OutlineParser {\n return async (bytes: ArrayBuffer): Promise<OutlineFace> => {\n const parse = parserOf(await loadOpenType());\n const { bytes: single } = sfntFromCollection(bytes, postScriptName);\n return faceFor(parse(single));\n };\n}\n\n/** The parser used when a registration supplies none of its own. */\nexport const openTypeParser: OutlineParser = createOpenTypeParser();\n\n/** @internal Test seam — drop the memoized module so a test can re-import. */\nexport function _resetOpenTypeModuleForTests(): void {\n modulePromise = null;\n}\n","/**\n * The outline tier's registry: which faces have real font bytes behind them,\n * and what a given glyph looks like.\n *\n * ### What this tier is for\n *\n * A distance field is a *sampled* representation. The baked MSDF atlas is\n * generated from outlines and holds up well; the dynamic canvas-SDF tier\n * (`../dynamic/`) reconstructs its field from a 48px raster, so magnifying it\n * past a few times the bake size exposes the raster as contour wobble — bumps\n * one bake-texel apart, ±2–3px at 8×. No bake size fixes that, it only moves\n * the size at which it appears (`glyphRasterizer.ts` measures the tradeoff:\n * error is *minimized at* the bake size, so raising it spoils the 12–32px\n * range where most text lives).\n *\n * Above a size threshold the answer is to stop sampling: parse the font, take\n * the glyph's outline, and hand it to the path renderer the kit already has.\n * Exact at every zoom, and — because a glyph becomes an ordinary path — it\n * takes strokes and non-solid fills for free.\n *\n * Below the threshold the atlas still wins, and not narrowly: outlines carry\n * no hinting and no stem darkening, so body text at 12–16px rendered from\n * them looks *worse* than a platform rasterizer that puts stems on the pixel\n * grid. Two tiers with a size threshold is the standard hybrid, not a\n * compromise.\n *\n * ### Metric neutrality (the load-bearing invariant)\n *\n * This tier replaces how a glyph is *painted*, never where it sits. Advances,\n * kerning, line breaking and baselines all keep coming from whichever tier\n * resolved the run — the baked atlas or the canvas face. That is what lets\n * the threshold be a rendering decision: zooming past it swaps glyph geometry\n * with the layout untouched, so text cannot reflow under the user's cursor,\n * and `measureTextBounds` / `textLineBoxes` need to know nothing about\n * outlines at all.\n *\n * The cost is that a face whose real advances disagree with the atlas's\n * inherits the atlas's. For the bundled Inter that is exact (the subset ships\n * from the same source the atlas was baked from), and for a machine font the\n * outline bytes and the canvas metrics come from the same file.\n *\n * ### Availability\n *\n * Everything here degrades rather than blocks. Bytes arrive over `fetch` or\n * `queryLocalFonts` — asynchronous, and in the local case gated behind a\n * permission the user can refuse — so `glyphOutline` answers `null` until a\n * face is loaded and forever if it failed, and the caller falls back down the\n * ladder to SDF. A family must never render *nothing* because the outline\n * tier could not get bytes.\n */\n\nimport { notifyGlyphReady } from '../glyphReady';\nimport type { OutlineFace, OutlineFontStyle, OutlineParser } from './OutlineFace';\nimport { openTypeParser } from './opentypeParser';\n\n/**\n * Where a face's bytes come from. A URL is fetched; a buffer or blob is used\n * as-is; a thunk is called at first use, which is what lets `queryLocalFonts`\n * results be registered eagerly and read lazily — the permission prompt and\n * the (potentially many megabytes of) blob only happen for a family the\n * document actually sets text in.\n */\nexport type OutlineSource =\n | string\n | ArrayBuffer\n | Blob\n | (() => ArrayBuffer | Blob | Promise<ArrayBuffer | Blob>);\n\n/** Which face within a family to register outlines for. Defaults to weight\n * 400, style `'normal'`. */\nexport interface OutlineVariant {\n weight?: number;\n style?: OutlineFontStyle;\n}\n\n/** Options for registering an outline font. */\nexport interface OutlineFontOptions {\n /** Override the default opentype.js parser. Mostly a test seam; also the\n * hook for a consumer who already has a font parser in their bundle. */\n parser?: OutlineParser;\n}\n\n/** Load state of one registered face. */\nexport type OutlineStatus = 'idle' | 'loading' | 'ready' | 'failed';\n\ninterface FaceSlot {\n family: string;\n weight: number;\n style: OutlineFontStyle;\n source: OutlineSource;\n parser: OutlineParser;\n status: OutlineStatus;\n face: OutlineFace | null;\n /** Memoized `glyphD` answers, including the `null` misses — a codepoint the\n * face lacks is asked for on every frame that draws it, and re-deriving\n * the miss means re-running the cmap lookup forever. */\n glyphs: Map<number, string | null>;\n}\n\nlet slots = new Map<string, FaceSlot>();\n\nfunction slotKey(family: string, weight: number, style: OutlineFontStyle): string {\n return `${family}|${weight}|${style}`;\n}\n\nfunction normalize(v: OutlineVariant): { weight: number; style: OutlineFontStyle } {\n return { weight: v.weight ?? 400, style: v.style ?? 'normal' };\n}\n\n/**\n * Register font file bytes for one face, so text set in it can render from\n * outlines above the size threshold.\n *\n * Registration is cheap and synchronous: nothing is fetched, and the parser\n * is not even imported, until a frame actually asks for a glyph from this\n * face. Registering a face that is never drawn large costs one map entry.\n *\n * The variant must match exactly what the layout tier resolved — this is\n * deliberately *not* a fallback chain. Painting 400-weight outlines at\n * 700-weight advances, or upright outlines where the shader was going to\n * fake an oblique, looks worse than the SDF it replaced; a miss here falls\n * back down the ladder instead, which is always safe.\n */\nexport function registerFontOutlines(\n family: string,\n variant: OutlineVariant,\n source: OutlineSource,\n opts: OutlineFontOptions = {},\n): void {\n const { weight, style } = normalize(variant);\n slots.set(slotKey(family, weight, style), {\n family, weight, style, source,\n parser: opts.parser ?? openTypeParser,\n status: 'idle',\n face: null,\n glyphs: new Map(),\n });\n // Layouts cache which tier each run resolved to and poll `glyphGeneration()`\n // to know when to drop it; a registration that leaves it still is invisible.\n notifyGlyphReady();\n}\n\n/** Drop a registration. Glyphs already handed out stay valid — they are\n * plain path data — but nothing further resolves from this face. */\nexport function unregisterFontOutlines(family: string, variant: OutlineVariant = {}): void {\n const { weight, style } = normalize(variant);\n // Only when something was actually dropped: `disableMachineFontOutlines`\n // sweeps every weight/style pair, and a miss must not invalidate any layout.\n if (slots.delete(slotKey(family, weight, style))) notifyGlyphReady();\n}\n\n/**\n * Is an outline face registered for this exact variant? Answers `true` while\n * the bytes are still loading — the question is \"could this face serve\n * outlines\", which is what a caller deciding whether to *ask* wants; use\n * `outlineStatus` for the narrower \"can it right now\".\n */\nexport function hasFontOutlines(\n family: string, weight = 400, style: OutlineFontStyle = 'normal',\n): boolean {\n return slots.has(slotKey(family, weight, style));\n}\n\n/** Load state of a registered face; `null` when nothing is registered. */\nexport function outlineStatus(\n family: string, weight = 400, style: OutlineFontStyle = 'normal',\n): OutlineStatus | null {\n return slots.get(slotKey(family, weight, style))?.status ?? null;\n}\n\n/** Every registered outline face and its load state — the enumeration a\n * debug overlay or font picker needs, mirroring `listFonts`. */\nexport function listFontOutlines(): readonly {\n family: string; weight: number; style: OutlineFontStyle; status: OutlineStatus;\n}[] {\n return [...slots.values()]\n .map(({ family, weight, style, status }) => ({ family, weight, style, status }))\n .sort((a, b) => a.family.localeCompare(b.family) || a.weight - b.weight\n || a.style.localeCompare(b.style));\n}\n\n/**\n * Em-space SVG path data for one glyph, or `null` when this tier cannot serve\n * it — no registration, bytes still loading, load failed, no such glyph, or a\n * glyph with no contours.\n *\n * Synchronous by construction: it is called from the per-frame glyph walk, so\n * it can only ever report what is already in hand. The first call for an\n * unloaded face starts the load and returns `null`; when the load lands,\n * `notifyGlyphReady` asks the canvas to draw again and the second frame gets\n * the outline. Same shape as the dynamic tier's deferred bakes.\n */\n/**\n * Close every contour of a glyph's path data.\n *\n * A glyph contour is closed by definition — neither TrueType nor CFF has any\n * other kind — but not every serializer writes the `Z` that says so, and the\n * omission is invisible until someone *strokes* the outline: a fill closes the\n * contour implicitly (earcut joins last point to first), while a stroke\n * follows exactly the path it is handed and leaves the closing edge unpainted,\n * with a cap at each loose end. That showed up as glyphs missing part of their\n * outline along long straight edges, which is where a contour's seam usually\n * falls.\n *\n * Normalized here rather than in one parser because the same hole is open to\n * every consumer-supplied `OutlineParser`, and a contract that says \"closed\"\n * is cheaper to guarantee than to document.\n */\nexport function closeContours(d: string): string {\n let out = '';\n let start = 0;\n for (let i = 1; i < d.length; i++) {\n const c = d[i];\n if (c !== 'M' && c !== 'm') continue;\n out += closeOne(d.slice(start, i));\n start = i;\n }\n return out + closeOne(d.slice(start));\n}\n\nfunction closeOne(contour: string): string {\n const trimmed = contour.trimEnd();\n if (trimmed.length === 0) return '';\n const last = trimmed[trimmed.length - 1];\n return last === 'Z' || last === 'z' ? trimmed : `${trimmed}Z`;\n}\n\n/**\n * Em-space SVG path data for one glyph of a registered outline face, or `null`\n * when there is nothing to draw.\n *\n * Synchronous and non-throwing by design: a face that has not been parsed yet\n * starts loading and answers `null` for now, so a renderer can call this every\n * frame and simply fall through to another text tier until the outline\n * arrives. Results are cached per codepoint.\n */\nexport function glyphOutline(\n family: string,\n weight: number,\n style: OutlineFontStyle,\n cp: number,\n): string | null {\n const slot = slots.get(slotKey(family, weight, style));\n if (!slot) return null;\n if (slot.status === 'idle') {\n void beginLoad(slot);\n return null;\n }\n if (slot.status !== 'ready') return null;\n\n const cached = slot.glyphs.get(cp);\n if (cached !== undefined) return cached;\n let d: string | null = null;\n try {\n const raw = slot.face!.glyphD(cp);\n d = raw === null ? null : closeContours(raw);\n } catch (err) {\n // A parser that throws on one glyph should cost that glyph, not the face.\n warnOnce(`glyph|${slotKey(family, weight, style)}`,\n `weasel: outline face \"${family}\" (${weight}/${style}) could not produce a glyph ` +\n `for U+${cp.toString(16).toUpperCase().padStart(4, '0')} — ` +\n `${err instanceof Error ? err.message : String(err)}. Falling back to the SDF tier.`);\n }\n slot.glyphs.set(cp, d);\n return d;\n}\n\n/**\n * Metrics for a registered outline face, or `null` when this tier cannot\n * supply them yet — nothing registered, bytes still loading, or a failed load.\n *\n * The face is the *only* metrics source for a family that has no atlas, which\n * is the case this exists for: without it such a family cannot lay out at all.\n * It does not disturb metric neutrality — a family that has an atlas resolves\n * to the atlas long before anything asks here, so registering outlines still\n * cannot move text that was already rendering.\n *\n * Starts the load on a first call and answers `null` for now, exactly like\n * `glyphOutline`, so a per-frame caller falls through and picks it up on the\n * frame after the bytes land.\n */\nexport function outlineMetrics(\n family: string,\n weight: number,\n style: OutlineFontStyle,\n): OutlineFace | null {\n const slot = slots.get(slotKey(family, weight, style));\n if (!slot) return null;\n if (slot.status === 'idle') {\n void beginLoad(slot);\n return null;\n }\n return slot.status === 'ready' ? slot.face! : null;\n}\n\nasync function beginLoad(slot: FaceSlot): Promise<void> {\n slot.status = 'loading';\n try {\n slot.face = await slot.parser(await readSource(slot.source));\n slot.status = 'ready';\n // The frame that asked for these glyphs has long since drawn. Without\n // this the outlines sit in memory until something else invalidates the\n // canvas, which on a static document is \"never\".\n notifyGlyphReady();\n } catch (err) {\n slot.status = 'failed';\n warnOnce(`load|${slotKey(slot.family, slot.weight, slot.style)}`,\n `weasel registerFontOutlines(\"${slot.family}\" ${slot.weight}/${slot.style}): ` +\n `${err instanceof Error ? err.message : String(err)}. Large text in this face ` +\n `keeps rendering from the SDF tier.`);\n }\n}\n\nasync function readSource(source: OutlineSource): Promise<ArrayBuffer> {\n const resolved = typeof source === 'function' ? await source() : source;\n if (typeof resolved === 'string') {\n const res = await fetch(resolved);\n if (!res.ok) throw new Error(`HTTP ${res.status} fetching ${resolved}`);\n return res.arrayBuffer();\n }\n if (resolved instanceof ArrayBuffer) return resolved;\n return resolved.arrayBuffer();\n}\n\n// Loading and glyph lookup both run off the render loop, so an unguarded warn\n// would repeat every frame.\nconst warned = new Set<string>();\n\nfunction warnOnce(key: string, message: string): void {\n if (warned.has(key)) return;\n warned.add(key);\n console.warn(message);\n}\n\n/** @internal Test seam — registry and warn-once keys are module state. */\nexport function _resetFontOutlinesForTests(): void {\n slots = new Map();\n warned.clear();\n}\n","/**\n * FontRegistry and registerFont() public API.\n *\n * Variants are keyed by (family, weight, style). registerFont() takes a\n * FontVariant alongside the family and the two URLs; the registry stores\n * entries in a two-level Map so resolveFontVariant() can iterate a family's\n * variants for the fallback chain.\n */\n\nimport { notifyGlyphReady } from './glyphReady';\nimport { parseBmFont, type BmFont } from './FontAtlas';\nimport type { GlyphTextureSink } from './textureSink';\nimport {\n isCanvasFont, isExplicitCanvasFont, autoEnrollCanvasFont, getDynamicFace,\n type DynamicFace,\n} from './dynamic/dynamicAtlas';\nimport {\n getFontFallbackPolicy, getDefaultFontFamily,\n claimFallbackWarning, _clearFallbackWarnings,\n} from './fallback';\nimport { outlineMetrics } from './outline/outlineRegistry';\nimport type { OutlineFace } from './outline/OutlineFace';\n\n/** A registered face: its parsed metrics and the atlas image to sample. */\nexport interface FontEntry {\n font: BmFont;\n bitmap: ImageBitmap;\n}\n\n/** Which face within a family. Defaults to weight 400, style `'normal'`. */\nexport interface FontVariant {\n weight?: number;\n style?: 'normal' | 'italic';\n}\n\ntype FontStyle = 'normal' | 'italic';\n\nlet registry = new Map<string, Map<string, FontEntry>>();\n\nfunction variantKey(weight: number, style: FontStyle): string {\n return `${weight}|${style}`;\n}\n\nfunction normalizeVariant(v: FontVariant): { weight: number; style: FontStyle } {\n return {\n weight: v.weight ?? 400,\n style: v.style ?? 'normal',\n };\n}\n\n/** Test helper. Do not call from product code. */\nexport function _resetFontRegistryForTests(): void {\n registry = new Map();\n _clearFallbackWarnings();\n}\n\n/** Exact lookup — does NOT walk the fallback chain. Use `resolveFontVariant` for that. */\nexport function getFont(\n family: string,\n weight: number = 400,\n style: FontStyle = 'normal',\n): FontEntry | null {\n return registry.get(family)?.get(variantKey(weight, style)) ?? null;\n}\n\n/** One family in the registry and the variants registered for it — what a\n * font picker can honestly offer. */\nexport interface RegisteredFont {\n family: string;\n variants: readonly { weight: number; style: FontStyle }[];\n}\n\n/**\n * Enumerate the registry — what a font picker can honestly offer. Families\n * come back in registration order; variants sorted by weight, then style, so\n * the output is stable enough to assert against.\n */\nexport function listFonts(): readonly RegisteredFont[] {\n const out: RegisteredFont[] = [];\n for (const [family, variantMap] of registry) {\n const variants = [...variantMap.keys()]\n .map((key) => {\n const [w, s] = key.split('|') as [string, FontStyle];\n return { weight: Number(w), style: s };\n })\n .sort((a, b) => a.weight - b.weight || a.style.localeCompare(b.style));\n out.push({ family, variants });\n }\n return out;\n}\n\n/**\n * Fetch a baked MSDF atlas and its metrics, and register them as one variant\n * of `family`. Resolves once the face is usable; re-registering a variant that\n * is already present is a no-op.\n */\nexport async function registerFont(\n family: string,\n variant: FontVariant,\n metricsUrl: string,\n atlasUrl: string,\n): Promise<void> {\n const { weight, style } = normalizeVariant(variant);\n const key = variantKey(weight, style);\n\n if (registry.get(family)?.has(key)) return;\n\n try {\n const [metricsRes, atlasRes] = await Promise.all([\n fetch(metricsUrl),\n fetch(atlasUrl),\n ]);\n\n if (!metricsRes.ok) {\n throw new Error(`HTTP ${metricsRes.status} fetching metrics from ${metricsUrl}`);\n }\n if (!atlasRes.ok) {\n throw new Error(`HTTP ${atlasRes.status} fetching atlas from ${atlasUrl}`);\n }\n\n const [rawJson, blob] = await Promise.all([\n metricsRes.json(),\n atlasRes.blob(),\n ]);\n\n const font = parseBmFont(rawJson);\n const bitmap = await createImageBitmap(blob);\n\n // Re-read the registry here (not the pre-await snapshot): concurrent\n // registerFont() calls for other variants of the same family (e.g. the\n // 400/700 weights registered together in Promise.all) may have created\n // the family's Map while this call was awaiting its fetch. Reusing a\n // stale local reference would recreate the Map and silently drop\n // whichever variant's registerFont() resolved first.\n let familyMap = registry.get(family);\n if (!familyMap) {\n familyMap = new Map();\n registry.set(family, familyMap);\n }\n familyMap.set(key, { font, bitmap });\n // Same meaning the lazy tiers give it: text that was painting from a\n // fallback face — or painting nothing — can now paint from this one. The\n // early return above covers the already-registered case, so this fires\n // once per variant that actually lands.\n notifyGlyphReady();\n } catch (err) {\n throw new Error(\n `weasel registerFont(\"${family}\" ${weight}/${style}): ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n}\n\n/**\n * Ensure the atlas for `(family, weight, style)` is uploaded to\n * `textureCache`. Cache key is `${family}|${weight}|${style}` so each\n * variant occupies its own texture slot.\n */\nexport function ensureFontTexture(\n family: string,\n weight: number,\n style: FontStyle,\n textureCache: GlyphTextureSink,\n): boolean {\n const entry = getFont(family, weight, style);\n if (!entry) return false;\n textureCache.upload(textureCacheKey(family, weight, style), entry.bitmap);\n return true;\n}\n\n/** The texture cache key used by `ensureFontTexture` for a given variant. */\nexport function textureCacheKey(family: string, weight: number, style: FontStyle): string {\n return `${family}|${weight}|${style}`;\n}\n\n/** Kept as a no-op for context-restore call sites; per-cache dedup handles it now. */\nexport function markAllFontsNotUploaded(): void {}\n\n/** What `resolveFontVariant` found: the atlas to draw with, the face it\n * actually landed on after walking the fallback chain, and what has to be\n * synthesized to cover the difference. */\nexport interface ResolveResult {\n entry: FontEntry | null;\n /**\n * The (family, weight, style) triple that was actually matched. May differ\n * from the requested values when the resolver walked the fallback chain —\n * including `family`, when the cross-family policy substituted a default.\n *\n * This is the atlas identity: pass all three to `getFont` /\n * `textureCacheKey` and the lookup hits. Describing only weight and style\n * here once let a caller key its draw on the *requested* family, which\n * resolves to no atlas at all and paints nothing.\n *\n * The synthetic flags describe the gap between requested and resolved for\n * shader-side compensation. When `entry` is null, these mirror the\n * requested values.\n */\n resolved: { family: string; weight: number; style: FontStyle };\n synthetic: { bold: boolean; italic: boolean };\n /** Which tier resolved: a baked MSDF atlas, the runtime canvas-SDF dynamic\n * atlas, or a parsed font face serving both geometry and metrics. Misses\n * report 'atlas' (the default tier). */\n source: 'atlas' | 'canvas' | 'outline';\n /** Set only when source === 'canvas': the dynamic face whose BmFont-shaped\n * `font` layoutRuns consumes in place of `entry.font`. */\n dynamicFace?: DynamicFace;\n /** Set only when source === 'outline': the parsed face supplying advances,\n * kerning and the baseline. There is no atlas behind this tier, so it is\n * the only metrics source the run has. */\n outlineFace?: OutlineFace;\n /**\n * Set when the requested family was not registered and the fallback policy\n * substituted a different one. Reported structurally so a UI can say\n * \"Inter — not loaded, showing Roboto\" instead of leaving the user to\n * wonder why the family control did nothing.\n */\n substituted?: { requested: string; resolved: string };\n}\n\nfunction missResolveResult(\n family: string, weight: number, style: FontStyle, suppressWarn = false,\n): ResolveResult {\n // Canvas-dynamic tier: reached only when the fallback chain selected no\n // baked variant, so any selected baked match always wins. Dynamic faces\n // rasterize the real weight/style — no synthetic flags.\n //\n // Explicit enrollment only. A family the `'canvas'` policy enrolled for\n // itself must not keep routing here after the policy changes, or `'none'`\n // could never restore the hard miss it documents once any family had been\n // auto-enrolled.\n if (isExplicitCanvasFont(family)) {\n return {\n entry: null,\n dynamicFace: getDynamicFace(family, weight, style),\n resolved: { family, weight, style },\n synthetic: { bold: false, italic: false },\n source: 'canvas',\n };\n }\n\n // Outline-only: a family with parsed font bytes and no atlas. Ranked above\n // every fallback below because it is the *real* face — exact geometry and\n // the font's own advances — where the alternatives are a resampled raster\n // or a different typeface. Below explicit canvas enrollment, which is a\n // consumer saying which tier it wants for this family.\n const face = outlineMetrics(family, weight, style === 'italic' ? 'italic' : 'normal');\n if (face) {\n return {\n entry: null,\n outlineFace: face,\n resolved: { family, weight, style },\n synthetic: { bold: false, italic: false },\n source: 'outline',\n };\n }\n\n const policy = getFontFallbackPolicy();\n\n if (policy === 'canvas') {\n // Auto-enroll: the browser probably has this family even though no atlas\n // was baked for it. Real typeface, canvas-SDF quality.\n autoEnrollCanvasFont(family);\n return {\n entry: null,\n dynamicFace: getDynamicFace(family, weight, style),\n resolved: { family, weight, style },\n synthetic: { bold: false, italic: false },\n source: 'canvas',\n };\n }\n\n if (policy === 'substitute') {\n const fallback = getDefaultFontFamily() ?? firstRegisteredFamily();\n // Guard against recursing when the default family is itself unknown.\n // Canvas families never enter `registry`, so membership there alone would\n // reject `setDefaultFontFamily` pointed at one. `isCanvasFont` answers\n // \"served by the dynamic tier right now\", which is the question here: a\n // family the `'canvas'` policy auto-enrolled is not served under this\n // policy, so substituting *to* it would report a swap that paints nothing.\n if (fallback !== null && fallback !== family) {\n if (registry.has(fallback) || isCanvasFont(fallback)) {\n // Probing whether the fallback family renders, not resolving a\n // top-level request for it — suppress so this recursion can't also\n // land in the `fallback === family` branch below (the fallback\n // family's own default is itself) and double-warn for one miss.\n // Whichever of `warnMissingFamilyOnce` / `warnUnusableDefaultOnce`\n // fires below, based on this probe's result, is the single warning.\n const result = resolveFontVariantInternal(fallback, weight, style, true);\n // Renderable, not baked: a fallback served by the dynamic tier reports\n // `entry: null` with a dynamicFace, and testing entry alone threw it away.\n if (result.entry !== null || result.dynamicFace !== undefined) {\n if (!suppressWarn) warnMissingFamilyOnce(family, weight, style, fallback);\n return { ...result, substituted: { requested: family, resolved: fallback } };\n }\n }\n // Substitution was supposed to happen and produced nothing. Falling\n // through silently here is the invisible-text failure this whole policy\n // exists to eliminate, so say which of the two families to fix.\n if (!suppressWarn) warnUnusableDefaultOnce(family, weight, style, fallback);\n } else if (fallback === family && !suppressWarn) {\n // `fallback === family` above exists to stop the request from\n // substituting for itself — recursion into the same miss forever. But\n // when the family that can't serve this variant *is* the effective\n // default, that guard also throws away the one case it was most likely\n // to hit: a default registered at the wrong variant. Nothing renders\n // and, without this branch, nothing is logged either.\n // `suppressWarn` keeps this from firing when a *different* top-level\n // request's substitution probe happens to recurse into the default\n // family and find it can't serve either — that miss is reported by the\n // top-level caller via `warnUnusableDefaultOnce`, not from in here.\n if (registry.has(family)) {\n warnSelfUnusableDefaultOnce(family, weight, style);\n } else {\n // Unregistered, yet still the effective default: the default can only\n // have been named explicitly, because the implicit one is the first\n // *registered* family (and with nothing registered at all, `fallback`\n // is null and never equals `family`). So this is a real\n // misconfiguration — someone pointed setDefaultFontFamily at a family\n // that does not exist — and not the deliberately-silent case of an app\n // that simply hasn't loaded any fonts yet.\n warnUnregisteredDefaultOnce(family, weight, style);\n }\n }\n }\n\n return {\n entry: null,\n resolved: { family, weight, style },\n synthetic: { bold: false, italic: false },\n source: 'atlas',\n };\n}\n\n/** Insertion order of the registry Map — the first family an app registered. */\nfunction firstRegisteredFamily(): string | null {\n for (const family of registry.keys()) return family;\n return null;\n}\n\n// Resolution runs per frame, so an unguarded warn would flood the console.\n// Keyed per (family, weight, style) variant, not per family: each variant is a\n// distinct thing the app asked for and failed to get. The claimed keys live in\n// fallback.ts so both reset seams clear them.\nfunction warnMissingFamilyOnce(\n family: string, weight: number, style: FontStyle, resolved: string,\n): void {\n if (!claimFallbackWarning(`substituted|${family}|${weight}|${style}`)) return;\n // Two distinct failures land here. Saying \"not registered\" for a family\n // that IS registered — just not in a variant the within-family chain can\n // reach — sends the reader hunting for a registerFont call that already\n // exists. Name the actual gap so the fix is the obvious one.\n const cause = registry.has(family)\n ? `has no variant matching ${weight}/${style}, and none of its registered ` +\n `variants are close enough for the within-family chain to substitute — ` +\n `rendering with \"${resolved}\" instead. Bake that variant with ` +\n `registerFont(\"${family}\", { weight: ${weight}, style: '${style}' }, …)`\n : `is not registered — rendering with \"${resolved}\" instead. ` +\n `Call registerFont(\"${family}\", …)`;\n console.warn(\n `weasel: font family \"${family}\" (${weight}/${style}) ${cause}. ` +\n `Advance widths will differ from the requested font. Use ` +\n `setFontFallbackPolicy('none') to make this a hard miss instead.`,\n );\n}\n\n/**\n * The substitute policy engaged and still came up empty. Distinct from\n * `warnMissingFamilyOnce`, which reports a *successful* swap: here nothing\n * renders, and the fix is almost always in the fallback family rather than\n * the requested one — so name it, and say which way it was chosen.\n */\nfunction warnUnusableDefaultOnce(\n family: string, weight: number, style: FontStyle, fallback: string,\n): void {\n if (!claimFallbackWarning(`unusable-default|${family}|${weight}|${style}`)) return;\n const origin = getDefaultFontFamily() === fallback\n ? 'set via setDefaultFontFamily'\n : 'the first registered family, since setDefaultFontFamily was never called';\n // Same policy-aware question as the substitution guard: a fallback the\n // `'canvas'` policy auto-enrolled has nothing serving it under this policy,\n // so \"has no variant\" would send the reader looking for a variant to bake\n // when the family has no atlas at all.\n const gap = registry.has(fallback) || isCanvasFont(fallback)\n ? `has no variant that can serve ${weight}/${style}`\n : 'is not registered either';\n console.warn(\n `weasel: font family \"${family}\" (${weight}/${style}) is not available, and ` +\n `the fallback family \"${fallback}\" (${origin}) ${gap} — this text will not ` +\n `render at all. Bake that variant with registerFont(\"${fallback}\", ` +\n `{ weight: ${weight}, style: '${style}' }, …), or point ` +\n `setDefaultFontFamily() at a family that covers it.`,\n );\n}\n\n/**\n * The requested family is also the effective default — there is nowhere left\n * to fall back to. Distinct from `warnUnusableDefaultOnce`, which names a\n * *different* fallback family to fix; here the requested and fallback\n * families are the same one, so repeating the name the way that message does\n * would read as nonsense (\"X is not available, and the fallback X … \").\n * Named once, with both facts — registered-but-wrong-variant, and also the\n * fallback — folded into a single sentence.\n */\nfunction warnSelfUnusableDefaultOnce(\n family: string, weight: number, style: FontStyle,\n): void {\n if (!claimFallbackWarning(`self-unusable-default|${family}|${weight}|${style}`)) return;\n const origin = getDefaultFontFamily() === family\n ? 'set via setDefaultFontFamily'\n : 'the first registered family, since setDefaultFontFamily was never called';\n console.warn(\n `weasel: font family \"${family}\" (${weight}/${style}) has no variant that can ` +\n `serve this request, and \"${family}\" is also the fallback family (${origin}) — ` +\n `there is nothing left to fall back to, so this text will not render at all. ` +\n `Bake that variant with registerFont(\"${family}\", { weight: ${weight}, ` +\n `style: '${style}' }, …), or point setDefaultFontFamily() at a different family.`,\n );\n}\n\n/**\n * The requested family is the explicitly set default, and that default names\n * a family that was never registered at all. Distinct from\n * `warnSelfUnusableDefaultOnce`, which reports a default that *is* registered\n * but not in a variant that can serve the request: there the fix is to bake a\n * variant, here the family has no atlas whatsoever, so pointing the reader at\n * a missing variant would send them looking for a `registerFont` call to\n * amend rather than one to write.\n */\nfunction warnUnregisteredDefaultOnce(\n family: string, weight: number, style: FontStyle,\n): void {\n if (!claimFallbackWarning(`unregistered-default|${family}|${weight}|${style}`)) return;\n console.warn(\n `weasel: font family \"${family}\" (${weight}/${style}) was never registered, and ` +\n `it is also the fallback family — setDefaultFontFamily(\"${family}\") names a ` +\n `family with no registered variants at all, so there is nothing left to fall ` +\n `back to and this text will not render at all. Call registerFont(\"${family}\", ` +\n `{ weight: ${weight}, style: '${style}' }, …), or point setDefaultFontFamily() ` +\n `at a family you have registered.`,\n );\n}\n\nfunction weightBucket(w: number): 'regular' | 'bold' {\n return w >= 600 ? 'bold' : 'regular';\n}\n\n/**\n * Resolve a `(family, weight, style)` request to a registered font entry,\n * walking the fallback chain when an exact match isn't available. Returns\n * synthetic flags describing the gap between requested and resolved so the\n * renderer can apply SDF-thicken / vertex-skew fakes.\n */\nexport function resolveFontVariant(\n family: string,\n weight: number,\n style: FontStyle,\n): ResolveResult {\n return resolveFontVariantInternal(family, weight, style, false);\n}\n\n/**\n * Escalate a *single codepoint* to the dynamic tier when the atlas that\n * resolved for the run has no glyph for it.\n *\n * `resolveFontVariant` answers at family granularity: it picks one tier for a\n * whole run. But a baked MSDF atlas covers a fixed charset, so a run served by\n * a perfectly good atlas can still contain a character that atlas never baked\n * — an em dash, a curly quote, anything outside the subset. The dynamic tier\n * rasterizes on demand from installed fonts and can serve exactly those.\n *\n * Returns a canvas-tier `ResolveResult` whose `dynamicFace` the caller drives\n * with `requestGlyph(cp)`, or `null` when escalation isn't available:\n *\n * - Policy `'none'` documents a miss as a *hard* miss. Quietly reaching for\n * another tier per codepoint would undo that, so it doesn't.\n * - No canvas to rasterize into (SSR, a jsdom test without one) makes the\n * dynamic tier constructible-but-broken; `getDynamicFace` throws and this\n * reports the miss instead of taking the caller down with it.\n *\n * Cheap to call per missing codepoint: faces are cached by variant and glyphs\n * by codepoint, so a repeat is two map lookups.\n */\nexport function resolveGlyphFallback(\n family: string,\n weight: number,\n style: FontStyle,\n): ResolveResult | null {\n if (getFontFallbackPolicy() === 'none') return null;\n try {\n return {\n entry: null,\n dynamicFace: getDynamicFace(family, weight, style),\n resolved: { family, weight, style },\n // The dynamic tier rasterizes the real weight and style, so there is\n // nothing for the shader to fake.\n synthetic: { bold: false, italic: false },\n source: 'canvas',\n };\n } catch {\n return null;\n }\n}\n\n/**\n * `suppressWarn` is set only by the recursive substitution probe in\n * `missResolveResult`, which resolves the fallback family purely to check\n * whether it renders. That probe is not itself a request anything asked\n * for, so it must not emit — or claim the warn-once key for — a message\n * about a resolution the caller never made; the caller's own top-level\n * `missResolveResult` call decides, from the probe's result, which single\n * warning (if any) describes the overall miss.\n */\nfunction resolveFontVariantInternal(\n family: string,\n weight: number,\n style: FontStyle,\n suppressWarn: boolean,\n): ResolveResult {\n const familyMap = registry.get(family);\n if (!familyMap || familyMap.size === 0) {\n return missResolveResult(family, weight, style, suppressWarn);\n }\n\n // 1. Exact match\n const exact = familyMap.get(variantKey(weight, style));\n if (exact) {\n return {\n entry: exact,\n resolved: { family, weight, style },\n synthetic: { bold: false, italic: false },\n source: 'atlas',\n };\n }\n\n // 2. Same style, nearest weight in same bucket (ties broken by higher weight)\n const requestedBucket = weightBucket(weight);\n let bestSameStyle: { entry: FontEntry; weight: number; distance: number } | null = null;\n for (const [key, entry] of familyMap) {\n const [wStr, s] = key.split('|') as [string, FontStyle];\n const w = Number(wStr);\n if (s !== style) continue;\n if (weightBucket(w) !== requestedBucket) continue;\n const distance = Math.abs(w - weight);\n if (\n bestSameStyle === null ||\n distance < bestSameStyle.distance ||\n (distance === bestSameStyle.distance && w > bestSameStyle.weight)\n ) {\n bestSameStyle = { entry, weight: w, distance };\n }\n }\n if (bestSameStyle) {\n return {\n entry: bestSameStyle.entry,\n resolved: { family, weight: bestSameStyle.weight, style },\n synthetic: { bold: false, italic: false },\n source: 'atlas',\n };\n }\n\n // 3. (family, 400, style)\n const sameStyleRegular = familyMap.get(variantKey(400, style));\n if (sameStyleRegular) {\n return {\n entry: sameStyleRegular,\n resolved: { family, weight: 400, style },\n synthetic: {\n bold: weight >= 600,\n italic: false,\n },\n source: 'atlas',\n };\n }\n\n // 4. (family, weight, 'normal') — same weight, no italic\n const sameWeightNormal = familyMap.get(variantKey(weight, 'normal'));\n if (sameWeightNormal) {\n return {\n entry: sameWeightNormal,\n resolved: { family, weight, style: 'normal' },\n synthetic: {\n bold: false,\n italic: style === 'italic',\n },\n source: 'atlas',\n };\n }\n\n // 4b. Nearest weight, normal style, same bucket\n let bestNormal: { entry: FontEntry; weight: number; distance: number } | null = null;\n for (const [key, entry] of familyMap) {\n const [wStr, s] = key.split('|') as [string, FontStyle];\n const w = Number(wStr);\n if (s !== 'normal') continue;\n if (weightBucket(w) !== requestedBucket) continue;\n const distance = Math.abs(w - weight);\n if (\n bestNormal === null ||\n distance < bestNormal.distance ||\n (distance === bestNormal.distance && w > bestNormal.weight)\n ) {\n bestNormal = { entry, weight: w, distance };\n }\n }\n if (bestNormal) {\n return {\n entry: bestNormal.entry,\n resolved: { family, weight: bestNormal.weight, style: 'normal' },\n synthetic: {\n bold: false,\n italic: style === 'italic',\n },\n source: 'atlas',\n };\n }\n\n // 5. (family, 400, 'normal') — last resort within family\n const regular = familyMap.get(variantKey(400, 'normal'));\n if (regular) {\n return {\n entry: regular,\n resolved: { family, weight: 400, style: 'normal' },\n synthetic: {\n bold: weight >= 600,\n italic: style === 'italic',\n },\n source: 'atlas',\n };\n }\n\n return missResolveResult(family, weight, style, suppressWarn);\n}\n"]}
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { registerFontOutlines, createOpenTypeParser } from './chunk-XK73IOFB.js';
2
- export { DEFAULT_BAKE_BUDGET, FIXTURE_FONT, dynamicPageTextureId, ensureFontTexture, getDefaultFontFamily, getFont, getFontFallbackPolicy, glyphGeneration, glyphOutline, hasFontOutlines, isCanvasFont, listCanvasFonts, listFontOutlines, listFonts, markAllFontsNotUploaded, outlineMetrics, outlineStatus, parseBmFont, registerCanvasFont, registerFont, registerFontOutlines, resetBakeBudget, resolveFontVariant, resolveGlyphFallback, setDefaultFontFamily, setFontFallbackPolicy, subscribeGlyphReady, syncDynamicPageTexture, textureCacheKey, unregisterCanvasFont, unregisterFontOutlines } from './chunk-XK73IOFB.js';
1
+ import { registerFontOutlines, createOpenTypeParser } from './chunk-NRVRDX3F.js';
2
+ export { DEFAULT_BAKE_BUDGET, FIXTURE_FONT, dynamicPageTextureId, ensureFontTexture, getDefaultFontFamily, getFont, getFontFallbackPolicy, glyphGeneration, glyphOutline, hasFontOutlines, isCanvasFont, listCanvasFonts, listFontOutlines, listFonts, markAllFontsNotUploaded, outlineMetrics, outlineStatus, parseBmFont, registerCanvasFont, registerFont, registerFontOutlines, resetBakeBudget, resolveFontVariant, resolveGlyphFallback, setDefaultFontFamily, setFontFallbackPolicy, subscribeGlyphReady, syncDynamicPageTexture, textureCacheKey, unregisterCanvasFont, unregisterFontOutlines } from './chunk-NRVRDX3F.js';
3
3
 
4
4
  // src/outline/localFonts.ts
5
5
  function canQueryLocalFonts() {
@@ -1,3 +1,3 @@
1
- export { __setGlyphRasterizerForTests, _getPagesForTests, _resetDynamicFontsForTests, _resetFallbackForTests, _resetFontOutlinesForTests, _resetFontRegistryForTests } from './chunk-XK73IOFB.js';
1
+ export { __setGlyphRasterizerForTests, _getPagesForTests, _resetDynamicFontsForTests, _resetFallbackForTests, _resetFontOutlinesForTests, _resetFontRegistryForTests } from './chunk-NRVRDX3F.js';
2
2
  //# sourceMappingURL=test-seams.js.map
3
3
  //# sourceMappingURL=test-seams.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weasel-js/font",
3
- "version": "1.3.0-pre.0",
3
+ "version": "1.4.0-pre.0",
4
4
  "description": "MSDF font atlases, glyph metrics, and runtime glyph rasterization for @weasel-js/core. Registry, kerning-aware glyph layout, and the SDF text shader source.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/FontAtlas.ts","../src/glyphReady.ts","../src/fallback.ts","../src/dynamic/shelfPack.ts","../src/dynamic/distanceTransform.ts","../src/dynamic/glyphRasterizer.ts","../src/dynamic/dynamicAtlas.ts","../src/outline/OutlineFace.ts","../src/outline/sfnt.ts","../src/outline/opentypeParser.ts","../src/outline/outlineRegistry.ts","../src/registerFont.ts"],"names":["policy"],"mappings":";AAsDO,IAAM,YAAA,GAAe;AAAA,EAC1B,IAAA,EAAM,EAAE,IAAA,EAAM,OAAA,EAAS,MAAM,EAAA,EAAG;AAAA,EAChC,MAAA,EAAQ,EAAE,UAAA,EAAY,EAAA,EAAI,MAAM,EAAA,EAAI,MAAA,EAAQ,GAAA,EAAK,MAAA,EAAQ,GAAA,EAAI;AAAA,EAC7D,KAAA,EAAO;AAAA,IACL,EAAE,EAAA,EAAI,EAAA,EAAI,GAAG,CAAA,EAAI,CAAA,EAAG,GAAG,KAAA,EAAO,EAAA,EAAI,MAAA,EAAQ,EAAA,EAAI,SAAS,CAAA,EAAG,OAAA,EAAS,GAAG,QAAA,EAAU,EAAA,EAAI,MAAM,CAAA,EAAE;AAAA,IAC5F,EAAE,EAAA,EAAI,EAAA,EAAI,GAAG,EAAA,EAAI,CAAA,EAAG,GAAG,KAAA,EAAO,EAAA,EAAI,MAAA,EAAQ,EAAA,EAAI,SAAS,CAAA,EAAG,OAAA,EAAS,GAAG,QAAA,EAAU,EAAA,EAAI,MAAM,CAAA;AAAE,GAC9F;AAAA,EACA,QAAA,EAAU;AAAA,IACR,EAAE,KAAA,EAAO,EAAA,EAAI,MAAA,EAAQ,EAAA,EAAI,QAAQ,EAAA;AAAG;AAExC;AAIO,SAAS,YAAY,GAAA,EAAsB;AAChD,EAAA,IAAI,OAAO,QAAQ,QAAA,IAAY,GAAA,KAAQ,MAAM,MAAM,IAAI,MAAM,8BAA8B,CAAA;AAC3F,EAAA,MAAM,CAAA,GAAI,GAAA;AAEV,EAAA,IAAI,CAAC,CAAA,CAAE,IAAA,IAAQ,OAAO,CAAA,CAAE,SAAS,QAAA,EAAU,MAAM,IAAI,KAAA,CAAM,2BAA2B,CAAA;AACtF,EAAA,IAAI,CAAC,CAAA,CAAE,MAAA,IAAU,OAAO,CAAA,CAAE,WAAW,QAAA,EAAU,MAAM,IAAI,KAAA,CAAM,6BAA6B,CAAA;AAC5F,EAAA,IAAI,CAAC,MAAM,OAAA,CAAQ,CAAA,CAAE,KAAK,CAAA,EAAG,MAAM,IAAI,KAAA,CAAM,qCAAqC,CAAA;AAElF,EAAA,MAAM,OAAO,CAAA,CAAE,IAAA;AACf,EAAA,MAAM,SAAS,CAAA,CAAE,MAAA;AACjB,EAAA,MAAM,QAAQ,CAAA,CAAE,KAAA;AAChB,EAAA,MAAM,QAAA,GAA4B,MAAM,OAAA,CAAQ,CAAA,CAAE,QAAQ,CAAA,GACrD,CAAA,CAAE,WACH,EAAC;AAEL,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAwB;AAC5C,EAAA,KAAA,MAAW,MAAM,KAAA,EAAO,OAAA,CAAQ,GAAA,CAAI,EAAA,CAAG,IAAI,EAAE,CAAA;AAE7C,EAAA,MAAM,UAAA,uBAAiB,GAAA,EAAiC;AACxD,EAAA,KAAA,MAAW,KAAK,QAAA,EAAU;AACxB,IAAA,IAAI,KAAA,GAAQ,UAAA,CAAW,GAAA,CAAI,CAAA,CAAE,KAAK,CAAA;AAClC,IAAA,IAAI,CAAC,KAAA,EAAO;AAAE,MAAA,KAAA,uBAAY,GAAA,EAAI;AAAG,MAAA,UAAA,CAAW,GAAA,CAAI,CAAA,CAAE,KAAA,EAAO,KAAK,CAAA;AAAA,IAAG;AACjE,IAAA,KAAA,CAAM,GAAA,CAAI,CAAA,CAAE,MAAA,EAAQ,CAAA,CAAE,MAAM,CAAA;AAAA,EAC9B;AAEA,EAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,KAAA,EAAO,QAAA,EAAU,SAAS,UAAA,EAAW;AAC9D;;;AC9EA,IAAM,WAAA,uBAAkB,GAAA,EAAgB;AAIxC,IAAI,UAAA,GAAa,CAAA;AAkBV,SAAS,eAAA,GAA0B;AACxC,EAAA,OAAO,UAAA;AACT;AAQO,SAAS,oBAAoB,EAAA,EAA4B;AAC9D,EAAA,WAAA,CAAY,IAAI,EAAE,CAAA;AAClB,EAAA,OAAO,MAAM;AACX,IAAA,WAAA,CAAY,OAAO,EAAE,CAAA;AAAA,EACvB,CAAA;AACF;AAGO,SAAS,gBAAA,GAAyB;AACvC,EAAA,UAAA,EAAA;AACA,EAAA,KAAA,MAAW,EAAA,IAAM,aAAa,EAAA,EAAG;AACnC;AAGO,SAAS,2BAAA,GAAoC;AAClD,EAAA,WAAA,CAAY,KAAA,EAAM;AACpB;;;AC7CA,IAAI,MAAA,GAA6B,YAAA;AACjC,IAAI,aAAA,GAA+B,IAAA;AAI5B,SAAS,sBAAsB,IAAA,EAAgC;AACpE,EAAA,MAAA,GAAS,IAAA;AACX;AAGO,SAAS,qBAAA,GAA4C;AAC1D,EAAA,OAAO,MAAA;AACT;AAKO,SAAS,qBAAqB,MAAA,EAAsB;AACzD,EAAA,aAAA,GAAgB,MAAA;AAClB;AAIO,SAAS,oBAAA,GAAsC;AACpD,EAAA,OAAO,aAAA;AACT;AAUA,IAAM,eAAA,uBAAsB,GAAA,EAAY;AAGjC,SAAS,qBAAqB,GAAA,EAAsB;AACzD,EAAA,IAAI,eAAA,CAAgB,GAAA,CAAI,GAAG,CAAA,EAAG,OAAO,KAAA;AACrC,EAAA,eAAA,CAAgB,IAAI,GAAG,CAAA;AACvB,EAAA,OAAO,IAAA;AACT;AAIO,SAAS,sBAAA,GAA+B;AAC7C,EAAA,eAAA,CAAgB,KAAA,EAAM;AACxB;AAGO,SAAS,sBAAA,GAA+B;AAC7C,EAAA,MAAA,GAAS,YAAA;AACT,EAAA,aAAA,GAAgB,IAAA;AAChB,EAAA,eAAA,CAAgB,KAAA,EAAM;AACxB;;;AC3DO,IAAM,cAAN,MAAkB;AAAA,EAIvB,WAAA,CACmB,UACA,QAAA,EACjB;AAFiB,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AACA,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AAAA,EAChB;AAAA,EAFgB,QAAA;AAAA,EACA,QAAA;AAAA,EALX,QAAgB,EAAC;AAAA,EACjB,MAAA,GAAS,KAAA;AAAA,EAOjB,IAAI,SAAA,GAAoB;AACtB,IAAA,OAAO,KAAK,KAAA,CAAM,MAAA;AAAA,EACpB;AAAA;AAAA,EAGA,KAAA,CAAM,GAAW,CAAA,EAA8B;AAC7C,IAAA,IAAI,CAAA,GAAI,KAAK,QAAA,IAAY,CAAA,GAAI,KAAK,QAAA,EAAU,OAAO,KAAK,IAAA,EAAK;AAC7D,IAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AAC1C,MAAA,MAAM,IAAA,GAAO,KAAK,WAAA,CAAY,IAAA,CAAK,MAAM,CAAC,CAAA,EAAG,GAAG,CAAC,CAAA;AACjD,MAAA,IAAI,MAAM,OAAO,EAAE,IAAA,EAAM,CAAA,EAAG,GAAG,IAAA,EAAK;AAAA,IACtC;AACA,IAAA,IAAI,IAAA,CAAK,KAAA,CAAM,MAAA,GAAS,IAAA,CAAK,QAAA,EAAU;AACrC,MAAA,MAAM,OAAa,EAAE,OAAA,EAAS,EAAC,EAAG,OAAO,CAAA,EAAE;AAC3C,MAAA,IAAA,CAAK,KAAA,CAAM,KAAK,IAAI,CAAA;AACpB,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,WAAA,CAAY,IAAA,EAAM,GAAG,CAAC,CAAA;AACxC,MAAA,IAAI,IAAA,SAAa,EAAE,IAAA,EAAM,KAAK,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG,GAAG,IAAA,EAAK;AAAA,IAC1D;AACA,IAAA,OAAO,KAAK,IAAA,EAAK;AAAA,EACnB;AAAA,EAEQ,WAAA,CAAY,IAAA,EAAY,CAAA,EAAW,CAAA,EAA4C;AACrF,IAAA,KAAA,MAAW,KAAA,IAAS,KAAK,OAAA,EAAS;AAChC,MAAA,IAAI,KAAK,KAAA,CAAM,MAAA,IAAU,MAAM,CAAA,GAAI,CAAA,IAAK,KAAK,QAAA,EAAU;AACrD,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA;AAChB,QAAA,KAAA,CAAM,CAAA,IAAK,CAAA;AACX,QAAA,OAAO,EAAE,CAAA,EAAG,CAAA,EAAG,KAAA,CAAM,CAAA,EAAE;AAAA,MACzB;AAAA,IACF;AACA,IAAA,IAAI,IAAA,CAAK,KAAA,GAAQ,CAAA,IAAK,IAAA,CAAK,QAAA,EAAU;AACnC,MAAA,MAAM,KAAA,GAAe,EAAE,CAAA,EAAG,IAAA,CAAK,OAAO,MAAA,EAAQ,CAAA,EAAG,GAAG,CAAA,EAAE;AACtD,MAAA,IAAA,CAAK,OAAA,CAAQ,KAAK,KAAK,CAAA;AACvB,MAAA,IAAA,CAAK,KAAA,IAAS,CAAA;AACd,MAAA,OAAO,EAAE,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,MAAM,CAAA,EAAE;AAAA,IAC5B;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EAEQ,IAAA,GAAa;AACnB,IAAA,IAAI,CAAC,KAAK,MAAA,EAAQ;AAChB,MAAA,IAAA,CAAK,MAAA,GAAS,IAAA;AACd,MAAA,OAAA,CAAQ,IAAA;AAAA,QACN,CAAA,4CAAA,EAA+C,IAAA,CAAK,QAAQ,CAAA,MAAA,EAAM,KAAK,QAAQ,CAAA,8CAAA;AAAA,OAEjF;AAAA,IACF;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AACF,CAAA;;;AC9DA,IAAM,GAAA,GAAM,IAAA;AAGZ,SAAS,KAAA,CACP,CAAA,EAAiB,CAAA,EAAiB,CAAA,EAAe,GAAiB,CAAA,EAC5D;AACN,EAAA,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA;AACP,EAAA,CAAA,CAAE,CAAC,IAAI,CAAC,GAAA;AACR,EAAA,CAAA,CAAE,CAAC,CAAA,GAAI,GAAA;AACP,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA,EAAK;AAC1B,IAAA,IAAI,CAAA,GAAA,CAAK,EAAE,CAAC,CAAA,GAAI,IAAI,CAAA,IAAK,CAAA,CAAE,EAAE,CAAC,CAAC,IAAI,CAAA,CAAE,CAAC,IAAI,CAAA,CAAE,CAAC,OAAO,CAAA,GAAI,CAAA,GAAI,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,CAAA;AACnE,IAAA,OAAO,CAAA,IAAK,CAAA,CAAE,CAAC,CAAA,EAAG;AAChB,MAAA,CAAA,EAAA;AACA,MAAA,CAAA,GAAA,CAAK,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,GAAI,KAAK,CAAA,CAAE,CAAA,CAAE,CAAC,CAAC,CAAA,GAAI,EAAE,CAAC,CAAA,GAAI,EAAE,CAAC,CAAA,CAAA,KAAO,IAAI,CAAA,GAAI,CAAA,GAAI,EAAE,CAAC,CAAA,CAAA;AAAA,IACjE;AACA,IAAA,CAAA,EAAA;AACA,IAAA,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA;AACP,IAAA,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA;AACP,IAAA,CAAA,CAAE,CAAA,GAAI,CAAC,CAAA,GAAI,GAAA;AAAA,EACb;AACA,EAAA,CAAA,GAAI,CAAA;AACJ,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA,EAAK;AAC1B,IAAA,OAAO,CAAA,CAAE,CAAA,GAAI,CAAC,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA;AACrB,IAAA,CAAA,CAAE,CAAC,CAAA,GAAA,CAAK,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,KAAM,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,CAAA,GAAK,CAAA,CAAE,CAAA,CAAE,CAAC,CAAC,CAAA;AAAA,EACzC;AACF;AAGA,SAAS,MACP,IAAA,EAAoB,KAAA,EAAe,QACnC,CAAA,EAAiB,CAAA,EAAiB,GAAe,CAAA,EAC3C;AACN,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,EAAO,CAAA,EAAA,EAAK;AAC9B,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,EAAQ,CAAA,EAAA,EAAK,CAAA,CAAE,CAAC,CAAA,GAAI,IAAA,CAAK,CAAA,GAAI,KAAA,GAAQ,CAAC,CAAA;AAC1D,IAAA,KAAA,CAAM,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,MAAM,CAAA;AACxB,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,EAAQ,CAAA,EAAA,EAAK,IAAA,CAAK,CAAA,GAAI,KAAA,GAAQ,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA;AAAA,EAC5D;AACA,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,EAAQ,CAAA,EAAA,EAAK;AAC/B,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,EAAO,CAAA,EAAA,EAAK,CAAA,CAAE,CAAC,CAAA,GAAI,IAAA,CAAK,CAAA,GAAI,KAAA,GAAQ,CAAC,CAAA;AACzD,IAAA,KAAA,CAAM,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,KAAK,CAAA;AACvB,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,EAAO,CAAA,EAAA,EAAK,IAAA,CAAK,CAAA,GAAI,KAAA,GAAQ,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA;AAAA,EAC3D;AACF;AAQO,SAAS,UAAA,CACd,KAAA,EACA,KAAA,EACA,MAAA,EACA,QACA,MAAA,EACY;AACZ,EAAA,MAAM,IAAI,KAAA,GAAQ,MAAA;AAClB,EAAA,MAAM,SAAA,GAAY,IAAI,YAAA,CAAa,CAAC,CAAA;AACpC,EAAA,MAAM,SAAA,GAAY,IAAI,YAAA,CAAa,CAAC,CAAA;AACpC,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,KAAA,EAAO,MAAM,CAAA;AACnC,EAAA,MAAM,CAAA,GAAI,IAAI,YAAA,CAAa,IAAI,CAAA;AAC/B,EAAA,MAAM,CAAA,GAAI,IAAI,YAAA,CAAa,IAAI,CAAA;AAC/B,EAAA,MAAM,CAAA,GAAI,IAAI,UAAA,CAAW,IAAI,CAAA;AAC7B,EAAA,MAAM,CAAA,GAAI,IAAI,YAAA,CAAa,IAAA,GAAO,CAAC,CAAA;AAEnC,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA,EAAK;AAC1B,IAAA,MAAM,CAAA,GAAI,KAAA,CAAM,CAAC,CAAA,GAAI,GAAA;AACrB,IAAA,SAAA,CAAU,CAAC,CAAA,GAAI,CAAA,KAAM,CAAA,GAAI,CAAA,GAAI,CAAA,KAAM,CAAA,GAAI,GAAA,GAAM,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,GAAA,GAAM,CAAC,CAAA,IAAK,CAAA;AACrE,IAAA,SAAA,CAAU,CAAC,CAAA,GAAI,CAAA,KAAM,CAAA,GAAI,GAAA,GAAM,CAAA,KAAM,CAAA,GAAI,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,CAAA,GAAI,GAAG,CAAA,IAAK,CAAA;AAAA,EACvE;AACA,EAAA,KAAA,CAAM,WAAW,KAAA,EAAO,MAAA,EAAQ,CAAA,EAAG,CAAA,EAAG,GAAG,CAAC,CAAA;AAC1C,EAAA,KAAA,CAAM,WAAW,KAAA,EAAO,MAAA,EAAQ,CAAA,EAAG,CAAA,EAAG,GAAG,CAAC,CAAA;AAE1C,EAAA,MAAM,GAAA,GAAM,IAAI,UAAA,CAAW,CAAC,CAAA;AAC5B,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA,EAAK;AAC1B,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,SAAA,CAAU,CAAC,CAAC,CAAA,GAAI,IAAA,CAAK,IAAA,CAAK,SAAA,CAAU,CAAC,CAAC,CAAA;AAC7D,IAAA,MAAM,OAAO,IAAA,CAAK,KAAA,CAAM,MAAM,GAAA,IAAO,IAAA,GAAO,SAAS,MAAA,CAAO,CAAA;AAC5D,IAAA,GAAA,CAAI,CAAC,CAAA,GAAI,IAAA,GAAO,IAAI,CAAA,GAAI,IAAA,GAAO,MAAM,GAAA,GAAM,IAAA;AAAA,EAC7C;AACA,EAAA,OAAO,GAAA;AACT;;;ACvDO,IAAM,SAAA,GAAY,EAAA;AAClB,IAAM,GAAA,GAAM,CAAA;AAyBnB,SAAS,aAAA,CAAc,MAAA,EAAgB,KAAA,EAA4B,MAAA,EAAwB;AACzF,EAAA,OAAO,CAAA,EAAG,KAAA,KAAU,QAAA,GAAW,SAAA,GAAY,EAAE,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,SAAS,CAAA,GAAA,EAAM,IAAA,CAAK,SAAA,CAAU,MAAM,CAAC,CAAA,CAAA;AACjG;AAEO,SAAS,sBAAA,GAA0C;AACxD,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI,OAAO,oBAAoB,WAAA,EAAa;AAC1C,IAAA,MAAA,GAAS,IAAI,eAAA,CAAgB,SAAA,GAAY,CAAA,EAAG,YAAY,CAAC,CAAA;AAAA,EAC3D,CAAA,MAAA,IAAW,OAAO,QAAA,KAAa,WAAA,EAAa;AAC1C,IAAA,MAAA,GAAS,QAAA,CAAS,cAAc,QAAQ,CAAA;AACxC,IAAA,MAAA,CAAO,QAAQ,SAAA,GAAY,CAAA;AAC3B,IAAA,MAAA,CAAO,SAAS,SAAA,GAAY,CAAA;AAAA,EAC9B,CAAA,MAAO;AACL,IAAA,MAAM,IAAI,MAAM,uEAAuE,CAAA;AAAA,EACzF;AACA,EAAA,MAAM,MAAM,MAAA,CAAO,UAAA,CAAW,MAAM,EAAE,kBAAA,EAAoB,MAAM,CAAA;AAChE,EAAA,IAAI,CAAC,GAAA,EAAK,MAAM,IAAI,MAAM,kDAAkD,CAAA;AAE5E,EAAA,SAAS,OAAA,CAAQ,MAAA,EAAgB,MAAA,EAAgB,KAAA,EAAkC;AACjF,IAAA,GAAA,CAAK,IAAA,GAAO,aAAA,CAAc,MAAA,EAAQ,KAAA,EAAO,MAAM,CAAA;AAC/C,IAAA,GAAA,CAAK,YAAA,GAAe,YAAA;AACpB,IAAA,GAAA,CAAK,SAAA,GAAY,MAAA;AAAA,EACnB;AAEA,EAAA,OAAO;AAAA,IACL,WAAA,CAAY,MAAA,EAAQ,MAAA,EAAQ,KAAA,EAAO;AACjC,MAAA,OAAA,CAAQ,MAAA,EAAQ,QAAQ,KAAK,CAAA;AAC7B,MAAA,MAAM,CAAA,GAAI,GAAA,CAAK,WAAA,CAAY,IAAI,CAAA;AAC/B,MAAA,OAAO;AAAA,QACL,MAAA,EAAQ,CAAA,CAAE,qBAAA,IAAyB,SAAA,GAAY,GAAA;AAAA,QAC/C,OAAA,EAAS,CAAA,CAAE,sBAAA,IAA0B,SAAA,GAAY;AAAA,OACnD;AAAA,IACF,CAAA;AAAA,IAEA,SAAA,CAAU,MAAA,EAAQ,MAAA,EAAQ,KAAA,EAAO,SAAA,EAAW;AAC1C,MAAA,OAAA,CAAQ,MAAA,EAAQ,QAAQ,KAAK,CAAA;AAC7B,MAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,aAAA,CAAc,SAAS,CAAA;AAC5C,MAAA,MAAM,CAAA,GAAI,GAAA,CAAK,WAAA,CAAY,KAAK,CAAA;AAChC,MAAA,MAAM,UAAU,CAAA,CAAE,KAAA;AAClB,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,IAAA,CAAK,CAAA,CAAE,yBAAyB,CAAC,CAAA;AACtD,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,IAAA,CAAK,CAAA,CAAE,0BAA0B,OAAO,CAAA;AAC9D,MAAA,MAAM,YAAY,IAAA,CAAK,IAAA,CAAK,CAAA,CAAE,uBAAA,IAA2B,YAAY,GAAG,CAAA;AACxE,MAAA,MAAM,aAAa,IAAA,CAAK,IAAA,CAAK,CAAA,CAAE,wBAAA,IAA4B,YAAY,GAAG,CAAA;AAC1E,MAAA,MAAM,OAAO,OAAA,GAAU,QAAA;AACvB,MAAA,MAAM,OAAO,SAAA,GAAY,UAAA;AACzB,MAAA,IAAI,IAAA,IAAQ,CAAA,IAAK,IAAA,IAAQ,CAAA,EAAG;AAC1B,QAAA,OAAO,EAAE,KAAA,EAAO,CAAA,EAAG,MAAA,EAAQ,GAAG,KAAA,EAAO,IAAI,iBAAA,CAAkB,CAAC,CAAA,EAAG,IAAA,EAAM,CAAA,EAAG,GAAA,EAAK,GAAG,OAAA,EAAQ;AAAA,MAC1F;AACA,MAAA,MAAM,CAAA,GAAI,OAAO,CAAA,GAAI,GAAA;AACrB,MAAA,MAAM,CAAA,GAAI,OAAO,CAAA,GAAI,GAAA;AACrB,MAAA,IAAI,MAAA,CAAO,KAAA,GAAQ,CAAA,IAAK,MAAA,CAAO,SAAS,CAAA,EAAG;AACzC,QAAA,MAAA,CAAO,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,OAAO,CAAC,CAAA;AACvC,QAAA,MAAA,CAAO,MAAA,GAAS,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,QAAQ,CAAC,CAAA;AACzC,QAAA,OAAA,CAAQ,MAAA,EAAQ,QAAQ,KAAK,CAAA;AAAA,MAC/B;AACA,MAAA,GAAA,CAAK,SAAA,CAAU,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA;AACzB,MAAA,GAAA,CAAK,SAAA,GAAY,MAAA;AACjB,MAAA,GAAA,CAAK,QAAA,CAAS,KAAA,EAAO,GAAA,GAAM,OAAA,EAAS,MAAM,SAAS,CAAA;AACnD,MAAA,MAAM,MAAM,GAAA,CAAK,YAAA,CAAa,CAAA,EAAG,CAAA,EAAG,GAAG,CAAC,CAAA;AACxC,MAAA,MAAM,KAAA,GAAQ,IAAI,iBAAA,CAAkB,CAAA,GAAI,CAAC,CAAA;AACzC,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,MAAA,EAAQ,CAAA,EAAA,EAAK,KAAA,CAAM,CAAC,CAAA,GAAI,GAAA,CAAI,IAAA,CAAK,CAAA,GAAI,IAAI,CAAC,CAAA;AACpE,MAAA,OAAO;AAAA,QACL,KAAA,EAAO,CAAA;AAAA,QACP,MAAA,EAAQ,CAAA;AAAA,QACR,KAAA;AAAA,QACA,IAAA,EAAM,EAAE,OAAA,GAAU,GAAA,CAAA;AAAA,QAClB,KAAK,SAAA,GAAY,GAAA;AAAA,QACjB;AAAA,OACF;AAAA,IACF;AAAA,GACF;AACF;;;ACzGO,IAAM,SAAA,GAAY,IAAA;AAClB,IAAM,SAAA,GAAY,CAAA;AAClB,IAAM,UAAA,GAAa,CAAA;AACnB,IAAM,UAAA,GAAa,GAAA;AAKnB,IAAM,mBAAA,GAAsB;AA+BnC,IAAM,cAAA,uBAAqB,GAAA,EAAY;AAMvC,IAAM,oBAAA,uBAA2B,GAAA,EAAY;AAC7C,IAAI,KAAA,uBAAY,GAAA,EAAyB;AACzC,IAAI,QAAuB,EAAC;AAC5B,IAAI,MAAA,GAAS,IAAI,WAAA,CAAY,SAAA,EAAW,SAAS,CAAA;AACjD,IAAI,UAAyB,EAAC;AAC9B,IAAI,cAAA,GAAiB,KAAA;AACrB,IAAI,MAAA,GAAS,mBAAA;AACb,IAAI,UAAA,GAAqC,IAAA;AAEzC,SAAS,aAAA,GAAiC;AACxC,EAAA,IAAI,CAAC,UAAA,EAAY,UAAA,GAAa,sBAAA,EAAuB;AACrD,EAAA,OAAO,UAAA;AACT;AAIO,SAAS,mBAAmB,MAAA,EAAsB;AACvD,EAAA,cAAA,CAAe,IAAI,MAAM,CAAA;AAEzB,EAAA,oBAAA,CAAqB,OAAO,MAAM,CAAA;AACpC;AAqBO,SAAS,aAAa,MAAA,EAAyB;AACpD,EAAA,IAAI,CAAC,cAAA,CAAe,GAAA,CAAI,MAAM,GAAG,OAAO,KAAA;AACxC,EAAA,OAAO,CAAC,oBAAA,CAAqB,GAAA,CAAI,MAAM,CAAA,IAAK,uBAAsB,KAAM,QAAA;AAC1E;AAkBO,SAAS,eAAA,GAA8C;AAC5D,EAAA,MAAM,MAAyB,EAAC;AAChC,EAAA,KAAA,MAAW,UAAU,cAAA,EAAgB;AACnC,IAAA,IAAI,CAAC,YAAA,CAAa,MAAM,CAAA,EAAG;AAC3B,IAAA,GAAA,CAAI,IAAA,CAAK,EAAE,MAAA,EAAQ,UAAA,EAAY,oBAAA,CAAqB,IAAI,MAAM,CAAA,GAAI,MAAA,GAAS,UAAA,EAAY,CAAA;AAAA,EACzF;AACA,EAAA,OAAO,GAAA,CAAI,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,EAAE,MAAA,CAAO,aAAA,CAAc,CAAA,CAAE,MAAM,CAAC,CAAA;AAC5D;AAOO,SAAS,qBAAqB,MAAA,EAAsB;AACzD,EAAA,IAAI,cAAA,CAAe,IAAI,MAAM,CAAA,IAAK,CAAC,oBAAA,CAAqB,GAAA,CAAI,MAAM,CAAA,EAAG;AACrE,EAAA,cAAA,CAAe,IAAI,MAAM,CAAA;AACzB,EAAA,oBAAA,CAAqB,IAAI,MAAM,CAAA;AACjC;AAQO,SAAS,qBAAqB,MAAA,EAAyB;AAC5D,EAAA,OAAO,eAAe,GAAA,CAAI,MAAM,KAAK,CAAC,oBAAA,CAAqB,IAAI,MAAM,CAAA;AACvE;AAIO,SAAS,qBAAqB,MAAA,EAAsB;AACzD,EAAA,cAAA,CAAe,OAAO,MAAM,CAAA;AAC5B,EAAA,oBAAA,CAAqB,OAAO,MAAM,CAAA;AAClC,EAAA,KAAA,MAAW,OAAO,CAAC,GAAG,KAAA,CAAM,IAAA,EAAM,CAAA,EAAG;AACnC,IAAA,IAAI,KAAA,CAAM,IAAI,GAAG,CAAA,CAAG,WAAW,MAAA,EAAQ,KAAA,CAAM,OAAO,GAAG,CAAA;AAAA,EACzD;AACF;AAMO,SAAS,cAAA,CACd,MAAA,EAAgB,MAAA,EAAgB,KAAA,EACnB;AACb,EAAA,MAAM,MAAM,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,MAAM,IAAI,KAAK,CAAA,CAAA;AACxC,EAAA,MAAM,QAAA,GAAW,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA;AAC9B,EAAA,IAAI,UAAU,OAAO,QAAA;AAErB,EAAA,MAAM,IAAI,aAAA,EAAc;AACxB,EAAA,MAAM,OAAA,GAAU,CAAA,CAAE,WAAA,CAAY,MAAA,EAAQ,QAAQ,KAAK,CAAA;AACnD,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA;AACtC,EAAA,MAAM,IAAA,GAAe;AAAA,IACnB,IAAA,EAAM,EAAE,IAAA,EAAM,MAAA,EAAQ,MAAM,SAAA,EAAU;AAAA,IACtC,MAAA,EAAQ;AAAA,MACN,YAAY,IAAA,CAAK,KAAA,CAAM,OAAA,CAAQ,MAAA,GAAS,QAAQ,OAAO,CAAA;AAAA,MACvD,IAAA;AAAA,MACA,MAAA,EAAQ,SAAA;AAAA,MACR,MAAA,EAAQ;AAAA,KACV;AAAA,IACA,OAAO,EAAC;AAAA,IACR,UAAU,EAAC;AAAA;AAAA,IACX,OAAA,sBAAa,GAAA,EAAI;AAAA,IACjB,UAAA,sBAAgB,GAAA;AAAI,GACtB;AAEA,EAAA,MAAM,IAAA,GAAoB;AAAA,IACxB,MAAA;AAAA,IAAQ,MAAA;AAAA,IAAQ,KAAA;AAAA,IAAO,IAAA;AAAA,IACvB,aAAa,EAAA,EAAwB;AACnC,MAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,EAAE,CAAA;AAClC,MAAA,IAAI,QAAQ,OAAO,MAAA;AACnB,MAAA,MAAM,SAAS,CAAA,CAAE,SAAA,CAAU,MAAA,EAAQ,MAAA,EAAQ,OAAO,EAAE,CAAA;AACpD,MAAA,MAAM,IAAA,GAAmB;AAAA,QACvB,EAAA,EAAI,EAAA;AAAA,QAAI,CAAA,EAAG,CAAA;AAAA,QAAG,CAAA,EAAG,CAAA;AAAA,QAAG,KAAA,EAAO,CAAA;AAAA,QAAG,MAAA,EAAQ,CAAA;AAAA,QACtC,SAAS,MAAA,CAAO,IAAA;AAAA,QAChB,OAAA,EAAS,OAAO,MAAA,CAAO,GAAA;AAAA,QACvB,UAAU,MAAA,CAAO,OAAA;AAAA,QACjB,IAAA,EAAM;AAAA,OACR;AACA,MAAA,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,EAAA,EAAI,IAAI,CAAA;AACzB,MAAA,IAAA,CAAK,KAAA,CAAM,KAAK,IAAI,CAAA;AACpB,MAAA,IAAI,MAAA,CAAO,KAAA,KAAU,CAAA,IAAK,MAAA,CAAO,WAAW,CAAA,EAAG;AAC7C,QAAA,IAAA,CAAK,IAAA,GAAO,CAAA;AACZ,QAAA,OAAO,IAAA;AAAA,MACT;AACA,MAAA,IAAI,SAAS,CAAA,EAAG;AACd,QAAA,MAAA,EAAA;AACA,QAAA,IAAA,CAAK,MAAM,MAAM,CAAA;AAAA,MACnB,CAAA,MAAO;AACL,QAAA,OAAA,CAAQ,IAAA,CAAK,EAAE,IAAA,EAAM,MAAA,EAAQ,CAAA;AAC7B,QAAA,aAAA,EAAc;AAAA,MAChB;AACA,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,GACF;AACA,EAAA,KAAA,CAAM,GAAA,CAAI,KAAK,IAAI,CAAA;AACnB,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,IAAA,CAAK,MAAkB,MAAA,EAA+B;AAC7D,EAAA,MAAM,OAAO,MAAA,CAAO,KAAA,CAAM,MAAA,CAAO,KAAA,EAAO,OAAO,MAAM,CAAA;AACrD,EAAA,IAAI,CAAC,IAAA,EAAM;AACX,EAAA,MAAM,GAAA,GAAM,WAAW,MAAA,CAAO,KAAA,EAAO,OAAO,KAAA,EAAO,MAAA,CAAO,MAAA,EAAQ,UAAA,EAAY,UAAU,CAAA;AACxF,EAAA,OAAO,KAAA,CAAM,MAAA,IAAU,IAAA,CAAK,IAAA,EAAM;AAChC,IAAA,KAAA,CAAM,IAAA,CAAK,EAAE,IAAA,EAAM,IAAI,UAAA,CAAW,SAAA,GAAY,SAAS,CAAA,EAAG,OAAA,EAAS,CAAA,EAAG,OAAA,EAAS,IAAI,CAAA;AAAA,EACrF;AACA,EAAA,MAAM,IAAA,GAAO,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA;AAC5B,EAAA,KAAA,IAAS,GAAA,GAAM,CAAA,EAAG,GAAA,GAAM,MAAA,CAAO,QAAQ,GAAA,EAAA,EAAO;AAC5C,IAAA,IAAA,CAAK,IAAA,CAAK,GAAA;AAAA,MACR,GAAA,CAAI,SAAS,GAAA,GAAM,MAAA,CAAO,QAAQ,GAAA,GAAM,CAAA,IAAK,OAAO,KAAK,CAAA;AAAA,MAAA,CACxD,IAAA,CAAK,CAAA,GAAI,GAAA,IAAO,SAAA,GAAY,IAAA,CAAK;AAAA,KACpC;AAAA,EACF;AACA,EAAA,IAAA,CAAK,OAAA,EAAA;AACL,EAAA,IAAA,CAAK,QAAQ,IAAA,CAAK,EAAE,KAAK,IAAA,CAAK,OAAA,EAAS,GAAG,IAAA,CAAK,CAAA,EAAG,CAAA,EAAG,IAAA,CAAK,GAAG,CAAA,EAAG,MAAA,CAAO,OAAO,CAAA,EAAG,MAAA,CAAO,QAAQ,CAAA;AAChG,EAAA,IAAA,CAAK,IAAI,IAAA,CAAK,CAAA;AACd,EAAA,IAAA,CAAK,IAAI,IAAA,CAAK,CAAA;AACd,EAAA,IAAA,CAAK,QAAQ,MAAA,CAAO,KAAA;AACpB,EAAA,IAAA,CAAK,SAAS,MAAA,CAAO,MAAA;AACrB,EAAA,IAAA,CAAK,OAAO,IAAA,CAAK,IAAA;AACnB;AAEA,SAAS,aAAA,GAAsB;AAC7B,EAAA,IAAI,cAAA,EAAgB;AACpB,EAAA,cAAA,GAAiB,IAAA;AACjB,EAAA,UAAA,CAAW,cAAc,CAAC,CAAA;AAC5B;AAEA,SAAS,YAAA,GAAqB;AAC5B,EAAA,cAAA,GAAiB,KAAA;AACjB,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,OAAO,OAAA,CAAQ,MAAA,GAAS,CAAA,IAAK,CAAA,GAAI,mBAAA,EAAqB;AACpD,IAAA,MAAM,GAAA,GAAM,QAAQ,KAAA,EAAM;AAC1B,IAAA,IAAI,GAAA,CAAI,IAAA,CAAK,IAAA,KAAS,EAAA,EAAI;AAC1B,IAAA,IAAA,CAAK,GAAA,CAAI,IAAA,EAAM,GAAA,CAAI,MAAM,CAAA;AACzB,IAAA,CAAA,EAAA;AAAA,EACF;AACA,EAAA,IAAI,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAG,aAAA,EAAc;AACtC,EAAA,gBAAA,EAAiB;AACnB;AAKO,SAAS,eAAA,CAAgB,IAAY,mBAAA,EAA2B;AACrE,EAAA,MAAA,GAAS,CAAA;AACX;AAOO,SAAS,qBAAqB,IAAA,EAAsB;AACzD,EAAA,OAAO,uBAAuB,IAAI,CAAA,CAAA;AACpC;AAIA,IAAM,gBAAA,uBAAuB,OAAA,EAA+C;AAKrE,SAAS,sBAAA,CAAuB,OAAyB,SAAA,EAA4B;AAC1F,EAAA,MAAM,IAAA,GAAO,MAAM,SAAS,CAAA;AAC5B,EAAA,IAAI,CAAC,MAAM,OAAO,KAAA;AAClB,EAAA,MAAM,EAAA,GAAK,qBAAqB,SAAS,CAAA;AACzC,EAAA,IAAI,IAAA,GAAO,gBAAA,CAAiB,GAAA,CAAI,KAAK,CAAA;AACrC,EAAA,IAAI,CAAC,IAAA,EAAM;AACT,IAAA,IAAA,uBAAW,GAAA,EAAI;AACf,IAAA,gBAAA,CAAiB,GAAA,CAAI,OAAO,IAAI,CAAA;AAAA,EAClC;AACA,EAAA,IAAI,CAAC,KAAA,CAAM,GAAA,CAAI,EAAE,CAAA,EAAG;AAClB,IAAA,KAAA,CAAM,QAAA,CAAS,EAAA,EAAI,SAAA,EAAW,SAAA,EAAW,KAAK,IAAI,CAAA;AAClD,IAAA,IAAA,CAAK,GAAA,CAAI,SAAA,EAAW,IAAA,CAAK,OAAO,CAAA;AAChC,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,SAAS,CAAA,IAAK,CAAA;AACpC,EAAA,IAAI,IAAA,IAAQ,IAAA,CAAK,OAAA,EAAS,OAAO,IAAA;AACjC,EAAA,KAAA,MAAW,KAAA,IAAS,KAAK,OAAA,EAAS;AAChC,IAAA,IAAI,KAAA,CAAM,OAAO,IAAA,EAAM;AACvB,IAAA,MAAM,QAAQ,IAAI,UAAA,CAAW,KAAA,CAAM,CAAA,GAAI,MAAM,CAAC,CAAA;AAC9C,IAAA,KAAA,IAAS,GAAA,GAAM,CAAA,EAAG,GAAA,GAAM,KAAA,CAAM,GAAG,GAAA,EAAA,EAAO;AACtC,MAAA,MAAM,GAAA,GAAA,CAAO,KAAA,CAAM,CAAA,GAAI,GAAA,IAAO,YAAY,KAAA,CAAM,CAAA;AAChD,MAAA,KAAA,CAAM,GAAA,CAAI,IAAA,CAAK,IAAA,CAAK,QAAA,CAAS,GAAA,EAAK,GAAA,GAAM,KAAA,CAAM,CAAC,CAAA,EAAG,GAAA,GAAM,KAAA,CAAM,CAAC,CAAA;AAAA,IACjE;AACA,IAAA,KAAA,CAAM,UAAA,CAAW,EAAA,EAAI,KAAA,CAAM,CAAA,EAAG,KAAA,CAAM,GAAG,KAAA,CAAM,CAAA,EAAG,KAAA,CAAM,CAAA,EAAG,KAAK,CAAA;AAAA,EAChE;AACA,EAAA,IAAA,CAAK,GAAA,CAAI,SAAA,EAAW,IAAA,CAAK,OAAO,CAAA;AAChC,EAAA,OAAO,IAAA;AACT;AAQO,SAAS,6BAA6B,CAAA,EAAiC;AAC5E,EAAA,UAAA,GAAa,CAAA;AACf;AAGO,SAAS,iBAAA,GAA4C;AAC1D,EAAA,OAAO,KAAA;AACT;AAGO,SAAS,0BAAA,GAAmC;AACjD,EAAA,cAAA,CAAe,KAAA,EAAM;AACrB,EAAA,oBAAA,CAAqB,KAAA,EAAM;AAC3B,EAAA,KAAA,uBAAY,GAAA,EAAI;AAChB,EAAA,KAAA,GAAQ,EAAC;AACT,EAAA,MAAA,GAAS,IAAI,WAAA,CAAY,SAAA,EAAW,SAAS,CAAA;AAC7C,EAAA,OAAA,GAAU,EAAC;AACX,EAAA,cAAA,GAAiB,KAAA;AACjB,EAAA,MAAA,GAAS,mBAAA;AACT,EAAA,2BAAA,EAA4B;AAC5B,EAAA,UAAA,GAAa,IAAA;AACf;;;ACtRO,IAAM,iBAAA,GAAoB,CAAA;;;AC1BjC,IAAM,iBAAA,GAAoB,EAAA;AAC1B,IAAM,kBAAA,GAAqB,EAAA;AAE3B,SAAS,KAAA,CAAM,MAAgB,MAAA,EAAwB;AACrD,EAAA,OAAO,MAAA,CAAO,YAAA;AAAA,IACZ,IAAA,CAAK,SAAS,MAAM,CAAA;AAAA,IAAG,IAAA,CAAK,QAAA,CAAS,MAAA,GAAS,CAAC,CAAA;AAAA,IAC/C,IAAA,CAAK,QAAA,CAAS,MAAA,GAAS,CAAC,CAAA;AAAA,IAAG,IAAA,CAAK,QAAA,CAAS,MAAA,GAAS,CAAC;AAAA,GACrD;AACF;AAGO,SAAS,iBAAiB,KAAA,EAA6B;AAC5D,EAAA,IAAI,KAAA,CAAM,UAAA,GAAa,CAAA,EAAG,OAAO,KAAA;AACjC,EAAA,OAAO,MAAM,IAAI,QAAA,CAAS,KAAK,CAAA,EAAG,CAAC,CAAA,KAAM,MAAA;AAC3C;AAGA,IAAM,eAAA,uBAA2C,GAAA,CAAI;AAAA,EACnD,SAAA;AAAA,EAAoB,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ;AAC9D,CAAC,CAAA;AAED,IAAM,qBAAA,GAAwB,EAAA;AAiBvB,SAAS,eAAe,KAAA,EAA6B;AAC1D,EAAA,IAAI,KAAA,CAAM,UAAA,GAAa,qBAAA,EAAuB,OAAO,KAAA;AACrD,EAAA,MAAM,IAAA,GAAO,IAAI,QAAA,CAAS,KAAK,CAAA;AAC/B,EAAA,IAAI,gBAAgB,GAAA,CAAI,KAAA,CAAM,MAAM,CAAC,CAAC,GAAG,OAAO,KAAA;AAChD,EAAA,MAAM,UAAA,GAAa,IAAA,CAAK,SAAA,CAAU,CAAC,CAAA;AACnC,EAAA,MAAM,SAAA,GAAY,IAAA,CAAK,SAAA,CAAU,CAAC,CAAA;AAClC,EAAA,MAAM,UAAA,GAAa,IAAA,CAAK,SAAA,CAAU,CAAC,CAAA;AACnC,EAAA,MAAM,SAAA,GAAY,IAAA,CAAK,SAAA,CAAU,EAAE,CAAA;AACnC,EAAA,OAAO,cAAc,qBAAA,IAChB,UAAA,GAAa,eAAe,SAAA,IAC5B,SAAA,GAAY,aAAa,KAAA,CAAM,UAAA;AACtC;AAIA,SAAS,kBAAA,CAAmB,MAAgB,SAAA,EAAkC;AAC5E,EAAA,MAAM,SAAA,GAAY,IAAA,CAAK,SAAA,CAAU,SAAA,GAAY,CAAC,CAAA;AAC9C,EAAA,MAAM,UAAyB,EAAC;AAChC,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,SAAA,EAAW,CAAA,EAAA,EAAK;AAClC,IAAA,MAAM,EAAA,GAAK,SAAA,GAAY,iBAAA,GAAoB,CAAA,GAAI,kBAAA;AAC/C,IAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,MACX,GAAA,EAAK,KAAA,CAAM,IAAA,EAAM,EAAE,CAAA;AAAA,MACnB,QAAA,EAAU,IAAA,CAAK,SAAA,CAAU,EAAA,GAAK,CAAC,CAAA;AAAA,MAC/B,MAAA,EAAQ,IAAA,CAAK,SAAA,CAAU,EAAA,GAAK,CAAC,CAAA;AAAA,MAC7B,MAAA,EAAQ,IAAA,CAAK,SAAA,CAAU,EAAA,GAAK,EAAE;AAAA,KAC/B,CAAA;AAAA,EACH;AACA,EAAA,OAAO,OAAA;AACT;AAaA,SAAS,gBAAA,CAAiB,MAAgB,OAAA,EAAgD;AACxF,EAAA,MAAM,OAAO,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,QAAQ,MAAM,CAAA;AACjD,EAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,EAAA,MAAM,OAAO,IAAA,CAAK,MAAA;AAClB,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,SAAA,CAAU,IAAA,GAAO,CAAC,CAAA;AACrC,EAAA,MAAM,YAAA,GAAe,IAAA,CAAK,SAAA,CAAU,IAAA,GAAO,CAAC,CAAA;AAC5C,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,EAAO,CAAA,EAAA,EAAK;AAC9B,IAAA,MAAM,GAAA,GAAM,IAAA,GAAO,CAAA,GAAI,CAAA,GAAI,EAAA;AAC3B,IAAA,IAAI,IAAA,CAAK,SAAA,CAAU,GAAA,GAAM,CAAC,MAAM,CAAA,EAAG;AACnC,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,SAAA,CAAU,GAAA,GAAM,CAAC,CAAA;AACrC,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,SAAA,CAAU,GAAA,GAAM,EAAE,CAAA;AACtC,IAAA,IAAI,GAAA,GAAM,EAAA;AACV,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,EAAQ,CAAA,EAAA,EAAK;AAC/B,MAAA,MAAM,OAAO,IAAA,CAAK,QAAA,CAAS,IAAA,GAAO,YAAA,GAAe,SAAS,CAAC,CAAA;AAC3D,MAAA,IAAI,IAAA,KAAS,CAAA,EAAG,GAAA,IAAO,MAAA,CAAO,aAAa,IAAI,CAAA;AAAA,IACjD;AACA,IAAA,IAAI,GAAA,CAAI,MAAA,GAAS,CAAA,EAAG,OAAO,GAAA;AAAA,EAC7B;AACA,EAAA,OAAO,IAAA;AACT;AAGA,SAAS,WAAA,CAAY,MAAA,EAAqB,IAAA,EAAgB,SAAA,EAAgC;AACxF,EAAA,MAAM,OAAA,GAAU,kBAAA,CAAmB,IAAA,EAAM,SAAS,CAAA;AAGlD,EAAA,MAAM,MAAA,GAAS,CAAC,CAAA,KAAuB,CAAA,GAAI,IAAK,EAAC;AACjD,EAAA,IAAI,KAAA,GAAQ,iBAAA,GAAoB,OAAA,CAAQ,MAAA,GAAS,kBAAA;AACjD,EAAA,KAAA,MAAW,CAAA,IAAK,OAAA,EAAS,KAAA,IAAS,MAAA,CAAO,EAAE,MAAM,CAAA;AAEjD,EAAA,MAAM,GAAA,GAAM,IAAI,WAAA,CAAY,KAAK,CAAA;AACjC,EAAA,MAAM,GAAA,GAAM,IAAI,QAAA,CAAS,GAAG,CAAA;AAC5B,EAAA,MAAM,QAAA,GAAW,IAAI,UAAA,CAAW,GAAG,CAAA;AACnC,EAAA,MAAM,QAAA,GAAW,IAAI,UAAA,CAAW,MAAM,CAAA;AAEtC,EAAA,GAAA,CAAI,SAAA,CAAU,CAAA,EAAG,IAAA,CAAK,SAAA,CAAU,SAAS,CAAC,CAAA;AAC1C,EAAA,GAAA,CAAI,SAAA,CAAU,CAAA,EAAG,OAAA,CAAQ,MAAM,CAAA;AAK/B,EAAA,MAAM,gBAAgB,IAAA,CAAK,KAAA,CAAM,KAAK,IAAA,CAAK,OAAA,CAAQ,MAAM,CAAC,CAAA;AAC1D,EAAA,MAAM,WAAA,GAAc,KAAK,aAAA,GAAgB,EAAA;AACzC,EAAA,GAAA,CAAI,SAAA,CAAU,GAAG,WAAW,CAAA;AAC5B,EAAA,GAAA,CAAI,SAAA,CAAU,GAAG,aAAa,CAAA;AAC9B,EAAA,GAAA,CAAI,SAAA,CAAU,EAAA,EAAI,OAAA,CAAQ,MAAA,GAAS,KAAK,WAAW,CAAA;AAEnD,EAAA,IAAI,MAAA,GAAS,iBAAA,GAAoB,OAAA,CAAQ,MAAA,GAAS,kBAAA;AAClD,EAAA,OAAA,CAAQ,OAAA,CAAQ,CAAC,CAAA,EAAG,CAAA,KAAM;AACxB,IAAA,MAAM,EAAA,GAAK,oBAAoB,CAAA,GAAI,kBAAA;AACnC,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA,EAAK,GAAA,CAAI,QAAA,CAAS,EAAA,GAAK,CAAA,EAAG,CAAA,CAAE,GAAA,CAAI,UAAA,CAAW,CAAC,CAAC,CAAA;AACpE,IAAA,GAAA,CAAI,SAAA,CAAU,EAAA,GAAK,CAAA,EAAG,CAAA,CAAE,QAAQ,CAAA;AAChC,IAAA,GAAA,CAAI,SAAA,CAAU,EAAA,GAAK,CAAA,EAAG,MAAM,CAAA;AAC5B,IAAA,GAAA,CAAI,SAAA,CAAU,EAAA,GAAK,EAAA,EAAI,CAAA,CAAE,MAAM,CAAA;AAC/B,IAAA,QAAA,CAAS,GAAA,CAAI,QAAA,CAAS,QAAA,CAAS,CAAA,CAAE,MAAA,EAAQ,EAAE,MAAA,GAAS,CAAA,CAAE,MAAM,CAAA,EAAG,MAAM,CAAA;AACrE,IAAA,MAAA,IAAU,MAAA,CAAO,EAAE,MAAM,CAAA;AAAA,EAC3B,CAAC,CAAA;AACD,EAAA,OAAO,GAAA;AACT;AAeO,SAAS,kBAAA,CACd,OACA,cAAA,EAC0C;AAC1C,EAAA,IAAI,cAAA,CAAe,KAAK,CAAA,EAAG;AACzB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KAEF;AAAA,EACF;AACA,EAAA,IAAI,CAAC,iBAAiB,KAAK,CAAA,SAAU,EAAE,KAAA,EAAO,SAAS,IAAA,EAAK;AAE5D,EAAA,MAAM,IAAA,GAAO,IAAI,QAAA,CAAS,KAAK,CAAA;AAC/B,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,SAAA,CAAU,CAAC,CAAA;AACjC,EAAA,IAAI,QAAA,KAAa,CAAA,EAAG,MAAM,IAAI,MAAM,mCAAmC,CAAA;AAEvE,EAAA,MAAM,UAAoB,EAAC;AAC3B,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,QAAA,EAAU,CAAA,EAAA,EAAK,OAAA,CAAQ,IAAA,CAAK,IAAA,CAAK,SAAA,CAAU,EAAA,GAAK,CAAA,GAAI,CAAC,CAAC,CAAA;AAE1E,EAAA,IAAI,cAAA,EAAgB;AAClB,IAAA,KAAA,MAAW,aAAa,OAAA,EAAS;AAC/B,MAAA,MAAM,OAAA,GAAU,kBAAA,CAAmB,IAAA,EAAM,SAAS,CAAA;AAClD,MAAA,IAAI,gBAAA,CAAiB,IAAA,EAAM,OAAO,CAAA,KAAM,cAAA,EAAgB;AACtD,QAAA,OAAO,EAAE,OAAO,WAAA,CAAY,KAAA,EAAO,MAAM,SAAS,CAAA,EAAG,SAAS,IAAA,EAAK;AAAA,MACrE;AAAA,IACF;AAAA,EACF;AACA,EAAA,OAAO,EAAE,KAAA,EAAO,WAAA,CAAY,KAAA,EAAO,IAAA,EAAM,OAAA,CAAQ,CAAC,CAAC,CAAA,EAAG,OAAA,EAAS,CAAC,cAAA,EAAe;AACjF;;;AC1MA,IAAI,aAAA,GAA0C,IAAA;AAG9C,SAAS,YAAA,GAAkC;AACzC,EAAA,aAAA,KAAkB,OAAO,aAAa,CAAA;AACtC,EAAA,OAAO,aAAA;AACT;AAaO,SAAS,SAAS,EAAA,EAAiC;AACxD,EAAA,MAAM,OAAA,GAAU,EAAA;AAChB,EAAA,OAAO,OAAA,CAAQ,OAAA,EAAS,KAAA,IAAS,EAAA,CAAG,KAAA;AACtC;AAWA,SAAS,QAAQ,IAAA,EAA+C;AAC9D,EAAA,MAAM,OAAO,IAAA,CAAK,UAAA;AAClB,EAAA,OAAO;AAAA,IACL,UAAA,EAAY,IAAA;AAAA,IACZ,QAAA,EAAU,KAAK,QAAA,GAAW,IAAA;AAAA,IAC1B,UAAU,EAAA,EAA2B;AACnC,MAAA,MAAM,QAAQ,IAAA,CAAK,gBAAA,CAAiB,MAAA,CAAO,aAAA,CAAc,EAAE,CAAC,CAAA;AAC5D,MAAA,IAAI,CAAC,OAAO,OAAO,IAAA;AACnB,MAAA,OAAA,CAAQ,KAAK,MAAA,CAAO,GAAA,CAAI,KAAK,CAAA,CAAE,gBAAgB,CAAA,IAAK,IAAA;AAAA,IACtD,CAAA;AAAA,IACA,MAAA,CAAO,MAAc,KAAA,EAAuB;AAC1C,MAAA,MAAM,IAAI,IAAA,CAAK,gBAAA,CAAiB,MAAA,CAAO,aAAA,CAAc,IAAI,CAAC,CAAA;AAC1D,MAAA,MAAM,IAAI,IAAA,CAAK,gBAAA,CAAiB,MAAA,CAAO,aAAA,CAAc,KAAK,CAAC,CAAA;AAC3D,MAAA,IAAI,CAAC,CAAA,IAAK,CAAC,CAAA,EAAG,OAAO,CAAA;AACrB,MAAA,OAAO,IAAA,CAAK,eAAA,CAAgB,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,EAAG,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,CAAC,CAAC,CAAA,GAAI,IAAA;AAAA,IACxE,CAAA;AAAA,IACA,OAAO,EAAA,EAA2B;AAChC,MAAA,MAAM,QAAQ,IAAA,CAAK,gBAAA,CAAiB,MAAA,CAAO,aAAA,CAAc,EAAE,CAAC,CAAA;AAC5D,MAAA,IAAI,CAAC,OAAO,OAAO,IAAA;AACnB,MAAA,MAAM,CAAA,GAAI,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,KAAK,CAAA,CAAE,OAAA,CAAQ,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA,CAAE,UAAA,CAAW,iBAAiB,CAAA;AAI9E,MAAA,OAAO,CAAA,CAAE,MAAA,GAAS,CAAA,GAAI,CAAA,GAAI,IAAA;AAAA,IAC5B;AAAA,GACF;AACF;AAOO,SAAS,qBAAqB,cAAA,EAAwC;AAC3E,EAAA,OAAO,OAAO,KAAA,KAA6C;AACzD,IAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,MAAM,YAAA,EAAc,CAAA;AAC3C,IAAA,MAAM,EAAE,KAAA,EAAO,MAAA,EAAO,GAAI,kBAAA,CAAmB,OAAO,cAAc,CAAA;AAClE,IAAA,OAAO,OAAA,CAAQ,KAAA,CAAM,MAAM,CAAC,CAAA;AAAA,EAC9B,CAAA;AACF;AAGO,IAAM,iBAAgC,oBAAA,EAAqB;;;ACPlE,IAAI,KAAA,uBAAY,GAAA,EAAsB;AAEtC,SAAS,OAAA,CAAQ,MAAA,EAAgB,MAAA,EAAgB,KAAA,EAAiC;AAChF,EAAA,OAAO,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,MAAM,IAAI,KAAK,CAAA,CAAA;AACrC;AAEA,SAAS,UAAU,CAAA,EAAgE;AACjF,EAAA,OAAO,EAAE,QAAQ,CAAA,CAAE,MAAA,IAAU,KAAK,KAAA,EAAO,CAAA,CAAE,SAAS,QAAA,EAAS;AAC/D;AAgBO,SAAS,qBACd,MAAA,EACA,OAAA,EACA,MAAA,EACA,IAAA,GAA2B,EAAC,EACtB;AACN,EAAA,MAAM,EAAE,MAAA,EAAQ,KAAA,EAAM,GAAI,UAAU,OAAO,CAAA;AAC3C,EAAA,KAAA,CAAM,GAAA,CAAI,OAAA,CAAQ,MAAA,EAAQ,MAAA,EAAQ,KAAK,CAAA,EAAG;AAAA,IACxC,MAAA;AAAA,IAAQ,MAAA;AAAA,IAAQ,KAAA;AAAA,IAAO,MAAA;AAAA,IACvB,MAAA,EAAQ,KAAK,MAAA,IAAU,cAAA;AAAA,IACvB,MAAA,EAAQ,MAAA;AAAA,IACR,IAAA,EAAM,IAAA;AAAA,IACN,MAAA,sBAAY,GAAA;AAAI,GACjB,CAAA;AACH;AAIO,SAAS,sBAAA,CAAuB,MAAA,EAAgB,OAAA,GAA0B,EAAC,EAAS;AACzF,EAAA,MAAM,EAAE,MAAA,EAAQ,KAAA,EAAM,GAAI,UAAU,OAAO,CAAA;AAC3C,EAAA,KAAA,CAAM,MAAA,CAAO,OAAA,CAAQ,MAAA,EAAQ,MAAA,EAAQ,KAAK,CAAC,CAAA;AAC7C;AAQO,SAAS,eAAA,CACd,MAAA,EAAgB,MAAA,GAAS,GAAA,EAAK,QAA0B,QAAA,EAC/C;AACT,EAAA,OAAO,MAAM,GAAA,CAAI,OAAA,CAAQ,MAAA,EAAQ,MAAA,EAAQ,KAAK,CAAC,CAAA;AACjD;AAGO,SAAS,aAAA,CACd,MAAA,EAAgB,MAAA,GAAS,GAAA,EAAK,QAA0B,QAAA,EAClC;AACtB,EAAA,OAAO,KAAA,CAAM,IAAI,OAAA,CAAQ,MAAA,EAAQ,QAAQ,KAAK,CAAC,GAAG,MAAA,IAAU,IAAA;AAC9D;AAIO,SAAS,gBAAA,GAEZ;AACF,EAAA,OAAO,CAAC,GAAG,KAAA,CAAM,QAAQ,CAAA,CACtB,IAAI,CAAC,EAAE,MAAA,EAAQ,MAAA,EAAQ,OAAO,MAAA,EAAO,MAAO,EAAE,MAAA,EAAQ,MAAA,EAAQ,OAAO,MAAA,EAAO,CAAE,CAAA,CAC9E,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,EAAE,MAAA,CAAO,aAAA,CAAc,EAAE,MAAM,CAAA,IAAK,CAAA,CAAE,MAAA,GAAS,EAAE,MAAA,IAC5D,CAAA,CAAE,MAAM,aAAA,CAAc,CAAA,CAAE,KAAK,CAAC,CAAA;AACvC;AA6BO,SAAS,cAAc,CAAA,EAAmB;AAC/C,EAAA,IAAI,GAAA,GAAM,EAAA;AACV,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,CAAE,QAAQ,CAAA,EAAA,EAAK;AACjC,IAAA,MAAM,CAAA,GAAI,EAAE,CAAC,CAAA;AACb,IAAA,IAAI,CAAA,KAAM,GAAA,IAAO,CAAA,KAAM,GAAA,EAAK;AAC5B,IAAA,GAAA,IAAO,QAAA,CAAS,CAAA,CAAE,KAAA,CAAM,KAAA,EAAO,CAAC,CAAC,CAAA;AACjC,IAAA,KAAA,GAAQ,CAAA;AAAA,EACV;AACA,EAAA,OAAO,GAAA,GAAM,QAAA,CAAS,CAAA,CAAE,KAAA,CAAM,KAAK,CAAC,CAAA;AACtC;AAEA,SAAS,SAAS,OAAA,EAAyB;AACzC,EAAA,MAAM,OAAA,GAAU,QAAQ,OAAA,EAAQ;AAChC,EAAA,IAAI,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG,OAAO,EAAA;AACjC,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,OAAA,CAAQ,MAAA,GAAS,CAAC,CAAA;AACvC,EAAA,OAAO,SAAS,GAAA,IAAO,IAAA,KAAS,GAAA,GAAM,OAAA,GAAU,GAAG,OAAO,CAAA,CAAA,CAAA;AAC5D;AAWO,SAAS,YAAA,CACd,MAAA,EACA,MAAA,EACA,KAAA,EACA,EAAA,EACe;AACf,EAAA,MAAM,OAAO,KAAA,CAAM,GAAA,CAAI,QAAQ,MAAA,EAAQ,MAAA,EAAQ,KAAK,CAAC,CAAA;AACrD,EAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,EAAA,IAAI,IAAA,CAAK,WAAW,MAAA,EAAQ;AAC1B,IAAA,KAAK,UAAU,IAAI,CAAA;AACnB,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAI,IAAA,CAAK,MAAA,KAAW,OAAA,EAAS,OAAO,IAAA;AAEpC,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,EAAE,CAAA;AACjC,EAAA,IAAI,MAAA,KAAW,QAAW,OAAO,MAAA;AACjC,EAAA,IAAI,CAAA,GAAmB,IAAA;AACvB,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,IAAA,CAAM,MAAA,CAAO,EAAE,CAAA;AAChC,IAAA,CAAA,GAAI,GAAA,KAAQ,IAAA,GAAO,IAAA,GAAO,aAAA,CAAc,GAAG,CAAA;AAAA,EAC7C,SAAS,GAAA,EAAK;AAEZ,IAAA,QAAA;AAAA,MAAS,CAAA,MAAA,EAAS,OAAA,CAAQ,MAAA,EAAQ,MAAA,EAAQ,KAAK,CAAC,CAAA,CAAA;AAAA,MAC9C,CAAA,sBAAA,EAAyB,MAAM,CAAA,GAAA,EAAM,MAAM,CAAA,CAAA,EAAI,KAAK,CAAA,kCAAA,EAC3C,EAAA,CAAG,QAAA,CAAS,EAAE,CAAA,CAAE,WAAA,GAAc,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,QAAA,EACpD,GAAA,YAAe,QAAQ,GAAA,CAAI,OAAA,GAAU,MAAA,CAAO,GAAG,CAAC,CAAA,+BAAA;AAAA,KAAiC;AAAA,EACxF;AACA,EAAA,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,EAAA,EAAI,CAAC,CAAA;AACrB,EAAA,OAAO,CAAA;AACT;AAgBO,SAAS,cAAA,CACd,MAAA,EACA,MAAA,EACA,KAAA,EACoB;AACpB,EAAA,MAAM,OAAO,KAAA,CAAM,GAAA,CAAI,QAAQ,MAAA,EAAQ,MAAA,EAAQ,KAAK,CAAC,CAAA;AACrD,EAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,EAAA,IAAI,IAAA,CAAK,WAAW,MAAA,EAAQ;AAC1B,IAAA,KAAK,UAAU,IAAI,CAAA;AACnB,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,IAAA,CAAK,MAAA,KAAW,OAAA,GAAU,IAAA,CAAK,IAAA,GAAQ,IAAA;AAChD;AAEA,eAAe,UAAU,IAAA,EAA+B;AACtD,EAAA,IAAA,CAAK,MAAA,GAAS,SAAA;AACd,EAAA,IAAI;AACF,IAAA,IAAA,CAAK,IAAA,GAAO,MAAM,IAAA,CAAK,MAAA,CAAO,MAAM,UAAA,CAAW,IAAA,CAAK,MAAM,CAAC,CAAA;AAC3D,IAAA,IAAA,CAAK,MAAA,GAAS,OAAA;AAId,IAAA,gBAAA,EAAiB;AAAA,EACnB,SAAS,GAAA,EAAK;AACZ,IAAA,IAAA,CAAK,MAAA,GAAS,QAAA;AACd,IAAA,QAAA;AAAA,MAAS,CAAA,KAAA,EAAQ,QAAQ,IAAA,CAAK,MAAA,EAAQ,KAAK,MAAA,EAAQ,IAAA,CAAK,KAAK,CAAC,CAAA,CAAA;AAAA,MAC5D,gCAAgC,IAAA,CAAK,MAAM,CAAA,EAAA,EAAK,IAAA,CAAK,MAAM,CAAA,CAAA,EAAI,IAAA,CAAK,KAAK,CAAA,GAAA,EACtE,eAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,MAAA,CAAO,GAAG,CAAC,CAAA,4DAAA;AAAA,KACf;AAAA,EACxC;AACF;AAEA,eAAe,WAAW,MAAA,EAA6C;AACrE,EAAA,MAAM,WAAW,OAAO,MAAA,KAAW,UAAA,GAAa,MAAM,QAAO,GAAI,MAAA;AACjE,EAAA,IAAI,OAAO,aAAa,QAAA,EAAU;AAChC,IAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,QAAQ,CAAA;AAChC,IAAA,IAAI,CAAC,GAAA,CAAI,EAAA,EAAI,MAAM,IAAI,KAAA,CAAM,CAAA,KAAA,EAAQ,GAAA,CAAI,MAAM,CAAA,UAAA,EAAa,QAAQ,CAAA,CAAE,CAAA;AACtE,IAAA,OAAO,IAAI,WAAA,EAAY;AAAA,EACzB;AACA,EAAA,IAAI,QAAA,YAAoB,aAAa,OAAO,QAAA;AAC5C,EAAA,OAAO,SAAS,WAAA,EAAY;AAC9B;AAIA,IAAM,MAAA,uBAAa,GAAA,EAAY;AAE/B,SAAS,QAAA,CAAS,KAAa,OAAA,EAAuB;AACpD,EAAA,IAAI,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA,EAAG;AACrB,EAAA,MAAA,CAAO,IAAI,GAAG,CAAA;AACd,EAAA,OAAA,CAAQ,KAAK,OAAO,CAAA;AACtB;AAGO,SAAS,0BAAA,GAAmC;AACjD,EAAA,KAAA,uBAAY,GAAA,EAAI;AAChB,EAAA,MAAA,CAAO,KAAA,EAAM;AACf;;;ACxSA,IAAI,QAAA,uBAAe,GAAA,EAAoC;AAEvD,SAAS,UAAA,CAAW,QAAgB,KAAA,EAA0B;AAC5D,EAAA,OAAO,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA;AAC3B;AAEA,SAAS,iBAAiB,CAAA,EAAsD;AAC9E,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,EAAE,MAAA,IAAU,GAAA;AAAA,IACpB,KAAA,EAAO,EAAE,KAAA,IAAS;AAAA,GACpB;AACF;AAGO,SAAS,0BAAA,GAAmC;AACjD,EAAA,QAAA,uBAAe,GAAA,EAAI;AACnB,EAAA,sBAAA,EAAuB;AACzB;AAGO,SAAS,OAAA,CACd,MAAA,EACA,MAAA,GAAiB,GAAA,EACjB,QAAmB,QAAA,EACD;AAClB,EAAA,OAAO,QAAA,CAAS,IAAI,MAAM,CAAA,EAAG,IAAI,UAAA,CAAW,MAAA,EAAQ,KAAK,CAAC,CAAA,IAAK,IAAA;AACjE;AAcO,SAAS,SAAA,GAAuC;AACrD,EAAA,MAAM,MAAwB,EAAC;AAC/B,EAAA,KAAA,MAAW,CAAC,MAAA,EAAQ,UAAU,CAAA,IAAK,QAAA,EAAU;AAC3C,IAAA,MAAM,QAAA,GAAW,CAAC,GAAG,UAAA,CAAW,MAAM,CAAA,CACnC,GAAA,CAAI,CAAC,GAAA,KAAQ;AACZ,MAAA,MAAM,CAAC,CAAA,EAAG,CAAC,CAAA,GAAI,GAAA,CAAI,MAAM,GAAG,CAAA;AAC5B,MAAA,OAAO,EAAE,MAAA,EAAQ,MAAA,CAAO,CAAC,CAAA,EAAG,OAAO,CAAA,EAAE;AAAA,IACvC,CAAC,CAAA,CACA,IAAA,CAAK,CAAC,GAAG,CAAA,KAAM,CAAA,CAAE,MAAA,GAAS,CAAA,CAAE,UAAU,CAAA,CAAE,KAAA,CAAM,aAAA,CAAc,CAAA,CAAE,KAAK,CAAC,CAAA;AACvE,IAAA,GAAA,CAAI,IAAA,CAAK,EAAE,MAAA,EAAQ,QAAA,EAAU,CAAA;AAAA,EAC/B;AACA,EAAA,OAAO,GAAA;AACT;AAOA,eAAsB,YAAA,CACpB,MAAA,EACA,OAAA,EACA,UAAA,EACA,QAAA,EACe;AACf,EAAA,MAAM,EAAE,MAAA,EAAQ,KAAA,EAAM,GAAI,iBAAiB,OAAO,CAAA;AAClD,EAAA,MAAM,GAAA,GAAM,UAAA,CAAW,MAAA,EAAQ,KAAK,CAAA;AAEpC,EAAA,IAAI,SAAS,GAAA,CAAI,MAAM,CAAA,EAAG,GAAA,CAAI,GAAG,CAAA,EAAG;AAEpC,EAAA,IAAI;AACF,IAAA,MAAM,CAAC,UAAA,EAAY,QAAQ,CAAA,GAAI,MAAM,QAAQ,GAAA,CAAI;AAAA,MAC/C,MAAM,UAAU,CAAA;AAAA,MAChB,MAAM,QAAQ;AAAA,KACf,CAAA;AAED,IAAA,IAAI,CAAC,WAAW,EAAA,EAAI;AAClB,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,KAAA,EAAQ,WAAW,MAAM,CAAA,uBAAA,EAA0B,UAAU,CAAA,CAAE,CAAA;AAAA,IACjF;AACA,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,KAAA,EAAQ,SAAS,MAAM,CAAA,qBAAA,EAAwB,QAAQ,CAAA,CAAE,CAAA;AAAA,IAC3E;AAEA,IAAA,MAAM,CAAC,OAAA,EAAS,IAAI,CAAA,GAAI,MAAM,QAAQ,GAAA,CAAI;AAAA,MACxC,WAAW,IAAA,EAAK;AAAA,MAChB,SAAS,IAAA;AAAK,KACf,CAAA;AAED,IAAA,MAAM,IAAA,GAAO,YAAY,OAAO,CAAA;AAChC,IAAA,MAAM,MAAA,GAAS,MAAM,iBAAA,CAAkB,IAAI,CAAA;AAQ3C,IAAA,IAAI,SAAA,GAAY,QAAA,CAAS,GAAA,CAAI,MAAM,CAAA;AACnC,IAAA,IAAI,CAAC,SAAA,EAAW;AACd,MAAA,SAAA,uBAAgB,GAAA,EAAI;AACpB,MAAA,QAAA,CAAS,GAAA,CAAI,QAAQ,SAAS,CAAA;AAAA,IAChC;AACA,IAAA,SAAA,CAAU,GAAA,CAAI,GAAA,EAAK,EAAE,IAAA,EAAM,QAAQ,CAAA;AAKnC,IAAA,gBAAA,EAAiB;AAAA,EACnB,SAAS,GAAA,EAAK;AACZ,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,qBAAA,EAAwB,MAAM,CAAA,EAAA,EAAK,MAAM,CAAA,CAAA,EAAI,KAAK,CAAA,GAAA,EAAM,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,MAAA,CAAO,GAAG,CAAC,CAAA;AAAA,KAC1G;AAAA,EACF;AACF;AAOO,SAAS,iBAAA,CACd,MAAA,EACA,MAAA,EACA,KAAA,EACA,YAAA,EACS;AACT,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,MAAA,EAAQ,MAAA,EAAQ,KAAK,CAAA;AAC3C,EAAA,IAAI,CAAC,OAAO,OAAO,KAAA;AACnB,EAAA,YAAA,CAAa,OAAO,eAAA,CAAgB,MAAA,EAAQ,QAAQ,KAAK,CAAA,EAAG,MAAM,MAAM,CAAA;AACxE,EAAA,OAAO,IAAA;AACT;AAGO,SAAS,eAAA,CAAgB,MAAA,EAAgB,MAAA,EAAgB,KAAA,EAA0B;AACxF,EAAA,OAAO,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,MAAM,IAAI,KAAK,CAAA,CAAA;AACrC;AAGO,SAAS,uBAAA,GAAgC;AAAC;AA2CjD,SAAS,iBAAA,CACP,MAAA,EAAgB,MAAA,EAAgB,KAAA,EAAkB,eAAe,KAAA,EAClD;AASf,EAAA,IAAI,oBAAA,CAAqB,MAAM,CAAA,EAAG;AAChC,IAAA,OAAO;AAAA,MACL,KAAA,EAAO,IAAA;AAAA,MACP,WAAA,EAAa,cAAA,CAAe,MAAA,EAAQ,MAAA,EAAQ,KAAK,CAAA;AAAA,MACjD,QAAA,EAAU,EAAE,MAAA,EAAQ,MAAA,EAAQ,KAAA,EAAM;AAAA,MAClC,SAAA,EAAW,EAAE,IAAA,EAAM,KAAA,EAAO,QAAQ,KAAA,EAAM;AAAA,MACxC,MAAA,EAAQ;AAAA,KACV;AAAA,EACF;AAOA,EAAA,MAAM,OAAO,cAAA,CAAe,MAAA,EAAQ,QAAQ,KAAA,KAAU,QAAA,GAAW,WAAW,QAAQ,CAAA;AACpF,EAAA,IAAI,IAAA,EAAM;AACR,IAAA,OAAO;AAAA,MACL,KAAA,EAAO,IAAA;AAAA,MACP,WAAA,EAAa,IAAA;AAAA,MACb,QAAA,EAAU,EAAE,MAAA,EAAQ,MAAA,EAAQ,KAAA,EAAM;AAAA,MAClC,SAAA,EAAW,EAAE,IAAA,EAAM,KAAA,EAAO,QAAQ,KAAA,EAAM;AAAA,MACxC,MAAA,EAAQ;AAAA,KACV;AAAA,EACF;AAEA,EAAA,MAAMA,UAAS,qBAAA,EAAsB;AAErC,EAAA,IAAIA,YAAW,QAAA,EAAU;AAGvB,IAAA,oBAAA,CAAqB,MAAM,CAAA;AAC3B,IAAA,OAAO;AAAA,MACL,KAAA,EAAO,IAAA;AAAA,MACP,WAAA,EAAa,cAAA,CAAe,MAAA,EAAQ,MAAA,EAAQ,KAAK,CAAA;AAAA,MACjD,QAAA,EAAU,EAAE,MAAA,EAAQ,MAAA,EAAQ,KAAA,EAAM;AAAA,MAClC,SAAA,EAAW,EAAE,IAAA,EAAM,KAAA,EAAO,QAAQ,KAAA,EAAM;AAAA,MACxC,MAAA,EAAQ;AAAA,KACV;AAAA,EACF;AAEA,EAAA,IAAIA,YAAW,YAAA,EAAc;AAC3B,IAAA,MAAM,QAAA,GAAW,oBAAA,EAAqB,IAAK,qBAAA,EAAsB;AAOjE,IAAA,IAAI,QAAA,KAAa,IAAA,IAAQ,QAAA,KAAa,MAAA,EAAQ;AAC5C,MAAA,IAAI,SAAS,GAAA,CAAI,QAAQ,CAAA,IAAK,YAAA,CAAa,QAAQ,CAAA,EAAG;AAOpD,QAAA,MAAM,MAAA,GAAS,0BAAA,CAA2B,QAAA,EAAU,MAAA,EAAQ,OAAO,IAAI,CAAA;AAGvE,QAAA,IAAI,MAAA,CAAO,KAAA,KAAU,IAAA,IAAQ,MAAA,CAAO,gBAAgB,MAAA,EAAW;AAC7D,UAAA,IAAI,CAAC,YAAA,EAAc,qBAAA,CAAsB,MAAA,EAAQ,MAAA,EAAQ,OAAO,QAAQ,CAAA;AACxE,UAAA,OAAO,EAAE,GAAG,MAAA,EAAQ,WAAA,EAAa,EAAE,SAAA,EAAW,MAAA,EAAQ,QAAA,EAAU,QAAA,EAAS,EAAE;AAAA,QAC7E;AAAA,MACF;AAIA,MAAA,IAAI,CAAC,YAAA,EAAc,uBAAA,CAAwB,MAAA,EAAQ,MAAA,EAAQ,OAAO,QAAQ,CAAA;AAAA,IAC5E,CAAA,MAAA,IAAW,QAAA,KAAa,MAAA,IAAU,CAAC,YAAA,EAAc;AAW/C,MAAA,IAAI,QAAA,CAAS,GAAA,CAAI,MAAM,CAAA,EAAG;AACxB,QAAA,2BAAA,CAA4B,MAAA,EAAQ,QAAQ,KAAK,CAAA;AAAA,MACnD,CAAA,MAAO;AAQL,QAAA,2BAAA,CAA4B,MAAA,EAAQ,QAAQ,KAAK,CAAA;AAAA,MACnD;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,IAAA;AAAA,IACP,QAAA,EAAU,EAAE,MAAA,EAAQ,MAAA,EAAQ,KAAA,EAAM;AAAA,IAClC,SAAA,EAAW,EAAE,IAAA,EAAM,KAAA,EAAO,QAAQ,KAAA,EAAM;AAAA,IACxC,MAAA,EAAQ;AAAA,GACV;AACF;AAGA,SAAS,qBAAA,GAAuC;AAC9C,EAAA,KAAA,MAAW,MAAA,IAAU,QAAA,CAAS,IAAA,EAAK,EAAG,OAAO,MAAA;AAC7C,EAAA,OAAO,IAAA;AACT;AAMA,SAAS,qBAAA,CACP,MAAA,EAAgB,MAAA,EAAgB,KAAA,EAAkB,QAAA,EAC5C;AACN,EAAA,IAAI,CAAC,qBAAqB,CAAA,YAAA,EAAe,MAAM,IAAI,MAAM,CAAA,CAAA,EAAI,KAAK,CAAA,CAAE,CAAA,EAAG;AAKvE,EAAA,MAAM,KAAA,GAAQ,SAAS,GAAA,CAAI,MAAM,IAC7B,CAAA,wBAAA,EAA2B,MAAM,IAAI,KAAK,CAAA,wHAAA,EAEvB,QAAQ,CAAA,gDAAA,EACV,MAAM,gBAAgB,MAAM,CAAA,UAAA,EAAa,KAAK,CAAA,YAAA,CAAA,GAC/D,CAAA,yCAAA,EAAuC,QAAQ,CAAA,8BAAA,EACzB,MAAM,CAAA,UAAA,CAAA;AAChC,EAAA,OAAA,CAAQ,IAAA;AAAA,IACN,wBAAwB,MAAM,CAAA,GAAA,EAAM,MAAM,CAAA,CAAA,EAAI,KAAK,KAAK,KAAK,CAAA,yHAAA;AAAA,GAG/D;AACF;AAQA,SAAS,uBAAA,CACP,MAAA,EAAgB,MAAA,EAAgB,KAAA,EAAkB,QAAA,EAC5C;AACN,EAAA,IAAI,CAAC,qBAAqB,CAAA,iBAAA,EAAoB,MAAM,IAAI,MAAM,CAAA,CAAA,EAAI,KAAK,CAAA,CAAE,CAAA,EAAG;AAC5E,EAAA,MAAM,MAAA,GAAS,oBAAA,EAAqB,KAAM,QAAA,GACtC,8BAAA,GACA,0EAAA;AAKJ,EAAA,MAAM,GAAA,GAAM,QAAA,CAAS,GAAA,CAAI,QAAQ,CAAA,IAAK,YAAA,CAAa,QAAQ,CAAA,GACvD,CAAA,8BAAA,EAAiC,MAAM,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,GAChD,0BAAA;AACJ,EAAA,OAAA,CAAQ,IAAA;AAAA,IACN,wBAAwB,MAAM,CAAA,GAAA,EAAM,MAAM,CAAA,CAAA,EAAI,KAAK,CAAA,6CAAA,EAC3B,QAAQ,CAAA,GAAA,EAAM,MAAM,KAAK,GAAG,CAAA,+EAAA,EACG,QAAQ,CAAA,aAAA,EAClD,MAAM,aAAa,KAAK,CAAA,yEAAA;AAAA,GAEvC;AACF;AAWA,SAAS,2BAAA,CACP,MAAA,EAAgB,MAAA,EAAgB,KAAA,EAC1B;AACN,EAAA,IAAI,CAAC,qBAAqB,CAAA,sBAAA,EAAyB,MAAM,IAAI,MAAM,CAAA,CAAA,EAAI,KAAK,CAAA,CAAE,CAAA,EAAG;AACjF,EAAA,MAAM,MAAA,GAAS,oBAAA,EAAqB,KAAM,MAAA,GACtC,8BAAA,GACA,0EAAA;AACJ,EAAA,OAAA,CAAQ,IAAA;AAAA,IACN,CAAA,qBAAA,EAAwB,MAAM,CAAA,GAAA,EAAM,MAAM,IAAI,KAAK,CAAA,mDAAA,EACvB,MAAM,CAAA,+BAAA,EAAkC,MAAM,CAAA,0HAAA,EAElC,MAAM,CAAA,aAAA,EAAgB,MAAM,aACzD,KAAK,CAAA,oEAAA;AAAA,GAClB;AACF;AAWA,SAAS,2BAAA,CACP,MAAA,EAAgB,MAAA,EAAgB,KAAA,EAC1B;AACN,EAAA,IAAI,CAAC,qBAAqB,CAAA,qBAAA,EAAwB,MAAM,IAAI,MAAM,CAAA,CAAA,EAAI,KAAK,CAAA,CAAE,CAAA,EAAG;AAChF,EAAA,OAAA,CAAQ,IAAA;AAAA,IACN,CAAA,qBAAA,EAAwB,MAAM,CAAA,GAAA,EAAM,MAAM,CAAA,CAAA,EAAI,KAAK,CAAA,wFAAA,EACO,MAAM,CAAA,wJAAA,EAEI,MAAM,CAAA,aAAA,EAC7D,MAAM,aAAa,KAAK,CAAA,8EAAA;AAAA,GAEvC;AACF;AAEA,SAAS,aAAa,CAAA,EAA+B;AACnD,EAAA,OAAO,CAAA,IAAK,MAAM,MAAA,GAAS,SAAA;AAC7B;AAQO,SAAS,kBAAA,CACd,MAAA,EACA,MAAA,EACA,KAAA,EACe;AACf,EAAA,OAAO,0BAAA,CAA2B,MAAA,EAAQ,MAAA,EAAQ,KAAA,EAAO,KAAK,CAAA;AAChE;AAwBO,SAAS,oBAAA,CACd,MAAA,EACA,MAAA,EACA,KAAA,EACsB;AACtB,EAAA,IAAI,qBAAA,EAAsB,KAAM,MAAA,EAAQ,OAAO,IAAA;AAC/C,EAAA,IAAI;AACF,IAAA,OAAO;AAAA,MACL,KAAA,EAAO,IAAA;AAAA,MACP,WAAA,EAAa,cAAA,CAAe,MAAA,EAAQ,MAAA,EAAQ,KAAK,CAAA;AAAA,MACjD,QAAA,EAAU,EAAE,MAAA,EAAQ,MAAA,EAAQ,KAAA,EAAM;AAAA;AAAA;AAAA,MAGlC,SAAA,EAAW,EAAE,IAAA,EAAM,KAAA,EAAO,QAAQ,KAAA,EAAM;AAAA,MACxC,MAAA,EAAQ;AAAA,KACV;AAAA,EACF,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAWA,SAAS,0BAAA,CACP,MAAA,EACA,MAAA,EACA,KAAA,EACA,YAAA,EACe;AACf,EAAA,MAAM,SAAA,GAAY,QAAA,CAAS,GAAA,CAAI,MAAM,CAAA;AACrC,EAAA,IAAI,CAAC,SAAA,IAAa,SAAA,CAAU,IAAA,KAAS,CAAA,EAAG;AACtC,IAAA,OAAO,iBAAA,CAAkB,MAAA,EAAQ,MAAA,EAAQ,KAAA,EAAO,YAAY,CAAA;AAAA,EAC9D;AAGA,EAAA,MAAM,QAAQ,SAAA,CAAU,GAAA,CAAI,UAAA,CAAW,MAAA,EAAQ,KAAK,CAAC,CAAA;AACrD,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,OAAO;AAAA,MACL,KAAA,EAAO,KAAA;AAAA,MACP,QAAA,EAAU,EAAE,MAAA,EAAQ,MAAA,EAAQ,KAAA,EAAM;AAAA,MAClC,SAAA,EAAW,EAAE,IAAA,EAAM,KAAA,EAAO,QAAQ,KAAA,EAAM;AAAA,MACxC,MAAA,EAAQ;AAAA,KACV;AAAA,EACF;AAGA,EAAA,MAAM,eAAA,GAAkB,aAAa,MAAM,CAAA;AAC3C,EAAA,IAAI,aAAA,GAA+E,IAAA;AACnF,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,CAAA,IAAK,SAAA,EAAW;AACpC,IAAA,MAAM,CAAC,IAAA,EAAM,CAAC,CAAA,GAAI,GAAA,CAAI,MAAM,GAAG,CAAA;AAC/B,IAAA,MAAM,CAAA,GAAI,OAAO,IAAI,CAAA;AACrB,IAAA,IAAI,MAAM,KAAA,EAAO;AACjB,IAAA,IAAI,YAAA,CAAa,CAAC,CAAA,KAAM,eAAA,EAAiB;AACzC,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,CAAA,GAAI,MAAM,CAAA;AACpC,IAAA,IACE,aAAA,KAAkB,IAAA,IAClB,QAAA,GAAW,aAAA,CAAc,QAAA,IACxB,aAAa,aAAA,CAAc,QAAA,IAAY,CAAA,GAAI,aAAA,CAAc,MAAA,EAC1D;AACA,MAAA,aAAA,GAAgB,EAAE,KAAA,EAAO,MAAA,EAAQ,CAAA,EAAG,QAAA,EAAS;AAAA,IAC/C;AAAA,EACF;AACA,EAAA,IAAI,aAAA,EAAe;AACjB,IAAA,OAAO;AAAA,MACL,OAAO,aAAA,CAAc,KAAA;AAAA,MACrB,UAAU,EAAE,MAAA,EAAQ,MAAA,EAAQ,aAAA,CAAc,QAAQ,KAAA,EAAM;AAAA,MACxD,SAAA,EAAW,EAAE,IAAA,EAAM,KAAA,EAAO,QAAQ,KAAA,EAAM;AAAA,MACxC,MAAA,EAAQ;AAAA,KACV;AAAA,EACF;AAGA,EAAA,MAAM,mBAAmB,SAAA,CAAU,GAAA,CAAI,UAAA,CAAW,GAAA,EAAK,KAAK,CAAC,CAAA;AAC7D,EAAA,IAAI,gBAAA,EAAkB;AACpB,IAAA,OAAO;AAAA,MACL,KAAA,EAAO,gBAAA;AAAA,MACP,QAAA,EAAU,EAAE,MAAA,EAAQ,MAAA,EAAQ,KAAK,KAAA,EAAM;AAAA,MACvC,SAAA,EAAW;AAAA,QACT,MAAM,MAAA,IAAU,GAAA;AAAA,QAChB,MAAA,EAAQ;AAAA,OACV;AAAA,MACA,MAAA,EAAQ;AAAA,KACV;AAAA,EACF;AAGA,EAAA,MAAM,mBAAmB,SAAA,CAAU,GAAA,CAAI,UAAA,CAAW,MAAA,EAAQ,QAAQ,CAAC,CAAA;AACnE,EAAA,IAAI,gBAAA,EAAkB;AACpB,IAAA,OAAO;AAAA,MACL,KAAA,EAAO,gBAAA;AAAA,MACP,QAAA,EAAU,EAAE,MAAA,EAAQ,MAAA,EAAQ,OAAO,QAAA,EAAS;AAAA,MAC5C,SAAA,EAAW;AAAA,QACT,IAAA,EAAM,KAAA;AAAA,QACN,QAAQ,KAAA,KAAU;AAAA,OACpB;AAAA,MACA,MAAA,EAAQ;AAAA,KACV;AAAA,EACF;AAGA,EAAA,IAAI,UAAA,GAA4E,IAAA;AAChF,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,CAAA,IAAK,SAAA,EAAW;AACpC,IAAA,MAAM,CAAC,IAAA,EAAM,CAAC,CAAA,GAAI,GAAA,CAAI,MAAM,GAAG,CAAA;AAC/B,IAAA,MAAM,CAAA,GAAI,OAAO,IAAI,CAAA;AACrB,IAAA,IAAI,MAAM,QAAA,EAAU;AACpB,IAAA,IAAI,YAAA,CAAa,CAAC,CAAA,KAAM,eAAA,EAAiB;AACzC,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,CAAA,GAAI,MAAM,CAAA;AACpC,IAAA,IACE,UAAA,KAAe,IAAA,IACf,QAAA,GAAW,UAAA,CAAW,QAAA,IACrB,aAAa,UAAA,CAAW,QAAA,IAAY,CAAA,GAAI,UAAA,CAAW,MAAA,EACpD;AACA,MAAA,UAAA,GAAa,EAAE,KAAA,EAAO,MAAA,EAAQ,CAAA,EAAG,QAAA,EAAS;AAAA,IAC5C;AAAA,EACF;AACA,EAAA,IAAI,UAAA,EAAY;AACd,IAAA,OAAO;AAAA,MACL,OAAO,UAAA,CAAW,KAAA;AAAA,MAClB,UAAU,EAAE,MAAA,EAAQ,QAAQ,UAAA,CAAW,MAAA,EAAQ,OAAO,QAAA,EAAS;AAAA,MAC/D,SAAA,EAAW;AAAA,QACT,IAAA,EAAM,KAAA;AAAA,QACN,QAAQ,KAAA,KAAU;AAAA,OACpB;AAAA,MACA,MAAA,EAAQ;AAAA,KACV;AAAA,EACF;AAGA,EAAA,MAAM,UAAU,SAAA,CAAU,GAAA,CAAI,UAAA,CAAW,GAAA,EAAK,QAAQ,CAAC,CAAA;AACvD,EAAA,IAAI,OAAA,EAAS;AACX,IAAA,OAAO;AAAA,MACL,KAAA,EAAO,OAAA;AAAA,MACP,UAAU,EAAE,MAAA,EAAQ,MAAA,EAAQ,GAAA,EAAK,OAAO,QAAA,EAAS;AAAA,MACjD,SAAA,EAAW;AAAA,QACT,MAAM,MAAA,IAAU,GAAA;AAAA,QAChB,QAAQ,KAAA,KAAU;AAAA,OACpB;AAAA,MACA,MAAA,EAAQ;AAAA,KACV;AAAA,EACF;AAEA,EAAA,OAAO,iBAAA,CAAkB,MAAA,EAAQ,MAAA,EAAQ,KAAA,EAAO,YAAY,CAAA;AAC9D","file":"chunk-XK73IOFB.js","sourcesContent":["/**\n * BmFont JSON types and parser for the MSDF atlas format produced by\n * msdf-bmfont-xml. The parser builds accelerator maps (charMap, kerningMap)\n * for O(1) glyph and kerning lookup during layout.\n */\n\nexport interface BmFontInfo {\n face: string;\n size: number;\n}\n\n/** Font-wide vertical metrics and the atlas page dimensions, in pixels. */\nexport interface BmFontCommon {\n lineHeight: number;\n base: number;\n scaleW: number;\n scaleH: number;\n}\n\n/** One glyph: where it sits in the atlas page (`x`/`y`/`width`/`height`),\n * where to draw it relative to the pen (`xoffset`/`yoffset`), and how far the\n * pen then advances. */\nexport interface BmFontChar {\n id: number;\n x: number;\n y: number;\n width: number;\n height: number;\n xoffset: number;\n yoffset: number;\n xadvance: number;\n page: number;\n}\n\n/** A kerning pair: `amount` px to add to the advance when `second` follows\n * `first`. Codepoints, not glyph indices. */\nexport interface BmFontKerning {\n first: number;\n second: number;\n amount: number;\n}\n\n/** A parsed MSDF atlas: the BmFont record plus the `charMap` / `kerningMap`\n * accelerators layout reads per glyph. */\nexport interface BmFont {\n info: BmFontInfo;\n common: BmFontCommon;\n chars: BmFontChar[];\n kernings: BmFontKerning[];\n charMap: Map<number, BmFontChar>;\n kerningMap: Map<number, Map<number, number>>;\n}\n\n/** Two-glyph fixture for unit tests. */\nexport const FIXTURE_FONT = {\n info: { face: 'Inter', size: 32 },\n common: { lineHeight: 38, base: 29, scaleW: 512, scaleH: 512 },\n chars: [\n { id: 65, x: 0, y: 0, width: 22, height: 28, xoffset: 1, yoffset: 4, xadvance: 23, page: 0 },\n { id: 66, x: 24, y: 0, width: 20, height: 28, xoffset: 2, yoffset: 4, xadvance: 22, page: 0 },\n ],\n kernings: [\n { first: 65, second: 66, amount: -1 },\n ],\n};\n\n/** Validate a BmFont JSON document and build its lookup maps. Throws with the\n * missing or malformed field named. */\nexport function parseBmFont(raw: unknown): BmFont {\n if (typeof raw !== 'object' || raw === null) throw new Error('parseBmFont: expected object');\n const r = raw as Record<string, unknown>;\n\n if (!r.info || typeof r.info !== 'object') throw new Error('parseBmFont: missing info');\n if (!r.common || typeof r.common !== 'object') throw new Error('parseBmFont: missing common');\n if (!Array.isArray(r.chars)) throw new Error('parseBmFont: chars must be an array');\n\n const info = r.info as BmFontInfo;\n const common = r.common as BmFontCommon;\n const chars = r.chars as BmFontChar[];\n const kernings: BmFontKerning[] = Array.isArray(r.kernings)\n ? (r.kernings as BmFontKerning[])\n : [];\n\n const charMap = new Map<number, BmFontChar>();\n for (const ch of chars) charMap.set(ch.id, ch);\n\n const kerningMap = new Map<number, Map<number, number>>();\n for (const k of kernings) {\n let inner = kerningMap.get(k.first);\n if (!inner) { inner = new Map(); kerningMap.set(k.first, inner); }\n inner.set(k.second, k.amount);\n }\n\n return { info, common, chars, kernings, charMap, kerningMap };\n}\n","/**\n * \"A glyph the renderer asked for can now paint\" — the redraw signal shared\n * by every asynchronous glyph source.\n *\n * Both lazy tiers land their work *after* the frame that asked for it: the\n * dynamic canvas-SDF atlas defers bakes past a per-frame budget, and the\n * outline tier has to fetch and parse font bytes. Neither can paint anything\n * on the frame that first requests a glyph, so both have to tell the canvas\n * to draw again.\n *\n * One subscriber set, not one per tier: a consumer wiring \"redraw when text\n * becomes drawable\" should not have to know how many tiers exist, or grow a\n * second subscription every time one is added. `<SceneCanvas>` subscribes\n * once and both tiers reach it.\n */\n\nconst subscribers = new Set<() => void>();\n\n/** Advanced by every `notifyGlyphReady`, so state can be checked rather than\n * listened for. See {@link glyphGeneration}. */\nlet generation = 0;\n\n/**\n * How many times glyph availability has changed — the pull-based companion to\n * {@link subscribeGlyphReady}.\n *\n * For caches that cannot hold a subscription. Subscribing at module load is a\n * side effect that reaches across a package boundary: it makes importing the\n * module that holds the cache require this package's whole surface, so a\n * consumer partially mocking `@weasel-js/font` breaks at import rather than at\n * use, and import order starts to matter. Comparing a counter has neither\n * problem, and costs a field read on a path that was going to check a cache\n * key anyway.\n *\n * Callers keep the last value they saw and compare; any difference means\n * anything derived from font metrics is stale. The absolute value carries no\n * meaning and may wrap in principle — compare with `!==`, not `<`.\n */\nexport function glyphGeneration(): number {\n return generation;\n}\n\n/**\n * Subscribe to glyph availability. Fires after a batch of deferred SDF bakes\n * completes, and when an outline face finishes loading — in both cases, text\n * that painted nothing (or painted from a lower tier) can now paint. Returns\n * an unsubscribe.\n */\nexport function subscribeGlyphReady(cb: () => void): () => void {\n subscribers.add(cb);\n return () => {\n subscribers.delete(cb);\n };\n}\n\n/** @internal Fired by a glyph source once newly-available glyphs can paint. */\nexport function notifyGlyphReady(): void {\n generation++;\n for (const cb of subscribers) cb();\n}\n\n/** @internal Test seam — the subscriber set is module state. */\nexport function _clearGlyphReadySubscribers(): void {\n subscribers.clear();\n}\n","/**\n * Cross-family fallback policy. The per-family chain in `resolveFontVariant`\n * (weight → style → synthetic) has always been rich; what was missing is what\n * happens when the family itself was never registered. That case used to\n * render nothing at all, which is the single most common cause of \"my text is\n * invisible\".\n */\n\n/**\n * What happens when a requested family has no baked atlas:\n * - `'substitute'` — render with the default family (see\n * `setDefaultFontFamily`), reporting the swap on `ResolveResult.substituted`.\n * - `'canvas'` — auto-enroll the family with the dynamic canvas-SDF\n * rasterizer. The consumer gets the *real* typeface if the browser has it,\n * at canvas-SDF quality rather than baked-MSDF quality.\n * - `'none'` — hard miss; the run renders nothing.\n */\nexport type FontFallbackPolicy = 'substitute' | 'canvas' | 'none';\n\nlet policy: FontFallbackPolicy = 'substitute';\nlet defaultFamily: string | null = null;\n\n/** Set what happens when text asks for a family that was never registered.\n * Process-wide; defaults to `'substitute'`. */\nexport function setFontFallbackPolicy(next: FontFallbackPolicy): void {\n policy = next;\n}\n\n/** The cross-family fallback policy currently in force. */\nexport function getFontFallbackPolicy(): FontFallbackPolicy {\n return policy;\n}\n\n/** Explicit default family for `'substitute'`. When unset, the first\n * registered family wins — the right answer for the common case of an app\n * that registers exactly one. */\nexport function setDefaultFontFamily(family: string): void {\n defaultFamily = family;\n}\n\n/** The family `setDefaultFontFamily` named, or `null` if none was set — in\n * which case `'substitute'` falls back to the first registered family. */\nexport function getDefaultFontFamily(): string | null {\n return defaultFamily;\n}\n\n/**\n * Warn-once gate for the cross-family fallback warnings. The messages are\n * built in `registerFont.ts` (they read the registry to name the actual gap),\n * but the dedup state lives here so `_resetFallbackForTests` clears it —\n * warnings about a fallback are fallback state. While it sat in\n * `registerFont.ts`, only a registry reset cleared it, and a test that reset\n * just the policy silently swallowed its next warning.\n */\nconst warnedFallbacks = new Set<string>();\n\n/** @internal Claim `key` for a one-time warning; true the first time only. */\nexport function claimFallbackWarning(key: string): boolean {\n if (warnedFallbacks.has(key)) return false;\n warnedFallbacks.add(key);\n return true;\n}\n\n/** @internal Also called by `_resetFontRegistryForTests`: dropping the fonts\n * a warning was about has to drop the warning too. */\nexport function _clearFallbackWarnings(): void {\n warnedFallbacks.clear();\n}\n\n/** Test helper. Do not call from product code. */\nexport function _resetFallbackForTests(): void {\n policy = 'substitute';\n defaultFamily = null;\n warnedFallbacks.clear();\n}\n","/**\n * Shelf packer for the dynamic glyph atlas: fixed-size square pages, rows\n * (\"shelves\") of same-ish-height rects filled left to right. Simple and\n * good enough for glyph rects; no rotation, no eviction (v1).\n */\n\nexport interface ShelfAlloc {\n page: number;\n x: number;\n y: number;\n}\n\ninterface Shelf { y: number; height: number; x: number; }\ninterface Page { shelves: Shelf[]; nextY: number; }\n\nexport class ShelfPacker {\n private pages: Page[] = [];\n private warned = false;\n\n constructor(\n private readonly pageSize: number,\n private readonly maxPages: number,\n ) {}\n\n get pageCount(): number {\n return this.pages.length;\n }\n\n /** Allocate a w×h rect. Returns null (warning once) when capacity is out. */\n alloc(w: number, h: number): ShelfAlloc | null {\n if (w > this.pageSize || h > this.pageSize) return this.fail();\n for (let p = 0; p < this.pages.length; p++) {\n const spot = this.allocInPage(this.pages[p], w, h);\n if (spot) return { page: p, ...spot };\n }\n if (this.pages.length < this.maxPages) {\n const page: Page = { shelves: [], nextY: 0 };\n this.pages.push(page);\n const spot = this.allocInPage(page, w, h);\n if (spot) return { page: this.pages.length - 1, ...spot };\n }\n return this.fail();\n }\n\n private allocInPage(page: Page, w: number, h: number): { x: number; y: number } | null {\n for (const shelf of page.shelves) {\n if (h <= shelf.height && shelf.x + w <= this.pageSize) {\n const x = shelf.x;\n shelf.x += w;\n return { x, y: shelf.y };\n }\n }\n if (page.nextY + h <= this.pageSize) {\n const shelf: Shelf = { y: page.nextY, height: h, x: w };\n page.shelves.push(shelf);\n page.nextY += h;\n return { x: 0, y: shelf.y };\n }\n return null;\n }\n\n private fail(): null {\n if (!this.warned) {\n this.warned = true;\n console.warn(\n `weasel DynamicGlyphAtlas: glyph pages full (${this.maxPages} × ${this.pageSize}²); ` +\n 'further dynamic glyphs will not render.',\n );\n }\n return null;\n }\n}\n","/**\n * Euclidean distance transform for runtime SDF glyph baking (the TinySDF\n * technique): antialiased canvas coverage in → single-channel SDF bytes out.\n *\n * Uses Felzenszwalb & Huttenlocher's 1D squared-distance transform applied\n * along columns then rows. Pure JS, no dependencies, no allocation beyond\n * the work arrays sized to the input.\n */\n\nconst INF = 1e20;\n\n/** One 1D pass of the squared EDT (Felzenszwalb & Huttenlocher 2012, §2). */\nfunction edt1d(\n f: Float64Array, d: Float64Array, v: Int32Array, z: Float64Array, n: number,\n): void {\n v[0] = 0;\n z[0] = -INF;\n z[1] = INF;\n let k = 0;\n for (let q = 1; q < n; q++) {\n let s = (f[q] + q * q - (f[v[k]] + v[k] * v[k])) / (2 * q - 2 * v[k]);\n while (s <= z[k]) {\n k--;\n s = (f[q] + q * q - (f[v[k]] + v[k] * v[k])) / (2 * q - 2 * v[k]);\n }\n k++;\n v[k] = q;\n z[k] = s;\n z[k + 1] = INF;\n }\n k = 0;\n for (let q = 0; q < n; q++) {\n while (z[k + 1] < q) k++;\n d[q] = (q - v[k]) * (q - v[k]) + f[v[k]];\n }\n}\n\n/** In-place 2D squared EDT over `grid` (width × height): columns, then rows. */\nfunction edt2d(\n grid: Float64Array, width: number, height: number,\n f: Float64Array, d: Float64Array, v: Int32Array, z: Float64Array,\n): void {\n for (let x = 0; x < width; x++) {\n for (let y = 0; y < height; y++) f[y] = grid[y * width + x];\n edt1d(f, d, v, z, height);\n for (let y = 0; y < height; y++) grid[y * width + x] = d[y];\n }\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) f[x] = grid[y * width + x];\n edt1d(f, d, v, z, width);\n for (let x = 0; x < width; x++) grid[y * width + x] = d[x];\n }\n}\n\n/**\n * Convert an alpha-coverage bitmap (0–255) to single-channel SDF bytes.\n * Signed distance is positive outside the shape; the output maps it as\n * `255 − 255·(dist/radius + cutoff)` clamped to [0,255], so with\n * cutoff 0.5 the shape edge lands at byte ~128 (shader threshold 0.5).\n */\nexport function alphaToSdf(\n alpha: Uint8ClampedArray | Uint8Array,\n width: number,\n height: number,\n radius: number,\n cutoff: number,\n): Uint8Array {\n const n = width * height;\n const gridOuter = new Float64Array(n);\n const gridInner = new Float64Array(n);\n const size = Math.max(width, height);\n const f = new Float64Array(size);\n const d = new Float64Array(size);\n const v = new Int32Array(size);\n const z = new Float64Array(size + 1);\n\n for (let i = 0; i < n; i++) {\n const a = alpha[i] / 255;\n gridOuter[i] = a === 1 ? 0 : a === 0 ? INF : Math.max(0, 0.5 - a) ** 2;\n gridInner[i] = a === 1 ? INF : a === 0 ? 0 : Math.max(0, a - 0.5) ** 2;\n }\n edt2d(gridOuter, width, height, f, d, v, z);\n edt2d(gridInner, width, height, f, d, v, z);\n\n const out = new Uint8Array(n);\n for (let i = 0; i < n; i++) {\n const dist = Math.sqrt(gridOuter[i]) - Math.sqrt(gridInner[i]);\n const byte = Math.round(255 - 255 * (dist / radius + cutoff));\n out[i] = byte < 0 ? 0 : byte > 255 ? 255 : byte;\n }\n return out;\n}\n","/**\n * Canvas-2D glyph rasterizer for the dynamic SDF atlas. `fillText` is the\n * only web-platform route to *installed* machine fonts (no outline access),\n * which is exactly why this tier exists.\n *\n * Coordinate contract (all values in bake-size px, i.e. at BAKE_SIZE):\n * bitmap left = penX + left (left is negative: pad + left bearing)\n * bitmap top = baseline − top (top is positive above the baseline)\n * pen advance = advance\n * The bitmap includes a PAD border on all four sides so the SDF field has\n * room to fall off. Blank glyphs (e.g. space) return width/height 0.\n *\n * On BAKE_SIZE — measured 2026-07-29, comparing the reconstructed field\n * against a direct `fillText` of the same glyph at each display size, with\n * sub-pixel registration searched out so it measures fidelity and not\n * alignment. Mean per-pixel coverage error, averaged over A/S/e/W/8:\n *\n * display px 12 16 24 32 48 64 96 128\n * error .096 .083 .059 .039 .024 .023 .037 .049\n *\n * Two things follow, both of them counterintuitive enough to be worth\n * writing down. The error is minimized *at* the bake size, so raising\n * BAKE_SIZE does not improve small text — it moves the sweet spot away from\n * the 12–32px range where UI text actually lives and makes it worse. And the\n * magnification side is the mild one: 128px costs about twice the floor,\n * which is the corner rounding the shader header already owns.\n *\n * The 12–16px end is the largest divergence, and it is not undersampling —\n * 3×3 supersampling the reconstruction roughly halves the error at 24–48px\n * but recovers almost nothing at 12–16px (.096 → .089, .083 → .068). What is\n * left there is a hinted rasterizer placing stems on the pixel grid, which no\n * size-independent field can encode. So there is nothing to buy with more\n * taps, a bigger bake, or mipmaps (which a packed atlas cannot have anyway —\n * mip levels blend across glyph rects).\n */\n\nexport const BAKE_SIZE = 48;\nexport const PAD = 8;\n\nexport interface FaceMetrics {\n ascent: number;\n descent: number;\n}\n\nexport interface RasterizedGlyph {\n width: number;\n height: number;\n alpha: Uint8ClampedArray;\n left: number;\n top: number;\n advance: number;\n}\n\nexport interface GlyphRasterizer {\n faceMetrics(family: string, weight: number, style: 'normal' | 'italic'): FaceMetrics;\n rasterize(\n family: string, weight: number, style: 'normal' | 'italic', codepoint: number,\n ): RasterizedGlyph;\n}\n\ntype Canvas2D = OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D;\n\nfunction cssFontString(weight: number, style: 'normal' | 'italic', family: string): string {\n return `${style === 'italic' ? 'italic ' : ''}${weight} ${BAKE_SIZE}px ${JSON.stringify(family)}`;\n}\n\nexport function createCanvasRasterizer(): GlyphRasterizer {\n let canvas: OffscreenCanvas | HTMLCanvasElement;\n if (typeof OffscreenCanvas !== 'undefined') {\n canvas = new OffscreenCanvas(BAKE_SIZE * 3, BAKE_SIZE * 3);\n } else if (typeof document !== 'undefined') {\n canvas = document.createElement('canvas');\n canvas.width = BAKE_SIZE * 3;\n canvas.height = BAKE_SIZE * 3;\n } else {\n throw new Error('weasel DynamicGlyphAtlas: no canvas available for glyph rasterization');\n }\n const ctx = canvas.getContext('2d', { willReadFrequently: true }) as Canvas2D | null;\n if (!ctx) throw new Error('weasel DynamicGlyphAtlas: 2D context unavailable');\n\n function setFont(family: string, weight: number, style: 'normal' | 'italic'): void {\n ctx!.font = cssFontString(weight, style, family);\n ctx!.textBaseline = 'alphabetic';\n ctx!.textAlign = 'left';\n }\n\n return {\n faceMetrics(family, weight, style) {\n setFont(family, weight, style);\n const m = ctx!.measureText('Hg');\n return {\n ascent: m.fontBoundingBoxAscent ?? BAKE_SIZE * 0.8,\n descent: m.fontBoundingBoxDescent ?? BAKE_SIZE * 0.2,\n };\n },\n\n rasterize(family, weight, style, codepoint) {\n setFont(family, weight, style);\n const chStr = String.fromCodePoint(codepoint);\n const m = ctx!.measureText(chStr);\n const advance = m.width;\n const inkLeft = Math.ceil(m.actualBoundingBoxLeft ?? 0);\n const inkRight = Math.ceil(m.actualBoundingBoxRight ?? advance);\n const inkAscent = Math.ceil(m.actualBoundingBoxAscent ?? BAKE_SIZE * 0.8);\n const inkDescent = Math.ceil(m.actualBoundingBoxDescent ?? BAKE_SIZE * 0.2);\n const inkW = inkLeft + inkRight;\n const inkH = inkAscent + inkDescent;\n if (inkW <= 0 || inkH <= 0) {\n return { width: 0, height: 0, alpha: new Uint8ClampedArray(0), left: 0, top: 0, advance };\n }\n const w = inkW + 2 * PAD;\n const h = inkH + 2 * PAD;\n if (canvas.width < w || canvas.height < h) {\n canvas.width = Math.max(canvas.width, w);\n canvas.height = Math.max(canvas.height, h);\n setFont(family, weight, style); // resizing resets 2D state\n }\n ctx!.clearRect(0, 0, w, h);\n ctx!.fillStyle = '#fff';\n ctx!.fillText(chStr, PAD + inkLeft, PAD + inkAscent);\n const img = ctx!.getImageData(0, 0, w, h);\n const alpha = new Uint8ClampedArray(w * h);\n for (let i = 0; i < alpha.length; i++) alpha[i] = img.data[i * 4 + 3];\n return {\n width: w,\n height: h,\n alpha,\n left: -(inkLeft + PAD),\n top: inkAscent + PAD,\n advance,\n };\n },\n };\n}\n","/**\n * DynamicGlyphAtlas — runtime single-channel SDF glyphs for canvas-sourced\n * (installed machine) fonts. TinySDF technique: canvas fillText at 48 px →\n * Euclidean distance transform → shelf-packed R8 pages (1024², max 4).\n *\n * Baked MSDF atlases always win: this tier only serves families registered\n * via `registerCanvasFont` that have no baked entry (see resolveFontVariant).\n *\n * Faces expose a BmFont-shaped `font` whose charMap grows as glyphs are\n * requested, so `layoutRuns` consumes them through the same code path as\n * baked atlases. A char's advance is valid immediately (measureText); its\n * atlas rect fills in when the bake lands (width 0 / page -1 until then, so\n * layout advances the pen but emits no quad).\n */\n\nimport type { BmFont, BmFontChar } from '../FontAtlas';\nimport type { GlyphTextureSink } from '../textureSink';\n// `fallback.ts` imports nothing, so this edge cannot close a cycle; keep it\n// that way. (registerFont.ts imports both this module and fallback.ts.)\nimport { getFontFallbackPolicy } from '../fallback';\nimport { notifyGlyphReady, _clearGlyphReadySubscribers } from '../glyphReady';\nimport { ShelfPacker } from './shelfPack';\nimport { alphaToSdf } from './distanceTransform';\nimport {\n createCanvasRasterizer, BAKE_SIZE,\n type GlyphRasterizer, type RasterizedGlyph,\n} from './glyphRasterizer';\n\nexport const PAGE_SIZE = 1024;\nexport const MAX_PAGES = 4;\nexport const SDF_RADIUS = 8;\nexport const SDF_CUTOFF = 0.5;\n/** How many glyphs the dynamic atlas will rasterize synchronously before\n * deferring the rest to a later flush. Caps the frame cost of text that\n * suddenly needs many new glyphs; the leftovers arrive a tick later and\n * notify through `onGlyphReady`. */\nexport const DEFAULT_BAKE_BUDGET = 16;\n\nexport interface DynamicFace {\n family: string;\n weight: number;\n style: 'normal' | 'italic';\n /** BmFont-shaped view consumed by layoutRuns; charMap grows lazily. */\n font: BmFont;\n /** Char record for `cp`, measured on first request (advance always valid\n * immediately; atlas rect fills in when the bake lands). */\n requestGlyph(cp: number): BmFontChar;\n}\n\ninterface DynamicPage {\n data: Uint8Array;\n /** Bumps on every glyph blit; each blit appends a patch with seq = version. */\n version: number;\n patches: { seq: number; x: number; y: number; w: number; h: number }[];\n}\n\ninterface PendingBake { char: BmFontChar; raster: RasterizedGlyph; }\n\n/** One family served by the dynamic canvas-SDF tier. See `listCanvasFonts`. */\nexport interface CanvasFontEntry {\n family: string;\n /** `'explicit'` — a `registerCanvasFont` call; `'auto'` — the `'canvas'`\n * fallback policy enrolled it on a miss, and the enrollment lapses if\n * that policy changes. */\n enrollment: 'explicit' | 'auto';\n}\n\nconst canvasFamilies = new Set<string>();\n// Enrollment provenance. A family the `'canvas'` fallback policy enrolled on\n// its own is only canvas-served while that policy is in force; one a consumer\n// named via registerCanvasFont outranks every policy. Tracked here rather\n// than in fallback.ts so the two sets can only ever be mutated together —\n// every register / unregister / reset path is in this file.\nconst autoEnrolledFamilies = new Set<string>();\nlet faces = new Map<string, DynamicFace>();\nlet pages: DynamicPage[] = [];\nlet packer = new ShelfPacker(PAGE_SIZE, MAX_PAGES);\nlet pending: PendingBake[] = [];\nlet flushScheduled = false;\nlet budget = DEFAULT_BAKE_BUDGET;\nlet rasterizer: GlyphRasterizer | null = null;\n\nfunction getRasterizer(): GlyphRasterizer {\n if (!rasterizer) rasterizer = createCanvasRasterizer();\n return rasterizer;\n}\n\n/** Mark `family` as canvas-sourced: when no baked atlas covers it,\n * resolveFontVariant serves it from this dynamic atlas. */\nexport function registerCanvasFont(family: string): void {\n canvasFamilies.add(family);\n // An explicit call promotes a previously auto-enrolled family for good.\n autoEnrolledFamilies.delete(family);\n}\n\n/**\n * Will `family` be served by the dynamic canvas-SDF tier *right now*?\n *\n * Service, not membership — the answer depends on the fallback policy in\n * force and can change without any enrollment call:\n * - explicitly enrolled via `registerCanvasFont` → `true` under every\n * policy; a consumer naming a family outranks the policy.\n * - auto-enrolled by the `'canvas'` policy → `true` only while that policy\n * is still in force. The enrollment lapses rather than being discarded,\n * so returning to `'canvas'` makes it `true` again.\n * - never enrolled → `false`, including under `'canvas'` (that policy\n * enrolls lazily, on the first miss).\n *\n * The membership reading would answer `true` for an auto-enrolled family\n * under `'substitute'` / `'none'`, where nothing routes to this tier — a\n * caller predicting what renders would be told the opposite of the truth.\n * Mirrors `listFonts`, which reports the baked registry alone for the same\n * reason: \"enrolled\" is not \"will render\".\n */\nexport function isCanvasFont(family: string): boolean {\n if (!canvasFamilies.has(family)) return false;\n return !autoEnrolledFamilies.has(family) || getFontFallbackPolicy() === 'canvas';\n}\n\n/**\n * Every family the dynamic canvas-SDF tier will serve *right now* — the\n * enumeration companion to `isCanvasFont`, which answers one family at a\n * time. Same \"service, not membership\" rule: an auto-enrolled family appears\n * only while the `'canvas'` policy is in force.\n *\n * Exists so a consumer can offer these families in a font picker.\n * `listFonts` reports the baked registry alone, so without this the only\n * ways to present canvas-served families were to hard-code a list beside the\n * `registerCanvasFont` calls or to omit them — a UI inventing its own answer\n * about what will render.\n *\n * `enrollment` distinguishes a consumer's explicit `registerCanvasFont` from\n * a lazy enrollment the policy made on a miss; both render identically, but\n * only the explicit one survives a policy change.\n */\nexport function listCanvasFonts(): readonly CanvasFontEntry[] {\n const out: CanvasFontEntry[] = [];\n for (const family of canvasFamilies) {\n if (!isCanvasFont(family)) continue;\n out.push({ family, enrollment: autoEnrolledFamilies.has(family) ? 'auto' : 'explicit' });\n }\n return out.sort((a, b) => a.family.localeCompare(b.family));\n}\n\n/**\n * @internal Enroll `family` on behalf of the `'canvas'` fallback policy.\n * Distinct from `registerCanvasFont` only in provenance: the enrollment\n * lapses (see `isExplicitCanvasFont`) if the policy later changes.\n */\nexport function autoEnrollCanvasFont(family: string): void {\n if (canvasFamilies.has(family) && !autoEnrolledFamilies.has(family)) return;\n canvasFamilies.add(family);\n autoEnrolledFamilies.add(family);\n}\n\n/**\n * @internal Enrolled by a consumer's own `registerCanvasFont` call rather than\n * by the `'canvas'` policy. Only these are served by the dynamic tier\n * regardless of the policy in force; an auto-enrolled family falls back to\n * whatever the current policy says once that policy is no longer `'canvas'`.\n */\nexport function isExplicitCanvasFont(family: string): boolean {\n return canvasFamilies.has(family) && !autoEnrolledFamilies.has(family);\n}\n\n/** Remove a canvas family. Its faces are dropped; already-baked glyph\n * pixels stay in their pages (no eviction in v1). */\nexport function unregisterCanvasFont(family: string): void {\n canvasFamilies.delete(family);\n autoEnrolledFamilies.delete(family);\n for (const key of [...faces.keys()]) {\n if (faces.get(key)!.family === family) faces.delete(key);\n }\n}\n\n/**\n * Internal resolver helper — not part of the public barrel; consumers go\n * through registerCanvasFont + resolveFontVariant.\n */\nexport function getDynamicFace(\n family: string, weight: number, style: 'normal' | 'italic',\n): DynamicFace {\n const key = `${family}|${weight}|${style}`;\n const existing = faces.get(key);\n if (existing) return existing;\n\n const r = getRasterizer();\n const metrics = r.faceMetrics(family, weight, style);\n const base = Math.round(metrics.ascent);\n const font: BmFont = {\n info: { face: family, size: BAKE_SIZE },\n common: {\n lineHeight: Math.round(metrics.ascent + metrics.descent),\n base,\n scaleW: PAGE_SIZE,\n scaleH: PAGE_SIZE,\n },\n chars: [],\n kernings: [], // no kerning in v1 (measured-pair kerning is future work)\n charMap: new Map(),\n kerningMap: new Map(),\n };\n\n const face: DynamicFace = {\n family, weight, style, font,\n requestGlyph(cp: number): BmFontChar {\n const cached = font.charMap.get(cp);\n if (cached) return cached;\n const raster = r.rasterize(family, weight, style, cp);\n const char: BmFontChar = {\n id: cp, x: 0, y: 0, width: 0, height: 0,\n xoffset: raster.left,\n yoffset: base - raster.top,\n xadvance: raster.advance,\n page: -1,\n };\n font.charMap.set(cp, char);\n font.chars.push(char);\n if (raster.width === 0 || raster.height === 0) {\n char.page = 0; // blank glyph (space): nothing to bake\n return char;\n }\n if (budget > 0) {\n budget--;\n bake(char, raster);\n } else {\n pending.push({ char, raster });\n scheduleFlush();\n }\n return char;\n },\n };\n faces.set(key, face);\n return face;\n}\n\nfunction bake(char: BmFontChar, raster: RasterizedGlyph): void {\n const spot = packer.alloc(raster.width, raster.height);\n if (!spot) return; // pages full — packer warned once; glyph stays invisible\n const sdf = alphaToSdf(raster.alpha, raster.width, raster.height, SDF_RADIUS, SDF_CUTOFF);\n while (pages.length <= spot.page) {\n pages.push({ data: new Uint8Array(PAGE_SIZE * PAGE_SIZE), version: 0, patches: [] });\n }\n const page = pages[spot.page];\n for (let row = 0; row < raster.height; row++) {\n page.data.set(\n sdf.subarray(row * raster.width, (row + 1) * raster.width),\n (spot.y + row) * PAGE_SIZE + spot.x,\n );\n }\n page.version++;\n page.patches.push({ seq: page.version, x: spot.x, y: spot.y, w: raster.width, h: raster.height });\n char.x = spot.x;\n char.y = spot.y;\n char.width = raster.width;\n char.height = raster.height;\n char.page = spot.page;\n}\n\nfunction scheduleFlush(): void {\n if (flushScheduled) return;\n flushScheduled = true;\n setTimeout(flushPending, 0);\n}\n\nfunction flushPending(): void {\n flushScheduled = false;\n let n = 0;\n while (pending.length > 0 && n < DEFAULT_BAKE_BUDGET) {\n const job = pending.shift()!;\n if (job.char.page !== -1) continue; // already baked\n bake(job.char, job.raster);\n n++;\n }\n if (pending.length > 0) scheduleFlush();\n notifyGlyphReady();\n}\n\n/** Reset the per-frame synchronous bake budget. Called by\n * `WeaselRenderer.render()` at frame start; the headless\n * `renderSceneToPixels` path passes Infinity so print never defers. */\nexport function resetBakeBudget(n: number = DEFAULT_BAKE_BUDGET): void {\n budget = n;\n}\n\n/* ------------------------------------------------------------------ */\n/* GPU sync */\n/* ------------------------------------------------------------------ */\n\n/** Texture-cache key for a dynamic page (parallel to `textureCacheKey`). */\nexport function dynamicPageTextureId(page: number): string {\n return `weasel-dyn-sdf-page-${page}`;\n}\n\n// Per-GL-cache upload progress: last page version each cache has seen.\n// WeakMap-keyed so disposed renderers don't pin anything.\nconst uploadedVersions = new WeakMap<GlyphTextureSink, Map<number, number>>();\n\n/** Bring `cache`'s copy of page `pageIndex` up to date: full R8 upload the\n * first time, `texSubImage2D` patches after. Returns false if the page\n * doesn't exist yet. */\nexport function syncDynamicPageTexture(cache: GlyphTextureSink, pageIndex: number): boolean {\n const page = pages[pageIndex];\n if (!page) return false;\n const id = dynamicPageTextureId(pageIndex);\n let seen = uploadedVersions.get(cache);\n if (!seen) {\n seen = new Map();\n uploadedVersions.set(cache, seen);\n }\n if (!cache.has(id)) {\n cache.uploadR8(id, PAGE_SIZE, PAGE_SIZE, page.data);\n seen.set(pageIndex, page.version);\n return true;\n }\n const last = seen.get(pageIndex) ?? 0;\n if (last >= page.version) return true;\n for (const patch of page.patches) {\n if (patch.seq <= last) continue;\n const tight = new Uint8Array(patch.w * patch.h);\n for (let row = 0; row < patch.h; row++) {\n const src = (patch.y + row) * PAGE_SIZE + patch.x;\n tight.set(page.data.subarray(src, src + patch.w), row * patch.w);\n }\n cache.subImageR8(id, patch.x, patch.y, patch.w, patch.h, tight);\n }\n seen.set(pageIndex, page.version);\n return true;\n}\n\n/* ------------------------------------------------------------------ */\n/* Test seams */\n/* ------------------------------------------------------------------ */\n\n/** @internal test seam — inject a fake rasterizer (jsdom has no canvas\n * metrics). Pass null to restore the lazy default. */\nexport function __setGlyphRasterizerForTests(r: GlyphRasterizer | null): void {\n rasterizer = r;\n}\n\n/** @internal test seam — inspect CPU-side pages. */\nexport function _getPagesForTests(): readonly DynamicPage[] {\n return pages;\n}\n\n/** @internal test seam — clear all dynamic-font state. */\nexport function _resetDynamicFontsForTests(): void {\n canvasFamilies.clear();\n autoEnrolledFamilies.clear();\n faces = new Map();\n pages = [];\n packer = new ShelfPacker(PAGE_SIZE, MAX_PAGES);\n pending = [];\n flushScheduled = false;\n budget = DEFAULT_BAKE_BUDGET;\n _clearGlyphReadySubscribers();\n rasterizer = null;\n}\n","/**\n * The parsed-font seam for the outline tier.\n *\n * A face answers exactly one question — \"what does codepoint N look like?\" —\n * and answers it as **SVG path data in em space**: one unit is one em, y\n * grows downward, and the origin sits on the baseline at the glyph's pen\n * position. That is a complete description of the glyph independent of size,\n * zoom, and position, which is the whole reason the tier exists: tessellate\n * once, transform per instance.\n *\n * ### Why `d` and not a command stream\n *\n * `@weasel-js/font` is a Tier A leaf — `@weasel-js/core` depends on it and\n * never the reverse (see `leaf-purity.test.ts`), so this package cannot name\n * core's `PolygonPath`. The alternative to a string would be re-declaring\n * core's `PATH_M`/`PATH_L`/… opcodes over here and trusting two packages to\n * keep the same numbering forever. SVG `d` is the kit's documented language\n * for geometry crossing a boundary (`docs/conventions.md`), core already\n * ships `pathFromD`, and a glyph outline is exactly the case it describes.\n *\n * The string is also a natural cache key and costs nothing to hold: the\n * parse happens once per glyph, and core caches the *tessellation*, not the\n * text.\n */\n\n/** Weight/style pair identifying one face within a family. */\nexport type OutlineFontStyle = 'normal' | 'italic';\n\n/** A parsed font face, viewed only as a source of glyph outlines. See the\n * module comment for the em-space contract `glyphD` returns. */\nexport interface OutlineFace {\n /** Font design units per em. Reported for diagnostics; `glyphD` has already\n * divided by it, so callers never need to. */\n unitsPerEm: number;\n /**\n * Distance from the line top to the baseline, in em units — the outline\n * tier's analogue of a `BmFont`'s `common.base`.\n *\n * Read from `hhea`, which is what `msdf-bmfont-xml` bakes, so a face used\n * for metrics puts text on the same baseline as an atlas of the same font.\n * `docs/TODO.md` tracks the wider disagreement with `sTypoAscender`.\n */\n ascender: number;\n /**\n * Em-space SVG path data for `cp`, or `null` when this face has no glyph\n * for the codepoint *or* the glyph has no contours (a space). Both answers\n * mean the same thing to a caller: there is nothing here to tessellate, so\n * fall through to whatever tier would have drawn it.\n */\n glyphD(cp: number): string | null;\n /**\n * Advance width for `cp` in em units, or `null` when the face has no glyph\n * for it. Distinct from `glyphD` answering `null`: a space has an advance\n * and no contours, and layout needs the advance either way.\n */\n advanceOf(cp: number): number | null;\n /** Kerning adjustment between two codepoints, in em units — negative pulls\n * them together. `0` when the face kerns neither this pair nor at all. */\n kernOf(left: number, right: number): number;\n}\n\n/**\n * Turn font file bytes into a face. Async because the default implementation\n * dynamically imports its parser — see `opentypeParser.ts` for why that\n * matters — and because a caller may want to hand back a face that finishes\n * initializing off-thread.\n */\nexport type OutlineParser = (bytes: ArrayBuffer) => OutlineFace | Promise<OutlineFace>;\n\n/**\n * Decimal places kept when serializing em-space coordinates.\n *\n * Five is chosen against two constraints, not by taste. Below: 1e-5 em is\n * 0.01px on a 1000px-tall glyph, an order of magnitude under anything a\n * display can show. Above: `pathFromD`'s tokenizer splits argument runs on\n * *letters*, so a coordinate that JavaScript chooses to print in exponential\n * form (`1e-7`) would tokenize as the command `e`. Numbers stay in\n * positional notation down to 1e-6, so five decimals cannot produce one.\n */\nexport const OUTLINE_PRECISION = 5;\n","/**\n * TrueType/OpenType **collection** unpacking.\n *\n * `queryLocalFonts()` hands back the font *file* behind a face, and on macOS\n * a large share of the interesting ones — Helvetica, Times, Courier, Menlo —\n * are `.ttc` collections holding every weight and style in a single file with\n * one shared glyph store. A collection is not a font: its header is `ttcf`\n * rather than an sfnt version, so every parser worth using rejects it, and\n * opentype.js is no exception (it recognizes `\\0\\1\\0\\0`, `true`, `typ1`,\n * `OTTO`, `wOFF` and throws on anything else).\n *\n * The fix is mechanical, because a collection is just N table directories\n * over one pool of tables: pick the directory whose PostScript name matches\n * the face we were asked for, then re-emit it as a standalone sfnt with the\n * tables copied and the offsets rewritten. Nothing is re-encoded — the table\n * bytes are the same bytes — so the result parses identically to a font that\n * had shipped on its own.\n *\n * Kept separate from `opentypeParser.ts` so the collection handling is\n * testable without a parser, and so swapping the parser later doesn't drag\n * this along.\n *\n * ### Why this lives here rather than upstream or in a bigger library\n *\n * Decided 2026-07-31, after looking at both alternatives — recorded so this\n * doesn't get \"tidied up\" into one of them later.\n *\n * The upstream fix is genuinely small: `parseOpenTypeTableEntries` hardcodes\n * `p = 12`, so the only thing opentype.js cannot do is be *told* the table\n * directory starts somewhere other than byte zero. Table records already\n * carry absolute offsets and the parser already reads them from a\n * whole-buffer view, so a `dirOffset` parameter and a `ttcf` branch would be\n * about ten lines. (Typr takes an offset in `readFONT` and gets collections\n * for free — same capability, one better-chosen signature.) It would make a\n * good PR. It would also not help for a while: opentype.js sat untouched from\n * 2021 to 2026, and we would carry this file until a release landed anyway.\n *\n * fontkit handles `.ttc` and `.dfont` natively, and WOFF2 besides — but it is\n * ~5.6 MB unpacked across nine dependencies (brotli, unicode-trie, dfa, …).\n * That is a shaping engine, and all this tier wants is a glyph outline.\n *\n * This version has an advantage over both: it runs *before* anything parses,\n * so it is parser-agnostic and survives swapping opentype.js out.\n *\n * **Known gap: `.dfont`** (Datafork TrueType) is not unpacked — its sfnt\n * tables live inside a Macintosh resource map, which is a second container\n * format on top of the one above. `isDataForkFont` recognizes it and\n * `sfntFromCollection` throws by name, so the face degrades to the SDF tier\n * saying why; the registry's `warnOnce` carries the message. Not currently\n * reachable on macOS, whose system font directories are 204 `.ttf` / 128\n * `.ttc` / 38 `.otf` and no `.dfont`; it is a real format on older systems.\n */\n\nconst SFNT_HEADER_BYTES = 12;\nconst TABLE_RECORD_BYTES = 16;\n\nfunction tagAt(view: DataView, offset: number): string {\n return String.fromCharCode(\n view.getUint8(offset), view.getUint8(offset + 1),\n view.getUint8(offset + 2), view.getUint8(offset + 3),\n );\n}\n\n/** Is `bytes` a font collection rather than a single font? */\nexport function isFontCollection(bytes: ArrayBuffer): boolean {\n if (bytes.byteLength < 4) return false;\n return tagAt(new DataView(bytes), 0) === 'ttcf';\n}\n\n/** Every signature that opens a font file this tier can hand to a parser. */\nconst FONT_SIGNATURES: ReadonlySet<string> = new Set([\n '\\x00\\x01\\x00\\x00', 'true', 'typ1', 'OTTO', 'ttcf', 'wOFF', 'wOF2',\n]);\n\nconst RESOURCE_HEADER_BYTES = 16;\n\n/**\n * Is `bytes` a Datafork TrueType file (`.dfont`)?\n *\n * A `.dfont` is a bare Macintosh resource fork written to the data fork, so\n * unlike every other font format it opens with no signature — just the\n * resource header's four big-endian offsets. It is recognized by those\n * adding up, which is why the signature check has to run first: an sfnt's\n * header bytes are numbers too, and nothing stops them from coincidentally\n * being consistent.\n *\n * Detection only. Reading the `sfnt` resources out of the map is the rest of\n * the job and is not implemented — the point is that the face declines the\n * outline tier by name instead of dying on an unrecognized-signature message\n * that never mentions the format.\n */\nexport function isDataForkFont(bytes: ArrayBuffer): boolean {\n if (bytes.byteLength < RESOURCE_HEADER_BYTES) return false;\n const view = new DataView(bytes);\n if (FONT_SIGNATURES.has(tagAt(view, 0))) return false;\n const dataOffset = view.getUint32(0);\n const mapOffset = view.getUint32(4);\n const dataLength = view.getUint32(8);\n const mapLength = view.getUint32(12);\n return dataOffset >= RESOURCE_HEADER_BYTES\n && dataOffset + dataLength === mapOffset\n && mapOffset + mapLength <= bytes.byteLength;\n}\n\ninterface TableRecord { tag: string; offset: number; length: number; checksum: number }\n\nfunction readTableDirectory(view: DataView, dirOffset: number): TableRecord[] {\n const numTables = view.getUint16(dirOffset + 4);\n const records: TableRecord[] = [];\n for (let i = 0; i < numTables; i++) {\n const at = dirOffset + SFNT_HEADER_BYTES + i * TABLE_RECORD_BYTES;\n records.push({\n tag: tagAt(view, at),\n checksum: view.getUint32(at + 4),\n offset: view.getUint32(at + 8),\n length: view.getUint32(at + 12),\n });\n }\n return records;\n}\n\n/**\n * PostScript name (`name` table, nameID 6) of the sub-font at `dirOffset`,\n * or `null` when it carries none.\n *\n * A deliberately minimal reader: identifying which member of a collection to\n * unpack is the only thing needed here, and a full `name` parser would be a\n * second implementation of something the real parser does properly once the\n * font is standalone. PostScript names are ASCII by specification, so both\n * the Macintosh (single-byte) and Windows (UTF-16BE) encodings reduce to\n * \"take every byte that isn't a zero pad\".\n */\nfunction postScriptNameAt(view: DataView, records: readonly TableRecord[]): string | null {\n const name = records.find((r) => r.tag === 'name');\n if (!name) return null;\n const base = name.offset;\n const count = view.getUint16(base + 2);\n const stringOffset = view.getUint16(base + 4);\n for (let i = 0; i < count; i++) {\n const rec = base + 6 + i * 12;\n if (view.getUint16(rec + 6) !== 6) continue; // nameID 6 === PostScript name\n const length = view.getUint16(rec + 8);\n const offset = view.getUint16(rec + 10);\n let out = '';\n for (let b = 0; b < length; b++) {\n const code = view.getUint8(base + stringOffset + offset + b);\n if (code !== 0) out += String.fromCharCode(code);\n }\n if (out.length > 0) return out;\n }\n return null;\n}\n\n/** Re-emit the table directory at `dirOffset` as a standalone sfnt buffer. */\nfunction extractFont(source: ArrayBuffer, view: DataView, dirOffset: number): ArrayBuffer {\n const records = readTableDirectory(view, dirOffset);\n // Tables are copied 4-byte aligned, which is what the format requires and\n // what every checksum in the directory was computed over.\n const padded = (n: number): number => (n + 3) & ~3;\n let total = SFNT_HEADER_BYTES + records.length * TABLE_RECORD_BYTES;\n for (const r of records) total += padded(r.length);\n\n const out = new ArrayBuffer(total);\n const dst = new DataView(out);\n const dstBytes = new Uint8Array(out);\n const srcBytes = new Uint8Array(source);\n\n dst.setUint32(0, view.getUint32(dirOffset)); // sfntVersion\n dst.setUint16(4, records.length);\n // searchRange / entrySelector / rangeShift are a binary-search hint over the\n // table records. Recomputed rather than copied: the member directory's\n // values describe its own table count, which is usually but not always the\n // same, and a wrong hint is a parser walking off the end of the directory.\n const entrySelector = Math.floor(Math.log2(records.length));\n const searchRange = 2 ** entrySelector * 16;\n dst.setUint16(6, searchRange);\n dst.setUint16(8, entrySelector);\n dst.setUint16(10, records.length * 16 - searchRange);\n\n let cursor = SFNT_HEADER_BYTES + records.length * TABLE_RECORD_BYTES;\n records.forEach((r, i) => {\n const at = SFNT_HEADER_BYTES + i * TABLE_RECORD_BYTES;\n for (let b = 0; b < 4; b++) dst.setUint8(at + b, r.tag.charCodeAt(b));\n dst.setUint32(at + 4, r.checksum);\n dst.setUint32(at + 8, cursor);\n dst.setUint32(at + 12, r.length);\n dstBytes.set(srcBytes.subarray(r.offset, r.offset + r.length), cursor);\n cursor += padded(r.length);\n });\n return out;\n}\n\n/**\n * Standalone font bytes for one member of a collection.\n *\n * `postScriptName` selects the member; when it is absent or matches nothing,\n * the first member is returned. Falling back rather than failing is\n * deliberate — the name comes from `FontData.postscriptName`, and a browser\n * that reports it differently from the `name` table should degrade to \"some\n * weight of the right family\", not to no text at all. The caller sees which\n * it got via the returned `matched` flag.\n *\n * Passing a single font through is a no-op, so this is safe to call on any\n * bytes.\n */\nexport function sfntFromCollection(\n bytes: ArrayBuffer,\n postScriptName?: string,\n): { bytes: ArrayBuffer; matched: boolean } {\n if (isDataForkFont(bytes)) {\n throw new Error(\n 'Datafork TrueType (.dfont) is not supported — the outline tier reads sfnt '\n + 'tables and a .dfont holds them inside a Macintosh resource map.',\n );\n }\n if (!isFontCollection(bytes)) return { bytes, matched: true };\n\n const view = new DataView(bytes);\n const numFonts = view.getUint32(8);\n if (numFonts === 0) throw new Error('font collection contains no fonts');\n\n const offsets: number[] = [];\n for (let i = 0; i < numFonts; i++) offsets.push(view.getUint32(12 + i * 4));\n\n if (postScriptName) {\n for (const dirOffset of offsets) {\n const records = readTableDirectory(view, dirOffset);\n if (postScriptNameAt(view, records) === postScriptName) {\n return { bytes: extractFont(bytes, view, dirOffset), matched: true };\n }\n }\n }\n return { bytes: extractFont(bytes, view, offsets[0]), matched: !postScriptName };\n}\n","/**\n * The default `OutlineParser`: opentype.js, loaded on demand.\n *\n * ### Why the dynamic import\n *\n * opentype.js is ~49 kB gzipped and it is the *only* runtime dependency this\n * package has. Charging that to every consumer of `@weasel-js/font` — most of\n * whom render text through a baked atlas and never touch an outline — would\n * be a poor trade for a tier that only engages above a size threshold. The\n * tier is inherently asynchronous anyway (font bytes arrive over `fetch` or\n * `queryLocalFonts`), so there is no synchronous path to slow down: the\n * import rides along with the load that was already going to happen, and a\n * bundler splits it into a chunk nobody fetches until large text appears.\n *\n * The other candidate was Typr — smaller, but unmaintained and untyped, and\n * this is a runtime dependency of a published package.\n *\n * ### Coordinate convention\n *\n * `glyph.getPath(0, 0, 1)` already emits exactly what `OutlineFace` promises:\n * font units divided by the em, y flipped to grow downward, and the origin on\n * the baseline at the pen position. That is opentype.js's canvas-rendering\n * convention, and it happens to be the kit's world convention too, so no\n * transform is applied here — a flip would have to be undone downstream.\n */\n\nimport { OUTLINE_PRECISION, type OutlineFace, type OutlineParser } from './OutlineFace';\nimport { sfntFromCollection } from './sfnt';\n\ntype OpenType = typeof import('opentype.js');\n\nlet modulePromise: Promise<OpenType> | null = null;\n\n/** Load (once) and cache the parser module. */\nfunction loadOpenType(): Promise<OpenType> {\n modulePromise ??= import('opentype.js');\n return modulePromise;\n}\n\n/**\n * opentype.js 2.0 publishes ESM under `module` and a UMD bundle under `main`.\n * Only a bundler reads `module`; Node takes the UMD one, whose named exports\n * it cannot detect, so `ns.parse` is `undefined` there and every face fails to\n * load. The registry catches that and degrades to the SDF tier, which is why\n * it looks like nothing is wrong in an app that has an atlas — and why a\n * headless consumer, which has neither, gets no glyphs and no explanation.\n *\n * Exported for the test: the suite resolves through vite, which reads\n * `module` and therefore cannot reproduce the shape that breaks.\n */\nexport function parserOf(ns: OpenType): OpenType['parse'] {\n const interop = ns as OpenType & { default?: OpenType };\n return interop.default?.parse ?? ns.parse;\n}\n\n/**\n * Wrap a parsed opentype.js font.\n *\n * `charToGlyphIndex` reports 0 — `.notdef` — for a codepoint the font does\n * not cover. That is a real glyph (the tofu box) and it renders, so returning\n * its outline would silently substitute a box for a character the atlas tier\n * might have been able to serve. Report the miss instead and let the caller's\n * fallback ladder run.\n */\nfunction faceFor(font: import('opentype.js').Font): OutlineFace {\n const upem = font.unitsPerEm;\n return {\n unitsPerEm: upem,\n ascender: font.ascender / upem,\n advanceOf(cp: number): number | null {\n const index = font.charToGlyphIndex(String.fromCodePoint(cp));\n if (!index) return null;\n return (font.glyphs.get(index).advanceWidth ?? 0) / upem;\n },\n kernOf(left: number, right: number): number {\n const l = font.charToGlyphIndex(String.fromCodePoint(left));\n const r = font.charToGlyphIndex(String.fromCodePoint(right));\n if (!l || !r) return 0;\n return font.getKerningValue(font.glyphs.get(l), font.glyphs.get(r)) / upem;\n },\n glyphD(cp: number): string | null {\n const index = font.charToGlyphIndex(String.fromCodePoint(cp));\n if (!index) return null;\n const d = font.glyphs.get(index).getPath(0, 0, 1).toPathData(OUTLINE_PRECISION);\n // A glyph with no contours (a space) serializes to the empty string.\n // Same answer as a missing glyph from the caller's point of view:\n // nothing to tessellate.\n return d.length > 0 ? d : null;\n },\n };\n}\n\n/**\n * Parse font file bytes into a face. Accepts single fonts and collections\n * (`.ttc`); `postScriptName` picks the member of a collection, and is\n * ignored for a single font.\n */\nexport function createOpenTypeParser(postScriptName?: string): OutlineParser {\n return async (bytes: ArrayBuffer): Promise<OutlineFace> => {\n const parse = parserOf(await loadOpenType());\n const { bytes: single } = sfntFromCollection(bytes, postScriptName);\n return faceFor(parse(single));\n };\n}\n\n/** The parser used when a registration supplies none of its own. */\nexport const openTypeParser: OutlineParser = createOpenTypeParser();\n\n/** @internal Test seam — drop the memoized module so a test can re-import. */\nexport function _resetOpenTypeModuleForTests(): void {\n modulePromise = null;\n}\n","/**\n * The outline tier's registry: which faces have real font bytes behind them,\n * and what a given glyph looks like.\n *\n * ### What this tier is for\n *\n * A distance field is a *sampled* representation. The baked MSDF atlas is\n * generated from outlines and holds up well; the dynamic canvas-SDF tier\n * (`../dynamic/`) reconstructs its field from a 48px raster, so magnifying it\n * past a few times the bake size exposes the raster as contour wobble — bumps\n * one bake-texel apart, ±2–3px at 8×. No bake size fixes that, it only moves\n * the size at which it appears (`glyphRasterizer.ts` measures the tradeoff:\n * error is *minimized at* the bake size, so raising it spoils the 12–32px\n * range where most text lives).\n *\n * Above a size threshold the answer is to stop sampling: parse the font, take\n * the glyph's outline, and hand it to the path renderer the kit already has.\n * Exact at every zoom, and — because a glyph becomes an ordinary path — it\n * takes strokes and non-solid fills for free.\n *\n * Below the threshold the atlas still wins, and not narrowly: outlines carry\n * no hinting and no stem darkening, so body text at 12–16px rendered from\n * them looks *worse* than a platform rasterizer that puts stems on the pixel\n * grid. Two tiers with a size threshold is the standard hybrid, not a\n * compromise.\n *\n * ### Metric neutrality (the load-bearing invariant)\n *\n * This tier replaces how a glyph is *painted*, never where it sits. Advances,\n * kerning, line breaking and baselines all keep coming from whichever tier\n * resolved the run — the baked atlas or the canvas face. That is what lets\n * the threshold be a rendering decision: zooming past it swaps glyph geometry\n * with the layout untouched, so text cannot reflow under the user's cursor,\n * and `measureTextBounds` / `textLineBoxes` need to know nothing about\n * outlines at all.\n *\n * The cost is that a face whose real advances disagree with the atlas's\n * inherits the atlas's. For the bundled Inter that is exact (the subset ships\n * from the same source the atlas was baked from), and for a machine font the\n * outline bytes and the canvas metrics come from the same file.\n *\n * ### Availability\n *\n * Everything here degrades rather than blocks. Bytes arrive over `fetch` or\n * `queryLocalFonts` — asynchronous, and in the local case gated behind a\n * permission the user can refuse — so `glyphOutline` answers `null` until a\n * face is loaded and forever if it failed, and the caller falls back down the\n * ladder to SDF. A family must never render *nothing* because the outline\n * tier could not get bytes.\n */\n\nimport { notifyGlyphReady } from '../glyphReady';\nimport type { OutlineFace, OutlineFontStyle, OutlineParser } from './OutlineFace';\nimport { openTypeParser } from './opentypeParser';\n\n/**\n * Where a face's bytes come from. A URL is fetched; a buffer or blob is used\n * as-is; a thunk is called at first use, which is what lets `queryLocalFonts`\n * results be registered eagerly and read lazily — the permission prompt and\n * the (potentially many megabytes of) blob only happen for a family the\n * document actually sets text in.\n */\nexport type OutlineSource =\n | string\n | ArrayBuffer\n | Blob\n | (() => ArrayBuffer | Blob | Promise<ArrayBuffer | Blob>);\n\n/** Which face within a family to register outlines for. Defaults to weight\n * 400, style `'normal'`. */\nexport interface OutlineVariant {\n weight?: number;\n style?: OutlineFontStyle;\n}\n\n/** Options for registering an outline font. */\nexport interface OutlineFontOptions {\n /** Override the default opentype.js parser. Mostly a test seam; also the\n * hook for a consumer who already has a font parser in their bundle. */\n parser?: OutlineParser;\n}\n\n/** Load state of one registered face. */\nexport type OutlineStatus = 'idle' | 'loading' | 'ready' | 'failed';\n\ninterface FaceSlot {\n family: string;\n weight: number;\n style: OutlineFontStyle;\n source: OutlineSource;\n parser: OutlineParser;\n status: OutlineStatus;\n face: OutlineFace | null;\n /** Memoized `glyphD` answers, including the `null` misses — a codepoint the\n * face lacks is asked for on every frame that draws it, and re-deriving\n * the miss means re-running the cmap lookup forever. */\n glyphs: Map<number, string | null>;\n}\n\nlet slots = new Map<string, FaceSlot>();\n\nfunction slotKey(family: string, weight: number, style: OutlineFontStyle): string {\n return `${family}|${weight}|${style}`;\n}\n\nfunction normalize(v: OutlineVariant): { weight: number; style: OutlineFontStyle } {\n return { weight: v.weight ?? 400, style: v.style ?? 'normal' };\n}\n\n/**\n * Register font file bytes for one face, so text set in it can render from\n * outlines above the size threshold.\n *\n * Registration is cheap and synchronous: nothing is fetched, and the parser\n * is not even imported, until a frame actually asks for a glyph from this\n * face. Registering a face that is never drawn large costs one map entry.\n *\n * The variant must match exactly what the layout tier resolved — this is\n * deliberately *not* a fallback chain. Painting 400-weight outlines at\n * 700-weight advances, or upright outlines where the shader was going to\n * fake an oblique, looks worse than the SDF it replaced; a miss here falls\n * back down the ladder instead, which is always safe.\n */\nexport function registerFontOutlines(\n family: string,\n variant: OutlineVariant,\n source: OutlineSource,\n opts: OutlineFontOptions = {},\n): void {\n const { weight, style } = normalize(variant);\n slots.set(slotKey(family, weight, style), {\n family, weight, style, source,\n parser: opts.parser ?? openTypeParser,\n status: 'idle',\n face: null,\n glyphs: new Map(),\n });\n}\n\n/** Drop a registration. Glyphs already handed out stay valid — they are\n * plain path data — but nothing further resolves from this face. */\nexport function unregisterFontOutlines(family: string, variant: OutlineVariant = {}): void {\n const { weight, style } = normalize(variant);\n slots.delete(slotKey(family, weight, style));\n}\n\n/**\n * Is an outline face registered for this exact variant? Answers `true` while\n * the bytes are still loading — the question is \"could this face serve\n * outlines\", which is what a caller deciding whether to *ask* wants; use\n * `outlineStatus` for the narrower \"can it right now\".\n */\nexport function hasFontOutlines(\n family: string, weight = 400, style: OutlineFontStyle = 'normal',\n): boolean {\n return slots.has(slotKey(family, weight, style));\n}\n\n/** Load state of a registered face; `null` when nothing is registered. */\nexport function outlineStatus(\n family: string, weight = 400, style: OutlineFontStyle = 'normal',\n): OutlineStatus | null {\n return slots.get(slotKey(family, weight, style))?.status ?? null;\n}\n\n/** Every registered outline face and its load state — the enumeration a\n * debug overlay or font picker needs, mirroring `listFonts`. */\nexport function listFontOutlines(): readonly {\n family: string; weight: number; style: OutlineFontStyle; status: OutlineStatus;\n}[] {\n return [...slots.values()]\n .map(({ family, weight, style, status }) => ({ family, weight, style, status }))\n .sort((a, b) => a.family.localeCompare(b.family) || a.weight - b.weight\n || a.style.localeCompare(b.style));\n}\n\n/**\n * Em-space SVG path data for one glyph, or `null` when this tier cannot serve\n * it — no registration, bytes still loading, load failed, no such glyph, or a\n * glyph with no contours.\n *\n * Synchronous by construction: it is called from the per-frame glyph walk, so\n * it can only ever report what is already in hand. The first call for an\n * unloaded face starts the load and returns `null`; when the load lands,\n * `notifyGlyphReady` asks the canvas to draw again and the second frame gets\n * the outline. Same shape as the dynamic tier's deferred bakes.\n */\n/**\n * Close every contour of a glyph's path data.\n *\n * A glyph contour is closed by definition — neither TrueType nor CFF has any\n * other kind — but not every serializer writes the `Z` that says so, and the\n * omission is invisible until someone *strokes* the outline: a fill closes the\n * contour implicitly (earcut joins last point to first), while a stroke\n * follows exactly the path it is handed and leaves the closing edge unpainted,\n * with a cap at each loose end. That showed up as glyphs missing part of their\n * outline along long straight edges, which is where a contour's seam usually\n * falls.\n *\n * Normalized here rather than in one parser because the same hole is open to\n * every consumer-supplied `OutlineParser`, and a contract that says \"closed\"\n * is cheaper to guarantee than to document.\n */\nexport function closeContours(d: string): string {\n let out = '';\n let start = 0;\n for (let i = 1; i < d.length; i++) {\n const c = d[i];\n if (c !== 'M' && c !== 'm') continue;\n out += closeOne(d.slice(start, i));\n start = i;\n }\n return out + closeOne(d.slice(start));\n}\n\nfunction closeOne(contour: string): string {\n const trimmed = contour.trimEnd();\n if (trimmed.length === 0) return '';\n const last = trimmed[trimmed.length - 1];\n return last === 'Z' || last === 'z' ? trimmed : `${trimmed}Z`;\n}\n\n/**\n * Em-space SVG path data for one glyph of a registered outline face, or `null`\n * when there is nothing to draw.\n *\n * Synchronous and non-throwing by design: a face that has not been parsed yet\n * starts loading and answers `null` for now, so a renderer can call this every\n * frame and simply fall through to another text tier until the outline\n * arrives. Results are cached per codepoint.\n */\nexport function glyphOutline(\n family: string,\n weight: number,\n style: OutlineFontStyle,\n cp: number,\n): string | null {\n const slot = slots.get(slotKey(family, weight, style));\n if (!slot) return null;\n if (slot.status === 'idle') {\n void beginLoad(slot);\n return null;\n }\n if (slot.status !== 'ready') return null;\n\n const cached = slot.glyphs.get(cp);\n if (cached !== undefined) return cached;\n let d: string | null = null;\n try {\n const raw = slot.face!.glyphD(cp);\n d = raw === null ? null : closeContours(raw);\n } catch (err) {\n // A parser that throws on one glyph should cost that glyph, not the face.\n warnOnce(`glyph|${slotKey(family, weight, style)}`,\n `weasel: outline face \"${family}\" (${weight}/${style}) could not produce a glyph ` +\n `for U+${cp.toString(16).toUpperCase().padStart(4, '0')} — ` +\n `${err instanceof Error ? err.message : String(err)}. Falling back to the SDF tier.`);\n }\n slot.glyphs.set(cp, d);\n return d;\n}\n\n/**\n * Metrics for a registered outline face, or `null` when this tier cannot\n * supply them yet — nothing registered, bytes still loading, or a failed load.\n *\n * The face is the *only* metrics source for a family that has no atlas, which\n * is the case this exists for: without it such a family cannot lay out at all.\n * It does not disturb metric neutrality — a family that has an atlas resolves\n * to the atlas long before anything asks here, so registering outlines still\n * cannot move text that was already rendering.\n *\n * Starts the load on a first call and answers `null` for now, exactly like\n * `glyphOutline`, so a per-frame caller falls through and picks it up on the\n * frame after the bytes land.\n */\nexport function outlineMetrics(\n family: string,\n weight: number,\n style: OutlineFontStyle,\n): OutlineFace | null {\n const slot = slots.get(slotKey(family, weight, style));\n if (!slot) return null;\n if (slot.status === 'idle') {\n void beginLoad(slot);\n return null;\n }\n return slot.status === 'ready' ? slot.face! : null;\n}\n\nasync function beginLoad(slot: FaceSlot): Promise<void> {\n slot.status = 'loading';\n try {\n slot.face = await slot.parser(await readSource(slot.source));\n slot.status = 'ready';\n // The frame that asked for these glyphs has long since drawn. Without\n // this the outlines sit in memory until something else invalidates the\n // canvas, which on a static document is \"never\".\n notifyGlyphReady();\n } catch (err) {\n slot.status = 'failed';\n warnOnce(`load|${slotKey(slot.family, slot.weight, slot.style)}`,\n `weasel registerFontOutlines(\"${slot.family}\" ${slot.weight}/${slot.style}): ` +\n `${err instanceof Error ? err.message : String(err)}. Large text in this face ` +\n `keeps rendering from the SDF tier.`);\n }\n}\n\nasync function readSource(source: OutlineSource): Promise<ArrayBuffer> {\n const resolved = typeof source === 'function' ? await source() : source;\n if (typeof resolved === 'string') {\n const res = await fetch(resolved);\n if (!res.ok) throw new Error(`HTTP ${res.status} fetching ${resolved}`);\n return res.arrayBuffer();\n }\n if (resolved instanceof ArrayBuffer) return resolved;\n return resolved.arrayBuffer();\n}\n\n// Loading and glyph lookup both run off the render loop, so an unguarded warn\n// would repeat every frame.\nconst warned = new Set<string>();\n\nfunction warnOnce(key: string, message: string): void {\n if (warned.has(key)) return;\n warned.add(key);\n console.warn(message);\n}\n\n/** @internal Test seam — registry and warn-once keys are module state. */\nexport function _resetFontOutlinesForTests(): void {\n slots = new Map();\n warned.clear();\n}\n","/**\n * FontRegistry and registerFont() public API.\n *\n * Variants are keyed by (family, weight, style). registerFont() takes a\n * FontVariant alongside the family and the two URLs; the registry stores\n * entries in a two-level Map so resolveFontVariant() can iterate a family's\n * variants for the fallback chain.\n */\n\nimport { notifyGlyphReady } from './glyphReady';\nimport { parseBmFont, type BmFont } from './FontAtlas';\nimport type { GlyphTextureSink } from './textureSink';\nimport {\n isCanvasFont, isExplicitCanvasFont, autoEnrollCanvasFont, getDynamicFace,\n type DynamicFace,\n} from './dynamic/dynamicAtlas';\nimport {\n getFontFallbackPolicy, getDefaultFontFamily,\n claimFallbackWarning, _clearFallbackWarnings,\n} from './fallback';\nimport { outlineMetrics } from './outline/outlineRegistry';\nimport type { OutlineFace } from './outline/OutlineFace';\n\n/** A registered face: its parsed metrics and the atlas image to sample. */\nexport interface FontEntry {\n font: BmFont;\n bitmap: ImageBitmap;\n}\n\n/** Which face within a family. Defaults to weight 400, style `'normal'`. */\nexport interface FontVariant {\n weight?: number;\n style?: 'normal' | 'italic';\n}\n\ntype FontStyle = 'normal' | 'italic';\n\nlet registry = new Map<string, Map<string, FontEntry>>();\n\nfunction variantKey(weight: number, style: FontStyle): string {\n return `${weight}|${style}`;\n}\n\nfunction normalizeVariant(v: FontVariant): { weight: number; style: FontStyle } {\n return {\n weight: v.weight ?? 400,\n style: v.style ?? 'normal',\n };\n}\n\n/** Test helper. Do not call from product code. */\nexport function _resetFontRegistryForTests(): void {\n registry = new Map();\n _clearFallbackWarnings();\n}\n\n/** Exact lookup — does NOT walk the fallback chain. Use `resolveFontVariant` for that. */\nexport function getFont(\n family: string,\n weight: number = 400,\n style: FontStyle = 'normal',\n): FontEntry | null {\n return registry.get(family)?.get(variantKey(weight, style)) ?? null;\n}\n\n/** One family in the registry and the variants registered for it — what a\n * font picker can honestly offer. */\nexport interface RegisteredFont {\n family: string;\n variants: readonly { weight: number; style: FontStyle }[];\n}\n\n/**\n * Enumerate the registry — what a font picker can honestly offer. Families\n * come back in registration order; variants sorted by weight, then style, so\n * the output is stable enough to assert against.\n */\nexport function listFonts(): readonly RegisteredFont[] {\n const out: RegisteredFont[] = [];\n for (const [family, variantMap] of registry) {\n const variants = [...variantMap.keys()]\n .map((key) => {\n const [w, s] = key.split('|') as [string, FontStyle];\n return { weight: Number(w), style: s };\n })\n .sort((a, b) => a.weight - b.weight || a.style.localeCompare(b.style));\n out.push({ family, variants });\n }\n return out;\n}\n\n/**\n * Fetch a baked MSDF atlas and its metrics, and register them as one variant\n * of `family`. Resolves once the face is usable; re-registering a variant that\n * is already present is a no-op.\n */\nexport async function registerFont(\n family: string,\n variant: FontVariant,\n metricsUrl: string,\n atlasUrl: string,\n): Promise<void> {\n const { weight, style } = normalizeVariant(variant);\n const key = variantKey(weight, style);\n\n if (registry.get(family)?.has(key)) return;\n\n try {\n const [metricsRes, atlasRes] = await Promise.all([\n fetch(metricsUrl),\n fetch(atlasUrl),\n ]);\n\n if (!metricsRes.ok) {\n throw new Error(`HTTP ${metricsRes.status} fetching metrics from ${metricsUrl}`);\n }\n if (!atlasRes.ok) {\n throw new Error(`HTTP ${atlasRes.status} fetching atlas from ${atlasUrl}`);\n }\n\n const [rawJson, blob] = await Promise.all([\n metricsRes.json(),\n atlasRes.blob(),\n ]);\n\n const font = parseBmFont(rawJson);\n const bitmap = await createImageBitmap(blob);\n\n // Re-read the registry here (not the pre-await snapshot): concurrent\n // registerFont() calls for other variants of the same family (e.g. the\n // 400/700 weights registered together in Promise.all) may have created\n // the family's Map while this call was awaiting its fetch. Reusing a\n // stale local reference would recreate the Map and silently drop\n // whichever variant's registerFont() resolved first.\n let familyMap = registry.get(family);\n if (!familyMap) {\n familyMap = new Map();\n registry.set(family, familyMap);\n }\n familyMap.set(key, { font, bitmap });\n // Same meaning the lazy tiers give it: text that was painting from a\n // fallback face — or painting nothing — can now paint from this one. The\n // early return above covers the already-registered case, so this fires\n // once per variant that actually lands.\n notifyGlyphReady();\n } catch (err) {\n throw new Error(\n `weasel registerFont(\"${family}\" ${weight}/${style}): ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n}\n\n/**\n * Ensure the atlas for `(family, weight, style)` is uploaded to\n * `textureCache`. Cache key is `${family}|${weight}|${style}` so each\n * variant occupies its own texture slot.\n */\nexport function ensureFontTexture(\n family: string,\n weight: number,\n style: FontStyle,\n textureCache: GlyphTextureSink,\n): boolean {\n const entry = getFont(family, weight, style);\n if (!entry) return false;\n textureCache.upload(textureCacheKey(family, weight, style), entry.bitmap);\n return true;\n}\n\n/** The texture cache key used by `ensureFontTexture` for a given variant. */\nexport function textureCacheKey(family: string, weight: number, style: FontStyle): string {\n return `${family}|${weight}|${style}`;\n}\n\n/** Kept as a no-op for context-restore call sites; per-cache dedup handles it now. */\nexport function markAllFontsNotUploaded(): void {}\n\n/** What `resolveFontVariant` found: the atlas to draw with, the face it\n * actually landed on after walking the fallback chain, and what has to be\n * synthesized to cover the difference. */\nexport interface ResolveResult {\n entry: FontEntry | null;\n /**\n * The (family, weight, style) triple that was actually matched. May differ\n * from the requested values when the resolver walked the fallback chain —\n * including `family`, when the cross-family policy substituted a default.\n *\n * This is the atlas identity: pass all three to `getFont` /\n * `textureCacheKey` and the lookup hits. Describing only weight and style\n * here once let a caller key its draw on the *requested* family, which\n * resolves to no atlas at all and paints nothing.\n *\n * The synthetic flags describe the gap between requested and resolved for\n * shader-side compensation. When `entry` is null, these mirror the\n * requested values.\n */\n resolved: { family: string; weight: number; style: FontStyle };\n synthetic: { bold: boolean; italic: boolean };\n /** Which tier resolved: a baked MSDF atlas, the runtime canvas-SDF dynamic\n * atlas, or a parsed font face serving both geometry and metrics. Misses\n * report 'atlas' (the default tier). */\n source: 'atlas' | 'canvas' | 'outline';\n /** Set only when source === 'canvas': the dynamic face whose BmFont-shaped\n * `font` layoutRuns consumes in place of `entry.font`. */\n dynamicFace?: DynamicFace;\n /** Set only when source === 'outline': the parsed face supplying advances,\n * kerning and the baseline. There is no atlas behind this tier, so it is\n * the only metrics source the run has. */\n outlineFace?: OutlineFace;\n /**\n * Set when the requested family was not registered and the fallback policy\n * substituted a different one. Reported structurally so a UI can say\n * \"Inter — not loaded, showing Roboto\" instead of leaving the user to\n * wonder why the family control did nothing.\n */\n substituted?: { requested: string; resolved: string };\n}\n\nfunction missResolveResult(\n family: string, weight: number, style: FontStyle, suppressWarn = false,\n): ResolveResult {\n // Canvas-dynamic tier: reached only when the fallback chain selected no\n // baked variant, so any selected baked match always wins. Dynamic faces\n // rasterize the real weight/style — no synthetic flags.\n //\n // Explicit enrollment only. A family the `'canvas'` policy enrolled for\n // itself must not keep routing here after the policy changes, or `'none'`\n // could never restore the hard miss it documents once any family had been\n // auto-enrolled.\n if (isExplicitCanvasFont(family)) {\n return {\n entry: null,\n dynamicFace: getDynamicFace(family, weight, style),\n resolved: { family, weight, style },\n synthetic: { bold: false, italic: false },\n source: 'canvas',\n };\n }\n\n // Outline-only: a family with parsed font bytes and no atlas. Ranked above\n // every fallback below because it is the *real* face — exact geometry and\n // the font's own advances — where the alternatives are a resampled raster\n // or a different typeface. Below explicit canvas enrollment, which is a\n // consumer saying which tier it wants for this family.\n const face = outlineMetrics(family, weight, style === 'italic' ? 'italic' : 'normal');\n if (face) {\n return {\n entry: null,\n outlineFace: face,\n resolved: { family, weight, style },\n synthetic: { bold: false, italic: false },\n source: 'outline',\n };\n }\n\n const policy = getFontFallbackPolicy();\n\n if (policy === 'canvas') {\n // Auto-enroll: the browser probably has this family even though no atlas\n // was baked for it. Real typeface, canvas-SDF quality.\n autoEnrollCanvasFont(family);\n return {\n entry: null,\n dynamicFace: getDynamicFace(family, weight, style),\n resolved: { family, weight, style },\n synthetic: { bold: false, italic: false },\n source: 'canvas',\n };\n }\n\n if (policy === 'substitute') {\n const fallback = getDefaultFontFamily() ?? firstRegisteredFamily();\n // Guard against recursing when the default family is itself unknown.\n // Canvas families never enter `registry`, so membership there alone would\n // reject `setDefaultFontFamily` pointed at one. `isCanvasFont` answers\n // \"served by the dynamic tier right now\", which is the question here: a\n // family the `'canvas'` policy auto-enrolled is not served under this\n // policy, so substituting *to* it would report a swap that paints nothing.\n if (fallback !== null && fallback !== family) {\n if (registry.has(fallback) || isCanvasFont(fallback)) {\n // Probing whether the fallback family renders, not resolving a\n // top-level request for it — suppress so this recursion can't also\n // land in the `fallback === family` branch below (the fallback\n // family's own default is itself) and double-warn for one miss.\n // Whichever of `warnMissingFamilyOnce` / `warnUnusableDefaultOnce`\n // fires below, based on this probe's result, is the single warning.\n const result = resolveFontVariantInternal(fallback, weight, style, true);\n // Renderable, not baked: a fallback served by the dynamic tier reports\n // `entry: null` with a dynamicFace, and testing entry alone threw it away.\n if (result.entry !== null || result.dynamicFace !== undefined) {\n if (!suppressWarn) warnMissingFamilyOnce(family, weight, style, fallback);\n return { ...result, substituted: { requested: family, resolved: fallback } };\n }\n }\n // Substitution was supposed to happen and produced nothing. Falling\n // through silently here is the invisible-text failure this whole policy\n // exists to eliminate, so say which of the two families to fix.\n if (!suppressWarn) warnUnusableDefaultOnce(family, weight, style, fallback);\n } else if (fallback === family && !suppressWarn) {\n // `fallback === family` above exists to stop the request from\n // substituting for itself — recursion into the same miss forever. But\n // when the family that can't serve this variant *is* the effective\n // default, that guard also throws away the one case it was most likely\n // to hit: a default registered at the wrong variant. Nothing renders\n // and, without this branch, nothing is logged either.\n // `suppressWarn` keeps this from firing when a *different* top-level\n // request's substitution probe happens to recurse into the default\n // family and find it can't serve either — that miss is reported by the\n // top-level caller via `warnUnusableDefaultOnce`, not from in here.\n if (registry.has(family)) {\n warnSelfUnusableDefaultOnce(family, weight, style);\n } else {\n // Unregistered, yet still the effective default: the default can only\n // have been named explicitly, because the implicit one is the first\n // *registered* family (and with nothing registered at all, `fallback`\n // is null and never equals `family`). So this is a real\n // misconfiguration — someone pointed setDefaultFontFamily at a family\n // that does not exist — and not the deliberately-silent case of an app\n // that simply hasn't loaded any fonts yet.\n warnUnregisteredDefaultOnce(family, weight, style);\n }\n }\n }\n\n return {\n entry: null,\n resolved: { family, weight, style },\n synthetic: { bold: false, italic: false },\n source: 'atlas',\n };\n}\n\n/** Insertion order of the registry Map — the first family an app registered. */\nfunction firstRegisteredFamily(): string | null {\n for (const family of registry.keys()) return family;\n return null;\n}\n\n// Resolution runs per frame, so an unguarded warn would flood the console.\n// Keyed per (family, weight, style) variant, not per family: each variant is a\n// distinct thing the app asked for and failed to get. The claimed keys live in\n// fallback.ts so both reset seams clear them.\nfunction warnMissingFamilyOnce(\n family: string, weight: number, style: FontStyle, resolved: string,\n): void {\n if (!claimFallbackWarning(`substituted|${family}|${weight}|${style}`)) return;\n // Two distinct failures land here. Saying \"not registered\" for a family\n // that IS registered — just not in a variant the within-family chain can\n // reach — sends the reader hunting for a registerFont call that already\n // exists. Name the actual gap so the fix is the obvious one.\n const cause = registry.has(family)\n ? `has no variant matching ${weight}/${style}, and none of its registered ` +\n `variants are close enough for the within-family chain to substitute — ` +\n `rendering with \"${resolved}\" instead. Bake that variant with ` +\n `registerFont(\"${family}\", { weight: ${weight}, style: '${style}' }, …)`\n : `is not registered — rendering with \"${resolved}\" instead. ` +\n `Call registerFont(\"${family}\", …)`;\n console.warn(\n `weasel: font family \"${family}\" (${weight}/${style}) ${cause}. ` +\n `Advance widths will differ from the requested font. Use ` +\n `setFontFallbackPolicy('none') to make this a hard miss instead.`,\n );\n}\n\n/**\n * The substitute policy engaged and still came up empty. Distinct from\n * `warnMissingFamilyOnce`, which reports a *successful* swap: here nothing\n * renders, and the fix is almost always in the fallback family rather than\n * the requested one — so name it, and say which way it was chosen.\n */\nfunction warnUnusableDefaultOnce(\n family: string, weight: number, style: FontStyle, fallback: string,\n): void {\n if (!claimFallbackWarning(`unusable-default|${family}|${weight}|${style}`)) return;\n const origin = getDefaultFontFamily() === fallback\n ? 'set via setDefaultFontFamily'\n : 'the first registered family, since setDefaultFontFamily was never called';\n // Same policy-aware question as the substitution guard: a fallback the\n // `'canvas'` policy auto-enrolled has nothing serving it under this policy,\n // so \"has no variant\" would send the reader looking for a variant to bake\n // when the family has no atlas at all.\n const gap = registry.has(fallback) || isCanvasFont(fallback)\n ? `has no variant that can serve ${weight}/${style}`\n : 'is not registered either';\n console.warn(\n `weasel: font family \"${family}\" (${weight}/${style}) is not available, and ` +\n `the fallback family \"${fallback}\" (${origin}) ${gap} — this text will not ` +\n `render at all. Bake that variant with registerFont(\"${fallback}\", ` +\n `{ weight: ${weight}, style: '${style}' }, …), or point ` +\n `setDefaultFontFamily() at a family that covers it.`,\n );\n}\n\n/**\n * The requested family is also the effective default — there is nowhere left\n * to fall back to. Distinct from `warnUnusableDefaultOnce`, which names a\n * *different* fallback family to fix; here the requested and fallback\n * families are the same one, so repeating the name the way that message does\n * would read as nonsense (\"X is not available, and the fallback X … \").\n * Named once, with both facts — registered-but-wrong-variant, and also the\n * fallback — folded into a single sentence.\n */\nfunction warnSelfUnusableDefaultOnce(\n family: string, weight: number, style: FontStyle,\n): void {\n if (!claimFallbackWarning(`self-unusable-default|${family}|${weight}|${style}`)) return;\n const origin = getDefaultFontFamily() === family\n ? 'set via setDefaultFontFamily'\n : 'the first registered family, since setDefaultFontFamily was never called';\n console.warn(\n `weasel: font family \"${family}\" (${weight}/${style}) has no variant that can ` +\n `serve this request, and \"${family}\" is also the fallback family (${origin}) — ` +\n `there is nothing left to fall back to, so this text will not render at all. ` +\n `Bake that variant with registerFont(\"${family}\", { weight: ${weight}, ` +\n `style: '${style}' }, …), or point setDefaultFontFamily() at a different family.`,\n );\n}\n\n/**\n * The requested family is the explicitly set default, and that default names\n * a family that was never registered at all. Distinct from\n * `warnSelfUnusableDefaultOnce`, which reports a default that *is* registered\n * but not in a variant that can serve the request: there the fix is to bake a\n * variant, here the family has no atlas whatsoever, so pointing the reader at\n * a missing variant would send them looking for a `registerFont` call to\n * amend rather than one to write.\n */\nfunction warnUnregisteredDefaultOnce(\n family: string, weight: number, style: FontStyle,\n): void {\n if (!claimFallbackWarning(`unregistered-default|${family}|${weight}|${style}`)) return;\n console.warn(\n `weasel: font family \"${family}\" (${weight}/${style}) was never registered, and ` +\n `it is also the fallback family — setDefaultFontFamily(\"${family}\") names a ` +\n `family with no registered variants at all, so there is nothing left to fall ` +\n `back to and this text will not render at all. Call registerFont(\"${family}\", ` +\n `{ weight: ${weight}, style: '${style}' }, …), or point setDefaultFontFamily() ` +\n `at a family you have registered.`,\n );\n}\n\nfunction weightBucket(w: number): 'regular' | 'bold' {\n return w >= 600 ? 'bold' : 'regular';\n}\n\n/**\n * Resolve a `(family, weight, style)` request to a registered font entry,\n * walking the fallback chain when an exact match isn't available. Returns\n * synthetic flags describing the gap between requested and resolved so the\n * renderer can apply SDF-thicken / vertex-skew fakes.\n */\nexport function resolveFontVariant(\n family: string,\n weight: number,\n style: FontStyle,\n): ResolveResult {\n return resolveFontVariantInternal(family, weight, style, false);\n}\n\n/**\n * Escalate a *single codepoint* to the dynamic tier when the atlas that\n * resolved for the run has no glyph for it.\n *\n * `resolveFontVariant` answers at family granularity: it picks one tier for a\n * whole run. But a baked MSDF atlas covers a fixed charset, so a run served by\n * a perfectly good atlas can still contain a character that atlas never baked\n * — an em dash, a curly quote, anything outside the subset. The dynamic tier\n * rasterizes on demand from installed fonts and can serve exactly those.\n *\n * Returns a canvas-tier `ResolveResult` whose `dynamicFace` the caller drives\n * with `requestGlyph(cp)`, or `null` when escalation isn't available:\n *\n * - Policy `'none'` documents a miss as a *hard* miss. Quietly reaching for\n * another tier per codepoint would undo that, so it doesn't.\n * - No canvas to rasterize into (SSR, a jsdom test without one) makes the\n * dynamic tier constructible-but-broken; `getDynamicFace` throws and this\n * reports the miss instead of taking the caller down with it.\n *\n * Cheap to call per missing codepoint: faces are cached by variant and glyphs\n * by codepoint, so a repeat is two map lookups.\n */\nexport function resolveGlyphFallback(\n family: string,\n weight: number,\n style: FontStyle,\n): ResolveResult | null {\n if (getFontFallbackPolicy() === 'none') return null;\n try {\n return {\n entry: null,\n dynamicFace: getDynamicFace(family, weight, style),\n resolved: { family, weight, style },\n // The dynamic tier rasterizes the real weight and style, so there is\n // nothing for the shader to fake.\n synthetic: { bold: false, italic: false },\n source: 'canvas',\n };\n } catch {\n return null;\n }\n}\n\n/**\n * `suppressWarn` is set only by the recursive substitution probe in\n * `missResolveResult`, which resolves the fallback family purely to check\n * whether it renders. That probe is not itself a request anything asked\n * for, so it must not emit — or claim the warn-once key for — a message\n * about a resolution the caller never made; the caller's own top-level\n * `missResolveResult` call decides, from the probe's result, which single\n * warning (if any) describes the overall miss.\n */\nfunction resolveFontVariantInternal(\n family: string,\n weight: number,\n style: FontStyle,\n suppressWarn: boolean,\n): ResolveResult {\n const familyMap = registry.get(family);\n if (!familyMap || familyMap.size === 0) {\n return missResolveResult(family, weight, style, suppressWarn);\n }\n\n // 1. Exact match\n const exact = familyMap.get(variantKey(weight, style));\n if (exact) {\n return {\n entry: exact,\n resolved: { family, weight, style },\n synthetic: { bold: false, italic: false },\n source: 'atlas',\n };\n }\n\n // 2. Same style, nearest weight in same bucket (ties broken by higher weight)\n const requestedBucket = weightBucket(weight);\n let bestSameStyle: { entry: FontEntry; weight: number; distance: number } | null = null;\n for (const [key, entry] of familyMap) {\n const [wStr, s] = key.split('|') as [string, FontStyle];\n const w = Number(wStr);\n if (s !== style) continue;\n if (weightBucket(w) !== requestedBucket) continue;\n const distance = Math.abs(w - weight);\n if (\n bestSameStyle === null ||\n distance < bestSameStyle.distance ||\n (distance === bestSameStyle.distance && w > bestSameStyle.weight)\n ) {\n bestSameStyle = { entry, weight: w, distance };\n }\n }\n if (bestSameStyle) {\n return {\n entry: bestSameStyle.entry,\n resolved: { family, weight: bestSameStyle.weight, style },\n synthetic: { bold: false, italic: false },\n source: 'atlas',\n };\n }\n\n // 3. (family, 400, style)\n const sameStyleRegular = familyMap.get(variantKey(400, style));\n if (sameStyleRegular) {\n return {\n entry: sameStyleRegular,\n resolved: { family, weight: 400, style },\n synthetic: {\n bold: weight >= 600,\n italic: false,\n },\n source: 'atlas',\n };\n }\n\n // 4. (family, weight, 'normal') — same weight, no italic\n const sameWeightNormal = familyMap.get(variantKey(weight, 'normal'));\n if (sameWeightNormal) {\n return {\n entry: sameWeightNormal,\n resolved: { family, weight, style: 'normal' },\n synthetic: {\n bold: false,\n italic: style === 'italic',\n },\n source: 'atlas',\n };\n }\n\n // 4b. Nearest weight, normal style, same bucket\n let bestNormal: { entry: FontEntry; weight: number; distance: number } | null = null;\n for (const [key, entry] of familyMap) {\n const [wStr, s] = key.split('|') as [string, FontStyle];\n const w = Number(wStr);\n if (s !== 'normal') continue;\n if (weightBucket(w) !== requestedBucket) continue;\n const distance = Math.abs(w - weight);\n if (\n bestNormal === null ||\n distance < bestNormal.distance ||\n (distance === bestNormal.distance && w > bestNormal.weight)\n ) {\n bestNormal = { entry, weight: w, distance };\n }\n }\n if (bestNormal) {\n return {\n entry: bestNormal.entry,\n resolved: { family, weight: bestNormal.weight, style: 'normal' },\n synthetic: {\n bold: false,\n italic: style === 'italic',\n },\n source: 'atlas',\n };\n }\n\n // 5. (family, 400, 'normal') — last resort within family\n const regular = familyMap.get(variantKey(400, 'normal'));\n if (regular) {\n return {\n entry: regular,\n resolved: { family, weight: 400, style: 'normal' },\n synthetic: {\n bold: weight >= 600,\n italic: style === 'italic',\n },\n source: 'atlas',\n };\n }\n\n return missResolveResult(family, weight, style, suppressWarn);\n}\n"]}