@effing/canvas 0.18.3 → 0.18.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +56 -41
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -795,6 +795,10 @@ function toNumber(v) {
|
|
|
795
795
|
|
|
796
796
|
// src/jsx/draw/svg.ts
|
|
797
797
|
import { Path2D } from "@napi-rs/canvas";
|
|
798
|
+
function resolveCurrentColor(value, color) {
|
|
799
|
+
if (value?.toLowerCase() === "currentcolor") return color;
|
|
800
|
+
return value;
|
|
801
|
+
}
|
|
798
802
|
function mergeStyleIntoProps(props) {
|
|
799
803
|
const style = props.style;
|
|
800
804
|
if (!style) return props;
|
|
@@ -814,65 +818,66 @@ function drawSvgContainer(ctx, node, x, y, width, height) {
|
|
|
814
818
|
ctx.translate(-vbX, -vbY);
|
|
815
819
|
}
|
|
816
820
|
}
|
|
821
|
+
const color = node.style.color ?? "black";
|
|
817
822
|
const merged = mergeStyleIntoProps(node.props);
|
|
818
|
-
const inheritedFill = merged.fill ?? "black";
|
|
823
|
+
const inheritedFill = resolveCurrentColor(merged.fill, color) ?? "black";
|
|
819
824
|
const children = node.props.children;
|
|
820
825
|
if (children != null) {
|
|
821
826
|
const childArray = Array.isArray(children) ? children : [children];
|
|
822
827
|
for (const child of childArray) {
|
|
823
828
|
if (child != null && typeof child === "object") {
|
|
824
|
-
drawSvgChild(ctx, child, inheritedFill);
|
|
829
|
+
drawSvgChild(ctx, child, inheritedFill, color);
|
|
825
830
|
}
|
|
826
831
|
}
|
|
827
832
|
}
|
|
828
833
|
ctx.restore();
|
|
829
834
|
}
|
|
830
|
-
function drawSvgChild(ctx, child, inheritedFill) {
|
|
835
|
+
function drawSvgChild(ctx, child, inheritedFill, color) {
|
|
831
836
|
const { type } = child;
|
|
832
837
|
const props = mergeStyleIntoProps(child.props);
|
|
833
838
|
switch (type) {
|
|
834
839
|
case "path":
|
|
835
|
-
drawPath(ctx, props, inheritedFill);
|
|
840
|
+
drawPath(ctx, props, inheritedFill, color);
|
|
836
841
|
break;
|
|
837
842
|
case "circle":
|
|
838
|
-
drawCircle(ctx, props, inheritedFill);
|
|
843
|
+
drawCircle(ctx, props, inheritedFill, color);
|
|
839
844
|
break;
|
|
840
845
|
case "rect":
|
|
841
|
-
drawSvgRect(ctx, props, inheritedFill);
|
|
846
|
+
drawSvgRect(ctx, props, inheritedFill, color);
|
|
842
847
|
break;
|
|
843
848
|
case "line":
|
|
844
|
-
drawLine(ctx, props);
|
|
849
|
+
drawLine(ctx, props, color);
|
|
845
850
|
break;
|
|
846
851
|
case "ellipse":
|
|
847
|
-
drawEllipse(ctx, props, inheritedFill);
|
|
852
|
+
drawEllipse(ctx, props, inheritedFill, color);
|
|
848
853
|
break;
|
|
849
854
|
case "polygon":
|
|
850
|
-
drawPolygon(ctx, props, inheritedFill);
|
|
855
|
+
drawPolygon(ctx, props, inheritedFill, color);
|
|
851
856
|
break;
|
|
852
857
|
case "polyline":
|
|
853
|
-
drawPolyline(ctx, props, inheritedFill);
|
|
858
|
+
drawPolyline(ctx, props, inheritedFill, color);
|
|
854
859
|
break;
|
|
855
860
|
case "g":
|
|
856
|
-
drawGroup(ctx, child, inheritedFill);
|
|
861
|
+
drawGroup(ctx, child, inheritedFill, color);
|
|
857
862
|
break;
|
|
858
863
|
}
|
|
859
864
|
}
|
|
860
|
-
function drawPath(ctx, props, inheritedFill) {
|
|
865
|
+
function drawPath(ctx, props, inheritedFill, color) {
|
|
861
866
|
const d = props.d;
|
|
862
867
|
if (!d) return;
|
|
863
868
|
const path = new Path2D(d);
|
|
864
|
-
applyFillAndStroke(ctx, props, path, inheritedFill);
|
|
869
|
+
applyFillAndStroke(ctx, props, path, inheritedFill, color);
|
|
865
870
|
}
|
|
866
|
-
function drawCircle(ctx, props, inheritedFill) {
|
|
871
|
+
function drawCircle(ctx, props, inheritedFill, color) {
|
|
867
872
|
const cx = Number(props.cx ?? 0);
|
|
868
873
|
const cy = Number(props.cy ?? 0);
|
|
869
874
|
const r = Number(props.r ?? 0);
|
|
870
875
|
if (r <= 0) return;
|
|
871
876
|
const path = new Path2D();
|
|
872
877
|
path.arc(cx, cy, r, 0, Math.PI * 2);
|
|
873
|
-
applyFillAndStroke(ctx, props, path, inheritedFill);
|
|
878
|
+
applyFillAndStroke(ctx, props, path, inheritedFill, color);
|
|
874
879
|
}
|
|
875
|
-
function drawSvgRect(ctx, props, inheritedFill) {
|
|
880
|
+
function drawSvgRect(ctx, props, inheritedFill, color) {
|
|
876
881
|
const rx = Number(props.x ?? 0);
|
|
877
882
|
const ry = Number(props.y ?? 0);
|
|
878
883
|
const w = Number(props.width ?? 0);
|
|
@@ -880,9 +885,9 @@ function drawSvgRect(ctx, props, inheritedFill) {
|
|
|
880
885
|
if (w <= 0 || h <= 0) return;
|
|
881
886
|
const path = new Path2D();
|
|
882
887
|
path.rect(rx, ry, w, h);
|
|
883
|
-
applyFillAndStroke(ctx, props, path, inheritedFill);
|
|
888
|
+
applyFillAndStroke(ctx, props, path, inheritedFill, color);
|
|
884
889
|
}
|
|
885
|
-
function drawLine(ctx, props) {
|
|
890
|
+
function drawLine(ctx, props, color) {
|
|
886
891
|
const x1 = Number(props.x1 ?? 0);
|
|
887
892
|
const y1 = Number(props.y1 ?? 0);
|
|
888
893
|
const x2 = Number(props.x2 ?? 0);
|
|
@@ -890,9 +895,9 @@ function drawLine(ctx, props) {
|
|
|
890
895
|
const path = new Path2D();
|
|
891
896
|
path.moveTo(x1, y1);
|
|
892
897
|
path.lineTo(x2, y2);
|
|
893
|
-
applyStroke(ctx, props, path);
|
|
898
|
+
applyStroke(ctx, props, path, color);
|
|
894
899
|
}
|
|
895
|
-
function drawEllipse(ctx, props, inheritedFill) {
|
|
900
|
+
function drawEllipse(ctx, props, inheritedFill, color) {
|
|
896
901
|
const cx = Number(props.cx ?? 0);
|
|
897
902
|
const cy = Number(props.cy ?? 0);
|
|
898
903
|
const rx = Number(props.rx ?? 0);
|
|
@@ -900,9 +905,9 @@ function drawEllipse(ctx, props, inheritedFill) {
|
|
|
900
905
|
if (rx <= 0 || ry <= 0) return;
|
|
901
906
|
const path = new Path2D();
|
|
902
907
|
path.ellipse(cx, cy, rx, ry, 0, 0, Math.PI * 2);
|
|
903
|
-
applyFillAndStroke(ctx, props, path, inheritedFill);
|
|
908
|
+
applyFillAndStroke(ctx, props, path, inheritedFill, color);
|
|
904
909
|
}
|
|
905
|
-
function drawPolygon(ctx, props, inheritedFill) {
|
|
910
|
+
function drawPolygon(ctx, props, inheritedFill, color) {
|
|
906
911
|
const points = parsePoints(props.points);
|
|
907
912
|
if (points.length < 2) return;
|
|
908
913
|
const path = new Path2D();
|
|
@@ -911,9 +916,9 @@ function drawPolygon(ctx, props, inheritedFill) {
|
|
|
911
916
|
path.lineTo(points[i][0], points[i][1]);
|
|
912
917
|
}
|
|
913
918
|
path.closePath();
|
|
914
|
-
applyFillAndStroke(ctx, props, path, inheritedFill);
|
|
919
|
+
applyFillAndStroke(ctx, props, path, inheritedFill, color);
|
|
915
920
|
}
|
|
916
|
-
function drawPolyline(ctx, props, inheritedFill) {
|
|
921
|
+
function drawPolyline(ctx, props, inheritedFill, color) {
|
|
917
922
|
const points = parsePoints(props.points);
|
|
918
923
|
if (points.length < 2) return;
|
|
919
924
|
const path = new Path2D();
|
|
@@ -921,17 +926,17 @@ function drawPolyline(ctx, props, inheritedFill) {
|
|
|
921
926
|
for (let i = 1; i < points.length; i++) {
|
|
922
927
|
path.lineTo(points[i][0], points[i][1]);
|
|
923
928
|
}
|
|
924
|
-
applyFillAndStroke(ctx, props, path, inheritedFill);
|
|
929
|
+
applyFillAndStroke(ctx, props, path, inheritedFill, color);
|
|
925
930
|
}
|
|
926
|
-
function drawGroup(ctx, node, inheritedFill) {
|
|
931
|
+
function drawGroup(ctx, node, inheritedFill, color) {
|
|
927
932
|
const children = node.children ?? node.props.children;
|
|
928
933
|
if (children == null) return;
|
|
929
934
|
const merged = mergeStyleIntoProps(node.props);
|
|
930
|
-
const groupFill = merged.fill ?? inheritedFill;
|
|
935
|
+
const groupFill = resolveCurrentColor(merged.fill, color) ?? inheritedFill;
|
|
931
936
|
const childArray = Array.isArray(children) ? children : [children];
|
|
932
937
|
for (const child of childArray) {
|
|
933
938
|
if (child != null && typeof child === "object") {
|
|
934
|
-
drawSvgChild(ctx, child, groupFill);
|
|
939
|
+
drawSvgChild(ctx, child, groupFill, color);
|
|
935
940
|
}
|
|
936
941
|
}
|
|
937
942
|
}
|
|
@@ -944,16 +949,16 @@ function parsePoints(value) {
|
|
|
944
949
|
}
|
|
945
950
|
return result;
|
|
946
951
|
}
|
|
947
|
-
function applyFillAndStroke(ctx, props, path, inheritedFill) {
|
|
948
|
-
const fill = props.fill ?? inheritedFill;
|
|
952
|
+
function applyFillAndStroke(ctx, props, path, inheritedFill, color) {
|
|
953
|
+
const fill = resolveCurrentColor(props.fill, color) ?? inheritedFill;
|
|
949
954
|
if (fill !== "none") {
|
|
950
955
|
ctx.fillStyle = fill;
|
|
951
956
|
ctx.fill(path);
|
|
952
957
|
}
|
|
953
|
-
applyStroke(ctx, props, path);
|
|
958
|
+
applyStroke(ctx, props, path, color);
|
|
954
959
|
}
|
|
955
|
-
function applyStroke(ctx, props, path) {
|
|
956
|
-
const stroke = props.stroke;
|
|
960
|
+
function applyStroke(ctx, props, path, color) {
|
|
961
|
+
const stroke = resolveCurrentColor(props.stroke, color);
|
|
957
962
|
if (!stroke || stroke === "none") return;
|
|
958
963
|
ctx.strokeStyle = stroke;
|
|
959
964
|
ctx.lineWidth = Number(props.strokeWidth ?? props["stroke-width"] ?? 1);
|
|
@@ -2301,10 +2306,14 @@ async function buildNode(element, parentStyle, yogaNode, viewportWidth, viewport
|
|
|
2301
2306
|
resolveUnits(style, viewportWidth, viewportHeight);
|
|
2302
2307
|
const tagName = String(type);
|
|
2303
2308
|
if (tagName === "svg") {
|
|
2304
|
-
if (props.width != null && style.width === void 0)
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2309
|
+
if (props.width != null && style.width === void 0) {
|
|
2310
|
+
const v = props.width;
|
|
2311
|
+
style.width = typeof v === "string" && v.endsWith("%") ? v : Number(v);
|
|
2312
|
+
}
|
|
2313
|
+
if (props.height != null && style.height === void 0) {
|
|
2314
|
+
const v = props.height;
|
|
2315
|
+
style.height = typeof v === "string" && v.endsWith("%") ? v : Number(v);
|
|
2316
|
+
}
|
|
2308
2317
|
const viewBox = props.viewBox;
|
|
2309
2318
|
if (viewBox) {
|
|
2310
2319
|
const parts = viewBox.split(/[\s,]+/).map(Number);
|
|
@@ -2326,10 +2335,14 @@ async function buildNode(element, parentStyle, yogaNode, viewportWidth, viewport
|
|
|
2326
2335
|
}
|
|
2327
2336
|
}
|
|
2328
2337
|
if (tagName === "img") {
|
|
2329
|
-
if (props.width != null && style.width === void 0)
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2338
|
+
if (props.width != null && style.width === void 0) {
|
|
2339
|
+
const v = props.width;
|
|
2340
|
+
style.width = typeof v === "string" && v.endsWith("%") ? v : Number(v);
|
|
2341
|
+
}
|
|
2342
|
+
if (props.height != null && style.height === void 0) {
|
|
2343
|
+
const v = props.height;
|
|
2344
|
+
style.height = typeof v === "string" && v.endsWith("%") ? v : Number(v);
|
|
2345
|
+
}
|
|
2333
2346
|
const src = props.src;
|
|
2334
2347
|
if (src) {
|
|
2335
2348
|
try {
|
|
@@ -2369,6 +2382,8 @@ async function buildNode(element, parentStyle, yogaNode, viewportWidth, viewport
|
|
|
2369
2382
|
emojiEnabled
|
|
2370
2383
|
);
|
|
2371
2384
|
childYogaNode.setMeasureFunc(measureFunc);
|
|
2385
|
+
childYogaNode.setFlexGrow(1);
|
|
2386
|
+
childYogaNode.setFlexShrink(1);
|
|
2372
2387
|
yogaNode.insertChild(childYogaNode, 0);
|
|
2373
2388
|
return {
|
|
2374
2389
|
type: tagName,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/lottie.ts","../src/jsx/draw/index.ts","../src/jsx/language.ts","../src/jsx/text/linebreak.ts","../src/jsx/text/measure.ts","../src/jsx/text/index.ts","../src/jsx/draw/clip.ts","../src/jsx/draw/gradient.ts","../src/jsx/draw/image.ts","../src/jsx/draw/object-fit.ts","../src/jsx/draw/rect.ts","../src/jsx/draw/svg.ts","../src/jsx/draw/text.ts","../src/jsx/emoji.ts","../src/jsx/text/emoji-split.ts","../src/jsx/font.ts","../src/jsx/layout.ts","../src/jsx/style/expand.ts","../src/jsx/style/compute.ts","../src/jsx/yoga.ts","../src/jsx/style/properties.ts","../src/jsx/index.ts"],"sourcesContent":["// Re-export canvas primitives from @napi-rs/canvas\nimport { createCanvas as _createCanvas } from \"@napi-rs/canvas\";\nexport {\n Canvas,\n type SKRSContext2D,\n GlobalFonts,\n loadImage,\n Image,\n} from \"@napi-rs/canvas\";\n\nexport function createCanvas(width: number, height: number) {\n const canvas = _createCanvas(width, height);\n const origEncode = canvas.encode.bind(canvas);\n type Encode = typeof canvas.encode;\n\n // The native @napi-rs/canvas encode() returns Buffers backed by Rust/Skia\n // memory that can be freed before downstream consumers finish reading (e.g.\n // when streaming frames concurrently). We patch encode to copy the result\n // to the JS heap so the data remains valid regardless of native GC timing.\n canvas.encode = (async (...args: unknown[]) =>\n Buffer.from(await origEncode(...(args as Parameters<Encode>)))) as Encode;\n\n return canvas;\n}\n\n// Lottie API\nexport { LottieAnimation, loadLottie, renderLottieFrame } from \"./lottie.ts\";\n\n// JSX API\nexport { renderReactElement } from \"./jsx/index.ts\";\n\n// Font management\nexport {\n registerFont,\n registerFontFromPath,\n registeredFamilies,\n} from \"./jsx/font.ts\";\n\n// Types\nexport type {\n FontData,\n RenderReactElementOptions,\n EmojiStyle,\n} from \"./types.ts\";\n","import { LottieAnimation } from \"@napi-rs/canvas\";\nimport type { SKRSContext2D } from \"@napi-rs/canvas\";\n\nexport { LottieAnimation };\n\n/**\n * Load a Lottie animation from a JSON string or Buffer.\n *\n * @param data - Lottie JSON string or Buffer\n * @param options - Optional resource path for external assets\n * @returns A `LottieAnimation` handle ready for rendering\n *\n * @example\n * ```ts\n * const anim = loadLottie(fs.readFileSync(\"animation.json\", \"utf-8\"));\n * ```\n */\nexport function loadLottie(\n data: string | Buffer,\n options?: { resourcePath?: string },\n): LottieAnimation {\n const jsonString = typeof data === \"string\" ? data : data.toString(\"utf-8\");\n return LottieAnimation.loadFromData(jsonString, {\n resourcePath: options?.resourcePath,\n });\n}\n\n/**\n * Render a specific frame of a Lottie animation to a canvas context.\n *\n * Seeks the animation to the given frame, then renders it onto the\n * provided context. The canvas dimensions determine the render size.\n *\n * @param ctx - Canvas 2D rendering context to draw into\n * @param animation - Lottie animation handle (from {@link loadLottie})\n * @param frame - Zero-based frame number to render\n *\n * @example\n * ```ts\n * import { createCanvas, loadLottie, renderLottieFrame } from \"@effing/canvas\";\n *\n * const canvas = createCanvas(1080, 1080);\n * const ctx = canvas.getContext(\"2d\");\n * const anim = loadLottie(jsonString);\n *\n * renderLottieFrame(ctx, anim, 0);\n * const png = canvas.encodeSync(\"png\");\n * ```\n */\nexport function renderLottieFrame(\n ctx: SKRSContext2D,\n animation: LottieAnimation,\n frame: number,\n): void {\n animation.seekFrame(frame);\n animation.render(ctx);\n}\n","import type { Canvas, Image, SKRSContext2D } from \"@napi-rs/canvas\";\n\nimport { createCanvas, loadImage } from \"@napi-rs/canvas\";\n\nconst canvasPool = new Map<string, WeakRef<Canvas>[]>();\n\nfunction acquireOffscreen(w: number, h: number): [Canvas, SKRSContext2D] {\n const key = `${w}x${h}`;\n const stack = canvasPool.get(key);\n if (stack) {\n while (stack.length > 0) {\n const ref = stack.pop()!;\n const canvas = ref.deref();\n if (canvas) {\n const ctx = canvas.getContext(\"2d\");\n ctx.setTransform(1, 0, 0, 1, 0, 0);\n ctx.clearRect(0, 0, w, h);\n return [canvas, ctx];\n }\n }\n }\n const canvas = createCanvas(w, h);\n return [canvas, canvas.getContext(\"2d\")];\n}\n\nfunction releaseOffscreen(canvas: Canvas): void {\n const key = `${canvas.width}x${canvas.height}`;\n let stack = canvasPool.get(key);\n if (!stack) {\n stack = [];\n canvasPool.set(key, stack);\n }\n stack.push(new WeakRef(canvas));\n}\n\nimport type { EmojiStyle } from \"../emoji.ts\";\nimport type { LayoutNode } from \"../layout.ts\";\nimport { layoutText } from \"../text/index.ts\";\nimport { applyClip, roundedRect } from \"./clip.ts\";\nimport { createGradientFromCSS } from \"./gradient.ts\";\nimport { drawImage } from \"./image.ts\";\nimport { computeContain, computeCover } from \"./object-fit.ts\";\nimport { drawRect, getBorderRadiusFromStyle } from \"./rect.ts\";\nimport { drawSvgContainer } from \"./svg.ts\";\nimport { drawText } from \"./text.ts\";\n\n/**\n * Main draw dispatcher: recursively draws the layout tree onto the canvas.\n */\nexport async function drawNode(\n ctx: SKRSContext2D,\n node: LayoutNode,\n parentX: number,\n parentY: number,\n debug: boolean,\n emojiStyle?: EmojiStyle,\n): Promise<void> {\n const x = parentX + node.x;\n const y = parentY + node.y;\n const { width, height, style } = node;\n\n if (style.display === \"none\") return;\n\n const opacity = style.opacity ?? 1;\n if (opacity <= 0) return;\n\n // Detect scale in transform — if present, render to offscreen buffer at 1x\n // then composite scaled. This avoids Skia re-rasterizing glyphs per-frame.\n const scaleInfo = style.transform ? extractScale(style.transform) : null;\n if (scaleInfo && (scaleInfo.sx !== 1 || scaleInfo.sy !== 1)) {\n const sx = scaleInfo.sx;\n const sy = scaleInfo.sy;\n const transformWithoutScale = scaleInfo.remaining;\n\n // Quantize to ceil(|scale|) — buffer resolution only changes at\n // integer boundaries (no jitter), and composite is always ≤1x (sharp).\n const qx = Math.max(1, Math.ceil(Math.abs(sx)));\n const qy = Math.max(1, Math.ceil(Math.abs(sy)));\n\n const bufW = Math.ceil((width + 2) * qx);\n const bufH = Math.ceil((height + 2) * qy);\n if (bufW > 0 && bufH > 0) {\n const [offscreen, offCtx] = acquireOffscreen(bufW, bufH);\n\n // Render at qx×qy resolution — logical coords produce more pixels\n offCtx.save();\n offCtx.scale(qx, qy);\n await drawNodeInner(\n offCtx,\n node,\n parentX,\n parentY,\n 1 - x,\n 1 - y,\n debug,\n emojiStyle,\n transformWithoutScale,\n );\n offCtx.restore();\n\n ctx.save();\n if (opacity < 1) {\n ctx.globalAlpha *= opacity;\n }\n\n let ox = x + width / 2;\n let oy = y + height / 2;\n if (style.transformOrigin) {\n const parts = style.transformOrigin.split(/\\s+/);\n ox = resolveOrigin(parts[0], x, width);\n oy = resolveOrigin(parts[1], y, height);\n }\n\n // Apply the original scale — drawImage maps the high-res buffer\n // back to logical size, so the transform needs the full scale value.\n ctx.translate(ox, oy);\n ctx.scale(sx, sy);\n ctx.translate(-ox, -oy);\n\n // Draw high-res buffer back at logical size (qx→1x downscale happens here)\n ctx.drawImage(\n offscreen,\n 0,\n 0,\n bufW,\n bufH,\n x - 1,\n y - 1,\n width + 2,\n height + 2,\n );\n releaseOffscreen(offscreen);\n ctx.restore();\n return;\n }\n }\n\n ctx.save();\n\n // Apply opacity\n if (opacity < 1) {\n ctx.globalAlpha *= opacity;\n }\n\n // Apply CSS filter\n if (style.filter) {\n ctx.filter = style.filter;\n }\n\n // Apply transform\n if (style.transform) {\n applyTransform(\n ctx,\n style.transform,\n x,\n y,\n width,\n height,\n style.transformOrigin,\n );\n }\n\n // Apply clipping for overflow: hidden\n const isClipped =\n style.overflow === \"hidden\" ||\n style.overflowX === \"hidden\" ||\n style.overflowY === \"hidden\";\n\n if (isClipped) {\n const borderRadius = getBorderRadiusFromStyle(style);\n applyClip(ctx, x, y, width, height, borderRadius);\n }\n\n // Draw background and borders\n if (\n style.backgroundColor ||\n style.borderTopWidth ||\n style.borderRightWidth ||\n style.borderBottomWidth ||\n style.borderLeftWidth ||\n style.boxShadow\n ) {\n drawRect(ctx, x, y, width, height, style);\n }\n\n // Draw background-image (gradient or url)\n if (style.backgroundImage) {\n const gradient = createGradientFromCSS(\n ctx,\n style.backgroundImage,\n x,\n y,\n width,\n height,\n );\n if (gradient) {\n ctx.fillStyle = gradient;\n const borderRadius = getBorderRadiusFromStyle(style);\n if (\n borderRadius.topLeft > 0 ||\n borderRadius.topRight > 0 ||\n borderRadius.bottomRight > 0 ||\n borderRadius.bottomLeft > 0\n ) {\n ctx.beginPath();\n roundedRect(\n ctx,\n x,\n y,\n width,\n height,\n borderRadius.topLeft,\n borderRadius.topRight,\n borderRadius.bottomRight,\n borderRadius.bottomLeft,\n );\n ctx.fill();\n } else {\n ctx.fillRect(x, y, width, height);\n }\n } else {\n // Try url(...) background image\n const urlMatch = style.backgroundImage.match(/url\\([\"']?(.*?)[\"']?\\)/);\n if (urlMatch) {\n const borderRadius = getBorderRadiusFromStyle(style);\n const hasRadius =\n borderRadius.topLeft > 0 ||\n borderRadius.topRight > 0 ||\n borderRadius.bottomRight > 0 ||\n borderRadius.bottomLeft > 0;\n\n if (hasRadius) {\n applyClip(ctx, x, y, width, height, borderRadius);\n }\n\n const image = await loadImage(urlMatch[1]!);\n const bgSize = style.backgroundSize;\n\n if (bgSize === \"cover\") {\n // Cover fills the box completely — no tiling needed\n const r = computeCover(\n image.width,\n image.height,\n x,\n y,\n width,\n height,\n );\n ctx.drawImage(image, r.sx, r.sy, r.sw, r.sh, r.dx, r.dy, r.dw, r.dh);\n } else {\n // Compute tile dimensions based on backgroundSize\n let tileW: number, tileH: number;\n if (bgSize === \"contain\") {\n const r = computeContain(\n image.width,\n image.height,\n 0,\n 0,\n width,\n height,\n );\n tileW = r.dw;\n tileH = r.dh;\n } else if (bgSize === \"100% 100%\") {\n tileW = width;\n tileH = height;\n } else {\n // CSS default (auto): natural image size\n tileW = image.width;\n tileH = image.height;\n }\n // Tile the image to fill the box (CSS background-repeat: repeat)\n for (let ty = y; ty < y + height; ty += tileH) {\n for (let tx = x; tx < x + width; tx += tileW) {\n ctx.drawImage(image, tx, ty, tileW, tileH);\n }\n }\n }\n }\n }\n }\n\n // Debug: draw bounding boxes\n if (debug) {\n ctx.strokeStyle = \"rgba(255, 0, 0, 0.5)\";\n ctx.lineWidth = 1;\n ctx.strokeRect(x, y, width, height);\n }\n\n // Draw text content\n if (node.textContent !== undefined && node.textContent !== \"\") {\n const paddingTop = toNumber(style.paddingTop);\n const paddingLeft = toNumber(style.paddingLeft);\n const paddingRight = toNumber(style.paddingRight);\n\n const borderTopW = toNumber(style.borderTopWidth);\n const borderLeftW = toNumber(style.borderLeftWidth);\n const borderRightW = toNumber(style.borderRightWidth);\n\n const contentX = x + paddingLeft + borderLeftW;\n const contentY = y + paddingTop + borderTopW;\n const contentWidth =\n width - paddingLeft - paddingRight - borderLeftW - borderRightW;\n\n const textLayout = layoutText(\n node.textContent,\n style,\n contentWidth,\n ctx,\n !!emojiStyle,\n );\n await drawText(\n ctx,\n textLayout.segments,\n contentX,\n contentY,\n style.textShadow,\n emojiStyle,\n );\n }\n\n // Draw <img> elements\n if (node.type === \"img\" && node.props.src) {\n const paddingTop = toNumber(style.paddingTop);\n const paddingLeft = toNumber(style.paddingLeft);\n const paddingRight = toNumber(style.paddingRight);\n const paddingBottom = toNumber(style.paddingBottom);\n\n const imgX = x + paddingLeft;\n const imgY = y + paddingTop;\n const imgW = width - paddingLeft - paddingRight;\n const imgH = height - paddingTop - paddingBottom;\n\n // Images are replaced content — borderRadius clips them directly\n // (unlike child content which requires overflow:hidden)\n if (!isClipped) {\n const borderRadius = getBorderRadiusFromStyle(style);\n if (\n borderRadius.topLeft > 0 ||\n borderRadius.topRight > 0 ||\n borderRadius.bottomRight > 0 ||\n borderRadius.bottomLeft > 0\n ) {\n applyClip(ctx, imgX, imgY, imgW, imgH, borderRadius);\n }\n }\n\n await drawImage(\n ctx,\n node.props.src as string | Buffer,\n imgX,\n imgY,\n imgW,\n imgH,\n style,\n node.props.__loadedImage as Image | undefined,\n );\n }\n\n // Draw <svg> containers (handle their own child traversal in SVG coordinate space)\n if (node.type === \"svg\") {\n drawSvgContainer(ctx, node, x, y, width, height);\n } else {\n // Recursively draw children\n for (const child of node.children) {\n await drawNode(ctx, child, x, y, debug, emojiStyle);\n }\n }\n\n ctx.restore();\n}\n\n/**\n * Extract scale(sx, sy) from a transform string, returning the scale values\n * and the remaining transform with scale removed.\n */\nfunction extractScale(\n transform: string,\n): { sx: number; sy: number; remaining: string } | null {\n const scaleMatch = transform.match(/\\b(scale|scaleX|scaleY)\\(([^)]+)\\)/);\n if (!scaleMatch) return null;\n\n const [fullMatch, name, args] = scaleMatch;\n const values = args!.split(\",\").map((s) => s.trim());\n\n const sx = name === \"scaleY\" ? 1 : parseFloat(values[0]!);\n const sy =\n name === \"scaleX\"\n ? 1\n : parseFloat(values[name === \"scale\" ? 1 : 0] ?? String(sx));\n\n const remaining = transform.replace(fullMatch!, \"\").trim();\n return { sx, sy, remaining };\n}\n\n/**\n * Inner draw that renders a node with an optional override transform\n * (used by the offscreen-buffer path to strip scale from the transform).\n * offsetX/offsetY shift all coordinates so the node renders at a buffer-local position.\n */\nasync function drawNodeInner(\n ctx: SKRSContext2D,\n node: LayoutNode,\n parentX: number,\n parentY: number,\n offsetX: number,\n offsetY: number,\n debug: boolean,\n emojiStyle: EmojiStyle | undefined,\n overrideTransform: string | undefined,\n): Promise<void> {\n const x = parentX + node.x + offsetX;\n const y = parentY + node.y + offsetY;\n const { width, height, style } = node;\n\n if (style.display === \"none\") return;\n\n const opacity = style.opacity ?? 1;\n if (opacity <= 0) return;\n\n ctx.save();\n\n if (opacity < 1) {\n ctx.globalAlpha *= opacity;\n }\n\n if (style.filter) {\n ctx.filter = style.filter;\n }\n\n // Apply the override transform (scale stripped) or original\n const transformToApply =\n overrideTransform !== undefined ? overrideTransform : style.transform;\n if (transformToApply) {\n applyTransform(\n ctx,\n transformToApply,\n x,\n y,\n width,\n height,\n style.transformOrigin,\n );\n }\n\n const isClipped =\n style.overflow === \"hidden\" ||\n style.overflowX === \"hidden\" ||\n style.overflowY === \"hidden\";\n\n if (isClipped) {\n const borderRadius = getBorderRadiusFromStyle(style);\n applyClip(ctx, x, y, width, height, borderRadius);\n }\n\n if (\n style.backgroundColor ||\n style.borderTopWidth ||\n style.borderRightWidth ||\n style.borderBottomWidth ||\n style.borderLeftWidth ||\n style.boxShadow\n ) {\n drawRect(ctx, x, y, width, height, style);\n }\n\n if (style.backgroundImage) {\n const gradient = createGradientFromCSS(\n ctx,\n style.backgroundImage,\n x,\n y,\n width,\n height,\n );\n if (gradient) {\n ctx.fillStyle = gradient;\n const borderRadius = getBorderRadiusFromStyle(style);\n if (\n borderRadius.topLeft > 0 ||\n borderRadius.topRight > 0 ||\n borderRadius.bottomRight > 0 ||\n borderRadius.bottomLeft > 0\n ) {\n ctx.beginPath();\n roundedRect(\n ctx,\n x,\n y,\n width,\n height,\n borderRadius.topLeft,\n borderRadius.topRight,\n borderRadius.bottomRight,\n borderRadius.bottomLeft,\n );\n ctx.fill();\n } else {\n ctx.fillRect(x, y, width, height);\n }\n } else {\n const urlMatch = style.backgroundImage.match(/url\\([\"']?(.*?)[\"']?\\)/);\n if (urlMatch) {\n const borderRadius = getBorderRadiusFromStyle(style);\n const hasRadius =\n borderRadius.topLeft > 0 ||\n borderRadius.topRight > 0 ||\n borderRadius.bottomRight > 0 ||\n borderRadius.bottomLeft > 0;\n if (hasRadius) {\n applyClip(ctx, x, y, width, height, borderRadius);\n }\n const image = await loadImage(urlMatch[1]!);\n const bgSize = style.backgroundSize;\n if (bgSize === \"cover\") {\n const r = computeCover(\n image.width,\n image.height,\n x,\n y,\n width,\n height,\n );\n ctx.drawImage(image, r.sx, r.sy, r.sw, r.sh, r.dx, r.dy, r.dw, r.dh);\n } else {\n let tileW: number, tileH: number;\n if (bgSize === \"contain\") {\n const r = computeContain(\n image.width,\n image.height,\n 0,\n 0,\n width,\n height,\n );\n tileW = r.dw;\n tileH = r.dh;\n } else if (bgSize === \"100% 100%\") {\n tileW = width;\n tileH = height;\n } else {\n tileW = image.width;\n tileH = image.height;\n }\n for (let ty = y; ty < y + height; ty += tileH) {\n for (let tx = x; tx < x + width; tx += tileW) {\n ctx.drawImage(image, tx, ty, tileW, tileH);\n }\n }\n }\n }\n }\n }\n\n if (debug) {\n ctx.strokeStyle = \"rgba(255, 0, 0, 0.5)\";\n ctx.lineWidth = 1;\n ctx.strokeRect(x, y, width, height);\n }\n\n if (node.textContent !== undefined && node.textContent !== \"\") {\n const paddingTop = toNumber(style.paddingTop);\n const paddingLeft = toNumber(style.paddingLeft);\n const paddingRight = toNumber(style.paddingRight);\n const borderTopW = toNumber(style.borderTopWidth);\n const borderLeftW = toNumber(style.borderLeftWidth);\n const borderRightW = toNumber(style.borderRightWidth);\n const contentX = x + paddingLeft + borderLeftW;\n const contentY = y + paddingTop + borderTopW;\n const contentWidth =\n width - paddingLeft - paddingRight - borderLeftW - borderRightW;\n const textLayout = layoutText(\n node.textContent,\n style,\n contentWidth,\n ctx,\n !!emojiStyle,\n );\n await drawText(\n ctx,\n textLayout.segments,\n contentX,\n contentY,\n style.textShadow,\n emojiStyle,\n );\n }\n\n if (node.type === \"img\" && node.props.src) {\n const paddingTop = toNumber(style.paddingTop);\n const paddingLeft = toNumber(style.paddingLeft);\n const paddingRight = toNumber(style.paddingRight);\n const paddingBottom = toNumber(style.paddingBottom);\n const imgX = x + paddingLeft;\n const imgY = y + paddingTop;\n const imgW = width - paddingLeft - paddingRight;\n const imgH = height - paddingTop - paddingBottom;\n if (!isClipped) {\n const borderRadius = getBorderRadiusFromStyle(style);\n if (\n borderRadius.topLeft > 0 ||\n borderRadius.topRight > 0 ||\n borderRadius.bottomRight > 0 ||\n borderRadius.bottomLeft > 0\n ) {\n applyClip(ctx, imgX, imgY, imgW, imgH, borderRadius);\n }\n }\n await drawImage(\n ctx,\n node.props.src as string | Buffer,\n imgX,\n imgY,\n imgW,\n imgH,\n style,\n node.props.__loadedImage as Image | undefined,\n );\n }\n\n if (node.type === \"svg\") {\n drawSvgContainer(ctx, node, x, y, width, height);\n } else {\n // Children use offset 0 since x,y already incorporates the offset\n for (const child of node.children) {\n await drawNodeInner(ctx, child, x, y, 0, 0, debug, emojiStyle, undefined);\n }\n }\n\n ctx.restore();\n}\n\nfunction applyTransform(\n ctx: SKRSContext2D,\n transform: string,\n x: number,\n y: number,\n width: number,\n height: number,\n transformOrigin?: string,\n): void {\n // Resolve transform-origin (default: center)\n let ox = x + width / 2;\n let oy = y + height / 2;\n\n if (transformOrigin) {\n const parts = transformOrigin.split(/\\s+/);\n ox = resolveOrigin(parts[0], x, width);\n oy = resolveOrigin(parts[1], y, height);\n }\n\n ctx.translate(ox, oy);\n\n // Parse and apply transform functions\n const funcs = transform.matchAll(/(\\w+)\\(([^)]+)\\)/g);\n\n for (const [, name, args] of funcs) {\n const values = args!.split(\",\").map((s) => s.trim());\n\n switch (name) {\n case \"translate\":\n case \"translateX\":\n case \"translateY\": {\n const tx = name === \"translateY\" ? 0 : parseFloat(values[0]!);\n const ty =\n name === \"translateX\"\n ? 0\n : parseFloat(values[name === \"translate\" ? 1 : 0] ?? \"0\");\n ctx.translate(tx, ty);\n break;\n }\n case \"scale\":\n case \"scaleX\":\n case \"scaleY\": {\n const sx = name === \"scaleY\" ? 1 : parseFloat(values[0]!);\n const sy =\n name === \"scaleX\"\n ? 1\n : parseFloat(values[name === \"scale\" ? 1 : 0] ?? String(sx));\n ctx.scale(sx, sy);\n break;\n }\n case \"rotate\": {\n const angle = parseAngle(values[0]!);\n ctx.rotate(angle);\n break;\n }\n case \"skewX\": {\n const angle = parseAngle(values[0]!);\n ctx.transform(1, 0, Math.tan(angle), 1, 0, 0);\n break;\n }\n case \"skewY\": {\n const angle = parseAngle(values[0]!);\n ctx.transform(1, Math.tan(angle), 0, 1, 0, 0);\n break;\n }\n }\n }\n\n ctx.translate(-ox, -oy);\n}\n\nfunction resolveOrigin(\n value: string | undefined,\n base: number,\n size: number,\n): number {\n if (!value) return base + size / 2;\n if (value === \"left\" || value === \"top\") return base;\n if (value === \"right\" || value === \"bottom\") return base + size;\n if (value === \"center\") return base + size / 2;\n if (value.endsWith(\"%\")) return base + (parseFloat(value) / 100) * size;\n return base + parseFloat(value);\n}\n\nfunction parseAngle(value: string): number {\n if (value.endsWith(\"deg\")) return (parseFloat(value) * Math.PI) / 180;\n if (value.endsWith(\"rad\")) return parseFloat(value);\n if (value.endsWith(\"turn\")) return parseFloat(value) * 2 * Math.PI;\n return parseFloat(value);\n}\n\nfunction toNumber(v: unknown): number {\n if (typeof v === \"number\") return v;\n if (v === undefined || v === null) return 0;\n const n = parseFloat(String(v));\n return isNaN(n) ? 0 : n;\n}\n","// This file contains code adapted from Satori (https://github.com/vercel/satori)\n// Licensed under the Mozilla Public License 2.0 (MPL-2.0)\n// See NOTICE.md in the package root for details.\n\n/**\n * Detect the primary script/language of a text string.\n * Used for font selection and line-breaking behavior.\n */\nexport function detectLanguageCode(text: string): string | undefined {\n for (const char of text) {\n const cp = char.codePointAt(0);\n if (cp === undefined) continue;\n\n // CJK Unified Ideographs\n if (cp >= 0x4e00 && cp <= 0x9fff) return \"zh\";\n // CJK Extension A\n if (cp >= 0x3400 && cp <= 0x4dbf) return \"zh\";\n // Hiragana\n if (cp >= 0x3040 && cp <= 0x309f) return \"ja\";\n // Katakana\n if (cp >= 0x30a0 && cp <= 0x30ff) return \"ja\";\n // Hangul Syllables\n if (cp >= 0xac00 && cp <= 0xd7af) return \"ko\";\n // Hangul Jamo\n if (cp >= 0x1100 && cp <= 0x11ff) return \"ko\";\n // Thai\n if (cp >= 0x0e00 && cp <= 0x0e7f) return \"th\";\n // Arabic\n if (cp >= 0x0600 && cp <= 0x06ff) return \"ar\";\n // Hebrew\n if (cp >= 0x0590 && cp <= 0x05ff) return \"he\";\n // Devanagari\n if (cp >= 0x0900 && cp <= 0x097f) return \"hi\";\n // Bengali\n if (cp >= 0x0980 && cp <= 0x09ff) return \"bn\";\n // Tamil\n if (cp >= 0x0b80 && cp <= 0x0bff) return \"ta\";\n // Telugu\n if (cp >= 0x0c00 && cp <= 0x0c7f) return \"te\";\n // Kannada\n if (cp >= 0x0c80 && cp <= 0x0cff) return \"kn\";\n // Malayalam\n if (cp >= 0x0d00 && cp <= 0x0d7f) return \"ml\";\n }\n\n return undefined;\n}\n\n/**\n * Check if a character is an emoji.\n */\nexport function isEmoji(char: string): boolean {\n const cp = char.codePointAt(0);\n if (cp === undefined) return false;\n\n // Common emoji ranges\n if (cp >= 0x1f600 && cp <= 0x1f64f) return true; // Emoticons\n if (cp >= 0x1f300 && cp <= 0x1f5ff) return true; // Misc Symbols & Pictographs\n if (cp >= 0x1f680 && cp <= 0x1f6ff) return true; // Transport & Map\n if (cp >= 0x1f900 && cp <= 0x1f9ff) return true; // Supplemental Symbols\n if (cp >= 0x2600 && cp <= 0x26ff) return true; // Misc Symbols\n if (cp >= 0x2700 && cp <= 0x27bf) return true; // Dingbats\n if (cp >= 0x2b50 && cp <= 0x2b55) return true; // Misc Symbols & Arrows (star, circle)\n if (cp >= 0x200d && cp <= 0x200d) return true; // Zero Width Joiner\n if (cp >= 0xfe00 && cp <= 0xfe0f) return true; // Variation Selectors\n if (cp >= 0x1fa00 && cp <= 0x1fa6f) return true; // Chess Symbols\n if (cp >= 0x1fa70 && cp <= 0x1faff) return true; // Symbols Extended-A\n if (cp >= 0x231a && cp <= 0x23f3) return true; // Misc Technical (watch, hourglass)\n if (cp >= 0x23e9 && cp <= 0x23fa) return true; // Misc Technical (play, pause)\n if (cp >= 0x25aa && cp <= 0x25fe) return true; // Geometric Shapes\n if (cp >= 0x2934 && cp <= 0x2935) return true; // Arrows\n if (cp >= 0x2b05 && cp <= 0x2b07) return true; // Arrows\n if (cp >= 0x3030 && cp <= 0x3030) return true; // Wavy dash\n if (cp >= 0x303d && cp <= 0x303d) return true; // Part alternation mark\n if (cp >= 0x3297 && cp <= 0x3299) return true; // CJK symbols\n\n return false;\n}\n","import LineBreaker from \"linebreak\";\n\nexport type BreakOpportunity = {\n position: number;\n required: boolean;\n};\n\n/**\n * Find line-break opportunities in text using UAX #14 algorithm.\n *\n * @param text - The text to analyze\n * @returns Array of break opportunities with positions and whether they're required (hard breaks)\n */\nexport function findBreakOpportunities(text: string): BreakOpportunity[] {\n const breaker = new LineBreaker(text);\n const opportunities: BreakOpportunity[] = [];\n\n let bk = breaker.nextBreak();\n while (bk) {\n opportunities.push({\n position: bk.position,\n required: bk.required ?? false,\n });\n bk = breaker.nextBreak();\n }\n\n return opportunities;\n}\n","import { createCanvas } from \"@napi-rs/canvas\";\nimport type { SKRSContext2D } from \"@napi-rs/canvas\";\n\nexport type TextMetrics = {\n width: number;\n ascent: number;\n descent: number;\n height: number;\n};\n\n// Scratch canvas for text measurement when no ctx is available\nlet scratchCtx: SKRSContext2D | null = null;\n\nfunction getScratchCtx(): SKRSContext2D {\n if (!scratchCtx) {\n scratchCtx = createCanvas(1, 1).getContext(\"2d\");\n }\n return scratchCtx;\n}\n\n/**\n * Set font properties on a canvas context for measurement.\n */\nexport function setFont(\n ctx: SKRSContext2D,\n fontSize: number,\n fontFamily: string,\n fontWeight: number | string = 400,\n fontStyle: string = \"normal\",\n): void {\n ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily}`;\n}\n\n/**\n * Measure text using the canvas ctx.measureText() API.\n * Returns width, ascent, descent, and total height.\n */\nexport function measureText(\n text: string,\n fontSize: number,\n fontFamily: string,\n fontWeight: number | string = 400,\n fontStyle: string = \"normal\",\n ctx?: SKRSContext2D,\n): TextMetrics {\n const c = ctx ?? getScratchCtx();\n setFont(c, fontSize, fontFamily, fontWeight, fontStyle);\n\n const m = c.measureText(text);\n\n const ascent =\n m.fontBoundingBoxAscent ?? m.actualBoundingBoxAscent ?? fontSize * 0.8;\n const descent =\n m.fontBoundingBoxDescent ?? m.actualBoundingBoxDescent ?? fontSize * 0.2;\n\n return {\n width: m.width,\n ascent,\n descent,\n height: ascent + descent,\n };\n}\n\n/**\n * Measure the width of a single word.\n */\nexport function measureWord(\n word: string,\n fontSize: number,\n fontFamily: string,\n fontWeight: number | string = 400,\n fontStyle: string = \"normal\",\n ctx?: SKRSContext2D,\n letterSpacing: number = 0,\n): number {\n const base = measureText(\n word,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n ).width;\n if (letterSpacing === 0 || word.length === 0) return base;\n return base + letterSpacing * word.length;\n}\n","// This file contains code adapted from Satori (https://github.com/vercel/satori)\n// Licensed under the Mozilla Public License 2.0 (MPL-2.0)\n// See NOTICE.md in the package root for details.\n\nimport type { SKRSContext2D } from \"@napi-rs/canvas\";\n\nimport type { ComputedStyle } from \"../style/compute.ts\";\nimport { isEmoji } from \"../language.ts\";\nimport { findBreakOpportunities } from \"./linebreak.ts\";\nimport { measureText, measureWord } from \"./measure.ts\";\nimport type { TextMetrics } from \"./measure.ts\";\n\nexport type TextSegment = {\n text: string;\n x: number;\n y: number;\n width: number;\n height: number;\n fontSize: number;\n fontFamily: string;\n fontWeight: number | string;\n fontStyle: string;\n color: string;\n ascent: number;\n textDecoration?: string;\n letterSpacing: number;\n lineIndex: number;\n};\n\nexport type TextLayoutResult = {\n segments: TextSegment[];\n width: number;\n height: number;\n};\n\n/**\n * Measure the width of a word, accounting for emoji characters when enabled.\n * Emoji characters are treated as square images sized to fontSize.\n */\nfunction emojiAwareMeasureWord(\n word: string,\n fontSize: number,\n fontFamily: string,\n fontWeight: number | string,\n fontStyle: string,\n ctx?: SKRSContext2D,\n letterSpacing: number = 0,\n): number {\n const segmenter = new Intl.Segmenter(undefined, { granularity: \"grapheme\" });\n let totalWidth = 0;\n let textBuffer = \"\";\n\n for (const { segment } of segmenter.segment(word)) {\n let isEmojiSegment = false;\n for (const char of segment) {\n if (isEmoji(char)) {\n isEmojiSegment = true;\n break;\n }\n }\n\n if (isEmojiSegment) {\n if (textBuffer) {\n totalWidth += measureWord(\n textBuffer,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n letterSpacing,\n );\n textBuffer = \"\";\n }\n totalWidth += fontSize;\n } else {\n textBuffer += segment;\n }\n }\n\n if (textBuffer) {\n totalWidth += measureWord(\n textBuffer,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n letterSpacing,\n );\n }\n\n return totalWidth;\n}\n\n/**\n * Lay out text content into positioned segments with line-breaking.\n *\n * @param text - The text to lay out\n * @param style - Computed style\n * @param maxWidth - Maximum width for wrapping\n * @param ctx - Canvas context for measurement\n * @param emojiEnabled - Whether to use emoji-aware measurement\n * @returns Text segments with positions and total dimensions\n */\nexport function layoutText(\n text: string,\n style: ComputedStyle,\n maxWidth: number,\n ctx?: SKRSContext2D,\n emojiEnabled?: boolean,\n): TextLayoutResult {\n const fontSize = style.fontSize ?? 16;\n const fontFamily = style.fontFamily ?? \"sans-serif\";\n const fontWeight = style.fontWeight ?? 400;\n const fontStyle = style.fontStyle ?? \"normal\";\n const color = style.color ?? \"black\";\n const textAlign = style.textAlign ?? \"left\";\n // Measure reference metrics for \"normal\" lineHeight (font ascent + descent)\n const refMetrics = measureText(\n \"M\",\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n );\n const lineHeightPx = resolveLineHeight(\n style.lineHeight,\n fontSize,\n refMetrics,\n );\n const letterSpacing =\n typeof style.letterSpacing === \"number\" ? style.letterSpacing : 0;\n const whiteSpace = style.whiteSpace ?? \"normal\";\n const wordBreak = style.wordBreak ?? \"normal\";\n const textOverflow = style.textOverflow ?? \"clip\";\n const textDecoration = style.textDecoration;\n\n // Choose measurement function based on emoji mode\n const measure = emojiEnabled\n ? (word: string, ls?: number) =>\n emojiAwareMeasureWord(\n word,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n ls ?? letterSpacing,\n )\n : (word: string, ls?: number) =>\n measureWord(\n word,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n ls ?? letterSpacing,\n );\n\n // Apply text transform\n let processedText = text;\n if (style.textTransform === \"uppercase\") {\n processedText = text.toUpperCase();\n } else if (style.textTransform === \"lowercase\") {\n processedText = text.toLowerCase();\n } else if (style.textTransform === \"capitalize\") {\n processedText = text.replace(/\\b\\w/g, (c) => c.toUpperCase());\n }\n\n const noWrap = whiteSpace === \"nowrap\" || whiteSpace === \"pre\";\n const preserveWhitespace = whiteSpace === \"pre\" || whiteSpace === \"pre-wrap\";\n\n // Split by explicit newlines\n const paragraphs = preserveWhitespace\n ? processedText.split(\"\\n\")\n : processedText.split(\"\\n\");\n\n const lines: string[] = [];\n\n for (const paragraph of paragraphs) {\n if (noWrap) {\n lines.push(paragraph);\n continue;\n }\n\n // Wrap text\n const wrapped = wrapText(\n paragraph,\n maxWidth,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n letterSpacing,\n wordBreak,\n ctx,\n measure,\n );\n lines.push(...wrapped);\n }\n\n // Handle text-overflow: ellipsis\n if (textOverflow === \"ellipsis\" && noWrap && lines.length === 1) {\n const line = lines[0]!;\n const lineWidth = measure(line);\n if (lineWidth > maxWidth) {\n lines[0] = truncateWithEllipsis(\n line,\n maxWidth,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n letterSpacing,\n );\n }\n }\n\n // Create positioned segments\n const segments: TextSegment[] = [];\n let totalHeight = 0;\n let maxLineWidth = 0;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n const lineWidth = measure(line);\n\n let x = 0;\n if (textAlign === \"center\") {\n x = (maxWidth - lineWidth) / 2;\n } else if (textAlign === \"right\") {\n x = maxWidth - lineWidth;\n }\n\n const metrics = measureText(\n line || \"M\",\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n );\n\n segments.push({\n text: line,\n x,\n y: totalHeight + (lineHeightPx + metrics.ascent - metrics.descent) / 2,\n width: lineWidth,\n height: lineHeightPx,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n color,\n ascent: metrics.ascent,\n textDecoration,\n letterSpacing,\n lineIndex: i,\n });\n\n totalHeight += lineHeightPx;\n maxLineWidth = Math.max(maxLineWidth, lineWidth);\n }\n\n return {\n segments,\n width: maxLineWidth,\n height: totalHeight,\n };\n}\n\nfunction resolveLineHeight(\n lineHeight: number | string | undefined,\n fontSize: number,\n metrics?: TextMetrics,\n): number {\n if (lineHeight === undefined || lineHeight === \"normal\") {\n // CSS \"normal\": use font ascent + descent (matches satori behaviour)\n return metrics ? metrics.ascent + metrics.descent : fontSize * 1.2;\n }\n if (typeof lineHeight === \"number\") {\n // Already resolved to px in compute.ts if > 5, else multiplier\n return lineHeight > 5 ? lineHeight : lineHeight * fontSize;\n }\n const parsed = parseFloat(String(lineHeight));\n return isNaN(parsed) ? fontSize * 1.2 : parsed;\n}\n\nfunction wrapText(\n text: string,\n maxWidth: number,\n fontSize: number,\n fontFamily: string,\n fontWeight: number | string,\n fontStyle: string,\n letterSpacing: number,\n wordBreak: string,\n ctx?: SKRSContext2D,\n measureFn?: (word: string, ls?: number) => number,\n): string[] {\n if (!text) return [\"\"];\n\n const mw =\n measureFn ??\n ((word: string) =>\n measureWord(\n word,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n letterSpacing,\n ));\n\n const breakOpps = findBreakOpportunities(text);\n const lines: string[] = [];\n let lineStart = 0;\n let lastBreak = 0;\n\n for (const opp of breakOpps) {\n const segment = text.slice(lineStart, opp.position);\n const segWidth = mw(segment);\n\n if (segWidth > maxWidth && lastBreak > lineStart) {\n // Line overflows — break at last opportunity\n const line = text.slice(lineStart, lastBreak).replace(/\\s+$/, \"\");\n lines.push(line);\n lineStart = lastBreak;\n } else if (segWidth > maxWidth && wordBreak === \"break-all\") {\n // Force break within word\n const broken = forceBreakWord(\n text,\n lineStart,\n opp.position,\n maxWidth,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n letterSpacing,\n measureFn,\n );\n lines.push(...broken.lines);\n lineStart = broken.endPos;\n }\n\n if (opp.required) {\n // Hard break (newline)\n const line = text.slice(lineStart, opp.position).replace(/\\s+$/, \"\");\n lines.push(line);\n lineStart = opp.position;\n }\n\n lastBreak = opp.position;\n }\n\n // Remaining text\n if (lineStart < text.length) {\n const remaining = text.slice(lineStart).replace(/\\s+$/, \"\");\n if (remaining) {\n const remWidth = mw(remaining);\n if (remWidth > maxWidth && wordBreak === \"break-all\") {\n const broken = forceBreakWord(\n text,\n lineStart,\n text.length,\n maxWidth,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n letterSpacing,\n measureFn,\n );\n lines.push(...broken.lines);\n } else {\n lines.push(remaining);\n }\n }\n }\n\n return lines.length > 0 ? lines : [\"\"];\n}\n\nfunction forceBreakWord(\n text: string,\n start: number,\n end: number,\n maxWidth: number,\n fontSize: number,\n fontFamily: string,\n fontWeight: number | string,\n fontStyle: string,\n ctx?: SKRSContext2D,\n letterSpacing: number = 0,\n measureFn?: (word: string, ls?: number) => number,\n): { lines: string[]; endPos: number } {\n const mw =\n measureFn ??\n ((word: string) =>\n measureWord(\n word,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n letterSpacing,\n ));\n const lines: string[] = [];\n let pos = start;\n\n while (pos < end) {\n let breakPos = pos + 1;\n while (breakPos < end) {\n const chunk = text.slice(pos, breakPos + 1);\n const w = mw(chunk);\n if (w > maxWidth) break;\n breakPos++;\n }\n\n const line = text.slice(pos, breakPos);\n if (line.trim()) lines.push(line);\n pos = breakPos;\n }\n\n return { lines, endPos: end };\n}\n\nfunction truncateWithEllipsis(\n text: string,\n maxWidth: number,\n fontSize: number,\n fontFamily: string,\n fontWeight: number | string,\n fontStyle: string,\n ctx?: SKRSContext2D,\n letterSpacing: number = 0,\n): string {\n const ellipsis = \"\\u2026\";\n const ellipsisWidth = measureWord(\n ellipsis,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n letterSpacing,\n );\n const availWidth = maxWidth - ellipsisWidth;\n\n for (let i = text.length - 1; i > 0; i--) {\n const truncated = text.slice(0, i);\n const w = measureWord(\n truncated,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n letterSpacing,\n );\n if (w <= availWidth) {\n return truncated + ellipsis;\n }\n }\n\n return ellipsis;\n}\n\n/**\n * Yoga-compatible measure function for text nodes.\n * Returns the dimensions needed for the text content.\n */\nexport function createTextMeasureFunc(\n text: string,\n style: ComputedStyle,\n ctx?: SKRSContext2D,\n emojiEnabled?: boolean,\n) {\n // Strip textOverflow during measurement so ellipsis truncation doesn't\n // shrink the reported width below the Yoga constraint. The draw phase\n // still uses the original style (with textOverflow) for rendering.\n const measureStyle = { ...style, textOverflow: \"clip\" as const };\n return (\n width: number,\n _widthMode: number,\n _height: number,\n _heightMode: number,\n ) => {\n const maxWidth = width > 0 ? width : Infinity;\n const result = layoutText(text, measureStyle, maxWidth, ctx, emojiEnabled);\n // When text wraps to multiple lines, return the constraint width (like CSS\n // block layout). This ensures the draw phase re-layout gets the same\n // maxWidth and produces identical line-breaking. Without this, the\n // measured content width (widest trimmed line) can be narrower than what\n // the wrapping algorithm needs (it checks untrimmed segments), causing the\n // draw phase to wrap differently.\n const wrapped = result.segments.length > 1;\n const reportedWidth = wrapped\n ? Math.min(maxWidth, width > 0 ? width : result.width)\n : result.width;\n return { width: Math.min(reportedWidth, maxWidth), height: result.height };\n };\n}\n","import type { SKRSContext2D } from \"@napi-rs/canvas\";\n\n/**\n * Apply overflow:hidden clipping to a canvas context.\n * Creates a rectangular clip path with optional border-radius.\n */\nexport function applyClip(\n ctx: SKRSContext2D,\n x: number,\n y: number,\n width: number,\n height: number,\n borderRadius?: {\n topLeft: number;\n topRight: number;\n bottomRight: number;\n bottomLeft: number;\n },\n): void {\n ctx.beginPath();\n\n if (borderRadius && hasRadius(borderRadius)) {\n const { topLeft, topRight, bottomRight, bottomLeft } = borderRadius;\n roundedRect(\n ctx,\n x,\n y,\n width,\n height,\n topLeft,\n topRight,\n bottomRight,\n bottomLeft,\n );\n } else {\n ctx.rect(x, y, width, height);\n }\n\n ctx.clip();\n}\n\n/**\n * Draw a rounded rectangle path on the context.\n */\nexport function roundedRect(\n ctx: SKRSContext2D,\n x: number,\n y: number,\n w: number,\n h: number,\n tl: number,\n tr: number,\n br: number,\n bl: number,\n): void {\n // Clamp radii to half the smallest dimension\n const maxR = Math.min(w, h) / 2;\n tl = Math.min(tl, maxR);\n tr = Math.min(tr, maxR);\n br = Math.min(br, maxR);\n bl = Math.min(bl, maxR);\n\n ctx.moveTo(x + tl, y);\n ctx.lineTo(x + w - tr, y);\n if (tr > 0) ctx.arcTo(x + w, y, x + w, y + tr, tr);\n ctx.lineTo(x + w, y + h - br);\n if (br > 0) ctx.arcTo(x + w, y + h, x + w - br, y + h, br);\n ctx.lineTo(x + bl, y + h);\n if (bl > 0) ctx.arcTo(x, y + h, x, y + h - bl, bl);\n ctx.lineTo(x, y + tl);\n if (tl > 0) ctx.arcTo(x, y, x + tl, y, tl);\n ctx.closePath();\n}\n\nfunction hasRadius(r: {\n topLeft: number;\n topRight: number;\n bottomRight: number;\n bottomLeft: number;\n}): boolean {\n return (\n r.topLeft > 0 || r.topRight > 0 || r.bottomRight > 0 || r.bottomLeft > 0\n );\n}\n","import type { SKRSContext2D } from \"@napi-rs/canvas\";\n\n/**\n * Parse and create a canvas gradient from a CSS gradient string.\n * Supports linear-gradient and radial-gradient.\n *\n * @returns A CanvasGradient or null if parsing fails\n */\nexport function createGradientFromCSS(\n ctx: SKRSContext2D,\n cssGradient: string,\n x: number,\n y: number,\n width: number,\n height: number,\n): CanvasGradient | null {\n const trimmed = cssGradient.trim();\n\n if (trimmed.startsWith(\"linear-gradient\")) {\n return parseLinearGradient(ctx, trimmed, x, y, width, height);\n }\n\n if (trimmed.startsWith(\"radial-gradient\")) {\n return parseRadialGradient(ctx, trimmed, x, y, width, height);\n }\n\n return null;\n}\n\nfunction parseLinearGradient(\n ctx: SKRSContext2D,\n css: string,\n x: number,\n y: number,\n width: number,\n height: number,\n): CanvasGradient | null {\n // Extract content between parentheses\n const match = css.match(/linear-gradient\\((.*)\\)/s);\n if (!match) return null;\n\n const content = match[1]!.trim();\n const parts = splitGradientArgs(content);\n\n let angle = 180; // default: to bottom\n let colorStartIdx = 0;\n\n // Parse direction\n const first = parts[0]?.trim();\n if (first) {\n if (first.startsWith(\"to \")) {\n angle = directionToAngle(first);\n colorStartIdx = 1;\n } else if (first.endsWith(\"deg\")) {\n angle = parseFloat(first);\n colorStartIdx = 1;\n } else if (first.endsWith(\"turn\")) {\n angle = parseFloat(first) * 360;\n colorStartIdx = 1;\n }\n }\n\n // Calculate gradient line endpoints\n const rad = ((angle - 90) * Math.PI) / 180;\n const cx = x + width / 2;\n const cy = y + height / 2;\n const halfDiag =\n Math.abs(width * Math.cos(rad)) / 2 + Math.abs(height * Math.sin(rad)) / 2;\n\n const x0 = cx - halfDiag * Math.cos(rad);\n const y0 = cy - halfDiag * Math.sin(rad);\n const x1 = cx + halfDiag * Math.cos(rad);\n const y1 = cy + halfDiag * Math.sin(rad);\n\n const gradient = ctx.createLinearGradient(x0, y0, x1, y1);\n\n // Parse color stops\n const stops = parts.slice(colorStartIdx);\n addColorStops(gradient, stops);\n\n return gradient;\n}\n\nfunction parseRadialGradient(\n ctx: SKRSContext2D,\n css: string,\n x: number,\n y: number,\n width: number,\n height: number,\n): CanvasGradient | null {\n const match = css.match(/radial-gradient\\((.*)\\)/s);\n if (!match) return null;\n\n const content = match[1]!.trim();\n const parts = splitGradientArgs(content);\n\n const cx = x + width / 2;\n const cy = y + height / 2;\n const radius = Math.max(width, height) / 2;\n\n const gradient = ctx.createRadialGradient(cx, cy, 0, cx, cy, radius);\n\n // Simple parsing: skip shape/size/position, just get color stops\n let colorStartIdx = 0;\n const first = parts[0]?.trim() ?? \"\";\n if (\n first.startsWith(\"circle\") ||\n first.startsWith(\"ellipse\") ||\n first.startsWith(\"closest\") ||\n first.startsWith(\"farthest\")\n ) {\n colorStartIdx = 1;\n }\n\n addColorStops(gradient, parts.slice(colorStartIdx));\n\n return gradient;\n}\n\nfunction addColorStops(gradient: CanvasGradient, stops: string[]): void {\n if (stops.length === 0) return;\n\n for (let i = 0; i < stops.length; i++) {\n const stop = stops[i]!.trim();\n const percentMatch = stop.match(/^(.+?)\\s+(\\d+(?:\\.\\d+)?%?)$/);\n\n if (percentMatch) {\n const color = percentMatch[1]!;\n const pos = percentMatch[2]!;\n const offset = pos.endsWith(\"%\")\n ? parseFloat(pos) / 100\n : parseFloat(pos);\n gradient.addColorStop(Math.max(0, Math.min(1, offset)), color);\n } else {\n // Auto-distribute\n const offset = stops.length === 1 ? 0.5 : i / (stops.length - 1);\n gradient.addColorStop(offset, stop);\n }\n }\n}\n\nfunction directionToAngle(dir: string): number {\n const map: Record<string, number> = {\n \"to top\": 0,\n \"to right\": 90,\n \"to bottom\": 180,\n \"to left\": 270,\n \"to top right\": 45,\n \"to top left\": 315,\n \"to bottom right\": 135,\n \"to bottom left\": 225,\n };\n return map[dir] ?? 180;\n}\n\nfunction splitGradientArgs(content: string): string[] {\n const parts: string[] = [];\n let current = \"\";\n let parenDepth = 0;\n\n for (const char of content) {\n if (char === \"(\") parenDepth++;\n if (char === \")\") parenDepth--;\n if (char === \",\" && parenDepth === 0) {\n parts.push(current);\n current = \"\";\n } else {\n current += char;\n }\n }\n if (current.trim()) parts.push(current);\n\n return parts;\n}\n","import { loadImage } from \"@napi-rs/canvas\";\nimport type { Image, SKRSContext2D } from \"@napi-rs/canvas\";\n\nimport type { ComputedStyle } from \"../style/compute.ts\";\nimport { computeContain, computeCover } from \"./object-fit.ts\";\n\n/**\n * Draw an image element onto the canvas.\n *\n * @param ctx - Canvas rendering context\n * @param src - Image source (URL, file path, or Buffer)\n * @param x - X position\n * @param y - Y position\n * @param width - Target width\n * @param height - Target height\n * @param style - Computed style (for objectFit)\n */\nexport async function drawImage(\n ctx: SKRSContext2D,\n src: string | Buffer,\n x: number,\n y: number,\n width: number,\n height: number,\n style?: ComputedStyle,\n preloadedImage?: Image,\n): Promise<void> {\n const image = preloadedImage ?? (await loadImage(src));\n const objectFit = style?.objectFit ?? \"fill\";\n\n if (objectFit === \"fill\") {\n ctx.drawImage(image, x, y, width, height);\n return;\n }\n\n const imgW = image.width;\n const imgH = image.height;\n\n if (objectFit === \"contain\") {\n const r = computeContain(imgW, imgH, x, y, width, height);\n ctx.drawImage(image, r.dx, r.dy, r.dw, r.dh);\n } else if (objectFit === \"cover\") {\n const r = computeCover(imgW, imgH, x, y, width, height);\n ctx.drawImage(image, r.sx, r.sy, r.sw, r.sh, r.dx, r.dy, r.dw, r.dh);\n } else if (objectFit === \"none\") {\n const dx = x + (width - imgW) / 2;\n const dy = y + (height - imgH) / 2;\n ctx.drawImage(image, dx, dy);\n } else if (objectFit === \"scale-down\") {\n if (imgW <= width && imgH <= height) {\n const dx = x + (width - imgW) / 2;\n const dy = y + (height - imgH) / 2;\n ctx.drawImage(image, dx, dy);\n } else {\n const r = computeContain(imgW, imgH, x, y, width, height);\n ctx.drawImage(image, r.dx, r.dy, r.dw, r.dh);\n }\n }\n}\n","/**\n * Shared cover/contain sizing logic used by both `<img>` objectFit\n * and `backgroundImage` + `backgroundSize`.\n */\n\nexport interface FitRect {\n sx: number;\n sy: number;\n sw: number;\n sh: number;\n dx: number;\n dy: number;\n dw: number;\n dh: number;\n}\n\n/**\n * Compute source and destination rectangles for \"cover\" sizing.\n * The image fills the box completely, cropping the excess.\n */\nexport function computeCover(\n imgW: number,\n imgH: number,\n boxX: number,\n boxY: number,\n boxW: number,\n boxH: number,\n): FitRect {\n const imgRatio = imgW / imgH;\n const boxRatio = boxW / boxH;\n\n let sx: number, sy: number, sw: number, sh: number;\n\n if (imgRatio > boxRatio) {\n sh = imgH;\n sw = imgH * boxRatio;\n sx = (imgW - sw) / 2;\n sy = 0;\n } else {\n sw = imgW;\n sh = imgW / boxRatio;\n sx = 0;\n sy = (imgH - sh) / 2;\n }\n\n return { sx, sy, sw, sh, dx: boxX, dy: boxY, dw: boxW, dh: boxH };\n}\n\n/**\n * Compute destination rectangle for \"contain\" sizing.\n * The image fits entirely within the box, centered, with no cropping.\n */\nexport function computeContain(\n imgW: number,\n imgH: number,\n boxX: number,\n boxY: number,\n boxW: number,\n boxH: number,\n): FitRect {\n const imgRatio = imgW / imgH;\n const boxRatio = boxW / boxH;\n\n let dw: number, dh: number;\n\n if (imgRatio > boxRatio) {\n dw = boxW;\n dh = boxW / imgRatio;\n } else {\n dh = boxH;\n dw = boxH * imgRatio;\n }\n\n const dx = boxX + (boxW - dw) / 2;\n const dy = boxY + (boxH - dh) / 2;\n\n return { sx: 0, sy: 0, sw: imgW, sh: imgH, dx, dy, dw, dh };\n}\n","import type { SKRSContext2D } from \"@napi-rs/canvas\";\n\nimport type { ComputedStyle } from \"../style/compute.ts\";\nimport { roundedRect } from \"./clip.ts\";\n\n/**\n * Draw the background, borders, and box-shadow for a rectangular element.\n */\nexport function drawRect(\n ctx: SKRSContext2D,\n x: number,\n y: number,\n width: number,\n height: number,\n style: ComputedStyle,\n): void {\n const borderRadius = getBorderRadius(style);\n const hasRoundedCorners =\n borderRadius.topLeft > 0 ||\n borderRadius.topRight > 0 ||\n borderRadius.bottomRight > 0 ||\n borderRadius.bottomLeft > 0;\n\n // Box shadow (drawn before background)\n if (style.boxShadow) {\n drawBoxShadow(ctx, x, y, width, height, style.boxShadow, borderRadius);\n }\n\n // Background\n if (style.backgroundColor) {\n ctx.fillStyle = style.backgroundColor;\n\n if (hasRoundedCorners) {\n ctx.beginPath();\n roundedRect(\n ctx,\n x,\n y,\n width,\n height,\n borderRadius.topLeft,\n borderRadius.topRight,\n borderRadius.bottomRight,\n borderRadius.bottomLeft,\n );\n ctx.fill();\n } else {\n ctx.fillRect(x, y, width, height);\n }\n }\n\n // Borders\n drawBorders(ctx, x, y, width, height, style, borderRadius);\n}\n\nfunction getBorderRadius(style: ComputedStyle) {\n return {\n topLeft: toNumber(style.borderTopLeftRadius),\n topRight: toNumber(style.borderTopRightRadius),\n bottomRight: toNumber(style.borderBottomRightRadius),\n bottomLeft: toNumber(style.borderBottomLeftRadius),\n };\n}\n\nexport function getBorderRadiusFromStyle(style: ComputedStyle) {\n return getBorderRadius(style);\n}\n\nfunction drawBorders(\n ctx: SKRSContext2D,\n x: number,\n y: number,\n width: number,\n height: number,\n style: ComputedStyle,\n borderRadius: ReturnType<typeof getBorderRadius>,\n): void {\n const hasRoundedCorners =\n borderRadius.topLeft > 0 ||\n borderRadius.topRight > 0 ||\n borderRadius.bottomRight > 0 ||\n borderRadius.bottomLeft > 0;\n\n // If all borders are the same, draw as a single stroke\n const tw = toNumber(style.borderTopWidth);\n const rw = toNumber(style.borderRightWidth);\n const bw = toNumber(style.borderBottomWidth);\n const lw = toNumber(style.borderLeftWidth);\n\n if (tw === 0 && rw === 0 && bw === 0 && lw === 0) return;\n\n const allSameWidth = tw === rw && rw === bw && bw === lw && tw > 0;\n const tc = style.borderTopColor ?? \"black\";\n const rc = style.borderRightColor ?? \"black\";\n const bc = style.borderBottomColor ?? \"black\";\n const lc = style.borderLeftColor ?? \"black\";\n const allSameColor = tc === rc && rc === bc && bc === lc;\n\n if (allSameWidth && allSameColor) {\n ctx.strokeStyle = tc;\n ctx.lineWidth = tw;\n\n if (hasRoundedCorners) {\n ctx.beginPath();\n const half = tw / 2;\n roundedRect(\n ctx,\n x + half,\n y + half,\n width - tw,\n height - tw,\n Math.max(0, borderRadius.topLeft - half),\n Math.max(0, borderRadius.topRight - half),\n Math.max(0, borderRadius.bottomRight - half),\n Math.max(0, borderRadius.bottomLeft - half),\n );\n ctx.stroke();\n } else {\n ctx.strokeRect(x + tw / 2, y + tw / 2, width - tw, height - tw);\n }\n return;\n }\n\n // Draw individual borders\n if (tw > 0) {\n ctx.strokeStyle = tc;\n ctx.lineWidth = tw;\n ctx.beginPath();\n ctx.moveTo(x, y + tw / 2);\n ctx.lineTo(x + width, y + tw / 2);\n ctx.stroke();\n }\n if (rw > 0) {\n ctx.strokeStyle = rc;\n ctx.lineWidth = rw;\n ctx.beginPath();\n ctx.moveTo(x + width - rw / 2, y);\n ctx.lineTo(x + width - rw / 2, y + height);\n ctx.stroke();\n }\n if (bw > 0) {\n ctx.strokeStyle = bc;\n ctx.lineWidth = bw;\n ctx.beginPath();\n ctx.moveTo(x, y + height - bw / 2);\n ctx.lineTo(x + width, y + height - bw / 2);\n ctx.stroke();\n }\n if (lw > 0) {\n ctx.strokeStyle = lc;\n ctx.lineWidth = lw;\n ctx.beginPath();\n ctx.moveTo(x + lw / 2, y);\n ctx.lineTo(x + lw / 2, y + height);\n ctx.stroke();\n }\n}\n\nfunction drawBoxShadow(\n ctx: SKRSContext2D,\n x: number,\n y: number,\n width: number,\n height: number,\n boxShadow: string,\n borderRadius: ReturnType<typeof getBorderRadius>,\n): void {\n // Parse simple box-shadow: offsetX offsetY blur spread? color\n const parts = boxShadow.match(\n /(-?\\d+(?:\\.\\d+)?)\\s*(?:px)?\\s+(-?\\d+(?:\\.\\d+)?)\\s*(?:px)?\\s+(-?\\d+(?:\\.\\d+)?)\\s*(?:px)?(?:\\s+(-?\\d+(?:\\.\\d+)?)\\s*(?:px)?)?\\s+(.*)/,\n );\n if (!parts) return;\n\n const offsetX = parseFloat(parts[1]!);\n const offsetY = parseFloat(parts[2]!);\n const blur = parseFloat(parts[3]!);\n const color = parts[5]!.trim();\n\n const radii = [\n borderRadius.topLeft,\n borderRadius.topRight,\n borderRadius.bottomRight,\n borderRadius.bottomLeft,\n ];\n\n // Clip to area OUTSIDE the element so shadow renders but inner fill is hidden\n const margin = blur * 2 + Math.abs(offsetX) + Math.abs(offsetY);\n ctx.save();\n ctx.beginPath();\n ctx.rect(x - margin, y - margin, width + margin * 2, height + margin * 2);\n ctx.roundRect(x, y, width, height, radii);\n ctx.clip(\"evenodd\");\n\n // Use CSS filter blur (sigma = blur/2) instead of the canvas shadow API\n // because it matches SVG feGaussianBlur (used by satori) much more closely.\n ctx.filter = `blur(${blur / 2}px)`;\n ctx.translate(offsetX, offsetY);\n ctx.fillStyle = color;\n ctx.beginPath();\n ctx.roundRect(x, y, width, height, radii);\n ctx.fill();\n ctx.restore();\n}\n\nfunction toNumber(v: unknown): number {\n if (typeof v === \"number\") return v;\n if (v === undefined || v === null) return 0;\n const n = parseFloat(String(v));\n return isNaN(n) ? 0 : n;\n}\n","import { Path2D } from \"@napi-rs/canvas\";\nimport type { SKRSContext2D } from \"@napi-rs/canvas\";\n\nimport type { LayoutNode } from \"../layout.ts\";\n\ntype SvgChild = {\n type: string;\n props: Record<string, unknown>;\n children?: SvgChild | SvgChild[];\n};\n\n/**\n * Merge SVG presentation properties from `props.style` into the props object.\n * Style values win over direct props, matching browser CSS specificity rules.\n */\nfunction mergeStyleIntoProps(\n props: Record<string, unknown>,\n): Record<string, unknown> {\n const style = props.style as Record<string, unknown> | undefined;\n if (!style) return props;\n return { ...props, ...style };\n}\n\n/**\n * Draw an `<svg>` container and its SVG children (path, circle, rect, etc.).\n *\n * Parses the `viewBox` prop to compute scale factors, then recurses into\n * the React children stored in `node.props.children`.\n */\nexport function drawSvgContainer(\n ctx: SKRSContext2D,\n node: LayoutNode,\n x: number,\n y: number,\n width: number,\n height: number,\n): void {\n ctx.save();\n ctx.translate(x, y);\n\n // Parse viewBox for coordinate mapping\n const viewBox = node.props.viewBox as string | undefined;\n if (viewBox) {\n const parts = viewBox.split(/[\\s,]+/).map(Number);\n if (parts.length === 4) {\n const [vbX, vbY, vbW, vbH] = parts as [number, number, number, number];\n const scaleX = width / vbW;\n const scaleY = height / vbH;\n ctx.scale(scaleX, scaleY);\n ctx.translate(-vbX, -vbY);\n }\n }\n\n // Inherited fill from the <svg> element (SVG fill is inheritable)\n const merged = mergeStyleIntoProps(node.props);\n const inheritedFill = (merged.fill as string | undefined) ?? \"black\";\n\n // Traverse React children\n const children = node.props.children;\n if (children != null) {\n const childArray = Array.isArray(children) ? children : [children];\n for (const child of childArray) {\n if (child != null && typeof child === \"object\") {\n drawSvgChild(ctx, child as SvgChild, inheritedFill);\n }\n }\n }\n\n ctx.restore();\n}\n\nfunction drawSvgChild(\n ctx: SKRSContext2D,\n child: SvgChild,\n inheritedFill: string,\n): void {\n const { type } = child;\n const props = mergeStyleIntoProps(child.props);\n\n switch (type) {\n case \"path\":\n drawPath(ctx, props, inheritedFill);\n break;\n case \"circle\":\n drawCircle(ctx, props, inheritedFill);\n break;\n case \"rect\":\n drawSvgRect(ctx, props, inheritedFill);\n break;\n case \"line\":\n drawLine(ctx, props);\n break;\n case \"ellipse\":\n drawEllipse(ctx, props, inheritedFill);\n break;\n case \"polygon\":\n drawPolygon(ctx, props, inheritedFill);\n break;\n case \"polyline\":\n drawPolyline(ctx, props, inheritedFill);\n break;\n case \"g\":\n drawGroup(ctx, child, inheritedFill);\n break;\n }\n}\n\nfunction drawPath(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n inheritedFill: string,\n): void {\n const d = props.d as string | undefined;\n if (!d) return;\n\n const path = new Path2D(d);\n applyFillAndStroke(ctx, props, path, inheritedFill);\n}\n\nfunction drawCircle(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n inheritedFill: string,\n): void {\n const cx = Number(props.cx ?? 0);\n const cy = Number(props.cy ?? 0);\n const r = Number(props.r ?? 0);\n if (r <= 0) return;\n\n const path = new Path2D();\n path.arc(cx, cy, r, 0, Math.PI * 2);\n applyFillAndStroke(ctx, props, path, inheritedFill);\n}\n\nfunction drawSvgRect(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n inheritedFill: string,\n): void {\n const rx = Number(props.x ?? 0);\n const ry = Number(props.y ?? 0);\n const w = Number(props.width ?? 0);\n const h = Number(props.height ?? 0);\n if (w <= 0 || h <= 0) return;\n\n const path = new Path2D();\n path.rect(rx, ry, w, h);\n applyFillAndStroke(ctx, props, path, inheritedFill);\n}\n\nfunction drawLine(ctx: SKRSContext2D, props: Record<string, unknown>): void {\n const x1 = Number(props.x1 ?? 0);\n const y1 = Number(props.y1 ?? 0);\n const x2 = Number(props.x2 ?? 0);\n const y2 = Number(props.y2 ?? 0);\n\n const path = new Path2D();\n path.moveTo(x1, y1);\n path.lineTo(x2, y2);\n // Lines are stroke-only\n applyStroke(ctx, props, path);\n}\n\nfunction drawEllipse(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n inheritedFill: string,\n): void {\n const cx = Number(props.cx ?? 0);\n const cy = Number(props.cy ?? 0);\n const rx = Number(props.rx ?? 0);\n const ry = Number(props.ry ?? 0);\n if (rx <= 0 || ry <= 0) return;\n\n const path = new Path2D();\n path.ellipse(cx, cy, rx, ry, 0, 0, Math.PI * 2);\n applyFillAndStroke(ctx, props, path, inheritedFill);\n}\n\nfunction drawPolygon(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n inheritedFill: string,\n): void {\n const points = parsePoints(props.points as string | undefined);\n if (points.length < 2) return;\n\n const path = new Path2D();\n path.moveTo(points[0]![0], points[0]![1]);\n for (let i = 1; i < points.length; i++) {\n path.lineTo(points[i]![0], points[i]![1]);\n }\n path.closePath();\n applyFillAndStroke(ctx, props, path, inheritedFill);\n}\n\nfunction drawPolyline(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n inheritedFill: string,\n): void {\n const points = parsePoints(props.points as string | undefined);\n if (points.length < 2) return;\n\n const path = new Path2D();\n path.moveTo(points[0]![0], points[0]![1]);\n for (let i = 1; i < points.length; i++) {\n path.lineTo(points[i]![0], points[i]![1]);\n }\n applyFillAndStroke(ctx, props, path, inheritedFill);\n}\n\nfunction drawGroup(\n ctx: SKRSContext2D,\n node: SvgChild,\n inheritedFill: string,\n): void {\n const children =\n node.children ?? (node.props.children as SvgChild | SvgChild[] | undefined);\n if (children == null) return;\n // Group can override inherited fill\n const merged = mergeStyleIntoProps(node.props);\n const groupFill = (merged.fill as string | undefined) ?? inheritedFill;\n const childArray = Array.isArray(children) ? children : [children];\n for (const child of childArray) {\n if (child != null && typeof child === \"object\") {\n drawSvgChild(ctx, child, groupFill);\n }\n }\n}\n\nfunction parsePoints(value: string | undefined): [number, number][] {\n if (!value) return [];\n const nums = value\n .trim()\n .split(/[\\s,]+/)\n .map(Number);\n const result: [number, number][] = [];\n for (let i = 0; i + 1 < nums.length; i += 2) {\n result.push([nums[i]!, nums[i + 1]!]);\n }\n return result;\n}\n\nfunction applyFillAndStroke(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n path: Path2D,\n inheritedFill: string,\n): void {\n // Use element's own fill if set, otherwise inherit from parent\n const fill = (props.fill as string | undefined) ?? inheritedFill;\n if (fill !== \"none\") {\n ctx.fillStyle = fill;\n ctx.fill(path);\n }\n\n applyStroke(ctx, props, path);\n}\n\nfunction applyStroke(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n path: Path2D,\n): void {\n const stroke = props.stroke as string | undefined;\n if (!stroke || stroke === \"none\") return;\n\n ctx.strokeStyle = stroke;\n ctx.lineWidth = Number(props.strokeWidth ?? props[\"stroke-width\"] ?? 1);\n ctx.lineCap =\n ((props.strokeLinecap ?? props[\"stroke-linecap\"]) as CanvasLineCap) ??\n \"butt\";\n ctx.lineJoin =\n ((props.strokeLinejoin ?? props[\"stroke-linejoin\"]) as CanvasLineJoin) ??\n \"miter\";\n ctx.stroke(path);\n}\n","import { loadImage } from \"@napi-rs/canvas\";\nimport type { SKRSContext2D, Image } from \"@napi-rs/canvas\";\n\nimport type { EmojiStyle } from \"../emoji.ts\";\nimport { getEmojiCode, loadEmoji } from \"../emoji.ts\";\nimport type { TextSegment } from \"../text/index.ts\";\nimport { splitTextIntoRuns } from \"../text/emoji-split.ts\";\nimport { setFont } from \"../text/measure.ts\";\n\nconst emojiImageCache = new Map<string, Promise<Image | null>>();\n\nfunction loadEmojiImage(\n style: EmojiStyle,\n char: string,\n): Promise<Image | null> {\n const code = getEmojiCode(char);\n const key = style + \":\" + code;\n let cached = emojiImageCache.get(key);\n if (!cached) {\n cached = loadEmoji(style, code)\n .then((svgText) => {\n if (!svgText || !svgText.includes(\"<svg\")) return null;\n const dataUri =\n \"data:image/svg+xml;base64,\" +\n Buffer.from(svgText).toString(\"base64\");\n return loadImage(dataUri);\n })\n .catch(() => null);\n emojiImageCache.set(key, cached);\n }\n return cached;\n}\n\n/**\n * Draw text segments onto the canvas context.\n *\n * @param ctx - Canvas 2D rendering context\n * @param segments - Positioned text segments from the text layout engine\n * @param offsetX - X offset for the text block\n * @param offsetY - Y offset for the text block\n * @param textShadow - Optional text-shadow CSS value\n * @param emojiStyle - Optional emoji style for rendering emoji as images\n */\nexport async function drawText(\n ctx: SKRSContext2D,\n segments: TextSegment[],\n offsetX: number,\n offsetY: number,\n textShadow?: string,\n emojiStyle?: EmojiStyle,\n): Promise<void> {\n for (const seg of segments) {\n if (!seg.text) continue;\n\n setFont(ctx, seg.fontSize, seg.fontFamily, seg.fontWeight, seg.fontStyle);\n ctx.fillStyle = seg.color;\n\n const x = offsetX + seg.x;\n const y = offsetY + seg.y;\n\n if (emojiStyle) {\n await drawSegmentWithEmoji(ctx, seg, x, y, textShadow, emojiStyle);\n } else if (seg.letterSpacing && seg.letterSpacing !== 0) {\n drawTextWithLetterSpacing(ctx, seg.text, x, y, seg.letterSpacing);\n } else {\n if (textShadow) {\n drawTextShadow(ctx, seg.text, x, y, textShadow);\n }\n ctx.fillText(seg.text, x, y);\n }\n\n // Text decoration\n if (seg.textDecoration) {\n drawTextDecoration(ctx, seg, offsetX, offsetY);\n }\n }\n}\n\nasync function drawSegmentWithEmoji(\n ctx: SKRSContext2D,\n seg: TextSegment,\n x: number,\n y: number,\n textShadow: string | undefined,\n emojiStyle: EmojiStyle,\n): Promise<void> {\n const runs = splitTextIntoRuns(\n seg.text,\n (text) => {\n setFont(ctx, seg.fontSize, seg.fontFamily, seg.fontWeight, seg.fontStyle);\n return ctx.measureText(text).width;\n },\n seg.fontSize,\n );\n\n for (const run of runs) {\n if (run.kind === \"text\") {\n if (textShadow) {\n drawTextShadow(ctx, run.text, x + run.x, y, textShadow);\n }\n ctx.fillText(run.text, x + run.x, y);\n } else {\n const img = await loadEmojiImage(emojiStyle, run.char);\n if (img) {\n const emojiSize = seg.fontSize;\n // Position emoji so it aligns vertically with text:\n // y is the baseline, ascent goes up from baseline\n const emojiY = y - seg.ascent + (seg.height - seg.fontSize) / 2;\n ctx.drawImage(img, x + run.x, emojiY, emojiSize, emojiSize);\n } else {\n // Emoji image unavailable — fall back to text rendering\n ctx.fillText(run.char, x + run.x, y);\n }\n }\n }\n}\n\nfunction drawTextWithLetterSpacing(\n ctx: SKRSContext2D,\n text: string,\n x: number,\n y: number,\n letterSpacing: number,\n): void {\n let currentX = x;\n for (const char of text) {\n ctx.fillText(char, currentX, y);\n const metrics = ctx.measureText(char);\n currentX += metrics.width + letterSpacing;\n }\n}\n\nfunction drawTextShadow(\n ctx: SKRSContext2D,\n text: string,\n x: number,\n y: number,\n shadow: string,\n): void {\n const parts = shadow.match(\n /(-?\\d+(?:\\.\\d+)?)\\s*px?\\s+(-?\\d+(?:\\.\\d+)?)\\s*px?\\s+(-?\\d+(?:\\.\\d+)?)\\s*px?\\s+(.*)/,\n );\n if (!parts) return;\n\n ctx.save();\n ctx.shadowOffsetX = parseFloat(parts[1]!);\n ctx.shadowOffsetY = parseFloat(parts[2]!);\n ctx.shadowBlur = parseFloat(parts[3]!);\n ctx.shadowColor = parts[4]!.trim();\n ctx.fillText(text, x, y);\n ctx.restore();\n}\n\nfunction drawTextDecoration(\n ctx: SKRSContext2D,\n seg: TextSegment,\n offsetX: number,\n offsetY: number,\n): void {\n const decoration = seg.textDecoration;\n if (!decoration || decoration === \"none\") return;\n\n ctx.strokeStyle = seg.color;\n ctx.lineWidth = Math.max(1, seg.fontSize * 0.1);\n\n const x = offsetX + seg.x;\n const baseY = offsetY + seg.y;\n\n if (decoration.includes(\"underline\")) {\n const y = baseY + seg.ascent * 0.1;\n ctx.beginPath();\n ctx.moveTo(x, y);\n ctx.lineTo(x + seg.width, y);\n ctx.stroke();\n }\n\n if (decoration.includes(\"line-through\")) {\n const y = baseY - seg.fontSize * 0.3;\n ctx.beginPath();\n ctx.moveTo(x, y);\n ctx.lineTo(x + seg.width, y);\n ctx.stroke();\n }\n\n if (decoration.includes(\"overline\")) {\n const y = baseY - seg.fontSize * 0.85;\n ctx.beginPath();\n ctx.moveTo(x, y);\n ctx.lineTo(x + seg.width, y);\n ctx.stroke();\n }\n}\n","// This file contains code adapted from Satori (https://github.com/vercel/satori)\n// Licensed under the Mozilla Public License 2.0 (MPL-2.0)\n// See NOTICE.md in the package root for details.\n\n/**\n * Emoji style options for rendering\n */\nexport type EmojiStyle =\n | \"twemoji\"\n | \"openmoji\"\n | \"blobmoji\"\n | \"noto\"\n | \"fluent\"\n | \"fluentFlat\";\n\nexport const emojiApis: Record<\n EmojiStyle,\n string | ((code: string) => string)\n> = {\n twemoji: (code: string) =>\n `https://cdnjs.cloudflare.com/ajax/libs/twemoji/16.0.1/svg/${code.toLowerCase()}.svg`,\n openmoji: \"https://cdn.jsdelivr.net/npm/@svgmoji/openmoji@2.0.0/svg/\",\n blobmoji: \"https://cdn.jsdelivr.net/npm/@svgmoji/blob@2.0.0/svg/\",\n noto: \"https://cdn.jsdelivr.net/gh/svgmoji/svgmoji/packages/svgmoji__noto/svg/\",\n fluent: (code: string) =>\n `https://cdn.jsdelivr.net/gh/shuding/fluentui-emoji-unicode/assets/${code.toLowerCase()}_color.svg`,\n fluentFlat: (code: string) =>\n `https://cdn.jsdelivr.net/gh/shuding/fluentui-emoji-unicode/assets/${code.toLowerCase()}_flat.svg`,\n};\n\nconst U200D = String.fromCharCode(8205);\nconst UFE0Fg = /\\uFE0F/g;\n\nexport function getEmojiCode(char: string): string {\n return toCodePoint(char.indexOf(U200D) < 0 ? char.replace(UFE0Fg, \"\") : char);\n}\n\nexport function toCodePoint(unicodeSurrogates: string): string {\n const r: string[] = [];\n let c = 0,\n p = 0,\n i = 0;\n\n while (i < unicodeSurrogates.length) {\n c = unicodeSurrogates.charCodeAt(i++);\n if (p) {\n r.push((65536 + ((p - 55296) << 10) + (c - 56320)).toString(16));\n p = 0;\n } else if (55296 <= c && c <= 56319) {\n p = c;\n } else {\n r.push(c.toString(16));\n }\n }\n return r.join(\"-\");\n}\n\nconst emojiCache: Record<string, Promise<string>> = {};\n\nexport async function loadEmoji(\n type: EmojiStyle,\n code: string,\n): Promise<string> {\n const key = type + \":\" + code;\n if (key in emojiCache) return emojiCache[key];\n\n const api = emojiApis[type];\n if (typeof api === \"function\") {\n return (emojiCache[key] = fetch(api(code)).then((r) => r.text()));\n }\n return (emojiCache[key] = fetch(`${api}${code.toUpperCase()}.svg`).then((r) =>\n r.text(),\n ));\n}\n","import { isEmoji } from \"../language.ts\";\n\nexport type TextRun =\n | { kind: \"text\"; text: string; x: number; width: number }\n | { kind: \"emoji\"; char: string; x: number; width: number };\n\n/**\n * Split a text string into runs of plain text and individual emoji characters.\n * Uses Intl.Segmenter for correct grapheme cluster handling (multi-codepoint emoji).\n */\nexport function splitTextIntoRuns(\n text: string,\n measureText: (text: string) => number,\n emojiSize: number,\n): TextRun[] {\n const runs: TextRun[] = [];\n const segmenter = new Intl.Segmenter(undefined, { granularity: \"grapheme\" });\n let currentText = \"\";\n let currentX = 0;\n let textStartX = 0;\n\n for (const { segment } of segmenter.segment(text)) {\n if (isEmojiGrapheme(segment)) {\n // Flush accumulated text\n if (currentText) {\n const textWidth = measureText(currentText);\n runs.push({\n kind: \"text\",\n text: currentText,\n x: textStartX,\n width: textWidth,\n });\n currentX = textStartX + textWidth;\n currentText = \"\";\n }\n runs.push({\n kind: \"emoji\",\n char: segment,\n x: currentX,\n width: emojiSize,\n });\n currentX += emojiSize;\n textStartX = currentX;\n } else {\n if (!currentText) textStartX = currentX;\n currentText += segment;\n }\n }\n\n // Flush remaining text\n if (currentText) {\n const textWidth = measureText(currentText);\n runs.push({\n kind: \"text\",\n text: currentText,\n x: textStartX,\n width: textWidth,\n });\n }\n\n return runs;\n}\n\n/**\n * Check if a grapheme cluster is an emoji.\n * Checks the first code point of the grapheme.\n */\nfunction isEmojiGrapheme(grapheme: string): boolean {\n for (const char of grapheme) {\n if (isEmoji(char)) return true;\n }\n return false;\n}\n","import { GlobalFonts } from \"@napi-rs/canvas\";\n\nimport type { FontData } from \"../types.ts\";\n\nconst registeredFonts = new Set<string>();\n\n/**\n * Reset internal font state (test-only).\n */\nexport function _resetForTest(): void {\n registeredFonts.clear();\n}\n\n/**\n * Register a font from a FontData buffer.\n * Registration is idempotent — re-registering the same font name is a no-op.\n *\n * @param font - Font data to register\n */\nexport function registerFont(font: FontData): void {\n const key = `${font.name}:${font.weight}:${font.style}`;\n if (registeredFonts.has(key)) return;\n\n const buffer = Buffer.isBuffer(font.data)\n ? font.data\n : Buffer.from(font.data);\n\n GlobalFonts.register(buffer, font.name);\n\n registeredFonts.add(key);\n}\n\n/**\n * Register a font from a file path.\n *\n * @param path - Path to the font file\n * @param nameAlias - Optional font family name override\n */\nexport function registerFontFromPath(path: string, nameAlias?: string): void {\n GlobalFonts.registerFromPath(path, nameAlias ?? \"\");\n}\n\n/**\n * Get the list of registered font family names.\n *\n * @returns Array of font family names\n */\nexport function registeredFamilies(): string[] {\n return GlobalFonts.families.map((f: { family: string }) => f.family);\n}\n\n/**\n * Ensure all fonts from the given array are registered.\n * Called internally by `renderReactElement()`.\n */\nexport function ensureFontsRegistered(fonts: FontData[]): void {\n for (const font of fonts) {\n registerFont(font);\n }\n}\n","// This file contains code adapted from Satori (https://github.com/vercel/satori)\n// Licensed under the Mozilla Public License 2.0 (MPL-2.0)\n// See NOTICE.md in the package root for details.\n\nimport type { SKRSContext2D } from \"@napi-rs/canvas\";\nimport { loadImage } from \"@napi-rs/canvas\";\nimport type { ReactElement, ReactNode } from \"react\";\n\nimport { expandStyle } from \"./style/expand.ts\";\nimport { resolveStyle, resolveUnits, DEFAULT_STYLE } from \"./style/compute.ts\";\nimport type { ComputedStyle } from \"./style/compute.ts\";\nimport { applyStylesToYoga } from \"./style/properties.ts\";\nimport { createTextMeasureFunc } from \"./text/index.ts\";\nimport { createYogaNode, freeYogaNode } from \"./yoga.ts\";\nimport type { YogaNode } from \"./yoga.ts\";\n\n/**\n * A node in the computed layout tree, ready for drawing.\n */\nexport type LayoutNode = {\n type: string;\n style: ComputedStyle;\n children: LayoutNode[];\n textContent?: string;\n props: Record<string, unknown>;\n x: number;\n y: number;\n width: number;\n height: number;\n};\n\ntype ElementChild = string | number | ReactElement | null | undefined | boolean;\n\n/**\n * Build a layout tree from a React element tree.\n * Creates Yoga nodes, calculates layout, and returns the positioned tree.\n *\n * @param element - React element tree to lay out\n * @param containerWidth - Width of the container (from canvas)\n * @param containerHeight - Height of the container (from canvas)\n * @param ctx - Canvas context for text measurement\n * @returns Root layout node with computed positions and dimensions\n */\nexport async function buildLayoutTree(\n element: ReactNode,\n containerWidth: number,\n containerHeight: number,\n ctx?: SKRSContext2D,\n emojiEnabled?: boolean,\n): Promise<LayoutNode> {\n const rootYogaNode = createYogaNode();\n\n // Build the tree\n const rootNode = await buildNode(\n element,\n DEFAULT_STYLE,\n rootYogaNode,\n containerWidth,\n containerHeight,\n ctx,\n emojiEnabled,\n );\n\n // Set root dimensions\n rootYogaNode.setWidth(containerWidth);\n rootYogaNode.setHeight(containerHeight);\n\n // Calculate layout\n rootYogaNode.calculateLayout(containerWidth, containerHeight);\n\n // Extract computed positions\n const layoutTree = extractLayout(rootNode, rootYogaNode);\n\n // Free Yoga nodes\n freeYogaNode(rootYogaNode);\n\n return layoutTree;\n}\n\nasync function buildNode(\n element: ReactNode,\n parentStyle: ComputedStyle,\n yogaNode: YogaNode,\n viewportWidth: number,\n viewportHeight: number,\n ctx?: SKRSContext2D,\n emojiEnabled?: boolean,\n): Promise<IntermediateNode> {\n // Handle null/undefined/boolean\n if (\n element === null ||\n element === undefined ||\n typeof element === \"boolean\"\n ) {\n return {\n type: \"empty\",\n style: parentStyle,\n children: [],\n props: {},\n yogaNode,\n };\n }\n\n // Handle text/number primitives\n if (typeof element === \"string\" || typeof element === \"number\") {\n const text = String(element);\n const style = resolveStyle(undefined, parentStyle);\n\n // Set up text measurement\n const measureFunc = createTextMeasureFunc(text, style, ctx, emojiEnabled);\n yogaNode.setMeasureFunc(measureFunc);\n\n return {\n type: \"text\",\n style,\n children: [],\n textContent: text,\n props: {},\n yogaNode,\n };\n }\n\n // Handle arrays (fragments)\n if (Array.isArray(element)) {\n const style = resolveStyle(undefined, parentStyle);\n const children: IntermediateNode[] = [];\n\n for (let i = 0; i < element.length; i++) {\n const child = element[i] as ElementChild;\n if (child === null || child === undefined || typeof child === \"boolean\")\n continue;\n\n const childYogaNode = createYogaNode();\n yogaNode.insertChild(childYogaNode, children.length);\n children.push(\n await buildNode(\n child,\n style,\n childYogaNode,\n viewportWidth,\n viewportHeight,\n ctx,\n emojiEnabled,\n ),\n );\n }\n\n return {\n type: \"div\",\n style,\n children,\n props: {},\n yogaNode,\n };\n }\n\n // Handle React elements\n const el = element as ReactElement<Record<string, unknown>>;\n const type = el.type;\n\n // Expand function/class components\n if (typeof type === \"function\") {\n const rendered = (type as (props: Record<string, unknown>) => ReactNode)(\n el.props ?? {},\n );\n return await buildNode(\n rendered,\n parentStyle,\n yogaNode,\n viewportWidth,\n viewportHeight,\n ctx,\n emojiEnabled,\n );\n }\n\n const props = (el.props ?? {}) as Record<string, unknown>;\n const rawStyle = (props.style ?? {}) as Record<string, unknown>;\n const expanded = expandStyle(rawStyle);\n const style = resolveStyle(expanded, parentStyle);\n resolveUnits(style, viewportWidth, viewportHeight);\n\n const tagName = String(type);\n\n // For <svg> elements, merge width/height props into style when not set via CSS\n if (tagName === \"svg\") {\n if (props.width != null && style.width === undefined)\n style.width = Number(props.width);\n if (props.height != null && style.height === undefined)\n style.height = Number(props.height);\n\n // Derive missing dimension from viewBox aspect ratio\n const viewBox = props.viewBox as string | undefined;\n if (viewBox) {\n const parts = viewBox.split(/[\\s,]+/).map(Number);\n if (parts.length === 4) {\n const [, , vbW, vbH] = parts as [number, number, number, number];\n if (vbW > 0 && vbH > 0) {\n const w = typeof style.width === \"number\" ? style.width : undefined;\n const h = typeof style.height === \"number\" ? style.height : undefined;\n if (w !== undefined && h === undefined) {\n style.height = w * (vbH / vbW);\n } else if (h !== undefined && w === undefined) {\n style.width = h * (vbW / vbH);\n } else if (w === undefined && h === undefined) {\n style.width = vbW;\n style.height = vbH;\n }\n }\n }\n }\n }\n\n // For <img> elements, derive missing dimensions from intrinsic aspect ratio\n if (tagName === \"img\") {\n // Map HTML width/height attributes to style (like <svg>)\n if (props.width != null && style.width === undefined)\n style.width = Number(props.width);\n if (props.height != null && style.height === undefined)\n style.height = Number(props.height);\n\n const src = props.src as string | Buffer | undefined;\n if (src) {\n try {\n const image = await loadImage(src);\n const naturalW = image.width;\n const naturalH = image.height;\n\n const w = typeof style.width === \"number\" ? style.width : undefined;\n const h = typeof style.height === \"number\" ? style.height : undefined;\n\n if (w !== undefined && h === undefined && naturalW > 0) {\n style.height = w * (naturalH / naturalW);\n } else if (h !== undefined && w === undefined && naturalH > 0) {\n style.width = h * (naturalW / naturalH);\n }\n\n // Cache loaded image for reuse during drawing\n props.__loadedImage = image;\n } catch {\n // Silent fail — image will render at whatever size Yoga computes\n }\n }\n }\n\n // Apply styles to Yoga node\n applyStylesToYoga(yogaNode, style);\n\n // SVG containers: children use SVG coordinate space, not flex layout.\n // Skip Yoga child nodes and keep React children in props for the SVG drawer.\n if (tagName === \"svg\") {\n return {\n type: tagName,\n style,\n children: [],\n props,\n yogaNode,\n };\n }\n\n // Collect text content from direct string children\n const textContent = extractTextContent(props.children);\n\n // If this node has only text content, create a child text node.\n // Using a child node (instead of setMeasureFunc on this node directly)\n // ensures Yoga's baseline calculation accounts for this node's padding/border\n // when a parent uses alignItems: \"baseline\".\n if (textContent !== undefined && !hasElementChildren(props.children)) {\n const childStyle = resolveStyle(undefined, style);\n const childYogaNode = createYogaNode();\n const measureFunc = createTextMeasureFunc(\n textContent,\n childStyle,\n ctx,\n emojiEnabled,\n );\n childYogaNode.setMeasureFunc(measureFunc);\n yogaNode.insertChild(childYogaNode, 0);\n\n return {\n type: tagName,\n style,\n children: [\n {\n type: \"text\",\n style: childStyle,\n children: [],\n textContent,\n props: {},\n yogaNode: childYogaNode,\n },\n ],\n props,\n yogaNode,\n };\n }\n\n // Process children\n const children: IntermediateNode[] = [];\n const rawChildren = props.children;\n\n if (rawChildren !== undefined && rawChildren !== null) {\n const childArray = Array.isArray(rawChildren) ? rawChildren : [rawChildren];\n\n for (const child of childArray as ElementChild[]) {\n if (child === null || child === undefined || typeof child === \"boolean\")\n continue;\n\n const childYogaNode = createYogaNode();\n yogaNode.insertChild(childYogaNode, children.length);\n children.push(\n await buildNode(\n child,\n style,\n childYogaNode,\n viewportWidth,\n viewportHeight,\n ctx,\n emojiEnabled,\n ),\n );\n }\n }\n\n return {\n type: tagName,\n style,\n children,\n props,\n yogaNode,\n };\n}\n\ntype IntermediateNode = {\n type: string;\n style: ComputedStyle;\n children: IntermediateNode[];\n textContent?: string;\n props: Record<string, unknown>;\n yogaNode: YogaNode;\n};\n\nfunction extractLayout(node: IntermediateNode, yogaNode: YogaNode): LayoutNode {\n const layout = yogaNode.getComputedLayout();\n\n return {\n type: node.type,\n style: node.style,\n children: node.children.map((child, i) => {\n const childYoga = yogaNode.getChild(i);\n return extractLayout(child, childYoga);\n }),\n textContent: node.textContent,\n props: node.props,\n x: layout.left,\n y: layout.top,\n width: layout.width,\n height: layout.height,\n };\n}\n\n/**\n * Extract plain text content from children if they are all strings/numbers.\n */\nfunction extractTextContent(children: unknown): string | undefined {\n if (children === undefined || children === null) return undefined;\n if (typeof children === \"string\") return children;\n if (typeof children === \"number\") return String(children);\n\n if (Array.isArray(children)) {\n const parts: string[] = [];\n for (const child of children) {\n if (typeof child === \"string\") {\n parts.push(child);\n } else if (typeof child === \"number\") {\n parts.push(String(child));\n } else if (\n child !== null &&\n child !== undefined &&\n typeof child !== \"boolean\"\n ) {\n return undefined; // Mixed content — not pure text\n }\n }\n return parts.join(\"\");\n }\n\n return undefined;\n}\n\n/**\n * Check if children contains any React elements (not just strings/numbers).\n */\nfunction hasElementChildren(children: unknown): boolean {\n if (\n children === undefined ||\n children === null ||\n typeof children === \"boolean\"\n )\n return false;\n if (typeof children === \"string\" || typeof children === \"number\")\n return false;\n\n if (Array.isArray(children)) {\n return children.some(\n (child) =>\n child !== null &&\n child !== undefined &&\n typeof child !== \"boolean\" &&\n typeof child !== \"string\" &&\n typeof child !== \"number\",\n );\n }\n\n // Single React element\n return typeof children === \"object\";\n}\n","// This file contains code adapted from Satori (https://github.com/vercel/satori)\n// Licensed under the Mozilla Public License 2.0 (MPL-2.0)\n// See NOTICE.md in the package root for details.\n\nimport type { ComputedStyle } from \"./compute.ts\";\n\ntype RawStyle = Record<string, unknown>;\n\nconst SIDES = [\"Top\", \"Right\", \"Bottom\", \"Left\"] as const;\n\n/**\n * Parse a CSS shorthand value like \"10px 20px\" into 1-4 parts.\n */\nfunction parseSides(value: string): string[] {\n const parts = value.toString().split(/\\s+/).filter(Boolean);\n switch (parts.length) {\n case 1:\n return [parts[0]!, parts[0]!, parts[0]!, parts[0]!];\n case 2:\n return [parts[0]!, parts[1]!, parts[0]!, parts[1]!];\n case 3:\n return [parts[0]!, parts[1]!, parts[2]!, parts[1]!];\n default:\n return [parts[0]!, parts[1]!, parts[2]!, parts[3]!];\n }\n}\n\nfunction parseValue(v: unknown): number | string | undefined {\n if (v === undefined || v === null) return undefined;\n const s = String(v);\n if (s === \"auto\") return \"auto\";\n const n = parseFloat(s);\n if (!isNaN(n)) return n;\n return s;\n}\n\n/**\n * Expand CSS shorthand properties into their longhand equivalents.\n * Mutates and returns the style object.\n */\nexport function expandStyle(raw: RawStyle): ComputedStyle {\n const style = { ...raw } as Record<string, unknown>;\n\n // margin shorthand\n if (style.margin !== undefined) {\n const sides = parseSides(String(style.margin));\n for (let i = 0; i < 4; i++) {\n const key = `margin${SIDES[i]}`;\n if (style[key] === undefined) style[key] = parseValue(sides[i]);\n }\n delete style.margin;\n }\n\n // padding shorthand\n if (style.padding !== undefined) {\n const sides = parseSides(String(style.padding));\n for (let i = 0; i < 4; i++) {\n const key = `padding${SIDES[i]}`;\n if (style[key] === undefined) style[key] = parseValue(sides[i]);\n }\n delete style.padding;\n }\n\n // borderRadius shorthand\n if (style.borderRadius !== undefined) {\n const sides = parseSides(String(style.borderRadius));\n const corners = [\n \"borderTopLeftRadius\",\n \"borderTopRightRadius\",\n \"borderBottomRightRadius\",\n \"borderBottomLeftRadius\",\n ];\n for (let i = 0; i < 4; i++) {\n if (style[corners[i]!] === undefined)\n style[corners[i]!] = parseValue(sides[i]);\n }\n delete style.borderRadius;\n }\n\n // borderWidth shorthand\n if (style.borderWidth !== undefined) {\n const sides = parseSides(String(style.borderWidth));\n for (let i = 0; i < 4; i++) {\n const key = `border${SIDES[i]}Width`;\n if (style[key] === undefined) style[key] = parseValue(sides[i]);\n }\n delete style.borderWidth;\n }\n\n // borderColor shorthand\n if (style.borderColor !== undefined) {\n const val = style.borderColor;\n for (const side of SIDES) {\n const key = `border${side}Color`;\n if (style[key] === undefined) style[key] = val;\n }\n delete style.borderColor;\n }\n\n // borderStyle shorthand\n if (style.borderStyle !== undefined) {\n const val = style.borderStyle;\n for (const side of SIDES) {\n const key = `border${side}Style`;\n if (style[key] === undefined) style[key] = val;\n }\n delete style.borderStyle;\n }\n\n // border shorthand (e.g. \"1px solid black\")\n if (style.border !== undefined) {\n const parts = String(style.border).split(/\\s+/);\n const width = parseValue(parts[0]);\n const borderStyle = parts[1] ?? \"solid\";\n const color = parts[2] ?? \"black\";\n for (const side of SIDES) {\n if (style[`border${side}Width`] === undefined)\n style[`border${side}Width`] = width;\n if (style[`border${side}Style`] === undefined)\n style[`border${side}Style`] = borderStyle;\n if (style[`border${side}Color`] === undefined)\n style[`border${side}Color`] = color;\n }\n delete style.border;\n }\n\n // flex shorthand\n if (style.flex !== undefined) {\n const val = String(style.flex);\n const parts = val.split(/\\s+/);\n if (parts.length === 1) {\n const n = parseFloat(parts[0]!);\n if (!isNaN(n)) {\n if (style.flexGrow === undefined) style.flexGrow = n;\n if (style.flexShrink === undefined) style.flexShrink = 1;\n if (style.flexBasis === undefined) style.flexBasis = 0;\n }\n } else if (parts.length === 2) {\n if (style.flexGrow === undefined) style.flexGrow = parseFloat(parts[0]!);\n if (style.flexShrink === undefined)\n style.flexShrink = parseFloat(parts[1]!);\n } else if (parts.length >= 3) {\n if (style.flexGrow === undefined) style.flexGrow = parseFloat(parts[0]!);\n if (style.flexShrink === undefined)\n style.flexShrink = parseFloat(parts[1]!);\n if (style.flexBasis === undefined) style.flexBasis = parseValue(parts[2]);\n }\n delete style.flex;\n }\n\n // gap shorthand\n if (style.gap !== undefined) {\n const sides = parseSides(String(style.gap));\n if (style.rowGap === undefined) style.rowGap = parseValue(sides[0]);\n if (style.columnGap === undefined) style.columnGap = parseValue(sides[1]);\n delete style.gap;\n }\n\n // background shorthand\n if (style.background !== undefined) {\n const bg = String(style.background);\n if (bg.includes(\"gradient(\") || bg.includes(\"url(\")) {\n if (style.backgroundImage === undefined) style.backgroundImage = bg;\n } else {\n if (style.backgroundColor === undefined) style.backgroundColor = bg;\n }\n delete style.background;\n }\n\n // overflow shorthand\n if (style.overflow !== undefined) {\n if (style.overflowX === undefined) style.overflowX = style.overflow;\n if (style.overflowY === undefined) style.overflowY = style.overflow;\n }\n\n // fontFamily normalization\n if (typeof style.fontFamily === \"string\") {\n style.fontFamily = style.fontFamily\n .split(\",\")\n .map((s) => s.trim().replace(/^['\"]|['\"]$/g, \"\"))\n .filter(Boolean)\n .join(\", \");\n }\n\n return style as unknown as ComputedStyle;\n}\n","// This file contains code adapted from Satori (https://github.com/vercel/satori)\n// Licensed under the Mozilla Public License 2.0 (MPL-2.0)\n// See NOTICE.md in the package root for details.\n\n/**\n * Normalized, computed CSS style after shorthand expansion.\n * All dimension values are numbers (pixels) or percentage strings.\n */\nexport type ComputedStyle = {\n // Display & layout\n display?: \"flex\" | \"none\";\n flexDirection?: \"row\" | \"column\" | \"row-reverse\" | \"column-reverse\";\n justifyContent?:\n | \"flex-start\"\n | \"flex-end\"\n | \"center\"\n | \"space-between\"\n | \"space-around\"\n | \"space-evenly\";\n alignItems?: \"flex-start\" | \"flex-end\" | \"center\" | \"stretch\" | \"baseline\";\n alignSelf?:\n | \"auto\"\n | \"flex-start\"\n | \"flex-end\"\n | \"center\"\n | \"stretch\"\n | \"baseline\";\n alignContent?:\n | \"flex-start\"\n | \"flex-end\"\n | \"center\"\n | \"stretch\"\n | \"space-between\"\n | \"space-around\";\n flexWrap?: \"nowrap\" | \"wrap\" | \"wrap-reverse\";\n flexGrow?: number;\n flexShrink?: number;\n flexBasis?: number | string;\n\n // Dimensions\n width?: number | string;\n height?: number | string;\n minWidth?: number | string;\n minHeight?: number | string;\n maxWidth?: number | string;\n maxHeight?: number | string;\n\n // Position\n position?: \"relative\" | \"absolute\";\n top?: number | string;\n right?: number | string;\n bottom?: number | string;\n left?: number | string;\n\n // Margin\n marginTop?: number | string;\n marginRight?: number | string;\n marginBottom?: number | string;\n marginLeft?: number | string;\n\n // Padding\n paddingTop?: number | string;\n paddingRight?: number | string;\n paddingBottom?: number | string;\n paddingLeft?: number | string;\n\n // Border\n borderTopWidth?: number;\n borderRightWidth?: number;\n borderBottomWidth?: number;\n borderLeftWidth?: number;\n borderTopColor?: string;\n borderRightColor?: string;\n borderBottomColor?: string;\n borderLeftColor?: string;\n borderTopStyle?: string;\n borderRightStyle?: string;\n borderBottomStyle?: string;\n borderLeftStyle?: string;\n borderTopLeftRadius?: number;\n borderTopRightRadius?: number;\n borderBottomRightRadius?: number;\n borderBottomLeftRadius?: number;\n\n // Gap\n rowGap?: number;\n columnGap?: number;\n\n // Overflow\n overflow?: string;\n overflowX?: string;\n overflowY?: string;\n\n // Colors & background\n backgroundColor?: string;\n color?: string;\n opacity?: number;\n backgroundImage?: string;\n backgroundSize?: string;\n\n // Typography\n fontSize?: number;\n fontFamily?: string;\n fontWeight?: number | string;\n fontStyle?: \"normal\" | \"italic\";\n textAlign?: \"left\" | \"center\" | \"right\" | \"justify\";\n textDecoration?: string;\n textTransform?: \"none\" | \"uppercase\" | \"lowercase\" | \"capitalize\";\n lineHeight?: number | string;\n letterSpacing?: number | string;\n whiteSpace?: \"normal\" | \"nowrap\" | \"pre\" | \"pre-wrap\" | \"pre-line\";\n wordBreak?: \"normal\" | \"break-all\" | \"break-word\" | \"keep-all\";\n textOverflow?: \"clip\" | \"ellipsis\";\n\n // Box shadow\n boxShadow?: string;\n textShadow?: string;\n\n // Transform\n transform?: string;\n transformOrigin?: string;\n\n // Image\n objectFit?: \"contain\" | \"cover\" | \"fill\" | \"none\" | \"scale-down\";\n\n // Filter\n filter?: string;\n};\n\n/**\n * Default styles for the root element.\n */\nexport const DEFAULT_STYLE: ComputedStyle = {\n display: \"flex\",\n flexDirection: \"row\",\n flexWrap: \"nowrap\",\n flexGrow: 0,\n flexShrink: 0,\n alignItems: \"stretch\",\n justifyContent: \"flex-start\",\n position: \"relative\",\n fontSize: 16,\n fontWeight: 400,\n fontStyle: \"normal\",\n color: \"black\",\n lineHeight: \"normal\",\n textAlign: \"left\",\n whiteSpace: \"normal\",\n wordBreak: \"normal\",\n textOverflow: \"clip\",\n opacity: 1,\n overflow: \"visible\",\n};\n\n/**\n * CSS properties that are inherited by child elements.\n */\nconst INHERITABLE_PROPS: (keyof ComputedStyle)[] = [\n \"color\",\n \"fontSize\",\n \"fontFamily\",\n \"fontWeight\",\n \"fontStyle\",\n \"textAlign\",\n \"textTransform\",\n \"textDecoration\",\n \"lineHeight\",\n \"letterSpacing\",\n \"whiteSpace\",\n \"wordBreak\",\n \"textOverflow\",\n];\n\n/**\n * Resolve the computed style for a node, inheriting from parent where appropriate.\n */\nexport function resolveStyle(\n rawStyle: ComputedStyle | undefined,\n parentStyle: ComputedStyle,\n): ComputedStyle {\n const style = { ...rawStyle };\n\n // Apply inherited properties\n for (const prop of INHERITABLE_PROPS) {\n if (style[prop] === undefined && parentStyle[prop] !== undefined) {\n (style as Record<string, unknown>)[prop] = parentStyle[prop];\n }\n }\n\n // Resolve fontSize (ensure it's a number)\n if (typeof style.fontSize === \"string\") {\n const parsed = parseFloat(style.fontSize);\n style.fontSize = isNaN(parsed) ? parentStyle.fontSize : parsed;\n }\n\n // Resolve lineHeight: parse string values to numbers but keep multipliers\n // as-is so they're recalculated per-element in text layout (using each\n // element's own fontSize rather than the parent's).\n if (typeof style.lineHeight === \"string\") {\n const str = style.lineHeight;\n if (str.endsWith(\"%\")) {\n style.lineHeight = parseFloat(str) / 100;\n } else {\n const parsed = parseFloat(str);\n if (!isNaN(parsed)) {\n style.lineHeight = parsed;\n }\n }\n }\n\n // Resolve letterSpacing\n if (typeof style.letterSpacing === \"string\") {\n const parsed = parseFloat(style.letterSpacing);\n if (!isNaN(parsed)) {\n style.letterSpacing = parsed;\n }\n }\n\n return style;\n}\n\n/**\n * Dimension properties that may contain CSS units needing resolution.\n */\nconst DIMENSION_PROPS: (keyof ComputedStyle)[] = [\n \"width\",\n \"height\",\n \"minWidth\",\n \"minHeight\",\n \"maxWidth\",\n \"maxHeight\",\n \"top\",\n \"right\",\n \"bottom\",\n \"left\",\n \"marginTop\",\n \"marginRight\",\n \"marginBottom\",\n \"marginLeft\",\n \"paddingTop\",\n \"paddingRight\",\n \"paddingBottom\",\n \"paddingLeft\",\n \"rowGap\",\n \"columnGap\",\n \"flexBasis\",\n];\n\n/**\n * Resolve a single CSS dimension string to a pixel number.\n * Returns the original value for `%` and `auto` (Yoga handles those),\n * and for values that are already numbers or unrecognised strings.\n */\nfunction resolveUnit(\n value: string,\n viewportWidth: number,\n viewportHeight: number,\n fontSize: number,\n rootFontSize: number,\n): number | string {\n // Percentages and auto are handled downstream by Yoga\n if (value.endsWith(\"%\") || value === \"auto\") return value;\n\n // Viewport-relative units\n if (value.endsWith(\"vmin\")) {\n const n = parseFloat(value);\n return isNaN(n)\n ? value\n : (n / 100) * Math.min(viewportWidth, viewportHeight);\n }\n if (value.endsWith(\"vmax\")) {\n const n = parseFloat(value);\n return isNaN(n)\n ? value\n : (n / 100) * Math.max(viewportWidth, viewportHeight);\n }\n if (value.endsWith(\"vw\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : (n / 100) * viewportWidth;\n }\n if (value.endsWith(\"vh\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : (n / 100) * viewportHeight;\n }\n\n // Font-relative units\n if (value.endsWith(\"rem\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * rootFontSize;\n }\n if (value.endsWith(\"em\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * fontSize;\n }\n\n // Absolute units (CSS reference pixel = 1/96 inch)\n if (value.endsWith(\"px\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n;\n }\n if (value.endsWith(\"pt\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * (96 / 72);\n }\n if (value.endsWith(\"pc\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * 16;\n }\n if (value.endsWith(\"in\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * 96;\n }\n if (value.endsWith(\"cm\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * (96 / 2.54);\n }\n if (value.endsWith(\"mm\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * (96 / 25.4);\n }\n\n return value;\n}\n\n/**\n * Resolve CSS units (vw, vh, vmin, vmax, em, rem, px, pt, pc, in, cm, mm)\n * in a style object to pixel values. Percentages and `auto` pass through\n * unchanged for Yoga to handle.\n */\nexport function resolveUnits(\n style: ComputedStyle,\n viewportWidth: number,\n viewportHeight: number,\n rootFontSize: number = DEFAULT_STYLE.fontSize!,\n): ComputedStyle {\n const fontSize =\n typeof style.fontSize === \"number\" ? style.fontSize : rootFontSize;\n\n for (const prop of DIMENSION_PROPS) {\n const value = style[prop];\n if (typeof value !== \"string\") continue;\n const resolved = resolveUnit(\n value,\n viewportWidth,\n viewportHeight,\n fontSize,\n rootFontSize,\n );\n if (resolved !== value) {\n (style as Record<string, unknown>)[prop] = resolved;\n }\n }\n return style;\n}\n\n/**\n * Resolve a dimension value (width, height, margin, etc.) to pixels.\n * Percentage values are resolved relative to the provided container size.\n */\nexport function resolveDimension(\n value: number | string | undefined,\n containerSize: number,\n): number | undefined {\n if (value === undefined || value === \"auto\") return undefined;\n if (typeof value === \"number\") return value;\n const s = String(value);\n if (s.endsWith(\"%\")) {\n return (parseFloat(s) / 100) * containerSize;\n }\n const n = parseFloat(s);\n return isNaN(n) ? undefined : n;\n}\n","import Yoga, {\n Align,\n Display,\n Edge,\n FlexDirection,\n Gutter,\n Justify,\n Overflow,\n PositionType,\n Wrap,\n} from \"yoga-layout\";\nimport type { Node as YogaNode } from \"yoga-layout\";\n\nexport type { YogaNode };\n\nexport {\n Yoga,\n Align,\n Display,\n Edge,\n FlexDirection,\n Gutter,\n Justify,\n Overflow,\n PositionType,\n Wrap,\n};\n\nexport function createYogaNode(): YogaNode {\n return Yoga.Node.create();\n}\n\nexport function freeYogaNode(node: YogaNode): void {\n node.freeRecursive();\n}\n","import {\n Align,\n Display,\n Edge,\n FlexDirection,\n Gutter,\n Justify,\n Overflow,\n PositionType,\n Wrap,\n} from \"../yoga.ts\";\nimport type { YogaNode } from \"../yoga.ts\";\nimport type { ComputedStyle } from \"./compute.ts\";\n\n/**\n * Apply computed CSS styles to a Yoga node.\n */\nexport function applyStylesToYoga(node: YogaNode, style: ComputedStyle): void {\n // Display\n if (style.display === \"none\") {\n node.setDisplay(Display.None);\n } else {\n node.setDisplay(Display.Flex);\n }\n\n // Flex direction (CSS default is \"row\", Yoga defaults to \"column\")\n {\n const map: Record<string, FlexDirection> = {\n row: FlexDirection.Row,\n \"row-reverse\": FlexDirection.RowReverse,\n column: FlexDirection.Column,\n \"column-reverse\": FlexDirection.ColumnReverse,\n };\n node.setFlexDirection(\n map[style.flexDirection ?? \"row\"] ?? FlexDirection.Row,\n );\n }\n\n // Justify content\n if (style.justifyContent) {\n const map: Record<string, Justify> = {\n \"flex-start\": Justify.FlexStart,\n \"flex-end\": Justify.FlexEnd,\n center: Justify.Center,\n \"space-between\": Justify.SpaceBetween,\n \"space-around\": Justify.SpaceAround,\n \"space-evenly\": Justify.SpaceEvenly,\n };\n const jc = map[style.justifyContent];\n if (jc !== undefined) node.setJustifyContent(jc);\n }\n\n // Align items\n if (style.alignItems) {\n const map: Record<string, Align> = {\n \"flex-start\": Align.FlexStart,\n \"flex-end\": Align.FlexEnd,\n center: Align.Center,\n stretch: Align.Stretch,\n baseline: Align.Baseline,\n };\n const ai = map[style.alignItems];\n if (ai !== undefined) node.setAlignItems(ai);\n }\n\n // Align self\n if (style.alignSelf) {\n const map: Record<string, Align> = {\n auto: Align.Auto,\n \"flex-start\": Align.FlexStart,\n \"flex-end\": Align.FlexEnd,\n center: Align.Center,\n stretch: Align.Stretch,\n baseline: Align.Baseline,\n };\n const as_ = map[style.alignSelf];\n if (as_ !== undefined) node.setAlignSelf(as_);\n }\n\n // Align content\n if (style.alignContent) {\n const map: Record<string, Align> = {\n \"flex-start\": Align.FlexStart,\n \"flex-end\": Align.FlexEnd,\n center: Align.Center,\n stretch: Align.Stretch,\n \"space-between\": Align.SpaceBetween,\n \"space-around\": Align.SpaceAround,\n };\n const ac = map[style.alignContent];\n if (ac !== undefined) node.setAlignContent(ac);\n }\n\n // Flex wrap\n if (style.flexWrap) {\n const map: Record<string, Wrap> = {\n nowrap: Wrap.NoWrap,\n wrap: Wrap.Wrap,\n \"wrap-reverse\": Wrap.WrapReverse,\n };\n const fw = map[style.flexWrap];\n if (fw !== undefined) node.setFlexWrap(fw);\n }\n\n // Flex grow / shrink / basis\n if (style.flexGrow !== undefined) node.setFlexGrow(style.flexGrow);\n // Satori defaults flexShrink to 0 (React Native convention); match it for compatibility\n node.setFlexShrink(style.flexShrink ?? 0);\n if (style.flexBasis !== undefined) {\n if (typeof style.flexBasis === \"number\") {\n node.setFlexBasis(style.flexBasis);\n } else if (String(style.flexBasis).endsWith(\"%\")) {\n node.setFlexBasis(String(style.flexBasis) as `${number}%`);\n } else if (style.flexBasis === \"auto\") {\n node.setFlexBasis(\"auto\");\n } else {\n const n = parseFloat(String(style.flexBasis));\n if (!isNaN(n)) node.setFlexBasis(n);\n }\n }\n\n // Dimensions\n applyDimension(node, \"setWidth\", style.width);\n applyDimension(node, \"setHeight\", style.height);\n applyDimension(node, \"setMinWidth\", style.minWidth);\n applyDimension(node, \"setMinHeight\", style.minHeight);\n applyDimension(node, \"setMaxWidth\", style.maxWidth);\n applyDimension(node, \"setMaxHeight\", style.maxHeight);\n\n // Position\n if (style.position === \"absolute\") {\n node.setPositionType(PositionType.Absolute);\n } else {\n node.setPositionType(PositionType.Relative);\n }\n\n // Position edges\n applyEdgeValue(node, \"setPosition\", Edge.Top, style.top);\n applyEdgeValue(node, \"setPosition\", Edge.Right, style.right);\n applyEdgeValue(node, \"setPosition\", Edge.Bottom, style.bottom);\n applyEdgeValue(node, \"setPosition\", Edge.Left, style.left);\n\n // Margin\n applyEdgeValue(node, \"setMargin\", Edge.Top, style.marginTop);\n applyEdgeValue(node, \"setMargin\", Edge.Right, style.marginRight);\n applyEdgeValue(node, \"setMargin\", Edge.Bottom, style.marginBottom);\n applyEdgeValue(node, \"setMargin\", Edge.Left, style.marginLeft);\n\n // Padding\n applyEdgeValue(node, \"setPadding\", Edge.Top, style.paddingTop);\n applyEdgeValue(node, \"setPadding\", Edge.Right, style.paddingRight);\n applyEdgeValue(node, \"setPadding\", Edge.Bottom, style.paddingBottom);\n applyEdgeValue(node, \"setPadding\", Edge.Left, style.paddingLeft);\n\n // Border width\n if (style.borderTopWidth !== undefined)\n node.setBorder(Edge.Top, style.borderTopWidth);\n if (style.borderRightWidth !== undefined)\n node.setBorder(Edge.Right, style.borderRightWidth);\n if (style.borderBottomWidth !== undefined)\n node.setBorder(Edge.Bottom, style.borderBottomWidth);\n if (style.borderLeftWidth !== undefined)\n node.setBorder(Edge.Left, style.borderLeftWidth);\n\n // Gap\n if (style.rowGap !== undefined) node.setGap(Gutter.Row, style.rowGap);\n if (style.columnGap !== undefined)\n node.setGap(Gutter.Column, style.columnGap);\n\n // Overflow\n if (\n style.overflow === \"hidden\" ||\n style.overflowX === \"hidden\" ||\n style.overflowY === \"hidden\"\n ) {\n node.setOverflow(Overflow.Hidden);\n } else {\n node.setOverflow(Overflow.Visible);\n }\n}\n\nfunction applyDimension(\n node: YogaNode,\n setter:\n | \"setWidth\"\n | \"setHeight\"\n | \"setMinWidth\"\n | \"setMinHeight\"\n | \"setMaxWidth\"\n | \"setMaxHeight\",\n value: number | string | undefined,\n): void {\n if (value === undefined) return;\n if (value === \"auto\") {\n if (setter === \"setWidth\" || setter === \"setHeight\") {\n node[setter](\"auto\");\n }\n return;\n }\n if (typeof value === \"number\") {\n node[setter](value);\n return;\n }\n const s = String(value);\n if (s.endsWith(\"%\")) {\n node[setter](s as `${number}%`);\n } else {\n const n = parseFloat(s);\n if (!isNaN(n)) node[setter](n);\n }\n}\n\nfunction applyEdgeValue(\n node: YogaNode,\n setter: \"setMargin\" | \"setPadding\" | \"setPosition\",\n edge: Edge,\n value: number | string | undefined,\n): void {\n if (value === undefined) return;\n if (value === \"auto\" && setter === \"setMargin\") {\n node.setMargin(edge, \"auto\");\n return;\n }\n if (typeof value === \"number\") {\n node[setter](edge, value);\n return;\n }\n const s = String(value);\n if (s.endsWith(\"%\")) {\n node[setter](edge, s as `${number}%`);\n } else {\n const n = parseFloat(s);\n if (!isNaN(n)) node[setter](edge, n);\n }\n}\n","import type { SKRSContext2D } from \"@napi-rs/canvas\";\nimport type { ReactNode } from \"react\";\n\nimport type { RenderReactElementOptions } from \"../types.ts\";\nimport { drawNode } from \"./draw/index.ts\";\nimport { ensureFontsRegistered } from \"./font.ts\";\nimport { buildLayoutTree } from \"./layout.ts\";\n\n/**\n * Render a React element tree to a canvas context.\n *\n * Width and height are taken from the canvas itself (`ctx.canvas.width` /\n * `ctx.canvas.height`).\n *\n * @param ctx - Canvas 2D rendering context to draw into\n * @param element - React element tree to render\n * @param options - Rendering options (fonts, debug mode)\n *\n * @example\n * ```tsx\n * import { createCanvas, renderReactElement } from \"@effing/canvas\";\n *\n * const canvas = createCanvas(1080, 1080);\n * const ctx = canvas.getContext(\"2d\");\n *\n * await renderReactElement(ctx, <MyComponent />, { fonts: [myFont] });\n *\n * const png = canvas.encodeSync(\"png\");\n * ```\n */\nexport async function renderReactElement(\n ctx: SKRSContext2D,\n element: ReactNode,\n options: RenderReactElementOptions,\n): Promise<void> {\n // Register fonts\n ensureFontsRegistered(options.fonts);\n\n // Get dimensions from canvas\n const width = ctx.canvas.width;\n const height = ctx.canvas.height;\n\n // Build layout tree (Yoga)\n const emojiStyle =\n options.emoji === \"none\" ? undefined : (options.emoji ?? \"twemoji\");\n const layoutTree = await buildLayoutTree(\n element,\n width,\n height,\n ctx,\n !!emojiStyle,\n );\n\n // Draw to canvas\n await drawNode(ctx, layoutTree, 0, 0, options.debug ?? false, emojiStyle);\n}\n"],"mappings":"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","names":["GlobalFonts","loadImage","createCanvas","loadImage","loadImage","measureText","loadImage","canvas","createCanvas","hasRadius","loadImage","toNumber","loadImage","style","children","loadImage","createCanvas"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/lottie.ts","../src/jsx/draw/index.ts","../src/jsx/language.ts","../src/jsx/text/linebreak.ts","../src/jsx/text/measure.ts","../src/jsx/text/index.ts","../src/jsx/draw/clip.ts","../src/jsx/draw/gradient.ts","../src/jsx/draw/image.ts","../src/jsx/draw/object-fit.ts","../src/jsx/draw/rect.ts","../src/jsx/draw/svg.ts","../src/jsx/draw/text.ts","../src/jsx/emoji.ts","../src/jsx/text/emoji-split.ts","../src/jsx/font.ts","../src/jsx/layout.ts","../src/jsx/style/expand.ts","../src/jsx/style/compute.ts","../src/jsx/yoga.ts","../src/jsx/style/properties.ts","../src/jsx/index.ts"],"sourcesContent":["// Re-export canvas primitives from @napi-rs/canvas\nimport { createCanvas as _createCanvas } from \"@napi-rs/canvas\";\nexport {\n Canvas,\n type SKRSContext2D,\n GlobalFonts,\n loadImage,\n Image,\n} from \"@napi-rs/canvas\";\n\nexport function createCanvas(width: number, height: number) {\n const canvas = _createCanvas(width, height);\n const origEncode = canvas.encode.bind(canvas);\n type Encode = typeof canvas.encode;\n\n // The native @napi-rs/canvas encode() returns Buffers backed by Rust/Skia\n // memory that can be freed before downstream consumers finish reading (e.g.\n // when streaming frames concurrently). We patch encode to copy the result\n // to the JS heap so the data remains valid regardless of native GC timing.\n canvas.encode = (async (...args: unknown[]) =>\n Buffer.from(await origEncode(...(args as Parameters<Encode>)))) as Encode;\n\n return canvas;\n}\n\n// Lottie API\nexport { LottieAnimation, loadLottie, renderLottieFrame } from \"./lottie.ts\";\n\n// JSX API\nexport { renderReactElement } from \"./jsx/index.ts\";\n\n// Font management\nexport {\n registerFont,\n registerFontFromPath,\n registeredFamilies,\n} from \"./jsx/font.ts\";\n\n// Types\nexport type {\n FontData,\n RenderReactElementOptions,\n EmojiStyle,\n} from \"./types.ts\";\n","import { LottieAnimation } from \"@napi-rs/canvas\";\nimport type { SKRSContext2D } from \"@napi-rs/canvas\";\n\nexport { LottieAnimation };\n\n/**\n * Load a Lottie animation from a JSON string or Buffer.\n *\n * @param data - Lottie JSON string or Buffer\n * @param options - Optional resource path for external assets\n * @returns A `LottieAnimation` handle ready for rendering\n *\n * @example\n * ```ts\n * const anim = loadLottie(fs.readFileSync(\"animation.json\", \"utf-8\"));\n * ```\n */\nexport function loadLottie(\n data: string | Buffer,\n options?: { resourcePath?: string },\n): LottieAnimation {\n const jsonString = typeof data === \"string\" ? data : data.toString(\"utf-8\");\n return LottieAnimation.loadFromData(jsonString, {\n resourcePath: options?.resourcePath,\n });\n}\n\n/**\n * Render a specific frame of a Lottie animation to a canvas context.\n *\n * Seeks the animation to the given frame, then renders it onto the\n * provided context. The canvas dimensions determine the render size.\n *\n * @param ctx - Canvas 2D rendering context to draw into\n * @param animation - Lottie animation handle (from {@link loadLottie})\n * @param frame - Zero-based frame number to render\n *\n * @example\n * ```ts\n * import { createCanvas, loadLottie, renderLottieFrame } from \"@effing/canvas\";\n *\n * const canvas = createCanvas(1080, 1080);\n * const ctx = canvas.getContext(\"2d\");\n * const anim = loadLottie(jsonString);\n *\n * renderLottieFrame(ctx, anim, 0);\n * const png = canvas.encodeSync(\"png\");\n * ```\n */\nexport function renderLottieFrame(\n ctx: SKRSContext2D,\n animation: LottieAnimation,\n frame: number,\n): void {\n animation.seekFrame(frame);\n animation.render(ctx);\n}\n","import type { Canvas, Image, SKRSContext2D } from \"@napi-rs/canvas\";\n\nimport { createCanvas, loadImage } from \"@napi-rs/canvas\";\n\nconst canvasPool = new Map<string, WeakRef<Canvas>[]>();\n\nfunction acquireOffscreen(w: number, h: number): [Canvas, SKRSContext2D] {\n const key = `${w}x${h}`;\n const stack = canvasPool.get(key);\n if (stack) {\n while (stack.length > 0) {\n const ref = stack.pop()!;\n const canvas = ref.deref();\n if (canvas) {\n const ctx = canvas.getContext(\"2d\");\n ctx.setTransform(1, 0, 0, 1, 0, 0);\n ctx.clearRect(0, 0, w, h);\n return [canvas, ctx];\n }\n }\n }\n const canvas = createCanvas(w, h);\n return [canvas, canvas.getContext(\"2d\")];\n}\n\nfunction releaseOffscreen(canvas: Canvas): void {\n const key = `${canvas.width}x${canvas.height}`;\n let stack = canvasPool.get(key);\n if (!stack) {\n stack = [];\n canvasPool.set(key, stack);\n }\n stack.push(new WeakRef(canvas));\n}\n\nimport type { EmojiStyle } from \"../emoji.ts\";\nimport type { LayoutNode } from \"../layout.ts\";\nimport { layoutText } from \"../text/index.ts\";\nimport { applyClip, roundedRect } from \"./clip.ts\";\nimport { createGradientFromCSS } from \"./gradient.ts\";\nimport { drawImage } from \"./image.ts\";\nimport { computeContain, computeCover } from \"./object-fit.ts\";\nimport { drawRect, getBorderRadiusFromStyle } from \"./rect.ts\";\nimport { drawSvgContainer } from \"./svg.ts\";\nimport { drawText } from \"./text.ts\";\n\n/**\n * Main draw dispatcher: recursively draws the layout tree onto the canvas.\n */\nexport async function drawNode(\n ctx: SKRSContext2D,\n node: LayoutNode,\n parentX: number,\n parentY: number,\n debug: boolean,\n emojiStyle?: EmojiStyle,\n): Promise<void> {\n const x = parentX + node.x;\n const y = parentY + node.y;\n const { width, height, style } = node;\n\n if (style.display === \"none\") return;\n\n const opacity = style.opacity ?? 1;\n if (opacity <= 0) return;\n\n // Detect scale in transform — if present, render to offscreen buffer at 1x\n // then composite scaled. This avoids Skia re-rasterizing glyphs per-frame.\n const scaleInfo = style.transform ? extractScale(style.transform) : null;\n if (scaleInfo && (scaleInfo.sx !== 1 || scaleInfo.sy !== 1)) {\n const sx = scaleInfo.sx;\n const sy = scaleInfo.sy;\n const transformWithoutScale = scaleInfo.remaining;\n\n // Quantize to ceil(|scale|) — buffer resolution only changes at\n // integer boundaries (no jitter), and composite is always ≤1x (sharp).\n const qx = Math.max(1, Math.ceil(Math.abs(sx)));\n const qy = Math.max(1, Math.ceil(Math.abs(sy)));\n\n const bufW = Math.ceil((width + 2) * qx);\n const bufH = Math.ceil((height + 2) * qy);\n if (bufW > 0 && bufH > 0) {\n const [offscreen, offCtx] = acquireOffscreen(bufW, bufH);\n\n // Render at qx×qy resolution — logical coords produce more pixels\n offCtx.save();\n offCtx.scale(qx, qy);\n await drawNodeInner(\n offCtx,\n node,\n parentX,\n parentY,\n 1 - x,\n 1 - y,\n debug,\n emojiStyle,\n transformWithoutScale,\n );\n offCtx.restore();\n\n ctx.save();\n if (opacity < 1) {\n ctx.globalAlpha *= opacity;\n }\n\n let ox = x + width / 2;\n let oy = y + height / 2;\n if (style.transformOrigin) {\n const parts = style.transformOrigin.split(/\\s+/);\n ox = resolveOrigin(parts[0], x, width);\n oy = resolveOrigin(parts[1], y, height);\n }\n\n // Apply the original scale — drawImage maps the high-res buffer\n // back to logical size, so the transform needs the full scale value.\n ctx.translate(ox, oy);\n ctx.scale(sx, sy);\n ctx.translate(-ox, -oy);\n\n // Draw high-res buffer back at logical size (qx→1x downscale happens here)\n ctx.drawImage(\n offscreen,\n 0,\n 0,\n bufW,\n bufH,\n x - 1,\n y - 1,\n width + 2,\n height + 2,\n );\n releaseOffscreen(offscreen);\n ctx.restore();\n return;\n }\n }\n\n ctx.save();\n\n // Apply opacity\n if (opacity < 1) {\n ctx.globalAlpha *= opacity;\n }\n\n // Apply CSS filter\n if (style.filter) {\n ctx.filter = style.filter;\n }\n\n // Apply transform\n if (style.transform) {\n applyTransform(\n ctx,\n style.transform,\n x,\n y,\n width,\n height,\n style.transformOrigin,\n );\n }\n\n // Apply clipping for overflow: hidden\n const isClipped =\n style.overflow === \"hidden\" ||\n style.overflowX === \"hidden\" ||\n style.overflowY === \"hidden\";\n\n if (isClipped) {\n const borderRadius = getBorderRadiusFromStyle(style);\n applyClip(ctx, x, y, width, height, borderRadius);\n }\n\n // Draw background and borders\n if (\n style.backgroundColor ||\n style.borderTopWidth ||\n style.borderRightWidth ||\n style.borderBottomWidth ||\n style.borderLeftWidth ||\n style.boxShadow\n ) {\n drawRect(ctx, x, y, width, height, style);\n }\n\n // Draw background-image (gradient or url)\n if (style.backgroundImage) {\n const gradient = createGradientFromCSS(\n ctx,\n style.backgroundImage,\n x,\n y,\n width,\n height,\n );\n if (gradient) {\n ctx.fillStyle = gradient;\n const borderRadius = getBorderRadiusFromStyle(style);\n if (\n borderRadius.topLeft > 0 ||\n borderRadius.topRight > 0 ||\n borderRadius.bottomRight > 0 ||\n borderRadius.bottomLeft > 0\n ) {\n ctx.beginPath();\n roundedRect(\n ctx,\n x,\n y,\n width,\n height,\n borderRadius.topLeft,\n borderRadius.topRight,\n borderRadius.bottomRight,\n borderRadius.bottomLeft,\n );\n ctx.fill();\n } else {\n ctx.fillRect(x, y, width, height);\n }\n } else {\n // Try url(...) background image\n const urlMatch = style.backgroundImage.match(/url\\([\"']?(.*?)[\"']?\\)/);\n if (urlMatch) {\n const borderRadius = getBorderRadiusFromStyle(style);\n const hasRadius =\n borderRadius.topLeft > 0 ||\n borderRadius.topRight > 0 ||\n borderRadius.bottomRight > 0 ||\n borderRadius.bottomLeft > 0;\n\n if (hasRadius) {\n applyClip(ctx, x, y, width, height, borderRadius);\n }\n\n const image = await loadImage(urlMatch[1]!);\n const bgSize = style.backgroundSize;\n\n if (bgSize === \"cover\") {\n // Cover fills the box completely — no tiling needed\n const r = computeCover(\n image.width,\n image.height,\n x,\n y,\n width,\n height,\n );\n ctx.drawImage(image, r.sx, r.sy, r.sw, r.sh, r.dx, r.dy, r.dw, r.dh);\n } else {\n // Compute tile dimensions based on backgroundSize\n let tileW: number, tileH: number;\n if (bgSize === \"contain\") {\n const r = computeContain(\n image.width,\n image.height,\n 0,\n 0,\n width,\n height,\n );\n tileW = r.dw;\n tileH = r.dh;\n } else if (bgSize === \"100% 100%\") {\n tileW = width;\n tileH = height;\n } else {\n // CSS default (auto): natural image size\n tileW = image.width;\n tileH = image.height;\n }\n // Tile the image to fill the box (CSS background-repeat: repeat)\n for (let ty = y; ty < y + height; ty += tileH) {\n for (let tx = x; tx < x + width; tx += tileW) {\n ctx.drawImage(image, tx, ty, tileW, tileH);\n }\n }\n }\n }\n }\n }\n\n // Debug: draw bounding boxes\n if (debug) {\n ctx.strokeStyle = \"rgba(255, 0, 0, 0.5)\";\n ctx.lineWidth = 1;\n ctx.strokeRect(x, y, width, height);\n }\n\n // Draw text content\n if (node.textContent !== undefined && node.textContent !== \"\") {\n const paddingTop = toNumber(style.paddingTop);\n const paddingLeft = toNumber(style.paddingLeft);\n const paddingRight = toNumber(style.paddingRight);\n\n const borderTopW = toNumber(style.borderTopWidth);\n const borderLeftW = toNumber(style.borderLeftWidth);\n const borderRightW = toNumber(style.borderRightWidth);\n\n const contentX = x + paddingLeft + borderLeftW;\n const contentY = y + paddingTop + borderTopW;\n const contentWidth =\n width - paddingLeft - paddingRight - borderLeftW - borderRightW;\n\n const textLayout = layoutText(\n node.textContent,\n style,\n contentWidth,\n ctx,\n !!emojiStyle,\n );\n await drawText(\n ctx,\n textLayout.segments,\n contentX,\n contentY,\n style.textShadow,\n emojiStyle,\n );\n }\n\n // Draw <img> elements\n if (node.type === \"img\" && node.props.src) {\n const paddingTop = toNumber(style.paddingTop);\n const paddingLeft = toNumber(style.paddingLeft);\n const paddingRight = toNumber(style.paddingRight);\n const paddingBottom = toNumber(style.paddingBottom);\n\n const imgX = x + paddingLeft;\n const imgY = y + paddingTop;\n const imgW = width - paddingLeft - paddingRight;\n const imgH = height - paddingTop - paddingBottom;\n\n // Images are replaced content — borderRadius clips them directly\n // (unlike child content which requires overflow:hidden)\n if (!isClipped) {\n const borderRadius = getBorderRadiusFromStyle(style);\n if (\n borderRadius.topLeft > 0 ||\n borderRadius.topRight > 0 ||\n borderRadius.bottomRight > 0 ||\n borderRadius.bottomLeft > 0\n ) {\n applyClip(ctx, imgX, imgY, imgW, imgH, borderRadius);\n }\n }\n\n await drawImage(\n ctx,\n node.props.src as string | Buffer,\n imgX,\n imgY,\n imgW,\n imgH,\n style,\n node.props.__loadedImage as Image | undefined,\n );\n }\n\n // Draw <svg> containers (handle their own child traversal in SVG coordinate space)\n if (node.type === \"svg\") {\n drawSvgContainer(ctx, node, x, y, width, height);\n } else {\n // Recursively draw children\n for (const child of node.children) {\n await drawNode(ctx, child, x, y, debug, emojiStyle);\n }\n }\n\n ctx.restore();\n}\n\n/**\n * Extract scale(sx, sy) from a transform string, returning the scale values\n * and the remaining transform with scale removed.\n */\nfunction extractScale(\n transform: string,\n): { sx: number; sy: number; remaining: string } | null {\n const scaleMatch = transform.match(/\\b(scale|scaleX|scaleY)\\(([^)]+)\\)/);\n if (!scaleMatch) return null;\n\n const [fullMatch, name, args] = scaleMatch;\n const values = args!.split(\",\").map((s) => s.trim());\n\n const sx = name === \"scaleY\" ? 1 : parseFloat(values[0]!);\n const sy =\n name === \"scaleX\"\n ? 1\n : parseFloat(values[name === \"scale\" ? 1 : 0] ?? String(sx));\n\n const remaining = transform.replace(fullMatch!, \"\").trim();\n return { sx, sy, remaining };\n}\n\n/**\n * Inner draw that renders a node with an optional override transform\n * (used by the offscreen-buffer path to strip scale from the transform).\n * offsetX/offsetY shift all coordinates so the node renders at a buffer-local position.\n */\nasync function drawNodeInner(\n ctx: SKRSContext2D,\n node: LayoutNode,\n parentX: number,\n parentY: number,\n offsetX: number,\n offsetY: number,\n debug: boolean,\n emojiStyle: EmojiStyle | undefined,\n overrideTransform: string | undefined,\n): Promise<void> {\n const x = parentX + node.x + offsetX;\n const y = parentY + node.y + offsetY;\n const { width, height, style } = node;\n\n if (style.display === \"none\") return;\n\n const opacity = style.opacity ?? 1;\n if (opacity <= 0) return;\n\n ctx.save();\n\n if (opacity < 1) {\n ctx.globalAlpha *= opacity;\n }\n\n if (style.filter) {\n ctx.filter = style.filter;\n }\n\n // Apply the override transform (scale stripped) or original\n const transformToApply =\n overrideTransform !== undefined ? overrideTransform : style.transform;\n if (transformToApply) {\n applyTransform(\n ctx,\n transformToApply,\n x,\n y,\n width,\n height,\n style.transformOrigin,\n );\n }\n\n const isClipped =\n style.overflow === \"hidden\" ||\n style.overflowX === \"hidden\" ||\n style.overflowY === \"hidden\";\n\n if (isClipped) {\n const borderRadius = getBorderRadiusFromStyle(style);\n applyClip(ctx, x, y, width, height, borderRadius);\n }\n\n if (\n style.backgroundColor ||\n style.borderTopWidth ||\n style.borderRightWidth ||\n style.borderBottomWidth ||\n style.borderLeftWidth ||\n style.boxShadow\n ) {\n drawRect(ctx, x, y, width, height, style);\n }\n\n if (style.backgroundImage) {\n const gradient = createGradientFromCSS(\n ctx,\n style.backgroundImage,\n x,\n y,\n width,\n height,\n );\n if (gradient) {\n ctx.fillStyle = gradient;\n const borderRadius = getBorderRadiusFromStyle(style);\n if (\n borderRadius.topLeft > 0 ||\n borderRadius.topRight > 0 ||\n borderRadius.bottomRight > 0 ||\n borderRadius.bottomLeft > 0\n ) {\n ctx.beginPath();\n roundedRect(\n ctx,\n x,\n y,\n width,\n height,\n borderRadius.topLeft,\n borderRadius.topRight,\n borderRadius.bottomRight,\n borderRadius.bottomLeft,\n );\n ctx.fill();\n } else {\n ctx.fillRect(x, y, width, height);\n }\n } else {\n const urlMatch = style.backgroundImage.match(/url\\([\"']?(.*?)[\"']?\\)/);\n if (urlMatch) {\n const borderRadius = getBorderRadiusFromStyle(style);\n const hasRadius =\n borderRadius.topLeft > 0 ||\n borderRadius.topRight > 0 ||\n borderRadius.bottomRight > 0 ||\n borderRadius.bottomLeft > 0;\n if (hasRadius) {\n applyClip(ctx, x, y, width, height, borderRadius);\n }\n const image = await loadImage(urlMatch[1]!);\n const bgSize = style.backgroundSize;\n if (bgSize === \"cover\") {\n const r = computeCover(\n image.width,\n image.height,\n x,\n y,\n width,\n height,\n );\n ctx.drawImage(image, r.sx, r.sy, r.sw, r.sh, r.dx, r.dy, r.dw, r.dh);\n } else {\n let tileW: number, tileH: number;\n if (bgSize === \"contain\") {\n const r = computeContain(\n image.width,\n image.height,\n 0,\n 0,\n width,\n height,\n );\n tileW = r.dw;\n tileH = r.dh;\n } else if (bgSize === \"100% 100%\") {\n tileW = width;\n tileH = height;\n } else {\n tileW = image.width;\n tileH = image.height;\n }\n for (let ty = y; ty < y + height; ty += tileH) {\n for (let tx = x; tx < x + width; tx += tileW) {\n ctx.drawImage(image, tx, ty, tileW, tileH);\n }\n }\n }\n }\n }\n }\n\n if (debug) {\n ctx.strokeStyle = \"rgba(255, 0, 0, 0.5)\";\n ctx.lineWidth = 1;\n ctx.strokeRect(x, y, width, height);\n }\n\n if (node.textContent !== undefined && node.textContent !== \"\") {\n const paddingTop = toNumber(style.paddingTop);\n const paddingLeft = toNumber(style.paddingLeft);\n const paddingRight = toNumber(style.paddingRight);\n const borderTopW = toNumber(style.borderTopWidth);\n const borderLeftW = toNumber(style.borderLeftWidth);\n const borderRightW = toNumber(style.borderRightWidth);\n const contentX = x + paddingLeft + borderLeftW;\n const contentY = y + paddingTop + borderTopW;\n const contentWidth =\n width - paddingLeft - paddingRight - borderLeftW - borderRightW;\n const textLayout = layoutText(\n node.textContent,\n style,\n contentWidth,\n ctx,\n !!emojiStyle,\n );\n await drawText(\n ctx,\n textLayout.segments,\n contentX,\n contentY,\n style.textShadow,\n emojiStyle,\n );\n }\n\n if (node.type === \"img\" && node.props.src) {\n const paddingTop = toNumber(style.paddingTop);\n const paddingLeft = toNumber(style.paddingLeft);\n const paddingRight = toNumber(style.paddingRight);\n const paddingBottom = toNumber(style.paddingBottom);\n const imgX = x + paddingLeft;\n const imgY = y + paddingTop;\n const imgW = width - paddingLeft - paddingRight;\n const imgH = height - paddingTop - paddingBottom;\n if (!isClipped) {\n const borderRadius = getBorderRadiusFromStyle(style);\n if (\n borderRadius.topLeft > 0 ||\n borderRadius.topRight > 0 ||\n borderRadius.bottomRight > 0 ||\n borderRadius.bottomLeft > 0\n ) {\n applyClip(ctx, imgX, imgY, imgW, imgH, borderRadius);\n }\n }\n await drawImage(\n ctx,\n node.props.src as string | Buffer,\n imgX,\n imgY,\n imgW,\n imgH,\n style,\n node.props.__loadedImage as Image | undefined,\n );\n }\n\n if (node.type === \"svg\") {\n drawSvgContainer(ctx, node, x, y, width, height);\n } else {\n // Children use offset 0 since x,y already incorporates the offset\n for (const child of node.children) {\n await drawNodeInner(ctx, child, x, y, 0, 0, debug, emojiStyle, undefined);\n }\n }\n\n ctx.restore();\n}\n\nfunction applyTransform(\n ctx: SKRSContext2D,\n transform: string,\n x: number,\n y: number,\n width: number,\n height: number,\n transformOrigin?: string,\n): void {\n // Resolve transform-origin (default: center)\n let ox = x + width / 2;\n let oy = y + height / 2;\n\n if (transformOrigin) {\n const parts = transformOrigin.split(/\\s+/);\n ox = resolveOrigin(parts[0], x, width);\n oy = resolveOrigin(parts[1], y, height);\n }\n\n ctx.translate(ox, oy);\n\n // Parse and apply transform functions\n const funcs = transform.matchAll(/(\\w+)\\(([^)]+)\\)/g);\n\n for (const [, name, args] of funcs) {\n const values = args!.split(\",\").map((s) => s.trim());\n\n switch (name) {\n case \"translate\":\n case \"translateX\":\n case \"translateY\": {\n const tx = name === \"translateY\" ? 0 : parseFloat(values[0]!);\n const ty =\n name === \"translateX\"\n ? 0\n : parseFloat(values[name === \"translate\" ? 1 : 0] ?? \"0\");\n ctx.translate(tx, ty);\n break;\n }\n case \"scale\":\n case \"scaleX\":\n case \"scaleY\": {\n const sx = name === \"scaleY\" ? 1 : parseFloat(values[0]!);\n const sy =\n name === \"scaleX\"\n ? 1\n : parseFloat(values[name === \"scale\" ? 1 : 0] ?? String(sx));\n ctx.scale(sx, sy);\n break;\n }\n case \"rotate\": {\n const angle = parseAngle(values[0]!);\n ctx.rotate(angle);\n break;\n }\n case \"skewX\": {\n const angle = parseAngle(values[0]!);\n ctx.transform(1, 0, Math.tan(angle), 1, 0, 0);\n break;\n }\n case \"skewY\": {\n const angle = parseAngle(values[0]!);\n ctx.transform(1, Math.tan(angle), 0, 1, 0, 0);\n break;\n }\n }\n }\n\n ctx.translate(-ox, -oy);\n}\n\nfunction resolveOrigin(\n value: string | undefined,\n base: number,\n size: number,\n): number {\n if (!value) return base + size / 2;\n if (value === \"left\" || value === \"top\") return base;\n if (value === \"right\" || value === \"bottom\") return base + size;\n if (value === \"center\") return base + size / 2;\n if (value.endsWith(\"%\")) return base + (parseFloat(value) / 100) * size;\n return base + parseFloat(value);\n}\n\nfunction parseAngle(value: string): number {\n if (value.endsWith(\"deg\")) return (parseFloat(value) * Math.PI) / 180;\n if (value.endsWith(\"rad\")) return parseFloat(value);\n if (value.endsWith(\"turn\")) return parseFloat(value) * 2 * Math.PI;\n return parseFloat(value);\n}\n\nfunction toNumber(v: unknown): number {\n if (typeof v === \"number\") return v;\n if (v === undefined || v === null) return 0;\n const n = parseFloat(String(v));\n return isNaN(n) ? 0 : n;\n}\n","// This file contains code adapted from Satori (https://github.com/vercel/satori)\n// Licensed under the Mozilla Public License 2.0 (MPL-2.0)\n// See NOTICE.md in the package root for details.\n\n/**\n * Detect the primary script/language of a text string.\n * Used for font selection and line-breaking behavior.\n */\nexport function detectLanguageCode(text: string): string | undefined {\n for (const char of text) {\n const cp = char.codePointAt(0);\n if (cp === undefined) continue;\n\n // CJK Unified Ideographs\n if (cp >= 0x4e00 && cp <= 0x9fff) return \"zh\";\n // CJK Extension A\n if (cp >= 0x3400 && cp <= 0x4dbf) return \"zh\";\n // Hiragana\n if (cp >= 0x3040 && cp <= 0x309f) return \"ja\";\n // Katakana\n if (cp >= 0x30a0 && cp <= 0x30ff) return \"ja\";\n // Hangul Syllables\n if (cp >= 0xac00 && cp <= 0xd7af) return \"ko\";\n // Hangul Jamo\n if (cp >= 0x1100 && cp <= 0x11ff) return \"ko\";\n // Thai\n if (cp >= 0x0e00 && cp <= 0x0e7f) return \"th\";\n // Arabic\n if (cp >= 0x0600 && cp <= 0x06ff) return \"ar\";\n // Hebrew\n if (cp >= 0x0590 && cp <= 0x05ff) return \"he\";\n // Devanagari\n if (cp >= 0x0900 && cp <= 0x097f) return \"hi\";\n // Bengali\n if (cp >= 0x0980 && cp <= 0x09ff) return \"bn\";\n // Tamil\n if (cp >= 0x0b80 && cp <= 0x0bff) return \"ta\";\n // Telugu\n if (cp >= 0x0c00 && cp <= 0x0c7f) return \"te\";\n // Kannada\n if (cp >= 0x0c80 && cp <= 0x0cff) return \"kn\";\n // Malayalam\n if (cp >= 0x0d00 && cp <= 0x0d7f) return \"ml\";\n }\n\n return undefined;\n}\n\n/**\n * Check if a character is an emoji.\n */\nexport function isEmoji(char: string): boolean {\n const cp = char.codePointAt(0);\n if (cp === undefined) return false;\n\n // Common emoji ranges\n if (cp >= 0x1f600 && cp <= 0x1f64f) return true; // Emoticons\n if (cp >= 0x1f300 && cp <= 0x1f5ff) return true; // Misc Symbols & Pictographs\n if (cp >= 0x1f680 && cp <= 0x1f6ff) return true; // Transport & Map\n if (cp >= 0x1f900 && cp <= 0x1f9ff) return true; // Supplemental Symbols\n if (cp >= 0x2600 && cp <= 0x26ff) return true; // Misc Symbols\n if (cp >= 0x2700 && cp <= 0x27bf) return true; // Dingbats\n if (cp >= 0x2b50 && cp <= 0x2b55) return true; // Misc Symbols & Arrows (star, circle)\n if (cp >= 0x200d && cp <= 0x200d) return true; // Zero Width Joiner\n if (cp >= 0xfe00 && cp <= 0xfe0f) return true; // Variation Selectors\n if (cp >= 0x1fa00 && cp <= 0x1fa6f) return true; // Chess Symbols\n if (cp >= 0x1fa70 && cp <= 0x1faff) return true; // Symbols Extended-A\n if (cp >= 0x231a && cp <= 0x23f3) return true; // Misc Technical (watch, hourglass)\n if (cp >= 0x23e9 && cp <= 0x23fa) return true; // Misc Technical (play, pause)\n if (cp >= 0x25aa && cp <= 0x25fe) return true; // Geometric Shapes\n if (cp >= 0x2934 && cp <= 0x2935) return true; // Arrows\n if (cp >= 0x2b05 && cp <= 0x2b07) return true; // Arrows\n if (cp >= 0x3030 && cp <= 0x3030) return true; // Wavy dash\n if (cp >= 0x303d && cp <= 0x303d) return true; // Part alternation mark\n if (cp >= 0x3297 && cp <= 0x3299) return true; // CJK symbols\n\n return false;\n}\n","import LineBreaker from \"linebreak\";\n\nexport type BreakOpportunity = {\n position: number;\n required: boolean;\n};\n\n/**\n * Find line-break opportunities in text using UAX #14 algorithm.\n *\n * @param text - The text to analyze\n * @returns Array of break opportunities with positions and whether they're required (hard breaks)\n */\nexport function findBreakOpportunities(text: string): BreakOpportunity[] {\n const breaker = new LineBreaker(text);\n const opportunities: BreakOpportunity[] = [];\n\n let bk = breaker.nextBreak();\n while (bk) {\n opportunities.push({\n position: bk.position,\n required: bk.required ?? false,\n });\n bk = breaker.nextBreak();\n }\n\n return opportunities;\n}\n","import { createCanvas } from \"@napi-rs/canvas\";\nimport type { SKRSContext2D } from \"@napi-rs/canvas\";\n\nexport type TextMetrics = {\n width: number;\n ascent: number;\n descent: number;\n height: number;\n};\n\n// Scratch canvas for text measurement when no ctx is available\nlet scratchCtx: SKRSContext2D | null = null;\n\nfunction getScratchCtx(): SKRSContext2D {\n if (!scratchCtx) {\n scratchCtx = createCanvas(1, 1).getContext(\"2d\");\n }\n return scratchCtx;\n}\n\n/**\n * Set font properties on a canvas context for measurement.\n */\nexport function setFont(\n ctx: SKRSContext2D,\n fontSize: number,\n fontFamily: string,\n fontWeight: number | string = 400,\n fontStyle: string = \"normal\",\n): void {\n ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily}`;\n}\n\n/**\n * Measure text using the canvas ctx.measureText() API.\n * Returns width, ascent, descent, and total height.\n */\nexport function measureText(\n text: string,\n fontSize: number,\n fontFamily: string,\n fontWeight: number | string = 400,\n fontStyle: string = \"normal\",\n ctx?: SKRSContext2D,\n): TextMetrics {\n const c = ctx ?? getScratchCtx();\n setFont(c, fontSize, fontFamily, fontWeight, fontStyle);\n\n const m = c.measureText(text);\n\n const ascent =\n m.fontBoundingBoxAscent ?? m.actualBoundingBoxAscent ?? fontSize * 0.8;\n const descent =\n m.fontBoundingBoxDescent ?? m.actualBoundingBoxDescent ?? fontSize * 0.2;\n\n return {\n width: m.width,\n ascent,\n descent,\n height: ascent + descent,\n };\n}\n\n/**\n * Measure the width of a single word.\n */\nexport function measureWord(\n word: string,\n fontSize: number,\n fontFamily: string,\n fontWeight: number | string = 400,\n fontStyle: string = \"normal\",\n ctx?: SKRSContext2D,\n letterSpacing: number = 0,\n): number {\n const base = measureText(\n word,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n ).width;\n if (letterSpacing === 0 || word.length === 0) return base;\n return base + letterSpacing * word.length;\n}\n","// This file contains code adapted from Satori (https://github.com/vercel/satori)\n// Licensed under the Mozilla Public License 2.0 (MPL-2.0)\n// See NOTICE.md in the package root for details.\n\nimport type { SKRSContext2D } from \"@napi-rs/canvas\";\n\nimport type { ComputedStyle } from \"../style/compute.ts\";\nimport { isEmoji } from \"../language.ts\";\nimport { findBreakOpportunities } from \"./linebreak.ts\";\nimport { measureText, measureWord } from \"./measure.ts\";\nimport type { TextMetrics } from \"./measure.ts\";\n\nexport type TextSegment = {\n text: string;\n x: number;\n y: number;\n width: number;\n height: number;\n fontSize: number;\n fontFamily: string;\n fontWeight: number | string;\n fontStyle: string;\n color: string;\n ascent: number;\n textDecoration?: string;\n letterSpacing: number;\n lineIndex: number;\n};\n\nexport type TextLayoutResult = {\n segments: TextSegment[];\n width: number;\n height: number;\n};\n\n/**\n * Measure the width of a word, accounting for emoji characters when enabled.\n * Emoji characters are treated as square images sized to fontSize.\n */\nfunction emojiAwareMeasureWord(\n word: string,\n fontSize: number,\n fontFamily: string,\n fontWeight: number | string,\n fontStyle: string,\n ctx?: SKRSContext2D,\n letterSpacing: number = 0,\n): number {\n const segmenter = new Intl.Segmenter(undefined, { granularity: \"grapheme\" });\n let totalWidth = 0;\n let textBuffer = \"\";\n\n for (const { segment } of segmenter.segment(word)) {\n let isEmojiSegment = false;\n for (const char of segment) {\n if (isEmoji(char)) {\n isEmojiSegment = true;\n break;\n }\n }\n\n if (isEmojiSegment) {\n if (textBuffer) {\n totalWidth += measureWord(\n textBuffer,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n letterSpacing,\n );\n textBuffer = \"\";\n }\n totalWidth += fontSize;\n } else {\n textBuffer += segment;\n }\n }\n\n if (textBuffer) {\n totalWidth += measureWord(\n textBuffer,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n letterSpacing,\n );\n }\n\n return totalWidth;\n}\n\n/**\n * Lay out text content into positioned segments with line-breaking.\n *\n * @param text - The text to lay out\n * @param style - Computed style\n * @param maxWidth - Maximum width for wrapping\n * @param ctx - Canvas context for measurement\n * @param emojiEnabled - Whether to use emoji-aware measurement\n * @returns Text segments with positions and total dimensions\n */\nexport function layoutText(\n text: string,\n style: ComputedStyle,\n maxWidth: number,\n ctx?: SKRSContext2D,\n emojiEnabled?: boolean,\n): TextLayoutResult {\n const fontSize = style.fontSize ?? 16;\n const fontFamily = style.fontFamily ?? \"sans-serif\";\n const fontWeight = style.fontWeight ?? 400;\n const fontStyle = style.fontStyle ?? \"normal\";\n const color = style.color ?? \"black\";\n const textAlign = style.textAlign ?? \"left\";\n // Measure reference metrics for \"normal\" lineHeight (font ascent + descent)\n const refMetrics = measureText(\n \"M\",\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n );\n const lineHeightPx = resolveLineHeight(\n style.lineHeight,\n fontSize,\n refMetrics,\n );\n const letterSpacing =\n typeof style.letterSpacing === \"number\" ? style.letterSpacing : 0;\n const whiteSpace = style.whiteSpace ?? \"normal\";\n const wordBreak = style.wordBreak ?? \"normal\";\n const textOverflow = style.textOverflow ?? \"clip\";\n const textDecoration = style.textDecoration;\n\n // Choose measurement function based on emoji mode\n const measure = emojiEnabled\n ? (word: string, ls?: number) =>\n emojiAwareMeasureWord(\n word,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n ls ?? letterSpacing,\n )\n : (word: string, ls?: number) =>\n measureWord(\n word,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n ls ?? letterSpacing,\n );\n\n // Apply text transform\n let processedText = text;\n if (style.textTransform === \"uppercase\") {\n processedText = text.toUpperCase();\n } else if (style.textTransform === \"lowercase\") {\n processedText = text.toLowerCase();\n } else if (style.textTransform === \"capitalize\") {\n processedText = text.replace(/\\b\\w/g, (c) => c.toUpperCase());\n }\n\n const noWrap = whiteSpace === \"nowrap\" || whiteSpace === \"pre\";\n const preserveWhitespace = whiteSpace === \"pre\" || whiteSpace === \"pre-wrap\";\n\n // Split by explicit newlines\n const paragraphs = preserveWhitespace\n ? processedText.split(\"\\n\")\n : processedText.split(\"\\n\");\n\n const lines: string[] = [];\n\n for (const paragraph of paragraphs) {\n if (noWrap) {\n lines.push(paragraph);\n continue;\n }\n\n // Wrap text\n const wrapped = wrapText(\n paragraph,\n maxWidth,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n letterSpacing,\n wordBreak,\n ctx,\n measure,\n );\n lines.push(...wrapped);\n }\n\n // Handle text-overflow: ellipsis\n if (textOverflow === \"ellipsis\" && noWrap && lines.length === 1) {\n const line = lines[0]!;\n const lineWidth = measure(line);\n if (lineWidth > maxWidth) {\n lines[0] = truncateWithEllipsis(\n line,\n maxWidth,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n letterSpacing,\n );\n }\n }\n\n // Create positioned segments\n const segments: TextSegment[] = [];\n let totalHeight = 0;\n let maxLineWidth = 0;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n const lineWidth = measure(line);\n\n let x = 0;\n if (textAlign === \"center\") {\n x = (maxWidth - lineWidth) / 2;\n } else if (textAlign === \"right\") {\n x = maxWidth - lineWidth;\n }\n\n const metrics = measureText(\n line || \"M\",\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n );\n\n segments.push({\n text: line,\n x,\n y: totalHeight + (lineHeightPx + metrics.ascent - metrics.descent) / 2,\n width: lineWidth,\n height: lineHeightPx,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n color,\n ascent: metrics.ascent,\n textDecoration,\n letterSpacing,\n lineIndex: i,\n });\n\n totalHeight += lineHeightPx;\n maxLineWidth = Math.max(maxLineWidth, lineWidth);\n }\n\n return {\n segments,\n width: maxLineWidth,\n height: totalHeight,\n };\n}\n\nfunction resolveLineHeight(\n lineHeight: number | string | undefined,\n fontSize: number,\n metrics?: TextMetrics,\n): number {\n if (lineHeight === undefined || lineHeight === \"normal\") {\n // CSS \"normal\": use font ascent + descent (matches satori behaviour)\n return metrics ? metrics.ascent + metrics.descent : fontSize * 1.2;\n }\n if (typeof lineHeight === \"number\") {\n // Already resolved to px in compute.ts if > 5, else multiplier\n return lineHeight > 5 ? lineHeight : lineHeight * fontSize;\n }\n const parsed = parseFloat(String(lineHeight));\n return isNaN(parsed) ? fontSize * 1.2 : parsed;\n}\n\nfunction wrapText(\n text: string,\n maxWidth: number,\n fontSize: number,\n fontFamily: string,\n fontWeight: number | string,\n fontStyle: string,\n letterSpacing: number,\n wordBreak: string,\n ctx?: SKRSContext2D,\n measureFn?: (word: string, ls?: number) => number,\n): string[] {\n if (!text) return [\"\"];\n\n const mw =\n measureFn ??\n ((word: string) =>\n measureWord(\n word,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n letterSpacing,\n ));\n\n const breakOpps = findBreakOpportunities(text);\n const lines: string[] = [];\n let lineStart = 0;\n let lastBreak = 0;\n\n for (const opp of breakOpps) {\n const segment = text.slice(lineStart, opp.position);\n const segWidth = mw(segment);\n\n if (segWidth > maxWidth && lastBreak > lineStart) {\n // Line overflows — break at last opportunity\n const line = text.slice(lineStart, lastBreak).replace(/\\s+$/, \"\");\n lines.push(line);\n lineStart = lastBreak;\n } else if (segWidth > maxWidth && wordBreak === \"break-all\") {\n // Force break within word\n const broken = forceBreakWord(\n text,\n lineStart,\n opp.position,\n maxWidth,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n letterSpacing,\n measureFn,\n );\n lines.push(...broken.lines);\n lineStart = broken.endPos;\n }\n\n if (opp.required) {\n // Hard break (newline)\n const line = text.slice(lineStart, opp.position).replace(/\\s+$/, \"\");\n lines.push(line);\n lineStart = opp.position;\n }\n\n lastBreak = opp.position;\n }\n\n // Remaining text\n if (lineStart < text.length) {\n const remaining = text.slice(lineStart).replace(/\\s+$/, \"\");\n if (remaining) {\n const remWidth = mw(remaining);\n if (remWidth > maxWidth && wordBreak === \"break-all\") {\n const broken = forceBreakWord(\n text,\n lineStart,\n text.length,\n maxWidth,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n letterSpacing,\n measureFn,\n );\n lines.push(...broken.lines);\n } else {\n lines.push(remaining);\n }\n }\n }\n\n return lines.length > 0 ? lines : [\"\"];\n}\n\nfunction forceBreakWord(\n text: string,\n start: number,\n end: number,\n maxWidth: number,\n fontSize: number,\n fontFamily: string,\n fontWeight: number | string,\n fontStyle: string,\n ctx?: SKRSContext2D,\n letterSpacing: number = 0,\n measureFn?: (word: string, ls?: number) => number,\n): { lines: string[]; endPos: number } {\n const mw =\n measureFn ??\n ((word: string) =>\n measureWord(\n word,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n letterSpacing,\n ));\n const lines: string[] = [];\n let pos = start;\n\n while (pos < end) {\n let breakPos = pos + 1;\n while (breakPos < end) {\n const chunk = text.slice(pos, breakPos + 1);\n const w = mw(chunk);\n if (w > maxWidth) break;\n breakPos++;\n }\n\n const line = text.slice(pos, breakPos);\n if (line.trim()) lines.push(line);\n pos = breakPos;\n }\n\n return { lines, endPos: end };\n}\n\nfunction truncateWithEllipsis(\n text: string,\n maxWidth: number,\n fontSize: number,\n fontFamily: string,\n fontWeight: number | string,\n fontStyle: string,\n ctx?: SKRSContext2D,\n letterSpacing: number = 0,\n): string {\n const ellipsis = \"\\u2026\";\n const ellipsisWidth = measureWord(\n ellipsis,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n letterSpacing,\n );\n const availWidth = maxWidth - ellipsisWidth;\n\n for (let i = text.length - 1; i > 0; i--) {\n const truncated = text.slice(0, i);\n const w = measureWord(\n truncated,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n ctx,\n letterSpacing,\n );\n if (w <= availWidth) {\n return truncated + ellipsis;\n }\n }\n\n return ellipsis;\n}\n\n/**\n * Yoga-compatible measure function for text nodes.\n * Returns the dimensions needed for the text content.\n */\nexport function createTextMeasureFunc(\n text: string,\n style: ComputedStyle,\n ctx?: SKRSContext2D,\n emojiEnabled?: boolean,\n) {\n // Strip textOverflow during measurement so ellipsis truncation doesn't\n // shrink the reported width below the Yoga constraint. The draw phase\n // still uses the original style (with textOverflow) for rendering.\n const measureStyle = { ...style, textOverflow: \"clip\" as const };\n return (\n width: number,\n _widthMode: number,\n _height: number,\n _heightMode: number,\n ) => {\n const maxWidth = width > 0 ? width : Infinity;\n const result = layoutText(text, measureStyle, maxWidth, ctx, emojiEnabled);\n // When text wraps to multiple lines, return the constraint width (like CSS\n // block layout). This ensures the draw phase re-layout gets the same\n // maxWidth and produces identical line-breaking. Without this, the\n // measured content width (widest trimmed line) can be narrower than what\n // the wrapping algorithm needs (it checks untrimmed segments), causing the\n // draw phase to wrap differently.\n const wrapped = result.segments.length > 1;\n const reportedWidth = wrapped\n ? Math.min(maxWidth, width > 0 ? width : result.width)\n : result.width;\n return { width: Math.min(reportedWidth, maxWidth), height: result.height };\n };\n}\n","import type { SKRSContext2D } from \"@napi-rs/canvas\";\n\n/**\n * Apply overflow:hidden clipping to a canvas context.\n * Creates a rectangular clip path with optional border-radius.\n */\nexport function applyClip(\n ctx: SKRSContext2D,\n x: number,\n y: number,\n width: number,\n height: number,\n borderRadius?: {\n topLeft: number;\n topRight: number;\n bottomRight: number;\n bottomLeft: number;\n },\n): void {\n ctx.beginPath();\n\n if (borderRadius && hasRadius(borderRadius)) {\n const { topLeft, topRight, bottomRight, bottomLeft } = borderRadius;\n roundedRect(\n ctx,\n x,\n y,\n width,\n height,\n topLeft,\n topRight,\n bottomRight,\n bottomLeft,\n );\n } else {\n ctx.rect(x, y, width, height);\n }\n\n ctx.clip();\n}\n\n/**\n * Draw a rounded rectangle path on the context.\n */\nexport function roundedRect(\n ctx: SKRSContext2D,\n x: number,\n y: number,\n w: number,\n h: number,\n tl: number,\n tr: number,\n br: number,\n bl: number,\n): void {\n // Clamp radii to half the smallest dimension\n const maxR = Math.min(w, h) / 2;\n tl = Math.min(tl, maxR);\n tr = Math.min(tr, maxR);\n br = Math.min(br, maxR);\n bl = Math.min(bl, maxR);\n\n ctx.moveTo(x + tl, y);\n ctx.lineTo(x + w - tr, y);\n if (tr > 0) ctx.arcTo(x + w, y, x + w, y + tr, tr);\n ctx.lineTo(x + w, y + h - br);\n if (br > 0) ctx.arcTo(x + w, y + h, x + w - br, y + h, br);\n ctx.lineTo(x + bl, y + h);\n if (bl > 0) ctx.arcTo(x, y + h, x, y + h - bl, bl);\n ctx.lineTo(x, y + tl);\n if (tl > 0) ctx.arcTo(x, y, x + tl, y, tl);\n ctx.closePath();\n}\n\nfunction hasRadius(r: {\n topLeft: number;\n topRight: number;\n bottomRight: number;\n bottomLeft: number;\n}): boolean {\n return (\n r.topLeft > 0 || r.topRight > 0 || r.bottomRight > 0 || r.bottomLeft > 0\n );\n}\n","import type { SKRSContext2D } from \"@napi-rs/canvas\";\n\n/**\n * Parse and create a canvas gradient from a CSS gradient string.\n * Supports linear-gradient and radial-gradient.\n *\n * @returns A CanvasGradient or null if parsing fails\n */\nexport function createGradientFromCSS(\n ctx: SKRSContext2D,\n cssGradient: string,\n x: number,\n y: number,\n width: number,\n height: number,\n): CanvasGradient | null {\n const trimmed = cssGradient.trim();\n\n if (trimmed.startsWith(\"linear-gradient\")) {\n return parseLinearGradient(ctx, trimmed, x, y, width, height);\n }\n\n if (trimmed.startsWith(\"radial-gradient\")) {\n return parseRadialGradient(ctx, trimmed, x, y, width, height);\n }\n\n return null;\n}\n\nfunction parseLinearGradient(\n ctx: SKRSContext2D,\n css: string,\n x: number,\n y: number,\n width: number,\n height: number,\n): CanvasGradient | null {\n // Extract content between parentheses\n const match = css.match(/linear-gradient\\((.*)\\)/s);\n if (!match) return null;\n\n const content = match[1]!.trim();\n const parts = splitGradientArgs(content);\n\n let angle = 180; // default: to bottom\n let colorStartIdx = 0;\n\n // Parse direction\n const first = parts[0]?.trim();\n if (first) {\n if (first.startsWith(\"to \")) {\n angle = directionToAngle(first);\n colorStartIdx = 1;\n } else if (first.endsWith(\"deg\")) {\n angle = parseFloat(first);\n colorStartIdx = 1;\n } else if (first.endsWith(\"turn\")) {\n angle = parseFloat(first) * 360;\n colorStartIdx = 1;\n }\n }\n\n // Calculate gradient line endpoints\n const rad = ((angle - 90) * Math.PI) / 180;\n const cx = x + width / 2;\n const cy = y + height / 2;\n const halfDiag =\n Math.abs(width * Math.cos(rad)) / 2 + Math.abs(height * Math.sin(rad)) / 2;\n\n const x0 = cx - halfDiag * Math.cos(rad);\n const y0 = cy - halfDiag * Math.sin(rad);\n const x1 = cx + halfDiag * Math.cos(rad);\n const y1 = cy + halfDiag * Math.sin(rad);\n\n const gradient = ctx.createLinearGradient(x0, y0, x1, y1);\n\n // Parse color stops\n const stops = parts.slice(colorStartIdx);\n addColorStops(gradient, stops);\n\n return gradient;\n}\n\nfunction parseRadialGradient(\n ctx: SKRSContext2D,\n css: string,\n x: number,\n y: number,\n width: number,\n height: number,\n): CanvasGradient | null {\n const match = css.match(/radial-gradient\\((.*)\\)/s);\n if (!match) return null;\n\n const content = match[1]!.trim();\n const parts = splitGradientArgs(content);\n\n const cx = x + width / 2;\n const cy = y + height / 2;\n const radius = Math.max(width, height) / 2;\n\n const gradient = ctx.createRadialGradient(cx, cy, 0, cx, cy, radius);\n\n // Simple parsing: skip shape/size/position, just get color stops\n let colorStartIdx = 0;\n const first = parts[0]?.trim() ?? \"\";\n if (\n first.startsWith(\"circle\") ||\n first.startsWith(\"ellipse\") ||\n first.startsWith(\"closest\") ||\n first.startsWith(\"farthest\")\n ) {\n colorStartIdx = 1;\n }\n\n addColorStops(gradient, parts.slice(colorStartIdx));\n\n return gradient;\n}\n\nfunction addColorStops(gradient: CanvasGradient, stops: string[]): void {\n if (stops.length === 0) return;\n\n for (let i = 0; i < stops.length; i++) {\n const stop = stops[i]!.trim();\n const percentMatch = stop.match(/^(.+?)\\s+(\\d+(?:\\.\\d+)?%?)$/);\n\n if (percentMatch) {\n const color = percentMatch[1]!;\n const pos = percentMatch[2]!;\n const offset = pos.endsWith(\"%\")\n ? parseFloat(pos) / 100\n : parseFloat(pos);\n gradient.addColorStop(Math.max(0, Math.min(1, offset)), color);\n } else {\n // Auto-distribute\n const offset = stops.length === 1 ? 0.5 : i / (stops.length - 1);\n gradient.addColorStop(offset, stop);\n }\n }\n}\n\nfunction directionToAngle(dir: string): number {\n const map: Record<string, number> = {\n \"to top\": 0,\n \"to right\": 90,\n \"to bottom\": 180,\n \"to left\": 270,\n \"to top right\": 45,\n \"to top left\": 315,\n \"to bottom right\": 135,\n \"to bottom left\": 225,\n };\n return map[dir] ?? 180;\n}\n\nfunction splitGradientArgs(content: string): string[] {\n const parts: string[] = [];\n let current = \"\";\n let parenDepth = 0;\n\n for (const char of content) {\n if (char === \"(\") parenDepth++;\n if (char === \")\") parenDepth--;\n if (char === \",\" && parenDepth === 0) {\n parts.push(current);\n current = \"\";\n } else {\n current += char;\n }\n }\n if (current.trim()) parts.push(current);\n\n return parts;\n}\n","import { loadImage } from \"@napi-rs/canvas\";\nimport type { Image, SKRSContext2D } from \"@napi-rs/canvas\";\n\nimport type { ComputedStyle } from \"../style/compute.ts\";\nimport { computeContain, computeCover } from \"./object-fit.ts\";\n\n/**\n * Draw an image element onto the canvas.\n *\n * @param ctx - Canvas rendering context\n * @param src - Image source (URL, file path, or Buffer)\n * @param x - X position\n * @param y - Y position\n * @param width - Target width\n * @param height - Target height\n * @param style - Computed style (for objectFit)\n */\nexport async function drawImage(\n ctx: SKRSContext2D,\n src: string | Buffer,\n x: number,\n y: number,\n width: number,\n height: number,\n style?: ComputedStyle,\n preloadedImage?: Image,\n): Promise<void> {\n const image = preloadedImage ?? (await loadImage(src));\n const objectFit = style?.objectFit ?? \"fill\";\n\n if (objectFit === \"fill\") {\n ctx.drawImage(image, x, y, width, height);\n return;\n }\n\n const imgW = image.width;\n const imgH = image.height;\n\n if (objectFit === \"contain\") {\n const r = computeContain(imgW, imgH, x, y, width, height);\n ctx.drawImage(image, r.dx, r.dy, r.dw, r.dh);\n } else if (objectFit === \"cover\") {\n const r = computeCover(imgW, imgH, x, y, width, height);\n ctx.drawImage(image, r.sx, r.sy, r.sw, r.sh, r.dx, r.dy, r.dw, r.dh);\n } else if (objectFit === \"none\") {\n const dx = x + (width - imgW) / 2;\n const dy = y + (height - imgH) / 2;\n ctx.drawImage(image, dx, dy);\n } else if (objectFit === \"scale-down\") {\n if (imgW <= width && imgH <= height) {\n const dx = x + (width - imgW) / 2;\n const dy = y + (height - imgH) / 2;\n ctx.drawImage(image, dx, dy);\n } else {\n const r = computeContain(imgW, imgH, x, y, width, height);\n ctx.drawImage(image, r.dx, r.dy, r.dw, r.dh);\n }\n }\n}\n","/**\n * Shared cover/contain sizing logic used by both `<img>` objectFit\n * and `backgroundImage` + `backgroundSize`.\n */\n\nexport interface FitRect {\n sx: number;\n sy: number;\n sw: number;\n sh: number;\n dx: number;\n dy: number;\n dw: number;\n dh: number;\n}\n\n/**\n * Compute source and destination rectangles for \"cover\" sizing.\n * The image fills the box completely, cropping the excess.\n */\nexport function computeCover(\n imgW: number,\n imgH: number,\n boxX: number,\n boxY: number,\n boxW: number,\n boxH: number,\n): FitRect {\n const imgRatio = imgW / imgH;\n const boxRatio = boxW / boxH;\n\n let sx: number, sy: number, sw: number, sh: number;\n\n if (imgRatio > boxRatio) {\n sh = imgH;\n sw = imgH * boxRatio;\n sx = (imgW - sw) / 2;\n sy = 0;\n } else {\n sw = imgW;\n sh = imgW / boxRatio;\n sx = 0;\n sy = (imgH - sh) / 2;\n }\n\n return { sx, sy, sw, sh, dx: boxX, dy: boxY, dw: boxW, dh: boxH };\n}\n\n/**\n * Compute destination rectangle for \"contain\" sizing.\n * The image fits entirely within the box, centered, with no cropping.\n */\nexport function computeContain(\n imgW: number,\n imgH: number,\n boxX: number,\n boxY: number,\n boxW: number,\n boxH: number,\n): FitRect {\n const imgRatio = imgW / imgH;\n const boxRatio = boxW / boxH;\n\n let dw: number, dh: number;\n\n if (imgRatio > boxRatio) {\n dw = boxW;\n dh = boxW / imgRatio;\n } else {\n dh = boxH;\n dw = boxH * imgRatio;\n }\n\n const dx = boxX + (boxW - dw) / 2;\n const dy = boxY + (boxH - dh) / 2;\n\n return { sx: 0, sy: 0, sw: imgW, sh: imgH, dx, dy, dw, dh };\n}\n","import type { SKRSContext2D } from \"@napi-rs/canvas\";\n\nimport type { ComputedStyle } from \"../style/compute.ts\";\nimport { roundedRect } from \"./clip.ts\";\n\n/**\n * Draw the background, borders, and box-shadow for a rectangular element.\n */\nexport function drawRect(\n ctx: SKRSContext2D,\n x: number,\n y: number,\n width: number,\n height: number,\n style: ComputedStyle,\n): void {\n const borderRadius = getBorderRadius(style);\n const hasRoundedCorners =\n borderRadius.topLeft > 0 ||\n borderRadius.topRight > 0 ||\n borderRadius.bottomRight > 0 ||\n borderRadius.bottomLeft > 0;\n\n // Box shadow (drawn before background)\n if (style.boxShadow) {\n drawBoxShadow(ctx, x, y, width, height, style.boxShadow, borderRadius);\n }\n\n // Background\n if (style.backgroundColor) {\n ctx.fillStyle = style.backgroundColor;\n\n if (hasRoundedCorners) {\n ctx.beginPath();\n roundedRect(\n ctx,\n x,\n y,\n width,\n height,\n borderRadius.topLeft,\n borderRadius.topRight,\n borderRadius.bottomRight,\n borderRadius.bottomLeft,\n );\n ctx.fill();\n } else {\n ctx.fillRect(x, y, width, height);\n }\n }\n\n // Borders\n drawBorders(ctx, x, y, width, height, style, borderRadius);\n}\n\nfunction getBorderRadius(style: ComputedStyle) {\n return {\n topLeft: toNumber(style.borderTopLeftRadius),\n topRight: toNumber(style.borderTopRightRadius),\n bottomRight: toNumber(style.borderBottomRightRadius),\n bottomLeft: toNumber(style.borderBottomLeftRadius),\n };\n}\n\nexport function getBorderRadiusFromStyle(style: ComputedStyle) {\n return getBorderRadius(style);\n}\n\nfunction drawBorders(\n ctx: SKRSContext2D,\n x: number,\n y: number,\n width: number,\n height: number,\n style: ComputedStyle,\n borderRadius: ReturnType<typeof getBorderRadius>,\n): void {\n const hasRoundedCorners =\n borderRadius.topLeft > 0 ||\n borderRadius.topRight > 0 ||\n borderRadius.bottomRight > 0 ||\n borderRadius.bottomLeft > 0;\n\n // If all borders are the same, draw as a single stroke\n const tw = toNumber(style.borderTopWidth);\n const rw = toNumber(style.borderRightWidth);\n const bw = toNumber(style.borderBottomWidth);\n const lw = toNumber(style.borderLeftWidth);\n\n if (tw === 0 && rw === 0 && bw === 0 && lw === 0) return;\n\n const allSameWidth = tw === rw && rw === bw && bw === lw && tw > 0;\n const tc = style.borderTopColor ?? \"black\";\n const rc = style.borderRightColor ?? \"black\";\n const bc = style.borderBottomColor ?? \"black\";\n const lc = style.borderLeftColor ?? \"black\";\n const allSameColor = tc === rc && rc === bc && bc === lc;\n\n if (allSameWidth && allSameColor) {\n ctx.strokeStyle = tc;\n ctx.lineWidth = tw;\n\n if (hasRoundedCorners) {\n ctx.beginPath();\n const half = tw / 2;\n roundedRect(\n ctx,\n x + half,\n y + half,\n width - tw,\n height - tw,\n Math.max(0, borderRadius.topLeft - half),\n Math.max(0, borderRadius.topRight - half),\n Math.max(0, borderRadius.bottomRight - half),\n Math.max(0, borderRadius.bottomLeft - half),\n );\n ctx.stroke();\n } else {\n ctx.strokeRect(x + tw / 2, y + tw / 2, width - tw, height - tw);\n }\n return;\n }\n\n // Draw individual borders\n if (tw > 0) {\n ctx.strokeStyle = tc;\n ctx.lineWidth = tw;\n ctx.beginPath();\n ctx.moveTo(x, y + tw / 2);\n ctx.lineTo(x + width, y + tw / 2);\n ctx.stroke();\n }\n if (rw > 0) {\n ctx.strokeStyle = rc;\n ctx.lineWidth = rw;\n ctx.beginPath();\n ctx.moveTo(x + width - rw / 2, y);\n ctx.lineTo(x + width - rw / 2, y + height);\n ctx.stroke();\n }\n if (bw > 0) {\n ctx.strokeStyle = bc;\n ctx.lineWidth = bw;\n ctx.beginPath();\n ctx.moveTo(x, y + height - bw / 2);\n ctx.lineTo(x + width, y + height - bw / 2);\n ctx.stroke();\n }\n if (lw > 0) {\n ctx.strokeStyle = lc;\n ctx.lineWidth = lw;\n ctx.beginPath();\n ctx.moveTo(x + lw / 2, y);\n ctx.lineTo(x + lw / 2, y + height);\n ctx.stroke();\n }\n}\n\nfunction drawBoxShadow(\n ctx: SKRSContext2D,\n x: number,\n y: number,\n width: number,\n height: number,\n boxShadow: string,\n borderRadius: ReturnType<typeof getBorderRadius>,\n): void {\n // Parse simple box-shadow: offsetX offsetY blur spread? color\n const parts = boxShadow.match(\n /(-?\\d+(?:\\.\\d+)?)\\s*(?:px)?\\s+(-?\\d+(?:\\.\\d+)?)\\s*(?:px)?\\s+(-?\\d+(?:\\.\\d+)?)\\s*(?:px)?(?:\\s+(-?\\d+(?:\\.\\d+)?)\\s*(?:px)?)?\\s+(.*)/,\n );\n if (!parts) return;\n\n const offsetX = parseFloat(parts[1]!);\n const offsetY = parseFloat(parts[2]!);\n const blur = parseFloat(parts[3]!);\n const color = parts[5]!.trim();\n\n const radii = [\n borderRadius.topLeft,\n borderRadius.topRight,\n borderRadius.bottomRight,\n borderRadius.bottomLeft,\n ];\n\n // Clip to area OUTSIDE the element so shadow renders but inner fill is hidden\n const margin = blur * 2 + Math.abs(offsetX) + Math.abs(offsetY);\n ctx.save();\n ctx.beginPath();\n ctx.rect(x - margin, y - margin, width + margin * 2, height + margin * 2);\n ctx.roundRect(x, y, width, height, radii);\n ctx.clip(\"evenodd\");\n\n // Use CSS filter blur (sigma = blur/2) instead of the canvas shadow API\n // because it matches SVG feGaussianBlur (used by satori) much more closely.\n ctx.filter = `blur(${blur / 2}px)`;\n ctx.translate(offsetX, offsetY);\n ctx.fillStyle = color;\n ctx.beginPath();\n ctx.roundRect(x, y, width, height, radii);\n ctx.fill();\n ctx.restore();\n}\n\nfunction toNumber(v: unknown): number {\n if (typeof v === \"number\") return v;\n if (v === undefined || v === null) return 0;\n const n = parseFloat(String(v));\n return isNaN(n) ? 0 : n;\n}\n","import { Path2D } from \"@napi-rs/canvas\";\nimport type { SKRSContext2D } from \"@napi-rs/canvas\";\n\nimport type { LayoutNode } from \"../layout.ts\";\n\ntype SvgChild = {\n type: string;\n props: Record<string, unknown>;\n children?: SvgChild | SvgChild[];\n};\n\n/** Replace `\"currentColor\"` with the inherited CSS `color` value. */\nfunction resolveCurrentColor(\n value: string | undefined,\n color: string,\n): string | undefined {\n if (value?.toLowerCase() === \"currentcolor\") return color;\n return value;\n}\n\n/**\n * Merge SVG presentation properties from `props.style` into the props object.\n * Style values win over direct props, matching browser CSS specificity rules.\n */\nfunction mergeStyleIntoProps(\n props: Record<string, unknown>,\n): Record<string, unknown> {\n const style = props.style as Record<string, unknown> | undefined;\n if (!style) return props;\n return { ...props, ...style };\n}\n\n/**\n * Draw an `<svg>` container and its SVG children (path, circle, rect, etc.).\n *\n * Parses the `viewBox` prop to compute scale factors, then recurses into\n * the React children stored in `node.props.children`.\n */\nexport function drawSvgContainer(\n ctx: SKRSContext2D,\n node: LayoutNode,\n x: number,\n y: number,\n width: number,\n height: number,\n): void {\n ctx.save();\n ctx.translate(x, y);\n\n // Parse viewBox for coordinate mapping\n const viewBox = node.props.viewBox as string | undefined;\n if (viewBox) {\n const parts = viewBox.split(/[\\s,]+/).map(Number);\n if (parts.length === 4) {\n const [vbX, vbY, vbW, vbH] = parts as [number, number, number, number];\n const scaleX = width / vbW;\n const scaleY = height / vbH;\n ctx.scale(scaleX, scaleY);\n ctx.translate(-vbX, -vbY);\n }\n }\n\n // Resolve the CSS `color` property for `currentColor` references\n const color = (node.style.color as string | undefined) ?? \"black\";\n\n // Inherited fill from the <svg> element (SVG fill is inheritable)\n const merged = mergeStyleIntoProps(node.props);\n const inheritedFill =\n resolveCurrentColor(merged.fill as string | undefined, color) ?? \"black\";\n\n // Traverse React children\n const children = node.props.children;\n if (children != null) {\n const childArray = Array.isArray(children) ? children : [children];\n for (const child of childArray) {\n if (child != null && typeof child === \"object\") {\n drawSvgChild(ctx, child as SvgChild, inheritedFill, color);\n }\n }\n }\n\n ctx.restore();\n}\n\nfunction drawSvgChild(\n ctx: SKRSContext2D,\n child: SvgChild,\n inheritedFill: string,\n color: string,\n): void {\n const { type } = child;\n const props = mergeStyleIntoProps(child.props);\n\n switch (type) {\n case \"path\":\n drawPath(ctx, props, inheritedFill, color);\n break;\n case \"circle\":\n drawCircle(ctx, props, inheritedFill, color);\n break;\n case \"rect\":\n drawSvgRect(ctx, props, inheritedFill, color);\n break;\n case \"line\":\n drawLine(ctx, props, color);\n break;\n case \"ellipse\":\n drawEllipse(ctx, props, inheritedFill, color);\n break;\n case \"polygon\":\n drawPolygon(ctx, props, inheritedFill, color);\n break;\n case \"polyline\":\n drawPolyline(ctx, props, inheritedFill, color);\n break;\n case \"g\":\n drawGroup(ctx, child, inheritedFill, color);\n break;\n }\n}\n\nfunction drawPath(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n inheritedFill: string,\n color: string,\n): void {\n const d = props.d as string | undefined;\n if (!d) return;\n\n const path = new Path2D(d);\n applyFillAndStroke(ctx, props, path, inheritedFill, color);\n}\n\nfunction drawCircle(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n inheritedFill: string,\n color: string,\n): void {\n const cx = Number(props.cx ?? 0);\n const cy = Number(props.cy ?? 0);\n const r = Number(props.r ?? 0);\n if (r <= 0) return;\n\n const path = new Path2D();\n path.arc(cx, cy, r, 0, Math.PI * 2);\n applyFillAndStroke(ctx, props, path, inheritedFill, color);\n}\n\nfunction drawSvgRect(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n inheritedFill: string,\n color: string,\n): void {\n const rx = Number(props.x ?? 0);\n const ry = Number(props.y ?? 0);\n const w = Number(props.width ?? 0);\n const h = Number(props.height ?? 0);\n if (w <= 0 || h <= 0) return;\n\n const path = new Path2D();\n path.rect(rx, ry, w, h);\n applyFillAndStroke(ctx, props, path, inheritedFill, color);\n}\n\nfunction drawLine(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n color: string,\n): void {\n const x1 = Number(props.x1 ?? 0);\n const y1 = Number(props.y1 ?? 0);\n const x2 = Number(props.x2 ?? 0);\n const y2 = Number(props.y2 ?? 0);\n\n const path = new Path2D();\n path.moveTo(x1, y1);\n path.lineTo(x2, y2);\n // Lines are stroke-only\n applyStroke(ctx, props, path, color);\n}\n\nfunction drawEllipse(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n inheritedFill: string,\n color: string,\n): void {\n const cx = Number(props.cx ?? 0);\n const cy = Number(props.cy ?? 0);\n const rx = Number(props.rx ?? 0);\n const ry = Number(props.ry ?? 0);\n if (rx <= 0 || ry <= 0) return;\n\n const path = new Path2D();\n path.ellipse(cx, cy, rx, ry, 0, 0, Math.PI * 2);\n applyFillAndStroke(ctx, props, path, inheritedFill, color);\n}\n\nfunction drawPolygon(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n inheritedFill: string,\n color: string,\n): void {\n const points = parsePoints(props.points as string | undefined);\n if (points.length < 2) return;\n\n const path = new Path2D();\n path.moveTo(points[0]![0], points[0]![1]);\n for (let i = 1; i < points.length; i++) {\n path.lineTo(points[i]![0], points[i]![1]);\n }\n path.closePath();\n applyFillAndStroke(ctx, props, path, inheritedFill, color);\n}\n\nfunction drawPolyline(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n inheritedFill: string,\n color: string,\n): void {\n const points = parsePoints(props.points as string | undefined);\n if (points.length < 2) return;\n\n const path = new Path2D();\n path.moveTo(points[0]![0], points[0]![1]);\n for (let i = 1; i < points.length; i++) {\n path.lineTo(points[i]![0], points[i]![1]);\n }\n applyFillAndStroke(ctx, props, path, inheritedFill, color);\n}\n\nfunction drawGroup(\n ctx: SKRSContext2D,\n node: SvgChild,\n inheritedFill: string,\n color: string,\n): void {\n const children =\n node.children ?? (node.props.children as SvgChild | SvgChild[] | undefined);\n if (children == null) return;\n // Group can override inherited fill\n const merged = mergeStyleIntoProps(node.props);\n const groupFill =\n resolveCurrentColor(merged.fill as string | undefined, color) ??\n inheritedFill;\n const childArray = Array.isArray(children) ? children : [children];\n for (const child of childArray) {\n if (child != null && typeof child === \"object\") {\n drawSvgChild(ctx, child, groupFill, color);\n }\n }\n}\n\nfunction parsePoints(value: string | undefined): [number, number][] {\n if (!value) return [];\n const nums = value\n .trim()\n .split(/[\\s,]+/)\n .map(Number);\n const result: [number, number][] = [];\n for (let i = 0; i + 1 < nums.length; i += 2) {\n result.push([nums[i]!, nums[i + 1]!]);\n }\n return result;\n}\n\nfunction applyFillAndStroke(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n path: Path2D,\n inheritedFill: string,\n color: string,\n): void {\n // Use element's own fill if set, otherwise inherit from parent\n const fill =\n resolveCurrentColor(props.fill as string | undefined, color) ??\n inheritedFill;\n if (fill !== \"none\") {\n ctx.fillStyle = fill;\n ctx.fill(path);\n }\n\n applyStroke(ctx, props, path, color);\n}\n\nfunction applyStroke(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n path: Path2D,\n color: string,\n): void {\n const stroke = resolveCurrentColor(props.stroke as string | undefined, color);\n if (!stroke || stroke === \"none\") return;\n\n ctx.strokeStyle = stroke;\n ctx.lineWidth = Number(props.strokeWidth ?? props[\"stroke-width\"] ?? 1);\n ctx.lineCap =\n ((props.strokeLinecap ?? props[\"stroke-linecap\"]) as CanvasLineCap) ??\n \"butt\";\n ctx.lineJoin =\n ((props.strokeLinejoin ?? props[\"stroke-linejoin\"]) as CanvasLineJoin) ??\n \"miter\";\n ctx.stroke(path);\n}\n","import { loadImage } from \"@napi-rs/canvas\";\nimport type { SKRSContext2D, Image } from \"@napi-rs/canvas\";\n\nimport type { EmojiStyle } from \"../emoji.ts\";\nimport { getEmojiCode, loadEmoji } from \"../emoji.ts\";\nimport type { TextSegment } from \"../text/index.ts\";\nimport { splitTextIntoRuns } from \"../text/emoji-split.ts\";\nimport { setFont } from \"../text/measure.ts\";\n\nconst emojiImageCache = new Map<string, Promise<Image | null>>();\n\nfunction loadEmojiImage(\n style: EmojiStyle,\n char: string,\n): Promise<Image | null> {\n const code = getEmojiCode(char);\n const key = style + \":\" + code;\n let cached = emojiImageCache.get(key);\n if (!cached) {\n cached = loadEmoji(style, code)\n .then((svgText) => {\n if (!svgText || !svgText.includes(\"<svg\")) return null;\n const dataUri =\n \"data:image/svg+xml;base64,\" +\n Buffer.from(svgText).toString(\"base64\");\n return loadImage(dataUri);\n })\n .catch(() => null);\n emojiImageCache.set(key, cached);\n }\n return cached;\n}\n\n/**\n * Draw text segments onto the canvas context.\n *\n * @param ctx - Canvas 2D rendering context\n * @param segments - Positioned text segments from the text layout engine\n * @param offsetX - X offset for the text block\n * @param offsetY - Y offset for the text block\n * @param textShadow - Optional text-shadow CSS value\n * @param emojiStyle - Optional emoji style for rendering emoji as images\n */\nexport async function drawText(\n ctx: SKRSContext2D,\n segments: TextSegment[],\n offsetX: number,\n offsetY: number,\n textShadow?: string,\n emojiStyle?: EmojiStyle,\n): Promise<void> {\n for (const seg of segments) {\n if (!seg.text) continue;\n\n setFont(ctx, seg.fontSize, seg.fontFamily, seg.fontWeight, seg.fontStyle);\n ctx.fillStyle = seg.color;\n\n const x = offsetX + seg.x;\n const y = offsetY + seg.y;\n\n if (emojiStyle) {\n await drawSegmentWithEmoji(ctx, seg, x, y, textShadow, emojiStyle);\n } else if (seg.letterSpacing && seg.letterSpacing !== 0) {\n drawTextWithLetterSpacing(ctx, seg.text, x, y, seg.letterSpacing);\n } else {\n if (textShadow) {\n drawTextShadow(ctx, seg.text, x, y, textShadow);\n }\n ctx.fillText(seg.text, x, y);\n }\n\n // Text decoration\n if (seg.textDecoration) {\n drawTextDecoration(ctx, seg, offsetX, offsetY);\n }\n }\n}\n\nasync function drawSegmentWithEmoji(\n ctx: SKRSContext2D,\n seg: TextSegment,\n x: number,\n y: number,\n textShadow: string | undefined,\n emojiStyle: EmojiStyle,\n): Promise<void> {\n const runs = splitTextIntoRuns(\n seg.text,\n (text) => {\n setFont(ctx, seg.fontSize, seg.fontFamily, seg.fontWeight, seg.fontStyle);\n return ctx.measureText(text).width;\n },\n seg.fontSize,\n );\n\n for (const run of runs) {\n if (run.kind === \"text\") {\n if (textShadow) {\n drawTextShadow(ctx, run.text, x + run.x, y, textShadow);\n }\n ctx.fillText(run.text, x + run.x, y);\n } else {\n const img = await loadEmojiImage(emojiStyle, run.char);\n if (img) {\n const emojiSize = seg.fontSize;\n // Position emoji so it aligns vertically with text:\n // y is the baseline, ascent goes up from baseline\n const emojiY = y - seg.ascent + (seg.height - seg.fontSize) / 2;\n ctx.drawImage(img, x + run.x, emojiY, emojiSize, emojiSize);\n } else {\n // Emoji image unavailable — fall back to text rendering\n ctx.fillText(run.char, x + run.x, y);\n }\n }\n }\n}\n\nfunction drawTextWithLetterSpacing(\n ctx: SKRSContext2D,\n text: string,\n x: number,\n y: number,\n letterSpacing: number,\n): void {\n let currentX = x;\n for (const char of text) {\n ctx.fillText(char, currentX, y);\n const metrics = ctx.measureText(char);\n currentX += metrics.width + letterSpacing;\n }\n}\n\nfunction drawTextShadow(\n ctx: SKRSContext2D,\n text: string,\n x: number,\n y: number,\n shadow: string,\n): void {\n const parts = shadow.match(\n /(-?\\d+(?:\\.\\d+)?)\\s*px?\\s+(-?\\d+(?:\\.\\d+)?)\\s*px?\\s+(-?\\d+(?:\\.\\d+)?)\\s*px?\\s+(.*)/,\n );\n if (!parts) return;\n\n ctx.save();\n ctx.shadowOffsetX = parseFloat(parts[1]!);\n ctx.shadowOffsetY = parseFloat(parts[2]!);\n ctx.shadowBlur = parseFloat(parts[3]!);\n ctx.shadowColor = parts[4]!.trim();\n ctx.fillText(text, x, y);\n ctx.restore();\n}\n\nfunction drawTextDecoration(\n ctx: SKRSContext2D,\n seg: TextSegment,\n offsetX: number,\n offsetY: number,\n): void {\n const decoration = seg.textDecoration;\n if (!decoration || decoration === \"none\") return;\n\n ctx.strokeStyle = seg.color;\n ctx.lineWidth = Math.max(1, seg.fontSize * 0.1);\n\n const x = offsetX + seg.x;\n const baseY = offsetY + seg.y;\n\n if (decoration.includes(\"underline\")) {\n const y = baseY + seg.ascent * 0.1;\n ctx.beginPath();\n ctx.moveTo(x, y);\n ctx.lineTo(x + seg.width, y);\n ctx.stroke();\n }\n\n if (decoration.includes(\"line-through\")) {\n const y = baseY - seg.fontSize * 0.3;\n ctx.beginPath();\n ctx.moveTo(x, y);\n ctx.lineTo(x + seg.width, y);\n ctx.stroke();\n }\n\n if (decoration.includes(\"overline\")) {\n const y = baseY - seg.fontSize * 0.85;\n ctx.beginPath();\n ctx.moveTo(x, y);\n ctx.lineTo(x + seg.width, y);\n ctx.stroke();\n }\n}\n","// This file contains code adapted from Satori (https://github.com/vercel/satori)\n// Licensed under the Mozilla Public License 2.0 (MPL-2.0)\n// See NOTICE.md in the package root for details.\n\n/**\n * Emoji style options for rendering\n */\nexport type EmojiStyle =\n | \"twemoji\"\n | \"openmoji\"\n | \"blobmoji\"\n | \"noto\"\n | \"fluent\"\n | \"fluentFlat\";\n\nexport const emojiApis: Record<\n EmojiStyle,\n string | ((code: string) => string)\n> = {\n twemoji: (code: string) =>\n `https://cdnjs.cloudflare.com/ajax/libs/twemoji/16.0.1/svg/${code.toLowerCase()}.svg`,\n openmoji: \"https://cdn.jsdelivr.net/npm/@svgmoji/openmoji@2.0.0/svg/\",\n blobmoji: \"https://cdn.jsdelivr.net/npm/@svgmoji/blob@2.0.0/svg/\",\n noto: \"https://cdn.jsdelivr.net/gh/svgmoji/svgmoji/packages/svgmoji__noto/svg/\",\n fluent: (code: string) =>\n `https://cdn.jsdelivr.net/gh/shuding/fluentui-emoji-unicode/assets/${code.toLowerCase()}_color.svg`,\n fluentFlat: (code: string) =>\n `https://cdn.jsdelivr.net/gh/shuding/fluentui-emoji-unicode/assets/${code.toLowerCase()}_flat.svg`,\n};\n\nconst U200D = String.fromCharCode(8205);\nconst UFE0Fg = /\\uFE0F/g;\n\nexport function getEmojiCode(char: string): string {\n return toCodePoint(char.indexOf(U200D) < 0 ? char.replace(UFE0Fg, \"\") : char);\n}\n\nexport function toCodePoint(unicodeSurrogates: string): string {\n const r: string[] = [];\n let c = 0,\n p = 0,\n i = 0;\n\n while (i < unicodeSurrogates.length) {\n c = unicodeSurrogates.charCodeAt(i++);\n if (p) {\n r.push((65536 + ((p - 55296) << 10) + (c - 56320)).toString(16));\n p = 0;\n } else if (55296 <= c && c <= 56319) {\n p = c;\n } else {\n r.push(c.toString(16));\n }\n }\n return r.join(\"-\");\n}\n\nconst emojiCache: Record<string, Promise<string>> = {};\n\nexport async function loadEmoji(\n type: EmojiStyle,\n code: string,\n): Promise<string> {\n const key = type + \":\" + code;\n if (key in emojiCache) return emojiCache[key];\n\n const api = emojiApis[type];\n if (typeof api === \"function\") {\n return (emojiCache[key] = fetch(api(code)).then((r) => r.text()));\n }\n return (emojiCache[key] = fetch(`${api}${code.toUpperCase()}.svg`).then((r) =>\n r.text(),\n ));\n}\n","import { isEmoji } from \"../language.ts\";\n\nexport type TextRun =\n | { kind: \"text\"; text: string; x: number; width: number }\n | { kind: \"emoji\"; char: string; x: number; width: number };\n\n/**\n * Split a text string into runs of plain text and individual emoji characters.\n * Uses Intl.Segmenter for correct grapheme cluster handling (multi-codepoint emoji).\n */\nexport function splitTextIntoRuns(\n text: string,\n measureText: (text: string) => number,\n emojiSize: number,\n): TextRun[] {\n const runs: TextRun[] = [];\n const segmenter = new Intl.Segmenter(undefined, { granularity: \"grapheme\" });\n let currentText = \"\";\n let currentX = 0;\n let textStartX = 0;\n\n for (const { segment } of segmenter.segment(text)) {\n if (isEmojiGrapheme(segment)) {\n // Flush accumulated text\n if (currentText) {\n const textWidth = measureText(currentText);\n runs.push({\n kind: \"text\",\n text: currentText,\n x: textStartX,\n width: textWidth,\n });\n currentX = textStartX + textWidth;\n currentText = \"\";\n }\n runs.push({\n kind: \"emoji\",\n char: segment,\n x: currentX,\n width: emojiSize,\n });\n currentX += emojiSize;\n textStartX = currentX;\n } else {\n if (!currentText) textStartX = currentX;\n currentText += segment;\n }\n }\n\n // Flush remaining text\n if (currentText) {\n const textWidth = measureText(currentText);\n runs.push({\n kind: \"text\",\n text: currentText,\n x: textStartX,\n width: textWidth,\n });\n }\n\n return runs;\n}\n\n/**\n * Check if a grapheme cluster is an emoji.\n * Checks the first code point of the grapheme.\n */\nfunction isEmojiGrapheme(grapheme: string): boolean {\n for (const char of grapheme) {\n if (isEmoji(char)) return true;\n }\n return false;\n}\n","import { GlobalFonts } from \"@napi-rs/canvas\";\n\nimport type { FontData } from \"../types.ts\";\n\nconst registeredFonts = new Set<string>();\n\n/**\n * Reset internal font state (test-only).\n */\nexport function _resetForTest(): void {\n registeredFonts.clear();\n}\n\n/**\n * Register a font from a FontData buffer.\n * Registration is idempotent — re-registering the same font name is a no-op.\n *\n * @param font - Font data to register\n */\nexport function registerFont(font: FontData): void {\n const key = `${font.name}:${font.weight}:${font.style}`;\n if (registeredFonts.has(key)) return;\n\n const buffer = Buffer.isBuffer(font.data)\n ? font.data\n : Buffer.from(font.data);\n\n GlobalFonts.register(buffer, font.name);\n\n registeredFonts.add(key);\n}\n\n/**\n * Register a font from a file path.\n *\n * @param path - Path to the font file\n * @param nameAlias - Optional font family name override\n */\nexport function registerFontFromPath(path: string, nameAlias?: string): void {\n GlobalFonts.registerFromPath(path, nameAlias ?? \"\");\n}\n\n/**\n * Get the list of registered font family names.\n *\n * @returns Array of font family names\n */\nexport function registeredFamilies(): string[] {\n return GlobalFonts.families.map((f: { family: string }) => f.family);\n}\n\n/**\n * Ensure all fonts from the given array are registered.\n * Called internally by `renderReactElement()`.\n */\nexport function ensureFontsRegistered(fonts: FontData[]): void {\n for (const font of fonts) {\n registerFont(font);\n }\n}\n","// This file contains code adapted from Satori (https://github.com/vercel/satori)\n// Licensed under the Mozilla Public License 2.0 (MPL-2.0)\n// See NOTICE.md in the package root for details.\n\nimport type { SKRSContext2D } from \"@napi-rs/canvas\";\nimport { loadImage } from \"@napi-rs/canvas\";\nimport type { ReactElement, ReactNode } from \"react\";\n\nimport { expandStyle } from \"./style/expand.ts\";\nimport { resolveStyle, resolveUnits, DEFAULT_STYLE } from \"./style/compute.ts\";\nimport type { ComputedStyle } from \"./style/compute.ts\";\nimport { applyStylesToYoga } from \"./style/properties.ts\";\nimport { createTextMeasureFunc } from \"./text/index.ts\";\nimport { createYogaNode, freeYogaNode } from \"./yoga.ts\";\nimport type { YogaNode } from \"./yoga.ts\";\n\n/**\n * A node in the computed layout tree, ready for drawing.\n */\nexport type LayoutNode = {\n type: string;\n style: ComputedStyle;\n children: LayoutNode[];\n textContent?: string;\n props: Record<string, unknown>;\n x: number;\n y: number;\n width: number;\n height: number;\n};\n\ntype ElementChild = string | number | ReactElement | null | undefined | boolean;\n\n/**\n * Build a layout tree from a React element tree.\n * Creates Yoga nodes, calculates layout, and returns the positioned tree.\n *\n * @param element - React element tree to lay out\n * @param containerWidth - Width of the container (from canvas)\n * @param containerHeight - Height of the container (from canvas)\n * @param ctx - Canvas context for text measurement\n * @returns Root layout node with computed positions and dimensions\n */\nexport async function buildLayoutTree(\n element: ReactNode,\n containerWidth: number,\n containerHeight: number,\n ctx?: SKRSContext2D,\n emojiEnabled?: boolean,\n): Promise<LayoutNode> {\n const rootYogaNode = createYogaNode();\n\n // Build the tree\n const rootNode = await buildNode(\n element,\n DEFAULT_STYLE,\n rootYogaNode,\n containerWidth,\n containerHeight,\n ctx,\n emojiEnabled,\n );\n\n // Set root dimensions\n rootYogaNode.setWidth(containerWidth);\n rootYogaNode.setHeight(containerHeight);\n\n // Calculate layout\n rootYogaNode.calculateLayout(containerWidth, containerHeight);\n\n // Extract computed positions\n const layoutTree = extractLayout(rootNode, rootYogaNode);\n\n // Free Yoga nodes\n freeYogaNode(rootYogaNode);\n\n return layoutTree;\n}\n\nasync function buildNode(\n element: ReactNode,\n parentStyle: ComputedStyle,\n yogaNode: YogaNode,\n viewportWidth: number,\n viewportHeight: number,\n ctx?: SKRSContext2D,\n emojiEnabled?: boolean,\n): Promise<IntermediateNode> {\n // Handle null/undefined/boolean\n if (\n element === null ||\n element === undefined ||\n typeof element === \"boolean\"\n ) {\n return {\n type: \"empty\",\n style: parentStyle,\n children: [],\n props: {},\n yogaNode,\n };\n }\n\n // Handle text/number primitives\n if (typeof element === \"string\" || typeof element === \"number\") {\n const text = String(element);\n const style = resolveStyle(undefined, parentStyle);\n\n // Set up text measurement\n const measureFunc = createTextMeasureFunc(text, style, ctx, emojiEnabled);\n yogaNode.setMeasureFunc(measureFunc);\n\n return {\n type: \"text\",\n style,\n children: [],\n textContent: text,\n props: {},\n yogaNode,\n };\n }\n\n // Handle arrays (fragments)\n if (Array.isArray(element)) {\n const style = resolveStyle(undefined, parentStyle);\n const children: IntermediateNode[] = [];\n\n for (let i = 0; i < element.length; i++) {\n const child = element[i] as ElementChild;\n if (child === null || child === undefined || typeof child === \"boolean\")\n continue;\n\n const childYogaNode = createYogaNode();\n yogaNode.insertChild(childYogaNode, children.length);\n children.push(\n await buildNode(\n child,\n style,\n childYogaNode,\n viewportWidth,\n viewportHeight,\n ctx,\n emojiEnabled,\n ),\n );\n }\n\n return {\n type: \"div\",\n style,\n children,\n props: {},\n yogaNode,\n };\n }\n\n // Handle React elements\n const el = element as ReactElement<Record<string, unknown>>;\n const type = el.type;\n\n // Expand function/class components\n if (typeof type === \"function\") {\n const rendered = (type as (props: Record<string, unknown>) => ReactNode)(\n el.props ?? {},\n );\n return await buildNode(\n rendered,\n parentStyle,\n yogaNode,\n viewportWidth,\n viewportHeight,\n ctx,\n emojiEnabled,\n );\n }\n\n const props = (el.props ?? {}) as Record<string, unknown>;\n const rawStyle = (props.style ?? {}) as Record<string, unknown>;\n const expanded = expandStyle(rawStyle);\n const style = resolveStyle(expanded, parentStyle);\n resolveUnits(style, viewportWidth, viewportHeight);\n\n const tagName = String(type);\n\n // For <svg> elements, merge width/height props into style when not set via CSS\n if (tagName === \"svg\") {\n if (props.width != null && style.width === undefined) {\n const v = props.width;\n style.width = typeof v === \"string\" && v.endsWith(\"%\") ? v : Number(v);\n }\n if (props.height != null && style.height === undefined) {\n const v = props.height;\n style.height = typeof v === \"string\" && v.endsWith(\"%\") ? v : Number(v);\n }\n\n // Derive missing dimension from viewBox aspect ratio\n const viewBox = props.viewBox as string | undefined;\n if (viewBox) {\n const parts = viewBox.split(/[\\s,]+/).map(Number);\n if (parts.length === 4) {\n const [, , vbW, vbH] = parts as [number, number, number, number];\n if (vbW > 0 && vbH > 0) {\n const w = typeof style.width === \"number\" ? style.width : undefined;\n const h = typeof style.height === \"number\" ? style.height : undefined;\n if (w !== undefined && h === undefined) {\n style.height = w * (vbH / vbW);\n } else if (h !== undefined && w === undefined) {\n style.width = h * (vbW / vbH);\n } else if (w === undefined && h === undefined) {\n style.width = vbW;\n style.height = vbH;\n }\n }\n }\n }\n }\n\n // For <img> elements, derive missing dimensions from intrinsic aspect ratio\n if (tagName === \"img\") {\n // Map HTML width/height attributes to style (like <svg>)\n if (props.width != null && style.width === undefined) {\n const v = props.width;\n style.width = typeof v === \"string\" && v.endsWith(\"%\") ? v : Number(v);\n }\n if (props.height != null && style.height === undefined) {\n const v = props.height;\n style.height = typeof v === \"string\" && v.endsWith(\"%\") ? v : Number(v);\n }\n\n const src = props.src as string | Buffer | undefined;\n if (src) {\n try {\n const image = await loadImage(src);\n const naturalW = image.width;\n const naturalH = image.height;\n\n const w = typeof style.width === \"number\" ? style.width : undefined;\n const h = typeof style.height === \"number\" ? style.height : undefined;\n\n if (w !== undefined && h === undefined && naturalW > 0) {\n style.height = w * (naturalH / naturalW);\n } else if (h !== undefined && w === undefined && naturalH > 0) {\n style.width = h * (naturalW / naturalH);\n }\n\n // Cache loaded image for reuse during drawing\n props.__loadedImage = image;\n } catch {\n // Silent fail — image will render at whatever size Yoga computes\n }\n }\n }\n\n // Apply styles to Yoga node\n applyStylesToYoga(yogaNode, style);\n\n // SVG containers: children use SVG coordinate space, not flex layout.\n // Skip Yoga child nodes and keep React children in props for the SVG drawer.\n if (tagName === \"svg\") {\n return {\n type: tagName,\n style,\n children: [],\n props,\n yogaNode,\n };\n }\n\n // Collect text content from direct string children\n const textContent = extractTextContent(props.children);\n\n // If this node has only text content, create a child text node.\n // Using a child node (instead of setMeasureFunc on this node directly)\n // ensures Yoga's baseline calculation accounts for this node's padding/border\n // when a parent uses alignItems: \"baseline\".\n if (textContent !== undefined && !hasElementChildren(props.children)) {\n const childStyle = resolveStyle(undefined, style);\n const childYogaNode = createYogaNode();\n const measureFunc = createTextMeasureFunc(\n textContent,\n childStyle,\n ctx,\n emojiEnabled,\n );\n childYogaNode.setMeasureFunc(measureFunc);\n childYogaNode.setFlexGrow(1);\n childYogaNode.setFlexShrink(1);\n yogaNode.insertChild(childYogaNode, 0);\n\n return {\n type: tagName,\n style,\n children: [\n {\n type: \"text\",\n style: childStyle,\n children: [],\n textContent,\n props: {},\n yogaNode: childYogaNode,\n },\n ],\n props,\n yogaNode,\n };\n }\n\n // Process children\n const children: IntermediateNode[] = [];\n const rawChildren = props.children;\n\n if (rawChildren !== undefined && rawChildren !== null) {\n const childArray = Array.isArray(rawChildren) ? rawChildren : [rawChildren];\n\n for (const child of childArray as ElementChild[]) {\n if (child === null || child === undefined || typeof child === \"boolean\")\n continue;\n\n const childYogaNode = createYogaNode();\n yogaNode.insertChild(childYogaNode, children.length);\n children.push(\n await buildNode(\n child,\n style,\n childYogaNode,\n viewportWidth,\n viewportHeight,\n ctx,\n emojiEnabled,\n ),\n );\n }\n }\n\n return {\n type: tagName,\n style,\n children,\n props,\n yogaNode,\n };\n}\n\ntype IntermediateNode = {\n type: string;\n style: ComputedStyle;\n children: IntermediateNode[];\n textContent?: string;\n props: Record<string, unknown>;\n yogaNode: YogaNode;\n};\n\nfunction extractLayout(node: IntermediateNode, yogaNode: YogaNode): LayoutNode {\n const layout = yogaNode.getComputedLayout();\n\n return {\n type: node.type,\n style: node.style,\n children: node.children.map((child, i) => {\n const childYoga = yogaNode.getChild(i);\n return extractLayout(child, childYoga);\n }),\n textContent: node.textContent,\n props: node.props,\n x: layout.left,\n y: layout.top,\n width: layout.width,\n height: layout.height,\n };\n}\n\n/**\n * Extract plain text content from children if they are all strings/numbers.\n */\nfunction extractTextContent(children: unknown): string | undefined {\n if (children === undefined || children === null) return undefined;\n if (typeof children === \"string\") return children;\n if (typeof children === \"number\") return String(children);\n\n if (Array.isArray(children)) {\n const parts: string[] = [];\n for (const child of children) {\n if (typeof child === \"string\") {\n parts.push(child);\n } else if (typeof child === \"number\") {\n parts.push(String(child));\n } else if (\n child !== null &&\n child !== undefined &&\n typeof child !== \"boolean\"\n ) {\n return undefined; // Mixed content — not pure text\n }\n }\n return parts.join(\"\");\n }\n\n return undefined;\n}\n\n/**\n * Check if children contains any React elements (not just strings/numbers).\n */\nfunction hasElementChildren(children: unknown): boolean {\n if (\n children === undefined ||\n children === null ||\n typeof children === \"boolean\"\n )\n return false;\n if (typeof children === \"string\" || typeof children === \"number\")\n return false;\n\n if (Array.isArray(children)) {\n return children.some(\n (child) =>\n child !== null &&\n child !== undefined &&\n typeof child !== \"boolean\" &&\n typeof child !== \"string\" &&\n typeof child !== \"number\",\n );\n }\n\n // Single React element\n return typeof children === \"object\";\n}\n","// This file contains code adapted from Satori (https://github.com/vercel/satori)\n// Licensed under the Mozilla Public License 2.0 (MPL-2.0)\n// See NOTICE.md in the package root for details.\n\nimport type { ComputedStyle } from \"./compute.ts\";\n\ntype RawStyle = Record<string, unknown>;\n\nconst SIDES = [\"Top\", \"Right\", \"Bottom\", \"Left\"] as const;\n\n/**\n * Parse a CSS shorthand value like \"10px 20px\" into 1-4 parts.\n */\nfunction parseSides(value: string): string[] {\n const parts = value.toString().split(/\\s+/).filter(Boolean);\n switch (parts.length) {\n case 1:\n return [parts[0]!, parts[0]!, parts[0]!, parts[0]!];\n case 2:\n return [parts[0]!, parts[1]!, parts[0]!, parts[1]!];\n case 3:\n return [parts[0]!, parts[1]!, parts[2]!, parts[1]!];\n default:\n return [parts[0]!, parts[1]!, parts[2]!, parts[3]!];\n }\n}\n\nfunction parseValue(v: unknown): number | string | undefined {\n if (v === undefined || v === null) return undefined;\n const s = String(v);\n if (s === \"auto\") return \"auto\";\n const n = parseFloat(s);\n if (!isNaN(n)) return n;\n return s;\n}\n\n/**\n * Expand CSS shorthand properties into their longhand equivalents.\n * Mutates and returns the style object.\n */\nexport function expandStyle(raw: RawStyle): ComputedStyle {\n const style = { ...raw } as Record<string, unknown>;\n\n // margin shorthand\n if (style.margin !== undefined) {\n const sides = parseSides(String(style.margin));\n for (let i = 0; i < 4; i++) {\n const key = `margin${SIDES[i]}`;\n if (style[key] === undefined) style[key] = parseValue(sides[i]);\n }\n delete style.margin;\n }\n\n // padding shorthand\n if (style.padding !== undefined) {\n const sides = parseSides(String(style.padding));\n for (let i = 0; i < 4; i++) {\n const key = `padding${SIDES[i]}`;\n if (style[key] === undefined) style[key] = parseValue(sides[i]);\n }\n delete style.padding;\n }\n\n // borderRadius shorthand\n if (style.borderRadius !== undefined) {\n const sides = parseSides(String(style.borderRadius));\n const corners = [\n \"borderTopLeftRadius\",\n \"borderTopRightRadius\",\n \"borderBottomRightRadius\",\n \"borderBottomLeftRadius\",\n ];\n for (let i = 0; i < 4; i++) {\n if (style[corners[i]!] === undefined)\n style[corners[i]!] = parseValue(sides[i]);\n }\n delete style.borderRadius;\n }\n\n // borderWidth shorthand\n if (style.borderWidth !== undefined) {\n const sides = parseSides(String(style.borderWidth));\n for (let i = 0; i < 4; i++) {\n const key = `border${SIDES[i]}Width`;\n if (style[key] === undefined) style[key] = parseValue(sides[i]);\n }\n delete style.borderWidth;\n }\n\n // borderColor shorthand\n if (style.borderColor !== undefined) {\n const val = style.borderColor;\n for (const side of SIDES) {\n const key = `border${side}Color`;\n if (style[key] === undefined) style[key] = val;\n }\n delete style.borderColor;\n }\n\n // borderStyle shorthand\n if (style.borderStyle !== undefined) {\n const val = style.borderStyle;\n for (const side of SIDES) {\n const key = `border${side}Style`;\n if (style[key] === undefined) style[key] = val;\n }\n delete style.borderStyle;\n }\n\n // border shorthand (e.g. \"1px solid black\")\n if (style.border !== undefined) {\n const parts = String(style.border).split(/\\s+/);\n const width = parseValue(parts[0]);\n const borderStyle = parts[1] ?? \"solid\";\n const color = parts[2] ?? \"black\";\n for (const side of SIDES) {\n if (style[`border${side}Width`] === undefined)\n style[`border${side}Width`] = width;\n if (style[`border${side}Style`] === undefined)\n style[`border${side}Style`] = borderStyle;\n if (style[`border${side}Color`] === undefined)\n style[`border${side}Color`] = color;\n }\n delete style.border;\n }\n\n // flex shorthand\n if (style.flex !== undefined) {\n const val = String(style.flex);\n const parts = val.split(/\\s+/);\n if (parts.length === 1) {\n const n = parseFloat(parts[0]!);\n if (!isNaN(n)) {\n if (style.flexGrow === undefined) style.flexGrow = n;\n if (style.flexShrink === undefined) style.flexShrink = 1;\n if (style.flexBasis === undefined) style.flexBasis = 0;\n }\n } else if (parts.length === 2) {\n if (style.flexGrow === undefined) style.flexGrow = parseFloat(parts[0]!);\n if (style.flexShrink === undefined)\n style.flexShrink = parseFloat(parts[1]!);\n } else if (parts.length >= 3) {\n if (style.flexGrow === undefined) style.flexGrow = parseFloat(parts[0]!);\n if (style.flexShrink === undefined)\n style.flexShrink = parseFloat(parts[1]!);\n if (style.flexBasis === undefined) style.flexBasis = parseValue(parts[2]);\n }\n delete style.flex;\n }\n\n // gap shorthand\n if (style.gap !== undefined) {\n const sides = parseSides(String(style.gap));\n if (style.rowGap === undefined) style.rowGap = parseValue(sides[0]);\n if (style.columnGap === undefined) style.columnGap = parseValue(sides[1]);\n delete style.gap;\n }\n\n // background shorthand\n if (style.background !== undefined) {\n const bg = String(style.background);\n if (bg.includes(\"gradient(\") || bg.includes(\"url(\")) {\n if (style.backgroundImage === undefined) style.backgroundImage = bg;\n } else {\n if (style.backgroundColor === undefined) style.backgroundColor = bg;\n }\n delete style.background;\n }\n\n // overflow shorthand\n if (style.overflow !== undefined) {\n if (style.overflowX === undefined) style.overflowX = style.overflow;\n if (style.overflowY === undefined) style.overflowY = style.overflow;\n }\n\n // fontFamily normalization\n if (typeof style.fontFamily === \"string\") {\n style.fontFamily = style.fontFamily\n .split(\",\")\n .map((s) => s.trim().replace(/^['\"]|['\"]$/g, \"\"))\n .filter(Boolean)\n .join(\", \");\n }\n\n return style as unknown as ComputedStyle;\n}\n","// This file contains code adapted from Satori (https://github.com/vercel/satori)\n// Licensed under the Mozilla Public License 2.0 (MPL-2.0)\n// See NOTICE.md in the package root for details.\n\n/**\n * Normalized, computed CSS style after shorthand expansion.\n * All dimension values are numbers (pixels) or percentage strings.\n */\nexport type ComputedStyle = {\n // Display & layout\n display?: \"flex\" | \"none\";\n flexDirection?: \"row\" | \"column\" | \"row-reverse\" | \"column-reverse\";\n justifyContent?:\n | \"flex-start\"\n | \"flex-end\"\n | \"center\"\n | \"space-between\"\n | \"space-around\"\n | \"space-evenly\";\n alignItems?: \"flex-start\" | \"flex-end\" | \"center\" | \"stretch\" | \"baseline\";\n alignSelf?:\n | \"auto\"\n | \"flex-start\"\n | \"flex-end\"\n | \"center\"\n | \"stretch\"\n | \"baseline\";\n alignContent?:\n | \"flex-start\"\n | \"flex-end\"\n | \"center\"\n | \"stretch\"\n | \"space-between\"\n | \"space-around\";\n flexWrap?: \"nowrap\" | \"wrap\" | \"wrap-reverse\";\n flexGrow?: number;\n flexShrink?: number;\n flexBasis?: number | string;\n\n // Dimensions\n width?: number | string;\n height?: number | string;\n minWidth?: number | string;\n minHeight?: number | string;\n maxWidth?: number | string;\n maxHeight?: number | string;\n\n // Position\n position?: \"relative\" | \"absolute\";\n top?: number | string;\n right?: number | string;\n bottom?: number | string;\n left?: number | string;\n\n // Margin\n marginTop?: number | string;\n marginRight?: number | string;\n marginBottom?: number | string;\n marginLeft?: number | string;\n\n // Padding\n paddingTop?: number | string;\n paddingRight?: number | string;\n paddingBottom?: number | string;\n paddingLeft?: number | string;\n\n // Border\n borderTopWidth?: number;\n borderRightWidth?: number;\n borderBottomWidth?: number;\n borderLeftWidth?: number;\n borderTopColor?: string;\n borderRightColor?: string;\n borderBottomColor?: string;\n borderLeftColor?: string;\n borderTopStyle?: string;\n borderRightStyle?: string;\n borderBottomStyle?: string;\n borderLeftStyle?: string;\n borderTopLeftRadius?: number;\n borderTopRightRadius?: number;\n borderBottomRightRadius?: number;\n borderBottomLeftRadius?: number;\n\n // Gap\n rowGap?: number;\n columnGap?: number;\n\n // Overflow\n overflow?: string;\n overflowX?: string;\n overflowY?: string;\n\n // Colors & background\n backgroundColor?: string;\n color?: string;\n opacity?: number;\n backgroundImage?: string;\n backgroundSize?: string;\n\n // Typography\n fontSize?: number;\n fontFamily?: string;\n fontWeight?: number | string;\n fontStyle?: \"normal\" | \"italic\";\n textAlign?: \"left\" | \"center\" | \"right\" | \"justify\";\n textDecoration?: string;\n textTransform?: \"none\" | \"uppercase\" | \"lowercase\" | \"capitalize\";\n lineHeight?: number | string;\n letterSpacing?: number | string;\n whiteSpace?: \"normal\" | \"nowrap\" | \"pre\" | \"pre-wrap\" | \"pre-line\";\n wordBreak?: \"normal\" | \"break-all\" | \"break-word\" | \"keep-all\";\n textOverflow?: \"clip\" | \"ellipsis\";\n\n // Box shadow\n boxShadow?: string;\n textShadow?: string;\n\n // Transform\n transform?: string;\n transformOrigin?: string;\n\n // Image\n objectFit?: \"contain\" | \"cover\" | \"fill\" | \"none\" | \"scale-down\";\n\n // Filter\n filter?: string;\n};\n\n/**\n * Default styles for the root element.\n */\nexport const DEFAULT_STYLE: ComputedStyle = {\n display: \"flex\",\n flexDirection: \"row\",\n flexWrap: \"nowrap\",\n flexGrow: 0,\n flexShrink: 0,\n alignItems: \"stretch\",\n justifyContent: \"flex-start\",\n position: \"relative\",\n fontSize: 16,\n fontWeight: 400,\n fontStyle: \"normal\",\n color: \"black\",\n lineHeight: \"normal\",\n textAlign: \"left\",\n whiteSpace: \"normal\",\n wordBreak: \"normal\",\n textOverflow: \"clip\",\n opacity: 1,\n overflow: \"visible\",\n};\n\n/**\n * CSS properties that are inherited by child elements.\n */\nconst INHERITABLE_PROPS: (keyof ComputedStyle)[] = [\n \"color\",\n \"fontSize\",\n \"fontFamily\",\n \"fontWeight\",\n \"fontStyle\",\n \"textAlign\",\n \"textTransform\",\n \"textDecoration\",\n \"lineHeight\",\n \"letterSpacing\",\n \"whiteSpace\",\n \"wordBreak\",\n \"textOverflow\",\n];\n\n/**\n * Resolve the computed style for a node, inheriting from parent where appropriate.\n */\nexport function resolveStyle(\n rawStyle: ComputedStyle | undefined,\n parentStyle: ComputedStyle,\n): ComputedStyle {\n const style = { ...rawStyle };\n\n // Apply inherited properties\n for (const prop of INHERITABLE_PROPS) {\n if (style[prop] === undefined && parentStyle[prop] !== undefined) {\n (style as Record<string, unknown>)[prop] = parentStyle[prop];\n }\n }\n\n // Resolve fontSize (ensure it's a number)\n if (typeof style.fontSize === \"string\") {\n const parsed = parseFloat(style.fontSize);\n style.fontSize = isNaN(parsed) ? parentStyle.fontSize : parsed;\n }\n\n // Resolve lineHeight: parse string values to numbers but keep multipliers\n // as-is so they're recalculated per-element in text layout (using each\n // element's own fontSize rather than the parent's).\n if (typeof style.lineHeight === \"string\") {\n const str = style.lineHeight;\n if (str.endsWith(\"%\")) {\n style.lineHeight = parseFloat(str) / 100;\n } else {\n const parsed = parseFloat(str);\n if (!isNaN(parsed)) {\n style.lineHeight = parsed;\n }\n }\n }\n\n // Resolve letterSpacing\n if (typeof style.letterSpacing === \"string\") {\n const parsed = parseFloat(style.letterSpacing);\n if (!isNaN(parsed)) {\n style.letterSpacing = parsed;\n }\n }\n\n return style;\n}\n\n/**\n * Dimension properties that may contain CSS units needing resolution.\n */\nconst DIMENSION_PROPS: (keyof ComputedStyle)[] = [\n \"width\",\n \"height\",\n \"minWidth\",\n \"minHeight\",\n \"maxWidth\",\n \"maxHeight\",\n \"top\",\n \"right\",\n \"bottom\",\n \"left\",\n \"marginTop\",\n \"marginRight\",\n \"marginBottom\",\n \"marginLeft\",\n \"paddingTop\",\n \"paddingRight\",\n \"paddingBottom\",\n \"paddingLeft\",\n \"rowGap\",\n \"columnGap\",\n \"flexBasis\",\n];\n\n/**\n * Resolve a single CSS dimension string to a pixel number.\n * Returns the original value for `%` and `auto` (Yoga handles those),\n * and for values that are already numbers or unrecognised strings.\n */\nfunction resolveUnit(\n value: string,\n viewportWidth: number,\n viewportHeight: number,\n fontSize: number,\n rootFontSize: number,\n): number | string {\n // Percentages and auto are handled downstream by Yoga\n if (value.endsWith(\"%\") || value === \"auto\") return value;\n\n // Viewport-relative units\n if (value.endsWith(\"vmin\")) {\n const n = parseFloat(value);\n return isNaN(n)\n ? value\n : (n / 100) * Math.min(viewportWidth, viewportHeight);\n }\n if (value.endsWith(\"vmax\")) {\n const n = parseFloat(value);\n return isNaN(n)\n ? value\n : (n / 100) * Math.max(viewportWidth, viewportHeight);\n }\n if (value.endsWith(\"vw\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : (n / 100) * viewportWidth;\n }\n if (value.endsWith(\"vh\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : (n / 100) * viewportHeight;\n }\n\n // Font-relative units\n if (value.endsWith(\"rem\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * rootFontSize;\n }\n if (value.endsWith(\"em\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * fontSize;\n }\n\n // Absolute units (CSS reference pixel = 1/96 inch)\n if (value.endsWith(\"px\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n;\n }\n if (value.endsWith(\"pt\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * (96 / 72);\n }\n if (value.endsWith(\"pc\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * 16;\n }\n if (value.endsWith(\"in\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * 96;\n }\n if (value.endsWith(\"cm\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * (96 / 2.54);\n }\n if (value.endsWith(\"mm\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * (96 / 25.4);\n }\n\n return value;\n}\n\n/**\n * Resolve CSS units (vw, vh, vmin, vmax, em, rem, px, pt, pc, in, cm, mm)\n * in a style object to pixel values. Percentages and `auto` pass through\n * unchanged for Yoga to handle.\n */\nexport function resolveUnits(\n style: ComputedStyle,\n viewportWidth: number,\n viewportHeight: number,\n rootFontSize: number = DEFAULT_STYLE.fontSize!,\n): ComputedStyle {\n const fontSize =\n typeof style.fontSize === \"number\" ? style.fontSize : rootFontSize;\n\n for (const prop of DIMENSION_PROPS) {\n const value = style[prop];\n if (typeof value !== \"string\") continue;\n const resolved = resolveUnit(\n value,\n viewportWidth,\n viewportHeight,\n fontSize,\n rootFontSize,\n );\n if (resolved !== value) {\n (style as Record<string, unknown>)[prop] = resolved;\n }\n }\n return style;\n}\n\n/**\n * Resolve a dimension value (width, height, margin, etc.) to pixels.\n * Percentage values are resolved relative to the provided container size.\n */\nexport function resolveDimension(\n value: number | string | undefined,\n containerSize: number,\n): number | undefined {\n if (value === undefined || value === \"auto\") return undefined;\n if (typeof value === \"number\") return value;\n const s = String(value);\n if (s.endsWith(\"%\")) {\n return (parseFloat(s) / 100) * containerSize;\n }\n const n = parseFloat(s);\n return isNaN(n) ? undefined : n;\n}\n","import Yoga, {\n Align,\n Display,\n Edge,\n FlexDirection,\n Gutter,\n Justify,\n Overflow,\n PositionType,\n Wrap,\n} from \"yoga-layout\";\nimport type { Node as YogaNode } from \"yoga-layout\";\n\nexport type { YogaNode };\n\nexport {\n Yoga,\n Align,\n Display,\n Edge,\n FlexDirection,\n Gutter,\n Justify,\n Overflow,\n PositionType,\n Wrap,\n};\n\nexport function createYogaNode(): YogaNode {\n return Yoga.Node.create();\n}\n\nexport function freeYogaNode(node: YogaNode): void {\n node.freeRecursive();\n}\n","import {\n Align,\n Display,\n Edge,\n FlexDirection,\n Gutter,\n Justify,\n Overflow,\n PositionType,\n Wrap,\n} from \"../yoga.ts\";\nimport type { YogaNode } from \"../yoga.ts\";\nimport type { ComputedStyle } from \"./compute.ts\";\n\n/**\n * Apply computed CSS styles to a Yoga node.\n */\nexport function applyStylesToYoga(node: YogaNode, style: ComputedStyle): void {\n // Display\n if (style.display === \"none\") {\n node.setDisplay(Display.None);\n } else {\n node.setDisplay(Display.Flex);\n }\n\n // Flex direction (CSS default is \"row\", Yoga defaults to \"column\")\n {\n const map: Record<string, FlexDirection> = {\n row: FlexDirection.Row,\n \"row-reverse\": FlexDirection.RowReverse,\n column: FlexDirection.Column,\n \"column-reverse\": FlexDirection.ColumnReverse,\n };\n node.setFlexDirection(\n map[style.flexDirection ?? \"row\"] ?? FlexDirection.Row,\n );\n }\n\n // Justify content\n if (style.justifyContent) {\n const map: Record<string, Justify> = {\n \"flex-start\": Justify.FlexStart,\n \"flex-end\": Justify.FlexEnd,\n center: Justify.Center,\n \"space-between\": Justify.SpaceBetween,\n \"space-around\": Justify.SpaceAround,\n \"space-evenly\": Justify.SpaceEvenly,\n };\n const jc = map[style.justifyContent];\n if (jc !== undefined) node.setJustifyContent(jc);\n }\n\n // Align items\n if (style.alignItems) {\n const map: Record<string, Align> = {\n \"flex-start\": Align.FlexStart,\n \"flex-end\": Align.FlexEnd,\n center: Align.Center,\n stretch: Align.Stretch,\n baseline: Align.Baseline,\n };\n const ai = map[style.alignItems];\n if (ai !== undefined) node.setAlignItems(ai);\n }\n\n // Align self\n if (style.alignSelf) {\n const map: Record<string, Align> = {\n auto: Align.Auto,\n \"flex-start\": Align.FlexStart,\n \"flex-end\": Align.FlexEnd,\n center: Align.Center,\n stretch: Align.Stretch,\n baseline: Align.Baseline,\n };\n const as_ = map[style.alignSelf];\n if (as_ !== undefined) node.setAlignSelf(as_);\n }\n\n // Align content\n if (style.alignContent) {\n const map: Record<string, Align> = {\n \"flex-start\": Align.FlexStart,\n \"flex-end\": Align.FlexEnd,\n center: Align.Center,\n stretch: Align.Stretch,\n \"space-between\": Align.SpaceBetween,\n \"space-around\": Align.SpaceAround,\n };\n const ac = map[style.alignContent];\n if (ac !== undefined) node.setAlignContent(ac);\n }\n\n // Flex wrap\n if (style.flexWrap) {\n const map: Record<string, Wrap> = {\n nowrap: Wrap.NoWrap,\n wrap: Wrap.Wrap,\n \"wrap-reverse\": Wrap.WrapReverse,\n };\n const fw = map[style.flexWrap];\n if (fw !== undefined) node.setFlexWrap(fw);\n }\n\n // Flex grow / shrink / basis\n if (style.flexGrow !== undefined) node.setFlexGrow(style.flexGrow);\n // Satori defaults flexShrink to 0 (React Native convention); match it for compatibility\n node.setFlexShrink(style.flexShrink ?? 0);\n if (style.flexBasis !== undefined) {\n if (typeof style.flexBasis === \"number\") {\n node.setFlexBasis(style.flexBasis);\n } else if (String(style.flexBasis).endsWith(\"%\")) {\n node.setFlexBasis(String(style.flexBasis) as `${number}%`);\n } else if (style.flexBasis === \"auto\") {\n node.setFlexBasis(\"auto\");\n } else {\n const n = parseFloat(String(style.flexBasis));\n if (!isNaN(n)) node.setFlexBasis(n);\n }\n }\n\n // Dimensions\n applyDimension(node, \"setWidth\", style.width);\n applyDimension(node, \"setHeight\", style.height);\n applyDimension(node, \"setMinWidth\", style.minWidth);\n applyDimension(node, \"setMinHeight\", style.minHeight);\n applyDimension(node, \"setMaxWidth\", style.maxWidth);\n applyDimension(node, \"setMaxHeight\", style.maxHeight);\n\n // Position\n if (style.position === \"absolute\") {\n node.setPositionType(PositionType.Absolute);\n } else {\n node.setPositionType(PositionType.Relative);\n }\n\n // Position edges\n applyEdgeValue(node, \"setPosition\", Edge.Top, style.top);\n applyEdgeValue(node, \"setPosition\", Edge.Right, style.right);\n applyEdgeValue(node, \"setPosition\", Edge.Bottom, style.bottom);\n applyEdgeValue(node, \"setPosition\", Edge.Left, style.left);\n\n // Margin\n applyEdgeValue(node, \"setMargin\", Edge.Top, style.marginTop);\n applyEdgeValue(node, \"setMargin\", Edge.Right, style.marginRight);\n applyEdgeValue(node, \"setMargin\", Edge.Bottom, style.marginBottom);\n applyEdgeValue(node, \"setMargin\", Edge.Left, style.marginLeft);\n\n // Padding\n applyEdgeValue(node, \"setPadding\", Edge.Top, style.paddingTop);\n applyEdgeValue(node, \"setPadding\", Edge.Right, style.paddingRight);\n applyEdgeValue(node, \"setPadding\", Edge.Bottom, style.paddingBottom);\n applyEdgeValue(node, \"setPadding\", Edge.Left, style.paddingLeft);\n\n // Border width\n if (style.borderTopWidth !== undefined)\n node.setBorder(Edge.Top, style.borderTopWidth);\n if (style.borderRightWidth !== undefined)\n node.setBorder(Edge.Right, style.borderRightWidth);\n if (style.borderBottomWidth !== undefined)\n node.setBorder(Edge.Bottom, style.borderBottomWidth);\n if (style.borderLeftWidth !== undefined)\n node.setBorder(Edge.Left, style.borderLeftWidth);\n\n // Gap\n if (style.rowGap !== undefined) node.setGap(Gutter.Row, style.rowGap);\n if (style.columnGap !== undefined)\n node.setGap(Gutter.Column, style.columnGap);\n\n // Overflow\n if (\n style.overflow === \"hidden\" ||\n style.overflowX === \"hidden\" ||\n style.overflowY === \"hidden\"\n ) {\n node.setOverflow(Overflow.Hidden);\n } else {\n node.setOverflow(Overflow.Visible);\n }\n}\n\nfunction applyDimension(\n node: YogaNode,\n setter:\n | \"setWidth\"\n | \"setHeight\"\n | \"setMinWidth\"\n | \"setMinHeight\"\n | \"setMaxWidth\"\n | \"setMaxHeight\",\n value: number | string | undefined,\n): void {\n if (value === undefined) return;\n if (value === \"auto\") {\n if (setter === \"setWidth\" || setter === \"setHeight\") {\n node[setter](\"auto\");\n }\n return;\n }\n if (typeof value === \"number\") {\n node[setter](value);\n return;\n }\n const s = String(value);\n if (s.endsWith(\"%\")) {\n node[setter](s as `${number}%`);\n } else {\n const n = parseFloat(s);\n if (!isNaN(n)) node[setter](n);\n }\n}\n\nfunction applyEdgeValue(\n node: YogaNode,\n setter: \"setMargin\" | \"setPadding\" | \"setPosition\",\n edge: Edge,\n value: number | string | undefined,\n): void {\n if (value === undefined) return;\n if (value === \"auto\" && setter === \"setMargin\") {\n node.setMargin(edge, \"auto\");\n return;\n }\n if (typeof value === \"number\") {\n node[setter](edge, value);\n return;\n }\n const s = String(value);\n if (s.endsWith(\"%\")) {\n node[setter](edge, s as `${number}%`);\n } else {\n const n = parseFloat(s);\n if (!isNaN(n)) node[setter](edge, n);\n }\n}\n","import type { SKRSContext2D } from \"@napi-rs/canvas\";\nimport type { ReactNode } from \"react\";\n\nimport type { RenderReactElementOptions } from \"../types.ts\";\nimport { drawNode } from \"./draw/index.ts\";\nimport { ensureFontsRegistered } from \"./font.ts\";\nimport { buildLayoutTree } from \"./layout.ts\";\n\n/**\n * Render a React element tree to a canvas context.\n *\n * Width and height are taken from the canvas itself (`ctx.canvas.width` /\n * `ctx.canvas.height`).\n *\n * @param ctx - Canvas 2D rendering context to draw into\n * @param element - React element tree to render\n * @param options - Rendering options (fonts, debug mode)\n *\n * @example\n * ```tsx\n * import { createCanvas, renderReactElement } from \"@effing/canvas\";\n *\n * const canvas = createCanvas(1080, 1080);\n * const ctx = canvas.getContext(\"2d\");\n *\n * await renderReactElement(ctx, <MyComponent />, { fonts: [myFont] });\n *\n * const png = canvas.encodeSync(\"png\");\n * ```\n */\nexport async function renderReactElement(\n ctx: SKRSContext2D,\n element: ReactNode,\n options: RenderReactElementOptions,\n): Promise<void> {\n // Register fonts\n ensureFontsRegistered(options.fonts);\n\n // Get dimensions from canvas\n const width = ctx.canvas.width;\n const height = ctx.canvas.height;\n\n // Build layout tree (Yoga)\n const emojiStyle =\n options.emoji === \"none\" ? undefined : (options.emoji ?? \"twemoji\");\n const layoutTree = await buildLayoutTree(\n element,\n width,\n height,\n ctx,\n !!emojiStyle,\n );\n\n // Draw to canvas\n await drawNode(ctx, layoutTree, 0, 0, options.debug ?? false, emojiStyle);\n}\n"],"mappings":";AACA,SAAS,gBAAgB,qBAAqB;AAC9C;AAAA,EACE;AAAA,EAEA,eAAAA;AAAA,EACA,aAAAC;AAAA,EACA;AAAA,OACK;;;ACRP,SAAS,uBAAuB;AAiBzB,SAAS,WACd,MACA,SACiB;AACjB,QAAM,aAAa,OAAO,SAAS,WAAW,OAAO,KAAK,SAAS,OAAO;AAC1E,SAAO,gBAAgB,aAAa,YAAY;AAAA,IAC9C,cAAc,SAAS;AAAA,EACzB,CAAC;AACH;AAwBO,SAAS,kBACd,KACA,WACA,OACM;AACN,YAAU,UAAU,KAAK;AACzB,YAAU,OAAO,GAAG;AACtB;;;ACtDA,SAAS,gBAAAC,eAAc,aAAAC,kBAAiB;;;ACiDjC,SAAS,QAAQ,MAAuB;AAC7C,QAAM,KAAK,KAAK,YAAY,CAAC;AAC7B,MAAI,OAAO,OAAW,QAAO;AAG7B,MAAI,MAAM,UAAW,MAAM,OAAS,QAAO;AAC3C,MAAI,MAAM,UAAW,MAAM,OAAS,QAAO;AAC3C,MAAI,MAAM,UAAW,MAAM,OAAS,QAAO;AAC3C,MAAI,MAAM,UAAW,MAAM,OAAS,QAAO;AAC3C,MAAI,MAAM,QAAU,MAAM,KAAQ,QAAO;AACzC,MAAI,MAAM,QAAU,MAAM,MAAQ,QAAO;AACzC,MAAI,MAAM,SAAU,MAAM,MAAQ,QAAO;AACzC,MAAI,MAAM,QAAU,MAAM,KAAQ,QAAO;AACzC,MAAI,MAAM,SAAU,MAAM,MAAQ,QAAO;AACzC,MAAI,MAAM,UAAW,MAAM,OAAS,QAAO;AAC3C,MAAI,MAAM,UAAW,MAAM,OAAS,QAAO;AAC3C,MAAI,MAAM,QAAU,MAAM,KAAQ,QAAO;AACzC,MAAI,MAAM,QAAU,MAAM,KAAQ,QAAO;AACzC,MAAI,MAAM,QAAU,MAAM,KAAQ,QAAO;AACzC,MAAI,MAAM,SAAU,MAAM,MAAQ,QAAO;AACzC,MAAI,MAAM,SAAU,MAAM,MAAQ,QAAO;AACzC,MAAI,MAAM,SAAU,MAAM,MAAQ,QAAO;AACzC,MAAI,MAAM,SAAU,MAAM,MAAQ,QAAO;AACzC,MAAI,MAAM,SAAU,MAAM,MAAQ,QAAO;AAEzC,SAAO;AACT;;;AC7EA,OAAO,iBAAiB;AAajB,SAAS,uBAAuB,MAAkC;AACvE,QAAM,UAAU,IAAI,YAAY,IAAI;AACpC,QAAM,gBAAoC,CAAC;AAE3C,MAAI,KAAK,QAAQ,UAAU;AAC3B,SAAO,IAAI;AACT,kBAAc,KAAK;AAAA,MACjB,UAAU,GAAG;AAAA,MACb,UAAU,GAAG,YAAY;AAAA,IAC3B,CAAC;AACD,SAAK,QAAQ,UAAU;AAAA,EACzB;AAEA,SAAO;AACT;;;AC3BA,SAAS,oBAAoB;AAW7B,IAAI,aAAmC;AAEvC,SAAS,gBAA+B;AACtC,MAAI,CAAC,YAAY;AACf,iBAAa,aAAa,GAAG,CAAC,EAAE,WAAW,IAAI;AAAA,EACjD;AACA,SAAO;AACT;AAKO,SAAS,QACd,KACA,UACA,YACA,aAA8B,KAC9B,YAAoB,UACd;AACN,MAAI,OAAO,GAAG,SAAS,IAAI,UAAU,IAAI,QAAQ,MAAM,UAAU;AACnE;AAMO,SAAS,YACd,MACA,UACA,YACA,aAA8B,KAC9B,YAAoB,UACpB,KACa;AACb,QAAM,IAAI,OAAO,cAAc;AAC/B,UAAQ,GAAG,UAAU,YAAY,YAAY,SAAS;AAEtD,QAAM,IAAI,EAAE,YAAY,IAAI;AAE5B,QAAM,SACJ,EAAE,yBAAyB,EAAE,2BAA2B,WAAW;AACrE,QAAM,UACJ,EAAE,0BAA0B,EAAE,4BAA4B,WAAW;AAEvE,SAAO;AAAA,IACL,OAAO,EAAE;AAAA,IACT;AAAA,IACA;AAAA,IACA,QAAQ,SAAS;AAAA,EACnB;AACF;AAKO,SAAS,YACd,MACA,UACA,YACA,aAA8B,KAC9B,YAAoB,UACpB,KACA,gBAAwB,GAChB;AACR,QAAM,OAAO;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE;AACF,MAAI,kBAAkB,KAAK,KAAK,WAAW,EAAG,QAAO;AACrD,SAAO,OAAO,gBAAgB,KAAK;AACrC;;;AC9CA,SAAS,sBACP,MACA,UACA,YACA,YACA,WACA,KACA,gBAAwB,GAChB;AACR,QAAM,YAAY,IAAI,KAAK,UAAU,QAAW,EAAE,aAAa,WAAW,CAAC;AAC3E,MAAI,aAAa;AACjB,MAAI,aAAa;AAEjB,aAAW,EAAE,QAAQ,KAAK,UAAU,QAAQ,IAAI,GAAG;AACjD,QAAI,iBAAiB;AACrB,eAAW,QAAQ,SAAS;AAC1B,UAAI,QAAQ,IAAI,GAAG;AACjB,yBAAiB;AACjB;AAAA,MACF;AAAA,IACF;AAEA,QAAI,gBAAgB;AAClB,UAAI,YAAY;AACd,sBAAc;AAAA,UACZ;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AACA,qBAAa;AAAA,MACf;AACA,oBAAc;AAAA,IAChB,OAAO;AACL,oBAAc;AAAA,IAChB;AAAA,EACF;AAEA,MAAI,YAAY;AACd,kBAAc;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAYO,SAAS,WACd,MACA,OACA,UACA,KACA,cACkB;AAClB,QAAM,WAAW,MAAM,YAAY;AACnC,QAAM,aAAa,MAAM,cAAc;AACvC,QAAM,aAAa,MAAM,cAAc;AACvC,QAAM,YAAY,MAAM,aAAa;AACrC,QAAM,QAAQ,MAAM,SAAS;AAC7B,QAAM,YAAY,MAAM,aAAa;AAErC,QAAM,aAAa;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,eAAe;AAAA,IACnB,MAAM;AAAA,IACN;AAAA,IACA;AAAA,EACF;AACA,QAAM,gBACJ,OAAO,MAAM,kBAAkB,WAAW,MAAM,gBAAgB;AAClE,QAAM,aAAa,MAAM,cAAc;AACvC,QAAM,YAAY,MAAM,aAAa;AACrC,QAAM,eAAe,MAAM,gBAAgB;AAC3C,QAAM,iBAAiB,MAAM;AAG7B,QAAM,UAAU,eACZ,CAAC,MAAc,OACb;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM;AAAA,EACR,IACF,CAAC,MAAc,OACb;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM;AAAA,EACR;AAGN,MAAI,gBAAgB;AACpB,MAAI,MAAM,kBAAkB,aAAa;AACvC,oBAAgB,KAAK,YAAY;AAAA,EACnC,WAAW,MAAM,kBAAkB,aAAa;AAC9C,oBAAgB,KAAK,YAAY;AAAA,EACnC,WAAW,MAAM,kBAAkB,cAAc;AAC/C,oBAAgB,KAAK,QAAQ,SAAS,CAAC,MAAM,EAAE,YAAY,CAAC;AAAA,EAC9D;AAEA,QAAM,SAAS,eAAe,YAAY,eAAe;AACzD,QAAM,qBAAqB,eAAe,SAAS,eAAe;AAGlE,QAAM,aAAa,qBACf,cAAc,MAAM,IAAI,IACxB,cAAc,MAAM,IAAI;AAE5B,QAAM,QAAkB,CAAC;AAEzB,aAAW,aAAa,YAAY;AAClC,QAAI,QAAQ;AACV,YAAM,KAAK,SAAS;AACpB;AAAA,IACF;AAGA,UAAM,UAAU;AAAA,MACd;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,UAAM,KAAK,GAAG,OAAO;AAAA,EACvB;AAGA,MAAI,iBAAiB,cAAc,UAAU,MAAM,WAAW,GAAG;AAC/D,UAAM,OAAO,MAAM,CAAC;AACpB,UAAM,YAAY,QAAQ,IAAI;AAC9B,QAAI,YAAY,UAAU;AACxB,YAAM,CAAC,IAAI;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,QAAM,WAA0B,CAAC;AACjC,MAAI,cAAc;AAClB,MAAI,eAAe;AAEnB,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,OAAO,MAAM,CAAC;AACpB,UAAM,YAAY,QAAQ,IAAI;AAE9B,QAAI,IAAI;AACR,QAAI,cAAc,UAAU;AAC1B,WAAK,WAAW,aAAa;AAAA,IAC/B,WAAW,cAAc,SAAS;AAChC,UAAI,WAAW;AAAA,IACjB;AAEA,UAAM,UAAU;AAAA,MACd,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,aAAS,KAAK;AAAA,MACZ,MAAM;AAAA,MACN;AAAA,MACA,GAAG,eAAe,eAAe,QAAQ,SAAS,QAAQ,WAAW;AAAA,MACrE,OAAO;AAAA,MACP,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ,QAAQ;AAAA,MAChB;AAAA,MACA;AAAA,MACA,WAAW;AAAA,IACb,CAAC;AAED,mBAAe;AACf,mBAAe,KAAK,IAAI,cAAc,SAAS;AAAA,EACjD;AAEA,SAAO;AAAA,IACL;AAAA,IACA,OAAO;AAAA,IACP,QAAQ;AAAA,EACV;AACF;AAEA,SAAS,kBACP,YACA,UACA,SACQ;AACR,MAAI,eAAe,UAAa,eAAe,UAAU;AAEvD,WAAO,UAAU,QAAQ,SAAS,QAAQ,UAAU,WAAW;AAAA,EACjE;AACA,MAAI,OAAO,eAAe,UAAU;AAElC,WAAO,aAAa,IAAI,aAAa,aAAa;AAAA,EACpD;AACA,QAAM,SAAS,WAAW,OAAO,UAAU,CAAC;AAC5C,SAAO,MAAM,MAAM,IAAI,WAAW,MAAM;AAC1C;AAEA,SAAS,SACP,MACA,UACA,UACA,YACA,YACA,WACA,eACA,WACA,KACA,WACU;AACV,MAAI,CAAC,KAAM,QAAO,CAAC,EAAE;AAErB,QAAM,KACJ,cACC,CAAC,SACA;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEJ,QAAM,YAAY,uBAAuB,IAAI;AAC7C,QAAM,QAAkB,CAAC;AACzB,MAAI,YAAY;AAChB,MAAI,YAAY;AAEhB,aAAW,OAAO,WAAW;AAC3B,UAAM,UAAU,KAAK,MAAM,WAAW,IAAI,QAAQ;AAClD,UAAM,WAAW,GAAG,OAAO;AAE3B,QAAI,WAAW,YAAY,YAAY,WAAW;AAEhD,YAAM,OAAO,KAAK,MAAM,WAAW,SAAS,EAAE,QAAQ,QAAQ,EAAE;AAChE,YAAM,KAAK,IAAI;AACf,kBAAY;AAAA,IACd,WAAW,WAAW,YAAY,cAAc,aAAa;AAE3D,YAAM,SAAS;AAAA,QACb;AAAA,QACA;AAAA,QACA,IAAI;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,YAAM,KAAK,GAAG,OAAO,KAAK;AAC1B,kBAAY,OAAO;AAAA,IACrB;AAEA,QAAI,IAAI,UAAU;AAEhB,YAAM,OAAO,KAAK,MAAM,WAAW,IAAI,QAAQ,EAAE,QAAQ,QAAQ,EAAE;AACnE,YAAM,KAAK,IAAI;AACf,kBAAY,IAAI;AAAA,IAClB;AAEA,gBAAY,IAAI;AAAA,EAClB;AAGA,MAAI,YAAY,KAAK,QAAQ;AAC3B,UAAM,YAAY,KAAK,MAAM,SAAS,EAAE,QAAQ,QAAQ,EAAE;AAC1D,QAAI,WAAW;AACb,YAAM,WAAW,GAAG,SAAS;AAC7B,UAAI,WAAW,YAAY,cAAc,aAAa;AACpD,cAAM,SAAS;AAAA,UACb;AAAA,UACA;AAAA,UACA,KAAK;AAAA,UACL;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AACA,cAAM,KAAK,GAAG,OAAO,KAAK;AAAA,MAC5B,OAAO;AACL,cAAM,KAAK,SAAS;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAEA,SAAO,MAAM,SAAS,IAAI,QAAQ,CAAC,EAAE;AACvC;AAEA,SAAS,eACP,MACA,OACA,KACA,UACA,UACA,YACA,YACA,WACA,KACA,gBAAwB,GACxB,WACqC;AACrC,QAAM,KACJ,cACC,CAAC,SACA;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACJ,QAAM,QAAkB,CAAC;AACzB,MAAI,MAAM;AAEV,SAAO,MAAM,KAAK;AAChB,QAAI,WAAW,MAAM;AACrB,WAAO,WAAW,KAAK;AACrB,YAAM,QAAQ,KAAK,MAAM,KAAK,WAAW,CAAC;AAC1C,YAAM,IAAI,GAAG,KAAK;AAClB,UAAI,IAAI,SAAU;AAClB;AAAA,IACF;AAEA,UAAM,OAAO,KAAK,MAAM,KAAK,QAAQ;AACrC,QAAI,KAAK,KAAK,EAAG,OAAM,KAAK,IAAI;AAChC,UAAM;AAAA,EACR;AAEA,SAAO,EAAE,OAAO,QAAQ,IAAI;AAC9B;AAEA,SAAS,qBACP,MACA,UACA,UACA,YACA,YACA,WACA,KACA,gBAAwB,GAChB;AACR,QAAM,WAAW;AACjB,QAAM,gBAAgB;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,aAAa,WAAW;AAE9B,WAAS,IAAI,KAAK,SAAS,GAAG,IAAI,GAAG,KAAK;AACxC,UAAM,YAAY,KAAK,MAAM,GAAG,CAAC;AACjC,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,QAAI,KAAK,YAAY;AACnB,aAAO,YAAY;AAAA,IACrB;AAAA,EACF;AAEA,SAAO;AACT;AAMO,SAAS,sBACd,MACA,OACA,KACA,cACA;AAIA,QAAM,eAAe,EAAE,GAAG,OAAO,cAAc,OAAgB;AAC/D,SAAO,CACL,OACA,YACA,SACA,gBACG;AACH,UAAM,WAAW,QAAQ,IAAI,QAAQ;AACrC,UAAM,SAAS,WAAW,MAAM,cAAc,UAAU,KAAK,YAAY;AAOzE,UAAM,UAAU,OAAO,SAAS,SAAS;AACzC,UAAM,gBAAgB,UAClB,KAAK,IAAI,UAAU,QAAQ,IAAI,QAAQ,OAAO,KAAK,IACnD,OAAO;AACX,WAAO,EAAE,OAAO,KAAK,IAAI,eAAe,QAAQ,GAAG,QAAQ,OAAO,OAAO;AAAA,EAC3E;AACF;;;ACzfO,SAAS,UACd,KACA,GACA,GACA,OACA,QACA,cAMM;AACN,MAAI,UAAU;AAEd,MAAI,gBAAgB,UAAU,YAAY,GAAG;AAC3C,UAAM,EAAE,SAAS,UAAU,aAAa,WAAW,IAAI;AACvD;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF,OAAO;AACL,QAAI,KAAK,GAAG,GAAG,OAAO,MAAM;AAAA,EAC9B;AAEA,MAAI,KAAK;AACX;AAKO,SAAS,YACd,KACA,GACA,GACA,GACA,GACA,IACA,IACA,IACA,IACM;AAEN,QAAM,OAAO,KAAK,IAAI,GAAG,CAAC,IAAI;AAC9B,OAAK,KAAK,IAAI,IAAI,IAAI;AACtB,OAAK,KAAK,IAAI,IAAI,IAAI;AACtB,OAAK,KAAK,IAAI,IAAI,IAAI;AACtB,OAAK,KAAK,IAAI,IAAI,IAAI;AAEtB,MAAI,OAAO,IAAI,IAAI,CAAC;AACpB,MAAI,OAAO,IAAI,IAAI,IAAI,CAAC;AACxB,MAAI,KAAK,EAAG,KAAI,MAAM,IAAI,GAAG,GAAG,IAAI,GAAG,IAAI,IAAI,EAAE;AACjD,MAAI,OAAO,IAAI,GAAG,IAAI,IAAI,EAAE;AAC5B,MAAI,KAAK,EAAG,KAAI,MAAM,IAAI,GAAG,IAAI,GAAG,IAAI,IAAI,IAAI,IAAI,GAAG,EAAE;AACzD,MAAI,OAAO,IAAI,IAAI,IAAI,CAAC;AACxB,MAAI,KAAK,EAAG,KAAI,MAAM,GAAG,IAAI,GAAG,GAAG,IAAI,IAAI,IAAI,EAAE;AACjD,MAAI,OAAO,GAAG,IAAI,EAAE;AACpB,MAAI,KAAK,EAAG,KAAI,MAAM,GAAG,GAAG,IAAI,IAAI,GAAG,EAAE;AACzC,MAAI,UAAU;AAChB;AAEA,SAAS,UAAU,GAKP;AACV,SACE,EAAE,UAAU,KAAK,EAAE,WAAW,KAAK,EAAE,cAAc,KAAK,EAAE,aAAa;AAE3E;;;AC3EO,SAAS,sBACd,KACA,aACA,GACA,GACA,OACA,QACuB;AACvB,QAAM,UAAU,YAAY,KAAK;AAEjC,MAAI,QAAQ,WAAW,iBAAiB,GAAG;AACzC,WAAO,oBAAoB,KAAK,SAAS,GAAG,GAAG,OAAO,MAAM;AAAA,EAC9D;AAEA,MAAI,QAAQ,WAAW,iBAAiB,GAAG;AACzC,WAAO,oBAAoB,KAAK,SAAS,GAAG,GAAG,OAAO,MAAM;AAAA,EAC9D;AAEA,SAAO;AACT;AAEA,SAAS,oBACP,KACA,KACA,GACA,GACA,OACA,QACuB;AAEvB,QAAM,QAAQ,IAAI,MAAM,0BAA0B;AAClD,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,UAAU,MAAM,CAAC,EAAG,KAAK;AAC/B,QAAM,QAAQ,kBAAkB,OAAO;AAEvC,MAAI,QAAQ;AACZ,MAAI,gBAAgB;AAGpB,QAAM,QAAQ,MAAM,CAAC,GAAG,KAAK;AAC7B,MAAI,OAAO;AACT,QAAI,MAAM,WAAW,KAAK,GAAG;AAC3B,cAAQ,iBAAiB,KAAK;AAC9B,sBAAgB;AAAA,IAClB,WAAW,MAAM,SAAS,KAAK,GAAG;AAChC,cAAQ,WAAW,KAAK;AACxB,sBAAgB;AAAA,IAClB,WAAW,MAAM,SAAS,MAAM,GAAG;AACjC,cAAQ,WAAW,KAAK,IAAI;AAC5B,sBAAgB;AAAA,IAClB;AAAA,EACF;AAGA,QAAM,OAAQ,QAAQ,MAAM,KAAK,KAAM;AACvC,QAAM,KAAK,IAAI,QAAQ;AACvB,QAAM,KAAK,IAAI,SAAS;AACxB,QAAM,WACJ,KAAK,IAAI,QAAQ,KAAK,IAAI,GAAG,CAAC,IAAI,IAAI,KAAK,IAAI,SAAS,KAAK,IAAI,GAAG,CAAC,IAAI;AAE3E,QAAM,KAAK,KAAK,WAAW,KAAK,IAAI,GAAG;AACvC,QAAM,KAAK,KAAK,WAAW,KAAK,IAAI,GAAG;AACvC,QAAM,KAAK,KAAK,WAAW,KAAK,IAAI,GAAG;AACvC,QAAM,KAAK,KAAK,WAAW,KAAK,IAAI,GAAG;AAEvC,QAAM,WAAW,IAAI,qBAAqB,IAAI,IAAI,IAAI,EAAE;AAGxD,QAAM,QAAQ,MAAM,MAAM,aAAa;AACvC,gBAAc,UAAU,KAAK;AAE7B,SAAO;AACT;AAEA,SAAS,oBACP,KACA,KACA,GACA,GACA,OACA,QACuB;AACvB,QAAM,QAAQ,IAAI,MAAM,0BAA0B;AAClD,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,UAAU,MAAM,CAAC,EAAG,KAAK;AAC/B,QAAM,QAAQ,kBAAkB,OAAO;AAEvC,QAAM,KAAK,IAAI,QAAQ;AACvB,QAAM,KAAK,IAAI,SAAS;AACxB,QAAM,SAAS,KAAK,IAAI,OAAO,MAAM,IAAI;AAEzC,QAAM,WAAW,IAAI,qBAAqB,IAAI,IAAI,GAAG,IAAI,IAAI,MAAM;AAGnE,MAAI,gBAAgB;AACpB,QAAM,QAAQ,MAAM,CAAC,GAAG,KAAK,KAAK;AAClC,MACE,MAAM,WAAW,QAAQ,KACzB,MAAM,WAAW,SAAS,KAC1B,MAAM,WAAW,SAAS,KAC1B,MAAM,WAAW,UAAU,GAC3B;AACA,oBAAgB;AAAA,EAClB;AAEA,gBAAc,UAAU,MAAM,MAAM,aAAa,CAAC;AAElD,SAAO;AACT;AAEA,SAAS,cAAc,UAA0B,OAAuB;AACtE,MAAI,MAAM,WAAW,EAAG;AAExB,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,OAAO,MAAM,CAAC,EAAG,KAAK;AAC5B,UAAM,eAAe,KAAK,MAAM,6BAA6B;AAE7D,QAAI,cAAc;AAChB,YAAM,QAAQ,aAAa,CAAC;AAC5B,YAAM,MAAM,aAAa,CAAC;AAC1B,YAAM,SAAS,IAAI,SAAS,GAAG,IAC3B,WAAW,GAAG,IAAI,MAClB,WAAW,GAAG;AAClB,eAAS,aAAa,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,MAAM,CAAC,GAAG,KAAK;AAAA,IAC/D,OAAO;AAEL,YAAM,SAAS,MAAM,WAAW,IAAI,MAAM,KAAK,MAAM,SAAS;AAC9D,eAAS,aAAa,QAAQ,IAAI;AAAA,IACpC;AAAA,EACF;AACF;AAEA,SAAS,iBAAiB,KAAqB;AAC7C,QAAM,MAA8B;AAAA,IAClC,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,WAAW;AAAA,IACX,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,mBAAmB;AAAA,IACnB,kBAAkB;AAAA,EACpB;AACA,SAAO,IAAI,GAAG,KAAK;AACrB;AAEA,SAAS,kBAAkB,SAA2B;AACpD,QAAM,QAAkB,CAAC;AACzB,MAAI,UAAU;AACd,MAAI,aAAa;AAEjB,aAAW,QAAQ,SAAS;AAC1B,QAAI,SAAS,IAAK;AAClB,QAAI,SAAS,IAAK;AAClB,QAAI,SAAS,OAAO,eAAe,GAAG;AACpC,YAAM,KAAK,OAAO;AAClB,gBAAU;AAAA,IACZ,OAAO;AACL,iBAAW;AAAA,IACb;AAAA,EACF;AACA,MAAI,QAAQ,KAAK,EAAG,OAAM,KAAK,OAAO;AAEtC,SAAO;AACT;;;AC9KA,SAAS,iBAAiB;;;ACoBnB,SAAS,aACd,MACA,MACA,MACA,MACA,MACA,MACS;AACT,QAAM,WAAW,OAAO;AACxB,QAAM,WAAW,OAAO;AAExB,MAAI,IAAY,IAAY,IAAY;AAExC,MAAI,WAAW,UAAU;AACvB,SAAK;AACL,SAAK,OAAO;AACZ,UAAM,OAAO,MAAM;AACnB,SAAK;AAAA,EACP,OAAO;AACL,SAAK;AACL,SAAK,OAAO;AACZ,SAAK;AACL,UAAM,OAAO,MAAM;AAAA,EACrB;AAEA,SAAO,EAAE,IAAI,IAAI,IAAI,IAAI,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,KAAK;AAClE;AAMO,SAAS,eACd,MACA,MACA,MACA,MACA,MACA,MACS;AACT,QAAM,WAAW,OAAO;AACxB,QAAM,WAAW,OAAO;AAExB,MAAI,IAAY;AAEhB,MAAI,WAAW,UAAU;AACvB,SAAK;AACL,SAAK,OAAO;AAAA,EACd,OAAO;AACL,SAAK;AACL,SAAK,OAAO;AAAA,EACd;AAEA,QAAM,KAAK,QAAQ,OAAO,MAAM;AAChC,QAAM,KAAK,QAAQ,OAAO,MAAM;AAEhC,SAAO,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,MAAM,IAAI,MAAM,IAAI,IAAI,IAAI,GAAG;AAC5D;;;AD5DA,eAAsB,UACpB,KACA,KACA,GACA,GACA,OACA,QACA,OACA,gBACe;AACf,QAAM,QAAQ,kBAAmB,MAAM,UAAU,GAAG;AACpD,QAAM,YAAY,OAAO,aAAa;AAEtC,MAAI,cAAc,QAAQ;AACxB,QAAI,UAAU,OAAO,GAAG,GAAG,OAAO,MAAM;AACxC;AAAA,EACF;AAEA,QAAM,OAAO,MAAM;AACnB,QAAM,OAAO,MAAM;AAEnB,MAAI,cAAc,WAAW;AAC3B,UAAM,IAAI,eAAe,MAAM,MAAM,GAAG,GAAG,OAAO,MAAM;AACxD,QAAI,UAAU,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;AAAA,EAC7C,WAAW,cAAc,SAAS;AAChC,UAAM,IAAI,aAAa,MAAM,MAAM,GAAG,GAAG,OAAO,MAAM;AACtD,QAAI,UAAU,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;AAAA,EACrE,WAAW,cAAc,QAAQ;AAC/B,UAAM,KAAK,KAAK,QAAQ,QAAQ;AAChC,UAAM,KAAK,KAAK,SAAS,QAAQ;AACjC,QAAI,UAAU,OAAO,IAAI,EAAE;AAAA,EAC7B,WAAW,cAAc,cAAc;AACrC,QAAI,QAAQ,SAAS,QAAQ,QAAQ;AACnC,YAAM,KAAK,KAAK,QAAQ,QAAQ;AAChC,YAAM,KAAK,KAAK,SAAS,QAAQ;AACjC,UAAI,UAAU,OAAO,IAAI,EAAE;AAAA,IAC7B,OAAO;AACL,YAAM,IAAI,eAAe,MAAM,MAAM,GAAG,GAAG,OAAO,MAAM;AACxD,UAAI,UAAU,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;AAAA,IAC7C;AAAA,EACF;AACF;;;AElDO,SAAS,SACd,KACA,GACA,GACA,OACA,QACA,OACM;AACN,QAAM,eAAe,gBAAgB,KAAK;AAC1C,QAAM,oBACJ,aAAa,UAAU,KACvB,aAAa,WAAW,KACxB,aAAa,cAAc,KAC3B,aAAa,aAAa;AAG5B,MAAI,MAAM,WAAW;AACnB,kBAAc,KAAK,GAAG,GAAG,OAAO,QAAQ,MAAM,WAAW,YAAY;AAAA,EACvE;AAGA,MAAI,MAAM,iBAAiB;AACzB,QAAI,YAAY,MAAM;AAEtB,QAAI,mBAAmB;AACrB,UAAI,UAAU;AACd;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,aAAa;AAAA,QACb,aAAa;AAAA,QACb,aAAa;AAAA,QACb,aAAa;AAAA,MACf;AACA,UAAI,KAAK;AAAA,IACX,OAAO;AACL,UAAI,SAAS,GAAG,GAAG,OAAO,MAAM;AAAA,IAClC;AAAA,EACF;AAGA,cAAY,KAAK,GAAG,GAAG,OAAO,QAAQ,OAAO,YAAY;AAC3D;AAEA,SAAS,gBAAgB,OAAsB;AAC7C,SAAO;AAAA,IACL,SAAS,SAAS,MAAM,mBAAmB;AAAA,IAC3C,UAAU,SAAS,MAAM,oBAAoB;AAAA,IAC7C,aAAa,SAAS,MAAM,uBAAuB;AAAA,IACnD,YAAY,SAAS,MAAM,sBAAsB;AAAA,EACnD;AACF;AAEO,SAAS,yBAAyB,OAAsB;AAC7D,SAAO,gBAAgB,KAAK;AAC9B;AAEA,SAAS,YACP,KACA,GACA,GACA,OACA,QACA,OACA,cACM;AACN,QAAM,oBACJ,aAAa,UAAU,KACvB,aAAa,WAAW,KACxB,aAAa,cAAc,KAC3B,aAAa,aAAa;AAG5B,QAAM,KAAK,SAAS,MAAM,cAAc;AACxC,QAAM,KAAK,SAAS,MAAM,gBAAgB;AAC1C,QAAM,KAAK,SAAS,MAAM,iBAAiB;AAC3C,QAAM,KAAK,SAAS,MAAM,eAAe;AAEzC,MAAI,OAAO,KAAK,OAAO,KAAK,OAAO,KAAK,OAAO,EAAG;AAElD,QAAM,eAAe,OAAO,MAAM,OAAO,MAAM,OAAO,MAAM,KAAK;AACjE,QAAM,KAAK,MAAM,kBAAkB;AACnC,QAAM,KAAK,MAAM,oBAAoB;AACrC,QAAM,KAAK,MAAM,qBAAqB;AACtC,QAAM,KAAK,MAAM,mBAAmB;AACpC,QAAM,eAAe,OAAO,MAAM,OAAO,MAAM,OAAO;AAEtD,MAAI,gBAAgB,cAAc;AAChC,QAAI,cAAc;AAClB,QAAI,YAAY;AAEhB,QAAI,mBAAmB;AACrB,UAAI,UAAU;AACd,YAAM,OAAO,KAAK;AAClB;AAAA,QACE;AAAA,QACA,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,KAAK,IAAI,GAAG,aAAa,UAAU,IAAI;AAAA,QACvC,KAAK,IAAI,GAAG,aAAa,WAAW,IAAI;AAAA,QACxC,KAAK,IAAI,GAAG,aAAa,cAAc,IAAI;AAAA,QAC3C,KAAK,IAAI,GAAG,aAAa,aAAa,IAAI;AAAA,MAC5C;AACA,UAAI,OAAO;AAAA,IACb,OAAO;AACL,UAAI,WAAW,IAAI,KAAK,GAAG,IAAI,KAAK,GAAG,QAAQ,IAAI,SAAS,EAAE;AAAA,IAChE;AACA;AAAA,EACF;AAGA,MAAI,KAAK,GAAG;AACV,QAAI,cAAc;AAClB,QAAI,YAAY;AAChB,QAAI,UAAU;AACd,QAAI,OAAO,GAAG,IAAI,KAAK,CAAC;AACxB,QAAI,OAAO,IAAI,OAAO,IAAI,KAAK,CAAC;AAChC,QAAI,OAAO;AAAA,EACb;AACA,MAAI,KAAK,GAAG;AACV,QAAI,cAAc;AAClB,QAAI,YAAY;AAChB,QAAI,UAAU;AACd,QAAI,OAAO,IAAI,QAAQ,KAAK,GAAG,CAAC;AAChC,QAAI,OAAO,IAAI,QAAQ,KAAK,GAAG,IAAI,MAAM;AACzC,QAAI,OAAO;AAAA,EACb;AACA,MAAI,KAAK,GAAG;AACV,QAAI,cAAc;AAClB,QAAI,YAAY;AAChB,QAAI,UAAU;AACd,QAAI,OAAO,GAAG,IAAI,SAAS,KAAK,CAAC;AACjC,QAAI,OAAO,IAAI,OAAO,IAAI,SAAS,KAAK,CAAC;AACzC,QAAI,OAAO;AAAA,EACb;AACA,MAAI,KAAK,GAAG;AACV,QAAI,cAAc;AAClB,QAAI,YAAY;AAChB,QAAI,UAAU;AACd,QAAI,OAAO,IAAI,KAAK,GAAG,CAAC;AACxB,QAAI,OAAO,IAAI,KAAK,GAAG,IAAI,MAAM;AACjC,QAAI,OAAO;AAAA,EACb;AACF;AAEA,SAAS,cACP,KACA,GACA,GACA,OACA,QACA,WACA,cACM;AAEN,QAAM,QAAQ,UAAU;AAAA,IACtB;AAAA,EACF;AACA,MAAI,CAAC,MAAO;AAEZ,QAAM,UAAU,WAAW,MAAM,CAAC,CAAE;AACpC,QAAM,UAAU,WAAW,MAAM,CAAC,CAAE;AACpC,QAAM,OAAO,WAAW,MAAM,CAAC,CAAE;AACjC,QAAM,QAAQ,MAAM,CAAC,EAAG,KAAK;AAE7B,QAAM,QAAQ;AAAA,IACZ,aAAa;AAAA,IACb,aAAa;AAAA,IACb,aAAa;AAAA,IACb,aAAa;AAAA,EACf;AAGA,QAAM,SAAS,OAAO,IAAI,KAAK,IAAI,OAAO,IAAI,KAAK,IAAI,OAAO;AAC9D,MAAI,KAAK;AACT,MAAI,UAAU;AACd,MAAI,KAAK,IAAI,QAAQ,IAAI,QAAQ,QAAQ,SAAS,GAAG,SAAS,SAAS,CAAC;AACxE,MAAI,UAAU,GAAG,GAAG,OAAO,QAAQ,KAAK;AACxC,MAAI,KAAK,SAAS;AAIlB,MAAI,SAAS,QAAQ,OAAO,CAAC;AAC7B,MAAI,UAAU,SAAS,OAAO;AAC9B,MAAI,YAAY;AAChB,MAAI,UAAU;AACd,MAAI,UAAU,GAAG,GAAG,OAAO,QAAQ,KAAK;AACxC,MAAI,KAAK;AACT,MAAI,QAAQ;AACd;AAEA,SAAS,SAAS,GAAoB;AACpC,MAAI,OAAO,MAAM,SAAU,QAAO;AAClC,MAAI,MAAM,UAAa,MAAM,KAAM,QAAO;AAC1C,QAAM,IAAI,WAAW,OAAO,CAAC,CAAC;AAC9B,SAAO,MAAM,CAAC,IAAI,IAAI;AACxB;;;ACjNA,SAAS,cAAc;AAYvB,SAAS,oBACP,OACA,OACoB;AACpB,MAAI,OAAO,YAAY,MAAM,eAAgB,QAAO;AACpD,SAAO;AACT;AAMA,SAAS,oBACP,OACyB;AACzB,QAAM,QAAQ,MAAM;AACpB,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,EAAE,GAAG,OAAO,GAAG,MAAM;AAC9B;AAQO,SAAS,iBACd,KACA,MACA,GACA,GACA,OACA,QACM;AACN,MAAI,KAAK;AACT,MAAI,UAAU,GAAG,CAAC;AAGlB,QAAM,UAAU,KAAK,MAAM;AAC3B,MAAI,SAAS;AACX,UAAM,QAAQ,QAAQ,MAAM,QAAQ,EAAE,IAAI,MAAM;AAChD,QAAI,MAAM,WAAW,GAAG;AACtB,YAAM,CAAC,KAAK,KAAK,KAAK,GAAG,IAAI;AAC7B,YAAM,SAAS,QAAQ;AACvB,YAAM,SAAS,SAAS;AACxB,UAAI,MAAM,QAAQ,MAAM;AACxB,UAAI,UAAU,CAAC,KAAK,CAAC,GAAG;AAAA,IAC1B;AAAA,EACF;AAGA,QAAM,QAAS,KAAK,MAAM,SAAgC;AAG1D,QAAM,SAAS,oBAAoB,KAAK,KAAK;AAC7C,QAAM,gBACJ,oBAAoB,OAAO,MAA4B,KAAK,KAAK;AAGnE,QAAM,WAAW,KAAK,MAAM;AAC5B,MAAI,YAAY,MAAM;AACpB,UAAM,aAAa,MAAM,QAAQ,QAAQ,IAAI,WAAW,CAAC,QAAQ;AACjE,eAAW,SAAS,YAAY;AAC9B,UAAI,SAAS,QAAQ,OAAO,UAAU,UAAU;AAC9C,qBAAa,KAAK,OAAmB,eAAe,KAAK;AAAA,MAC3D;AAAA,IACF;AAAA,EACF;AAEA,MAAI,QAAQ;AACd;AAEA,SAAS,aACP,KACA,OACA,eACA,OACM;AACN,QAAM,EAAE,KAAK,IAAI;AACjB,QAAM,QAAQ,oBAAoB,MAAM,KAAK;AAE7C,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,eAAS,KAAK,OAAO,eAAe,KAAK;AACzC;AAAA,IACF,KAAK;AACH,iBAAW,KAAK,OAAO,eAAe,KAAK;AAC3C;AAAA,IACF,KAAK;AACH,kBAAY,KAAK,OAAO,eAAe,KAAK;AAC5C;AAAA,IACF,KAAK;AACH,eAAS,KAAK,OAAO,KAAK;AAC1B;AAAA,IACF,KAAK;AACH,kBAAY,KAAK,OAAO,eAAe,KAAK;AAC5C;AAAA,IACF,KAAK;AACH,kBAAY,KAAK,OAAO,eAAe,KAAK;AAC5C;AAAA,IACF,KAAK;AACH,mBAAa,KAAK,OAAO,eAAe,KAAK;AAC7C;AAAA,IACF,KAAK;AACH,gBAAU,KAAK,OAAO,eAAe,KAAK;AAC1C;AAAA,EACJ;AACF;AAEA,SAAS,SACP,KACA,OACA,eACA,OACM;AACN,QAAM,IAAI,MAAM;AAChB,MAAI,CAAC,EAAG;AAER,QAAM,OAAO,IAAI,OAAO,CAAC;AACzB,qBAAmB,KAAK,OAAO,MAAM,eAAe,KAAK;AAC3D;AAEA,SAAS,WACP,KACA,OACA,eACA,OACM;AACN,QAAM,KAAK,OAAO,MAAM,MAAM,CAAC;AAC/B,QAAM,KAAK,OAAO,MAAM,MAAM,CAAC;AAC/B,QAAM,IAAI,OAAO,MAAM,KAAK,CAAC;AAC7B,MAAI,KAAK,EAAG;AAEZ,QAAM,OAAO,IAAI,OAAO;AACxB,OAAK,IAAI,IAAI,IAAI,GAAG,GAAG,KAAK,KAAK,CAAC;AAClC,qBAAmB,KAAK,OAAO,MAAM,eAAe,KAAK;AAC3D;AAEA,SAAS,YACP,KACA,OACA,eACA,OACM;AACN,QAAM,KAAK,OAAO,MAAM,KAAK,CAAC;AAC9B,QAAM,KAAK,OAAO,MAAM,KAAK,CAAC;AAC9B,QAAM,IAAI,OAAO,MAAM,SAAS,CAAC;AACjC,QAAM,IAAI,OAAO,MAAM,UAAU,CAAC;AAClC,MAAI,KAAK,KAAK,KAAK,EAAG;AAEtB,QAAM,OAAO,IAAI,OAAO;AACxB,OAAK,KAAK,IAAI,IAAI,GAAG,CAAC;AACtB,qBAAmB,KAAK,OAAO,MAAM,eAAe,KAAK;AAC3D;AAEA,SAAS,SACP,KACA,OACA,OACM;AACN,QAAM,KAAK,OAAO,MAAM,MAAM,CAAC;AAC/B,QAAM,KAAK,OAAO,MAAM,MAAM,CAAC;AAC/B,QAAM,KAAK,OAAO,MAAM,MAAM,CAAC;AAC/B,QAAM,KAAK,OAAO,MAAM,MAAM,CAAC;AAE/B,QAAM,OAAO,IAAI,OAAO;AACxB,OAAK,OAAO,IAAI,EAAE;AAClB,OAAK,OAAO,IAAI,EAAE;AAElB,cAAY,KAAK,OAAO,MAAM,KAAK;AACrC;AAEA,SAAS,YACP,KACA,OACA,eACA,OACM;AACN,QAAM,KAAK,OAAO,MAAM,MAAM,CAAC;AAC/B,QAAM,KAAK,OAAO,MAAM,MAAM,CAAC;AAC/B,QAAM,KAAK,OAAO,MAAM,MAAM,CAAC;AAC/B,QAAM,KAAK,OAAO,MAAM,MAAM,CAAC;AAC/B,MAAI,MAAM,KAAK,MAAM,EAAG;AAExB,QAAM,OAAO,IAAI,OAAO;AACxB,OAAK,QAAQ,IAAI,IAAI,IAAI,IAAI,GAAG,GAAG,KAAK,KAAK,CAAC;AAC9C,qBAAmB,KAAK,OAAO,MAAM,eAAe,KAAK;AAC3D;AAEA,SAAS,YACP,KACA,OACA,eACA,OACM;AACN,QAAM,SAAS,YAAY,MAAM,MAA4B;AAC7D,MAAI,OAAO,SAAS,EAAG;AAEvB,QAAM,OAAO,IAAI,OAAO;AACxB,OAAK,OAAO,OAAO,CAAC,EAAG,CAAC,GAAG,OAAO,CAAC,EAAG,CAAC,CAAC;AACxC,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,SAAK,OAAO,OAAO,CAAC,EAAG,CAAC,GAAG,OAAO,CAAC,EAAG,CAAC,CAAC;AAAA,EAC1C;AACA,OAAK,UAAU;AACf,qBAAmB,KAAK,OAAO,MAAM,eAAe,KAAK;AAC3D;AAEA,SAAS,aACP,KACA,OACA,eACA,OACM;AACN,QAAM,SAAS,YAAY,MAAM,MAA4B;AAC7D,MAAI,OAAO,SAAS,EAAG;AAEvB,QAAM,OAAO,IAAI,OAAO;AACxB,OAAK,OAAO,OAAO,CAAC,EAAG,CAAC,GAAG,OAAO,CAAC,EAAG,CAAC,CAAC;AACxC,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,SAAK,OAAO,OAAO,CAAC,EAAG,CAAC,GAAG,OAAO,CAAC,EAAG,CAAC,CAAC;AAAA,EAC1C;AACA,qBAAmB,KAAK,OAAO,MAAM,eAAe,KAAK;AAC3D;AAEA,SAAS,UACP,KACA,MACA,eACA,OACM;AACN,QAAM,WACJ,KAAK,YAAa,KAAK,MAAM;AAC/B,MAAI,YAAY,KAAM;AAEtB,QAAM,SAAS,oBAAoB,KAAK,KAAK;AAC7C,QAAM,YACJ,oBAAoB,OAAO,MAA4B,KAAK,KAC5D;AACF,QAAM,aAAa,MAAM,QAAQ,QAAQ,IAAI,WAAW,CAAC,QAAQ;AACjE,aAAW,SAAS,YAAY;AAC9B,QAAI,SAAS,QAAQ,OAAO,UAAU,UAAU;AAC9C,mBAAa,KAAK,OAAO,WAAW,KAAK;AAAA,IAC3C;AAAA,EACF;AACF;AAEA,SAAS,YAAY,OAA+C;AAClE,MAAI,CAAC,MAAO,QAAO,CAAC;AACpB,QAAM,OAAO,MACV,KAAK,EACL,MAAM,QAAQ,EACd,IAAI,MAAM;AACb,QAAM,SAA6B,CAAC;AACpC,WAAS,IAAI,GAAG,IAAI,IAAI,KAAK,QAAQ,KAAK,GAAG;AAC3C,WAAO,KAAK,CAAC,KAAK,CAAC,GAAI,KAAK,IAAI,CAAC,CAAE,CAAC;AAAA,EACtC;AACA,SAAO;AACT;AAEA,SAAS,mBACP,KACA,OACA,MACA,eACA,OACM;AAEN,QAAM,OACJ,oBAAoB,MAAM,MAA4B,KAAK,KAC3D;AACF,MAAI,SAAS,QAAQ;AACnB,QAAI,YAAY;AAChB,QAAI,KAAK,IAAI;AAAA,EACf;AAEA,cAAY,KAAK,OAAO,MAAM,KAAK;AACrC;AAEA,SAAS,YACP,KACA,OACA,MACA,OACM;AACN,QAAM,SAAS,oBAAoB,MAAM,QAA8B,KAAK;AAC5E,MAAI,CAAC,UAAU,WAAW,OAAQ;AAElC,MAAI,cAAc;AAClB,MAAI,YAAY,OAAO,MAAM,eAAe,MAAM,cAAc,KAAK,CAAC;AACtE,MAAI,UACA,MAAM,iBAAiB,MAAM,gBAAgB,KAC/C;AACF,MAAI,WACA,MAAM,kBAAkB,MAAM,iBAAiB,KACjD;AACF,MAAI,OAAO,IAAI;AACjB;;;ACpTA,SAAS,aAAAC,kBAAiB;;;ACenB,IAAM,YAGT;AAAA,EACF,SAAS,CAAC,SACR,6DAA6D,KAAK,YAAY,CAAC;AAAA,EACjF,UAAU;AAAA,EACV,UAAU;AAAA,EACV,MAAM;AAAA,EACN,QAAQ,CAAC,SACP,qEAAqE,KAAK,YAAY,CAAC;AAAA,EACzF,YAAY,CAAC,SACX,qEAAqE,KAAK,YAAY,CAAC;AAC3F;AAEA,IAAM,QAAQ,OAAO,aAAa,IAAI;AACtC,IAAM,SAAS;AAER,SAAS,aAAa,MAAsB;AACjD,SAAO,YAAY,KAAK,QAAQ,KAAK,IAAI,IAAI,KAAK,QAAQ,QAAQ,EAAE,IAAI,IAAI;AAC9E;AAEO,SAAS,YAAY,mBAAmC;AAC7D,QAAM,IAAc,CAAC;AACrB,MAAI,IAAI,GACN,IAAI,GACJ,IAAI;AAEN,SAAO,IAAI,kBAAkB,QAAQ;AACnC,QAAI,kBAAkB,WAAW,GAAG;AACpC,QAAI,GAAG;AACL,QAAE,MAAM,SAAU,IAAI,SAAU,OAAO,IAAI,QAAQ,SAAS,EAAE,CAAC;AAC/D,UAAI;AAAA,IACN,WAAW,SAAS,KAAK,KAAK,OAAO;AACnC,UAAI;AAAA,IACN,OAAO;AACL,QAAE,KAAK,EAAE,SAAS,EAAE,CAAC;AAAA,IACvB;AAAA,EACF;AACA,SAAO,EAAE,KAAK,GAAG;AACnB;AAEA,IAAM,aAA8C,CAAC;AAErD,eAAsB,UACpB,MACA,MACiB;AACjB,QAAM,MAAM,OAAO,MAAM;AACzB,MAAI,OAAO,WAAY,QAAO,WAAW,GAAG;AAE5C,QAAM,MAAM,UAAU,IAAI;AAC1B,MAAI,OAAO,QAAQ,YAAY;AAC7B,WAAQ,WAAW,GAAG,IAAI,MAAM,IAAI,IAAI,CAAC,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC;AAAA,EACjE;AACA,SAAQ,WAAW,GAAG,IAAI,MAAM,GAAG,GAAG,GAAG,KAAK,YAAY,CAAC,MAAM,EAAE;AAAA,IAAK,CAAC,MACvE,EAAE,KAAK;AAAA,EACT;AACF;;;AC/DO,SAAS,kBACd,MACAC,cACA,WACW;AACX,QAAM,OAAkB,CAAC;AACzB,QAAM,YAAY,IAAI,KAAK,UAAU,QAAW,EAAE,aAAa,WAAW,CAAC;AAC3E,MAAI,cAAc;AAClB,MAAI,WAAW;AACf,MAAI,aAAa;AAEjB,aAAW,EAAE,QAAQ,KAAK,UAAU,QAAQ,IAAI,GAAG;AACjD,QAAI,gBAAgB,OAAO,GAAG;AAE5B,UAAI,aAAa;AACf,cAAM,YAAYA,aAAY,WAAW;AACzC,aAAK,KAAK;AAAA,UACR,MAAM;AAAA,UACN,MAAM;AAAA,UACN,GAAG;AAAA,UACH,OAAO;AAAA,QACT,CAAC;AACD,mBAAW,aAAa;AACxB,sBAAc;AAAA,MAChB;AACA,WAAK,KAAK;AAAA,QACR,MAAM;AAAA,QACN,MAAM;AAAA,QACN,GAAG;AAAA,QACH,OAAO;AAAA,MACT,CAAC;AACD,kBAAY;AACZ,mBAAa;AAAA,IACf,OAAO;AACL,UAAI,CAAC,YAAa,cAAa;AAC/B,qBAAe;AAAA,IACjB;AAAA,EACF;AAGA,MAAI,aAAa;AACf,UAAM,YAAYA,aAAY,WAAW;AACzC,SAAK,KAAK;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,MACN,GAAG;AAAA,MACH,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAMA,SAAS,gBAAgB,UAA2B;AAClD,aAAW,QAAQ,UAAU;AAC3B,QAAI,QAAQ,IAAI,EAAG,QAAO;AAAA,EAC5B;AACA,SAAO;AACT;;;AF/DA,IAAM,kBAAkB,oBAAI,IAAmC;AAE/D,SAAS,eACP,OACA,MACuB;AACvB,QAAM,OAAO,aAAa,IAAI;AAC9B,QAAM,MAAM,QAAQ,MAAM;AAC1B,MAAI,SAAS,gBAAgB,IAAI,GAAG;AACpC,MAAI,CAAC,QAAQ;AACX,aAAS,UAAU,OAAO,IAAI,EAC3B,KAAK,CAAC,YAAY;AACjB,UAAI,CAAC,WAAW,CAAC,QAAQ,SAAS,MAAM,EAAG,QAAO;AAClD,YAAM,UACJ,+BACA,OAAO,KAAK,OAAO,EAAE,SAAS,QAAQ;AACxC,aAAOC,WAAU,OAAO;AAAA,IAC1B,CAAC,EACA,MAAM,MAAM,IAAI;AACnB,oBAAgB,IAAI,KAAK,MAAM;AAAA,EACjC;AACA,SAAO;AACT;AAYA,eAAsB,SACpB,KACA,UACA,SACA,SACA,YACA,YACe;AACf,aAAW,OAAO,UAAU;AAC1B,QAAI,CAAC,IAAI,KAAM;AAEf,YAAQ,KAAK,IAAI,UAAU,IAAI,YAAY,IAAI,YAAY,IAAI,SAAS;AACxE,QAAI,YAAY,IAAI;AAEpB,UAAM,IAAI,UAAU,IAAI;AACxB,UAAM,IAAI,UAAU,IAAI;AAExB,QAAI,YAAY;AACd,YAAM,qBAAqB,KAAK,KAAK,GAAG,GAAG,YAAY,UAAU;AAAA,IACnE,WAAW,IAAI,iBAAiB,IAAI,kBAAkB,GAAG;AACvD,gCAA0B,KAAK,IAAI,MAAM,GAAG,GAAG,IAAI,aAAa;AAAA,IAClE,OAAO;AACL,UAAI,YAAY;AACd,uBAAe,KAAK,IAAI,MAAM,GAAG,GAAG,UAAU;AAAA,MAChD;AACA,UAAI,SAAS,IAAI,MAAM,GAAG,CAAC;AAAA,IAC7B;AAGA,QAAI,IAAI,gBAAgB;AACtB,yBAAmB,KAAK,KAAK,SAAS,OAAO;AAAA,IAC/C;AAAA,EACF;AACF;AAEA,eAAe,qBACb,KACA,KACA,GACA,GACA,YACA,YACe;AACf,QAAM,OAAO;AAAA,IACX,IAAI;AAAA,IACJ,CAAC,SAAS;AACR,cAAQ,KAAK,IAAI,UAAU,IAAI,YAAY,IAAI,YAAY,IAAI,SAAS;AACxE,aAAO,IAAI,YAAY,IAAI,EAAE;AAAA,IAC/B;AAAA,IACA,IAAI;AAAA,EACN;AAEA,aAAW,OAAO,MAAM;AACtB,QAAI,IAAI,SAAS,QAAQ;AACvB,UAAI,YAAY;AACd,uBAAe,KAAK,IAAI,MAAM,IAAI,IAAI,GAAG,GAAG,UAAU;AAAA,MACxD;AACA,UAAI,SAAS,IAAI,MAAM,IAAI,IAAI,GAAG,CAAC;AAAA,IACrC,OAAO;AACL,YAAM,MAAM,MAAM,eAAe,YAAY,IAAI,IAAI;AACrD,UAAI,KAAK;AACP,cAAM,YAAY,IAAI;AAGtB,cAAM,SAAS,IAAI,IAAI,UAAU,IAAI,SAAS,IAAI,YAAY;AAC9D,YAAI,UAAU,KAAK,IAAI,IAAI,GAAG,QAAQ,WAAW,SAAS;AAAA,MAC5D,OAAO;AAEL,YAAI,SAAS,IAAI,MAAM,IAAI,IAAI,GAAG,CAAC;AAAA,MACrC;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,0BACP,KACA,MACA,GACA,GACA,eACM;AACN,MAAI,WAAW;AACf,aAAW,QAAQ,MAAM;AACvB,QAAI,SAAS,MAAM,UAAU,CAAC;AAC9B,UAAM,UAAU,IAAI,YAAY,IAAI;AACpC,gBAAY,QAAQ,QAAQ;AAAA,EAC9B;AACF;AAEA,SAAS,eACP,KACA,MACA,GACA,GACA,QACM;AACN,QAAM,QAAQ,OAAO;AAAA,IACnB;AAAA,EACF;AACA,MAAI,CAAC,MAAO;AAEZ,MAAI,KAAK;AACT,MAAI,gBAAgB,WAAW,MAAM,CAAC,CAAE;AACxC,MAAI,gBAAgB,WAAW,MAAM,CAAC,CAAE;AACxC,MAAI,aAAa,WAAW,MAAM,CAAC,CAAE;AACrC,MAAI,cAAc,MAAM,CAAC,EAAG,KAAK;AACjC,MAAI,SAAS,MAAM,GAAG,CAAC;AACvB,MAAI,QAAQ;AACd;AAEA,SAAS,mBACP,KACA,KACA,SACA,SACM;AACN,QAAM,aAAa,IAAI;AACvB,MAAI,CAAC,cAAc,eAAe,OAAQ;AAE1C,MAAI,cAAc,IAAI;AACtB,MAAI,YAAY,KAAK,IAAI,GAAG,IAAI,WAAW,GAAG;AAE9C,QAAM,IAAI,UAAU,IAAI;AACxB,QAAM,QAAQ,UAAU,IAAI;AAE5B,MAAI,WAAW,SAAS,WAAW,GAAG;AACpC,UAAM,IAAI,QAAQ,IAAI,SAAS;AAC/B,QAAI,UAAU;AACd,QAAI,OAAO,GAAG,CAAC;AACf,QAAI,OAAO,IAAI,IAAI,OAAO,CAAC;AAC3B,QAAI,OAAO;AAAA,EACb;AAEA,MAAI,WAAW,SAAS,cAAc,GAAG;AACvC,UAAM,IAAI,QAAQ,IAAI,WAAW;AACjC,QAAI,UAAU;AACd,QAAI,OAAO,GAAG,CAAC;AACf,QAAI,OAAO,IAAI,IAAI,OAAO,CAAC;AAC3B,QAAI,OAAO;AAAA,EACb;AAEA,MAAI,WAAW,SAAS,UAAU,GAAG;AACnC,UAAM,IAAI,QAAQ,IAAI,WAAW;AACjC,QAAI,UAAU;AACd,QAAI,OAAO,GAAG,CAAC;AACf,QAAI,OAAO,IAAI,IAAI,OAAO,CAAC;AAC3B,QAAI,OAAO;AAAA,EACb;AACF;;;AX3LA,IAAM,aAAa,oBAAI,IAA+B;AAEtD,SAAS,iBAAiB,GAAW,GAAoC;AACvE,QAAM,MAAM,GAAG,CAAC,IAAI,CAAC;AACrB,QAAM,QAAQ,WAAW,IAAI,GAAG;AAChC,MAAI,OAAO;AACT,WAAO,MAAM,SAAS,GAAG;AACvB,YAAM,MAAM,MAAM,IAAI;AACtB,YAAMC,UAAS,IAAI,MAAM;AACzB,UAAIA,SAAQ;AACV,cAAM,MAAMA,QAAO,WAAW,IAAI;AAClC,YAAI,aAAa,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AACjC,YAAI,UAAU,GAAG,GAAG,GAAG,CAAC;AACxB,eAAO,CAACA,SAAQ,GAAG;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AACA,QAAM,SAASC,cAAa,GAAG,CAAC;AAChC,SAAO,CAAC,QAAQ,OAAO,WAAW,IAAI,CAAC;AACzC;AAEA,SAAS,iBAAiB,QAAsB;AAC9C,QAAM,MAAM,GAAG,OAAO,KAAK,IAAI,OAAO,MAAM;AAC5C,MAAI,QAAQ,WAAW,IAAI,GAAG;AAC9B,MAAI,CAAC,OAAO;AACV,YAAQ,CAAC;AACT,eAAW,IAAI,KAAK,KAAK;AAAA,EAC3B;AACA,QAAM,KAAK,IAAI,QAAQ,MAAM,CAAC;AAChC;AAgBA,eAAsB,SACpB,KACA,MACA,SACA,SACA,OACA,YACe;AACf,QAAM,IAAI,UAAU,KAAK;AACzB,QAAM,IAAI,UAAU,KAAK;AACzB,QAAM,EAAE,OAAO,QAAQ,MAAM,IAAI;AAEjC,MAAI,MAAM,YAAY,OAAQ;AAE9B,QAAM,UAAU,MAAM,WAAW;AACjC,MAAI,WAAW,EAAG;AAIlB,QAAM,YAAY,MAAM,YAAY,aAAa,MAAM,SAAS,IAAI;AACpE,MAAI,cAAc,UAAU,OAAO,KAAK,UAAU,OAAO,IAAI;AAC3D,UAAM,KAAK,UAAU;AACrB,UAAM,KAAK,UAAU;AACrB,UAAM,wBAAwB,UAAU;AAIxC,UAAM,KAAK,KAAK,IAAI,GAAG,KAAK,KAAK,KAAK,IAAI,EAAE,CAAC,CAAC;AAC9C,UAAM,KAAK,KAAK,IAAI,GAAG,KAAK,KAAK,KAAK,IAAI,EAAE,CAAC,CAAC;AAE9C,UAAM,OAAO,KAAK,MAAM,QAAQ,KAAK,EAAE;AACvC,UAAM,OAAO,KAAK,MAAM,SAAS,KAAK,EAAE;AACxC,QAAI,OAAO,KAAK,OAAO,GAAG;AACxB,YAAM,CAAC,WAAW,MAAM,IAAI,iBAAiB,MAAM,IAAI;AAGvD,aAAO,KAAK;AACZ,aAAO,MAAM,IAAI,EAAE;AACnB,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,aAAO,QAAQ;AAEf,UAAI,KAAK;AACT,UAAI,UAAU,GAAG;AACf,YAAI,eAAe;AAAA,MACrB;AAEA,UAAI,KAAK,IAAI,QAAQ;AACrB,UAAI,KAAK,IAAI,SAAS;AACtB,UAAI,MAAM,iBAAiB;AACzB,cAAM,QAAQ,MAAM,gBAAgB,MAAM,KAAK;AAC/C,aAAK,cAAc,MAAM,CAAC,GAAG,GAAG,KAAK;AACrC,aAAK,cAAc,MAAM,CAAC,GAAG,GAAG,MAAM;AAAA,MACxC;AAIA,UAAI,UAAU,IAAI,EAAE;AACpB,UAAI,MAAM,IAAI,EAAE;AAChB,UAAI,UAAU,CAAC,IAAI,CAAC,EAAE;AAGtB,UAAI;AAAA,QACF;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,QAAQ;AAAA,QACR,SAAS;AAAA,MACX;AACA,uBAAiB,SAAS;AAC1B,UAAI,QAAQ;AACZ;AAAA,IACF;AAAA,EACF;AAEA,MAAI,KAAK;AAGT,MAAI,UAAU,GAAG;AACf,QAAI,eAAe;AAAA,EACrB;AAGA,MAAI,MAAM,QAAQ;AAChB,QAAI,SAAS,MAAM;AAAA,EACrB;AAGA,MAAI,MAAM,WAAW;AACnB;AAAA,MACE;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM;AAAA,IACR;AAAA,EACF;AAGA,QAAM,YACJ,MAAM,aAAa,YACnB,MAAM,cAAc,YACpB,MAAM,cAAc;AAEtB,MAAI,WAAW;AACb,UAAM,eAAe,yBAAyB,KAAK;AACnD,cAAU,KAAK,GAAG,GAAG,OAAO,QAAQ,YAAY;AAAA,EAClD;AAGA,MACE,MAAM,mBACN,MAAM,kBACN,MAAM,oBACN,MAAM,qBACN,MAAM,mBACN,MAAM,WACN;AACA,aAAS,KAAK,GAAG,GAAG,OAAO,QAAQ,KAAK;AAAA,EAC1C;AAGA,MAAI,MAAM,iBAAiB;AACzB,UAAM,WAAW;AAAA,MACf;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,QAAI,UAAU;AACZ,UAAI,YAAY;AAChB,YAAM,eAAe,yBAAyB,KAAK;AACnD,UACE,aAAa,UAAU,KACvB,aAAa,WAAW,KACxB,aAAa,cAAc,KAC3B,aAAa,aAAa,GAC1B;AACA,YAAI,UAAU;AACd;AAAA,UACE;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,aAAa;AAAA,UACb,aAAa;AAAA,UACb,aAAa;AAAA,UACb,aAAa;AAAA,QACf;AACA,YAAI,KAAK;AAAA,MACX,OAAO;AACL,YAAI,SAAS,GAAG,GAAG,OAAO,MAAM;AAAA,MAClC;AAAA,IACF,OAAO;AAEL,YAAM,WAAW,MAAM,gBAAgB,MAAM,wBAAwB;AACrE,UAAI,UAAU;AACZ,cAAM,eAAe,yBAAyB,KAAK;AACnD,cAAMC,aACJ,aAAa,UAAU,KACvB,aAAa,WAAW,KACxB,aAAa,cAAc,KAC3B,aAAa,aAAa;AAE5B,YAAIA,YAAW;AACb,oBAAU,KAAK,GAAG,GAAG,OAAO,QAAQ,YAAY;AAAA,QAClD;AAEA,cAAM,QAAQ,MAAMC,WAAU,SAAS,CAAC,CAAE;AAC1C,cAAM,SAAS,MAAM;AAErB,YAAI,WAAW,SAAS;AAEtB,gBAAM,IAAI;AAAA,YACR,MAAM;AAAA,YACN,MAAM;AAAA,YACN;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AACA,cAAI,UAAU,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;AAAA,QACrE,OAAO;AAEL,cAAI,OAAe;AACnB,cAAI,WAAW,WAAW;AACxB,kBAAM,IAAI;AAAA,cACR,MAAM;AAAA,cACN,MAAM;AAAA,cACN;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YACF;AACA,oBAAQ,EAAE;AACV,oBAAQ,EAAE;AAAA,UACZ,WAAW,WAAW,aAAa;AACjC,oBAAQ;AACR,oBAAQ;AAAA,UACV,OAAO;AAEL,oBAAQ,MAAM;AACd,oBAAQ,MAAM;AAAA,UAChB;AAEA,mBAAS,KAAK,GAAG,KAAK,IAAI,QAAQ,MAAM,OAAO;AAC7C,qBAAS,KAAK,GAAG,KAAK,IAAI,OAAO,MAAM,OAAO;AAC5C,kBAAI,UAAU,OAAO,IAAI,IAAI,OAAO,KAAK;AAAA,YAC3C;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,OAAO;AACT,QAAI,cAAc;AAClB,QAAI,YAAY;AAChB,QAAI,WAAW,GAAG,GAAG,OAAO,MAAM;AAAA,EACpC;AAGA,MAAI,KAAK,gBAAgB,UAAa,KAAK,gBAAgB,IAAI;AAC7D,UAAM,aAAaC,UAAS,MAAM,UAAU;AAC5C,UAAM,cAAcA,UAAS,MAAM,WAAW;AAC9C,UAAM,eAAeA,UAAS,MAAM,YAAY;AAEhD,UAAM,aAAaA,UAAS,MAAM,cAAc;AAChD,UAAM,cAAcA,UAAS,MAAM,eAAe;AAClD,UAAM,eAAeA,UAAS,MAAM,gBAAgB;AAEpD,UAAM,WAAW,IAAI,cAAc;AACnC,UAAM,WAAW,IAAI,aAAa;AAClC,UAAM,eACJ,QAAQ,cAAc,eAAe,cAAc;AAErD,UAAM,aAAa;AAAA,MACjB,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA,CAAC,CAAC;AAAA,IACJ;AACA,UAAM;AAAA,MACJ;AAAA,MACA,WAAW;AAAA,MACX;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAGA,MAAI,KAAK,SAAS,SAAS,KAAK,MAAM,KAAK;AACzC,UAAM,aAAaA,UAAS,MAAM,UAAU;AAC5C,UAAM,cAAcA,UAAS,MAAM,WAAW;AAC9C,UAAM,eAAeA,UAAS,MAAM,YAAY;AAChD,UAAM,gBAAgBA,UAAS,MAAM,aAAa;AAElD,UAAM,OAAO,IAAI;AACjB,UAAM,OAAO,IAAI;AACjB,UAAM,OAAO,QAAQ,cAAc;AACnC,UAAM,OAAO,SAAS,aAAa;AAInC,QAAI,CAAC,WAAW;AACd,YAAM,eAAe,yBAAyB,KAAK;AACnD,UACE,aAAa,UAAU,KACvB,aAAa,WAAW,KACxB,aAAa,cAAc,KAC3B,aAAa,aAAa,GAC1B;AACA,kBAAU,KAAK,MAAM,MAAM,MAAM,MAAM,YAAY;AAAA,MACrD;AAAA,IACF;AAEA,UAAM;AAAA,MACJ;AAAA,MACA,KAAK,MAAM;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,KAAK,MAAM;AAAA,IACb;AAAA,EACF;AAGA,MAAI,KAAK,SAAS,OAAO;AACvB,qBAAiB,KAAK,MAAM,GAAG,GAAG,OAAO,MAAM;AAAA,EACjD,OAAO;AAEL,eAAW,SAAS,KAAK,UAAU;AACjC,YAAM,SAAS,KAAK,OAAO,GAAG,GAAG,OAAO,UAAU;AAAA,IACpD;AAAA,EACF;AAEA,MAAI,QAAQ;AACd;AAMA,SAAS,aACP,WACsD;AACtD,QAAM,aAAa,UAAU,MAAM,oCAAoC;AACvE,MAAI,CAAC,WAAY,QAAO;AAExB,QAAM,CAAC,WAAW,MAAM,IAAI,IAAI;AAChC,QAAM,SAAS,KAAM,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AAEnD,QAAM,KAAK,SAAS,WAAW,IAAI,WAAW,OAAO,CAAC,CAAE;AACxD,QAAM,KACJ,SAAS,WACL,IACA,WAAW,OAAO,SAAS,UAAU,IAAI,CAAC,KAAK,OAAO,EAAE,CAAC;AAE/D,QAAM,YAAY,UAAU,QAAQ,WAAY,EAAE,EAAE,KAAK;AACzD,SAAO,EAAE,IAAI,IAAI,UAAU;AAC7B;AAOA,eAAe,cACb,KACA,MACA,SACA,SACA,SACA,SACA,OACA,YACA,mBACe;AACf,QAAM,IAAI,UAAU,KAAK,IAAI;AAC7B,QAAM,IAAI,UAAU,KAAK,IAAI;AAC7B,QAAM,EAAE,OAAO,QAAQ,MAAM,IAAI;AAEjC,MAAI,MAAM,YAAY,OAAQ;AAE9B,QAAM,UAAU,MAAM,WAAW;AACjC,MAAI,WAAW,EAAG;AAElB,MAAI,KAAK;AAET,MAAI,UAAU,GAAG;AACf,QAAI,eAAe;AAAA,EACrB;AAEA,MAAI,MAAM,QAAQ;AAChB,QAAI,SAAS,MAAM;AAAA,EACrB;AAGA,QAAM,mBACJ,sBAAsB,SAAY,oBAAoB,MAAM;AAC9D,MAAI,kBAAkB;AACpB;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM;AAAA,IACR;AAAA,EACF;AAEA,QAAM,YACJ,MAAM,aAAa,YACnB,MAAM,cAAc,YACpB,MAAM,cAAc;AAEtB,MAAI,WAAW;AACb,UAAM,eAAe,yBAAyB,KAAK;AACnD,cAAU,KAAK,GAAG,GAAG,OAAO,QAAQ,YAAY;AAAA,EAClD;AAEA,MACE,MAAM,mBACN,MAAM,kBACN,MAAM,oBACN,MAAM,qBACN,MAAM,mBACN,MAAM,WACN;AACA,aAAS,KAAK,GAAG,GAAG,OAAO,QAAQ,KAAK;AAAA,EAC1C;AAEA,MAAI,MAAM,iBAAiB;AACzB,UAAM,WAAW;AAAA,MACf;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,QAAI,UAAU;AACZ,UAAI,YAAY;AAChB,YAAM,eAAe,yBAAyB,KAAK;AACnD,UACE,aAAa,UAAU,KACvB,aAAa,WAAW,KACxB,aAAa,cAAc,KAC3B,aAAa,aAAa,GAC1B;AACA,YAAI,UAAU;AACd;AAAA,UACE;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,aAAa;AAAA,UACb,aAAa;AAAA,UACb,aAAa;AAAA,UACb,aAAa;AAAA,QACf;AACA,YAAI,KAAK;AAAA,MACX,OAAO;AACL,YAAI,SAAS,GAAG,GAAG,OAAO,MAAM;AAAA,MAClC;AAAA,IACF,OAAO;AACL,YAAM,WAAW,MAAM,gBAAgB,MAAM,wBAAwB;AACrE,UAAI,UAAU;AACZ,cAAM,eAAe,yBAAyB,KAAK;AACnD,cAAMF,aACJ,aAAa,UAAU,KACvB,aAAa,WAAW,KACxB,aAAa,cAAc,KAC3B,aAAa,aAAa;AAC5B,YAAIA,YAAW;AACb,oBAAU,KAAK,GAAG,GAAG,OAAO,QAAQ,YAAY;AAAA,QAClD;AACA,cAAM,QAAQ,MAAMC,WAAU,SAAS,CAAC,CAAE;AAC1C,cAAM,SAAS,MAAM;AACrB,YAAI,WAAW,SAAS;AACtB,gBAAM,IAAI;AAAA,YACR,MAAM;AAAA,YACN,MAAM;AAAA,YACN;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AACA,cAAI,UAAU,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;AAAA,QACrE,OAAO;AACL,cAAI,OAAe;AACnB,cAAI,WAAW,WAAW;AACxB,kBAAM,IAAI;AAAA,cACR,MAAM;AAAA,cACN,MAAM;AAAA,cACN;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YACF;AACA,oBAAQ,EAAE;AACV,oBAAQ,EAAE;AAAA,UACZ,WAAW,WAAW,aAAa;AACjC,oBAAQ;AACR,oBAAQ;AAAA,UACV,OAAO;AACL,oBAAQ,MAAM;AACd,oBAAQ,MAAM;AAAA,UAChB;AACA,mBAAS,KAAK,GAAG,KAAK,IAAI,QAAQ,MAAM,OAAO;AAC7C,qBAAS,KAAK,GAAG,KAAK,IAAI,OAAO,MAAM,OAAO;AAC5C,kBAAI,UAAU,OAAO,IAAI,IAAI,OAAO,KAAK;AAAA,YAC3C;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,OAAO;AACT,QAAI,cAAc;AAClB,QAAI,YAAY;AAChB,QAAI,WAAW,GAAG,GAAG,OAAO,MAAM;AAAA,EACpC;AAEA,MAAI,KAAK,gBAAgB,UAAa,KAAK,gBAAgB,IAAI;AAC7D,UAAM,aAAaC,UAAS,MAAM,UAAU;AAC5C,UAAM,cAAcA,UAAS,MAAM,WAAW;AAC9C,UAAM,eAAeA,UAAS,MAAM,YAAY;AAChD,UAAM,aAAaA,UAAS,MAAM,cAAc;AAChD,UAAM,cAAcA,UAAS,MAAM,eAAe;AAClD,UAAM,eAAeA,UAAS,MAAM,gBAAgB;AACpD,UAAM,WAAW,IAAI,cAAc;AACnC,UAAM,WAAW,IAAI,aAAa;AAClC,UAAM,eACJ,QAAQ,cAAc,eAAe,cAAc;AACrD,UAAM,aAAa;AAAA,MACjB,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA,CAAC,CAAC;AAAA,IACJ;AACA,UAAM;AAAA,MACJ;AAAA,MACA,WAAW;AAAA,MACX;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAEA,MAAI,KAAK,SAAS,SAAS,KAAK,MAAM,KAAK;AACzC,UAAM,aAAaA,UAAS,MAAM,UAAU;AAC5C,UAAM,cAAcA,UAAS,MAAM,WAAW;AAC9C,UAAM,eAAeA,UAAS,MAAM,YAAY;AAChD,UAAM,gBAAgBA,UAAS,MAAM,aAAa;AAClD,UAAM,OAAO,IAAI;AACjB,UAAM,OAAO,IAAI;AACjB,UAAM,OAAO,QAAQ,cAAc;AACnC,UAAM,OAAO,SAAS,aAAa;AACnC,QAAI,CAAC,WAAW;AACd,YAAM,eAAe,yBAAyB,KAAK;AACnD,UACE,aAAa,UAAU,KACvB,aAAa,WAAW,KACxB,aAAa,cAAc,KAC3B,aAAa,aAAa,GAC1B;AACA,kBAAU,KAAK,MAAM,MAAM,MAAM,MAAM,YAAY;AAAA,MACrD;AAAA,IACF;AACA,UAAM;AAAA,MACJ;AAAA,MACA,KAAK,MAAM;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,KAAK,MAAM;AAAA,IACb;AAAA,EACF;AAEA,MAAI,KAAK,SAAS,OAAO;AACvB,qBAAiB,KAAK,MAAM,GAAG,GAAG,OAAO,MAAM;AAAA,EACjD,OAAO;AAEL,eAAW,SAAS,KAAK,UAAU;AACjC,YAAM,cAAc,KAAK,OAAO,GAAG,GAAG,GAAG,GAAG,OAAO,YAAY,MAAS;AAAA,IAC1E;AAAA,EACF;AAEA,MAAI,QAAQ;AACd;AAEA,SAAS,eACP,KACA,WACA,GACA,GACA,OACA,QACA,iBACM;AAEN,MAAI,KAAK,IAAI,QAAQ;AACrB,MAAI,KAAK,IAAI,SAAS;AAEtB,MAAI,iBAAiB;AACnB,UAAM,QAAQ,gBAAgB,MAAM,KAAK;AACzC,SAAK,cAAc,MAAM,CAAC,GAAG,GAAG,KAAK;AACrC,SAAK,cAAc,MAAM,CAAC,GAAG,GAAG,MAAM;AAAA,EACxC;AAEA,MAAI,UAAU,IAAI,EAAE;AAGpB,QAAM,QAAQ,UAAU,SAAS,mBAAmB;AAEpD,aAAW,CAAC,EAAE,MAAM,IAAI,KAAK,OAAO;AAClC,UAAM,SAAS,KAAM,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AAEnD,YAAQ,MAAM;AAAA,MACZ,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK,cAAc;AACjB,cAAM,KAAK,SAAS,eAAe,IAAI,WAAW,OAAO,CAAC,CAAE;AAC5D,cAAM,KACJ,SAAS,eACL,IACA,WAAW,OAAO,SAAS,cAAc,IAAI,CAAC,KAAK,GAAG;AAC5D,YAAI,UAAU,IAAI,EAAE;AACpB;AAAA,MACF;AAAA,MACA,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK,UAAU;AACb,cAAM,KAAK,SAAS,WAAW,IAAI,WAAW,OAAO,CAAC,CAAE;AACxD,cAAM,KACJ,SAAS,WACL,IACA,WAAW,OAAO,SAAS,UAAU,IAAI,CAAC,KAAK,OAAO,EAAE,CAAC;AAC/D,YAAI,MAAM,IAAI,EAAE;AAChB;AAAA,MACF;AAAA,MACA,KAAK,UAAU;AACb,cAAM,QAAQ,WAAW,OAAO,CAAC,CAAE;AACnC,YAAI,OAAO,KAAK;AAChB;AAAA,MACF;AAAA,MACA,KAAK,SAAS;AACZ,cAAM,QAAQ,WAAW,OAAO,CAAC,CAAE;AACnC,YAAI,UAAU,GAAG,GAAG,KAAK,IAAI,KAAK,GAAG,GAAG,GAAG,CAAC;AAC5C;AAAA,MACF;AAAA,MACA,KAAK,SAAS;AACZ,cAAM,QAAQ,WAAW,OAAO,CAAC,CAAE;AACnC,YAAI,UAAU,GAAG,KAAK,IAAI,KAAK,GAAG,GAAG,GAAG,GAAG,CAAC;AAC5C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,UAAU,CAAC,IAAI,CAAC,EAAE;AACxB;AAEA,SAAS,cACP,OACA,MACA,MACQ;AACR,MAAI,CAAC,MAAO,QAAO,OAAO,OAAO;AACjC,MAAI,UAAU,UAAU,UAAU,MAAO,QAAO;AAChD,MAAI,UAAU,WAAW,UAAU,SAAU,QAAO,OAAO;AAC3D,MAAI,UAAU,SAAU,QAAO,OAAO,OAAO;AAC7C,MAAI,MAAM,SAAS,GAAG,EAAG,QAAO,OAAQ,WAAW,KAAK,IAAI,MAAO;AACnE,SAAO,OAAO,WAAW,KAAK;AAChC;AAEA,SAAS,WAAW,OAAuB;AACzC,MAAI,MAAM,SAAS,KAAK,EAAG,QAAQ,WAAW,KAAK,IAAI,KAAK,KAAM;AAClE,MAAI,MAAM,SAAS,KAAK,EAAG,QAAO,WAAW,KAAK;AAClD,MAAI,MAAM,SAAS,MAAM,EAAG,QAAO,WAAW,KAAK,IAAI,IAAI,KAAK;AAChE,SAAO,WAAW,KAAK;AACzB;AAEA,SAASA,UAAS,GAAoB;AACpC,MAAI,OAAO,MAAM,SAAU,QAAO;AAClC,MAAI,MAAM,UAAa,MAAM,KAAM,QAAO;AAC1C,QAAM,IAAI,WAAW,OAAO,CAAC,CAAC;AAC9B,SAAO,MAAM,CAAC,IAAI,IAAI;AACxB;;;AcxtBA,SAAS,mBAAmB;AAI5B,IAAM,kBAAkB,oBAAI,IAAY;AAejC,SAAS,aAAa,MAAsB;AACjD,QAAM,MAAM,GAAG,KAAK,IAAI,IAAI,KAAK,MAAM,IAAI,KAAK,KAAK;AACrD,MAAI,gBAAgB,IAAI,GAAG,EAAG;AAE9B,QAAM,SAAS,OAAO,SAAS,KAAK,IAAI,IACpC,KAAK,OACL,OAAO,KAAK,KAAK,IAAI;AAEzB,cAAY,SAAS,QAAQ,KAAK,IAAI;AAEtC,kBAAgB,IAAI,GAAG;AACzB;AAQO,SAAS,qBAAqB,MAAc,WAA0B;AAC3E,cAAY,iBAAiB,MAAM,aAAa,EAAE;AACpD;AAOO,SAAS,qBAA+B;AAC7C,SAAO,YAAY,SAAS,IAAI,CAAC,MAA0B,EAAE,MAAM;AACrE;AAMO,SAAS,sBAAsB,OAAyB;AAC7D,aAAW,QAAQ,OAAO;AACxB,iBAAa,IAAI;AAAA,EACnB;AACF;;;ACtDA,SAAS,aAAAC,kBAAiB;;;ACG1B,IAAM,QAAQ,CAAC,OAAO,SAAS,UAAU,MAAM;AAK/C,SAAS,WAAW,OAAyB;AAC3C,QAAM,QAAQ,MAAM,SAAS,EAAE,MAAM,KAAK,EAAE,OAAO,OAAO;AAC1D,UAAQ,MAAM,QAAQ;AAAA,IACpB,KAAK;AACH,aAAO,CAAC,MAAM,CAAC,GAAI,MAAM,CAAC,GAAI,MAAM,CAAC,GAAI,MAAM,CAAC,CAAE;AAAA,IACpD,KAAK;AACH,aAAO,CAAC,MAAM,CAAC,GAAI,MAAM,CAAC,GAAI,MAAM,CAAC,GAAI,MAAM,CAAC,CAAE;AAAA,IACpD,KAAK;AACH,aAAO,CAAC,MAAM,CAAC,GAAI,MAAM,CAAC,GAAI,MAAM,CAAC,GAAI,MAAM,CAAC,CAAE;AAAA,IACpD;AACE,aAAO,CAAC,MAAM,CAAC,GAAI,MAAM,CAAC,GAAI,MAAM,CAAC,GAAI,MAAM,CAAC,CAAE;AAAA,EACtD;AACF;AAEA,SAAS,WAAW,GAAyC;AAC3D,MAAI,MAAM,UAAa,MAAM,KAAM,QAAO;AAC1C,QAAM,IAAI,OAAO,CAAC;AAClB,MAAI,MAAM,OAAQ,QAAO;AACzB,QAAM,IAAI,WAAW,CAAC;AACtB,MAAI,CAAC,MAAM,CAAC,EAAG,QAAO;AACtB,SAAO;AACT;AAMO,SAAS,YAAY,KAA8B;AACxD,QAAM,QAAQ,EAAE,GAAG,IAAI;AAGvB,MAAI,MAAM,WAAW,QAAW;AAC9B,UAAM,QAAQ,WAAW,OAAO,MAAM,MAAM,CAAC;AAC7C,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,YAAM,MAAM,SAAS,MAAM,CAAC,CAAC;AAC7B,UAAI,MAAM,GAAG,MAAM,OAAW,OAAM,GAAG,IAAI,WAAW,MAAM,CAAC,CAAC;AAAA,IAChE;AACA,WAAO,MAAM;AAAA,EACf;AAGA,MAAI,MAAM,YAAY,QAAW;AAC/B,UAAM,QAAQ,WAAW,OAAO,MAAM,OAAO,CAAC;AAC9C,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,YAAM,MAAM,UAAU,MAAM,CAAC,CAAC;AAC9B,UAAI,MAAM,GAAG,MAAM,OAAW,OAAM,GAAG,IAAI,WAAW,MAAM,CAAC,CAAC;AAAA,IAChE;AACA,WAAO,MAAM;AAAA,EACf;AAGA,MAAI,MAAM,iBAAiB,QAAW;AACpC,UAAM,QAAQ,WAAW,OAAO,MAAM,YAAY,CAAC;AACnD,UAAM,UAAU;AAAA,MACd;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAI,MAAM,QAAQ,CAAC,CAAE,MAAM;AACzB,cAAM,QAAQ,CAAC,CAAE,IAAI,WAAW,MAAM,CAAC,CAAC;AAAA,IAC5C;AACA,WAAO,MAAM;AAAA,EACf;AAGA,MAAI,MAAM,gBAAgB,QAAW;AACnC,UAAM,QAAQ,WAAW,OAAO,MAAM,WAAW,CAAC;AAClD,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,YAAM,MAAM,SAAS,MAAM,CAAC,CAAC;AAC7B,UAAI,MAAM,GAAG,MAAM,OAAW,OAAM,GAAG,IAAI,WAAW,MAAM,CAAC,CAAC;AAAA,IAChE;AACA,WAAO,MAAM;AAAA,EACf;AAGA,MAAI,MAAM,gBAAgB,QAAW;AACnC,UAAM,MAAM,MAAM;AAClB,eAAW,QAAQ,OAAO;AACxB,YAAM,MAAM,SAAS,IAAI;AACzB,UAAI,MAAM,GAAG,MAAM,OAAW,OAAM,GAAG,IAAI;AAAA,IAC7C;AACA,WAAO,MAAM;AAAA,EACf;AAGA,MAAI,MAAM,gBAAgB,QAAW;AACnC,UAAM,MAAM,MAAM;AAClB,eAAW,QAAQ,OAAO;AACxB,YAAM,MAAM,SAAS,IAAI;AACzB,UAAI,MAAM,GAAG,MAAM,OAAW,OAAM,GAAG,IAAI;AAAA,IAC7C;AACA,WAAO,MAAM;AAAA,EACf;AAGA,MAAI,MAAM,WAAW,QAAW;AAC9B,UAAM,QAAQ,OAAO,MAAM,MAAM,EAAE,MAAM,KAAK;AAC9C,UAAM,QAAQ,WAAW,MAAM,CAAC,CAAC;AACjC,UAAM,cAAc,MAAM,CAAC,KAAK;AAChC,UAAM,QAAQ,MAAM,CAAC,KAAK;AAC1B,eAAW,QAAQ,OAAO;AACxB,UAAI,MAAM,SAAS,IAAI,OAAO,MAAM;AAClC,cAAM,SAAS,IAAI,OAAO,IAAI;AAChC,UAAI,MAAM,SAAS,IAAI,OAAO,MAAM;AAClC,cAAM,SAAS,IAAI,OAAO,IAAI;AAChC,UAAI,MAAM,SAAS,IAAI,OAAO,MAAM;AAClC,cAAM,SAAS,IAAI,OAAO,IAAI;AAAA,IAClC;AACA,WAAO,MAAM;AAAA,EACf;AAGA,MAAI,MAAM,SAAS,QAAW;AAC5B,UAAM,MAAM,OAAO,MAAM,IAAI;AAC7B,UAAM,QAAQ,IAAI,MAAM,KAAK;AAC7B,QAAI,MAAM,WAAW,GAAG;AACtB,YAAM,IAAI,WAAW,MAAM,CAAC,CAAE;AAC9B,UAAI,CAAC,MAAM,CAAC,GAAG;AACb,YAAI,MAAM,aAAa,OAAW,OAAM,WAAW;AACnD,YAAI,MAAM,eAAe,OAAW,OAAM,aAAa;AACvD,YAAI,MAAM,cAAc,OAAW,OAAM,YAAY;AAAA,MACvD;AAAA,IACF,WAAW,MAAM,WAAW,GAAG;AAC7B,UAAI,MAAM,aAAa,OAAW,OAAM,WAAW,WAAW,MAAM,CAAC,CAAE;AACvE,UAAI,MAAM,eAAe;AACvB,cAAM,aAAa,WAAW,MAAM,CAAC,CAAE;AAAA,IAC3C,WAAW,MAAM,UAAU,GAAG;AAC5B,UAAI,MAAM,aAAa,OAAW,OAAM,WAAW,WAAW,MAAM,CAAC,CAAE;AACvE,UAAI,MAAM,eAAe;AACvB,cAAM,aAAa,WAAW,MAAM,CAAC,CAAE;AACzC,UAAI,MAAM,cAAc,OAAW,OAAM,YAAY,WAAW,MAAM,CAAC,CAAC;AAAA,IAC1E;AACA,WAAO,MAAM;AAAA,EACf;AAGA,MAAI,MAAM,QAAQ,QAAW;AAC3B,UAAM,QAAQ,WAAW,OAAO,MAAM,GAAG,CAAC;AAC1C,QAAI,MAAM,WAAW,OAAW,OAAM,SAAS,WAAW,MAAM,CAAC,CAAC;AAClE,QAAI,MAAM,cAAc,OAAW,OAAM,YAAY,WAAW,MAAM,CAAC,CAAC;AACxE,WAAO,MAAM;AAAA,EACf;AAGA,MAAI,MAAM,eAAe,QAAW;AAClC,UAAM,KAAK,OAAO,MAAM,UAAU;AAClC,QAAI,GAAG,SAAS,WAAW,KAAK,GAAG,SAAS,MAAM,GAAG;AACnD,UAAI,MAAM,oBAAoB,OAAW,OAAM,kBAAkB;AAAA,IACnE,OAAO;AACL,UAAI,MAAM,oBAAoB,OAAW,OAAM,kBAAkB;AAAA,IACnE;AACA,WAAO,MAAM;AAAA,EACf;AAGA,MAAI,MAAM,aAAa,QAAW;AAChC,QAAI,MAAM,cAAc,OAAW,OAAM,YAAY,MAAM;AAC3D,QAAI,MAAM,cAAc,OAAW,OAAM,YAAY,MAAM;AAAA,EAC7D;AAGA,MAAI,OAAO,MAAM,eAAe,UAAU;AACxC,UAAM,aAAa,MAAM,WACtB,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,gBAAgB,EAAE,CAAC,EAC/C,OAAO,OAAO,EACd,KAAK,IAAI;AAAA,EACd;AAEA,SAAO;AACT;;;ACrDO,IAAM,gBAA+B;AAAA,EAC1C,SAAS;AAAA,EACT,eAAe;AAAA,EACf,UAAU;AAAA,EACV,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,cAAc;AAAA,EACd,SAAS;AAAA,EACT,UAAU;AACZ;AAKA,IAAM,oBAA6C;AAAA,EACjD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAKO,SAAS,aACd,UACA,aACe;AACf,QAAM,QAAQ,EAAE,GAAG,SAAS;AAG5B,aAAW,QAAQ,mBAAmB;AACpC,QAAI,MAAM,IAAI,MAAM,UAAa,YAAY,IAAI,MAAM,QAAW;AAChE,MAAC,MAAkC,IAAI,IAAI,YAAY,IAAI;AAAA,IAC7D;AAAA,EACF;AAGA,MAAI,OAAO,MAAM,aAAa,UAAU;AACtC,UAAM,SAAS,WAAW,MAAM,QAAQ;AACxC,UAAM,WAAW,MAAM,MAAM,IAAI,YAAY,WAAW;AAAA,EAC1D;AAKA,MAAI,OAAO,MAAM,eAAe,UAAU;AACxC,UAAM,MAAM,MAAM;AAClB,QAAI,IAAI,SAAS,GAAG,GAAG;AACrB,YAAM,aAAa,WAAW,GAAG,IAAI;AAAA,IACvC,OAAO;AACL,YAAM,SAAS,WAAW,GAAG;AAC7B,UAAI,CAAC,MAAM,MAAM,GAAG;AAClB,cAAM,aAAa;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AAGA,MAAI,OAAO,MAAM,kBAAkB,UAAU;AAC3C,UAAM,SAAS,WAAW,MAAM,aAAa;AAC7C,QAAI,CAAC,MAAM,MAAM,GAAG;AAClB,YAAM,gBAAgB;AAAA,IACxB;AAAA,EACF;AAEA,SAAO;AACT;AAKA,IAAM,kBAA2C;AAAA,EAC/C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAOA,SAAS,YACP,OACA,eACA,gBACA,UACA,cACiB;AAEjB,MAAI,MAAM,SAAS,GAAG,KAAK,UAAU,OAAQ,QAAO;AAGpD,MAAI,MAAM,SAAS,MAAM,GAAG;AAC1B,UAAM,IAAI,WAAW,KAAK;AAC1B,WAAO,MAAM,CAAC,IACV,QACC,IAAI,MAAO,KAAK,IAAI,eAAe,cAAc;AAAA,EACxD;AACA,MAAI,MAAM,SAAS,MAAM,GAAG;AAC1B,UAAM,IAAI,WAAW,KAAK;AAC1B,WAAO,MAAM,CAAC,IACV,QACC,IAAI,MAAO,KAAK,IAAI,eAAe,cAAc;AAAA,EACxD;AACA,MAAI,MAAM,SAAS,IAAI,GAAG;AACxB,UAAM,IAAI,WAAW,KAAK;AAC1B,WAAO,MAAM,CAAC,IAAI,QAAS,IAAI,MAAO;AAAA,EACxC;AACA,MAAI,MAAM,SAAS,IAAI,GAAG;AACxB,UAAM,IAAI,WAAW,KAAK;AAC1B,WAAO,MAAM,CAAC,IAAI,QAAS,IAAI,MAAO;AAAA,EACxC;AAGA,MAAI,MAAM,SAAS,KAAK,GAAG;AACzB,UAAM,IAAI,WAAW,KAAK;AAC1B,WAAO,MAAM,CAAC,IAAI,QAAQ,IAAI;AAAA,EAChC;AACA,MAAI,MAAM,SAAS,IAAI,GAAG;AACxB,UAAM,IAAI,WAAW,KAAK;AAC1B,WAAO,MAAM,CAAC,IAAI,QAAQ,IAAI;AAAA,EAChC;AAGA,MAAI,MAAM,SAAS,IAAI,GAAG;AACxB,UAAM,IAAI,WAAW,KAAK;AAC1B,WAAO,MAAM,CAAC,IAAI,QAAQ;AAAA,EAC5B;AACA,MAAI,MAAM,SAAS,IAAI,GAAG;AACxB,UAAM,IAAI,WAAW,KAAK;AAC1B,WAAO,MAAM,CAAC,IAAI,QAAQ,KAAK,KAAK;AAAA,EACtC;AACA,MAAI,MAAM,SAAS,IAAI,GAAG;AACxB,UAAM,IAAI,WAAW,KAAK;AAC1B,WAAO,MAAM,CAAC,IAAI,QAAQ,IAAI;AAAA,EAChC;AACA,MAAI,MAAM,SAAS,IAAI,GAAG;AACxB,UAAM,IAAI,WAAW,KAAK;AAC1B,WAAO,MAAM,CAAC,IAAI,QAAQ,IAAI;AAAA,EAChC;AACA,MAAI,MAAM,SAAS,IAAI,GAAG;AACxB,UAAM,IAAI,WAAW,KAAK;AAC1B,WAAO,MAAM,CAAC,IAAI,QAAQ,KAAK,KAAK;AAAA,EACtC;AACA,MAAI,MAAM,SAAS,IAAI,GAAG;AACxB,UAAM,IAAI,WAAW,KAAK;AAC1B,WAAO,MAAM,CAAC,IAAI,QAAQ,KAAK,KAAK;AAAA,EACtC;AAEA,SAAO;AACT;AAOO,SAAS,aACd,OACA,eACA,gBACA,eAAuB,cAAc,UACtB;AACf,QAAM,WACJ,OAAO,MAAM,aAAa,WAAW,MAAM,WAAW;AAExD,aAAW,QAAQ,iBAAiB;AAClC,UAAM,QAAQ,MAAM,IAAI;AACxB,QAAI,OAAO,UAAU,SAAU;AAC/B,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,QAAI,aAAa,OAAO;AACtB,MAAC,MAAkC,IAAI,IAAI;AAAA,IAC7C;AAAA,EACF;AACA,SAAO;AACT;;;ACjWA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAkBA,SAAS,iBAA2B;AACzC,SAAO,KAAK,KAAK,OAAO;AAC1B;AAEO,SAAS,aAAa,MAAsB;AACjD,OAAK,cAAc;AACrB;;;ACjBO,SAAS,kBAAkB,MAAgB,OAA4B;AAE5E,MAAI,MAAM,YAAY,QAAQ;AAC5B,SAAK,WAAW,QAAQ,IAAI;AAAA,EAC9B,OAAO;AACL,SAAK,WAAW,QAAQ,IAAI;AAAA,EAC9B;AAGA;AACE,UAAM,MAAqC;AAAA,MACzC,KAAK,cAAc;AAAA,MACnB,eAAe,cAAc;AAAA,MAC7B,QAAQ,cAAc;AAAA,MACtB,kBAAkB,cAAc;AAAA,IAClC;AACA,SAAK;AAAA,MACH,IAAI,MAAM,iBAAiB,KAAK,KAAK,cAAc;AAAA,IACrD;AAAA,EACF;AAGA,MAAI,MAAM,gBAAgB;AACxB,UAAM,MAA+B;AAAA,MACnC,cAAc,QAAQ;AAAA,MACtB,YAAY,QAAQ;AAAA,MACpB,QAAQ,QAAQ;AAAA,MAChB,iBAAiB,QAAQ;AAAA,MACzB,gBAAgB,QAAQ;AAAA,MACxB,gBAAgB,QAAQ;AAAA,IAC1B;AACA,UAAM,KAAK,IAAI,MAAM,cAAc;AACnC,QAAI,OAAO,OAAW,MAAK,kBAAkB,EAAE;AAAA,EACjD;AAGA,MAAI,MAAM,YAAY;AACpB,UAAM,MAA6B;AAAA,MACjC,cAAc,MAAM;AAAA,MACpB,YAAY,MAAM;AAAA,MAClB,QAAQ,MAAM;AAAA,MACd,SAAS,MAAM;AAAA,MACf,UAAU,MAAM;AAAA,IAClB;AACA,UAAM,KAAK,IAAI,MAAM,UAAU;AAC/B,QAAI,OAAO,OAAW,MAAK,cAAc,EAAE;AAAA,EAC7C;AAGA,MAAI,MAAM,WAAW;AACnB,UAAM,MAA6B;AAAA,MACjC,MAAM,MAAM;AAAA,MACZ,cAAc,MAAM;AAAA,MACpB,YAAY,MAAM;AAAA,MAClB,QAAQ,MAAM;AAAA,MACd,SAAS,MAAM;AAAA,MACf,UAAU,MAAM;AAAA,IAClB;AACA,UAAM,MAAM,IAAI,MAAM,SAAS;AAC/B,QAAI,QAAQ,OAAW,MAAK,aAAa,GAAG;AAAA,EAC9C;AAGA,MAAI,MAAM,cAAc;AACtB,UAAM,MAA6B;AAAA,MACjC,cAAc,MAAM;AAAA,MACpB,YAAY,MAAM;AAAA,MAClB,QAAQ,MAAM;AAAA,MACd,SAAS,MAAM;AAAA,MACf,iBAAiB,MAAM;AAAA,MACvB,gBAAgB,MAAM;AAAA,IACxB;AACA,UAAM,KAAK,IAAI,MAAM,YAAY;AACjC,QAAI,OAAO,OAAW,MAAK,gBAAgB,EAAE;AAAA,EAC/C;AAGA,MAAI,MAAM,UAAU;AAClB,UAAM,MAA4B;AAAA,MAChC,QAAQ,KAAK;AAAA,MACb,MAAM,KAAK;AAAA,MACX,gBAAgB,KAAK;AAAA,IACvB;AACA,UAAM,KAAK,IAAI,MAAM,QAAQ;AAC7B,QAAI,OAAO,OAAW,MAAK,YAAY,EAAE;AAAA,EAC3C;AAGA,MAAI,MAAM,aAAa,OAAW,MAAK,YAAY,MAAM,QAAQ;AAEjE,OAAK,cAAc,MAAM,cAAc,CAAC;AACxC,MAAI,MAAM,cAAc,QAAW;AACjC,QAAI,OAAO,MAAM,cAAc,UAAU;AACvC,WAAK,aAAa,MAAM,SAAS;AAAA,IACnC,WAAW,OAAO,MAAM,SAAS,EAAE,SAAS,GAAG,GAAG;AAChD,WAAK,aAAa,OAAO,MAAM,SAAS,CAAiB;AAAA,IAC3D,WAAW,MAAM,cAAc,QAAQ;AACrC,WAAK,aAAa,MAAM;AAAA,IAC1B,OAAO;AACL,YAAM,IAAI,WAAW,OAAO,MAAM,SAAS,CAAC;AAC5C,UAAI,CAAC,MAAM,CAAC,EAAG,MAAK,aAAa,CAAC;AAAA,IACpC;AAAA,EACF;AAGA,iBAAe,MAAM,YAAY,MAAM,KAAK;AAC5C,iBAAe,MAAM,aAAa,MAAM,MAAM;AAC9C,iBAAe,MAAM,eAAe,MAAM,QAAQ;AAClD,iBAAe,MAAM,gBAAgB,MAAM,SAAS;AACpD,iBAAe,MAAM,eAAe,MAAM,QAAQ;AAClD,iBAAe,MAAM,gBAAgB,MAAM,SAAS;AAGpD,MAAI,MAAM,aAAa,YAAY;AACjC,SAAK,gBAAgB,aAAa,QAAQ;AAAA,EAC5C,OAAO;AACL,SAAK,gBAAgB,aAAa,QAAQ;AAAA,EAC5C;AAGA,iBAAe,MAAM,eAAe,KAAK,KAAK,MAAM,GAAG;AACvD,iBAAe,MAAM,eAAe,KAAK,OAAO,MAAM,KAAK;AAC3D,iBAAe,MAAM,eAAe,KAAK,QAAQ,MAAM,MAAM;AAC7D,iBAAe,MAAM,eAAe,KAAK,MAAM,MAAM,IAAI;AAGzD,iBAAe,MAAM,aAAa,KAAK,KAAK,MAAM,SAAS;AAC3D,iBAAe,MAAM,aAAa,KAAK,OAAO,MAAM,WAAW;AAC/D,iBAAe,MAAM,aAAa,KAAK,QAAQ,MAAM,YAAY;AACjE,iBAAe,MAAM,aAAa,KAAK,MAAM,MAAM,UAAU;AAG7D,iBAAe,MAAM,cAAc,KAAK,KAAK,MAAM,UAAU;AAC7D,iBAAe,MAAM,cAAc,KAAK,OAAO,MAAM,YAAY;AACjE,iBAAe,MAAM,cAAc,KAAK,QAAQ,MAAM,aAAa;AACnE,iBAAe,MAAM,cAAc,KAAK,MAAM,MAAM,WAAW;AAG/D,MAAI,MAAM,mBAAmB;AAC3B,SAAK,UAAU,KAAK,KAAK,MAAM,cAAc;AAC/C,MAAI,MAAM,qBAAqB;AAC7B,SAAK,UAAU,KAAK,OAAO,MAAM,gBAAgB;AACnD,MAAI,MAAM,sBAAsB;AAC9B,SAAK,UAAU,KAAK,QAAQ,MAAM,iBAAiB;AACrD,MAAI,MAAM,oBAAoB;AAC5B,SAAK,UAAU,KAAK,MAAM,MAAM,eAAe;AAGjD,MAAI,MAAM,WAAW,OAAW,MAAK,OAAO,OAAO,KAAK,MAAM,MAAM;AACpE,MAAI,MAAM,cAAc;AACtB,SAAK,OAAO,OAAO,QAAQ,MAAM,SAAS;AAG5C,MACE,MAAM,aAAa,YACnB,MAAM,cAAc,YACpB,MAAM,cAAc,UACpB;AACA,SAAK,YAAY,SAAS,MAAM;AAAA,EAClC,OAAO;AACL,SAAK,YAAY,SAAS,OAAO;AAAA,EACnC;AACF;AAEA,SAAS,eACP,MACA,QAOA,OACM;AACN,MAAI,UAAU,OAAW;AACzB,MAAI,UAAU,QAAQ;AACpB,QAAI,WAAW,cAAc,WAAW,aAAa;AACnD,WAAK,MAAM,EAAE,MAAM;AAAA,IACrB;AACA;AAAA,EACF;AACA,MAAI,OAAO,UAAU,UAAU;AAC7B,SAAK,MAAM,EAAE,KAAK;AAClB;AAAA,EACF;AACA,QAAM,IAAI,OAAO,KAAK;AACtB,MAAI,EAAE,SAAS,GAAG,GAAG;AACnB,SAAK,MAAM,EAAE,CAAiB;AAAA,EAChC,OAAO;AACL,UAAM,IAAI,WAAW,CAAC;AACtB,QAAI,CAAC,MAAM,CAAC,EAAG,MAAK,MAAM,EAAE,CAAC;AAAA,EAC/B;AACF;AAEA,SAAS,eACP,MACA,QACA,MACA,OACM;AACN,MAAI,UAAU,OAAW;AACzB,MAAI,UAAU,UAAU,WAAW,aAAa;AAC9C,SAAK,UAAU,MAAM,MAAM;AAC3B;AAAA,EACF;AACA,MAAI,OAAO,UAAU,UAAU;AAC7B,SAAK,MAAM,EAAE,MAAM,KAAK;AACxB;AAAA,EACF;AACA,QAAM,IAAI,OAAO,KAAK;AACtB,MAAI,EAAE,SAAS,GAAG,GAAG;AACnB,SAAK,MAAM,EAAE,MAAM,CAAiB;AAAA,EACtC,OAAO;AACL,UAAM,IAAI,WAAW,CAAC;AACtB,QAAI,CAAC,MAAM,CAAC,EAAG,MAAK,MAAM,EAAE,MAAM,CAAC;AAAA,EACrC;AACF;;;AJ/LA,eAAsB,gBACpB,SACA,gBACA,iBACA,KACA,cACqB;AACrB,QAAM,eAAe,eAAe;AAGpC,QAAM,WAAW,MAAM;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAGA,eAAa,SAAS,cAAc;AACpC,eAAa,UAAU,eAAe;AAGtC,eAAa,gBAAgB,gBAAgB,eAAe;AAG5D,QAAM,aAAa,cAAc,UAAU,YAAY;AAGvD,eAAa,YAAY;AAEzB,SAAO;AACT;AAEA,eAAe,UACb,SACA,aACA,UACA,eACA,gBACA,KACA,cAC2B;AAE3B,MACE,YAAY,QACZ,YAAY,UACZ,OAAO,YAAY,WACnB;AACA,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,UAAU,CAAC;AAAA,MACX,OAAO,CAAC;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAGA,MAAI,OAAO,YAAY,YAAY,OAAO,YAAY,UAAU;AAC9D,UAAM,OAAO,OAAO,OAAO;AAC3B,UAAMC,SAAQ,aAAa,QAAW,WAAW;AAGjD,UAAM,cAAc,sBAAsB,MAAMA,QAAO,KAAK,YAAY;AACxE,aAAS,eAAe,WAAW;AAEnC,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAAA;AAAA,MACA,UAAU,CAAC;AAAA,MACX,aAAa;AAAA,MACb,OAAO,CAAC;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAGA,MAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,UAAMA,SAAQ,aAAa,QAAW,WAAW;AACjD,UAAMC,YAA+B,CAAC;AAEtC,aAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,YAAM,QAAQ,QAAQ,CAAC;AACvB,UAAI,UAAU,QAAQ,UAAU,UAAa,OAAO,UAAU;AAC5D;AAEF,YAAM,gBAAgB,eAAe;AACrC,eAAS,YAAY,eAAeA,UAAS,MAAM;AACnD,MAAAA,UAAS;AAAA,QACP,MAAM;AAAA,UACJ;AAAA,UACAD;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAAA;AAAA,MACA,UAAAC;AAAA,MACA,OAAO,CAAC;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAGA,QAAM,KAAK;AACX,QAAM,OAAO,GAAG;AAGhB,MAAI,OAAO,SAAS,YAAY;AAC9B,UAAM,WAAY;AAAA,MAChB,GAAG,SAAS,CAAC;AAAA,IACf;AACA,WAAO,MAAM;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,QAAS,GAAG,SAAS,CAAC;AAC5B,QAAM,WAAY,MAAM,SAAS,CAAC;AAClC,QAAM,WAAW,YAAY,QAAQ;AACrC,QAAM,QAAQ,aAAa,UAAU,WAAW;AAChD,eAAa,OAAO,eAAe,cAAc;AAEjD,QAAM,UAAU,OAAO,IAAI;AAG3B,MAAI,YAAY,OAAO;AACrB,QAAI,MAAM,SAAS,QAAQ,MAAM,UAAU,QAAW;AACpD,YAAM,IAAI,MAAM;AAChB,YAAM,QAAQ,OAAO,MAAM,YAAY,EAAE,SAAS,GAAG,IAAI,IAAI,OAAO,CAAC;AAAA,IACvE;AACA,QAAI,MAAM,UAAU,QAAQ,MAAM,WAAW,QAAW;AACtD,YAAM,IAAI,MAAM;AAChB,YAAM,SAAS,OAAO,MAAM,YAAY,EAAE,SAAS,GAAG,IAAI,IAAI,OAAO,CAAC;AAAA,IACxE;AAGA,UAAM,UAAU,MAAM;AACtB,QAAI,SAAS;AACX,YAAM,QAAQ,QAAQ,MAAM,QAAQ,EAAE,IAAI,MAAM;AAChD,UAAI,MAAM,WAAW,GAAG;AACtB,cAAM,CAAC,EAAE,EAAE,KAAK,GAAG,IAAI;AACvB,YAAI,MAAM,KAAK,MAAM,GAAG;AACtB,gBAAM,IAAI,OAAO,MAAM,UAAU,WAAW,MAAM,QAAQ;AAC1D,gBAAM,IAAI,OAAO,MAAM,WAAW,WAAW,MAAM,SAAS;AAC5D,cAAI,MAAM,UAAa,MAAM,QAAW;AACtC,kBAAM,SAAS,KAAK,MAAM;AAAA,UAC5B,WAAW,MAAM,UAAa,MAAM,QAAW;AAC7C,kBAAM,QAAQ,KAAK,MAAM;AAAA,UAC3B,WAAW,MAAM,UAAa,MAAM,QAAW;AAC7C,kBAAM,QAAQ;AACd,kBAAM,SAAS;AAAA,UACjB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,YAAY,OAAO;AAErB,QAAI,MAAM,SAAS,QAAQ,MAAM,UAAU,QAAW;AACpD,YAAM,IAAI,MAAM;AAChB,YAAM,QAAQ,OAAO,MAAM,YAAY,EAAE,SAAS,GAAG,IAAI,IAAI,OAAO,CAAC;AAAA,IACvE;AACA,QAAI,MAAM,UAAU,QAAQ,MAAM,WAAW,QAAW;AACtD,YAAM,IAAI,MAAM;AAChB,YAAM,SAAS,OAAO,MAAM,YAAY,EAAE,SAAS,GAAG,IAAI,IAAI,OAAO,CAAC;AAAA,IACxE;AAEA,UAAM,MAAM,MAAM;AAClB,QAAI,KAAK;AACP,UAAI;AACF,cAAM,QAAQ,MAAMC,WAAU,GAAG;AACjC,cAAM,WAAW,MAAM;AACvB,cAAM,WAAW,MAAM;AAEvB,cAAM,IAAI,OAAO,MAAM,UAAU,WAAW,MAAM,QAAQ;AAC1D,cAAM,IAAI,OAAO,MAAM,WAAW,WAAW,MAAM,SAAS;AAE5D,YAAI,MAAM,UAAa,MAAM,UAAa,WAAW,GAAG;AACtD,gBAAM,SAAS,KAAK,WAAW;AAAA,QACjC,WAAW,MAAM,UAAa,MAAM,UAAa,WAAW,GAAG;AAC7D,gBAAM,QAAQ,KAAK,WAAW;AAAA,QAChC;AAGA,cAAM,gBAAgB;AAAA,MACxB,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAGA,oBAAkB,UAAU,KAAK;AAIjC,MAAI,YAAY,OAAO;AACrB,WAAO;AAAA,MACL,MAAM;AAAA,MACN;AAAA,MACA,UAAU,CAAC;AAAA,MACX;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAGA,QAAM,cAAc,mBAAmB,MAAM,QAAQ;AAMrD,MAAI,gBAAgB,UAAa,CAAC,mBAAmB,MAAM,QAAQ,GAAG;AACpE,UAAM,aAAa,aAAa,QAAW,KAAK;AAChD,UAAM,gBAAgB,eAAe;AACrC,UAAM,cAAc;AAAA,MAClB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,kBAAc,eAAe,WAAW;AACxC,kBAAc,YAAY,CAAC;AAC3B,kBAAc,cAAc,CAAC;AAC7B,aAAS,YAAY,eAAe,CAAC;AAErC,WAAO;AAAA,MACL,MAAM;AAAA,MACN;AAAA,MACA,UAAU;AAAA,QACR;AAAA,UACE,MAAM;AAAA,UACN,OAAO;AAAA,UACP,UAAU,CAAC;AAAA,UACX;AAAA,UACA,OAAO,CAAC;AAAA,UACR,UAAU;AAAA,QACZ;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAGA,QAAM,WAA+B,CAAC;AACtC,QAAM,cAAc,MAAM;AAE1B,MAAI,gBAAgB,UAAa,gBAAgB,MAAM;AACrD,UAAM,aAAa,MAAM,QAAQ,WAAW,IAAI,cAAc,CAAC,WAAW;AAE1E,eAAW,SAAS,YAA8B;AAChD,UAAI,UAAU,QAAQ,UAAU,UAAa,OAAO,UAAU;AAC5D;AAEF,YAAM,gBAAgB,eAAe;AACrC,eAAS,YAAY,eAAe,SAAS,MAAM;AACnD,eAAS;AAAA,QACP,MAAM;AAAA,UACJ;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAWA,SAAS,cAAc,MAAwB,UAAgC;AAC7E,QAAM,SAAS,SAAS,kBAAkB;AAE1C,SAAO;AAAA,IACL,MAAM,KAAK;AAAA,IACX,OAAO,KAAK;AAAA,IACZ,UAAU,KAAK,SAAS,IAAI,CAAC,OAAO,MAAM;AACxC,YAAM,YAAY,SAAS,SAAS,CAAC;AACrC,aAAO,cAAc,OAAO,SAAS;AAAA,IACvC,CAAC;AAAA,IACD,aAAa,KAAK;AAAA,IAClB,OAAO,KAAK;AAAA,IACZ,GAAG,OAAO;AAAA,IACV,GAAG,OAAO;AAAA,IACV,OAAO,OAAO;AAAA,IACd,QAAQ,OAAO;AAAA,EACjB;AACF;AAKA,SAAS,mBAAmB,UAAuC;AACjE,MAAI,aAAa,UAAa,aAAa,KAAM,QAAO;AACxD,MAAI,OAAO,aAAa,SAAU,QAAO;AACzC,MAAI,OAAO,aAAa,SAAU,QAAO,OAAO,QAAQ;AAExD,MAAI,MAAM,QAAQ,QAAQ,GAAG;AAC3B,UAAM,QAAkB,CAAC;AACzB,eAAW,SAAS,UAAU;AAC5B,UAAI,OAAO,UAAU,UAAU;AAC7B,cAAM,KAAK,KAAK;AAAA,MAClB,WAAW,OAAO,UAAU,UAAU;AACpC,cAAM,KAAK,OAAO,KAAK,CAAC;AAAA,MAC1B,WACE,UAAU,QACV,UAAU,UACV,OAAO,UAAU,WACjB;AACA,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO,MAAM,KAAK,EAAE;AAAA,EACtB;AAEA,SAAO;AACT;AAKA,SAAS,mBAAmB,UAA4B;AACtD,MACE,aAAa,UACb,aAAa,QACb,OAAO,aAAa;AAEpB,WAAO;AACT,MAAI,OAAO,aAAa,YAAY,OAAO,aAAa;AACtD,WAAO;AAET,MAAI,MAAM,QAAQ,QAAQ,GAAG;AAC3B,WAAO,SAAS;AAAA,MACd,CAAC,UACC,UAAU,QACV,UAAU,UACV,OAAO,UAAU,aACjB,OAAO,UAAU,YACjB,OAAO,UAAU;AAAA,IACrB;AAAA,EACF;AAGA,SAAO,OAAO,aAAa;AAC7B;;;AK5YA,eAAsB,mBACpB,KACA,SACA,SACe;AAEf,wBAAsB,QAAQ,KAAK;AAGnC,QAAM,QAAQ,IAAI,OAAO;AACzB,QAAM,SAAS,IAAI,OAAO;AAG1B,QAAM,aACJ,QAAQ,UAAU,SAAS,SAAa,QAAQ,SAAS;AAC3D,QAAM,aAAa,MAAM;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,CAAC,CAAC;AAAA,EACJ;AAGA,QAAM,SAAS,KAAK,YAAY,GAAG,GAAG,QAAQ,SAAS,OAAO,UAAU;AAC1E;;;AtB7CO,SAASC,cAAa,OAAe,QAAgB;AAC1D,QAAM,SAAS,cAAc,OAAO,MAAM;AAC1C,QAAM,aAAa,OAAO,OAAO,KAAK,MAAM;AAO5C,SAAO,UAAU,UAAU,SACzB,OAAO,KAAK,MAAM,WAAW,GAAI,IAA2B,CAAC;AAE/D,SAAO;AACT;","names":["GlobalFonts","loadImage","createCanvas","loadImage","loadImage","measureText","loadImage","canvas","createCanvas","hasRadius","loadImage","toNumber","loadImage","style","children","loadImage","createCanvas"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effing/canvas",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.4",
|
|
4
4
|
"description": "Low-level canvas rendering for JSX and Lottie using @napi-rs/canvas (Skia)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"tsx": "^4.0.0",
|
|
34
34
|
"typescript": "^5.9.3",
|
|
35
35
|
"vitest": "^3.2.4",
|
|
36
|
-
"@effing/tween": "0.18.
|
|
36
|
+
"@effing/tween": "0.18.4"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"@napi-rs/canvas": ">=0.1.50",
|