procedural-paper 0.0.0-stage → 0.1.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.
Files changed (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +205 -2
  3. package/THIRD_PARTY_NOTICES.md +51 -0
  4. package/dist/cards.d.ts +42 -0
  5. package/dist/color.d.ts +5 -0
  6. package/dist/composition/assets.d.ts +7 -0
  7. package/dist/composition/cords.d.ts +43 -0
  8. package/dist/composition/filters.d.ts +1 -0
  9. package/dist/composition/fit.d.ts +58 -0
  10. package/dist/composition/index.d.ts +27 -0
  11. package/dist/composition/index.js +1247 -0
  12. package/dist/composition/index.js.map +1 -0
  13. package/dist/composition/model.d.ts +72 -0
  14. package/dist/composition/motion-spec.d.ts +98 -0
  15. package/dist/composition/motion.d.ts +36 -0
  16. package/dist/composition/motion.js +291 -0
  17. package/dist/composition/motion.js.map +1 -0
  18. package/dist/composition/nodes.d.ts +7 -0
  19. package/dist/composition/pen.d.ts +6 -0
  20. package/dist/composition/photos.d.ts +41 -0
  21. package/dist/composition/props.d.ts +32 -0
  22. package/dist/composition/react.d.ts +10 -0
  23. package/dist/composition/react.js +22 -0
  24. package/dist/composition/react.js.map +1 -0
  25. package/dist/composition/renderer.d.ts +77 -0
  26. package/dist/composition/rng.d.ts +11 -0
  27. package/dist/composition/scene.d.ts +77 -0
  28. package/dist/composition/unrotate.d.ts +3 -0
  29. package/dist/composition.css +78 -0
  30. package/dist/cpu/compose.d.ts +7 -0
  31. package/dist/cpu/field.d.ts +10 -0
  32. package/dist/cpu/noise.d.ts +7 -0
  33. package/dist/cpu/overlays.d.ts +12 -0
  34. package/dist/cpu/renderer.d.ts +16 -0
  35. package/dist/cpu/strands.d.ts +33 -0
  36. package/dist/dom.d.ts +110 -0
  37. package/dist/dom.js +65 -0
  38. package/dist/dom.js.map +1 -0
  39. package/dist/export.d.ts +20 -0
  40. package/dist/gl/renderer.d.ts +61 -0
  41. package/dist/gl/shaders.d.ts +10 -0
  42. package/dist/gl/sheet-shader.d.ts +1 -0
  43. package/dist/hash.d.ts +12 -0
  44. package/dist/index.d.ts +73 -0
  45. package/dist/index.js +2415 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/params.d.ts +169 -0
  48. package/dist/presets.d.ts +11 -0
  49. package/dist/react.d.ts +20 -0
  50. package/dist/react.js +50 -0
  51. package/dist/react.js.map +1 -0
  52. package/dist/resolve.d.ts +125 -0
  53. package/dist/sheet.d.ts +167 -0
  54. package/dist/stocks.d.ts +12 -0
  55. package/dist/styles.css +13 -0
  56. package/licenses/Apache-2.0.txt +201 -0
  57. package/package.json +116 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../src/composition/fit.ts","../../src/composition/cords.ts","../../src/composition/props.ts","../../src/composition/renderer.ts","../../src/composition/photos.ts","../../src/composition/nodes.ts","../../src/composition/assets.ts","../../src/composition/filters.ts","../../src/composition/rng.ts","../../src/composition/model.ts","../../src/composition/index.ts"],"sourcesContent":["/**\n * Fit card text to its box with @chenglou/pretext: text is measured once per\n * block (canvas, real font), then line counts at any size come from pure\n * arithmetic, so we can binary-search the largest size that fits without\n * touching the DOM. On ruled paper the line pitch is fixed, so we shrink a\n * little and then drop trailing items instead.\n */\nimport { layout, prepare, type PreparedText } from '@chenglou/pretext';\nexport interface Font { family: string; size: number; kind: 'hand' | 'mono'; marker?: boolean; weight?: string }\n\nexport interface FitBlock {\n /** Plain text used for measuring (and rendering, unless `html` is given). */\n text: string;\n /** Rendered markup when it differs from `text` (e.g. typewriter spans). */\n html?: string;\n /** Size relative to the block's base size (em). */\n scale?: number;\n /** Extra space above the block (em of its own size). */\n gap?: number;\n /** Letter-spacing in em. */\n spacing?: number;\n cls?: string;\n /** Font weight for this block (defaults to the spec's). */\n weight?: string;\n /** Only the first block is kept... unless this is set (titles, signatures stay). */\n keep?: boolean;\n}\n\nexport interface FitSpec {\n font: Font;\n weight?: string;\n /** Box in px. */\n width: number;\n height: number;\n /** Largest / smallest font size in px (final, after the font's own size factor). */\n max: number;\n min: number;\n /** Line height as a multiple of the font size... */\n lineHeight?: number;\n /** ...or a fixed pitch in px (ruled paper). */\n pitch?: number;\n whiteSpace?: 'normal' | 'pre-wrap';\n /** Drop trailing blocks when even `min` doesn't fit (default true). */\n drop?: boolean;\n /** Never wrap past this many lines (labels, one-liners). */\n maxLines?: number;\n /** Vertical writing mode: width/height describe the inline/block axes. */\n vertical?: boolean;\n blocks: FitBlock[];\n}\n\nexport interface FitResult {\n size: number;\n kept: number;\n lines: number;\n}\n\nconst REF = 100;\nconst loaded = new Map<string, Promise<unknown>>();\nconst prepared = new Map<string, PreparedText>();\n\nfunction fontString(f: Font, weight: string, px: number) {\n return `${weight} ${px}px \"${f.family}\"`;\n}\n\nfunction ensureFont(f: Font, weight: string) {\n const key = `${weight} ${f.family}`;\n let p = loaded.get(key);\n if (!p) {\n p = document.fonts.load(fontString(f, weight, 20), 'abc ☐☑').catch(() => undefined);\n loaded.set(key, p);\n }\n return p;\n}\n\nfunction prep(text: string, f: Font, weight: string, spacingEm: number, ws: 'normal' | 'pre-wrap') {\n const key = `${f.family}|${weight}|${spacingEm}|${ws}|${text}`;\n let p = prepared.get(key);\n if (!p) {\n p = prepare(text, fontString(f, weight, REF), { whiteSpace: ws, letterSpacing: spacingEm * REF });\n prepared.set(key, p);\n }\n return p;\n}\n\n/** Text widths scale linearly with size, so measure once at 100px and rescale the box. */\nfunction measure(spec: FitSpec, size: number, count: number) {\n const weight = spec.weight ?? '400';\n const ws = spec.whiteSpace ?? 'normal';\n let h = 0, lines = 0;\n for (let i = 0; i < count; i++) {\n const b = spec.blocks[i];\n const s = size * (b.scale ?? 1);\n const p = prep(b.text, spec.font, b.weight ?? weight, b.spacing ?? 0, ws);\n const n = b.text ? layout(p, (spec.width * REF) / s, 1).lineCount : 1;\n const lh = spec.pitch ?? s * (spec.lineHeight ?? 1.2);\n h += n * lh + (b.gap ?? 0) * s;\n lines += n;\n }\n return { h, lines };\n}\n\nexport async function fitText(spec: FitSpec): Promise<FitResult> {\n await Promise.all([spec.weight ?? '400', ...spec.blocks.map((b) => b.weight).filter(Boolean)].map((w) => ensureFont(spec.font, w!)));\n const fits = (size: number, count: number) => {\n const m = measure(spec, size, count);\n return m.h <= spec.height + 0.5 && (spec.maxLines === undefined || m.lines <= spec.maxLines);\n };\n let count = spec.blocks.length;\n // drop trailing optional blocks until the text fits at the minimum size\n if (spec.drop !== false) {\n while (count > 1 && !fits(spec.min, count)) {\n let i = count - 1;\n while (i > 0 && spec.blocks[i].keep) i--;\n if (i === 0) break;\n spec.blocks.splice(i, 1);\n count--;\n }\n }\n let lo = spec.min, hi = spec.max;\n if (fits(hi, count)) lo = hi;\n else\n for (let k = 0; k < 14; k++) {\n const mid = (lo + hi) / 2;\n if (fits(mid, count)) lo = mid;\n else hi = mid;\n }\n const size = Math.floor(lo * 4) / 4;\n return { size, kept: count, lines: measure(spec, size, count).lines };\n}\n\n// ---------------------------------------------------------------- DOM glue\n\nconst esc = (s: string) => s.replace(/&/g, '&amp;').replace(/</g, '&lt;');\nexport const fitSpecs = new WeakMap<HTMLElement, FitSpec>();\nconst jobs = new WeakMap<HTMLElement, FitSpec>();\n\nexport function blocksHTML(blocks: FitBlock[]) {\n return blocks\n .map((b) => {\n const st = [b.scale && b.scale !== 1 ? `font-size:${b.scale}em` : '', b.gap ? `margin-top:${b.gap}em` : '', b.spacing ? `letter-spacing:${b.spacing}em` : '', b.weight ? `font-weight:${b.weight}` : ''].filter(Boolean).join(';');\n return `<div class=\"${b.cls ?? ''}\"${st ? ` style=\"${st}\"` : ''}>${b.html ?? esc(b.text)}</div>`;\n })\n .join('');\n}\n\n/** Register `el` to be fitted before its card is shown; renders at max size for now. */\nexport function fitLater(el: HTMLElement, spec: FitSpec) {\n el.innerHTML = blocksHTML(spec.blocks);\n el.style.fontSize = `${spec.max}px`;\n if (spec.pitch) el.style.lineHeight = `${spec.pitch}px`;\n else el.style.lineHeight = `${spec.lineHeight ?? 1.2}`;\n el.style.width = `${spec.vertical ? spec.height : spec.width}px`;\n el.style.height = `${spec.vertical ? spec.width : spec.height}px`;\n el.classList.add('fit');\n jobs.set(el, spec);\n fitSpecs.set(el, spec);\n}\n\n/** Fit every registered text block inside `root`. */\nexport async function runFits(root: HTMLElement) {\n const els = [root, ...root.querySelectorAll<HTMLElement>('.fit')].filter((e) => jobs.has(e));\n for (const el of els) {\n const spec = jobs.get(el)!;\n const before = spec.blocks.length;\n const r = await fitText(spec);\n el.innerHTML = blocksHTML(spec.blocks.slice(0, r.kept));\n el.style.fontSize = `${r.size}px`;\n el.dataset.fit = `${r.size}px, ${r.lines} lines${r.kept < before ? `, dropped ${before - r.kept}` : ''}`;\n jobs.delete(el);\n }\n}\n","/**\n * Strings and ribbons: jute / hemp twine, baker's twine, cotton string,\n * twisted wire ties, satin and grosgrain ribbon. A cord is a set of polylines\n * in a card's local px; the shader finds the nearest segment, builds a\n * cross-section (round ply-twisted cord or flat ribbon), shades it with the\n * desk light and casts a short shadow. Segments carry a layer flag so one\n * cord can pass *through* a tag: the strands lying on the paper render in\n * front of the sheet, the parts tucked under it render behind.\n *\n * Reference: real tags are tied with a lark's head (cow hitch): from the front\n * you see two parallel strands running from the hole over the top edge, the\n * bight crosses the back of the hole, and the doubled tails continue beyond\n * the edge. Twine shows diagonal ply ridges and stray fibres and frays at the\n * ends; satin catches bright sheen bands; ribbon ends are cut on a slant or V.\n */\nimport { parseColor } from '../index';\nimport type { Rng } from './rng';\nimport type { Sprite } from './props';\n\nexport type CordKind = 'jute' | 'hemp' | 'baker' | 'cotton' | 'satin' | 'grosgrain' | 'wire';\nconst KIND_ID: Record<CordKind, number> = { jute: 0, hemp: 1, baker: 2, cotton: 3, satin: 4, grosgrain: 5, wire: 6 };\n\ntype P3 = [number, number, number];\nexport interface Polyline {\n pts: P3[];\n /** Per point: true if that point lies under the sheet. */\n under: boolean[];\n /** Free ends fray (twine) or get a cut (ribbon). */\n freeStart: boolean;\n freeEnd: boolean;\n}\nexport interface CordSpec {\n kind: CordKind;\n width: number;\n colors: [string, string];\n lines: Polyline[];\n /** Knots: x, y, radius (lying on top). */\n knots: [number, number, number][];\n seed: number;\n}\n\nconst MAXP = 96;\n\nconst FS = /* glsl */ `#version 300 es\nprecision highp float;\n#define MAXP ${MAXP}\nuniform vec4 uP[MAXP]; // x, y, z, layer (1 on top, 2 under); negative = first point of a polyline\nuniform vec4 uA[MAXP]; // arc length at point, polyline length, free-end bits, polyline index\nuniform int uN;\nuniform int uPart; // 1 front, 2 back\nuniform vec3 uKnots[4];\nuniform int uKnotN;\nuniform vec2 uOrigin;\nuniform float uScale;\nuniform vec3 uLight;\nuniform int uKind;\nuniform vec3 uC1, uC2;\nuniform float uW;\nuniform float uSeed;\nout vec4 outColor;\n\nconst int JUTE = 0, HEMP = 1, BAKER = 2, COTTON = 3, SATIN = 4, GROS = 5, WIRE = 6;\n\nfloat hash(vec2 p) { return fract(sin(dot(p, vec2(127.1, 311.7)) + uSeed * 17.3) * 43758.5453); }\nfloat vnoise(vec2 p) {\n vec2 i = floor(p), f = fract(p);\n f = f * f * (3.0 - 2.0 * f);\n return mix(mix(hash(i), hash(i + vec2(1, 0)), f.x), mix(hash(i + vec2(0, 1)), hash(i + vec2(1, 1)), f.x), f.y);\n}\n\nbool ribbon() { return uKind == SATIN || uKind == GROS; }\nfloat plies() { return uKind == BAKER ? 2.0 : (uKind == COTTON ? 4.0 : (uKind == WIRE ? 1.0 : 3.0)); }\nfloat pitch() { return uW * (uKind == COTTON ? 1.2 : (uKind == BAKER ? 2.4 : 1.9)); }\n\n// height of the cord surface above its centre-line height, in local (t along, s across in -1..1)\nfloat surf(float t, float s) {\n float r = uW * 0.5;\n float a = max(1.0 - s * s, 0.0);\n if (ribbon()) {\n // flat band: nearly no camber, crisp edges; grosgrain has fine ribs across its width\n float h = r * 0.04 * a;\n if (uKind == GROS) h += 0.16 * sin(t * 6.2831 / 1.1);\n return h;\n }\n float h = r * sqrt(a);\n if (uKind != WIRE) {\n float n = plies();\n float g = fract((t / pitch() + s * 0.45) * n);\n float groove = 1.0 - smoothstep(0.0, 0.28, g) * smoothstep(1.0, 0.72, g);\n h -= groove * r * (uKind == COTTON ? 0.18 : 0.38) * sqrt(a);\n }\n return h;\n}\n\nstruct Hit { float h; float d; float t; float s; float z; float len; float ends; vec2 tan; float side; float knot; };\n\nHit nearest(vec2 p, int part) {\n Hit best = Hit(-1e9, 1e9, 0.0, 0.0, 0.0, 1.0, 0.0, vec2(1.0, 0.0), 1.0, 0.0);\n float r = uW * 0.5;\n float bestD = 1e9;\n for (int i = 1; i < MAXP; i++) {\n if (i >= uN) break;\n vec4 b = uP[i];\n if (b.w < 0.0) continue;\n vec4 a = uP[i - 1];\n if (part != 0 && int(abs(a.w) + 0.5) != part) continue;\n vec2 ab = b.xy - a.xy;\n float L = length(ab);\n if (L < 1e-4) continue;\n vec2 td = ab / L;\n float u = clamp(dot(p - a.xy, td), 0.0, L);\n vec2 dv = p - (a.xy + td * u);\n float d = length(dv);\n if (d > r + 3.0) continue;\n float side = (td.x * dv.y - td.y * dv.x) >= 0.0 ? 1.0 : -1.0;\n float z = mix(a.z, b.z, u / L);\n float t = uA[i - 1].x + u;\n float s = side * d / r;\n float h = d < r ? z + surf(t, s) : -1e6 + z - d;\n if (h > best.h || (best.h < -1e5 && d < bestD)) {\n best = Hit(h, d, t, s, z, uA[i - 1].y, uA[i - 1].z, td, side, 0.0);\n bestD = d;\n }\n }\n for (int k = 0; k < 4; k++) {\n if (k >= uKnotN || part == 2) break;\n vec3 kn = uKnots[k];\n vec2 dv = p - kn.xy;\n float d = length(dv);\n if (d < kn.z) {\n float h = 0.4 + kn.z * 0.75 * sqrt(1.0 - (d / kn.z) * (d / kn.z));\n if (h > best.h) best = Hit(h, d, atan(dv.y, dv.x) * kn.z * 1.3, d / kn.z, 0.4, 1e3, 0.0, normalize(vec2(-dv.y, dv.x) + 1e-5), 1.0, 1.0);\n }\n }\n return best;\n}\n\nvec2 local(vec2 px) { return (px - uOrigin) / uScale; }\n\nvoid main() {\n vec2 p = local(gl_FragCoord.xy);\n Hit o = nearest(p, uPart);\n float r = uW * 0.5;\n vec3 L = normalize(uLight);\n vec2 ld = normalize(L.xy);\n float tanE = L.z / max(length(L.xy), 1e-3);\n\n float alpha = 0.0;\n vec3 col = vec3(0.0);\n bool fuzzy = uKind == JUTE || uKind == HEMP || uKind == BAKER;\n if (o.d < r + 3.0) {\n alpha = clamp((r - o.d) * uScale + 0.5, 0.0, 1.0);\n // free ends: twine frays (plies part), ribbon gets a V / slanted cut\n float fromStart = o.t, fromEnd = o.len - o.t;\n bool startFree = mod(o.ends, 2.0) >= 1.0, endFree = o.ends >= 2.0;\n float endDist = min(startFree ? fromStart : 1e3, endFree ? fromEnd : 1e3);\n if (o.knot < 0.5) {\n if (ribbon()) {\n float notch = r * 1.6;\n if (endDist < notch * (1.0 - abs(o.s)) + (o.s * 0.5 + 0.5) * r * 0.25) alpha = 0.0;\n } else if (endDist < uW * 2.2 && uKind != WIRE) {\n float g = fract((o.t / pitch() + o.s * 0.45) * plies());\n float gap = smoothstep(uW * 2.2, 0.0, endDist);\n alpha *= smoothstep(0.0, 0.25 * gap + 0.01, g) * smoothstep(1.0, 1.0 - 0.25 * gap - 0.01, g);\n } else if (endDist < 0.6) alpha = 0.0;\n }\n // stray fibres around twine\n if (fuzzy && o.d >= r - 0.3) {\n float k = o.d - r;\n float hair = smoothstep(0.62, 0.8, vnoise(vec2(o.t * 0.45, k * 0.9 + o.side * 11.0)) * (1.0 - k / 3.0));\n alpha = max(alpha, hair * 0.75);\n }\n if (alpha > 0.0) {\n // normal from the local surface: across (s) and along (t)\n float e = 0.08;\n float hs = (surf(o.t, clamp(o.s + e, -1.0, 1.0)) - surf(o.t, clamp(o.s - e, -1.0, 1.0))) / (2.0 * e * r);\n float ht = (surf(o.t + 0.2, o.s) - surf(o.t - 0.2, o.s)) / 0.4;\n vec2 perp = vec2(-o.tan.y, o.tan.x);\n vec2 grad = perp * hs + o.tan * ht;\n if (o.knot > 0.5) {\n // knots are little domes\n float q = min(o.s, 0.98);\n grad = vec2(o.tan.y, -o.tan.x) * (-0.75 * q / sqrt(1.0 - q * q)) + o.tan * ht;\n }\n if (uKind == SATIN) grad += o.tan * (0.35 * sin(o.t / 17.0 + uSeed) + 0.18 * sin(o.t / 6.3 + uSeed * 2.0));\n if (uKind == GROS) grad += o.tan * 0.15 * sin(o.t / 21.0 + uSeed);\n vec3 n = normalize(vec3(-grad, 1.0));\n vec3 V = vec3(0.0, 0.0, 1.0);\n vec3 H = normalize(L + V);\n float dif = max(dot(n, L), 0.0);\n float nh = max(dot(n, H), 0.0);\n\n vec3 base = uC1;\n float n2 = plies();\n float ply = mod(floor((o.t / pitch() + o.s * 0.45) * n2), n2);\n if (uKind == BAKER) base = ply < 0.5 ? uC1 : uC2;\n else if (uKind == JUTE || uKind == HEMP) base *= 0.9 + 0.08 * ply + 0.2 * (vnoise(vec2(o.t * 0.9, o.s * 3.0 + ply * 5.0)) - 0.5);\n else if (uKind == COTTON) base *= 0.96 + 0.06 * vnoise(vec2(o.t * 1.4, o.s * 4.0));\n if (ribbon()) base *= 1.0 - 0.07 * smoothstep(0.86, 1.0, abs(o.s));\n if (uKind == GROS) base *= 0.92 + 0.08 * sin(o.t * 6.2831 / 1.1);\n if (o.d >= r) base = mix(base, vec3(1.0), 0.15);\n\n if (uKind == WIRE) {\n vec3 rf = reflect(-V, n);\n float env = 0.35 + 0.35 * rf.z + 0.7 * max(dot(normalize(rf.xy + 1e-5), ld), 0.0) * length(rf.xy);\n col = base * env + vec3(1.0) * pow(nh, 80.0) * 1.2;\n } else if (uKind == SATIN) {\n col = base * (0.38 + 0.62 * dif) + mix(base, vec3(1.0), 0.55) * pow(nh, 26.0) * 0.85 + base * 0.12 * pow(1.0 - n.z, 0.5);\n } else {\n float spec = uKind == GROS ? 0.08 : 0.05;\n col = base * (0.36 + 0.74 * dif) + vec3(1.0) * pow(nh, 18.0) * spec;\n }\n }\n }\n\n // short cast shadow: the cord's footprint shifted away from the light by its height\n float shadow = 0.0;\n if (alpha < 1.0) {\n float hgt = (ribbon() ? 0.6 : r * 1.6) + 0.3;\n Hit s = nearest(p + ld * hgt / tanE, uPart);\n float reach = s.knot > 0.5 ? uW * 1.2 : r;\n shadow = smoothstep(reach + 1.2, reach - 0.6, s.d) * 0.34;\n }\n float outA = alpha + shadow * (1.0 - alpha);\n outColor = vec4(outA > 0.0 ? clamp(col, 0.0, 1.0) * alpha / outA : vec3(0.0), outA);\n}\n`;\n\nconst VS = `#version 300 es\nin vec2 aPos;\nvoid main() { gl_Position = vec4(aPos, 0.0, 1.0); }`;\n\nexport function createCordRenderer() {\nlet gl: WebGL2RenderingContext | null = null;\nlet prog: WebGLProgram;\nconst loc = new Map<string, WebGLUniformLocation | null>();\nconst u = (n: string) => {\n if (!loc.has(n)) loc.set(n, gl!.getUniformLocation(prog, n));\n return loc.get(n)!;\n};\n\nfunction init() {\n const canvas = new OffscreenCanvas(1, 1);\n const g = canvas.getContext('webgl2', { premultipliedAlpha: false, antialias: false, preserveDrawingBuffer: true }) as WebGL2RenderingContext | null;\n if (!g) throw new Error('WebGL2 not available');\n gl = g;\n const sh = (type: number, src: string) => {\n const s = g.createShader(type)!;\n g.shaderSource(s, src);\n g.compileShader(s);\n if (!g.getShaderParameter(s, g.COMPILE_STATUS)) throw new Error(g.getShaderInfoLog(s) ?? 'cord shader error');\n return s;\n };\n prog = g.createProgram()!;\n g.attachShader(prog, sh(g.VERTEX_SHADER, VS));\n g.attachShader(prog, sh(g.FRAGMENT_SHADER, FS));\n g.bindAttribLocation(prog, 0, 'aPos');\n g.linkProgram(prog);\n if (!g.getProgramParameter(prog, g.LINK_STATUS)) throw new Error(g.getProgramInfoLog(prog) ?? 'cord link error');\n g.bindVertexArray(g.createVertexArray());\n g.bindBuffer(g.ARRAY_BUFFER, g.createBuffer());\n g.bufferData(g.ARRAY_BUFFER, new Float32Array([-1, -1, 3, -1, -1, 3]), g.STATIC_DRAW);\n g.enableVertexAttribArray(0);\n g.vertexAttribPointer(0, 2, g.FLOAT, false, 0, 0);\n}\n\n/** Render the part of a cord that lies on top of the sheet ('front') or under it ('back'). */\nfunction renderCord(spec: CordSpec, part: 'front' | 'back', dpr: number, azimuth: number, elevation: number): Sprite | null {\n if (!gl) init();\n const g = gl!;\n const P = new Float32Array(MAXP * 4);\n const A = new Float32Array(MAXP * 4);\n let n = 0;\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n let any = false;\n spec.lines.forEach((line, li) => {\n let arc = 0;\n const start = n;\n line.pts.forEach((pt, i) => {\n if (n >= MAXP) return;\n if (i > 0) arc += Math.hypot(pt[0] - line.pts[i - 1][0], pt[1] - line.pts[i - 1][1]);\n const layer = line.under[i] ? 2 : 1;\n P.set([pt[0], pt[1], pt[2], i === 0 ? -layer : layer], n * 4);\n A.set([arc, 0, (line.freeStart ? 1 : 0) + (line.freeEnd ? 2 : 0), li], n * 4);\n if (i < line.pts.length - 1 && (layer === 2) === (part === 'back')) {\n any = true;\n for (const q of [pt, line.pts[i + 1]]) {\n minX = Math.min(minX, q[0]);\n maxX = Math.max(maxX, q[0]);\n minY = Math.min(minY, q[1]);\n maxY = Math.max(maxY, q[1]);\n }\n }\n n++;\n });\n for (let k = start; k < n; k++) A[k * 4 + 1] = arc;\n });\n if (part === 'front')\n for (const [x, y, r] of spec.knots) {\n any = true;\n minX = Math.min(minX, x - r);\n maxX = Math.max(maxX, x + r);\n minY = Math.min(minY, y - r);\n maxY = Math.max(maxY, y + r);\n }\n if (!any) return null;\n const pad = spec.width + 8;\n minX -= pad;\n minY -= pad;\n maxX += pad;\n maxY += pad;\n const w = Math.ceil(maxX - minX), h = Math.ceil(maxY - minY);\n const W = Math.ceil(w * dpr), H = Math.ceil(h * dpr);\n (g.canvas as OffscreenCanvas).width = W;\n (g.canvas as OffscreenCanvas).height = H;\n g.viewport(0, 0, W, H);\n g.useProgram(prog);\n g.uniform4fv(u('uP'), P);\n g.uniform4fv(u('uA'), A);\n g.uniform1i(u('uN'), n);\n g.uniform1i(u('uPart'), part === 'front' ? 1 : 2);\n const K = new Float32Array(12);\n spec.knots.slice(0, 4).forEach((k, i) => K.set(k, i * 3));\n g.uniform3fv(u('uKnots'), K);\n g.uniform1i(u('uKnotN'), Math.min(4, spec.knots.length));\n g.uniform2f(u('uOrigin'), -minX * dpr, -minY * dpr);\n g.uniform1f(u('uScale'), dpr);\n const el = (elevation * Math.PI) / 180, az = (azimuth * Math.PI) / 180;\n g.uniform3f(u('uLight'), Math.cos(el) * Math.cos(az), Math.cos(el) * Math.sin(az), Math.sin(el));\n g.uniform1i(u('uKind'), KIND_ID[spec.kind]);\n const c1 = parseColor(spec.colors[0]), c2 = parseColor(spec.colors[1]);\n g.uniform3f(u('uC1'), c1[0], c1[1], c1[2]);\n g.uniform3f(u('uC2'), c2[0], c2[1], c2[2]);\n g.uniform1f(u('uW'), spec.width);\n g.uniform1f(u('uSeed'), spec.seed % 97);\n g.drawArrays(g.TRIANGLES, 0, 3);\n const px = new Uint8ClampedArray(W * H * 4);\n g.readPixels(0, 0, W, H, g.RGBA, g.UNSIGNED_BYTE, px);\n const canvas = document.createElement('canvas');\n canvas.width = W;\n canvas.height = H;\n canvas.getContext('2d')!.putImageData(new ImageData(px, W, H), 0, 0);\n canvas.style.width = `${w}px`;\n canvas.style.height = `${h}px`;\n return { canvas, w, h, ox: -minX, oy: -minY };\n}\n\n\nreturn { renderCord, dispose() { gl?.getExtension('WEBGL_lose_context')?.loseContext(); gl = null; loc.clear(); } };\n}\nlet shared: ReturnType<typeof createCordRenderer> | undefined;\nexport const renderCord: ReturnType<typeof createCordRenderer>['renderCord'] = (...args) => (shared ??= createCordRenderer()).renderCord(...args);\n// ---------------------------------------------------------------- geometry\n\n/** A relaxed path lying on the desk: random-walk curvature, smoothed, sampled every `step` px. */\nfunction lazyPath(rng: Rng, x: number, y: number, angle: number, length: number, step = 5, wiggle = 0.06): [number, number][] {\n const pts: [number, number][] = [[x, y]];\n let a = angle, k = rng.range(-wiggle, wiggle);\n for (let s = step; s <= length; s += step) {\n k = k * 0.85 + rng.range(-wiggle, wiggle) * 0.6;\n a += k * step * 0.25;\n x += Math.cos(a) * step;\n y += Math.sin(a) * step;\n pts.push([x, y]);\n }\n return pts;\n}\n\n/** Offset a centre-line sideways (twisting doubled strands around each other). */\nfunction offsetPath(path: [number, number][], off: (i: number, t: number) => [number, number]): P3[] {\n let t = 0;\n return path.map((p, i) => {\n if (i > 0) t += Math.hypot(p[0] - path[i - 1][0], p[1] - path[i - 1][1]);\n const a = path[Math.max(0, i - 1)], b = path[Math.min(path.length - 1, i + 1)];\n const dx = b[0] - a[0], dy = b[1] - a[1];\n const L = Math.hypot(dx, dy) || 1;\n const [o, z] = off(i, t);\n return [p[0] - (dy / L) * o, p[1] + (dx / L) * o, z];\n });\n}\n\nexport const CORD_STYLES: { kind: CordKind; colors: [string, string]; width: number; weight: number; label: string }[] = [\n { kind: 'jute', colors: ['#b79a6c', '#b79a6c'], width: 2.6, weight: 3, label: 'jute twine' },\n { kind: 'hemp', colors: ['#cdb98f', '#cdb98f'], width: 2.0, weight: 2, label: 'hemp twine' },\n { kind: 'baker', colors: ['#c8323a', '#f3efe7'], width: 1.8, weight: 2, label: \"baker's twine\" },\n { kind: 'baker', colors: ['#2f7a4a', '#f3efe7'], width: 1.8, weight: 0.7, label: \"baker's twine\" },\n { kind: 'baker', colors: ['#1f1e24', '#f3efe7'], width: 1.8, weight: 0.7, label: \"baker's twine\" },\n { kind: 'cotton', colors: ['#efebe1', '#efebe1'], width: 1.7, weight: 1.2, label: 'cotton string' },\n { kind: 'wire', colors: ['#c9ccd0', '#c9ccd0'], width: 0.9, weight: 0.8, label: 'wire tie' },\n { kind: 'satin', colors: ['#b8233a', '#b8233a'], width: 6, weight: 1, label: 'satin ribbon' },\n { kind: 'satin', colors: ['#20385f', '#20385f'], width: 6, weight: 0.6, label: 'satin ribbon' },\n { kind: 'grosgrain', colors: ['#3f5e45', '#3f5e45'], width: 7, weight: 0.7, label: 'grosgrain ribbon' },\n { kind: 'grosgrain', colors: ['#e6dccb', '#e6dccb'], width: 7, weight: 0.6, label: 'grosgrain ribbon' },\n];\n\n/**\n * A cord tied through a tag's hole at (cx, cy), radius hr, tag top edge at y = 0.\n * Twine and wire: lark's head (two strands over the edge, bight behind the hole,\n * doubled tails). Ribbon: threaded once, knotted just past the edge, two V-cut tails.\n */\nexport function tagCord(rng: Rng, cx: number, cy: number, hr: number, tagW: number): { spec: CordSpec; label: string } {\n const style = rng.weighted(CORD_STYLES, (s) => s.weight);\n const w = style.width;\n const lines: Polyline[] = [];\n const knots: [number, number, number][] = [];\n const onTag = (x: number, y: number) => y > 0 && x > 0 && x < tagW;\n const isRibbon = style.kind === 'satin' || style.kind === 'grosgrain';\n // which way the tails fall\n const out = -Math.PI / 2 + rng.range(-0.9, 0.9);\n\n if (!isRibbon) {\n // the two strands of a lark's head lie side by side, just touching\n const gap = w * 1.08;\n // the two strands of the hitch, from inside the hole over the top edge\n for (const sx of [-1, 1]) {\n const x0 = cx + sx * gap * 0.5;\n const pts: P3[] = [\n [x0 + sx * 0.3, cy + hr * 0.15, -0.4],\n [x0, cy - hr * 0.6, 0.1],\n [x0, cy - hr - 2, 0.3],\n [x0 + sx * 0.2, (cy - hr) * 0.45, 0.35],\n [x0 + sx * 0.3, 0.8, 0.45],\n [x0 + sx * 0.3, -1.5, 0.1],\n ];\n lines.push({ pts, under: pts.map(() => false), freeStart: false, freeEnd: false });\n }\n // the bight crossing the back of the hole (seen through it)\n const bight: P3[] = [\n [cx - hr * 1.7, cy - hr * 0.2, 0],\n [cx - hr * 0.6, cy + hr * 0.5, 0],\n [cx + hr * 0.6, cy + hr * 0.5, 0],\n [cx + hr * 1.7, cy - hr * 0.2, 0],\n ];\n lines.push({ pts: bight, under: bight.map(() => true), freeStart: false, freeEnd: false });\n // doubled tails: start under the tag's top edge, twist around each other, part near the end\n const len = rng.range(70, 150);\n const path = lazyPath(rng, cx, 6, out, len);\n const twist = rng.range(16, 26) * (style.kind === 'wire' ? 0.35 : 1);\n const ph = rng.range(0, Math.PI * 2);\n const part = rng.range(0.55, 0.85) * len;\n for (const sx of [-1, 1]) {\n const strand = offsetPath(path, (_i, t) => {\n const spread = t > part ? (t - part) * (0.18 + rng.range(0, 0.02)) * sx : 0;\n const tw = Math.cos(ph + (t / twist) * Math.PI);\n return [gap * 0.5 * sx * tw + spread, 0.15 + 0.35 * w * sx * Math.sin(ph + (t / twist) * Math.PI)];\n });\n const cut = Math.floor(strand.length * rng.range(0.82, 1));\n const s = strand.slice(0, Math.max(3, cut));\n let left = false;\n const under = s.map(([x, y]) => {\n if (!onTag(x, y)) left = true;\n return !left && onTag(x, y);\n });\n lines.push({ pts: s, under, freeStart: false, freeEnd: true });\n }\n } else {\n // ribbon: one flat strip through the hole and over the edge, knotted past the edge\n const leg: P3[] = [\n [cx, cy + hr * 0.1, -0.3],\n [cx, cy - hr - 1, 0.1],\n [cx + rng.range(-1, 1), 2, 0.25],\n [cx, -w * 0.9, 0.3],\n ];\n lines.push({ pts: leg, under: leg.map(() => false), freeStart: false, freeEnd: false });\n const bight: P3[] = [\n [cx, cy - hr * 0.3, 0],\n [cx, cy + hr * 2.4, 0],\n ];\n lines.push({ pts: bight, under: [true, true], freeStart: false, freeEnd: false });\n const kx = cx, ky = -w * 1.05;\n knots.push([kx, ky, w * 0.85]);\n for (const sx of [-1, 1]) {\n const a = out + sx * rng.range(0.35, 0.7);\n const pts = lazyPath(rng, kx + Math.cos(a) * w * 0.6, ky + Math.sin(a) * w * 0.6, a, rng.range(45, 85), 5, 0.035).map(([x, y]) => [x, y, 0.2] as P3);\n lines.push({ pts, under: pts.map(() => false), freeStart: false, freeEnd: true });\n }\n }\n return { spec: { kind: style.kind, width: w, colors: style.colors, lines, knots, seed: rng.int(1, 9999) }, label: style.label };\n}\n","/**\n * Desk props & attachments, rendered as 2.5D height fields in one WebGL2\n * shader: push pins, map pins, thumbtacks, magnets, binder clips, paper clips,\n * staples, pencils, a steel ruler, an eraser, tape rolls, a mug and a craft\n * knife. Every prop is lit by the same light as the paper and casts a\n * ray-marched shadow from its real height, so tall things (mugs, pins) cast\n * long shadows and flat things (staples, tacks) barely any.\n *\n * Objects are rendered already rotated (the light stays fixed) and returned\n * as sprites with straight alpha.\n */\nimport { parseColor } from '../index';\n\nexport type PropKind =\n | 'pushpin'\n | 'mappin'\n | 'thumbtack'\n | 'magnet'\n | 'magnet-neo'\n | 'magnet-bar'\n | 'binder'\n | 'paperclip'\n | 'staple'\n | 'pencil'\n | 'ruler'\n | 'eraser'\n | 'tape-roll'\n | 'mug'\n | 'knife'\n | 'washi-roll'\n | 'eyelet';\n\nconst KIND_ID: Record<PropKind, number> = {\n pushpin: 0, mappin: 1, thumbtack: 2, magnet: 3, 'magnet-neo': 4, 'magnet-bar': 5, binder: 6, paperclip: 7, staple: 8,\n pencil: 9, ruler: 10, eraser: 11, 'tape-roll': 12, mug: 13, knife: 14, 'washi-roll': 15, eyelet: 16,\n};\n\n/** [footprint radius, max height] in CSS px. */\nexport const EXTENT: Record<PropKind, [number, number]> = {\n pushpin: [9.5, 15], mappin: [6.5, 20], thumbtack: [8, 2.6], magnet: [14, 8], 'magnet-neo': [6.5, 3.2], 'magnet-bar': [19, 6.5],\n binder: [34, 10], paperclip: [21, 2.4], staple: [8, 1.2], pencil: [92, 9.5], ruler: [158, 1.6], eraser: [27, 10.5],\n 'tape-roll': [32, 17], mug: [56, 84], knife: [66, 9.5], 'washi-roll': [25, 15], eyelet: [9.5, 1.4],\n};\n\nexport interface PropSpec {\n kind: PropKind;\n color?: string;\n color2?: string;\n /** Rotation in degrees (clockwise on screen). */\n angle?: number;\n /** Paper clip: 'front' = the loop on top of the paper, 'back' = the rest. */\n part?: 'all' | 'front' | 'back';\n /** Light direction in the sprite's frame (degrees, same convention as paper `lighting.azimuth`). */\n azimuth?: number;\n elevation?: number;\n seed?: number;\n /** Pencil / ruler / knife length (CSS px). */\n length?: number;\n}\n\nexport interface Sprite {\n canvas: HTMLCanvasElement;\n /** CSS size of the sprite. */\n w: number;\n h: number;\n /** Where the prop's origin sits inside the sprite (CSS px). */\n ox: number;\n oy: number;\n}\n\nconst VS = `#version 300 es\nin vec2 aPos;\nvoid main() { gl_Position = vec4(aPos, 0.0, 1.0); }`;\n\nconst FS = /* glsl */ `#version 300 es\nprecision highp float;\nuniform vec2 uOrigin; // object origin in sprite px\nuniform float uScale; // device px per CSS px\nuniform float uAngle;\nuniform vec3 uLight;\nuniform int uKind;\nuniform vec3 uColor, uColor2;\nuniform float uLength;\nuniform int uPart;\nuniform float uSeed;\nuniform float uMaxH;\nout vec4 outColor;\n\nconst int PLASTIC = 1, METAL = 2, BRASS = 3, MATTE = 4, WOOD = 5, GRAPHITE = 6, CERAMIC = 7, COFFEE = 8, PAINT = 9, STEEL = 10, CARD = 11;\n\nfloat hash(vec2 p) { return fract(sin(dot(p, vec2(127.1, 311.7)) + uSeed * 13.7) * 43758.5453); }\nfloat vnoise(vec2 p) {\n vec2 i = floor(p), f = fract(p);\n f = f * f * (3.0 - 2.0 * f);\n return mix(mix(hash(i), hash(i + vec2(1, 0)), f.x), mix(hash(i + vec2(0, 1)), hash(i + vec2(1, 1)), f.x), f.y);\n}\n\n// signed distances (negative inside)\nfloat sdCircle(vec2 p, float r) { return length(p) - r; }\nfloat sdBox(vec2 p, vec2 b, float r) { vec2 q = abs(p) - b + r; return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - r; }\nfloat sdSeg(vec2 p, vec2 a, vec2 b) { vec2 pa = p - a, ba = b - a; float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0); return length(pa - ba * h); }\n// half-circle arc around c from angle a0 to a1 (radians)\nfloat sdArc(vec2 p, vec2 c, float r, float a0, float a1) {\n vec2 d = p - c;\n float a = atan(d.y, d.x);\n float mid = (a0 + a1) * 0.5, half_ = abs(a1 - a0) * 0.5;\n float da = abs(mod(a - mid + 3.14159265, 6.2831853) - 3.14159265);\n if (da <= half_) return abs(length(d) - r);\n vec2 e0 = c + r * vec2(cos(a0), sin(a0)), e1 = c + r * vec2(cos(a1), sin(a1));\n return min(length(p - e0), length(p - e1));\n}\n\nstruct Hit { float h; float sd; int mat; vec3 col; };\n\nvoid add(inout Hit o, float sd, float h, int mat, vec3 col) {\n if (sd < 0.0 && h > o.h) { o.h = h; o.mat = mat; o.col = col; }\n o.sd = min(o.sd, sd);\n}\n\n// round tube of radius r lying with its top at height top: profile across distance d\nfloat tube(float d, float r, float top) { return top - r + sqrt(max(r * r - d * d, 0.0)); }\nfloat dome(float d, float R) { return sqrt(max(1.0 - (d / R) * (d / R), 0.0)); }\n\nHit scene(vec2 p) {\n Hit o = Hit(0.0, 1e5, 0, vec3(0.0));\n float d = length(p);\n if (uKind == 0) { // push pin: flared grip, domed cap\n float R = 9.0;\n add(o, sdCircle(p, R), 11.0 + 2.2 * dome(d, R), PLASTIC, uColor);\n if (d < R * 0.55) add(o, sdCircle(p, R * 0.55), 13.5 + 1.4 * dome(d, R * 0.55), PLASTIC, uColor * 1.08);\n } else if (uKind == 1) { // map pin: sphere on a needle\n add(o, sdCircle(p, 0.7), 14.0, METAL, vec3(0.8));\n add(o, sdCircle(p, 5.8), 14.0 + 5.8 * dome(d, 5.8), PLASTIC, uColor);\n } else if (uKind == 2) { // thumbtack\n float R = 7.6;\n float h = 1.1 + 1.2 * (1.0 - (d / R) * (d / R)) - 0.7 * exp(-(d / 1.3) * (d / 1.3));\n add(o, sdCircle(p, R), h, BRASS, uColor);\n } else if (uKind == 3) { // dome magnet\n float R = 13.0;\n add(o, sdCircle(p, R), 3.5 + 4.0 * pow(dome(d, R), 0.7), PLASTIC, uColor);\n } else if (uKind == 4) { // neodymium disc\n float R = 6.0;\n add(o, sdCircle(p, R), 2.2 + 0.8 * smoothstep(R, R - 0.9, d), METAL, vec3(0.86, 0.87, 0.9));\n } else if (uKind == 5) { // bar magnet\n float sd = sdBox(p, vec2(17.0, 8.5), 3.0);\n add(o, sd, 6.0 * smoothstep(0.0, -2.5, sd), PLASTIC, uColor);\n } else if (uKind == 6) { // binder clip: jaw on the paper (+y), hinge past the edge (-y), handles out\n float w = 15.0;\n float sd = sdBox(p - vec2(0.0, -4.0), vec2(w, 10.0), 1.2);\n float t = clamp((p.y + 14.0) / 20.0, 0.0, 1.0);\n float bevel = smoothstep(0.0, -1.2, sd);\n add(o, sd, mix(9.0, 1.8, t) * bevel, PAINT, uColor);\n // folded-out wire handles\n float wr = 1.1;\n for (int s = -1; s <= 1; s += 2) {\n vec2 a = vec2(float(s) * w * 0.72, -13.0), b = vec2(float(s) * w * 0.55, -30.0);\n float dw = sdSeg(p, a, b);\n float tt = clamp((-p.y - 13.0) / 17.0, 0.0, 1.0);\n add(o, dw - wr, tube(dw, wr, mix(9.5, 3.0, tt)), METAL, vec3(0.9));\n }\n float db = sdSeg(p, vec2(-w * 0.55, -30.0), vec2(w * 0.55, -30.0));\n add(o, db - wr, tube(db, wr, 3.0), METAL, vec3(0.9));\n } else if (uKind == 7) { // gem paper clip, 10 x 36, origin at its centre\n vec2 q = p + vec2(5.0, 18.0);\n float r = 0.75;\n float back = min(min(sdSeg(q, vec2(0.0, 8.0), vec2(0.0, 31.0)), sdArc(q, vec2(5.0, 31.0), 5.0, 0.0, 3.14159265)),\n sdSeg(q, vec2(10.0, 31.0), vec2(10.0, 5.0)));\n float front = min(min(sdArc(q, vec2(6.5, 5.0), 3.5, -3.14159265, 0.0), sdSeg(q, vec2(3.0, 5.0), vec2(3.0, 27.0))),\n min(sdArc(q, vec2(5.0, 27.0), 2.0, 0.0, 3.14159265), sdSeg(q, vec2(7.0, 27.0), vec2(7.0, 11.0))));\n float dd = uPart == 1 ? front : (uPart == 2 ? back : min(front, back));\n add(o, dd - r, tube(dd, r, 1.6), METAL, uColor);\n } else if (uKind == 8) { // staple crown\n float dd = sdSeg(p, vec2(-6.0, 0.0), vec2(6.0, 0.0));\n add(o, dd - 0.6, 0.9 + 0.2 * smoothstep(0.6, 0.0, dd), METAL, vec3(0.85));\n } else if (uKind == 9) { // pencil along x, tip at -L/2\n float L = uLength, w = 8.6, R = w * 0.5;\n float x = p.x + L * 0.5; // 0 at the tip\n float ay = abs(p.y);\n float cone = 24.0;\n if (x >= 0.0 && x < cone) {\n float rr = R * x / cone;\n if (ay < rr) {\n bool lead = x < 6.0;\n vec3 wood = uColor2;\n add(o, ay - rr, R + sqrt(max(rr * rr - p.y * p.y, 0.0)) - (R - rr) * 0.6, lead ? GRAPHITE : WOOD, lead ? vec3(0.17) : wood);\n }\n o.sd = min(o.sd, ay - rr);\n } else if (x >= cone && x <= L) {\n float hexTop = R * 1.0 - max(0.0, ay - w * 0.25) * 1.15;\n float sd = max(ay - R, max(cone - x, x - L));\n int mat = PAINT; vec3 c = uColor;\n if (x > L - 16.0 && x <= L - 6.0) { mat = METAL; c = vec3(0.82, 0.76, 0.55); hexTop = sqrt(max(R * R - p.y * p.y, 0.0)) * (0.92 + 0.08 * step(0.5, fract(x * 0.5))); }\n else if (x > L - 6.0) { mat = MATTE; c = vec3(0.92, 0.55, 0.55); hexTop = sqrt(max(R * R - p.y * p.y, 0.0)) * 0.95; }\n add(o, sd, R + hexTop * 0.95, mat, c);\n }\n } else if (uKind == 10) { // steel ruler\n float L = uLength;\n float sd = sdBox(p, vec2(L * 0.5, 13.0), 1.5);\n vec3 c = vec3(0.78, 0.79, 0.8) * (0.93 + 0.07 * vnoise(vec2(p.x * 0.05, p.y * 3.0)));\n float x = p.x + L * 0.5 - 8.0;\n float mm = 3.7795;\n float k = floor(x / mm + 0.5);\n float tl = mod(k, 10.0) == 0.0 ? 9.0 : (mod(k, 5.0) == 0.0 ? 6.5 : 4.0);\n if (x > -0.5 && x < L - 16.0 && abs(x - k * mm) < 0.35 && p.y < -13.0 + tl) c *= 0.25;\n add(o, sd, 1.4 * smoothstep(0.0, -0.8, sd), STEEL, c);\n } else if (uKind == 11) { // eraser with sleeve\n float sd = sdBox(p, vec2(23.0, 10.0), 3.0);\n float h = 9.5 * smoothstep(0.0, -3.5, sd);\n bool sleeve = p.x > -8.0 && p.x < 20.0;\n add(o, sd, h + (sleeve ? 0.4 : 0.0), sleeve ? CARD : MATTE, sleeve ? uColor : vec3(0.95, 0.94, 0.92));\n } else if (uKind == 12 || uKind == 15) { // tape roll / washi roll seen from above\n bool washi = uKind == 15;\n float Ro = washi ? 24.0 : 31.0, Ri = washi ? 16.0 : 21.0, Rc = Ri - 2.6;\n float H = washi ? 14.0 : 16.5;\n float sdOut = d - Ro;\n if (d > Ri && d < Ro) {\n vec3 c = uColor * (0.93 + 0.07 * sin(d * 7.0 + vnoise(p * 0.3) * 3.0));\n add(o, sdOut, H - 0.6 * smoothstep(Ro - 1.2, Ro, d) - 0.6 * smoothstep(Ri + 1.2, Ri, d), MATTE, c);\n }\n if (d > Rc && d <= Ri) add(o, -1.0, H + 0.4, CARD, vec3(0.62, 0.5, 0.37));\n o.sd = min(o.sd, max(sdOut, Rc - d));\n } else if (uKind == 13) { // mug: rim, coffee, handle\n float Ro = 38.0, Ri = 33.5;\n vec2 hp = p - vec2(Ro + 7.0, 0.0);\n float dh = abs(length(hp * vec2(1.0, 0.8)) - 9.0);\n if (p.x > Ro - 2.0) add(o, dh - 3.2, tube(dh, 3.2, 52.0), CERAMIC, uColor);\n if (d < Ro) {\n if (d > Ri) add(o, d - Ro, 80.0 + 1.5 * dome(abs(d - (Ro + Ri) * 0.5), (Ro - Ri) * 0.5), CERAMIC, uColor);\n else {\n float crema = smoothstep(Ri - 4.0, Ri - 0.5, d);\n vec3 c = mix(vec3(0.17, 0.09, 0.05), vec3(0.42, 0.27, 0.15), crema * 0.7);\n add(o, d - Ro, 66.0 + 2.0 * crema, COFFEE, c);\n }\n }\n o.sd = min(o.sd, d - Ro);\n } else if (uKind == 16) { // metal eyelet: rolled ring around a 6px hole, see-through middle\n float ri = 6.0, ro = 9.0;\n if (d > ri - 0.4 && d < ro) {\n float m = (d - ri) / (ro - ri);\n add(o, max(d - ro, ri - 0.4 - d), 0.35 + 1.0 * sqrt(max(1.0 - (2.0 * m - 0.7) * (2.0 * m - 0.7), 0.0)), BRASS, uColor);\n }\n o.sd = min(o.sd, max(d - ro, ri - 0.4 - d));\n } else if (uKind == 14) { // craft knife along x, blade at -L/2\n float L = uLength;\n float x = p.x + L * 0.5;\n float body = sdBox(p - vec2(8.0, 0.0), vec2(L * 0.5 - 8.0, 4.8), 4.5);\n float ay = abs(p.y);\n if (body < 0.0) {\n float hh = 4.8 + sqrt(max(4.8 * 4.8 - p.y * p.y, 0.0));\n bool grip = x > 30.0 && x < 70.0;\n bool collar = x > 16.0 && x < 24.0;\n vec3 c = grip ? uColor : vec3(0.75, 0.77, 0.8);\n if (grip) hh += 0.5 * sin(x * 1.6);\n add(o, body, hh, grip ? MATTE : (collar ? METAL : STEEL), c);\n }\n // blade: angled triangle\n vec2 b = vec2(x, p.y);\n float blade = max(max(-b.x, b.x - 18.0), max(-b.y - 3.2, b.y - 3.2 + (18.0 - b.x) * 0.35));\n if (x < 18.0 && blade < 0.0) add(o, blade, 1.2, METAL, vec3(0.92));\n o.sd = min(o.sd, min(body, x < 18.0 ? blade : 1e5));\n }\n return o;\n}\n\nfloat heightAt(vec2 p) { return scene(p).h; }\n\nvec2 local(vec2 px) {\n vec2 v = (px - uOrigin) / uScale;\n float c = cos(uAngle), s = sin(uAngle);\n return vec2(c * v.x + s * v.y, -s * v.x + c * v.y);\n}\nvec2 toLocalDir(vec2 dir) {\n float c = cos(uAngle), s = sin(uAngle);\n return vec2(c * dir.x + s * dir.y, -s * dir.x + c * dir.y);\n}\n\nvoid main() {\n vec2 px = gl_FragCoord.xy;\n vec2 p = local(px);\n Hit o = scene(p);\n float alpha = clamp(0.5 - o.sd * uScale, 0.0, 1.0);\n\n // light in the object's frame\n vec2 l2 = toLocalDir(uLight.xy);\n vec3 L = normalize(vec3(l2, uLight.z));\n float tanE = L.z / max(length(L.xy), 1e-3);\n vec2 ld = normalize(L.xy);\n\n // shadow: march towards the light, compare the ray height with the field\n float h0 = o.h * step(0.0, -o.sd);\n float vis = 1.0;\n float reach = (uMaxH - h0) / tanE + 2.0;\n for (int i = 1; i <= 40; i++) {\n float t = reach * float(i) / 40.0;\n float z = h0 + t * tanE;\n float hh = heightAt(p + ld * t);\n if (hh > 0.001) vis = min(vis, clamp((z - hh) / (0.07 * t + 0.5), 0.0, 1.0));\n if (vis <= 0.0) break;\n }\n\n vec3 col = vec3(0.0);\n if (alpha > 0.0) {\n float e = 0.3;\n float hx = (heightAt(p + vec2(e, 0.0)) - heightAt(p - vec2(e, 0.0))) / (2.0 * e);\n float hy = (heightAt(p + vec2(0.0, e)) - heightAt(p - vec2(0.0, e))) / (2.0 * e);\n vec3 n = normalize(vec3(-hx, -hy, 1.0));\n vec3 V = vec3(0.0, 0.0, 1.0);\n vec3 H = normalize(L + V);\n float dif = max(dot(n, L), 0.0) * (0.35 + 0.65 * vis);\n float nh = max(dot(n, H), 0.0);\n vec3 r = reflect(-V, n);\n vec3 base = o.col;\n int m = o.mat;\n if (m == METAL || m == BRASS || m == STEEL) {\n vec3 tint = base;\n float horizon = length(r.xy);\n float env = 0.32 + 0.38 * r.z + 0.75 * max(dot(normalize(r.xy + 1e-5), ld), 0.0) * horizon;\n if (m == STEEL) env += 0.08 * (vnoise(vec2(p.x * 0.08, p.y * 4.0)) - 0.5);\n col = tint * env * (0.55 + 0.45 * vis) + vec3(1.0) * pow(nh, 90.0) * 1.4 * vis;\n } else if (m == COFFEE) {\n col = base * (0.6 + 0.5 * dif) + vec3(1.0) * pow(nh, 180.0) * 1.2 * vis;\n } else {\n float sp = m == PLASTIC ? 0.55 : (m == CERAMIC ? 0.45 : (m == PAINT ? 0.5 : (m == GRAPHITE ? 0.25 : 0.05)));\n float sh = m == PLASTIC ? 70.0 : (m == CERAMIC ? 50.0 : 40.0);\n if (m == WOOD) base *= 0.9 + 0.12 * sin(p.x * 0.9 + vnoise(p * vec2(0.15, 1.2)) * 6.0);\n if (m == CARD) base *= 0.92 + 0.1 * vnoise(p * 0.8);\n if (m == MATTE) base *= 0.95 + 0.06 * vnoise(p * 1.3);\n col = base * (0.42 + 0.7 * dif) + vec3(1.0) * pow(nh, sh) * sp * vis;\n // soft translucent glow for coloured plastic\n if (m == PLASTIC) col += base * 0.12 * (1.0 - n.z);\n }\n }\n // ground shadow under / around the object\n float shadow = (1.0 - vis) * 0.42 * (1.0 - alpha);\n float outA = alpha + shadow;\n outColor = vec4(outA > 0.0 ? clamp(col, 0.0, 1.0) * alpha / outA : vec3(0.0), outA);\n}\n`;\n\nexport function createPropRenderer() {\nlet gl: WebGL2RenderingContext | null = null;\nlet prog: WebGLProgram;\nconst loc = new Map<string, WebGLUniformLocation | null>();\n\nfunction init() {\n const canvas = new OffscreenCanvas(1, 1);\n const g = canvas.getContext('webgl2', { premultipliedAlpha: false, antialias: false, preserveDrawingBuffer: true }) as WebGL2RenderingContext | null;\n if (!g) throw new Error('WebGL2 not available');\n gl = g;\n const sh = (type: number, src: string) => {\n const s = g.createShader(type)!;\n g.shaderSource(s, src);\n g.compileShader(s);\n if (!g.getShaderParameter(s, g.COMPILE_STATUS)) throw new Error(g.getShaderInfoLog(s) ?? 'shader error');\n return s;\n };\n prog = g.createProgram()!;\n g.attachShader(prog, sh(g.VERTEX_SHADER, VS));\n g.attachShader(prog, sh(g.FRAGMENT_SHADER, FS));\n g.bindAttribLocation(prog, 0, 'aPos');\n g.linkProgram(prog);\n if (!g.getProgramParameter(prog, g.LINK_STATUS)) throw new Error(g.getProgramInfoLog(prog) ?? 'link error');\n const vao = g.createVertexArray();\n g.bindVertexArray(vao);\n const buf = g.createBuffer();\n g.bindBuffer(g.ARRAY_BUFFER, buf);\n g.bufferData(g.ARRAY_BUFFER, new Float32Array([-1, -1, 3, -1, -1, 3]), g.STATIC_DRAW);\n g.enableVertexAttribArray(0);\n g.vertexAttribPointer(0, 2, g.FLOAT, false, 0, 0);\n}\n\nconst u = (n: string) => {\n if (!loc.has(n)) loc.set(n, gl!.getUniformLocation(prog, n));\n return loc.get(n)!;\n};\n\nconst DEFAULT_LIGHT = { azimuth: 225, elevation: 48 };\n\nfunction renderProp(spec: PropSpec, dpr: number): Sprite {\n if (!gl) init();\n const g = gl!;\n const [rad, maxH] = EXTENT[spec.kind];\n const len = spec.length ?? (spec.kind === 'ruler' ? 300 : spec.kind === 'knife' ? 120 : 170);\n const r = spec.kind === 'pencil' || spec.kind === 'ruler' || spec.kind === 'knife' ? len / 2 + 14 : rad;\n const el = ((spec.elevation ?? DEFAULT_LIGHT.elevation) * Math.PI) / 180;\n const az = ((spec.azimuth ?? DEFAULT_LIGHT.azimuth) * Math.PI) / 180;\n const shadowLen = maxH / Math.tan(el) + 3;\n // shadow falls away from the light\n const sx = -Math.cos(az) * shadowLen, sy = -Math.sin(az) * shadowLen;\n const minX = -r + Math.min(0, sx) - 2, maxX = r + Math.max(0, sx) + 2;\n const minY = -r + Math.min(0, sy) - 2, maxY = r + Math.max(0, sy) + 2;\n const w = Math.ceil(maxX - minX), h = Math.ceil(maxY - minY);\n const W = Math.ceil(w * dpr), H = Math.ceil(h * dpr);\n (g.canvas as OffscreenCanvas).width = W;\n (g.canvas as OffscreenCanvas).height = H;\n g.viewport(0, 0, W, H);\n g.useProgram(prog);\n const c1 = parseColor(spec.color ?? '#d33b3b');\n const c2 = parseColor(spec.color2 ?? '#e8c79a');\n g.uniform2f(u('uOrigin'), -minX * dpr, -minY * dpr);\n g.uniform1f(u('uScale'), dpr);\n g.uniform1f(u('uAngle'), ((spec.angle ?? 0) * Math.PI) / 180);\n g.uniform3f(u('uLight'), Math.cos(el) * Math.cos(az), Math.cos(el) * Math.sin(az), Math.sin(el));\n g.uniform1i(u('uKind'), KIND_ID[spec.kind]);\n g.uniform3f(u('uColor'), c1[0], c1[1], c1[2]);\n g.uniform3f(u('uColor2'), c2[0], c2[1], c2[2]);\n g.uniform1f(u('uLength'), len);\n g.uniform1i(u('uPart'), spec.part === 'front' ? 1 : spec.part === 'back' ? 2 : 0);\n g.uniform1f(u('uSeed'), spec.seed ?? 0);\n g.uniform1f(u('uMaxH'), maxH);\n g.drawArrays(g.TRIANGLES, 0, 3);\n const px = new Uint8ClampedArray(W * H * 4);\n g.readPixels(0, 0, W, H, g.RGBA, g.UNSIGNED_BYTE, px);\n const canvas = document.createElement('canvas');\n canvas.width = W;\n canvas.height = H;\n canvas.getContext('2d')!.putImageData(new ImageData(px, W, H), 0, 0);\n canvas.style.width = `${w}px`;\n canvas.style.height = `${h}px`;\n if (spec.kind === 'ruler') labelRuler(canvas, -minX, -minY, len, spec.angle ?? 0, dpr);\n return { canvas, w, h, ox: -minX, oy: -minY };\n}\n\nfunction labelRuler(canvas: HTMLCanvasElement, ox: number, oy: number, len: number, angle: number, dpr: number) {\n const ctx = canvas.getContext('2d')!;\n ctx.save();\n ctx.scale(dpr, dpr);\n ctx.translate(ox, oy);\n ctx.rotate((angle * Math.PI) / 180);\n ctx.font = \"600 7.5px 'IBM Plex Mono', monospace\";\n ctx.fillStyle = 'rgba(30,30,32,0.85)';\n ctx.textAlign = 'center';\n const mm = 3.7795;\n for (let cm = 1; cm * 10 * mm < len - 18; cm++) ctx.fillText(String(cm), -len / 2 + 8 + cm * 10 * mm, -1);\n ctx.font = \"500 6px 'IBM Plex Mono', monospace\";\n ctx.textAlign = 'left';\n ctx.fillText('STAINLESS · 30 cm', -len / 2 + 10, 9);\n ctx.restore();\n}\n\nreturn { renderProp, dispose() { gl?.getExtension('WEBGL_lose_context')?.loseContext(); gl = null; loc.clear(); } };\n}\nlet shared: ReturnType<typeof createPropRenderer> | undefined;\nexport const renderProp: ReturnType<typeof createPropRenderer>['renderProp'] = (...args) => (shared ??= createPropRenderer()).renderProp(...args);\n","import { renderPaperLayers } from '../dom';\n/**\n * Turns card plans into DOM + pixels. Every sheet and prop is rendered with\n * the light expressed in its own (rotated) frame, so after CSS rotation all\n * shadows on the desk fall the same way.\n *\n * .card positioned + rotated (peel.ts owns the transform)\n * .shadow cast shadow: contact canvas + pre-blurred lifted canvas\n * .back attachments under the paper (paper-clip loop, tag string)\n * .paper (isolated) base canvas · ink (masked to the sheet) · shade canvas (hard-light) · sheen\n * .front pins, magnets, tape, clips\n */\nimport { mergeParams, type PaperParams, type SheetOutput } from '../index';\nimport type { Attach, CardPlan, SheetLook } from './scene';\nimport { PaperRenderer, stockParams as paperParams } from '../index';\nimport { runFits } from './fit';\nimport { createCordRenderer } from './cords';\nimport { EXTENT, createPropRenderer, type PropKind, type PropSpec } from './props';\nimport type { createPhotoRenderer } from './photos';\n\nexport type HolderKind = 'free' | 'adhesive' | 'taped' | 'pinned' | 'magnetic' | 'hung';\nexport interface HolderPoint {\n /** Card-local position (px). */\n x: number;\n y: number;\n /** The attachment's sprite, if it has one of its own. */\n el?: HTMLElement;\n /** Tape: on-card angle and length. */\n angle?: number;\n len?: number;\n}\nexport interface Holder {\n kind: HolderKind;\n points: HolderPoint[];\n}\nexport type Thickness = 'thin' | 'normal' | 'thick';\nexport interface BuiltCard {\n el: HTMLElement;\n paper: HTMLElement;\n /** Cast shadow layer (moves on its own when the card is lifted). */\n shadow: HTMLElement;\n /** Highlight gradient for the peel curl (opacity 0 at rest). */\n sheen: HTMLElement;\n holder: Holder;\n thickness: Thickness;\n /** Bendable copy of the layers for the pickup curl (built on first grab, dropped on re-render). */\n copy: Promise<HTMLElement> | null;\n /** On-screen rotation the pixels were lit for (null until rendered). */\n litFor: number | null;\n /** Render (or re-render) for an on-screen rotation; defaults to the plan's. */\n render(angle?: number): Promise<void>;\n}\nexport interface BuiltProp {\n el: HTMLElement;\n ox: number;\n oy: number;\n w: number;\n h: number;\n /** Soft shadow for when the prop is lifted (hidden at rest). */\n shadow: HTMLElement;\n /** Physical height (CSS px): how far it has to be lifted, how heavy it feels. */\n height: number;\n}\nexport function createSceneRenderer(options: { renderer: PaperRenderer; light: { azimuth: number; elevation: number }; grain: () => number; photos: ReturnType<typeof createPhotoRenderer>; pixelRatio?: () => number; onPrepared?: (plan: CardPlan, built: BuiltCard, angle: number) => void }) {\nconst props = createPropRenderer(), cords = createCordRenderer();\nconst LIGHT = options.light;\nconst getRenderer = () => options.renderer;\nconst { renderProp } = props; const { renderCord } = cords;\nconst { preloadPhotos, renderPhoto, runPhotos } = options.photos;\nconst dpr = () => options.pixelRatio?.() ?? Math.min(2, window.devicePixelRatio || 1);\n\n/** Shadow offset (CSS px) for an object lying flat, in screen space. */\nconst SHADOW = { x: 1.5, y: 4 };\n/** Blur (CSS px) of the shadow a lifted sheet casts. */\nconst LIFT_BLUR = 9;\n\nconst rot = (x: number, y: number, deg: number): [number, number] => {\n const a = (deg * Math.PI) / 180;\n const c = Math.cos(a), s = Math.sin(a);\n return [c * x - s * y, s * x + c * y];\n};\n\n/** Unit vector (screen space) a lifted object's shadow moves along: away from the light. */\nfunction shadowDir(): [number, number] {\n const [x, y] = rot(SHADOW.x, SHADOW.y, LIGHT.azimuth - 225);\n const l = Math.hypot(x, y) || 1;\n return [x / l, y / l];\n}\n\n/** Paper params with the desk's grain scale applied (densities scale 1/t rather than 1/t² so small papers stay calm). */\nfunction grainParams(key: string, overrides?: Parameters<typeof mergeParams>[1]): PaperParams {\n const base = overrides ? mergeParams(paperParams(key), overrides) : paperParams(key);\n const t = options.grain();\n return {\n ...base,\n scale: base.scale * t,\n fibers: { ...base.fibers, density: base.fibers.density / t },\n specks: { ...base.specks, density: base.specks.density / t },\n };\n}\n\nfunction sheetCanvas(data: Uint8ClampedArray, W: number, H: number, k: number, cls: string): HTMLCanvasElement {\n const c = document.createElement('canvas');\n c.className = cls;\n c.width = W;\n c.height = H;\n c.getContext('2d')!.putImageData(new ImageData(data as Uint8ClampedArray<ArrayBuffer>, W, H), 0, 0);\n c.style.width = `${W / k}px`;\n c.style.height = `${H / k}px`;\n return c;\n}\n\n/** A blurred copy of a canvas' alpha, in black, with `pad` CSS px of room for the blur. */\nfunction blurredShadow(src: HTMLCanvasElement, k: number, blur: number, cls: string): { canvas: HTMLCanvasElement; pad: number } {\n const pad = Math.ceil(blur * 2);\n const c = document.createElement('canvas');\n c.className = cls;\n c.width = src.width + 2 * pad * k;\n c.height = src.height + 2 * pad * k;\n const ctx = c.getContext('2d')!;\n ctx.filter = `blur(${blur * k}px)`;\n ctx.drawImage(src, pad * k, pad * k);\n ctx.filter = 'none';\n ctx.globalCompositeOperation = 'source-in';\n ctx.fillStyle = '#000';\n ctx.fillRect(0, 0, c.width, c.height);\n c.style.width = `${c.width / k}px`;\n c.style.height = `${c.height / k}px`;\n return { canvas: c, pad };\n}\n\n/** Render a sheet whose total on-screen rotation is `angle` degrees. */\nfunction sheetInputs(key: string, overrides: CardPlan['params'], look: SheetLook, w: number, h: number, angle: number) {\n const params = grainParams(key, overrides);\n params.lighting = { ...params.lighting, azimuth: LIGHT.azimuth - angle, elevation: LIGHT.elevation };\n // the shadow is cast in screen space; express it in the sheet's frame\n const sh = look.shadow === false ? false : { ...(look.shadow ?? {}) };\n if (sh) {\n const scale = Math.tan(((90 - LIGHT.elevation) * Math.PI) / 180) / Math.tan((42 * Math.PI) / 180);\n const ox = (sh.offsetX ?? SHADOW.x) * scale, oy = (sh.offsetY ?? SHADOW.y) * scale;\n // rotate the default down-right offset with the light, then into the sheet frame\n const [gx, gy] = rot(ox, oy, LIGHT.azimuth - 225);\n [sh.offsetX, sh.offsetY] = rot(gx, gy, -angle);\n }\n const k = dpr();\n return { params, spec: { ...look, width: w, height: h, pixelRatio: k, shadow: sh as SheetLook['shadow'] }, k };\n}\n\nfunction renderSheetFor(key: string, overrides: CardPlan['params'], look: SheetLook, w: number, h: number, angle: number, outputs: SheetOutput[]) {\n const { params, spec, k } = sheetInputs(key, overrides, look, w, h, angle);\n return { res: getRenderer().renderSheet(params, spec, outputs), k };\n}\n\n// ---------------------------------------------------------------- holders\n\n/** How a card is held down, which decides how it peels off and goes back on. */\n\n\n\n\n\n\n\n\nconst PIN_KINDS: PropKind[] = ['pushpin', 'mappin', 'thumbtack', 'staple'];\nconst MAGNET_KINDS: PropKind[] = ['magnet', 'magnet-neo', 'magnet-bar'];\nconst CLIP_KINDS: PropKind[] = ['binder', 'paperclip'];\n\nfunction thicknessOf(paper: string): Thickness {\n if (paper.startsWith('card') || paper === 'chipboard' || paper === 'polaroid') return 'thick';\n if (['napkin', 'tracing', 'thermal', 'newsprint', 'newsprint-old', 'clear-tape', 'washi', 'masking'].includes(paper)) return 'thin';\n return 'normal';\n}\n\nfunction deriveHolder(plan: CardPlan, sprites: Map<Attach, HTMLElement>): Holder {\n const pts = (pred: (a: Attach) => boolean): HolderPoint[] =>\n plan.attach.filter((a) => !a.binds && pred(a)).map((a) => {\n const el = sprites.get(a);\n if (a.type === 'sheet') return { x: a.x, y: a.y, el, angle: a.angle, len: a.w };\n if (a.type === 'prop') return { x: a.x, y: a.y, el };\n if (a.type === 'photo') return { x: a.cx, y: a.cy, el };\n return { x: plan.w / 2, y: 28, el };\n });\n const pins = pts((a) => a.type === 'prop' && PIN_KINDS.includes(a.prop.kind));\n if (pins.length) return { kind: 'pinned', points: pins };\n const magnets = pts((a) => a.type === 'prop' && MAGNET_KINDS.includes(a.prop.kind));\n if (magnets.length) return { kind: 'magnetic', points: magnets };\n const tapes = pts((a) => a.type === 'sheet' && a.label.endsWith('tape'));\n if (tapes.length) return { kind: 'taped', points: tapes };\n const clips = pts((a) => a.type === 'prop' && CLIP_KINDS.includes(a.prop.kind) && a.layer === 'front');\n if (clips.length) return { kind: 'hung', points: clips };\n const cords = pts((a) => a.type === 'cord');\n if (cords.length) return { kind: 'hung', points: cords };\n if (plan.paper === 'sticky') return { kind: 'adhesive', points: [{ x: plan.w / 2, y: plan.h * 0.09 }] };\n return { kind: 'free', points: [] };\n}\n\n// ---------------------------------------------------------------- cards\n\n\n\nfunction buildCard(plan: CardPlan): BuiltCard {\n const el = document.createElement('div');\n el.className = 'card pc-card';\n el.style.width = `${plan.w}px`;\n el.style.height = `${plan.h}px`;\n const shadow = document.createElement('div');\n shadow.className = 'shadow';\n const back = document.createElement('div');\n back.className = 'back';\n const paper = document.createElement('div');\n paper.className = 'paper';\n const front = document.createElement('div');\n front.className = 'front';\n const sheen = document.createElement('div');\n sheen.className = 'sheen';\n el.append(shadow, back, paper, front);\n\n const built: BuiltCard = { el, paper, shadow, sheen, holder: { kind: 'free', points: [] }, thickness: thicknessOf(plan.paper), copy: null, litFor: null, render: async () => {} };\n let prepared = false;\n built.render = async (angle = plan.rot) => {\n paper.replaceChildren();\n back.replaceChildren();\n front.replaceChildren();\n shadow.replaceChildren();\n built.copy = null;\n built.litFor = angle;\n // size text to its boxes (pretext) before anything is shown\n if (plan.ink) await runFits(plan.ink);\n if (!prepared) { options.onPrepared?.(plan, built, angle); prepared = true; }\n // photos: draw the ones printed on the card, load the ones attached to it\n if (plan.ink) await runPhotos(plan.ink);\n await preloadPhotos(plan.attach.flatMap((a) => (a.type === 'photo' ? [a.photo] : [])));\n const { params, spec, k } = sheetInputs(plan.paper, plan.params, plan.look, plan.w, plan.h, angle);\n const layers = renderPaperLayers(getRenderer(), params, spec);\n const contact = layers.shadow; contact.className = 'contact';\n const lifted = blurredShadow(contact, k, LIFT_BLUR, 'lifted');\n lifted.canvas.style.left = `${parseFloat(contact.style.left) - lifted.pad}px`;\n lifted.canvas.style.top = `${parseFloat(contact.style.top) - lifted.pad}px`;\n shadow.append(contact, lifted.canvas);\n layers.base.className = 'base'; layers.shade.className = 'shade';\n paper.append(layers.base);\n if (plan.ink) paper.append(plan.ink);\n paper.append(layers.shade, sheen);\n for (const target of [plan.ink, sheen]) {\n if (!target) continue;\n Object.assign(target.style, { maskImage: layers.mask, webkitMaskImage: layers.mask, maskPosition: layers.maskPosition, maskSize: layers.maskSize, maskRepeat: 'no-repeat' });\n }\n const sprites = new Map<Attach, HTMLElement>();\n for (const a of plan.attach) {\n const s = attach(a, angle, a.type === 'cord' ? front : a.layer === 'back' ? back : front, back);\n if (s) sprites.set(a, s);\n }\n built.holder = deriveHolder(plan, sprites);\n el.classList.add('ready');\n };\n return built;\n}\n\n/** Returns the attachment's main sprite (the one effects animate), if any. */\nfunction attach(a: Attach, cardRot: number, layer: HTMLElement, back: HTMLElement): HTMLElement | null {\n if (a.type === 'cord') {\n let main: HTMLElement | null = null;\n for (const part of ['back', 'front'] as const) {\n const s = renderCord(a.spec, part, dpr(), LIGHT.azimuth - cardRot, LIGHT.elevation);\n if (!s) continue;\n s.canvas.className = 'prop-sprite';\n s.canvas.style.left = `${-s.ox}px`;\n s.canvas.style.top = `${-s.oy}px`;\n (part === 'back' ? back : layer).appendChild(s.canvas);\n if (part === 'front') main = s.canvas;\n }\n return main;\n }\n if (a.type === 'html') {\n layer.appendChild(a.el);\n return a.el;\n }\n if (a.type === 'prop') {\n const s = renderProp({ ...a.prop, azimuth: LIGHT.azimuth - cardRot, elevation: LIGHT.elevation }, dpr());\n s.canvas.className = 'prop-sprite';\n s.canvas.style.left = `${a.x - s.ox}px`;\n s.canvas.style.top = `${a.y - s.oy}px`;\n s.canvas.style.transformOrigin = `${s.ox}px ${s.oy}px`;\n layer.appendChild(s.canvas);\n return s.canvas;\n }\n if (a.type === 'photo') return attachPhoto(a, cardRot, layer);\n const { res, k } = renderSheetFor(a.paper, a.params, a.look, a.w, a.h, cardRot + a.angle, ['color']);\n const c = sheetCanvas(res.maps.color!.data, res.width, res.height, k, 'tape');\n c.style.left = `${a.x - res.width / k / 2}px`;\n c.style.top = `${a.y - res.height / k / 2}px`;\n c.style.transform = `rotate(${a.angle}deg)`;\n layer.appendChild(c);\n return c;\n}\n\n/**\n * A photo print on a card: its own small sheet (so it bends, shines and casts\n * a shadow on the card like paper does) with the graded photo composited\n * between the sheet's base and shade, all on one canvas.\n */\nfunction attachPhoto(a: Extract<Attach, { type: 'photo' }>, cardRot: number, layer: HTMLElement): HTMLElement {\n const { res, k } = renderSheetFor(a.paper, a.params, a.look, a.w, a.h, cardRot + a.angle, ['base', 'shade', 'shadow']);\n const m = res.margin;\n const base = sheetCanvas(res.maps.base!.data, res.width, res.height, k, '');\n const shade = sheetCanvas(res.maps.shade!.data, res.width, res.height, k, '');\n const out = document.createElement('canvas');\n out.width = res.width;\n out.height = res.height;\n const g = out.getContext('2d')!;\n g.drawImage(base, 0, 0);\n const ph = renderPhoto(a.photo, a.window.w, a.window.h, k);\n g.globalCompositeOperation = 'source-atop';\n g.drawImage(ph, m + a.window.x * k, m + a.window.y * k);\n g.globalCompositeOperation = 'hard-light';\n g.drawImage(shade, 0, 0);\n g.globalCompositeOperation = 'destination-in';\n g.drawImage(base, 0, 0);\n const shadow = sheetCanvas(res.maps.shadow!.data, res.width, res.height, k, 'tape photo-shadow');\n const place = (c: HTMLCanvasElement) => {\n c.style.left = `${a.cx - res.width / k / 2}px`;\n c.style.top = `${a.cy - res.height / k / 2}px`;\n c.style.width = `${res.width / k}px`;\n c.style.height = `${res.height / k}px`;\n c.style.transform = `rotate(${a.angle}deg)`;\n return c;\n };\n out.className = 'tape photo-print';\n layer.append(place(shadow), place(out));\n return out;\n}\n\n// ---------------------------------------------------------------- props\n\n\n\n/** A loose prop lying on the desk (rendered in screen space, no CSS rotation). */\nfunction buildProp(spec: PropSpec): BuiltProp {\n const s = renderProp({ ...spec, azimuth: LIGHT.azimuth, elevation: LIGHT.elevation }, dpr());\n const el = document.createElement('div');\n el.className = 'prop';\n el.style.width = `${s.w}px`;\n el.style.height = `${s.h}px`;\n s.canvas.className = 'prop-sprite';\n const k = dpr();\n const lifted = blurredShadow(s.canvas, k, 7, 'lifted');\n const shadow = document.createElement('div');\n shadow.className = 'shadow';\n lifted.canvas.style.left = `${-lifted.pad}px`;\n lifted.canvas.style.top = `${-lifted.pad}px`;\n shadow.appendChild(lifted.canvas);\n el.append(shadow, s.canvas, hitShape(s.canvas, s.w, s.h));\n return { el, ox: s.ox, oy: s.oy, w: s.w, h: s.h, shadow, height: EXTENT[spec.kind][1] };\n}\n\n/** Grid step of a prop's hit shape (CSS px); also how far it reaches past the object, so thin things stay easy to grab. */\nconst HIT_CELL = 2;\n\n/**\n * The prop's own outline as an SVG hit area. The element is a box big enough for the\n * rotated object and its cast shadow, so it ignores pointers (style.css) and only this\n * shape takes them: cells where the sprite is opaque (the shadow is at most 42% alpha),\n * grown by one cell, as one path of row runs. Being DOM, it follows every transform.\n */\nfunction hitShape(sprite: HTMLCanvasElement, w: number, h: number): SVGSVGElement {\n const { data } = sprite.getContext('2d')!.getImageData(0, 0, sprite.width, sprite.height);\n const kx = sprite.width / w, ky = sprite.height / h;\n const cols = Math.ceil(w / HIT_CELL), rows = Math.ceil(h / HIT_CELL);\n const solid = new Uint8Array(cols * rows);\n for (let y = 0; y < sprite.height; y++)\n for (let x = 0; x < sprite.width; x++)\n if (data[(y * sprite.width + x) * 4 + 3] > 128) solid[Math.floor(y / ky / HIT_CELL) * cols + Math.floor(x / kx / HIT_CELL)] = 1;\n const on = (c: number, r: number) => {\n for (let dr = -1; dr <= 1; dr++)\n for (let dc = -1; dc <= 1; dc++) {\n const cc = c + dc, rr = r + dr;\n if (cc >= 0 && rr >= 0 && cc < cols && rr < rows && solid[rr * cols + cc]) return true;\n }\n return false;\n };\n let d = '';\n for (let r = 0; r < rows; r++)\n for (let c = 0; c < cols; c++) {\n if (!on(c, r)) continue;\n const c0 = c;\n while (c + 1 < cols && on(c + 1, r)) c++;\n d += `M${c0 * HIT_CELL} ${r * HIT_CELL}h${(c - c0 + 1) * HIT_CELL}v${HIT_CELL}h${-(c - c0 + 1) * HIT_CELL}z`;\n }\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n svg.setAttribute('class', 'prop-hit');\n svg.setAttribute('width', `${w}`);\n svg.setAttribute('height', `${h}`);\n const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');\n path.setAttribute('d', d);\n svg.appendChild(path);\n return svg;\n}\n\nreturn { buildCard, buildProp, shadowDir, grainParams, dpr, dispose() { props.dispose(); cords.dispose(); } };\n}\n","export interface PhotoMeta {\n id: string;\n w: number;\n h: number;\n /** Crop focus, 0..1 of the image. */\n focus: [number, number];\n captions: string[];\n}\n\nexport type Grade = 'none' | 'bw' | 'sepia' | 'faded' | 'instant' | 'warm' | 'expired';\n\nexport interface PhotoSpec {\n id: string;\n grade?: Grade;\n /** 0..1 */\n vignette?: number;\n /** 0..1 */\n grain?: number;\n /** Light leak from one edge. */\n leak?: boolean;\n /** Orange LCD date stamp in the corner (\"'98 7 14\"). */\n stamp?: string;\n /** Colour halftone screen (newsprint, magazines). */\n halftone?: boolean;\n /** Extra crop zoom (>= 1). */\n zoom?: number;\n seed?: number;\n}\n\nexport interface Box { x: number; y: number; w: number; h: number }\nexport const photoSpecs = new WeakMap<HTMLCanvasElement, PhotoSpec>();\nexport function photoLater(spec: PhotoSpec, box: Box, cls = '', style = '') {\n const c = document.createElement('canvas'); c.className = `photo ${cls}`.trim();\n c.style.cssText = `left:${box.x}px;top:${box.y}px;width:${box.w}px;height:${box.h}px;${style}`;\n photoSpecs.set(c, spec); return c;\n}\nexport function createPhotoRenderer(metadata: (id: string) => Pick<PhotoMeta, 'focus'>, url: (id: string) => string | Promise<string>, ratio = () => Math.min(2, devicePixelRatio || 1)) {\nconst ready = new Map<string, HTMLImageElement>();\nconst pending = new Map<string, Promise<HTMLImageElement>>();\nconst photoMeta = metadata;\nasync function loadPhoto(id: string): Promise<HTMLImageElement> {\n let task = pending.get(id);\n if (!task) { task = (async () => { const img = new Image(); img.crossOrigin = 'anonymous'; img.src = await url(id); await img.decode(); ready.set(id, img); return img; })().catch(e => { pending.delete(id); throw new Error(`Unable to load photo ${id}: ${e}`); }); pending.set(id, task); }\n return task;\n}\nconst FILTERS: Record<Grade, string> = {\n none: 'contrast(1.04) saturate(1.04)',\n bw: 'grayscale(1) contrast(1.18) brightness(1.03)',\n sepia: 'sepia(0.85) contrast(1.06) brightness(0.98) saturate(0.9)',\n faded: 'contrast(0.82) saturate(0.68) brightness(1.06)',\n instant: 'contrast(0.9) saturate(0.85) brightness(1.04)',\n warm: 'sepia(0.22) saturate(1.18) contrast(1.05)',\n expired: 'contrast(0.86) saturate(1.3) hue-rotate(-10deg) brightness(1.04)',\n};\n\nlet noiseTile: HTMLCanvasElement | null = null;\nfunction noise(): HTMLCanvasElement {\n if (noiseTile) return noiseTile;\n const c = document.createElement('canvas');\n c.width = c.height = 128;\n // Keep photo sampling deterministic across first use, cached images and exports.\n const g = c.getContext('2d', { willReadFrequently: true })!;\n const d = g.createImageData(128, 128);\n let s = 12345;\n for (let i = 0; i < d.data.length; i += 4) {\n s = (s * 1103515245 + 12345) >>> 0;\n const v = 128 + (((s >>> 16) & 255) - 128) * 0.9;\n d.data[i] = d.data[i + 1] = d.data[i + 2] = v;\n d.data[i + 3] = 255;\n }\n g.putImageData(d, 0, 0);\n return (noiseTile = c);\n}\n\n/** Cheap seeded hash so finishes vary per photo without an rng. */\nconst h01 = (seed: number, k: number) => {\n const x = Math.sin(seed * 12.9898 + k * 78.233) * 43758.5453;\n return x - Math.floor(x);\n};\n\n/** Colour halftone: rotated dot screens per channel, blended with the original. */\nfunction halftone(g: CanvasRenderingContext2D, W: number, H: number, k: number) {\n const img = g.getImageData(0, 0, W, H);\n const d = img.data;\n const period = 3.4 * k;\n const angles = [0.26, 1.31, 0.79].map((a) => [Math.cos(a), Math.sin(a)]);\n const TAU = (Math.PI * 2) / period;\n for (let y = 0; y < H; y++)\n for (let x = 0; x < W; x++) {\n const i = (y * W + x) * 4;\n for (let c = 0; c < 3; c++) {\n const [ca, sa] = angles[c];\n const u = (x * ca - y * sa) * TAU, v = (x * sa + y * ca) * TAU;\n const screen = 0.5 + 0.25 * (Math.cos(u) + Math.cos(v));\n const val = d[i + c] / 255;\n // ink (1 - val) covers the cell where the screen is below it; soft edge for antialiasing\n const t = Math.min(1, Math.max(0, (1 - val - screen) * 3 + 0.5));\n const dot = 1 - t;\n d[i + c] = Math.round((val * 0.45 + dot * 0.55) * 255);\n }\n }\n g.putImageData(img, 0, 0);\n}\n\n/**\n * Draw a graded photo into a `w` x `h` CSS-px box at `k` device px per px.\n * Synchronous: the image must have been loaded (`loadPhoto`).\n */\nfunction renderPhoto(spec: PhotoSpec, w: number, h: number, k: number): HTMLCanvasElement {\n const meta = photoMeta(spec.id);\n const src = ready.get(spec.id);\n if (!src) throw new Error(`Photo not loaded: ${spec.id}`);\n const W = Math.max(1, Math.round(w * k)), H = Math.max(1, Math.round(h * k));\n const c = document.createElement('canvas');\n c.width = W;\n c.height = H;\n // Keep photo sampling deterministic across first use, cached images and exports.\n const g = c.getContext('2d', { willReadFrequently: true })!;\n const iw = src instanceof HTMLImageElement ? src.naturalWidth : (src as HTMLCanvasElement).width;\n const ih = src instanceof HTMLImageElement ? src.naturalHeight : (src as HTMLCanvasElement).height;\n // cover-crop around the focus point\n const scale = Math.max(W / iw, H / ih) * (spec.zoom ?? 1);\n const sw = W / scale, sh = H / scale;\n const sx = Math.min(iw - sw, Math.max(0, meta.focus[0] * iw - sw / 2));\n const sy = Math.min(ih - sh, Math.max(0, meta.focus[1] * ih - sh / 2));\n const grade = spec.grade ?? 'none';\n const seed = spec.seed ?? 1;\n g.filter = FILTERS[grade];\n g.drawImage(src, sx, sy, sw, sh, 0, 0, W, H);\n g.filter = 'none';\n\n const fill = (op: GlobalCompositeOperation, style: string | CanvasGradient | CanvasPattern, alpha = 1) => {\n g.globalCompositeOperation = op;\n g.globalAlpha = alpha;\n g.fillStyle = style;\n g.fillRect(0, 0, W, H);\n g.globalAlpha = 1;\n g.globalCompositeOperation = 'source-over';\n };\n // lifted blacks and colour casts\n if (grade === 'faded') fill('lighten', 'rgb(46,40,52)');\n if (grade === 'sepia') fill('lighten', 'rgb(52,40,30)');\n if (grade === 'instant') {\n fill('lighten', 'rgb(34,50,54)');\n fill('soft-light', '#ffd9a0', 0.35);\n }\n if (grade === 'expired') {\n fill('lighten', 'rgb(40,30,46)');\n fill('soft-light', h01(seed, 1) < 0.5 ? '#ff6fa0' : '#6fffb0', 0.3);\n }\n if (spec.leak) {\n const side = Math.floor(h01(seed, 2) * 4);\n const lx = side === 0 ? 0 : side === 1 ? W : W * h01(seed, 3);\n const ly = side === 2 ? 0 : side === 3 ? H : H * h01(seed, 4);\n const r = Math.max(W, H) * (0.45 + 0.3 * h01(seed, 5));\n const grad = g.createRadialGradient(lx, ly, 0, lx, ly, r);\n grad.addColorStop(0, 'rgba(255,150,60,0.85)');\n grad.addColorStop(0.35, 'rgba(255,90,40,0.4)');\n grad.addColorStop(1, 'rgba(255,60,30,0)');\n fill('screen', grad);\n }\n if (spec.halftone) halftone(g, W, H, k);\n if (spec.vignette) {\n const grad = g.createRadialGradient(W / 2, H / 2, Math.min(W, H) * 0.3, W / 2, H / 2, Math.hypot(W, H) * 0.56);\n grad.addColorStop(0, 'rgba(0,0,0,0)');\n grad.addColorStop(1, `rgba(0,0,0,${spec.vignette.toFixed(2)})`);\n fill('multiply', grad);\n }\n if (spec.grain) {\n const pat = g.createPattern(noise(), 'repeat')!;\n pat.setTransform(new DOMMatrix().translate(h01(seed, 6) * 128, h01(seed, 7) * 128).scale(k * 0.6));\n fill('overlay', pat, 0.18 * spec.grain);\n }\n if (spec.stamp) {\n const px = Math.max(9, Math.min(w, h) * 0.075) * k;\n g.font = `${px}px VT323, monospace`;\n g.textAlign = 'right';\n g.textBaseline = 'alphabetic';\n g.shadowColor = 'rgba(255,120,30,0.9)';\n g.shadowBlur = px * 0.35;\n g.fillStyle = 'rgba(255,150,60,0.95)';\n g.fillText(spec.stamp, W - px * 0.9, H - px * 0.7);\n g.shadowBlur = 0;\n }\n return c;\n}\n\n\nasync function preloadPhotos(specs: PhotoSpec[]) {\n await Promise.all([ ...specs.map(s => loadPhoto(s.id)), ...(specs.some(s => s.stamp) ? [document.fonts.load('16px VT323')] : []) ]);\n}\nasync function runPhotos(root: HTMLElement) {\n const nodes = [...root.querySelectorAll<HTMLCanvasElement>('canvas.photo')].filter(c => photoSpecs.has(c));\n await preloadPhotos(nodes.map(c => photoSpecs.get(c)!));\n for (const c of nodes) { const image = renderPhoto(photoSpecs.get(c)!, parseFloat(c.style.width), parseFloat(c.style.height), ratio()); c.width = image.width; c.height = image.height; c.getContext('2d')!.drawImage(image, 0, 0); }\n}\nreturn { renderPhoto, preloadPhotos, runPhotos, loadPhoto, dispose() { pending.clear(); ready.clear(); noiseTile = null; } };\n}\n","import { fitLater, fitSpecs, type FitSpec } from './fit';\nimport { photoSpecs } from './photos';\nimport type { CompositionNode } from './model';\nconst tags = new Set('div span b i em strong s u small sub sup br p h1 h2 h3 ul ol li img canvas svg g path rect circle ellipse line polyline polygon text tspan defs clipPath mask pattern linearGradient radialGradient stop filter feTurbulence feDisplacementMap feColorMatrix feComposite title'.split(' '));\nconst allowedAttributes = new Set('class style id width height viewBox d fill stroke stroke-width stroke-linecap stroke-linejoin stroke-dasharray stroke-dashoffset fill-rule clip-rule opacity transform x y x1 y1 x2 y2 cx cy r rx ry points offset stop-color stop-opacity gradientUnits gradientTransform patternUnits patternTransform preserveAspectRatio xmlns filter clip-path mask font-size font-family text-anchor dominant-baseline type baseFrequency numOctaves seed result in in2 scale xChannelSelector yChannelSelector values operator aria-hidden aria-label role'.split(' '));\nexport function safeAttributes(attributes: Record<string, string> = {}) {\n const result: Record<string, string> = {};\n for (const [name, value] of Object.entries(attributes)) {\n if (!allowedAttributes.has(name) || /(?:javascript:|expression\\s*\\(|@import|behavior\\s*:)/i.test(value)) continue;\n if ([...value.matchAll(/url\\(([^)]*)\\)/gi)].some(m => !/^['\"]?#[\\w-]+['\"]?$/.test(m[1].trim()))) continue;\n result[name] = value;\n }\n return result;\n}\n/** Capture generator output before motion; not a snapshot of an animated card. */\nexport function describeNode(node: Node, prefix = 'n', counter = { n: 0 }): CompositionNode {\n const id = `${prefix}-${counter.n++}`;\n if (node.nodeType === Node.TEXT_NODE) return { id, text: node.textContent ?? '' };\n if (!(node instanceof Element) || !tags.has(node.localName)) throw new Error(`Unsupported composition element ${node.nodeName}`);\n node.setAttribute('data-pc-node', id);\n const attributes = safeAttributes(Object.fromEntries([...node.attributes].filter(a => a.name !== 'data-pc-node').map(a => [a.name, a.value])));\n const fit = fitSpecs.get(node as HTMLElement);\n const photo = photoSpecs.get(node as HTMLCanvasElement);\n return { id, tag: node.localName, ...(node.namespaceURI?.includes('svg') ? { namespace: 'svg' as const } : {}), attributes,\n children: [...node.childNodes].filter(n => n.nodeType === Node.ELEMENT_NODE || n.nodeType === Node.TEXT_NODE).map(n => describeNode(n, prefix, counter)),\n ...(fit ? { fit: { spec: structuredClone(fit), ...(node.hasAttribute('data-fit') ? { resolved: JSON.stringify(fit) } : {}) } } : {}),\n ...(photo ? { photo: structuredClone(photo) } : {}),\n };\n}\nfunction safeFit(spec: FitSpec): FitSpec {\n const result = structuredClone(spec);\n for (const block of result.blocks) if (block.html) {\n const template = document.createElement('template'); template.innerHTML = block.html;\n const clean = document.createElement('div');\n for (const node of template.content.childNodes) {\n if (node.nodeType === Node.TEXT_NODE || (node instanceof Element && tags.has(node.localName))) clean.append(materializeNode(describeNode(node), 'fit'));\n }\n block.html = clean.innerHTML;\n }\n return result;\n}\nexport function materializeNode(node: CompositionNode, scope: string): Node {\n if (!node.tag) return document.createTextNode(node.text ?? '');\n const prefix = scope ? `${scope}-` : '';\n if (!tags.has(node.tag)) throw new Error(`Unsupported composition tag ${node.tag}`);\n const el = node.namespace === 'svg' ? document.createElementNS('http://www.w3.org/2000/svg', node.tag) : document.createElement(node.tag);\n for (const [name, value] of Object.entries(safeAttributes(node.attributes))) {\n el.setAttribute(name, name === 'id' ? `${prefix}${value}` : value.replace(/url\\(['\"]?#([\\w-]+)['\"]?\\)/g, `url(#${prefix}$1)`));\n }\n el.setAttribute('data-pc-node', node.id);\n for (const child of node.children ?? []) el.appendChild(materializeNode(child, scope));\n if (node.photo) photoSpecs.set(el as HTMLCanvasElement, structuredClone(node.photo));\n if (node.fit) {\n const spec = safeFit(node.fit.spec);\n fitSpecs.set(el as HTMLElement, spec);\n if (node.fit.resolved !== JSON.stringify(node.fit.spec)) fitLater(el as HTMLElement, spec);\n }\n return el;\n}\n","import type { AssetResolver, CompositionAsset } from './model';\nimport type { PenContext } from './pen';\nimport type { TegakiBundle } from 'tegaki/core';\n\n/** Font faces are shared with reference counting; unmounting one instance cannot break another. */\nconst fonts = new Map<string, { count: number; face: FontFace; ready: Promise<FontFace> }>();\nexport async function loadCompositionAssets(assets: CompositionAsset[], resolve: AssetResolver, pen: boolean) {\n const urls = new Map<string, string>();\n const releases: (() => void)[] = [];\n let disposed = false;\n const dispose = () => { if (disposed) return; disposed = true; releases.forEach(release => release()); };\n try {\n for (const asset of assets) urls.set(asset.id, await resolve(asset));\n await Promise.all(assets.filter(a => a.kind === 'font').map(async asset => {\n const url = urls.get(asset.id)!;\n if (!asset.family) throw new Error(`Missing font family for ${asset.id}`);\n const key = JSON.stringify([asset.family, asset.descriptors, url]);\n let entry = fonts.get(key);\n if (!entry) {\n const face = new FontFace(asset.family, `url(${JSON.stringify(url)})`, asset.descriptors);\n entry = { count: 0, face, ready: face.load() }; fonts.set(key, entry);\n }\n entry.count++;\n const current = entry;\n releases.push(() => { if (--current.count === 0) { document.fonts.delete(current.face); fonts.delete(key); } });\n await current.ready; if (!disposed) document.fonts.add(current.face);\n }));\n let penContext: PenContext | undefined;\n if (pen) {\n const penAssets = assets.filter(a => a.kind === 'pen');\n if (penAssets.length) {\n const { TegakiEngine } = await import('tegaki/core');\n const bundles = new Map<string, TegakiBundle>();\n for (const asset of penAssets) {\n const response = await fetch(urls.get(asset.id)!);\n if (!response.ok) throw new Error(`Unable to load pen data ${asset.id}`);\n const data = await response.json();\n const font = assets.find(a => a.kind === 'font' && a.family === asset.family);\n if (!font) throw new Error(`Missing pen font ${asset.family}`);\n const bundle = { ...data, fontUrl: urls.get(font.id), fontFaceCSS: undefined } as TegakiBundle;\n await TegakiEngine.preload(bundle);\n bundles.set(bundle.family.toLowerCase(), bundle);\n if (asset.matches) bundles.set(asset.matches.toLowerCase(), bundle);\n }\n penContext = { Engine: TegakiEngine, bundleFor: family => bundles.get(family.split(',')[0].trim().replace(/^['\"]|['\"]$/g, '').toLowerCase()) };\n }\n }\n return { urls, penContext, dispose };\n } catch (error) { dispose(); throw error; }\n}\n","export const filterMarkup = \" <svg width=\\\"0\\\" height=\\\"0\\\" style=\\\"position: absolute\\\" aria-hidden=\\\"true\\\">\\n <filter id=\\\"f-ink\\\" x=\\\"-5%\\\" y=\\\"-5%\\\" width=\\\"110%\\\" height=\\\"110%\\\">\\n <feTurbulence type=\\\"fractalNoise\\\" baseFrequency=\\\"0.8\\\" numOctaves=\\\"2\\\" seed=\\\"4\\\" result=\\\"n\\\" />\\n <feDisplacementMap in=\\\"SourceGraphic\\\" in2=\\\"n\\\" scale=\\\"1.4\\\" xChannelSelector=\\\"R\\\" yChannelSelector=\\\"G\\\" />\\n </filter>\\n <filter id=\\\"f-pencil\\\" x=\\\"-5%\\\" y=\\\"-5%\\\" width=\\\"110%\\\" height=\\\"110%\\\">\\n <feTurbulence type=\\\"fractalNoise\\\" baseFrequency=\\\"1.3\\\" numOctaves=\\\"2\\\" seed=\\\"9\\\" result=\\\"n\\\" />\\n <feColorMatrix in=\\\"n\\\" type=\\\"matrix\\\" values=\\\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2.4 0 0 0 -0.55\\\" result=\\\"m\\\" />\\n <feComposite in=\\\"SourceGraphic\\\" in2=\\\"m\\\" operator=\\\"in\\\" result=\\\"g\\\" />\\n <feDisplacementMap in=\\\"g\\\" in2=\\\"n\\\" scale=\\\"1\\\" xChannelSelector=\\\"G\\\" yChannelSelector=\\\"B\\\" />\\n </filter>\\n <filter id=\\\"f-stamp\\\" x=\\\"-5%\\\" y=\\\"-10%\\\" width=\\\"110%\\\" height=\\\"120%\\\">\\n <feTurbulence type=\\\"fractalNoise\\\" baseFrequency=\\\"0.55\\\" numOctaves=\\\"3\\\" seed=\\\"2\\\" result=\\\"n\\\" />\\n <feColorMatrix in=\\\"n\\\" type=\\\"matrix\\\" values=\\\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3.2 0 0 0 -0.75\\\" result=\\\"m\\\" />\\n <feComposite in=\\\"SourceGraphic\\\" in2=\\\"m\\\" operator=\\\"in\\\" result=\\\"g\\\" />\\n <feDisplacementMap in=\\\"g\\\" in2=\\\"n\\\" scale=\\\"1.6\\\" xChannelSelector=\\\"R\\\" yChannelSelector=\\\"G\\\" />\\n </filter>\\n <filter id=\\\"f-wash\\\" x=\\\"-10%\\\" y=\\\"-10%\\\" width=\\\"120%\\\" height=\\\"120%\\\">\\n <feTurbulence type=\\\"fractalNoise\\\" baseFrequency=\\\"0.035\\\" numOctaves=\\\"3\\\" seed=\\\"7\\\" result=\\\"n\\\" />\\n <feDisplacementMap in=\\\"SourceGraphic\\\" in2=\\\"n\\\" scale=\\\"16\\\" xChannelSelector=\\\"R\\\" yChannelSelector=\\\"G\\\" result=\\\"d\\\" />\\n <feTurbulence type=\\\"fractalNoise\\\" baseFrequency=\\\"0.9\\\" numOctaves=\\\"2\\\" seed=\\\"5\\\" result=\\\"g\\\" />\\n <feColorMatrix in=\\\"g\\\" type=\\\"matrix\\\" values=\\\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1.2 0 0 0 0.25\\\" result=\\\"ga\\\" />\\n <feComposite in=\\\"d\\\" in2=\\\"ga\\\" operator=\\\"in\\\" />\\n </filter>\\n <filter id=\\\"f-stain\\\" x=\\\"-10%\\\" y=\\\"-10%\\\" width=\\\"120%\\\" height=\\\"120%\\\">\\n <feTurbulence type=\\\"fractalNoise\\\" baseFrequency=\\\"0.06\\\" numOctaves=\\\"3\\\" seed=\\\"11\\\" result=\\\"n\\\" />\\n <feDisplacementMap in=\\\"SourceGraphic\\\" in2=\\\"n\\\" scale=\\\"7\\\" xChannelSelector=\\\"R\\\" yChannelSelector=\\\"G\\\" />\\n </filter>\\n </svg>\";\n","/** Small seeded PRNG (mulberry32) with helpers. */\nexport interface Rng {\n (): number;\n range(a: number, b: number): number;\n int(a: number, b: number): number;\n pick<T>(a: readonly T[]): T;\n chance(p: number): boolean;\n weighted<T>(items: readonly T[], weight: (t: T) => number): T;\n fork(): Rng;\n}\n\nexport function makeRng(seed: number): Rng {\n let s = seed >>> 0 || 0x9e3779b9;\n const next = () => {\n s = (s + 0x6d2b79f5) >>> 0;\n let t = s;\n t = Math.imul(t ^ (t >>> 15), t | 1);\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n const r = next as Rng;\n r.range = (a, b) => a + (b - a) * next();\n r.int = (a, b) => Math.floor(a + (b - a + 1) * next());\n r.pick = (a) => a[Math.floor(next() * a.length)];\n r.chance = (p) => next() < p;\n r.weighted = (items, weight) => {\n const total = items.reduce((t, i) => t + weight(i), 0);\n let x = next() * total;\n for (const i of items) if ((x -= weight(i)) < 0) return i;\n return items[items.length - 1];\n };\n r.fork = () => makeRng(Math.floor(next() * 4294967296));\n return r;\n}\n","import type { PaperParams } from '../params';\nimport type { FitSpec } from './fit';\nimport type { PhotoSpec, PhotoMeta } from './photos';\nimport type { Attach, CardInfo, SheetLook } from './scene';\nimport type { MotionSpec } from './motion-spec';\n\nexport interface CompositionAsset {\n id: string;\n kind: 'photo' | 'font' | 'pen';\n file: string;\n family?: string;\n descriptors?: { weight?: string; style?: string; unicodeRange?: string };\n photo?: Pick<PhotoMeta, 'focus'>;\n /** Pen bundle family may differ from the name used by text. */\n matches?: string;\n credits: string;\n licenseFiles: string[];\n}\nexport interface CompositionNode {\n id: string;\n tag?: string;\n namespace?: 'svg';\n text?: string;\n attributes?: Record<string, string>;\n children?: CompositionNode[];\n photo?: PhotoSpec;\n fit?: { spec: FitSpec; resolved?: string };\n}\nexport type CompositionAttachment = Exclude<Attach, { type: 'html' }> | { type: 'html'; layer: 'front' | 'back'; node: CompositionNode; label?: string; binds?: boolean };\nexport interface PaperComposition {\n version: 1;\n kind: string;\n width: number;\n height: number;\n rotation: number;\n paper: string;\n params: PaperParams;\n sheet: SheetLook;\n environment: { grain: number; light: { azimuth: number; elevation: number }; pixelRatio: number };\n content: CompositionNode | null;\n attachments: CompositionAttachment[];\n assets: CompositionAsset[];\n info: CardInfo;\n motion?: MotionSpec;\n motionSeed: number;\n pen: boolean;\n}\nexport type AssetResolver = (asset: CompositionAsset) => string | Promise<string>;\nexport function visitNodes(composition: PaperComposition, fn: (node: CompositionNode) => void) {\n const visit = (n: CompositionNode) => { fn(n); n.children?.forEach(visit); };\n if (composition.content) visit(composition.content);\n for (const a of composition.attachments) if (a.type === 'html') visit(a.node);\n}\nexport function setCompositionText(composition: PaperComposition, nodeId: string, text: string): PaperComposition {\n const copy = structuredClone(composition); let found = false;\n visitNodes(copy, node => {\n if (node.id !== nodeId) return;\n found = true;\n const descendants = new Set<string>();\n const collect = (n: CompositionNode) => { descendants.add(n.id); n.children?.forEach(collect); };\n node.children?.forEach(collect);\n if (node.tag) for (const step of copy.motion?.steps ?? []) {\n if (typeof step.target === 'string') step.target = [...new Set(step.target.split(',').map(target => descendants.has(target.match(/\"([\\w-]+)\"/)?.[1] ?? '') ? `[data-pc-node=\"${node.id}\"]` : target))].join(',');\n }\n if (node.fit) {\n node.fit.spec.blocks = [{ text, keep: true }]; delete node.fit.resolved; node.children = [];\n } else if (!node.tag) node.text = text;\n else node.children = [{ id: `${node.id}-text`, text }];\n });\n if (!found) throw new Error(`Unknown content node ${nodeId}`);\n return copy;\n}\nexport function validateComposition(value: PaperComposition) {\n if (value.version !== 1) throw new Error('Unsupported paper composition version');\n if (![value.width, value.height, value.environment.pixelRatio].every(n => Number.isFinite(n) && n > 0)) throw new Error('Invalid composition dimensions');\n if (![value.rotation, value.environment.grain, value.environment.light.azimuth, value.environment.light.elevation, value.motionSeed].every(Number.isFinite)) throw new Error('Invalid composition environment');\n if (!Array.isArray(value.assets) || !Array.isArray(value.attachments)) throw new Error('Invalid composition assets or attachments');\n const ids = new Set<string>();\n visitNodes(value, n => { if (!/^[\\w-]+$/.test(n.id) || ids.has(n.id)) throw new Error(`Invalid or duplicate node ID ${n.id}`); ids.add(n.id); });\n const assets = new Set<string>();\n for (const a of value.assets) {\n if (assets.has(a.id) || !a.file || a.file.includes('..') || a.file.includes('\\\\') || /^(?:[a-z]+:|\\/)/i.test(a.file)) throw new Error(`Invalid asset ${a.id}`);\n assets.add(a.id);\n }\n visitNodes(value, n => { if (n.photo && !assets.has(n.photo.id)) throw new Error(`Missing photo ${n.photo.id}`); });\n for (const a of value.attachments) if (a.type === 'photo' && !assets.has(a.photo.id)) throw new Error(`Missing photo ${a.photo.id}`);\n for (const step of value.motion?.steps ?? []) {\n if (typeof step.target !== 'string' || !/^\\[data-pc-node=\"[\\w-]+\"\\](,\\[data-pc-node=\"[\\w-]+\"\\])*$/.test(step.target)) throw new Error('Motion targets must reference composition node IDs');\n for (const match of step.target.matchAll(/\"([\\w-]+)\"/g)) if (!ids.has(match[1])) throw new Error(`Missing animation target ${match[1]}`);\n }\n}\n","import { PaperRenderer } from '../index';\nimport { createSceneRenderer, type BuiltCard } from './renderer';\nimport { createPhotoRenderer } from './photos';\nimport { materializeNode, describeNode } from './nodes';\nimport { loadCompositionAssets } from './assets';\nimport { filterMarkup } from './filters';\nimport { makeRng } from './rng';\nimport { validateComposition, type AssetResolver, type PaperComposition } from './model';\nimport type { CardPlan } from './scene';\nimport type { CardMotion } from './motion';\nexport * from './model';\nexport type { CompositionNode } from './model';\nexport interface CompositionOptions {\n composition: PaperComposition;\n resolveAsset: AssetResolver;\n autoplay?: boolean;\n fit?: 'natural' | 'contain';\n renderer?: PaperRenderer;\n}\nexport interface CompositionHandle {\n element: HTMLDivElement;\n readonly ready: Promise<void>;\n readonly rendered: boolean;\n update(options: Partial<CompositionOptions>): Promise<void>;\n play(): void; pause(): void; replay(): void; seek(progress: number): void;\n dispose(): void;\n}\nlet instance = 0;\nexport function hydrateComposition(composition: PaperComposition, scope: string): CardPlan {\n return {\n w: composition.width, h: composition.height, rot: composition.rotation, paper: composition.paper,\n params: composition.params, look: composition.sheet, info: composition.info,\n ink: composition.content ? materializeNode(composition.content, scope) as HTMLElement : null,\n attach: composition.attachments.map(a => a.type === 'html' ? { ...a, el: materializeNode(a.node, scope) as HTMLElement } : structuredClone(a)),\n motion: composition.motion,\n };\n}\n/** Use the same SVG filter definitions, with instance-local IDs. */\nexport function mountCompositionFilters(host: HTMLElement, scope: string) {\n const template = document.createElement('template'); template.innerHTML = filterMarkup;\n const svg = materializeNode(describeNode(template.content.firstElementChild!), scope);\n host.append(svg);\n for (const name of ['ink','pencil','stamp','wash','stain']) host.style.setProperty(`--pc-f-${name}`, `url(#${scope}-f-${name})`);\n}\nexport function createPaperComposition(initial: CompositionOptions): CompositionHandle {\n let options = initial, revision = 0, disposed = false, rendered = false;\n const element = document.createElement('div'); element.className = 'pc-composition';\n let motion: CardMotion | null = null;\n let cleanup = () => {};\n let currentReady: Promise<void> = Promise.resolve();\n const scope = `pc-${++instance}`;\n let resize: ResizeObserver | undefined;\n function bounds(built: BuiltCard, rotation: number) {\n const root = built.el; root.style.transform = 'none';\n const base = root.getBoundingClientRect();\n let minX = -24, minY = -24, maxX = root.offsetWidth + 24, maxY = root.offsetHeight + 24;\n for (const canvas of root.querySelectorAll('canvas')) {\n if (canvas.classList.contains('lifted')) continue;\n const rect = canvas.getBoundingClientRect();\n minX = Math.min(minX, rect.left - base.left); minY = Math.min(minY, rect.top - base.top);\n maxX = Math.max(maxX, rect.right - base.left); maxY = Math.max(maxY, rect.bottom - base.top);\n }\n for (const decoration of root.querySelectorAll('.front > *, .back > *')) {\n const rect = decoration.getBoundingClientRect();\n minX = Math.min(minX, rect.left - base.left - 8); minY = Math.min(minY, rect.top - base.top - 8);\n maxX = Math.max(maxX, rect.right - base.left + 8); maxY = Math.max(maxY, rect.bottom - base.top + 8);\n }\n const a = rotation * Math.PI / 180, cs = Math.cos(a), sn = Math.sin(a);\n const corners = [[minX,minY],[maxX,minY],[maxX,maxY],[minX,maxY]].map(([x,y]) => [x*cs-y*sn,x*sn+y*cs]);\n const left = Math.min(...corners.map(p=>p[0])), top = Math.min(...corners.map(p=>p[1]));\n const width = Math.max(...corners.map(p=>p[0]))-left, height = Math.max(...corners.map(p=>p[1]))-top;\n const resizeToFit = () => {\n const available = element.parentElement?.clientWidth ?? width;\n const scale = options.fit === 'contain' ? Math.min(1, available / width) : 1;\n element.style.width = `${width * scale}px`; element.style.height = `${height * scale}px`;\n root.style.left = `${-left * scale}px`; root.style.top = `${-top * scale}px`;\n root.style.transform = `scale(${scale}) rotate(${rotation}deg)`;\n };\n resizeToFit();\n if (options.fit === 'contain' && element.parentElement) { resize = new ResizeObserver(resizeToFit); resize.observe(element.parentElement); }\n }\n async function render() {\n if (disposed) return;\n const token = ++revision; cleanup(); resize?.disconnect(); motion = null; rendered = false;\n element.replaceChildren(); element.dataset.rendered = 'loading';\n const config = options, value = structuredClone(config.composition); validateComposition(value);\n const fallback = document.createElement('div'); fallback.style.cssText = `width:${value.width}px;height:${value.height}px;background:${value.params.color.base}`;\n fallback.textContent = value.info.kind; element.append(fallback);\n const loaded = await loadCompositionAssets(value.assets, config.resolveAsset, value.pen);\n if (disposed || token !== revision) { loaded.dispose(); return; }\n const renderer = config.renderer ?? new PaperRenderer();\n const photos = createPhotoRenderer(id => {\n const asset = value.assets.find(a => a.id === id); if (!asset?.photo) throw new Error(`Missing photo metadata: ${id}`); return asset.photo;\n }, id => { const url = loaded.urls.get(id); if (!url) throw new Error(`Missing photo asset: ${id}`); return url; }, () => value.environment.pixelRatio);\n const scene = createSceneRenderer({ renderer, photos, light: value.environment.light, grain: () => value.environment.grain, pixelRatio: () => value.environment.pixelRatio });\n let localMotion: CardMotion | null = null;\n let released = false;\n const release = () => { if (released) return; released = true; localMotion?.dispose(); photos.dispose(); scene.dispose(); if (!config.renderer) renderer.dispose(); loaded.dispose(); };\n cleanup = release;\n try {\n const plan = hydrateComposition(value, scope);\n element.replaceChildren(); mountCompositionFilters(element, scope);\n const built = scene.buildCard(plan); element.append(built.el);\n if (!renderer.gl) {\n built.paper.style.background = value.params.color.base;\n if (plan.ink) built.paper.append(plan.ink);\n element.dataset.rendered = 'fallback'; bounds(built, value.rotation); return;\n }\n await built.render(value.rotation);\n if (disposed || token !== revision) { release(); return; }\n if (value.motion?.steps.length && plan.ink) {\n const { prepareMotion } = await import('./motion');\n if (disposed || token !== revision) { release(); return; }\n localMotion = prepareMotion(plan, built, makeRng(value.motionSeed), loaded.penContext);\n motion = localMotion;\n if (config.autoplay !== false) motion?.play(); else motion?.finish();\n }\n bounds(built, value.rotation);\n rendered = true; element.dataset.rendered = 'webgl2';\n } catch (error) {\n release();\n throw error;\n }\n }\n function startRender() {\n const task = render(), token = revision;\n return task.catch(error => {\n if (token === revision && !disposed) { element.dataset.rendered = 'error'; element.dispatchEvent(new CustomEvent('papererror', { detail: error })); }\n throw error;\n });\n }\n currentReady = Promise.resolve().then(() => { if (!revision && !disposed) return startRender(); });\n // Callers can await ready; avoid an unhandled rejection before they attach a listener.\n void currentReady.catch(() => {});\n return {\n element, get ready() { return currentReady; }, get rendered() { return rendered; },\n update(patch) { if (disposed) return Promise.reject(new Error('Composition disposed')); options = { ...options, ...patch }; currentReady = startRender(); void currentReady.catch(() => {}); return currentReady; },\n play() { motion?.resume(); }, pause() { motion?.pause(); }, replay() { motion?.replay(); }, seek(p) { motion?.seek(p); },\n dispose() { if (disposed) return; disposed = true; revision++; resize?.disconnect(); cleanup(); element.remove(); },\n };\n}\n"],"names":["REF","loaded","prepared","fontString","f","weight","px","ensureFont","key","p","prep","text","spacingEm","ws","prepare","measure","spec","size","count","h","lines","i","b","s","n","layout","lh","fitText","w","fits","m","lo","hi","k","mid","esc","fitSpecs","jobs","blocksHTML","blocks","st","fitLater","el","runFits","root","els","e","before","r","KIND_ID","MAXP","FS","VS","createCordRenderer","gl","prog","loc","u","init","g","sh","type","src","renderCord","part","dpr","azimuth","elevation","P","A","minX","minY","maxX","maxY","any","line","li","arc","start","pt","layer","q","x","y","pad","W","H","K","az","c1","parseColor","c2","canvas","EXTENT","createPropRenderer","vao","buf","DEFAULT_LIGHT","renderProp","rad","maxH","len","shadowLen","sx","sy","labelRuler","ox","oy","angle","ctx","mm","cm","createSceneRenderer","options","props","cords","LIGHT","getRenderer","preloadPhotos","renderPhoto","runPhotos","SHADOW","LIFT_BLUR","rot","deg","a","c","shadowDir","l","grainParams","overrides","base","mergeParams","paperParams","t","sheetCanvas","data","cls","blurredShadow","blur","sheetInputs","look","params","scale","gx","gy","renderSheetFor","outputs","PIN_KINDS","MAGNET_KINDS","CLIP_KINDS","thicknessOf","paper","deriveHolder","plan","sprites","pts","pred","pins","magnets","tapes","clips","buildCard","shadow","back","front","sheen","built","layers","renderPaperLayers","contact","lifted","target","attach","cardRot","main","attachPhoto","res","shade","out","ph","place","buildProp","hitShape","HIT_CELL","sprite","kx","ky","cols","rows","solid","on","dr","dc","cc","rr","d","c0","svg","path","photoSpecs","createPhotoRenderer","metadata","url","ratio","ready","pending","photoMeta","loadPhoto","id","task","img","FILTERS","noiseTile","noise","v","h01","seed","halftone","period","angles","TAU","ca","sa","screen","val","dot","meta","iw","ih","sw","grade","fill","op","style","alpha","side","lx","ly","grad","pat","specs","nodes","image","tags","allowedAttributes","safeAttributes","attributes","result","name","value","describeNode","node","prefix","counter","fit","photo","safeFit","block","template","clean","materializeNode","scope","child","fonts","loadCompositionAssets","assets","resolve","pen","urls","releases","disposed","dispose","release","asset","entry","face","current","penContext","penAssets","TegakiEngine","bundles","response","font","bundle","family","error","filterMarkup","makeRng","next","items","total","visitNodes","composition","fn","visit","setCompositionText","nodeId","copy","found","descendants","collect","step","validateComposition","ids","match","instance","hydrateComposition","mountCompositionFilters","host","createPaperComposition","initial","revision","rendered","element","motion","cleanup","currentReady","resize","bounds","rotation","rect","decoration","cs","sn","corners","left","top","width","height","resizeToFit","available","render","token","config","fallback","renderer","PaperRenderer","photos","scene","localMotion","released","prepareMotion","startRender","patch"],"mappings":";;;AAyDA,MAAMA,KAAM,KACNC,yBAAa,IAAA,GACbC,yBAAe,IAAA;AAErB,SAASC,GAAWC,GAASC,GAAgBC,GAAY;AACvD,SAAO,GAAGD,CAAM,IAAIC,CAAE,OAAOF,EAAE,MAAM;AACvC;AAEA,SAASG,GAAWH,GAASC,GAAgB;AAC3C,QAAMG,IAAM,GAAGH,CAAM,IAAID,EAAE,MAAM;AACjC,MAAIK,IAAIR,GAAO,IAAIO,CAAG;AACtB,SAAKC,MACHA,IAAI,SAAS,MAAM,KAAKN,GAAWC,GAAGC,GAAQ,EAAE,GAAG,QAAQ,EAAE,MAAM,MAAA;AAAA,GAAe,GAClFJ,GAAO,IAAIO,GAAKC,CAAC,IAEZA;AACT;AAEA,SAASC,GAAKC,GAAcP,GAASC,GAAgBO,GAAmBC,GAA2B;AACjG,QAAML,IAAM,GAAGJ,EAAE,MAAM,IAAIC,CAAM,IAAIO,CAAS,IAAIC,CAAE,IAAIF,CAAI;AAC5D,MAAIF,IAAIP,GAAS,IAAIM,CAAG;AACxB,SAAKC,MACHA,IAAIK,GAAQH,GAAMR,GAAWC,GAAGC,GAAQL,EAAG,GAAG,EAAE,YAAYa,GAAI,eAAeD,IAAYZ,IAAK,GAChGE,GAAS,IAAIM,GAAKC,CAAC,IAEdA;AACT;AAGA,SAASM,GAAQC,GAAeC,GAAcC,GAAe;AAC3D,QAAMb,IAASW,EAAK,UAAU,OACxBH,IAAKG,EAAK,cAAc;AAC9B,MAAIG,IAAI,GAAGC,IAAQ;AACnB,WAASC,IAAI,GAAGA,IAAIH,GAAOG,KAAK;AAC9B,UAAMC,IAAIN,EAAK,OAAOK,CAAC,GACjBE,IAAIN,KAAQK,EAAE,SAAS,IACvBb,IAAIC,GAAKY,EAAE,MAAMN,EAAK,MAAMM,EAAE,UAAUjB,GAAQiB,EAAE,WAAW,GAAGT,CAAE,GAClEW,IAAIF,EAAE,OAAOG,GAAOhB,GAAIO,EAAK,QAAQhB,KAAOuB,GAAG,CAAC,EAAE,YAAY,GAC9DG,IAAKV,EAAK,SAASO,KAAKP,EAAK,cAAc;AACjD,IAAAG,KAAKK,IAAIE,KAAMJ,EAAE,OAAO,KAAKC,GAC7BH,KAASI;AAAA,EACX;AACA,SAAO,EAAE,GAAAL,GAAG,OAAAC,EAAA;AACd;AAEA,eAAsBO,GAAQX,GAAmC;AAC/D,QAAM,QAAQ,IAAI,CAACA,EAAK,UAAU,OAAO,GAAGA,EAAK,OAAO,IAAI,CAACM,MAAMA,EAAE,MAAM,EAAE,OAAO,OAAO,CAAC,EAAE,IAAI,CAACM,MAAMrB,GAAWS,EAAK,MAAMY,CAAE,CAAC,CAAC;AACnI,QAAMC,IAAO,CAACZ,GAAcC,MAAkB;AAC5C,UAAMY,IAAIf,GAAQC,GAAMC,GAAMC,CAAK;AACnC,WAAOY,EAAE,KAAKd,EAAK,SAAS,QAAQA,EAAK,aAAa,UAAac,EAAE,SAASd,EAAK;AAAA,EACrF;AACA,MAAIE,IAAQF,EAAK,OAAO;AAExB,MAAIA,EAAK,SAAS;AAChB,WAAOE,IAAQ,KAAK,CAACW,EAAKb,EAAK,KAAKE,CAAK,KAAG;AAC1C,UAAIG,IAAIH,IAAQ;AAChB,aAAOG,IAAI,KAAKL,EAAK,OAAOK,CAAC,EAAE,OAAM,CAAAA;AACrC,UAAIA,MAAM,EAAG;AACb,MAAAL,EAAK,OAAO,OAAOK,GAAG,CAAC,GACvBH;AAAA,IACF;AAEF,MAAIa,IAAKf,EAAK,KAAKgB,IAAKhB,EAAK;AAC7B,MAAIa,EAAKG,GAAId,CAAK,EAAG,CAAAa,IAAKC;AAAA;AAExB,aAASC,IAAI,GAAGA,IAAI,IAAIA,KAAK;AAC3B,YAAMC,KAAOH,IAAKC,KAAM;AACxB,MAAIH,EAAKK,GAAKhB,CAAK,IAAGa,IAAKG,IACtBF,IAAKE;AAAA,IACZ;AACF,QAAMjB,IAAO,KAAK,MAAMc,IAAK,CAAC,IAAI;AAClC,SAAO,EAAE,MAAAd,GAAM,MAAMC,GAAO,OAAOH,GAAQC,GAAMC,GAAMC,CAAK,EAAE,MAAA;AAChE;AAIA,MAAMiB,KAAM,CAACZ,MAAcA,EAAE,QAAQ,MAAM,OAAO,EAAE,QAAQ,MAAM,MAAM,GAC3Da,yBAAe,QAAA,GACtBC,wBAAW,QAAA;AAEV,SAASC,GAAWC,GAAoB;AAC7C,SAAOA,EACJ,IAAI,CAACjB,MAAM;AACV,UAAMkB,IAAK,CAAClB,EAAE,SAASA,EAAE,UAAU,IAAI,aAAaA,EAAE,KAAK,OAAO,IAAIA,EAAE,MAAM,cAAcA,EAAE,GAAG,OAAO,IAAIA,EAAE,UAAU,kBAAkBA,EAAE,OAAO,OAAO,IAAIA,EAAE,SAAS,eAAeA,EAAE,MAAM,KAAK,EAAE,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AACjO,WAAO,eAAeA,EAAE,OAAO,EAAE,IAAIkB,IAAK,WAAWA,CAAE,MAAM,EAAE,IAAIlB,EAAE,QAAQa,GAAIb,EAAE,IAAI,CAAC;AAAA,EAC1F,CAAC,EACA,KAAK,EAAE;AACZ;AAGO,SAASmB,GAASC,GAAiB1B,GAAe;AACvD,EAAA0B,EAAG,YAAYJ,GAAWtB,EAAK,MAAM,GACrC0B,EAAG,MAAM,WAAW,GAAG1B,EAAK,GAAG,MAC3BA,EAAK,QAAO0B,EAAG,MAAM,aAAa,GAAG1B,EAAK,KAAK,SAC3C,MAAM,aAAa,GAAGA,EAAK,cAAc,GAAG,IACpD0B,EAAG,MAAM,QAAQ,GAAG1B,EAAK,WAAWA,EAAK,SAASA,EAAK,KAAK,MAC5D0B,EAAG,MAAM,SAAS,GAAG1B,EAAK,WAAWA,EAAK,QAAQA,EAAK,MAAM,MAC7D0B,EAAG,UAAU,IAAI,KAAK,GACtBL,EAAK,IAAIK,GAAI1B,CAAI,GACjBoB,GAAS,IAAIM,GAAI1B,CAAI;AACvB;AAGA,eAAsB2B,GAAQC,GAAmB;AAC/C,QAAMC,IAAM,CAACD,GAAM,GAAGA,EAAK,iBAA8B,MAAM,CAAC,EAAE,OAAO,CAACE,MAAMT,EAAK,IAAIS,CAAC,CAAC;AAC3F,aAAWJ,KAAMG,GAAK;AACpB,UAAM7B,IAAOqB,EAAK,IAAIK,CAAE,GAClBK,IAAS/B,EAAK,OAAO,QACrBgC,IAAI,MAAMrB,GAAQX,CAAI;AAC5B,IAAA0B,EAAG,YAAYJ,GAAWtB,EAAK,OAAO,MAAM,GAAGgC,EAAE,IAAI,CAAC,GACtDN,EAAG,MAAM,WAAW,GAAGM,EAAE,IAAI,MAC7BN,EAAG,QAAQ,MAAM,GAAGM,EAAE,IAAI,OAAOA,EAAE,KAAK,SAASA,EAAE,OAAOD,IAAS,aAAaA,IAASC,EAAE,IAAI,KAAK,EAAE,IACtGX,EAAK,OAAOK,CAAE;AAAA,EAChB;AACF;ACvJA,MAAMO,KAAoC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,WAAW,GAAG,MAAM,EAAA,GAqB3GC,IAAO,IAEPC;AAAAA;AAAAA,EAAgB;AAAA;AAAA,eAEPD,CAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAuLbE,KAAK;AAAA;AAAA;AAIJ,SAASC,KAAqB;AACrC,MAAIC,IAAoC,MACpCC;AACJ,QAAMC,wBAAU,IAAA,GACVC,IAAI,CAACjC,OACJgC,EAAI,IAAIhC,CAAC,KAAGgC,EAAI,IAAIhC,GAAG8B,EAAI,mBAAmBC,GAAM/B,CAAC,CAAC,GACpDgC,EAAI,IAAIhC,CAAC;AAGlB,WAASkC,IAAO;AAEd,UAAMC,IADS,IAAI,gBAAgB,GAAG,CAAC,EACtB,WAAW,UAAU,EAAE,oBAAoB,IAAO,WAAW,IAAO,uBAAuB,GAAA,CAAM;AAClH,QAAI,CAACA,EAAG,OAAM,IAAI,MAAM,sBAAsB;AAC9C,IAAAL,IAAKK;AACL,UAAMC,IAAK,CAACC,GAAcC,MAAgB;AACxC,YAAMvC,IAAIoC,EAAE,aAAaE,CAAI;AAG7B,UAFAF,EAAE,aAAapC,GAAGuC,CAAG,GACrBH,EAAE,cAAcpC,CAAC,GACb,CAACoC,EAAE,mBAAmBpC,GAAGoC,EAAE,cAAc,EAAG,OAAM,IAAI,MAAMA,EAAE,iBAAiBpC,CAAC,KAAK,mBAAmB;AAC5G,aAAOA;AAAA,IACT;AAMA,QALAgC,IAAOI,EAAE,cAAA,GACTA,EAAE,aAAaJ,GAAMK,EAAGD,EAAE,eAAeP,EAAE,CAAC,GAC5CO,EAAE,aAAaJ,GAAMK,EAAGD,EAAE,iBAAiBR,EAAE,CAAC,GAC9CQ,EAAE,mBAAmBJ,GAAM,GAAG,MAAM,GACpCI,EAAE,YAAYJ,CAAI,GACd,CAACI,EAAE,oBAAoBJ,GAAMI,EAAE,WAAW,EAAG,OAAM,IAAI,MAAMA,EAAE,kBAAkBJ,CAAI,KAAK,iBAAiB;AAC/G,IAAAI,EAAE,gBAAgBA,EAAE,mBAAmB,GACvCA,EAAE,WAAWA,EAAE,cAAcA,EAAE,cAAc,GAC7CA,EAAE,WAAWA,EAAE,cAAc,IAAI,aAAa,CAAC,IAAI,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,GAAGA,EAAE,WAAW,GACpFA,EAAE,wBAAwB,CAAC,GAC3BA,EAAE,oBAAoB,GAAG,GAAGA,EAAE,OAAO,IAAO,GAAG,CAAC;AAAA,EAClD;AAGA,WAASI,EAAW/C,GAAgBgD,GAAwBC,GAAaC,GAAiBC,GAAkC;AAC1H,IAAKb,KAAII,EAAA;AACT,UAAMC,IAAIL,GACJc,IAAI,IAAI,aAAalB,IAAO,CAAC,GAC7BmB,IAAI,IAAI,aAAanB,IAAO,CAAC;AACnC,QAAI1B,IAAI,GACJ8C,IAAO,OAAUC,IAAO,OAAUC,IAAO,QAAWC,IAAO,QAC3DC,IAAM;AAuBV,QAtBA1D,EAAK,MAAM,QAAQ,CAAC2D,GAAMC,MAAO;AAC/B,UAAIC,IAAM;AACV,YAAMC,IAAQtD;AACd,MAAAmD,EAAK,IAAI,QAAQ,CAACI,GAAI1D,MAAM;AAC1B,YAAIG,KAAK0B,EAAM;AACf,QAAI7B,IAAI,MAAGwD,KAAO,KAAK,MAAME,EAAG,CAAC,IAAIJ,EAAK,IAAItD,IAAI,CAAC,EAAE,CAAC,GAAG0D,EAAG,CAAC,IAAIJ,EAAK,IAAItD,IAAI,CAAC,EAAE,CAAC,CAAC;AACnF,cAAM2D,IAAQL,EAAK,MAAMtD,CAAC,IAAI,IAAI;AAGlC,YAFA+C,EAAE,IAAI,CAACW,EAAG,CAAC,GAAGA,EAAG,CAAC,GAAGA,EAAG,CAAC,GAAG1D,MAAM,IAAI,CAAC2D,IAAQA,CAAK,GAAGxD,IAAI,CAAC,GAC5D6C,EAAE,IAAI,CAACQ,GAAK,IAAIF,EAAK,YAAY,IAAI,MAAMA,EAAK,UAAU,IAAI,IAAIC,CAAE,GAAGpD,IAAI,CAAC,GACxEH,IAAIsD,EAAK,IAAI,SAAS,KAAMK,MAAU,MAAQhB,MAAS,SAAS;AAClE,UAAAU,IAAM;AACN,qBAAWO,KAAK,CAACF,GAAIJ,EAAK,IAAItD,IAAI,CAAC,CAAC;AAClC,YAAAiD,IAAO,KAAK,IAAIA,GAAMW,EAAE,CAAC,CAAC,GAC1BT,IAAO,KAAK,IAAIA,GAAMS,EAAE,CAAC,CAAC,GAC1BV,IAAO,KAAK,IAAIA,GAAMU,EAAE,CAAC,CAAC,GAC1BR,IAAO,KAAK,IAAIA,GAAMQ,EAAE,CAAC,CAAC;AAAA,QAE9B;AACA,QAAAzD;AAAA,MACF,CAAC;AACD,eAASS,IAAI6C,GAAO7C,IAAIT,GAAGS,IAAK,CAAAoC,EAAEpC,IAAI,IAAI,CAAC,IAAI4C;AAAA,IACjD,CAAC,GACGb,MAAS;AACX,iBAAW,CAACkB,GAAGC,GAAGnC,CAAC,KAAKhC,EAAK;AAC3B,QAAA0D,IAAM,IACNJ,IAAO,KAAK,IAAIA,GAAMY,IAAIlC,CAAC,GAC3BwB,IAAO,KAAK,IAAIA,GAAMU,IAAIlC,CAAC,GAC3BuB,IAAO,KAAK,IAAIA,GAAMY,IAAInC,CAAC,GAC3ByB,IAAO,KAAK,IAAIA,GAAMU,IAAInC,CAAC;AAE/B,QAAI,CAAC0B,EAAK,QAAO;AACjB,UAAMU,IAAMpE,EAAK,QAAQ;AACzB,IAAAsD,KAAQc,GACRb,KAAQa,GACRZ,KAAQY,GACRX,KAAQW;AACR,UAAMxD,IAAI,KAAK,KAAK4C,IAAOF,CAAI,GAAGnD,IAAI,KAAK,KAAKsD,IAAOF,CAAI,GACrDc,IAAI,KAAK,KAAKzD,IAAIqC,CAAG,GAAGqB,IAAI,KAAK,KAAKnE,IAAI8C,CAAG;AAClD,IAAAN,EAAE,OAA2B,QAAQ0B,GACrC1B,EAAE,OAA2B,SAAS2B,GACvC3B,EAAE,SAAS,GAAG,GAAG0B,GAAGC,CAAC,GACrB3B,EAAE,WAAWJ,CAAI,GACjBI,EAAE,WAAWF,EAAE,IAAI,GAAGW,CAAC,GACvBT,EAAE,WAAWF,EAAE,IAAI,GAAGY,CAAC,GACvBV,EAAE,UAAUF,EAAE,IAAI,GAAGjC,CAAC,GACtBmC,EAAE,UAAUF,EAAE,OAAO,GAAGO,MAAS,UAAU,IAAI,CAAC;AAChD,UAAMuB,IAAI,IAAI,aAAa,EAAE;AAC7B,IAAAvE,EAAK,MAAM,MAAM,GAAG,CAAC,EAAE,QAAQ,CAACiB,GAAGZ,MAAMkE,EAAE,IAAItD,GAAGZ,IAAI,CAAC,CAAC,GACxDsC,EAAE,WAAWF,EAAE,QAAQ,GAAG8B,CAAC,GAC3B5B,EAAE,UAAUF,EAAE,QAAQ,GAAG,KAAK,IAAI,GAAGzC,EAAK,MAAM,MAAM,CAAC,GACvD2C,EAAE,UAAUF,EAAE,SAAS,GAAG,CAACa,IAAOL,GAAK,CAACM,IAAON,CAAG,GAClDN,EAAE,UAAUF,EAAE,QAAQ,GAAGQ,CAAG;AAC5B,UAAMvB,IAAMyB,IAAY,KAAK,KAAM,KAAKqB,IAAMtB,IAAU,KAAK,KAAM;AACnE,IAAAP,EAAE,UAAUF,EAAE,QAAQ,GAAG,KAAK,IAAIf,CAAE,IAAI,KAAK,IAAI8C,CAAE,GAAG,KAAK,IAAI9C,CAAE,IAAI,KAAK,IAAI8C,CAAE,GAAG,KAAK,IAAI9C,CAAE,CAAC,GAC/FiB,EAAE,UAAUF,EAAE,OAAO,GAAGR,GAAQjC,EAAK,IAAI,CAAC;AAC1C,UAAMyE,IAAKC,GAAW1E,EAAK,OAAO,CAAC,CAAC,GAAG2E,IAAKD,GAAW1E,EAAK,OAAO,CAAC,CAAC;AACrE,IAAA2C,EAAE,UAAUF,EAAE,KAAK,GAAGgC,EAAG,CAAC,GAAGA,EAAG,CAAC,GAAGA,EAAG,CAAC,CAAC,GACzC9B,EAAE,UAAUF,EAAE,KAAK,GAAGkC,EAAG,CAAC,GAAGA,EAAG,CAAC,GAAGA,EAAG,CAAC,CAAC,GACzChC,EAAE,UAAUF,EAAE,IAAI,GAAGzC,EAAK,KAAK,GAC/B2C,EAAE,UAAUF,EAAE,OAAO,GAAGzC,EAAK,OAAO,EAAE,GACtC2C,EAAE,WAAWA,EAAE,WAAW,GAAG,CAAC;AAC9B,UAAMrD,IAAK,IAAI,kBAAkB+E,IAAIC,IAAI,CAAC;AAC1C,IAAA3B,EAAE,WAAW,GAAG,GAAG0B,GAAGC,GAAG3B,EAAE,MAAMA,EAAE,eAAerD,CAAE;AACpD,UAAMsF,IAAS,SAAS,cAAc,QAAQ;AAC9C,WAAAA,EAAO,QAAQP,GACfO,EAAO,SAASN,GAChBM,EAAO,WAAW,IAAI,EAAG,aAAa,IAAI,UAAUtF,GAAI+E,GAAGC,CAAC,GAAG,GAAG,CAAC,GACnEM,EAAO,MAAM,QAAQ,GAAGhE,CAAC,MACzBgE,EAAO,MAAM,SAAS,GAAGzE,CAAC,MACnB,EAAE,QAAAyE,GAAQ,GAAAhE,GAAG,GAAAT,GAAG,IAAI,CAACmD,GAAM,IAAI,CAACC,EAAA;AAAA,EACzC;AAGA,SAAO,EAAE,YAAAR,GAAY,UAAU;AAAE,IAAAT,GAAI,aAAa,oBAAoB,GAAG,YAAA,GAAeA,IAAK,MAAME,EAAI,MAAA;AAAA,EAAS,EAAA;AAChH;AC7TA,MAAMP,KAAoC;AAAA,EACxC,SAAS;AAAA,EAAG,QAAQ;AAAA,EAAG,WAAW;AAAA,EAAG,QAAQ;AAAA,EAAG,cAAc;AAAA,EAAG,cAAc;AAAA,EAAG,QAAQ;AAAA,EAAG,WAAW;AAAA,EAAG,QAAQ;AAAA,EACnH,QAAQ;AAAA,EAAG,OAAO;AAAA,EAAI,QAAQ;AAAA,EAAI,aAAa;AAAA,EAAI,KAAK;AAAA,EAAI,OAAO;AAAA,EAAI,cAAc;AAAA,EAAI,QAAQ;AACnG,GAGa4C,KAA6C;AAAA,EACxD,SAAS,CAAC,KAAK,EAAE;AAAA,EAAG,QAAQ,CAAC,KAAK,EAAE;AAAA,EAAG,WAAW,CAAC,GAAG,GAAG;AAAA,EAAG,QAAQ,CAAC,IAAI,CAAC;AAAA,EAAG,cAAc,CAAC,KAAK,GAAG;AAAA,EAAG,cAAc,CAAC,IAAI,GAAG;AAAA,EAC7H,QAAQ,CAAC,IAAI,EAAE;AAAA,EAAG,WAAW,CAAC,IAAI,GAAG;AAAA,EAAG,QAAQ,CAAC,GAAG,GAAG;AAAA,EAAG,QAAQ,CAAC,IAAI,GAAG;AAAA,EAAG,OAAO,CAAC,KAAK,GAAG;AAAA,EAAG,QAAQ,CAAC,IAAI,IAAI;AAAA,EACjH,aAAa,CAAC,IAAI,EAAE;AAAA,EAAG,KAAK,CAAC,IAAI,EAAE;AAAA,EAAG,OAAO,CAAC,IAAI,GAAG;AAAA,EAAG,cAAc,CAAC,IAAI,EAAE;AAAA,EAAG,QAAQ,CAAC,KAAK,GAAG;AACnG,GA4BMzC,KAAK;AAAA;AAAA,sDAILD;AAAA;AAAA,EAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyQf,SAAS2C,KAAqB;AACrC,MAAIxC,IAAoC,MACpCC;AACJ,QAAMC,wBAAU,IAAA;AAEhB,WAASE,IAAO;AAEd,UAAM,IADS,IAAI,gBAAgB,GAAG,CAAC,EACtB,WAAW,UAAU,EAAE,oBAAoB,IAAO,WAAW,IAAO,uBAAuB,GAAA,CAAM;AAClH,QAAI,CAAC,EAAG,OAAM,IAAI,MAAM,sBAAsB;AAC9C,IAAAJ,IAAK;AACL,UAAMM,IAAK,CAACC,GAAcC,MAAgB;AACxC,YAAMvC,IAAI,EAAE,aAAasC,CAAI;AAG7B,UAFA,EAAE,aAAatC,GAAGuC,CAAG,GACrB,EAAE,cAAcvC,CAAC,GACb,CAAC,EAAE,mBAAmBA,GAAG,EAAE,cAAc,EAAG,OAAM,IAAI,MAAM,EAAE,iBAAiBA,CAAC,KAAK,cAAc;AACvG,aAAOA;AAAA,IACT;AAMA,QALAgC,IAAO,EAAE,cAAA,GACT,EAAE,aAAaA,GAAMK,EAAG,EAAE,eAAeR,EAAE,CAAC,GAC5C,EAAE,aAAaG,GAAMK,EAAG,EAAE,iBAAiBT,EAAE,CAAC,GAC9C,EAAE,mBAAmBI,GAAM,GAAG,MAAM,GACpC,EAAE,YAAYA,CAAI,GACd,CAAC,EAAE,oBAAoBA,GAAM,EAAE,WAAW,EAAG,OAAM,IAAI,MAAM,EAAE,kBAAkBA,CAAI,KAAK,YAAY;AAC1G,UAAMwC,IAAM,EAAE,kBAAA;AACd,MAAE,gBAAgBA,CAAG;AACrB,UAAMC,IAAM,EAAE,aAAA;AACd,MAAE,WAAW,EAAE,cAAcA,CAAG,GAChC,EAAE,WAAW,EAAE,cAAc,IAAI,aAAa,CAAC,IAAI,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,GAAG,EAAE,WAAW,GACpF,EAAE,wBAAwB,CAAC,GAC3B,EAAE,oBAAoB,GAAG,GAAG,EAAE,OAAO,IAAO,GAAG,CAAC;AAAA,EAClD;AAEA,QAAMvC,IAAI,CAACjC,OACJgC,EAAI,IAAIhC,CAAC,KAAGgC,EAAI,IAAIhC,GAAG8B,EAAI,mBAAmBC,GAAM/B,CAAC,CAAC,GACpDgC,EAAI,IAAIhC,CAAC,IAGZyE,IAAgB,EAAE,SAAS,KAAK,WAAW,GAAA;AAEjD,WAASC,EAAWlF,GAAgBiD,GAAqB;AACvD,IAAKX,KAAII,EAAA;AACT,UAAMC,IAAIL,GACJ,CAAC6C,GAAKC,CAAI,IAAIP,GAAO7E,EAAK,IAAI,GAC9BqF,IAAMrF,EAAK,WAAWA,EAAK,SAAS,UAAU,MAAMA,EAAK,SAAS,UAAU,MAAM,MAClFgC,IAAIhC,EAAK,SAAS,YAAYA,EAAK,SAAS,WAAWA,EAAK,SAAS,UAAUqF,IAAM,IAAI,KAAKF,GAC9FzD,KAAO1B,EAAK,aAAaiF,EAAc,aAAa,KAAK,KAAM,KAC/DT,KAAOxE,EAAK,WAAWiF,EAAc,WAAW,KAAK,KAAM,KAC3DK,IAAYF,IAAO,KAAK,IAAI1D,CAAE,IAAI,GAElC6D,IAAK,CAAC,KAAK,IAAIf,CAAE,IAAIc,GAAWE,IAAK,CAAC,KAAK,IAAIhB,CAAE,IAAIc,GACrDhC,IAAO,CAACtB,IAAI,KAAK,IAAI,GAAGuD,CAAE,IAAI,GAAG/B,IAAOxB,IAAI,KAAK,IAAI,GAAGuD,CAAE,IAAI,GAC9DhC,IAAO,CAACvB,IAAI,KAAK,IAAI,GAAGwD,CAAE,IAAI,GAAG/B,IAAOzB,IAAI,KAAK,IAAI,GAAGwD,CAAE,IAAI,GAC9D5E,IAAI,KAAK,KAAK4C,IAAOF,CAAI,GAAGnD,IAAI,KAAK,KAAKsD,IAAOF,CAAI,GACrDc,IAAI,KAAK,KAAKzD,IAAIqC,CAAG,GAAGqB,IAAI,KAAK,KAAKnE,IAAI8C,CAAG;AAClD,IAAAN,EAAE,OAA2B,QAAQ0B,GACrC1B,EAAE,OAA2B,SAAS2B,GACvC3B,EAAE,SAAS,GAAG,GAAG0B,GAAGC,CAAC,GACrB3B,EAAE,WAAWJ,CAAI;AACjB,UAAMkC,IAAKC,GAAW1E,EAAK,SAAS,SAAS,GACvC2E,IAAKD,GAAW1E,EAAK,UAAU,SAAS;AAC9C,IAAA2C,EAAE,UAAUF,EAAE,SAAS,GAAG,CAACa,IAAOL,GAAK,CAACM,IAAON,CAAG,GAClDN,EAAE,UAAUF,EAAE,QAAQ,GAAGQ,CAAG,GAC5BN,EAAE,UAAUF,EAAE,QAAQ,IAAKzC,EAAK,SAAS,KAAK,KAAK,KAAM,GAAG,GAC5D2C,EAAE,UAAUF,EAAE,QAAQ,GAAG,KAAK,IAAIf,CAAE,IAAI,KAAK,IAAI8C,CAAE,GAAG,KAAK,IAAI9C,CAAE,IAAI,KAAK,IAAI8C,CAAE,GAAG,KAAK,IAAI9C,CAAE,CAAC,GAC/FiB,EAAE,UAAUF,EAAE,OAAO,GAAGR,GAAQjC,EAAK,IAAI,CAAC,GAC1C2C,EAAE,UAAUF,EAAE,QAAQ,GAAGgC,EAAG,CAAC,GAAGA,EAAG,CAAC,GAAGA,EAAG,CAAC,CAAC,GAC5C9B,EAAE,UAAUF,EAAE,SAAS,GAAGkC,EAAG,CAAC,GAAGA,EAAG,CAAC,GAAGA,EAAG,CAAC,CAAC,GAC7ChC,EAAE,UAAUF,EAAE,SAAS,GAAG4C,CAAG,GAC7B1C,EAAE,UAAUF,EAAE,OAAO,GAAGzC,EAAK,SAAS,UAAU,IAAIA,EAAK,SAAS,SAAS,IAAI,CAAC,GAChF2C,EAAE,UAAUF,EAAE,OAAO,GAAGzC,EAAK,QAAQ,CAAC,GACtC2C,EAAE,UAAUF,EAAE,OAAO,GAAG2C,CAAI,GAC5BzC,EAAE,WAAWA,EAAE,WAAW,GAAG,CAAC;AAC9B,UAAMrD,IAAK,IAAI,kBAAkB+E,IAAIC,IAAI,CAAC;AAC1C,IAAA3B,EAAE,WAAW,GAAG,GAAG0B,GAAGC,GAAG3B,EAAE,MAAMA,EAAE,eAAerD,CAAE;AACpD,UAAMsF,IAAS,SAAS,cAAc,QAAQ;AAC9C,WAAAA,EAAO,QAAQP,GACfO,EAAO,SAASN,GAChBM,EAAO,WAAW,IAAI,EAAG,aAAa,IAAI,UAAUtF,GAAI+E,GAAGC,CAAC,GAAG,GAAG,CAAC,GACnEM,EAAO,MAAM,QAAQ,GAAGhE,CAAC,MACzBgE,EAAO,MAAM,SAAS,GAAGzE,CAAC,MACtBH,EAAK,SAAS,WAASyF,EAAWb,GAAQ,CAACtB,GAAM,CAACC,GAAM8B,GAAKrF,EAAK,SAAS,GAAGiD,CAAG,GAC9E,EAAE,QAAA2B,GAAQ,GAAAhE,GAAG,GAAAT,GAAG,IAAI,CAACmD,GAAM,IAAI,CAACC,EAAA;AAAA,EACzC;AAEA,WAASkC,EAAWb,GAA2Bc,GAAYC,GAAYN,GAAaO,GAAe3C,GAAa;AAC9G,UAAM4C,IAAMjB,EAAO,WAAW,IAAI;AAClC,IAAAiB,EAAI,KAAA,GACJA,EAAI,MAAM5C,GAAKA,CAAG,GAClB4C,EAAI,UAAUH,GAAIC,CAAE,GACpBE,EAAI,OAAQD,IAAQ,KAAK,KAAM,GAAG,GAClCC,EAAI,OAAO,wCACXA,EAAI,YAAY,uBAChBA,EAAI,YAAY;AAChB,UAAMC,IAAK;AACX,aAASC,IAAK,GAAGA,IAAK,KAAKD,IAAKT,IAAM,IAAIU,IAAM,CAAAF,EAAI,SAAS,OAAOE,CAAE,GAAG,CAACV,IAAM,IAAI,IAAIU,IAAK,KAAKD,GAAI,EAAE;AACxG,IAAAD,EAAI,OAAO,sCACXA,EAAI,YAAY,QAChBA,EAAI,SAAS,uBAAuB,CAACR,IAAM,IAAI,IAAI,CAAC,GACpDQ,EAAI,QAAA;AAAA,EACN;AAEA,SAAO,EAAE,YAAAX,GAAY,UAAU;AAAE,IAAA5C,GAAI,aAAa,oBAAoB,GAAG,YAAA,GAAeA,IAAK,MAAME,EAAI,MAAA;AAAA,EAAS,EAAA;AAChH;AC1XO,SAASwD,GAAoBC,GAA6P;AACjS,QAAMC,IAAQpB,MAAsBqB,IAAQ9D,GAAA,GACtC+D,IAAQH,EAAQ,OAChBI,IAAc,MAAMJ,EAAQ,UAC5B,EAAE,YAAAf,MAAegB,GAAa,EAAE,YAAAnD,MAAeoD,GAC/C,EAAE,eAAAG,GAAe,aAAAC,GAAa,WAAAC,EAAA,IAAcP,EAAQ,QACpDhD,IAAM,MAAMgD,EAAQ,kBAAkB,KAAK,IAAI,GAAG,OAAO,oBAAoB,CAAC,GAG9EQ,IAAS,EAAE,GAAG,KAAK,GAAG,EAAA,GAEtBC,IAAY,GAEZC,IAAM,CAACzC,GAAWC,GAAWyC,MAAkC;AACnE,UAAMC,IAAKD,IAAM,KAAK,KAAM,KACtBE,IAAI,KAAK,IAAID,CAAC,GAAGtG,IAAI,KAAK,IAAIsG,CAAC;AACrC,WAAO,CAACC,IAAI5C,IAAI3D,IAAI4D,GAAG5D,IAAI2D,IAAI4C,IAAI3C,CAAC;AAAA,EACtC;AAGA,WAAS4C,IAA8B;AACrC,UAAM,CAAC7C,GAAGC,CAAC,IAAIwC,EAAIF,EAAO,GAAGA,EAAO,GAAGL,EAAM,UAAU,GAAG,GACpDY,IAAI,KAAK,MAAM9C,GAAGC,CAAC,KAAK;AAC9B,WAAO,CAACD,IAAI8C,GAAG7C,IAAI6C,CAAC;AAAA,EACtB;AAGA,WAASC,EAAYzH,GAAa0H,GAA4D;AAC5F,UAAMC,IAAOD,IAAYE,GAAYC,GAAY7H,CAAG,GAAG0H,CAAS,IAAIG,GAAY7H,CAAG,GAC7E8H,IAAIrB,EAAQ,MAAA;AAClB,WAAO;AAAA,MACL,GAAGkB;AAAA,MACH,OAAOA,EAAK,QAAQG;AAAA,MACpB,QAAQ,EAAE,GAAGH,EAAK,QAAQ,SAASA,EAAK,OAAO,UAAUG,EAAA;AAAA,MACzD,QAAQ,EAAE,GAAGH,EAAK,QAAQ,SAASA,EAAK,OAAO,UAAUG,EAAA;AAAA,IAAE;AAAA,EAE/D;AAEA,WAASC,EAAYC,GAAyBnD,GAAWC,GAAWrD,GAAWwG,GAAgC;AAC7G,UAAMX,IAAI,SAAS,cAAc,QAAQ;AACzC,WAAAA,EAAE,YAAYW,GACdX,EAAE,QAAQzC,GACVyC,EAAE,SAASxC,GACXwC,EAAE,WAAW,IAAI,EAAG,aAAa,IAAI,UAAUU,GAAwCnD,GAAGC,CAAC,GAAG,GAAG,CAAC,GAClGwC,EAAE,MAAM,QAAQ,GAAGzC,IAAIpD,CAAC,MACxB6F,EAAE,MAAM,SAAS,GAAGxC,IAAIrD,CAAC,MAClB6F;AAAA,EACT;AAGA,WAASY,EAAc5E,GAAwB7B,GAAW0G,GAAcF,GAAyD;AAC/H,UAAMrD,IAAM,KAAK,KAAKuD,IAAO,CAAC,GACxBb,IAAI,SAAS,cAAc,QAAQ;AACzC,IAAAA,EAAE,YAAYW,GACdX,EAAE,QAAQhE,EAAI,QAAQ,IAAIsB,IAAMnD,GAChC6F,EAAE,SAAShE,EAAI,SAAS,IAAIsB,IAAMnD;AAClC,UAAM4E,IAAMiB,EAAE,WAAW,IAAI;AAC7B,WAAAjB,EAAI,SAAS,QAAQ8B,IAAO1G,CAAC,OAC7B4E,EAAI,UAAU/C,GAAKsB,IAAMnD,GAAGmD,IAAMnD,CAAC,GACnC4E,EAAI,SAAS,QACbA,EAAI,2BAA2B,aAC/BA,EAAI,YAAY,QAChBA,EAAI,SAAS,GAAG,GAAGiB,EAAE,OAAOA,EAAE,MAAM,GACpCA,EAAE,MAAM,QAAQ,GAAGA,EAAE,QAAQ7F,CAAC,MAC9B6F,EAAE,MAAM,SAAS,GAAGA,EAAE,SAAS7F,CAAC,MACzB,EAAE,QAAQ6F,GAAG,KAAA1C,EAAA;AAAA,EACtB;AAGA,WAASwD,EAAYpI,GAAa0H,GAA+BW,GAAiBjH,GAAW,GAAWgF,GAAe;AACrH,UAAMkC,IAASb,EAAYzH,GAAK0H,CAAS;AACzC,IAAAY,EAAO,WAAW,EAAE,GAAGA,EAAO,UAAU,SAAS1B,EAAM,UAAUR,GAAO,WAAWQ,EAAM,UAAA;AAEzF,UAAMxD,IAAKiF,EAAK,WAAW,KAAQ,KAAQ,EAAE,GAAIA,EAAK,UAAU,GAAC;AACjE,QAAIjF,GAAI;AACN,YAAMmF,IAAQ,KAAK,KAAM,KAAK3B,EAAM,aAAa,KAAK,KAAM,GAAG,IAAI,KAAK,IAAK,KAAK,KAAK,KAAM,GAAG,GAC1FV,KAAM9C,EAAG,WAAW6D,EAAO,KAAKsB,GAAOpC,KAAM/C,EAAG,WAAW6D,EAAO,KAAKsB,GAEvE,CAACC,GAAIC,CAAE,IAAItB,EAAIjB,GAAIC,GAAIS,EAAM,UAAU,GAAG;AAChD,OAACxD,EAAG,SAASA,EAAG,OAAO,IAAI+D,EAAIqB,GAAIC,GAAI,CAACrC,CAAK;AAAA,IAC/C;AACA,UAAM3E,IAAIgC,EAAA;AACV,WAAO,EAAE,QAAA6E,GAAQ,MAAM,EAAE,GAAGD,GAAM,OAAOjH,GAAG,QAAQ,GAAG,YAAYK,GAAG,QAAQ2B,EAAA,GAA6B,GAAA3B,EAAA;AAAA,EAC7G;AAEA,WAASiH,EAAe1I,GAAa0H,GAA+BW,GAAiBjH,GAAW,GAAWgF,GAAeuC,GAAwB;AAChJ,UAAM,EAAE,QAAAL,GAAQ,MAAA9H,GAAM,GAAAiB,EAAA,IAAM2G,EAAYpI,GAAK0H,GAAWW,GAAMjH,GAAG,GAAGgF,CAAK;AACzE,WAAO,EAAE,KAAKS,IAAc,YAAYyB,GAAQ9H,GAAMmI,CAAO,GAAG,GAAAlH,EAAA;AAAA,EAClE;AAaA,QAAMmH,IAAwB,CAAC,WAAW,UAAU,aAAa,QAAQ,GACnEC,IAA2B,CAAC,UAAU,cAAc,YAAY,GAChEC,IAAyB,CAAC,UAAU,WAAW;AAErD,WAASC,EAAYC,GAA0B;AAC7C,WAAIA,EAAM,WAAW,MAAM,KAAKA,MAAU,eAAeA,MAAU,aAAmB,UAClF,CAAC,UAAU,WAAW,WAAW,aAAa,iBAAiB,cAAc,SAAS,SAAS,EAAE,SAASA,CAAK,IAAU,SACtH;AAAA,EACT;AAEA,WAASC,EAAaC,GAAgBC,GAA2C;AAC/E,UAAMC,IAAM,CAACC,MACXH,EAAK,OAAO,OAAO,CAAC7B,MAAM,CAACA,EAAE,SAASgC,EAAKhC,CAAC,CAAC,EAAE,IAAI,CAACA,MAAM;AACxD,YAAMnF,IAAKiH,EAAQ,IAAI9B,CAAC;AACxB,aAAIA,EAAE,SAAS,UAAgB,EAAE,GAAGA,EAAE,GAAG,GAAGA,EAAE,GAAG,IAAAnF,GAAI,OAAOmF,EAAE,OAAO,KAAKA,EAAE,EAAA,IACxEA,EAAE,SAAS,SAAe,EAAE,GAAGA,EAAE,GAAG,GAAGA,EAAE,GAAG,IAAAnF,EAAA,IAC5CmF,EAAE,SAAS,UAAgB,EAAE,GAAGA,EAAE,IAAI,GAAGA,EAAE,IAAI,IAAAnF,EAAA,IAC5C,EAAE,GAAGgH,EAAK,IAAI,GAAG,GAAG,IAAI,IAAAhH,EAAA;AAAA,IACjC,CAAC,GACGoH,IAAOF,EAAI,CAAC/B,MAAMA,EAAE,SAAS,UAAUuB,EAAU,SAASvB,EAAE,KAAK,IAAI,CAAC;AAC5E,QAAIiC,EAAK,OAAQ,QAAO,EAAE,MAAM,UAAU,QAAQA,EAAA;AAClD,UAAMC,IAAUH,EAAI,CAAC/B,MAAMA,EAAE,SAAS,UAAUwB,EAAa,SAASxB,EAAE,KAAK,IAAI,CAAC;AAClF,QAAIkC,EAAQ,OAAQ,QAAO,EAAE,MAAM,YAAY,QAAQA,EAAA;AACvD,UAAMC,IAAQJ,EAAI,CAAC/B,MAAMA,EAAE,SAAS,WAAWA,EAAE,MAAM,SAAS,MAAM,CAAC;AACvE,QAAImC,EAAM,OAAQ,QAAO,EAAE,MAAM,SAAS,QAAQA,EAAA;AAClD,UAAMC,IAAQL,EAAI,CAAC/B,MAAMA,EAAE,SAAS,UAAUyB,EAAW,SAASzB,EAAE,KAAK,IAAI,KAAKA,EAAE,UAAU,OAAO;AACrG,QAAIoC,EAAM,OAAQ,QAAO,EAAE,MAAM,QAAQ,QAAQA,EAAA;AACjD,UAAM9C,IAAQyC,EAAI,CAAC/B,MAAMA,EAAE,SAAS,MAAM;AAC1C,WAAIV,EAAM,SAAe,EAAE,MAAM,QAAQ,QAAQA,EAAAA,IAC7CuC,EAAK,UAAU,WAAiB,EAAE,MAAM,YAAY,QAAQ,CAAC,EAAE,GAAGA,EAAK,IAAI,GAAG,GAAGA,EAAK,IAAI,KAAA,CAAM,EAAA,IAC7F,EAAE,MAAM,QAAQ,QAAQ,CAAA,EAAC;AAAA,EAClC;AAMA,WAASQ,EAAUR,GAA2B;AAC5C,UAAMhH,IAAK,SAAS,cAAc,KAAK;AACvC,IAAAA,EAAG,YAAY,gBACfA,EAAG,MAAM,QAAQ,GAAGgH,EAAK,CAAC,MAC1BhH,EAAG,MAAM,SAAS,GAAGgH,EAAK,CAAC;AAC3B,UAAMS,IAAS,SAAS,cAAc,KAAK;AAC3C,IAAAA,EAAO,YAAY;AACnB,UAAMC,IAAO,SAAS,cAAc,KAAK;AACzC,IAAAA,EAAK,YAAY;AACjB,UAAMZ,IAAQ,SAAS,cAAc,KAAK;AAC1C,IAAAA,EAAM,YAAY;AAClB,UAAMa,IAAQ,SAAS,cAAc,KAAK;AAC1C,IAAAA,EAAM,YAAY;AAClB,UAAMC,IAAQ,SAAS,cAAc,KAAK;AAC1C,IAAAA,EAAM,YAAY,SAClB5H,EAAG,OAAOyH,GAAQC,GAAMZ,GAAOa,CAAK;AAEpC,UAAME,IAAmB,EAAE,IAAA7H,GAAI,OAAA8G,GAAO,QAAAW,GAAQ,OAAAG,GAAO,QAAQ,EAAE,MAAM,QAAQ,QAAQ,MAAM,WAAWf,EAAYG,EAAK,KAAK,GAAG,MAAM,MAAM,QAAQ,MAAM,QAAQ,YAAY;AAAA,IAAC,EAAA;AAC9K,QAAIxJ,IAAW;AACf,WAAAqK,EAAM,SAAS,OAAO3D,IAAQ8C,EAAK,QAAQ;AACzC,MAAAF,EAAM,gBAAA,GACNY,EAAK,gBAAA,GACLC,EAAM,gBAAA,GACNF,EAAO,gBAAA,GACPI,EAAM,OAAO,MACbA,EAAM,SAAS3D,GAEX8C,EAAK,OAAK,MAAM/G,GAAQ+G,EAAK,GAAG,GAC/BxJ,MAAY+G,EAAQ,aAAayC,GAAMa,GAAO3D,CAAK,GAAG1G,IAAW,KAElEwJ,EAAK,OAAK,MAAMlC,EAAUkC,EAAK,GAAG,GACtC,MAAMpC,EAAcoC,EAAK,OAAO,QAAQ,CAAC7B,MAAOA,EAAE,SAAS,UAAU,CAACA,EAAE,KAAK,IAAI,CAAA,CAAG,CAAC;AACrF,YAAM,EAAE,QAAAiB,GAAQ,MAAA9H,GAAM,GAAAiB,EAAA,IAAM2G,EAAYc,EAAK,OAAOA,EAAK,QAAQA,EAAK,MAAMA,EAAK,GAAGA,EAAK,GAAG9C,CAAK,GAC3F4D,IAASC,GAAkBpD,EAAA,GAAeyB,GAAQ9H,CAAI,GACtD0J,IAAUF,EAAO;AAAQ,MAAAE,EAAQ,YAAY;AACnD,YAAMC,IAASjC,EAAcgC,GAASzI,GAAGyF,GAAW,QAAQ;AAC5D,MAAAiD,EAAO,OAAO,MAAM,OAAO,GAAG,WAAWD,EAAQ,MAAM,IAAI,IAAIC,EAAO,GAAG,MACzEA,EAAO,OAAO,MAAM,MAAM,GAAG,WAAWD,EAAQ,MAAM,GAAG,IAAIC,EAAO,GAAG,MACvER,EAAO,OAAOO,GAASC,EAAO,MAAM,GACpCH,EAAO,KAAK,YAAY,QAAQA,EAAO,MAAM,YAAY,SACzDhB,EAAM,OAAOgB,EAAO,IAAI,GACpBd,EAAK,OAAKF,EAAM,OAAOE,EAAK,GAAG,GACnCF,EAAM,OAAOgB,EAAO,OAAOF,CAAK;AAChC,iBAAWM,KAAU,CAAClB,EAAK,KAAKY,CAAK;AACnC,QAAKM,KACL,OAAO,OAAOA,EAAO,OAAO,EAAE,WAAWJ,EAAO,MAAM,iBAAiBA,EAAO,MAAM,cAAcA,EAAO,cAAc,UAAUA,EAAO,UAAU,YAAY,aAAa;AAE7K,YAAMb,wBAAc,IAAA;AACpB,iBAAW9B,KAAK6B,EAAK,QAAQ;AAC3B,cAAMnI,IAAIsJ,EAAOhD,GAAGjB,GAAOiB,EAAE,SAAS,SAASwC,IAAQxC,EAAE,UAAU,SAASuC,IAAOC,GAAOD,CAAI;AAC9F,QAAI7I,KAAGoI,EAAQ,IAAI9B,GAAGtG,CAAC;AAAA,MACzB;AACA,MAAAgJ,EAAM,SAASd,EAAaC,GAAMC,CAAO,GACzCjH,EAAG,UAAU,IAAI,OAAO;AAAA,IAC1B,GACO6H;AAAA,EACT;AAGA,WAASM,EAAOhD,GAAWiD,GAAiB9F,GAAoBoF,GAAuC;AACrG,QAAIvC,EAAE,SAAS,QAAQ;AACrB,UAAIkD,IAA2B;AAC/B,iBAAW/G,KAAQ,CAAC,QAAQ,OAAO,GAAY;AAC7C,cAAMzC,IAAIwC,EAAW8D,EAAE,MAAM7D,GAAMC,EAAA,GAAOmD,EAAM,UAAU0D,GAAS1D,EAAM,SAAS;AAClF,QAAK7F,MACLA,EAAE,OAAO,YAAY,eACrBA,EAAE,OAAO,MAAM,OAAO,GAAG,CAACA,EAAE,EAAE,MAC9BA,EAAE,OAAO,MAAM,MAAM,GAAG,CAACA,EAAE,EAAE,OAC5ByC,MAAS,SAASoG,IAAOpF,GAAO,YAAYzD,EAAE,MAAM,GACjDyC,MAAS,YAAS+G,IAAOxJ,EAAE;AAAA,MACjC;AACA,aAAOwJ;AAAA,IACT;AACA,QAAIlD,EAAE,SAAS;AACb,aAAA7C,EAAM,YAAY6C,EAAE,EAAE,GACfA,EAAE;AAEX,QAAIA,EAAE,SAAS,QAAQ;AACrB,YAAMtG,IAAI2E,EAAW,EAAE,GAAG2B,EAAE,MAAM,SAAST,EAAM,UAAU0D,GAAS,WAAW1D,EAAM,UAAA,GAAanD,GAAK;AACvG,aAAA1C,EAAE,OAAO,YAAY,eACrBA,EAAE,OAAO,MAAM,OAAO,GAAGsG,EAAE,IAAItG,EAAE,EAAE,MACnCA,EAAE,OAAO,MAAM,MAAM,GAAGsG,EAAE,IAAItG,EAAE,EAAE,MAClCA,EAAE,OAAO,MAAM,kBAAkB,GAAGA,EAAE,EAAE,MAAMA,EAAE,EAAE,MAClDyD,EAAM,YAAYzD,EAAE,MAAM,GACnBA,EAAE;AAAA,IACX;AACA,QAAIsG,EAAE,SAAS,gBAAgBmD,EAAYnD,GAAGiD,GAAS9F,CAAK;AAC5D,UAAM,EAAE,KAAAiG,GAAK,GAAAhJ,MAAMiH,EAAerB,EAAE,OAAOA,EAAE,QAAQA,EAAE,MAAMA,EAAE,GAAGA,EAAE,GAAGiD,IAAUjD,EAAE,OAAO,CAAC,OAAO,CAAC,GAC7FC,IAAIS,EAAY0C,EAAI,KAAK,MAAO,MAAMA,EAAI,OAAOA,EAAI,QAAQhJ,GAAG,MAAM;AAC5E,WAAA6F,EAAE,MAAM,OAAO,GAAGD,EAAE,IAAIoD,EAAI,QAAQhJ,IAAI,CAAC,MACzC6F,EAAE,MAAM,MAAM,GAAGD,EAAE,IAAIoD,EAAI,SAAShJ,IAAI,CAAC,MACzC6F,EAAE,MAAM,YAAY,UAAUD,EAAE,KAAK,QACrC7C,EAAM,YAAY8C,CAAC,GACZA;AAAA,EACT;AAOA,WAASkD,EAAYnD,GAAuCiD,GAAiB9F,GAAiC;AAC5G,UAAM,EAAE,KAAAiG,GAAK,GAAAhJ,EAAA,IAAMiH,EAAerB,EAAE,OAAOA,EAAE,QAAQA,EAAE,MAAMA,EAAE,GAAGA,EAAE,GAAGiD,IAAUjD,EAAE,OAAO,CAAC,QAAQ,SAAS,QAAQ,CAAC,GAC/G/F,IAAImJ,EAAI,QACR9C,IAAOI,EAAY0C,EAAI,KAAK,KAAM,MAAMA,EAAI,OAAOA,EAAI,QAAQhJ,GAAG,EAAE,GACpEiJ,IAAQ3C,EAAY0C,EAAI,KAAK,MAAO,MAAMA,EAAI,OAAOA,EAAI,QAAQhJ,GAAG,EAAE,GACtEkJ,IAAM,SAAS,cAAc,QAAQ;AAC3C,IAAAA,EAAI,QAAQF,EAAI,OAChBE,EAAI,SAASF,EAAI;AACjB,UAAMtH,IAAIwH,EAAI,WAAW,IAAI;AAC7B,IAAAxH,EAAE,UAAUwE,GAAM,GAAG,CAAC;AACtB,UAAMiD,IAAK7D,EAAYM,EAAE,OAAOA,EAAE,OAAO,GAAGA,EAAE,OAAO,GAAG5F,CAAC;AACzD,IAAA0B,EAAE,2BAA2B,eAC7BA,EAAE,UAAUyH,GAAItJ,IAAI+F,EAAE,OAAO,IAAI5F,GAAGH,IAAI+F,EAAE,OAAO,IAAI5F,CAAC,GACtD0B,EAAE,2BAA2B,cAC7BA,EAAE,UAAUuH,GAAO,GAAG,CAAC,GACvBvH,EAAE,2BAA2B,kBAC7BA,EAAE,UAAUwE,GAAM,GAAG,CAAC;AACtB,UAAMgC,IAAS5B,EAAY0C,EAAI,KAAK,OAAQ,MAAMA,EAAI,OAAOA,EAAI,QAAQhJ,GAAG,mBAAmB,GACzFoJ,IAAQ,CAACvD,OACbA,EAAE,MAAM,OAAO,GAAGD,EAAE,KAAKoD,EAAI,QAAQhJ,IAAI,CAAC,MAC1C6F,EAAE,MAAM,MAAM,GAAGD,EAAE,KAAKoD,EAAI,SAAShJ,IAAI,CAAC,MAC1C6F,EAAE,MAAM,QAAQ,GAAGmD,EAAI,QAAQhJ,CAAC,MAChC6F,EAAE,MAAM,SAAS,GAAGmD,EAAI,SAAShJ,CAAC,MAClC6F,EAAE,MAAM,YAAY,UAAUD,EAAE,KAAK,QAC9BC;AAET,WAAAqD,EAAI,YAAY,oBAChBnG,EAAM,OAAOqG,EAAMlB,CAAM,GAAGkB,EAAMF,CAAG,CAAC,GAC/BA;AAAA,EACT;AAOA,WAASG,EAAUtK,GAA2B;AAC5C,UAAMO,IAAI2E,EAAW,EAAE,GAAGlF,GAAM,SAASoG,EAAM,SAAS,WAAWA,EAAM,UAAA,GAAanD,GAAK,GACrFvB,IAAK,SAAS,cAAc,KAAK;AACvC,IAAAA,EAAG,YAAY,QACfA,EAAG,MAAM,QAAQ,GAAGnB,EAAE,CAAC,MACvBmB,EAAG,MAAM,SAAS,GAAGnB,EAAE,CAAC,MACxBA,EAAE,OAAO,YAAY;AACrB,UAAMU,IAAIgC,EAAA,GACJ0G,IAASjC,EAAcnH,EAAE,QAAQU,GAAG,GAAG,QAAQ,GAC/CkI,IAAS,SAAS,cAAc,KAAK;AAC3C,WAAAA,EAAO,YAAY,UACnBQ,EAAO,OAAO,MAAM,OAAO,GAAG,CAACA,EAAO,GAAG,MACzCA,EAAO,OAAO,MAAM,MAAM,GAAG,CAACA,EAAO,GAAG,MACxCR,EAAO,YAAYQ,EAAO,MAAM,GAChCjI,EAAG,OAAOyH,GAAQ5I,EAAE,QAAQgK,EAAShK,EAAE,QAAQA,EAAE,GAAGA,EAAE,CAAC,CAAC,GACjD,EAAE,IAAAmB,GAAI,IAAInB,EAAE,IAAI,IAAIA,EAAE,IAAI,GAAGA,EAAE,GAAG,GAAGA,EAAE,GAAG,QAAA4I,GAAQ,QAAQtE,GAAO7E,EAAK,IAAI,EAAE,CAAC,EAAA;AAAA,EACtF;AAGA,QAAMwK,IAAW;AAQjB,WAASD,EAASE,GAA2B7J,GAAWT,GAA0B;AAChF,UAAM,EAAE,MAAAqH,EAAA,IAASiD,EAAO,WAAW,IAAI,EAAG,aAAa,GAAG,GAAGA,EAAO,OAAOA,EAAO,MAAM,GAClFC,IAAKD,EAAO,QAAQ7J,GAAG+J,IAAKF,EAAO,SAAStK,GAC5CyK,IAAO,KAAK,KAAKhK,IAAI4J,CAAQ,GAAGK,IAAO,KAAK,KAAK1K,IAAIqK,CAAQ,GAC7DM,IAAQ,IAAI,WAAWF,IAAOC,CAAI;AACxC,aAAS1G,IAAI,GAAGA,IAAIsG,EAAO,QAAQtG;AACjC,eAASD,IAAI,GAAGA,IAAIuG,EAAO,OAAOvG;AAChC,QAAIsD,GAAMrD,IAAIsG,EAAO,QAAQvG,KAAK,IAAI,CAAC,IAAI,QAAK4G,EAAM,KAAK,MAAM3G,IAAIwG,IAAKH,CAAQ,IAAII,IAAO,KAAK,MAAM1G,IAAIwG,IAAKF,CAAQ,CAAC,IAAI;AAClI,UAAMO,IAAK,CAACjE,GAAW9E,MAAc;AACnC,eAASgJ,IAAK,IAAIA,KAAM,GAAGA;AACzB,iBAASC,IAAK,IAAIA,KAAM,GAAGA,KAAM;AAC/B,gBAAMC,IAAKpE,IAAImE,GAAIE,IAAKnJ,IAAIgJ;AAC5B,cAAIE,KAAM,KAAKC,KAAM,KAAKD,IAAKN,KAAQO,IAAKN,KAAQC,EAAMK,IAAKP,IAAOM,CAAE,EAAG,QAAO;AAAA,QACpF;AACF,aAAO;AAAA,IACT;AACA,QAAIE,IAAI;AACR,aAASpJ,IAAI,GAAGA,IAAI6I,GAAM7I;AACxB,eAAS8E,IAAI,GAAGA,IAAI8D,GAAM9D,KAAK;AAC7B,YAAI,CAACiE,EAAGjE,GAAG9E,CAAC,EAAG;AACf,cAAMqJ,IAAKvE;AACX,eAAOA,IAAI,IAAI8D,KAAQG,EAAGjE,IAAI,GAAG9E,CAAC,IAAG,CAAA8E;AACrC,QAAAsE,KAAK,IAAIC,IAAKb,CAAQ,IAAIxI,IAAIwI,CAAQ,KAAK1D,IAAIuE,IAAK,KAAKb,CAAQ,IAAIA,CAAQ,IAAI,EAAE1D,IAAIuE,IAAK,KAAKb,CAAQ;AAAA,MAC3G;AACF,UAAMc,IAAM,SAAS,gBAAgB,8BAA8B,KAAK;AACxE,IAAAA,EAAI,aAAa,SAAS,UAAU,GACpCA,EAAI,aAAa,SAAS,GAAG1K,CAAC,EAAE,GAChC0K,EAAI,aAAa,UAAU,GAAGnL,CAAC,EAAE;AACjC,UAAMoL,IAAO,SAAS,gBAAgB,8BAA8B,MAAM;AAC1E,WAAAA,EAAK,aAAa,KAAKH,CAAC,GACxBE,EAAI,YAAYC,CAAI,GACbD;AAAA,EACT;AAEA,SAAO,EAAE,WAAApC,GAAW,WAAAoB,GAAW,WAAAvD,GAAW,aAAAE,GAAa,KAAAhE,GAAK,UAAU;AAAE,IAAAiD,EAAM,QAAA,GAAWC,EAAM,QAAA;AAAA,EAAW,EAAA;AAC1G;AClXO,MAAMqF,wBAAiB,QAAA;AAMvB,SAASC,GAAoBC,GAAoDC,GAA+CC,IAAQ,MAAM,KAAK,IAAI,GAAG,oBAAoB,CAAC,GAAG;AACzL,QAAMC,wBAAY,IAAA,GACZC,wBAAc,IAAA,GACdC,IAAYL;AAClB,iBAAeM,EAAUC,GAAuC;AAC9D,QAAIC,IAAOJ,EAAQ,IAAIG,CAAE;AACzB,WAAKC,MAAQA,KAAQ,YAAY;AAAE,YAAMC,IAAM,IAAI,MAAA;AAAS,aAAAA,EAAI,cAAc,aAAaA,EAAI,MAAM,MAAMR,EAAIM,CAAE,GAAG,MAAME,EAAI,OAAA,GAAUN,EAAM,IAAII,GAAIE,CAAG,GAAUA;AAAA,IAAK,GAAA,EAAK,MAAM,CAAArK,MAAK;AAAE,YAAAgK,EAAQ,OAAOG,CAAE,GAAS,IAAI,MAAM,wBAAwBA,CAAE,KAAKnK,CAAC,EAAE;AAAA,IAAG,CAAC,GAAGgK,EAAQ,IAAIG,GAAIC,CAAI,IACpRA;AAAA,EACT;AACA,QAAME,IAAiC;AAAA,IACrC,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,SAAS;AAAA,IACT,MAAM;AAAA,IACN,SAAS;AAAA,EAAA;AAGX,MAAIC,IAAsC;AAC1C,WAASC,IAA2B;AAClC,QAAID,EAAW,QAAOA;AACtB,UAAMvF,IAAI,SAAS,cAAc,QAAQ;AACzC,IAAAA,EAAE,QAAQA,EAAE,SAAS;AAErB,UAAMnE,IAAImE,EAAE,WAAW,MAAM,EAAE,oBAAoB,IAAM,GACnDsE,IAAIzI,EAAE,gBAAgB,KAAK,GAAG;AACpC,QAAIpC,IAAI;AACR,aAASF,IAAI,GAAGA,IAAI+K,EAAE,KAAK,QAAQ/K,KAAK,GAAG;AACzC,MAAAE,IAAKA,IAAI,aAAa,UAAW;AACjC,YAAMgM,IAAI,QAAShM,MAAM,KAAM,OAAO,OAAO;AAC7C,MAAA6K,EAAE,KAAK/K,CAAC,IAAI+K,EAAE,KAAK/K,IAAI,CAAC,IAAI+K,EAAE,KAAK/K,IAAI,CAAC,IAAIkM,GAC5CnB,EAAE,KAAK/K,IAAI,CAAC,IAAI;AAAA,IAClB;AACA,WAAAsC,EAAE,aAAayI,GAAG,GAAG,CAAC,GACdiB,IAAYvF;AAAA,EACtB;AAGA,QAAM0F,IAAM,CAACC,GAAcxL,MAAc;AACvC,UAAMiD,IAAI,KAAK,IAAIuI,IAAO,UAAUxL,IAAI,MAAM,IAAI;AAClD,WAAOiD,IAAI,KAAK,MAAMA,CAAC;AAAA,EACzB;AAGA,WAASwI,EAAS/J,GAA6B0B,GAAWC,GAAW,GAAW;AAC9E,UAAM6H,IAAMxJ,EAAE,aAAa,GAAG,GAAG0B,GAAGC,CAAC,GAC/B8G,IAAIe,EAAI,MACRQ,IAAS,MAAM,GACfC,IAAS,CAAC,MAAM,MAAM,IAAI,EAAE,IAAI,CAAC/F,MAAM,CAAC,KAAK,IAAIA,CAAC,GAAG,KAAK,IAAIA,CAAC,CAAC,CAAC,GACjEgG,IAAO,KAAK,KAAK,IAAKF;AAC5B,aAASxI,IAAI,GAAGA,IAAIG,GAAGH;AACrB,eAASD,IAAI,GAAGA,IAAIG,GAAGH,KAAK;AAC1B,cAAM7D,KAAK8D,IAAIE,IAAIH,KAAK;AACxB,iBAAS4C,IAAI,GAAGA,IAAI,GAAGA,KAAK;AAC1B,gBAAM,CAACgG,GAAIC,CAAE,IAAIH,EAAO9F,CAAC,GACnBrE,KAAKyB,IAAI4I,IAAK3I,IAAI4I,KAAMF,GAAKN,KAAKrI,IAAI6I,IAAK5I,IAAI2I,KAAMD,GACrDG,IAAS,MAAM,QAAQ,KAAK,IAAIvK,CAAC,IAAI,KAAK,IAAI8J,CAAC,IAC/CU,IAAM7B,EAAE/K,IAAIyG,CAAC,IAAI,KAGjBoG,IAAM,IADF,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,IAAID,IAAMD,KAAU,IAAI,GAAG,CAAC;AAE/D,UAAA5B,EAAE/K,IAAIyG,CAAC,IAAI,KAAK,OAAOmG,IAAM,OAAOC,IAAM,QAAQ,GAAG;AAAA,QACvD;AAAA,MACF;AACF,IAAAvK,EAAE,aAAawJ,GAAK,GAAG,CAAC;AAAA,EAC1B;AAMA,WAAS5F,EAAYvG,GAAiBY,GAAWT,GAAW,GAA8B;AACxF,UAAMgN,IAAOpB,EAAU/L,EAAK,EAAE,GACxB8C,IAAM+I,EAAM,IAAI7L,EAAK,EAAE;AAC7B,QAAI,CAAC8C,EAAK,OAAM,IAAI,MAAM,qBAAqB9C,EAAK,EAAE,EAAE;AACxD,UAAMqE,IAAI,KAAK,IAAI,GAAG,KAAK,MAAMzD,IAAI,CAAC,CAAC,GAAG0D,IAAI,KAAK,IAAI,GAAG,KAAK,MAAMnE,IAAI,CAAC,CAAC,GACrE2G,IAAI,SAAS,cAAc,QAAQ;AACzC,IAAAA,EAAE,QAAQzC,GACVyC,EAAE,SAASxC;AAEX,UAAM3B,IAAImE,EAAE,WAAW,MAAM,EAAE,oBAAoB,IAAM,GACnDsG,IAAKtK,aAAe,mBAAmBA,EAAI,eAAgBA,EAA0B,OACrFuK,IAAKvK,aAAe,mBAAmBA,EAAI,gBAAiBA,EAA0B,QAEtFiF,IAAQ,KAAK,IAAI1D,IAAI+I,GAAI9I,IAAI+I,CAAE,KAAKrN,EAAK,QAAQ,IACjDsN,IAAKjJ,IAAI0D,GAAOnF,IAAK0B,IAAIyD,GACzBxC,IAAK,KAAK,IAAI6H,IAAKE,GAAI,KAAK,IAAI,GAAGH,EAAK,MAAM,CAAC,IAAIC,IAAKE,IAAK,CAAC,CAAC,GAC/D9H,IAAK,KAAK,IAAI6H,IAAKzK,GAAI,KAAK,IAAI,GAAGuK,EAAK,MAAM,CAAC,IAAIE,IAAKzK,IAAK,CAAC,CAAC,GAC/D2K,IAAQvN,EAAK,SAAS,QACtByM,IAAOzM,EAAK,QAAQ;AAC1B,IAAA2C,EAAE,SAASyJ,EAAQmB,CAAK,GACxB5K,EAAE,UAAUG,GAAKyC,GAAIC,GAAI8H,GAAI1K,GAAI,GAAG,GAAGyB,GAAGC,CAAC,GAC3C3B,EAAE,SAAS;AAEX,UAAM6K,IAAO,CAACC,GAA8BC,GAAgDC,IAAQ,MAAM;AACxG,MAAAhL,EAAE,2BAA2B8K,GAC7B9K,EAAE,cAAcgL,GAChBhL,EAAE,YAAY+K,GACd/K,EAAE,SAAS,GAAG,GAAG0B,GAAGC,CAAC,GACrB3B,EAAE,cAAc,GAChBA,EAAE,2BAA2B;AAAA,IAC/B;AAYA,QAVI4K,MAAU,WAASC,EAAK,WAAW,eAAe,GAClDD,MAAU,WAASC,EAAK,WAAW,eAAe,GAClDD,MAAU,cACZC,EAAK,WAAW,eAAe,GAC/BA,EAAK,cAAc,WAAW,IAAI,IAEhCD,MAAU,cACZC,EAAK,WAAW,eAAe,GAC/BA,EAAK,cAAchB,EAAIC,GAAM,CAAC,IAAI,MAAM,YAAY,WAAW,GAAG,IAEhEzM,EAAK,MAAM;AACb,YAAM4N,IAAO,KAAK,MAAMpB,EAAIC,GAAM,CAAC,IAAI,CAAC,GAClCoB,IAAKD,MAAS,IAAI,IAAIA,MAAS,IAAIvJ,IAAIA,IAAImI,EAAIC,GAAM,CAAC,GACtDqB,IAAKF,MAAS,IAAI,IAAIA,MAAS,IAAItJ,IAAIA,IAAIkI,EAAIC,GAAM,CAAC,GACtDzK,IAAI,KAAK,IAAIqC,GAAGC,CAAC,KAAK,OAAO,MAAMkI,EAAIC,GAAM,CAAC,IAC9CsB,IAAOpL,EAAE,qBAAqBkL,GAAIC,GAAI,GAAGD,GAAIC,GAAI9L,CAAC;AACxD,MAAA+L,EAAK,aAAa,GAAG,uBAAuB,GAC5CA,EAAK,aAAa,MAAM,qBAAqB,GAC7CA,EAAK,aAAa,GAAG,mBAAmB,GACxCP,EAAK,UAAUO,CAAI;AAAA,IACrB;AAEA,QADI/N,EAAK,YAAU0M,EAAS/J,GAAG0B,GAAGC,GAAG,CAAC,GAClCtE,EAAK,UAAU;AACjB,YAAM+N,IAAOpL,EAAE,qBAAqB0B,IAAI,GAAGC,IAAI,GAAG,KAAK,IAAID,GAAGC,CAAC,IAAI,KAAKD,IAAI,GAAGC,IAAI,GAAG,KAAK,MAAMD,GAAGC,CAAC,IAAI,IAAI;AAC7G,MAAAyJ,EAAK,aAAa,GAAG,eAAe,GACpCA,EAAK,aAAa,GAAG,cAAc/N,EAAK,SAAS,QAAQ,CAAC,CAAC,GAAG,GAC9DwN,EAAK,YAAYO,CAAI;AAAA,IACvB;AACA,QAAI/N,EAAK,OAAO;AACd,YAAMgO,IAAMrL,EAAE,cAAc2J,EAAA,GAAS,QAAQ;AAC7C,MAAA0B,EAAI,aAAa,IAAI,UAAA,EAAY,UAAUxB,EAAIC,GAAM,CAAC,IAAI,KAAKD,EAAIC,GAAM,CAAC,IAAI,GAAG,EAAE,MAAM,IAAI,GAAG,CAAC,GACjGe,EAAK,WAAWQ,GAAK,OAAOhO,EAAK,KAAK;AAAA,IACxC;AACA,QAAIA,EAAK,OAAO;AACd,YAAMV,IAAK,KAAK,IAAI,GAAG,KAAK,IAAIsB,GAAGT,CAAC,IAAI,KAAK,IAAI;AACjD,MAAAwC,EAAE,OAAO,GAAGrD,CAAE,uBACdqD,EAAE,YAAY,SACdA,EAAE,eAAe,cACjBA,EAAE,cAAc,wBAChBA,EAAE,aAAarD,IAAK,MACpBqD,EAAE,YAAY,yBACdA,EAAE,SAAS3C,EAAK,OAAOqE,IAAI/E,IAAK,KAAKgF,IAAIhF,IAAK,GAAG,GACjDqD,EAAE,aAAa;AAAA,IACjB;AACA,WAAOmE;AAAA,EACT;AAGA,iBAAeR,EAAc2H,GAAoB;AAC/C,UAAM,QAAQ,IAAI,CAAE,GAAGA,EAAM,IAAI,CAAA1N,MAAKyL,EAAUzL,EAAE,EAAE,CAAC,GAAG,GAAI0N,EAAM,KAAK,CAAA1N,MAAKA,EAAE,KAAK,IAAI,CAAC,SAAS,MAAM,KAAK,YAAY,CAAC,IAAI,CAAA,CAAI,CAAC;AAAA,EACpI;AACA,iBAAeiG,EAAU5E,GAAmB;AAC1C,UAAMsM,IAAQ,CAAC,GAAGtM,EAAK,iBAAoC,cAAc,CAAC,EAAE,OAAO,CAAAkF,MAAK0E,EAAW,IAAI1E,CAAC,CAAC;AACzG,UAAMR,EAAc4H,EAAM,IAAI,CAAApH,MAAK0E,EAAW,IAAI1E,CAAC,CAAE,CAAC;AACtD,eAAWA,KAAKoH,GAAO;AAAE,YAAMC,IAAQ5H,EAAYiF,EAAW,IAAI1E,CAAC,GAAI,WAAWA,EAAE,MAAM,KAAK,GAAG,WAAWA,EAAE,MAAM,MAAM,GAAG8E,GAAO;AAAG,MAAA9E,EAAE,QAAQqH,EAAM,OAAOrH,EAAE,SAASqH,EAAM,QAAQrH,EAAE,WAAW,IAAI,EAAG,UAAUqH,GAAO,GAAG,CAAC;AAAA,IAAG;AAAA,EACtO;AACA,SAAO,EAAE,aAAA5H,GAAa,eAAAD,GAAe,WAAAE,GAAW,WAAAwF,GAAW,UAAU;AAAE,IAAAF,EAAQ,MAAA,GAASD,EAAM,MAAA,GAASQ,IAAY;AAAA,EAAM,EAAA;AACzH;AClMA,MAAM+B,KAAO,IAAI,IAAI,iRAAiR,MAAM,GAAG,CAAC,GAC1SC,KAAoB,IAAI,IAAI,ohBAAohB,MAAM,GAAG,CAAC;AACzjB,SAASC,GAAeC,IAAqC,IAAI;AACtE,QAAMC,IAAiC,CAAA;AACvC,aAAW,CAACC,GAAMC,CAAK,KAAK,OAAO,QAAQH,CAAU;AACnD,IAAI,CAACF,GAAkB,IAAII,CAAI,KAAK,wDAAwD,KAAKC,CAAK,KAClG,CAAC,GAAGA,EAAM,SAAS,kBAAkB,CAAC,EAAE,KAAK,CAAA5N,MAAK,CAAC,sBAAsB,KAAKA,EAAE,CAAC,EAAE,KAAA,CAAM,CAAC,MAC9F0N,EAAOC,CAAI,IAAIC;AAEjB,SAAOF;AACT;AAEO,SAASG,GAAaC,GAAYC,IAAS,KAAKC,IAAU,EAAE,GAAG,KAAsB;AAC1F,QAAM7C,IAAK,GAAG4C,CAAM,IAAIC,EAAQ,GAAG;AACnC,MAAIF,EAAK,aAAa,KAAK,UAAW,QAAO,EAAE,IAAA3C,GAAI,MAAM2C,EAAK,eAAe,GAAA;AAC7E,MAAI,EAAEA,aAAgB,YAAY,CAACR,GAAK,IAAIQ,EAAK,SAAS,SAAS,IAAI,MAAM,mCAAmCA,EAAK,QAAQ,EAAE;AAC/H,EAAAA,EAAK,aAAa,gBAAgB3C,CAAE;AACpC,QAAMsC,IAAaD,GAAe,OAAO,YAAY,CAAC,GAAGM,EAAK,UAAU,EAAE,OAAO,CAAA/H,MAAKA,EAAE,SAAS,cAAc,EAAE,IAAI,CAAAA,MAAK,CAACA,EAAE,MAAMA,EAAE,KAAK,CAAC,CAAC,CAAC,GACvIkI,IAAM3N,GAAS,IAAIwN,CAAmB,GACtCI,IAAQxD,EAAW,IAAIoD,CAAyB;AACtD,SAAO;AAAA,IAAE,IAAA3C;AAAA,IAAI,KAAK2C,EAAK;AAAA,IAAW,GAAIA,EAAK,cAAc,SAAS,KAAK,IAAI,EAAE,WAAW,MAAA,IAAmB,CAAA;AAAA,IAAK,YAAAL;AAAA,IAC9G,UAAU,CAAC,GAAGK,EAAK,UAAU,EAAE,OAAO,CAAApO,MAAKA,EAAE,aAAa,KAAK,gBAAgBA,EAAE,aAAa,KAAK,SAAS,EAAE,IAAI,OAAKmO,GAAanO,GAAGqO,GAAQC,CAAO,CAAC;AAAA,IACvJ,GAAIC,IAAM,EAAE,KAAK,EAAE,MAAM,gBAAgBA,CAAG,GAAG,GAAIH,EAAK,aAAa,UAAU,IAAI,EAAE,UAAU,KAAK,UAAUG,CAAG,EAAA,IAAM,GAAC,EAAG,IAAM,CAAA;AAAA,IACjI,GAAIC,IAAQ,EAAE,OAAO,gBAAgBA,CAAK,EAAA,IAAM,CAAA;AAAA,EAAC;AAErD;AACA,SAASC,GAAQjP,GAAwB;AACvC,QAAMwO,IAAS,gBAAgBxO,CAAI;AACnC,aAAWkP,KAASV,EAAO,OAAQ,KAAIU,EAAM,MAAM;AACjD,UAAMC,IAAW,SAAS,cAAc,UAAU;AAAG,IAAAA,EAAS,YAAYD,EAAM;AAChF,UAAME,IAAQ,SAAS,cAAc,KAAK;AAC1C,eAAWR,KAAQO,EAAS,QAAQ;AAClC,OAAIP,EAAK,aAAa,KAAK,aAAcA,aAAgB,WAAWR,GAAK,IAAIQ,EAAK,SAAS,QAAU,OAAOS,EAAgBV,GAAaC,CAAI,GAAG,KAAK,CAAC;AAExJ,IAAAM,EAAM,OAAOE,EAAM;AAAA,EACrB;AACA,SAAOZ;AACT;AACO,SAASa,EAAgBT,GAAuBU,GAAqB;AAC1E,MAAI,CAACV,EAAK,IAAK,QAAO,SAAS,eAAeA,EAAK,QAAQ,EAAE;AAC7D,QAAMC,IAASS,IAAQ,GAAGA,CAAK,MAAM;AACrC,MAAI,CAAClB,GAAK,IAAIQ,EAAK,GAAG,EAAG,OAAM,IAAI,MAAM,+BAA+BA,EAAK,GAAG,EAAE;AAClF,QAAMlN,IAAKkN,EAAK,cAAc,QAAQ,SAAS,gBAAgB,8BAA8BA,EAAK,GAAG,IAAI,SAAS,cAAcA,EAAK,GAAG;AACxI,aAAW,CAACH,GAAMC,CAAK,KAAK,OAAO,QAAQJ,GAAeM,EAAK,UAAU,CAAC;AACxE,IAAAlN,EAAG,aAAa+M,GAAMA,MAAS,OAAO,GAAGI,CAAM,GAAGH,CAAK,KAAKA,EAAM,QAAQ,+BAA+B,QAAQG,CAAM,KAAK,CAAC;AAE/H,EAAAnN,EAAG,aAAa,gBAAgBkN,EAAK,EAAE;AACvC,aAAWW,KAASX,EAAK,YAAY,CAAA,KAAO,YAAYS,EAAgBE,GAAOD,CAAK,CAAC;AAErF,MADIV,EAAK,SAAOpD,EAAW,IAAI9J,GAAyB,gBAAgBkN,EAAK,KAAK,CAAC,GAC/EA,EAAK,KAAK;AACZ,UAAM5O,IAAOiP,GAAQL,EAAK,IAAI,IAAI;AAClC,IAAAxN,GAAS,IAAIM,GAAmB1B,CAAI,GAChC4O,EAAK,IAAI,aAAa,KAAK,UAAUA,EAAK,IAAI,IAAI,KAAGnN,GAASC,GAAmB1B,CAAI;AAAA,EAC3F;AACA,SAAO0B;AACT;ACrDA,MAAM8N,yBAAY,IAAA;AAClB,eAAsBC,GAAsBC,GAA4BC,GAAwBC,GAAc;AAC5G,QAAMC,wBAAW,IAAA,GACXC,IAA2B,CAAA;AACjC,MAAIC,IAAW;AACf,QAAMC,IAAU,MAAM;AAAE,IAAID,MAAkBA,IAAW,IAAMD,EAAS,QAAQ,CAAAG,MAAWA,EAAA,CAAS;AAAA,EAAG;AACvG,MAAI;AACF,eAAWC,KAASR,EAAQ,CAAAG,EAAK,IAAIK,EAAM,IAAI,MAAMP,EAAQO,CAAK,CAAC;AACnE,UAAM,QAAQ,IAAIR,EAAO,OAAO,CAAA7I,MAAKA,EAAE,SAAS,MAAM,EAAE,IAAI,OAAMqJ,MAAS;AACzE,YAAMvE,IAAMkE,EAAK,IAAIK,EAAM,EAAE;AAC7B,UAAI,CAACA,EAAM,OAAQ,OAAM,IAAI,MAAM,2BAA2BA,EAAM,EAAE,EAAE;AACxE,YAAM1Q,IAAM,KAAK,UAAU,CAAC0Q,EAAM,QAAQA,EAAM,aAAavE,CAAG,CAAC;AACjE,UAAIwE,IAAQX,GAAM,IAAIhQ,CAAG;AACzB,UAAI,CAAC2Q,GAAO;AACV,cAAMC,IAAO,IAAI,SAASF,EAAM,QAAQ,OAAO,KAAK,UAAUvE,CAAG,CAAC,KAAKuE,EAAM,WAAW;AACxF,QAAAC,IAAQ,EAAE,OAAO,GAAG,MAAAC,GAAM,OAAOA,EAAK,OAAK,GAAKZ,GAAM,IAAIhQ,GAAK2Q,CAAK;AAAA,MACtE;AACA,MAAAA,EAAM;AACN,YAAME,IAAUF;AAChB,MAAAL,EAAS,KAAK,MAAM;AAAE,QAAI,EAAEO,EAAQ,UAAU,MAAK,SAAS,MAAM,OAAOA,EAAQ,IAAI,GAAGb,GAAM,OAAOhQ,CAAG;AAAA,MAAK,CAAC,GAC9G,MAAM6Q,EAAQ,OAAYN,KAAU,SAAS,MAAM,IAAIM,EAAQ,IAAI;AAAA,IACrE,CAAC,CAAC;AACF,QAAIC;AACJ,QAAIV,GAAK;AACP,YAAMW,IAAYb,EAAO,OAAO,CAAA7I,MAAKA,EAAE,SAAS,KAAK;AACrD,UAAI0J,EAAU,QAAQ;AACpB,cAAM,EAAE,cAAAC,EAAA,IAAiB,MAAM,OAAO,aAAa,GAC7CC,wBAAc,IAAA;AACpB,mBAAWP,KAASK,GAAW;AAC7B,gBAAMG,IAAW,MAAM,MAAMb,EAAK,IAAIK,EAAM,EAAE,CAAE;AAChD,cAAI,CAACQ,EAAS,GAAI,OAAM,IAAI,MAAM,2BAA2BR,EAAM,EAAE,EAAE;AACvE,gBAAM1I,IAAO,MAAMkJ,EAAS,KAAA,GACtBC,IAAOjB,EAAO,KAAK,CAAA7I,MAAKA,EAAE,SAAS,UAAUA,EAAE,WAAWqJ,EAAM,MAAM;AAC5E,cAAI,CAACS,EAAM,OAAM,IAAI,MAAM,oBAAoBT,EAAM,MAAM,EAAE;AAC7D,gBAAMU,IAAS,EAAE,GAAGpJ,GAAM,SAASqI,EAAK,IAAIc,EAAK,EAAE,GAAG,aAAa,OAAA;AACnE,gBAAMH,EAAa,QAAQI,CAAM,GACjCH,EAAQ,IAAIG,EAAO,OAAO,YAAA,GAAeA,CAAM,GAC3CV,EAAM,WAASO,EAAQ,IAAIP,EAAM,QAAQ,YAAA,GAAeU,CAAM;AAAA,QACpE;AACA,QAAAN,IAAa,EAAE,QAAQE,GAAc,WAAW,OAAUC,EAAQ,IAAII,EAAO,MAAM,GAAG,EAAE,CAAC,EAAE,OAAO,QAAQ,gBAAgB,EAAE,EAAE,YAAA,CAAa,EAAA;AAAA,MAC7I;AAAA,IACF;AACA,WAAO,EAAE,MAAAhB,GAAM,YAAAS,GAAY,SAAAN,EAAA;AAAA,EAC7B,SAASc,GAAO;AAAE,UAAAd,EAAA,GAAiBc;AAAA,EAAO;AAC5C;ACjDO,MAAMC,KAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACWrB,SAASC,GAAQvE,GAAmB;AACzC,MAAIlM,IAAIkM,MAAS,KAAK;AACtB,QAAMwE,IAAO,MAAM;AACjB,IAAA1Q,IAAKA,IAAI,eAAgB;AACzB,QAAI+G,IAAI/G;AACR,WAAA+G,IAAI,KAAK,KAAKA,IAAKA,MAAM,IAAKA,IAAI,CAAC,GACnCA,KAAKA,IAAI,KAAK,KAAKA,IAAKA,MAAM,GAAIA,IAAI,EAAE,KAC/BA,IAAKA,MAAM,QAAS,KAAK;AAAA,EACpC,GACMtF,IAAIiP;AACV,SAAAjP,EAAE,QAAQ,CAAC6E,GAAGvG,MAAMuG,KAAKvG,IAAIuG,KAAKoK,EAAA,GAClCjP,EAAE,MAAM,CAAC6E,GAAGvG,MAAM,KAAK,MAAMuG,KAAKvG,IAAIuG,IAAI,KAAKoK,EAAA,CAAM,GACrDjP,EAAE,OAAO,CAAC6E,MAAMA,EAAE,KAAK,MAAMoK,EAAA,IAASpK,EAAE,MAAM,CAAC,GAC/C7E,EAAE,SAAS,CAACvC,MAAMwR,EAAA,IAASxR,GAC3BuC,EAAE,WAAW,CAACkP,GAAO7R,MAAW;AAC9B,UAAM8R,IAAQD,EAAM,OAAO,CAAC5J,GAAGjH,MAAMiH,IAAIjI,EAAOgB,CAAC,GAAG,CAAC;AACrD,QAAI6D,IAAI+M,MAASE;AACjB,eAAW9Q,KAAK6Q,EAAO,MAAKhN,KAAK7E,EAAOgB,CAAC,KAAK,EAAG,QAAOA;AACxD,WAAO6Q,EAAMA,EAAM,SAAS,CAAC;AAAA,EAC/B,GACAlP,EAAE,OAAO,MAAMgP,GAAQ,KAAK,MAAMC,EAAA,IAAS,UAAU,CAAC,GAC/CjP;AACT;ACeO,SAASoP,GAAWC,GAA+BC,GAAqC;AAC7F,QAAMC,IAAQ,CAAC/Q,MAAuB;AAAE,IAAA8Q,EAAG9Q,CAAC,GAAGA,EAAE,UAAU,QAAQ+Q,CAAK;AAAA,EAAG;AAC3E,EAAIF,EAAY,WAASE,EAAMF,EAAY,OAAO;AAClD,aAAWxK,KAAKwK,EAAY,YAAa,CAAIxK,EAAE,SAAS,UAAQ0K,EAAM1K,EAAE,IAAI;AAC9E;AACO,SAAS2K,GAAmBH,GAA+BI,GAAgB9R,GAAgC;AAChH,QAAM+R,IAAO,gBAAgBL,CAAW;AAAG,MAAIM,IAAQ;AAevD,MAdAP,GAAWM,GAAM,CAAA9C,MAAQ;AACvB,QAAIA,EAAK,OAAO6C,EAAQ;AACxB,IAAAE,IAAQ;AACR,UAAMC,wBAAkB,IAAA,GAClBC,IAAU,CAACrR,MAAuB;AAAE,MAAAoR,EAAY,IAAIpR,EAAE,EAAE,GAAGA,EAAE,UAAU,QAAQqR,CAAO;AAAA,IAAG;AAE/F,QADAjD,EAAK,UAAU,QAAQiD,CAAO,GAC1BjD,EAAK,IAAK,YAAWkD,KAAQJ,EAAK,QAAQ,SAAS;AACrD,MAAI,OAAOI,EAAK,UAAW,aAAUA,EAAK,SAAS,CAAC,GAAG,IAAI,IAAIA,EAAK,OAAO,MAAM,GAAG,EAAE,IAAI,CAAAlI,MAAUgI,EAAY,IAAIhI,EAAO,MAAM,YAAY,IAAI,CAAC,KAAK,EAAE,IAAI,kBAAkBgF,EAAK,EAAE,OAAOhF,CAAM,CAAC,CAAC,EAAE,KAAK,GAAG;AAEjN,IAAIgF,EAAK,OACPA,EAAK,IAAI,KAAK,SAAS,CAAC,EAAE,MAAAjP,GAAM,MAAM,IAAM,GAAG,OAAOiP,EAAK,IAAI,UAAUA,EAAK,WAAW,CAAA,KAC/EA,EAAK,MACZA,EAAK,WAAW,CAAC,EAAE,IAAI,GAAGA,EAAK,EAAE,SAAS,MAAAjP,GAAM,MAD1B,OAAOA;AAAA,EAEpC,CAAC,GACG,CAACgS,EAAO,OAAM,IAAI,MAAM,wBAAwBF,CAAM,EAAE;AAC5D,SAAOC;AACT;AACO,SAASK,GAAoBrD,GAAyB;AAC3D,MAAIA,EAAM,YAAY,EAAG,OAAM,IAAI,MAAM,uCAAuC;AAChF,MAAI,CAAC,CAACA,EAAM,OAAOA,EAAM,QAAQA,EAAM,YAAY,UAAU,EAAE,MAAM,OAAK,OAAO,SAASlO,CAAC,KAAKA,IAAI,CAAC,EAAG,OAAM,IAAI,MAAM,gCAAgC;AACxJ,MAAI,CAAC,CAACkO,EAAM,UAAUA,EAAM,YAAY,OAAOA,EAAM,YAAY,MAAM,SAASA,EAAM,YAAY,MAAM,WAAWA,EAAM,UAAU,EAAE,MAAM,OAAO,QAAQ,EAAG,OAAM,IAAI,MAAM,iCAAiC;AAC9M,MAAI,CAAC,MAAM,QAAQA,EAAM,MAAM,KAAK,CAAC,MAAM,QAAQA,EAAM,WAAW,EAAG,OAAM,IAAI,MAAM,2CAA2C;AAClI,QAAMsD,wBAAU,IAAA;AAChB,EAAAZ,GAAW1C,GAAO,CAAAlO,MAAK;AAAE,QAAI,CAAC,WAAW,KAAKA,EAAE,EAAE,KAAKwR,EAAI,IAAIxR,EAAE,EAAE,EAAG,OAAM,IAAI,MAAM,gCAAgCA,EAAE,EAAE,EAAE;AAAG,IAAAwR,EAAI,IAAIxR,EAAE,EAAE;AAAA,EAAG,CAAC;AAC/I,QAAMkP,wBAAa,IAAA;AACnB,aAAW7I,KAAK6H,EAAM,QAAQ;AAC5B,QAAIgB,EAAO,IAAI7I,EAAE,EAAE,KAAK,CAACA,EAAE,QAAQA,EAAE,KAAK,SAAS,IAAI,KAAKA,EAAE,KAAK,SAAS,IAAI,KAAK,mBAAmB,KAAKA,EAAE,IAAI,EAAG,OAAM,IAAI,MAAM,iBAAiBA,EAAE,EAAE,EAAE;AAC7J,IAAA6I,EAAO,IAAI7I,EAAE,EAAE;AAAA,EACjB;AACA,EAAAuK,GAAW1C,GAAO,CAAAlO,MAAK;AAAE,QAAIA,EAAE,SAAS,CAACkP,EAAO,IAAIlP,EAAE,MAAM,EAAE,EAAG,OAAM,IAAI,MAAM,iBAAiBA,EAAE,MAAM,EAAE,EAAE;AAAA,EAAG,CAAC;AAClH,aAAWqG,KAAK6H,EAAM,YAAa,KAAI7H,EAAE,SAAS,WAAW,CAAC6I,EAAO,IAAI7I,EAAE,MAAM,EAAE,EAAG,OAAM,IAAI,MAAM,iBAAiBA,EAAE,MAAM,EAAE,EAAE;AACnI,aAAWiL,KAAQpD,EAAM,QAAQ,SAAS,CAAA,GAAI;AAC5C,QAAI,OAAOoD,EAAK,UAAW,YAAY,CAAC,2DAA2D,KAAKA,EAAK,MAAM,EAAG,OAAM,IAAI,MAAM,oDAAoD;AAC1L,eAAWG,KAASH,EAAK,OAAO,SAAS,aAAa,EAAG,KAAI,CAACE,EAAI,IAAIC,EAAM,CAAC,CAAC,EAAG,OAAM,IAAI,MAAM,4BAA4BA,EAAM,CAAC,CAAC,EAAE;AAAA,EACzI;AACF;AC/DA,IAAIC,KAAW;AACR,SAASC,GAAmBd,GAA+B/B,GAAyB;AACzF,SAAO;AAAA,IACL,GAAG+B,EAAY;AAAA,IAAO,GAAGA,EAAY;AAAA,IAAQ,KAAKA,EAAY;AAAA,IAAU,OAAOA,EAAY;AAAA,IAC3F,QAAQA,EAAY;AAAA,IAAQ,MAAMA,EAAY;AAAA,IAAO,MAAMA,EAAY;AAAA,IACvE,KAAKA,EAAY,UAAUhC,EAAgBgC,EAAY,SAAS/B,CAAK,IAAmB;AAAA,IACxF,QAAQ+B,EAAY,YAAY,IAAI,OAAKxK,EAAE,SAAS,SAAS,EAAE,GAAGA,GAAG,IAAIwI,EAAgBxI,EAAE,MAAMyI,CAAK,MAAqB,gBAAgBzI,CAAC,CAAC;AAAA,IAC7I,QAAQwK,EAAY;AAAA,EAAA;AAExB;AAEO,SAASe,GAAwBC,GAAmB/C,GAAe;AACxE,QAAMH,IAAW,SAAS,cAAc,UAAU;AAAG,EAAAA,EAAS,YAAY4B;AAC1E,QAAMzF,IAAM+D,EAAgBV,GAAaQ,EAAS,QAAQ,iBAAkB,GAAGG,CAAK;AACpF,EAAA+C,EAAK,OAAO/G,CAAG;AACf,aAAWmD,KAAQ,CAAC,OAAM,UAAS,SAAQ,QAAO,OAAO,EAAG,CAAA4D,EAAK,MAAM,YAAY,UAAU5D,CAAI,IAAI,QAAQa,CAAK,MAAMb,CAAI,GAAG;AACjI;AACO,SAAS6D,GAAuBC,GAAgD;AACrF,MAAItM,IAAUsM,GAASC,IAAW,GAAGzC,IAAW,IAAO0C,IAAW;AAClE,QAAMC,IAAU,SAAS,cAAc,KAAK;AAAG,EAAAA,EAAQ,YAAY;AACnE,MAAIC,IAA4B,MAC5BC,IAAU,MAAM;AAAA,EAAC,GACjBC,IAA8B,QAAQ,QAAA;AAC1C,QAAMvD,IAAQ,MAAM,EAAE4C,EAAQ;AAC9B,MAAIY;AACJ,WAASC,EAAOxJ,GAAkByJ,GAAkB;AAClD,UAAMpR,IAAO2H,EAAM;AAAI,IAAA3H,EAAK,MAAM,YAAY;AAC9C,UAAMuF,IAAOvF,EAAK,sBAAA;AAClB,QAAI0B,IAAO,KAAKC,IAAO,KAAKC,IAAO5B,EAAK,cAAc,IAAI6B,IAAO7B,EAAK,eAAe;AACrF,eAAWgD,KAAUhD,EAAK,iBAAiB,QAAQ,GAAG;AACpD,UAAIgD,EAAO,UAAU,SAAS,QAAQ,EAAG;AACzC,YAAMqO,IAAOrO,EAAO,sBAAA;AACpB,MAAAtB,IAAO,KAAK,IAAIA,GAAM2P,EAAK,OAAO9L,EAAK,IAAI,GAAG5D,IAAO,KAAK,IAAIA,GAAM0P,EAAK,MAAM9L,EAAK,GAAG,GACvF3D,IAAO,KAAK,IAAIA,GAAMyP,EAAK,QAAQ9L,EAAK,IAAI,GAAG1D,IAAO,KAAK,IAAIA,GAAMwP,EAAK,SAAS9L,EAAK,GAAG;AAAA,IAC7F;AACA,eAAW+L,KAActR,EAAK,iBAAiB,uBAAuB,GAAG;AACvE,YAAMqR,IAAOC,EAAW,sBAAA;AACxB,MAAA5P,IAAO,KAAK,IAAIA,GAAM2P,EAAK,OAAO9L,EAAK,OAAO,CAAC,GAAG5D,IAAO,KAAK,IAAIA,GAAM0P,EAAK,MAAM9L,EAAK,MAAM,CAAC,GAC/F3D,IAAO,KAAK,IAAIA,GAAMyP,EAAK,QAAQ9L,EAAK,OAAO,CAAC,GAAG1D,IAAO,KAAK,IAAIA,GAAMwP,EAAK,SAAS9L,EAAK,MAAM,CAAC;AAAA,IACrG;AACA,UAAMN,IAAImM,IAAW,KAAK,KAAK,KAAKG,IAAK,KAAK,IAAItM,CAAC,GAAGuM,IAAK,KAAK,IAAIvM,CAAC,GAC/DwM,IAAU,CAAC,CAAC/P,GAAKC,CAAI,GAAE,CAACC,GAAKD,CAAI,GAAE,CAACC,GAAKC,CAAI,GAAE,CAACH,GAAKG,CAAI,CAAC,EAAE,IAAI,CAAC,CAACS,GAAEC,CAAC,MAAM,CAACD,IAAEiP,IAAGhP,IAAEiP,GAAGlP,IAAEkP,IAAGjP,IAAEgP,CAAE,CAAC,GAChGG,IAAO,KAAK,IAAI,GAAGD,EAAQ,IAAI,CAAA5T,MAAGA,EAAE,CAAC,CAAC,CAAC,GAAG8T,IAAM,KAAK,IAAI,GAAGF,EAAQ,IAAI,CAAA5T,MAAGA,EAAE,CAAC,CAAC,CAAC,GAChF+T,IAAQ,KAAK,IAAI,GAAGH,EAAQ,IAAI,CAAA5T,MAAGA,EAAE,CAAC,CAAC,CAAC,IAAE6T,GAAMG,IAAS,KAAK,IAAI,GAAGJ,EAAQ,IAAI,OAAG5T,EAAE,CAAC,CAAC,CAAC,IAAE8T,GAC3FG,IAAc,MAAM;AACxB,YAAMC,IAAYjB,EAAQ,eAAe,eAAec,GAClDzL,IAAQ9B,EAAQ,QAAQ,YAAY,KAAK,IAAI,GAAG0N,IAAYH,CAAK,IAAI;AAC3E,MAAAd,EAAQ,MAAM,QAAQ,GAAGc,IAAQzL,CAAK,MAAM2K,EAAQ,MAAM,SAAS,GAAGe,IAAS1L,CAAK,MACpFnG,EAAK,MAAM,OAAO,GAAG,CAAC0R,IAAOvL,CAAK,MAAMnG,EAAK,MAAM,MAAM,GAAG,CAAC2R,IAAMxL,CAAK,MACxEnG,EAAK,MAAM,YAAY,SAASmG,CAAK,YAAYiL,CAAQ;AAAA,IAC3D;AACA,IAAAU,EAAA,GACIzN,EAAQ,QAAQ,aAAayM,EAAQ,kBAAiBI,IAAS,IAAI,eAAeY,CAAW,GAAGZ,EAAO,QAAQJ,EAAQ,aAAa;AAAA,EAC1I;AACA,iBAAekB,IAAS;AACtB,QAAI7D,EAAU;AACd,UAAM8D,IAAQ,EAAErB;AAAU,IAAAI,EAAA,GAAWE,GAAQ,WAAA,GAAcH,IAAS,MAAMF,IAAW,IACrFC,EAAQ,gBAAA,GAAmBA,EAAQ,QAAQ,WAAW;AACtD,UAAMoB,IAAS7N,GAASyI,IAAQ,gBAAgBoF,EAAO,WAAW;AAAG,IAAA/B,GAAoBrD,CAAK;AAC9F,UAAMqF,IAAW,SAAS,cAAc,KAAK;AAAG,IAAAA,EAAS,MAAM,UAAU,SAASrF,EAAM,KAAK,aAAaA,EAAM,MAAM,iBAAiBA,EAAM,OAAO,MAAM,IAAI,IAC9JqF,EAAS,cAAcrF,EAAM,KAAK,MAAMgE,EAAQ,OAAOqB,CAAQ;AAC/D,UAAM9U,IAAS,MAAMwQ,GAAsBf,EAAM,QAAQoF,EAAO,cAAcpF,EAAM,GAAG;AACvF,QAAIqB,KAAY8D,MAAUrB,GAAU;AAAE,MAAAvT,EAAO,QAAA;AAAW;AAAA,IAAQ;AAChE,UAAM+U,IAAWF,EAAO,YAAY,IAAIG,GAAA,GAClCC,IAASzI,GAAoB,CAAAQ,MAAM;AACvC,YAAMiE,IAAQxB,EAAM,OAAO,KAAK,CAAA7H,MAAKA,EAAE,OAAOoF,CAAE;AAAG,UAAI,CAACiE,GAAO,MAAO,OAAM,IAAI,MAAM,2BAA2BjE,CAAE,EAAE;AAAG,aAAOiE,EAAM;AAAA,IACvI,GAAG,CAAAjE,MAAM;AAAE,YAAMN,IAAM1M,EAAO,KAAK,IAAIgN,CAAE;AAAG,UAAI,CAACN,EAAK,OAAM,IAAI,MAAM,wBAAwBM,CAAE,EAAE;AAAG,aAAON;AAAA,IAAK,GAAG,MAAM+C,EAAM,YAAY,UAAU,GAChJyF,IAAQnO,GAAoB,EAAE,UAAAgO,GAAU,QAAAE,GAAQ,OAAOxF,EAAM,YAAY,OAAO,OAAO,MAAMA,EAAM,YAAY,OAAO,YAAY,MAAMA,EAAM,YAAY,YAAY;AAC5K,QAAI0F,IAAiC,MACjCC,IAAW;AACf,UAAMpE,IAAU,MAAM;AAAE,MAAIoE,MAAkBA,IAAW,IAAMD,GAAa,QAAA,GAAWF,EAAO,QAAA,GAAWC,EAAM,QAAA,GAAgBL,EAAO,YAAUE,EAAS,QAAA,GAAW/U,EAAO,QAAA;AAAA,IAAW;AACtL,IAAA2T,IAAU3C;AACV,QAAI;AACF,YAAMvH,IAAOyJ,GAAmBzD,GAAOY,CAAK;AAC5C,MAAAoD,EAAQ,gBAAA,GAAmBN,GAAwBM,GAASpD,CAAK;AACjE,YAAM/F,IAAQ4K,EAAM,UAAUzL,CAAI;AAClC,UADqCgK,EAAQ,OAAOnJ,EAAM,EAAE,GACxD,CAACyK,EAAS,IAAI;AAChB,QAAAzK,EAAM,MAAM,MAAM,aAAamF,EAAM,OAAO,MAAM,MAC9ChG,EAAK,OAAKa,EAAM,MAAM,OAAOb,EAAK,GAAG,GACzCgK,EAAQ,QAAQ,WAAW,YAAYK,EAAOxJ,GAAOmF,EAAM,QAAQ;AAAG;AAAA,MACxE;AAEA,UADA,MAAMnF,EAAM,OAAOmF,EAAM,QAAQ,GAC7BqB,KAAY8D,MAAUrB,GAAU;AAAE,QAAAvC,EAAA;AAAW;AAAA,MAAQ;AACzD,UAAIvB,EAAM,QAAQ,MAAM,UAAUhG,EAAK,KAAK;AAC1C,cAAM,EAAE,eAAA4L,EAAA,IAAkB,MAAM,OAAO,aAAU;AACjD,YAAIvE,KAAY8D,MAAUrB,GAAU;AAAE,UAAAvC,EAAA;AAAW;AAAA,QAAQ;AACzD,QAAAmE,IAAcE,EAAc5L,GAAMa,GAAOyH,GAAQtC,EAAM,UAAU,GAAGzP,EAAO,UAAU,GACrF0T,IAASyB,GACLN,EAAO,aAAa,KAAOnB,GAAQ,KAAA,OAAqB,OAAA;AAAA,MAC9D;AACA,MAAAI,EAAOxJ,GAAOmF,EAAM,QAAQ,GAC5B+D,IAAW,IAAMC,EAAQ,QAAQ,WAAW;AAAA,IAC9C,SAAS5B,GAAO;AACd,YAAAb,EAAA,GACMa;AAAA,IACR;AAAA,EACF;AACA,WAASyD,IAAc;AACrB,UAAMrI,IAAO0H,KAAUC,IAAQrB;AAC/B,WAAOtG,EAAK,MAAM,CAAA4E,MAAS;AACzB,YAAI+C,MAAUrB,KAAY,CAACzC,MAAY2C,EAAQ,QAAQ,WAAW,SAASA,EAAQ,cAAc,IAAI,YAAY,cAAc,EAAE,QAAQ5B,EAAA,CAAO,CAAC,IAC3IA;AAAA,IACR,CAAC;AAAA,EACH;AACA,SAAA+B,IAAe,QAAQ,QAAA,EAAU,KAAK,MAAM;AAAE,QAAI,CAACL,KAAY,CAACzC,UAAiBwE,EAAA;AAAA,EAAe,CAAC,GAE5F1B,EAAa,MAAM,MAAM;AAAA,EAAC,CAAC,GACzB;AAAA,IACL,SAAAH;AAAA,IAAS,IAAI,QAAQ;AAAE,aAAOG;AAAA,IAAc;AAAA,IAAG,IAAI,WAAW;AAAE,aAAOJ;AAAA,IAAU;AAAA,IACjF,OAAO+B,GAAO;AAAE,aAAIzE,IAAiB,QAAQ,OAAO,IAAI,MAAM,sBAAsB,CAAC,KAAG9J,IAAU,EAAE,GAAGA,GAAS,GAAGuO,EAAA,GAAS3B,IAAe0B,EAAA,GAAoB1B,EAAa,MAAM,MAAM;AAAA,MAAC,CAAC,GAAUA;AAAA,IAAc;AAAA,IAClN,OAAO;AAAE,MAAAF,GAAQ,OAAA;AAAA,IAAU;AAAA,IAAG,QAAQ;AAAE,MAAAA,GAAQ,MAAA;AAAA,IAAS;AAAA,IAAG,SAAS;AAAE,MAAAA,GAAQ,OAAA;AAAA,IAAU;AAAA,IAAG,KAAKlT,GAAG;AAAE,MAAAkT,GAAQ,KAAKlT,CAAC;AAAA,IAAG;AAAA,IACvH,UAAU;AAAE,MAAIsQ,MAAkBA,IAAW,IAAMyC,KAAYM,GAAQ,WAAA,GAAcF,EAAA,GAAWF,EAAQ,OAAA;AAAA,IAAU;AAAA,EAAA;AAEtH;"}
@@ -0,0 +1,72 @@
1
+ import type { PaperParams } from '../params';
2
+ import type { FitSpec } from './fit';
3
+ import type { PhotoSpec, PhotoMeta } from './photos';
4
+ import type { Attach, CardInfo, SheetLook } from './scene';
5
+ import type { MotionSpec } from './motion-spec';
6
+ export interface CompositionAsset {
7
+ id: string;
8
+ kind: 'photo' | 'font' | 'pen';
9
+ file: string;
10
+ family?: string;
11
+ descriptors?: {
12
+ weight?: string;
13
+ style?: string;
14
+ unicodeRange?: string;
15
+ };
16
+ photo?: Pick<PhotoMeta, 'focus'>;
17
+ /** Pen bundle family may differ from the name used by text. */
18
+ matches?: string;
19
+ credits: string;
20
+ licenseFiles: string[];
21
+ }
22
+ export interface CompositionNode {
23
+ id: string;
24
+ tag?: string;
25
+ namespace?: 'svg';
26
+ text?: string;
27
+ attributes?: Record<string, string>;
28
+ children?: CompositionNode[];
29
+ photo?: PhotoSpec;
30
+ fit?: {
31
+ spec: FitSpec;
32
+ resolved?: string;
33
+ };
34
+ }
35
+ export type CompositionAttachment = Exclude<Attach, {
36
+ type: 'html';
37
+ }> | {
38
+ type: 'html';
39
+ layer: 'front' | 'back';
40
+ node: CompositionNode;
41
+ label?: string;
42
+ binds?: boolean;
43
+ };
44
+ export interface PaperComposition {
45
+ version: 1;
46
+ kind: string;
47
+ width: number;
48
+ height: number;
49
+ rotation: number;
50
+ paper: string;
51
+ params: PaperParams;
52
+ sheet: SheetLook;
53
+ environment: {
54
+ grain: number;
55
+ light: {
56
+ azimuth: number;
57
+ elevation: number;
58
+ };
59
+ pixelRatio: number;
60
+ };
61
+ content: CompositionNode | null;
62
+ attachments: CompositionAttachment[];
63
+ assets: CompositionAsset[];
64
+ info: CardInfo;
65
+ motion?: MotionSpec;
66
+ motionSeed: number;
67
+ pen: boolean;
68
+ }
69
+ export type AssetResolver = (asset: CompositionAsset) => string | Promise<string>;
70
+ export declare function visitNodes(composition: PaperComposition, fn: (node: CompositionNode) => void): void;
71
+ export declare function setCompositionText(composition: PaperComposition, nodeId: string, text: string): PaperComposition;
72
+ export declare function validateComposition(value: PaperComposition): void;
@@ -0,0 +1,98 @@
1
+ /**
2
+ * How the content of a card animates: a list of steps on one timeline per
3
+ * card. Makers attach a `MotionSpec` to their plan; motion.ts runs it after
4
+ * the card is rendered. Targets are selectors scoped to the card's ink layer
5
+ * (text fitting rewrites the ink's innerHTML, so element references taken in
6
+ * a maker are stale by the time the card is on the desk).
7
+ *
8
+ * This module is types and tiny helpers only: cards.ts imports it without
9
+ * pulling brushmark into the maker code path.
10
+ */
11
+ import type { AnnotationConfig } from 'brushmark';
12
+ import type { Rng } from './rng';
13
+ /** A selector scoped to the card's ink layer, or an element inside it. */
14
+ export type Target = string | HTMLElement;
15
+ /** Timeline position: seconds, or relative to the previous step (`'>'`, `'>+0.2'`, `'>-0.1'`). */
16
+ export type At = number | string;
17
+ interface StepBase {
18
+ target: Target;
19
+ at?: At;
20
+ /** Seconds. */
21
+ duration?: number;
22
+ /** Seconds, on top of `at`. */
23
+ delay?: number;
24
+ /** GSAP-style ease name: `power2.out`, `back.out`, `none`... */
25
+ ease?: string;
26
+ /** Brush steps over the per-card budget are dropped lowest priority first (default 0). */
27
+ priority?: number;
28
+ }
29
+ /** A Brushmark annotation (underline, circle, highlight, box, bracket, contour...). */
30
+ export type BrushStep = StepBase & {
31
+ kind: 'brush';
32
+ } & Omit<AnnotationConfig, 'observe' | 'measure' | 'animate' | 'timelineVars' | 'repeat' | 'yoyo' | 'onResize'>;
33
+ /** Draw an SVG's paths on, stroke by stroke. */
34
+ export type DrawStep = StepBase & {
35
+ kind: 'draw'; /** Seconds between paths (negative overlaps). */
36
+ stagger?: number;
37
+ };
38
+ /**
39
+ * Reveal text: typewriter glyphs (`.typed` ink), or a clip sweep across / down a block.
40
+ * With the optional Pen on (handwriting.ts), `auto` and `pen` draw handwriting stroke by stroke when the face has a pen font.
41
+ */
42
+ export type WriteStep = StepBase & {
43
+ kind: 'write';
44
+ mode?: 'auto' | 'glyph' | 'sweep-x' | 'sweep-y' | 'pen'; /** Glyphs per second. */
45
+ rate?: number;
46
+ };
47
+ export type FadeStep = StepBase & {
48
+ kind: 'fade';
49
+ from?: number;
50
+ };
51
+ /** Fade in while settling down from `dy` px above. */
52
+ export type RiseStep = StepBase & {
53
+ kind: 'rise';
54
+ dy?: number;
55
+ };
56
+ /** Slam down: scale overshoot from `from` with a fast fade-in (stamps, postmarks). */
57
+ export type StampStep = StepBase & {
58
+ kind: 'stamp';
59
+ from?: number;
60
+ };
61
+ /** Instant film developing: an overlay that starts opaque and clears (the element is hidden at rest). */
62
+ export type DevelopStep = StepBase & {
63
+ kind: 'develop';
64
+ };
65
+ export type MotionStep = BrushStep | DrawStep | WriteStep | FadeStep | RiseStep | StampStep | DevelopStep;
66
+ export interface MotionSpec {
67
+ steps: MotionStep[];
68
+ /** Seconds before the first step (after the card has dropped onto the desk). */
69
+ delay?: number;
70
+ /** Default duration for steps that leave it out. */
71
+ duration?: number;
72
+ /** Gap in seconds between steps that leave `at` out (negative overlaps). */
73
+ stagger?: number;
74
+ }
75
+ /** Wrap text in a span a step can target; use as a FitBlock's `html`. */
76
+ export declare const mark: (text: string, cls?: string) => string;
77
+ /**
78
+ * A spec when `on`, else nothing. Makers decide `on` from a forked rng
79
+ * (`const m = rng.fork(); const mo = m.chance(ctx.motion)`) so the card's
80
+ * content is the same whether motion is enabled or not.
81
+ */
82
+ export declare function motion(on: boolean, steps: MotionStep[], opts?: Omit<MotionSpec, 'steps'>): MotionSpec | undefined;
83
+ export declare const underlineTitle: (rng: Rng, target?: Target, color?: string) => MotionStep[];
84
+ export declare const strikeDone: (rng: Rng, target?: Target, color?: string) => MotionStep[];
85
+ export declare const circleWord: (rng: Rng, target: Target, color?: string) => MotionStep[];
86
+ export declare const highlightLine: (rng: Rng, target: Target, color?: string, opacity?: number) => MotionStep[];
87
+ export declare const boxWord: (rng: Rng, target: Target, color?: string) => MotionStep[];
88
+ export declare const bracketQuote: (rng: Rng, target: Target, color?: string) => MotionStep[];
89
+ export declare const drawDoodle: (target?: Target, duration?: number) => MotionStep[];
90
+ export declare const typeIn: (target?: Target, rate?: number) => MotionStep[];
91
+ export declare const writeOn: (target: Target, duration?: number) => MotionStep[];
92
+ export declare const stampIn: (target: Target) => MotionStep[];
93
+ export declare const riseIn: (target: Target, dy?: number, at?: At) => MotionStep[];
94
+ export declare const fadeIn: (target: Target, duration?: number, at?: At) => MotionStep[];
95
+ export declare const developPhoto: (target?: Target, duration?: number) => MotionStep[];
96
+ /** A grease-pencil mark around a picked frame (contact sheets, film strips). */
97
+ export declare const markFrame: (rng: Rng, target: Target, color: string) => MotionStep[];
98
+ export {};
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Runs a card's MotionSpec: one paused Brushmark timeline per card, with
3
+ * annotation timelines nested as children and native steps (draw, write,
4
+ * fade, rise, stamp) as tweens on plain numbers.
5
+ *
6
+ * Performance rules:
7
+ * - layout is read only in `prepare`, inside withUnrotated, once per card;
8
+ * - tweens write numbers; the master timeline's onUpdate flushes one batched
9
+ * style write per dirty element (transform / opacity / clip-path, plus
10
+ * stroke-dashoffset for the one small doodle SVG);
11
+ * - every card ticks on Brushmark's single rAF ticker, which stops when
12
+ * nothing is playing; Brushmark repaints only dirty overlays;
13
+ * - annotations are built one card per frame by the render queue, and the
14
+ * brush budget caps GL paints per card and per desk.
15
+ */
16
+ import { type BrushTimeline } from 'brushmark';
17
+ import type { CardPlan } from './scene';
18
+ import type { BuiltCard } from './renderer';
19
+ import type { Rng } from './rng';
20
+ import type { PenContext } from './pen';
21
+ export interface CardMotion {
22
+ timeline: BrushTimeline;
23
+ /** Start after the card's drop animation (right away if it already ran). */
24
+ play(): void;
25
+ pause(): void;
26
+ resume(): void;
27
+ /** Restart from the beginning after `delayMs`. */
28
+ replay(delayMs?: number): void;
29
+ /** Pause and show the state at progress 0..1 (debug scrubber). */
30
+ seek(p: number): void;
31
+ /** Jump to the end state, painted right now (grab, reduced motion). */
32
+ finish(): void;
33
+ dispose(): void;
34
+ }
35
+ export declare const prefersReducedMotion: () => boolean;
36
+ export declare function prepareMotion(plan: CardPlan, built: BuiltCard, rng: Rng, pen?: PenContext): CardMotion | null;