@spectratools/graphic-designer-cli 0.12.3 → 0.14.1

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 CHANGED
@@ -929,6 +929,27 @@ var drawTextRowSchema = z2.object({
929
929
  defaultColor: colorHexSchema2.default("#FFFFFF"),
930
930
  opacity: z2.number().min(0).max(1).default(1)
931
931
  }).strict();
932
+ var drawStatsBarItemSchema = z2.object({
933
+ value: z2.string().min(1).max(50),
934
+ label: z2.string().min(1).max(100)
935
+ }).strict();
936
+ var drawStatsBarSchema = z2.object({
937
+ type: z2.literal("stats-bar"),
938
+ y: z2.number().describe("Vertical position of the stats bar"),
939
+ items: z2.array(drawStatsBarItemSchema).min(1).max(8),
940
+ separator: z2.enum(["dot", "pipe", "none"]).default("dot"),
941
+ valueColor: colorHexSchema2.default("#FFFFFF"),
942
+ valueFontSize: z2.number().min(8).max(72).default(18),
943
+ valueFontWeight: z2.number().int().min(100).max(900).default(700),
944
+ valueFontFamily: drawFontFamilySchema.default("mono"),
945
+ labelColor: colorHexSchema2.default("#AAAAAA"),
946
+ labelFontSize: z2.number().min(8).max(72).default(14),
947
+ labelFontWeight: z2.number().int().min(100).max(900).default(400),
948
+ labelFontFamily: drawFontFamilySchema.default("body"),
949
+ separatorColor: colorHexSchema2.default("#666666"),
950
+ gap: z2.number().min(0).max(100).default(24),
951
+ opacity: z2.number().min(0).max(1).default(1)
952
+ }).strict();
932
953
  var drawCommandSchema = z2.discriminatedUnion("type", [
933
954
  drawRectSchema,
934
955
  drawCircleSchema,
@@ -940,7 +961,8 @@ var drawCommandSchema = z2.discriminatedUnion("type", [
940
961
  drawBadgeSchema,
941
962
  drawGradientRectSchema,
942
963
  drawGridSchema,
943
- drawTextRowSchema
964
+ drawTextRowSchema,
965
+ drawStatsBarSchema
944
966
  ]);
945
967
  var defaultCanvas = {
946
968
  width: 1200,
@@ -1142,6 +1164,24 @@ var imageElementSchema = z2.object({
1142
1164
  fit: z2.enum(["contain", "cover", "fill", "none"]).default("contain"),
1143
1165
  borderRadius: z2.number().min(0).default(0)
1144
1166
  }).strict();
1167
+ var ringSegmentSchema = z2.object({
1168
+ color: colorHexSchema2
1169
+ }).strict();
1170
+ var ringElementSchema = z2.object({
1171
+ type: z2.literal("ring"),
1172
+ id: z2.string().min(1).max(120),
1173
+ radius: z2.number().min(8).max(512).default(48),
1174
+ strokeWidth: z2.number().min(1).max(32).default(2),
1175
+ label: z2.string().max(100).optional(),
1176
+ labelColor: colorHexSchema2.optional(),
1177
+ labelSize: z2.number().min(8).max(48).default(12),
1178
+ segments: z2.array(ringSegmentSchema).min(1).max(24).default([{ color: "#4A7BF7" }]),
1179
+ glowRadius: z2.number().min(0).max(64).default(0),
1180
+ glowColor: colorHexSchema2.optional(),
1181
+ showCycleArrows: z2.boolean().default(false),
1182
+ fill: colorHexSchema2.optional(),
1183
+ fillOpacity: z2.number().min(0).max(1).default(0.05)
1184
+ }).strict();
1145
1185
  var elementSchema = z2.discriminatedUnion("type", [
1146
1186
  cardElementSchema,
1147
1187
  flowNodeElementSchema,
@@ -1150,7 +1190,8 @@ var elementSchema = z2.discriminatedUnion("type", [
1150
1190
  terminalElementSchema,
1151
1191
  textElementSchema,
1152
1192
  shapeElementSchema,
1153
- imageElementSchema
1193
+ imageElementSchema,
1194
+ ringElementSchema
1154
1195
  ]);
1155
1196
  var diagramCenterSchema = z2.object({
1156
1197
  x: z2.number(),
@@ -1271,8 +1312,13 @@ var decoratorSchema = z2.discriminatedUnion("type", [
1271
1312
  }).strict(),
1272
1313
  z2.object({
1273
1314
  type: z2.literal("vignette"),
1315
+ mode: z2.enum(["radial", "edge"]).default("radial"),
1274
1316
  intensity: z2.number().min(0).max(1).default(0.3),
1275
- color: colorHexSchema2.default("#000000")
1317
+ color: colorHexSchema2.default("#000000"),
1318
+ edgeTopHeight: z2.number().min(0).max(200).default(35),
1319
+ edgeBottomHeight: z2.number().min(0).max(200).default(55),
1320
+ edgeTopOpacity: z2.number().min(0).max(1).default(0.3),
1321
+ edgeBottomOpacity: z2.number().min(0).max(1).default(0.4)
1276
1322
  }).strict(),
1277
1323
  z2.object({
1278
1324
  type: z2.literal("gradient-overlay"),
@@ -2082,6 +2128,8 @@ function estimateElementHeight(element) {
2082
2128
  return 130;
2083
2129
  case "image":
2084
2130
  return 220;
2131
+ case "ring":
2132
+ return element.radius * 2 + element.glowRadius * 2 + 16;
2085
2133
  case "connection":
2086
2134
  return 0;
2087
2135
  }
@@ -2102,6 +2150,8 @@ function estimateElementWidth(element) {
2102
2150
  return 280;
2103
2151
  case "image":
2104
2152
  return 320;
2153
+ case "ring":
2154
+ return element.radius * 2 + element.glowRadius * 2 + 16;
2105
2155
  case "connection":
2106
2156
  return 0;
2107
2157
  }
@@ -2716,6 +2766,30 @@ function drawRainbowRule(ctx, x, y, width, thickness = 2, colors = [...DEFAULT_R
2716
2766
  ctx.fill();
2717
2767
  ctx.restore();
2718
2768
  }
2769
+ function drawEdgeVignette(ctx, width, height, color = "#000000", topHeight = 35, bottomHeight = 55, topOpacity = 0.3, bottomOpacity = 0.4) {
2770
+ if (width <= 0 || height <= 0) {
2771
+ return;
2772
+ }
2773
+ if (topHeight > 0 && topOpacity > 0) {
2774
+ const topGradient = ctx.createLinearGradient(0, 0, 0, topHeight);
2775
+ topGradient.addColorStop(0, withAlpha2(color, clamp01(topOpacity)));
2776
+ topGradient.addColorStop(1, withAlpha2(color, 0));
2777
+ ctx.save();
2778
+ ctx.fillStyle = topGradient;
2779
+ ctx.fillRect(0, 0, width, topHeight);
2780
+ ctx.restore();
2781
+ }
2782
+ if (bottomHeight > 0 && bottomOpacity > 0) {
2783
+ const bottomY = height - bottomHeight;
2784
+ const bottomGradient = ctx.createLinearGradient(0, bottomY, 0, height);
2785
+ bottomGradient.addColorStop(0, withAlpha2(color, 0));
2786
+ bottomGradient.addColorStop(1, withAlpha2(color, clamp01(bottomOpacity)));
2787
+ ctx.save();
2788
+ ctx.fillStyle = bottomGradient;
2789
+ ctx.fillRect(0, bottomY, width, bottomHeight);
2790
+ ctx.restore();
2791
+ }
2792
+ }
2719
2793
  function drawVignette(ctx, width, height, intensity = 0.3, color = "#000000") {
2720
2794
  if (width <= 0 || height <= 0 || intensity <= 0) {
2721
2795
  return;
@@ -4621,10 +4695,118 @@ function renderDrawCommands(ctx, commands, theme) {
4621
4695
  });
4622
4696
  break;
4623
4697
  }
4698
+ case "stats-bar": {
4699
+ const barRect = renderStatsBar(ctx, command, theme);
4700
+ rendered.push({
4701
+ id,
4702
+ kind: "draw",
4703
+ bounds: barRect,
4704
+ foregroundColor: command.valueColor,
4705
+ backgroundColor: theme.background
4706
+ });
4707
+ break;
4708
+ }
4624
4709
  }
4625
4710
  }
4626
4711
  return rendered;
4627
4712
  }
4713
+ function renderStatsBar(ctx, command, theme) {
4714
+ const canvasWidth = ctx.canvas.width;
4715
+ const valueFontFamily = resolveDrawFont(theme, command.valueFontFamily);
4716
+ const labelFontFamily = resolveDrawFont(theme, command.labelFontFamily);
4717
+ const spaceWidth = 4;
4718
+ const measuredItems = [];
4719
+ for (const item of command.items) {
4720
+ applyFont(ctx, {
4721
+ size: command.valueFontSize,
4722
+ weight: command.valueFontWeight,
4723
+ family: valueFontFamily
4724
+ });
4725
+ const valueWidth = ctx.measureText(item.value).width;
4726
+ applyFont(ctx, {
4727
+ size: command.labelFontSize,
4728
+ weight: command.labelFontWeight,
4729
+ family: labelFontFamily
4730
+ });
4731
+ const labelWidth = ctx.measureText(item.label).width;
4732
+ measuredItems.push({
4733
+ valueWidth,
4734
+ labelWidth,
4735
+ totalWidth: valueWidth + spaceWidth + labelWidth
4736
+ });
4737
+ }
4738
+ let separatorWidth = 0;
4739
+ let separatorText = "";
4740
+ if (command.separator !== "none" && command.items.length > 1) {
4741
+ separatorText = command.separator === "dot" ? "\xB7" : "|";
4742
+ const sepFontSize = Math.max(command.valueFontSize, command.labelFontSize);
4743
+ applyFont(ctx, { size: sepFontSize, weight: 400, family: labelFontFamily });
4744
+ separatorWidth = ctx.measureText(separatorText).width;
4745
+ }
4746
+ const itemsWidth = measuredItems.reduce((sum, m) => sum + m.totalWidth, 0);
4747
+ const gapCount = command.items.length - 1;
4748
+ const totalWidth = itemsWidth + gapCount * (command.gap + separatorWidth);
4749
+ let cursorX = (canvasWidth - totalWidth) / 2;
4750
+ const startX = cursorX;
4751
+ applyFont(ctx, {
4752
+ size: command.valueFontSize,
4753
+ weight: command.valueFontWeight,
4754
+ family: valueFontFamily
4755
+ });
4756
+ const valueMetrics = ctx.measureText("M");
4757
+ const valueAscent = valueMetrics.actualBoundingBoxAscent || command.valueFontSize * 0.75;
4758
+ const valueDescent = valueMetrics.actualBoundingBoxDescent || command.valueFontSize * 0.25;
4759
+ applyFont(ctx, {
4760
+ size: command.labelFontSize,
4761
+ weight: command.labelFontWeight,
4762
+ family: labelFontFamily
4763
+ });
4764
+ const labelMetrics = ctx.measureText("M");
4765
+ const labelAscent = labelMetrics.actualBoundingBoxAscent || command.labelFontSize * 0.75;
4766
+ const labelDescent = labelMetrics.actualBoundingBoxDescent || command.labelFontSize * 0.25;
4767
+ const maxAscent = Math.max(valueAscent, labelAscent);
4768
+ const maxDescent = Math.max(valueDescent, labelDescent);
4769
+ withOpacity(ctx, command.opacity, () => {
4770
+ for (let i = 0; i < command.items.length; i++) {
4771
+ const item = command.items[i];
4772
+ const measured = measuredItems[i];
4773
+ applyFont(ctx, {
4774
+ size: command.valueFontSize,
4775
+ weight: command.valueFontWeight,
4776
+ family: valueFontFamily
4777
+ });
4778
+ ctx.fillStyle = command.valueColor;
4779
+ ctx.textAlign = "left";
4780
+ ctx.textBaseline = "alphabetic";
4781
+ ctx.fillText(item.value, cursorX, command.y);
4782
+ cursorX += measured.valueWidth + spaceWidth;
4783
+ applyFont(ctx, {
4784
+ size: command.labelFontSize,
4785
+ weight: command.labelFontWeight,
4786
+ family: labelFontFamily
4787
+ });
4788
+ ctx.fillStyle = command.labelColor;
4789
+ ctx.fillText(item.label, cursorX, command.y);
4790
+ cursorX += measured.labelWidth;
4791
+ if (i < command.items.length - 1 && command.separator !== "none") {
4792
+ const sepFontSize = Math.max(command.valueFontSize, command.labelFontSize);
4793
+ applyFont(ctx, { size: sepFontSize, weight: 400, family: labelFontFamily });
4794
+ ctx.fillStyle = command.separatorColor;
4795
+ ctx.textAlign = "center";
4796
+ ctx.fillText(separatorText, cursorX + command.gap / 2 + separatorWidth / 2, command.y);
4797
+ ctx.textAlign = "left";
4798
+ cursorX += command.gap + separatorWidth;
4799
+ }
4800
+ }
4801
+ });
4802
+ const height = Math.max(1, maxAscent + maxDescent);
4803
+ return {
4804
+ x: startX,
4805
+ y: command.y - maxAscent,
4806
+ width: Math.max(1, totalWidth),
4807
+ height
4808
+ };
4809
+ }
4628
4810
 
4629
4811
  // src/renderers/image.ts
4630
4812
  import { loadImage } from "@napi-rs/canvas";
@@ -4711,6 +4893,110 @@ async function renderImageElement(ctx, image, bounds, theme) {
4711
4893
  }
4712
4894
  }
4713
4895
 
4896
+ // src/renderers/ring.ts
4897
+ function renderRingElement(ctx, ring, bounds, theme) {
4898
+ const cx = bounds.x + bounds.width / 2;
4899
+ const cy = bounds.y + bounds.height / 2;
4900
+ const { radius, strokeWidth, segments } = ring;
4901
+ if (ring.glowRadius > 0) {
4902
+ const glowColor = ring.glowColor ?? segments[0].color;
4903
+ ctx.save();
4904
+ ctx.globalAlpha = 0.15;
4905
+ ctx.beginPath();
4906
+ ctx.arc(cx, cy, radius + ring.glowRadius, 0, Math.PI * 2);
4907
+ ctx.fillStyle = glowColor;
4908
+ ctx.fill();
4909
+ ctx.restore();
4910
+ }
4911
+ if (ring.fill || ring.fillOpacity > 0) {
4912
+ const fillColor = ring.fill ?? segments[0].color;
4913
+ ctx.save();
4914
+ ctx.globalAlpha = ring.fillOpacity;
4915
+ ctx.beginPath();
4916
+ ctx.arc(cx, cy, radius, 0, Math.PI * 2);
4917
+ ctx.fillStyle = fillColor;
4918
+ ctx.fill();
4919
+ ctx.restore();
4920
+ }
4921
+ ctx.save();
4922
+ ctx.globalAlpha = 0.2;
4923
+ ctx.beginPath();
4924
+ ctx.arc(cx, cy, radius, 0, Math.PI * 2);
4925
+ ctx.strokeStyle = theme.border;
4926
+ ctx.lineWidth = strokeWidth;
4927
+ ctx.stroke();
4928
+ ctx.restore();
4929
+ const segmentAngle = 2 * Math.PI / segments.length;
4930
+ for (let i = 0; i < segments.length; i++) {
4931
+ const startAngle = i * segmentAngle - Math.PI / 2;
4932
+ ctx.beginPath();
4933
+ ctx.arc(cx, cy, radius, startAngle, startAngle + segmentAngle);
4934
+ ctx.strokeStyle = segments[i].color;
4935
+ ctx.lineWidth = strokeWidth;
4936
+ ctx.stroke();
4937
+ }
4938
+ if (ring.showCycleArrows) {
4939
+ const arrowArcRadius = radius + strokeWidth + 4;
4940
+ const arrowColor = segments[0].color;
4941
+ const numArrows = Math.min(segments.length, 4);
4942
+ const arrowSpacing = 2 * Math.PI / numArrows;
4943
+ for (let i = 0; i < numArrows; i++) {
4944
+ const baseAngle = i * arrowSpacing - Math.PI / 2;
4945
+ const arcStart = baseAngle + 0.15;
4946
+ const arcEnd = baseAngle + arrowSpacing - 0.15;
4947
+ ctx.beginPath();
4948
+ ctx.arc(cx, cy, arrowArcRadius, arcStart, arcEnd);
4949
+ ctx.strokeStyle = arrowColor;
4950
+ ctx.lineWidth = Math.max(1, strokeWidth * 0.6);
4951
+ ctx.stroke();
4952
+ const headAngle = arcEnd;
4953
+ const headX = cx + arrowArcRadius * Math.cos(headAngle);
4954
+ const headY = cy + arrowArcRadius * Math.sin(headAngle);
4955
+ const tangentAngle = headAngle + Math.PI / 2;
4956
+ const headSize = Math.max(4, strokeWidth * 2);
4957
+ ctx.beginPath();
4958
+ ctx.moveTo(headX, headY);
4959
+ ctx.lineTo(
4960
+ headX - headSize * Math.cos(tangentAngle - 0.4),
4961
+ headY - headSize * Math.sin(tangentAngle - 0.4)
4962
+ );
4963
+ ctx.lineTo(
4964
+ headX - headSize * Math.cos(tangentAngle + 0.4),
4965
+ headY - headSize * Math.sin(tangentAngle + 0.4)
4966
+ );
4967
+ ctx.closePath();
4968
+ ctx.fillStyle = arrowColor;
4969
+ ctx.fill();
4970
+ }
4971
+ }
4972
+ if (ring.label) {
4973
+ const labelColor = ring.labelColor ?? theme.text;
4974
+ const labelSize = ring.labelSize;
4975
+ const bodyFont = resolveFont(theme.fonts.body, "body");
4976
+ applyFont(ctx, { size: labelSize, weight: 500, family: bodyFont });
4977
+ ctx.fillStyle = labelColor;
4978
+ ctx.textAlign = "center";
4979
+ ctx.textBaseline = "middle";
4980
+ const lines = ring.label.split("\\n");
4981
+ const lineHeight = labelSize * 1.3;
4982
+ const totalHeight = lines.length * lineHeight;
4983
+ const startY = cy - totalHeight / 2 + lineHeight / 2;
4984
+ for (let i = 0; i < lines.length; i++) {
4985
+ ctx.fillText(lines[i], cx, startY + i * lineHeight);
4986
+ }
4987
+ ctx.textAlign = "left";
4988
+ ctx.textBaseline = "alphabetic";
4989
+ }
4990
+ return [
4991
+ {
4992
+ id: `ring-${ring.id}`,
4993
+ kind: "shape",
4994
+ bounds,
4995
+ foregroundColor: segments[0].color
4996
+ }
4997
+ ];
4998
+ }
4999
+
4714
5000
  // src/renderers/shape.ts
4715
5001
  function renderShapeElement(ctx, shape, bounds, theme) {
4716
5002
  const fill = shape.fill ?? theme.surfaceMuted;
@@ -5146,7 +5432,16 @@ async function renderDesign(input, options = {}) {
5146
5432
  const deferredVignettes = [];
5147
5433
  for (const [index, decorator] of spec.decorators.entries()) {
5148
5434
  if (decorator.type === "vignette") {
5149
- deferredVignettes.push({ index, intensity: decorator.intensity, color: decorator.color });
5435
+ deferredVignettes.push({
5436
+ index,
5437
+ mode: decorator.mode,
5438
+ intensity: decorator.intensity,
5439
+ color: decorator.color,
5440
+ edgeTopHeight: decorator.edgeTopHeight,
5441
+ edgeBottomHeight: decorator.edgeBottomHeight,
5442
+ edgeTopOpacity: decorator.edgeTopOpacity,
5443
+ edgeBottomOpacity: decorator.edgeBottomOpacity
5444
+ });
5150
5445
  continue;
5151
5446
  }
5152
5447
  if (decorator.type === "gradient-overlay") {
@@ -5219,6 +5514,9 @@ async function renderDesign(input, options = {}) {
5219
5514
  case "image":
5220
5515
  elements.push(...await renderImageElement(ctx, element, rect, theme));
5221
5516
  break;
5517
+ case "ring":
5518
+ elements.push(...renderRingElement(ctx, element, rect, theme));
5519
+ break;
5222
5520
  }
5223
5521
  }
5224
5522
  const nodeBounds = spec.elements.filter((element) => element.type !== "connection").map((element) => elementRects.get(element.id)).filter((rect) => rect != null);
@@ -5273,7 +5571,20 @@ async function renderDesign(input, options = {}) {
5273
5571
  }
5274
5572
  elements.push(...renderDrawCommands(ctx, spec.draw, theme));
5275
5573
  for (const vignette of deferredVignettes) {
5276
- drawVignette(ctx, spec.canvas.width, spec.canvas.height, vignette.intensity, vignette.color);
5574
+ if (vignette.mode === "edge") {
5575
+ drawEdgeVignette(
5576
+ ctx,
5577
+ spec.canvas.width,
5578
+ spec.canvas.height,
5579
+ vignette.color,
5580
+ vignette.edgeTopHeight,
5581
+ vignette.edgeBottomHeight,
5582
+ vignette.edgeTopOpacity,
5583
+ vignette.edgeBottomOpacity
5584
+ );
5585
+ } else {
5586
+ drawVignette(ctx, spec.canvas.width, spec.canvas.height, vignette.intensity, vignette.color);
5587
+ }
5277
5588
  elements.push({
5278
5589
  id: `decorator-vignette-${vignette.index}`,
5279
5590
  kind: "vignette",
package/dist/qa.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { R as RenderMetadata, D as DesignSpec } from './spec.schema-BkbcnVcm.js';
1
+ import { R as RenderMetadata, D as DesignSpec } from './spec.schema-De-IkUjn.js';
2
2
  import 'zod';
3
3
  import '@napi-rs/canvas';
4
4
 
package/dist/qa.js CHANGED
@@ -663,6 +663,27 @@ var drawTextRowSchema = z2.object({
663
663
  defaultColor: colorHexSchema2.default("#FFFFFF"),
664
664
  opacity: z2.number().min(0).max(1).default(1)
665
665
  }).strict();
666
+ var drawStatsBarItemSchema = z2.object({
667
+ value: z2.string().min(1).max(50),
668
+ label: z2.string().min(1).max(100)
669
+ }).strict();
670
+ var drawStatsBarSchema = z2.object({
671
+ type: z2.literal("stats-bar"),
672
+ y: z2.number().describe("Vertical position of the stats bar"),
673
+ items: z2.array(drawStatsBarItemSchema).min(1).max(8),
674
+ separator: z2.enum(["dot", "pipe", "none"]).default("dot"),
675
+ valueColor: colorHexSchema2.default("#FFFFFF"),
676
+ valueFontSize: z2.number().min(8).max(72).default(18),
677
+ valueFontWeight: z2.number().int().min(100).max(900).default(700),
678
+ valueFontFamily: drawFontFamilySchema.default("mono"),
679
+ labelColor: colorHexSchema2.default("#AAAAAA"),
680
+ labelFontSize: z2.number().min(8).max(72).default(14),
681
+ labelFontWeight: z2.number().int().min(100).max(900).default(400),
682
+ labelFontFamily: drawFontFamilySchema.default("body"),
683
+ separatorColor: colorHexSchema2.default("#666666"),
684
+ gap: z2.number().min(0).max(100).default(24),
685
+ opacity: z2.number().min(0).max(1).default(1)
686
+ }).strict();
666
687
  var drawCommandSchema = z2.discriminatedUnion("type", [
667
688
  drawRectSchema,
668
689
  drawCircleSchema,
@@ -674,7 +695,8 @@ var drawCommandSchema = z2.discriminatedUnion("type", [
674
695
  drawBadgeSchema,
675
696
  drawGradientRectSchema,
676
697
  drawGridSchema,
677
- drawTextRowSchema
698
+ drawTextRowSchema,
699
+ drawStatsBarSchema
678
700
  ]);
679
701
  var defaultCanvas = {
680
702
  width: 1200,
@@ -875,6 +897,24 @@ var imageElementSchema = z2.object({
875
897
  fit: z2.enum(["contain", "cover", "fill", "none"]).default("contain"),
876
898
  borderRadius: z2.number().min(0).default(0)
877
899
  }).strict();
900
+ var ringSegmentSchema = z2.object({
901
+ color: colorHexSchema2
902
+ }).strict();
903
+ var ringElementSchema = z2.object({
904
+ type: z2.literal("ring"),
905
+ id: z2.string().min(1).max(120),
906
+ radius: z2.number().min(8).max(512).default(48),
907
+ strokeWidth: z2.number().min(1).max(32).default(2),
908
+ label: z2.string().max(100).optional(),
909
+ labelColor: colorHexSchema2.optional(),
910
+ labelSize: z2.number().min(8).max(48).default(12),
911
+ segments: z2.array(ringSegmentSchema).min(1).max(24).default([{ color: "#4A7BF7" }]),
912
+ glowRadius: z2.number().min(0).max(64).default(0),
913
+ glowColor: colorHexSchema2.optional(),
914
+ showCycleArrows: z2.boolean().default(false),
915
+ fill: colorHexSchema2.optional(),
916
+ fillOpacity: z2.number().min(0).max(1).default(0.05)
917
+ }).strict();
878
918
  var elementSchema = z2.discriminatedUnion("type", [
879
919
  cardElementSchema,
880
920
  flowNodeElementSchema,
@@ -883,7 +923,8 @@ var elementSchema = z2.discriminatedUnion("type", [
883
923
  terminalElementSchema,
884
924
  textElementSchema,
885
925
  shapeElementSchema,
886
- imageElementSchema
926
+ imageElementSchema,
927
+ ringElementSchema
887
928
  ]);
888
929
  var diagramCenterSchema = z2.object({
889
930
  x: z2.number(),
@@ -1004,8 +1045,13 @@ var decoratorSchema = z2.discriminatedUnion("type", [
1004
1045
  }).strict(),
1005
1046
  z2.object({
1006
1047
  type: z2.literal("vignette"),
1048
+ mode: z2.enum(["radial", "edge"]).default("radial"),
1007
1049
  intensity: z2.number().min(0).max(1).default(0.3),
1008
- color: colorHexSchema2.default("#000000")
1050
+ color: colorHexSchema2.default("#000000"),
1051
+ edgeTopHeight: z2.number().min(0).max(200).default(35),
1052
+ edgeBottomHeight: z2.number().min(0).max(200).default(55),
1053
+ edgeTopOpacity: z2.number().min(0).max(1).default(0.3),
1054
+ edgeBottomOpacity: z2.number().min(0).max(1).default(0.4)
1009
1055
  }).strict(),
1010
1056
  z2.object({
1011
1057
  type: z2.literal("gradient-overlay"),
@@ -1,3 +1,3 @@
1
- export { i as DEFAULT_GENERATOR_VERSION, U as IterationMeta, W as LayoutSnapshot, a as Rect, Z as RenderDesignOptions, R as RenderMetadata, _ as RenderResult, d as RenderedElement, a5 as WrittenArtifacts, a8 as computeSpecHash, ar as inferSidecarPath, au as renderDesign, aw as writeRenderArtifacts } from './spec.schema-BkbcnVcm.js';
1
+ export { i as DEFAULT_GENERATOR_VERSION, U as IterationMeta, W as LayoutSnapshot, a as Rect, Z as RenderDesignOptions, R as RenderMetadata, _ as RenderResult, d as RenderedElement, a5 as WrittenArtifacts, a8 as computeSpecHash, ar as inferSidecarPath, au as renderDesign, aw as writeRenderArtifacts } from './spec.schema-De-IkUjn.js';
2
2
  import 'zod';
3
3
  import '@napi-rs/canvas';