circuit-to-svg 0.0.280 → 0.0.282

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
@@ -1582,7 +1582,8 @@ import { applyToPoint as applyToPoint12 } from "transformation-matrix";
1582
1582
  function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
1583
1583
  const { transform, colorMap: colorMap2, showSolderMask } = ctx;
1584
1584
  const [x, y] = applyToPoint12(transform, [hole.x, hole.y]);
1585
- const copperLayer = Array.isArray(hole.layers) && hole.layers[0] || hole.layer || "top";
1585
+ const layer = Array.isArray(hole.layers) && hole.layers[0] || hole.layer || "top";
1586
+ const maskLayer = layer;
1586
1587
  const isCoveredWithSolderMask = Boolean(hole.is_covered_with_solder_mask);
1587
1588
  const soldermaskMargin = (hole.soldermask_margin ?? 0) * Math.abs(transform.a);
1588
1589
  const shouldShowSolderMask = showSolderMask && isCoveredWithSolderMask && soldermaskMargin !== 0;
@@ -1620,7 +1621,7 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
1620
1621
  d: createPillPath(scaledOuterWidth, scaledOuterHeight),
1621
1622
  transform: outerTransform,
1622
1623
  "data-type": "pcb_plated_hole",
1623
- "data-pcb-layer": copperLayer
1624
+ "data-pcb-layer": layer
1624
1625
  },
1625
1626
  value: "",
1626
1627
  children: []
@@ -1656,7 +1657,7 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
1656
1657
  d: createPillPath(scaledOuterWidth, scaledOuterHeight),
1657
1658
  transform: outerTransform,
1658
1659
  "data-type": "pcb_plated_hole",
1659
- "data-pcb-layer": copperLayer
1660
+ "data-pcb-layer": layer
1660
1661
  },
1661
1662
  value: "",
1662
1663
  children: []
@@ -1670,7 +1671,8 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
1670
1671
  fill: colorMap2.copper.top,
1671
1672
  d: createPillPath(maskWidth, maskHeight),
1672
1673
  transform: outerTransform,
1673
- "data-type": "pcb_soldermask"
1674
+ "data-type": "pcb_soldermask",
1675
+ "data-pcb-layer": maskLayer
1674
1676
  },
1675
1677
  value: "",
1676
1678
  children: []
@@ -1689,7 +1691,7 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
1689
1691
  d: createPillPath(maskWidth, maskHeight),
1690
1692
  transform: outerTransform,
1691
1693
  "data-type": "pcb_soldermask_opening",
1692
- "data-pcb-layer": "soldermask-top"
1694
+ "data-pcb-layer": maskLayer
1693
1695
  },
1694
1696
  value: "",
1695
1697
  children: []
@@ -1730,7 +1732,7 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
1730
1732
  ry: (scaledOuterHeight / 2).toString(),
1731
1733
  transform: transformStr,
1732
1734
  "data-type": "pcb_plated_hole",
1733
- "data-pcb-layer": copperLayer
1735
+ "data-pcb-layer": layer
1734
1736
  },
1735
1737
  value: "",
1736
1738
  children: []
@@ -1785,7 +1787,7 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
1785
1787
  cy: y.toString(),
1786
1788
  r: outerRadius.toString(),
1787
1789
  "data-type": "pcb_plated_hole",
1788
- "data-pcb-layer": copperLayer
1790
+ "data-pcb-layer": layer
1789
1791
  },
1790
1792
  value: "",
1791
1793
  children: []
@@ -1821,7 +1823,7 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
1821
1823
  cy: y.toString(),
1822
1824
  r: outerRadius.toString(),
1823
1825
  "data-type": "pcb_plated_hole",
1824
- "data-pcb-layer": copperLayer
1826
+ "data-pcb-layer": layer
1825
1827
  },
1826
1828
  value: "",
1827
1829
  children: []
@@ -1836,7 +1838,8 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
1836
1838
  cx: x.toString(),
1837
1839
  cy: y.toString(),
1838
1840
  r: maskRadius.toString(),
1839
- "data-type": "pcb_soldermask"
1841
+ "data-type": "pcb_soldermask",
1842
+ "data-pcb-layer": maskLayer
1840
1843
  },
1841
1844
  value: "",
1842
1845
  children: []
@@ -1856,7 +1859,7 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
1856
1859
  cy: y.toString(),
1857
1860
  r: maskRadius.toString(),
1858
1861
  "data-type": "pcb_soldermask_opening",
1859
- "data-pcb-layer": "soldermask-top"
1862
+ "data-pcb-layer": maskLayer
1860
1863
  },
1861
1864
  value: "",
1862
1865
  children: []
@@ -1904,7 +1907,7 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
1904
1907
  ry: scaledRectBorderRadius.toString()
1905
1908
  } : {},
1906
1909
  "data-type": "pcb_plated_hole",
1907
- "data-pcb-layer": copperLayer
1910
+ "data-pcb-layer": layer
1908
1911
  },
1909
1912
  value: "",
1910
1913
  children: []
@@ -1948,7 +1951,7 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
1948
1951
  ry: scaledRectBorderRadius.toString()
1949
1952
  } : {},
1950
1953
  "data-type": "pcb_plated_hole",
1951
- "data-pcb-layer": copperLayer
1954
+ "data-pcb-layer": layer
1952
1955
  },
1953
1956
  value: "",
1954
1957
  children: []
@@ -1968,7 +1971,8 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
1968
1971
  rx: maskBorderRadius.toString(),
1969
1972
  ry: maskBorderRadius.toString()
1970
1973
  } : {},
1971
- "data-type": "pcb_soldermask"
1974
+ "data-type": "pcb_soldermask",
1975
+ "data-pcb-layer": maskLayer
1972
1976
  },
1973
1977
  value: "",
1974
1978
  children: []
@@ -1993,7 +1997,7 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
1993
1997
  ry: maskBorderRadius.toString()
1994
1998
  } : {},
1995
1999
  "data-type": "pcb_soldermask_opening",
1996
- "data-pcb-layer": "soldermask-top"
2000
+ "data-pcb-layer": maskLayer
1997
2001
  },
1998
2002
  value: "",
1999
2003
  children: []
@@ -2045,7 +2049,7 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
2045
2049
  ry: scaledRectBorderRadius.toString()
2046
2050
  } : {},
2047
2051
  "data-type": "pcb_plated_hole",
2048
- "data-pcb-layer": copperLayer
2052
+ "data-pcb-layer": layer
2049
2053
  },
2050
2054
  value: "",
2051
2055
  children: []
@@ -2092,7 +2096,7 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
2092
2096
  ry: scaledRectBorderRadius.toString()
2093
2097
  } : {},
2094
2098
  "data-type": "pcb_plated_hole",
2095
- "data-pcb-layer": copperLayer
2099
+ "data-pcb-layer": layer
2096
2100
  },
2097
2101
  value: "",
2098
2102
  children: []
@@ -2112,7 +2116,8 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
2112
2116
  rx: maskBorderRadius.toString(),
2113
2117
  ry: maskBorderRadius.toString()
2114
2118
  } : {},
2115
- "data-type": "pcb_soldermask"
2119
+ "data-type": "pcb_soldermask",
2120
+ "data-pcb-layer": maskLayer
2116
2121
  },
2117
2122
  value: "",
2118
2123
  children: []
@@ -2137,7 +2142,7 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
2137
2142
  ry: maskBorderRadius.toString()
2138
2143
  } : {},
2139
2144
  "data-type": "pcb_soldermask_opening",
2140
- "data-pcb-layer": "soldermask-top"
2145
+ "data-pcb-layer": maskLayer
2141
2146
  },
2142
2147
  value: "",
2143
2148
  children: []
@@ -2189,7 +2194,7 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
2189
2194
  ry: scaledRectBorderRadius.toString()
2190
2195
  } : {},
2191
2196
  "data-type": "pcb_plated_hole",
2192
- "data-pcb-layer": copperLayer
2197
+ "data-pcb-layer": layer
2193
2198
  },
2194
2199
  value: "",
2195
2200
  children: []
@@ -2237,7 +2242,7 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
2237
2242
  ry: scaledRectBorderRadius.toString()
2238
2243
  } : {},
2239
2244
  "data-type": "pcb_plated_hole",
2240
- "data-pcb-layer": copperLayer
2245
+ "data-pcb-layer": layer
2241
2246
  },
2242
2247
  value: "",
2243
2248
  children: []
@@ -2258,7 +2263,8 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
2258
2263
  rx: maskBorderRadius.toString(),
2259
2264
  ry: maskBorderRadius.toString()
2260
2265
  } : {},
2261
- "data-type": "pcb_soldermask"
2266
+ "data-type": "pcb_soldermask",
2267
+ "data-pcb-layer": maskLayer
2262
2268
  },
2263
2269
  value: "",
2264
2270
  children: []
@@ -2283,7 +2289,8 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
2283
2289
  rx: maskBorderRadius.toString(),
2284
2290
  ry: maskBorderRadius.toString()
2285
2291
  } : {},
2286
- "data-type": "pcb_soldermask"
2292
+ "data-type": "pcb_soldermask",
2293
+ "data-pcb-layer": maskLayer
2287
2294
  },
2288
2295
  value: "",
2289
2296
  children: []
@@ -2408,7 +2415,7 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
2408
2415
  fill: colorMap2.copper.top,
2409
2416
  points: padPointsString,
2410
2417
  "data-type": "pcb_plated_hole",
2411
- "data-pcb-layer": copperLayer
2418
+ "data-pcb-layer": layer
2412
2419
  },
2413
2420
  value: "",
2414
2421
  children: []
@@ -2838,7 +2845,11 @@ var DEFAULT_PCB_COLOR_MAP = {
2838
2845
  },
2839
2846
  soldermask: {
2840
2847
  top: "rgb(12, 55, 33)",
2841
- bottom: "rgb(52, 87, 136)"
2848
+ bottom: "rgb(12, 55, 33)"
2849
+ },
2850
+ soldermaskOverCopper: {
2851
+ top: "rgb(52, 135, 73)",
2852
+ bottom: "rgb(52, 135, 73)"
2842
2853
  },
2843
2854
  substrate: "rgb(201, 162, 110)",
2844
2855
  // FR4 substrate color (tan/beige)
@@ -2886,6 +2897,7 @@ function createSvgObjectsFromPcbTrace(trace, ctx) {
2886
2897
  const layer = "layer" in start ? start.layer : "layer" in end ? end.layer : null;
2887
2898
  if (!layer) continue;
2888
2899
  if (layerFilter && layer !== layerFilter) continue;
2900
+ const maskLayer = layer;
2889
2901
  const copperColor = layerNameToColor(layer, colorMap2);
2890
2902
  const maskColor = colorMap2.soldermaskWithCopperUnderneath[layer];
2891
2903
  const traceWidth = "width" in start ? start.width : "width" in end ? end.width : null;
@@ -2941,7 +2953,7 @@ function createSvgObjectsFromSmtPad(pad, ctx) {
2941
2953
  const { transform, layer: layerFilter, colorMap: colorMap2, showSolderMask } = ctx;
2942
2954
  if (layerFilter && pad.layer !== layerFilter) return [];
2943
2955
  const isCoveredWithSolderMask = Boolean(pad?.is_covered_with_solder_mask);
2944
- const shouldshowSolderMask = showSolderMask && isCoveredWithSolderMask;
2956
+ const shouldShowSolderMask = showSolderMask && isCoveredWithSolderMask;
2945
2957
  const soldermaskWithCopperUnderneathColor = colorMap2.soldermaskWithCopperUnderneath[pad.layer] ?? colorMap2.soldermaskWithCopperUnderneath.top;
2946
2958
  const soldermaskMargin = (pad.soldermask_margin ?? 0) * Math.abs(transform.a);
2947
2959
  if (pad.shape === "rect" || pad.shape === "rotated_rect") {
@@ -2972,7 +2984,7 @@ function createSvgObjectsFromSmtPad(pad, ctx) {
2972
2984
  } : {}
2973
2985
  }
2974
2986
  };
2975
- if (!shouldshowSolderMask) {
2987
+ if (!shouldShowSolderMask) {
2976
2988
  return [padElement2];
2977
2989
  }
2978
2990
  const maskWidth2 = width + 2 * soldermaskMargin;
@@ -3065,7 +3077,7 @@ function createSvgObjectsFromSmtPad(pad, ctx) {
3065
3077
  ry: maskBorderRadius2.toString()
3066
3078
  } : {},
3067
3079
  "data-type": "pcb_soldermask_opening",
3068
- "data-pcb-layer": `soldermask-${pad.layer}`
3080
+ "data-pcb-layer": pad.layer
3069
3081
  }
3070
3082
  };
3071
3083
  return [substrateElement2, padElement2];
@@ -3090,7 +3102,7 @@ function createSvgObjectsFromSmtPad(pad, ctx) {
3090
3102
  } : {}
3091
3103
  }
3092
3104
  };
3093
- if (!shouldshowSolderMask) {
3105
+ if (!shouldShowSolderMask) {
3094
3106
  return [padElement];
3095
3107
  }
3096
3108
  const maskWidth = width + 2 * soldermaskMargin;
@@ -3179,35 +3191,40 @@ function createSvgObjectsFromSmtPad(pad, ctx) {
3179
3191
  ry: maskBorderRadius.toString()
3180
3192
  } : {},
3181
3193
  "data-type": "pcb_soldermask_opening",
3182
- "data-pcb-layer": `soldermask-${pad.layer}`
3194
+ "data-pcb-layer": pad.layer
3183
3195
  }
3184
3196
  };
3185
3197
  return [substrateElement, padElement];
3186
3198
  }
3187
- if (pad.shape === "pill") {
3199
+ if (pad.shape === "pill" || pad.shape === "rotated_pill") {
3200
+ const isRotated = pad.shape === "rotated_pill";
3188
3201
  const width = pad.width * Math.abs(transform.a);
3189
3202
  const height = pad.height * Math.abs(transform.d);
3190
3203
  const radius = pad.radius * Math.abs(transform.a);
3191
3204
  const [x, y] = applyToPoint20(transform, [pad.x, pad.y]);
3205
+ const baseAttributes = {
3206
+ class: "pcb-pad",
3207
+ fill: layerNameToColor(pad.layer, colorMap2),
3208
+ x: isRotated ? (-width / 2).toString() : (x - width / 2).toString(),
3209
+ y: isRotated ? (-height / 2).toString() : (y - height / 2).toString(),
3210
+ width: width.toString(),
3211
+ height: height.toString(),
3212
+ rx: radius.toString(),
3213
+ ry: radius.toString(),
3214
+ "data-type": "pcb_smtpad",
3215
+ "data-pcb-layer": pad.layer,
3216
+ ...isRotated ? {
3217
+ transform: `translate(${x} ${y}) rotate(${-(pad.ccw_rotation ?? 0)})`
3218
+ } : {}
3219
+ };
3192
3220
  const padElement = {
3193
3221
  name: "rect",
3194
3222
  type: "element",
3195
3223
  value: "",
3196
3224
  children: [],
3197
- attributes: {
3198
- class: "pcb-pad",
3199
- fill: layerNameToColor(pad.layer, colorMap2),
3200
- x: (x - width / 2).toString(),
3201
- y: (y - height / 2).toString(),
3202
- width: width.toString(),
3203
- height: height.toString(),
3204
- rx: radius.toString(),
3205
- ry: radius.toString(),
3206
- "data-type": "pcb_smtpad",
3207
- "data-pcb-layer": pad.layer
3208
- }
3225
+ attributes: baseAttributes
3209
3226
  };
3210
- if (!shouldshowSolderMask) {
3227
+ if (!shouldShowSolderMask) {
3211
3228
  return [padElement];
3212
3229
  }
3213
3230
  const maskWidth = width + 2 * soldermaskMargin;
@@ -3232,23 +3249,25 @@ function createSvgObjectsFromSmtPad(pad, ctx) {
3232
3249
  "data-pcb-layer": pad.layer
3233
3250
  }
3234
3251
  };
3252
+ const exposedAttributes = {
3253
+ class: "pcb-pad-exposed",
3254
+ fill: layerNameToColor(pad.layer, colorMap2),
3255
+ x: isRotated ? (-maskWidth / 2).toString() : (x - maskWidth / 2).toString(),
3256
+ y: isRotated ? (-maskHeight / 2).toString() : (y - maskHeight / 2).toString(),
3257
+ width: maskWidth.toString(),
3258
+ height: maskHeight.toString(),
3259
+ rx: maskRadius.toString(),
3260
+ ry: maskRadius.toString(),
3261
+ "data-type": "pcb_soldermask",
3262
+ "data-pcb-layer": pad.layer,
3263
+ ...isRotated && pad.ccw_rotation ? { transform: `translate(${x} ${y}) rotate(${-pad.ccw_rotation})` } : {}
3264
+ };
3235
3265
  const exposedOpeningElement = {
3236
3266
  name: "rect",
3237
3267
  type: "element",
3238
3268
  value: "",
3239
3269
  children: [],
3240
- attributes: {
3241
- class: "pcb-pad-exposed",
3242
- fill: layerNameToColor(pad.layer, colorMap2),
3243
- x: (x - maskWidth / 2).toString(),
3244
- y: (y - maskHeight / 2).toString(),
3245
- width: maskWidth.toString(),
3246
- height: maskHeight.toString(),
3247
- rx: maskRadius.toString(),
3248
- ry: maskRadius.toString(),
3249
- "data-type": "pcb_soldermask",
3250
- "data-pcb-layer": pad.layer
3251
- }
3270
+ attributes: exposedAttributes
3252
3271
  };
3253
3272
  return [coveredPadElement, exposedOpeningElement];
3254
3273
  }
@@ -3273,23 +3292,25 @@ function createSvgObjectsFromSmtPad(pad, ctx) {
3273
3292
  };
3274
3293
  return [coveredPadElement];
3275
3294
  }
3295
+ const substrateAttributes = {
3296
+ class: "pcb-soldermask-cutout",
3297
+ fill: colorMap2.substrate,
3298
+ x: isRotated ? (-maskWidth / 2).toString() : (x - maskWidth / 2).toString(),
3299
+ y: isRotated ? (-maskHeight / 2).toString() : (y - maskHeight / 2).toString(),
3300
+ width: maskWidth.toString(),
3301
+ height: maskHeight.toString(),
3302
+ rx: maskRadius.toString(),
3303
+ ry: maskRadius.toString(),
3304
+ "data-type": "pcb_soldermask_opening",
3305
+ "data-pcb-layer": pad.layer,
3306
+ ...isRotated && pad.ccw_rotation ? { transform: `translate(${x} ${y}) rotate(${-pad.ccw_rotation})` } : {}
3307
+ };
3276
3308
  const substrateElement = {
3277
3309
  name: "rect",
3278
3310
  type: "element",
3279
3311
  value: "",
3280
3312
  children: [],
3281
- attributes: {
3282
- class: "pcb-soldermask-cutout",
3283
- fill: colorMap2.substrate,
3284
- x: (x - maskWidth / 2).toString(),
3285
- y: (y - maskHeight / 2).toString(),
3286
- width: maskWidth.toString(),
3287
- height: maskHeight.toString(),
3288
- rx: maskRadius.toString(),
3289
- ry: maskRadius.toString(),
3290
- "data-type": "pcb_soldermask_opening",
3291
- "data-pcb-layer": `soldermask-${pad.layer}`
3292
- }
3313
+ attributes: substrateAttributes
3293
3314
  };
3294
3315
  return [substrateElement, padElement];
3295
3316
  }
@@ -3311,7 +3332,7 @@ function createSvgObjectsFromSmtPad(pad, ctx) {
3311
3332
  "data-pcb-layer": pad.layer
3312
3333
  }
3313
3334
  };
3314
- if (!shouldshowSolderMask) {
3335
+ if (!shouldShowSolderMask) {
3315
3336
  return [padElement];
3316
3337
  }
3317
3338
  const maskRadius = radius + soldermaskMargin;
@@ -3378,7 +3399,7 @@ function createSvgObjectsFromSmtPad(pad, ctx) {
3378
3399
  cy: y.toString(),
3379
3400
  r: maskRadius.toString(),
3380
3401
  "data-type": "pcb_soldermask_opening",
3381
- "data-pcb-layer": `soldermask-${pad.layer}`
3402
+ "data-pcb-layer": pad.layer
3382
3403
  }
3383
3404
  };
3384
3405
  return [substrateElement, padElement];
@@ -3400,7 +3421,7 @@ function createSvgObjectsFromSmtPad(pad, ctx) {
3400
3421
  "data-pcb-layer": pad.layer
3401
3422
  }
3402
3423
  };
3403
- if (!shouldshowSolderMask) {
3424
+ if (!shouldShowSolderMask) {
3404
3425
  return [padElement];
3405
3426
  }
3406
3427
  let maskPoints = points;
@@ -3475,7 +3496,7 @@ function createSvgObjectsFromSmtPad(pad, ctx) {
3475
3496
  fill: colorMap2.substrate,
3476
3497
  points: maskPoints.map((p) => p.join(",")).join(" "),
3477
3498
  "data-type": "pcb_soldermask_opening",
3478
- "data-pcb-layer": `soldermask-${pad.layer}`
3499
+ "data-pcb-layer": pad.layer
3479
3500
  }
3480
3501
  };
3481
3502
  return [substrateElement, padElement];
@@ -3518,6 +3539,8 @@ function createSvgObjectsFromPcbBoard(pcbBoard, ctx) {
3518
3539
  path += " Z";
3519
3540
  const svgObjects = [];
3520
3541
  if (showSolderMask) {
3542
+ const layer = ctx.layer ?? "top";
3543
+ const maskLayer = layer === "bottom" ? "soldermask-bottom" : "soldermask-top";
3521
3544
  svgObjects.push({
3522
3545
  name: "path",
3523
3546
  type: "element",
@@ -3530,7 +3553,7 @@ function createSvgObjectsFromPcbBoard(pcbBoard, ctx) {
3530
3553
  "fill-opacity": "0.8",
3531
3554
  stroke: "none",
3532
3555
  "data-type": "pcb_soldermask",
3533
- "data-pcb-layer": "soldermask-top"
3556
+ "data-pcb-layer": maskLayer
3534
3557
  }
3535
3558
  });
3536
3559
  }
@@ -3579,7 +3602,7 @@ function createSvgObjectsFromPcbPanel(pcbPanel, ctx) {
3579
3602
  ]);
3580
3603
  const path = `M ${topLeft[0]} ${topLeft[1]} L ${topRight[0]} ${topRight[1]} L ${bottomRight[0]} ${bottomRight[1]} L ${bottomLeft[0]} ${bottomLeft[1]} Z`;
3581
3604
  const isCoveredWithSolderMask = pcbPanel.covered_with_solder_mask !== false;
3582
- const shouldshowSolderMask = Boolean(
3605
+ const shouldShowSolderMask = Boolean(
3583
3606
  showSolderMask && isCoveredWithSolderMask
3584
3607
  );
3585
3608
  return [
@@ -3654,6 +3677,7 @@ function createSvgObjectsFromPcbVia(hole, ctx) {
3654
3677
  import { applyToPoint as applyToPoint24 } from "transformation-matrix";
3655
3678
  function createSvgObjectsFromPcbHole(hole, ctx) {
3656
3679
  const { transform, colorMap: colorMap2, showSolderMask } = ctx;
3680
+ const layer = ctx.layer ?? "top";
3657
3681
  const [x, y] = applyToPoint24(transform, [hole.x, hole.y]);
3658
3682
  const isCoveredWithSolderMask = Boolean(hole.is_covered_with_solder_mask);
3659
3683
  const soldermaskMargin = (hole.soldermask_margin ?? 0) * Math.abs(transform.a);
@@ -3709,7 +3733,8 @@ function createSvgObjectsFromPcbHole(hole, ctx) {
3709
3733
  cx: x.toString(),
3710
3734
  cy: y.toString(),
3711
3735
  r: maskRadius.toString(),
3712
- "data-type": "pcb_soldermask"
3736
+ "data-type": "pcb_soldermask",
3737
+ "data-pcb-layer": "drill"
3713
3738
  }
3714
3739
  };
3715
3740
  return [coveredElement, exposedElement];
@@ -3726,7 +3751,7 @@ function createSvgObjectsFromPcbHole(hole, ctx) {
3726
3751
  cy: y.toString(),
3727
3752
  r: maskRadius.toString(),
3728
3753
  "data-type": "pcb_soldermask_opening",
3729
- "data-pcb-layer": "soldermask-top"
3754
+ "data-pcb-layer": layer
3730
3755
  }
3731
3756
  };
3732
3757
  return [substrateElement2, holeElement2];
@@ -3780,7 +3805,8 @@ function createSvgObjectsFromPcbHole(hole, ctx) {
3780
3805
  y: (y - maskDiameter / 2).toString(),
3781
3806
  width: maskDiameter.toString(),
3782
3807
  height: maskDiameter.toString(),
3783
- "data-type": "pcb_soldermask"
3808
+ "data-type": "pcb_soldermask",
3809
+ "data-pcb-layer": "drill"
3784
3810
  }
3785
3811
  };
3786
3812
  return [coveredElement, exposedElement];
@@ -3798,7 +3824,7 @@ function createSvgObjectsFromPcbHole(hole, ctx) {
3798
3824
  width: maskDiameter.toString(),
3799
3825
  height: maskDiameter.toString(),
3800
3826
  "data-type": "pcb_soldermask_opening",
3801
- "data-pcb-layer": "soldermask-top"
3827
+ "data-pcb-layer": layer
3802
3828
  }
3803
3829
  };
3804
3830
  return [substrateElement, holeElement];
@@ -3858,7 +3884,8 @@ function createSvgObjectsFromPcbHole(hole, ctx) {
3858
3884
  cy: y.toString(),
3859
3885
  rx: maskRx.toString(),
3860
3886
  ry: maskRy.toString(),
3861
- "data-type": "pcb_soldermask"
3887
+ "data-type": "pcb_soldermask",
3888
+ "data-pcb-layer": "drill"
3862
3889
  }
3863
3890
  };
3864
3891
  return [coveredElement, exposedElement];
@@ -3876,7 +3903,7 @@ function createSvgObjectsFromPcbHole(hole, ctx) {
3876
3903
  rx: maskRx.toString(),
3877
3904
  ry: maskRy.toString(),
3878
3905
  "data-type": "pcb_soldermask_opening",
3879
- "data-pcb-layer": "soldermask-top"
3906
+ "data-pcb-layer": layer
3880
3907
  }
3881
3908
  };
3882
3909
  return [substrateElement, holeElement];
@@ -3934,7 +3961,8 @@ function createSvgObjectsFromPcbHole(hole, ctx) {
3934
3961
  y: (y - maskHeight / 2).toString(),
3935
3962
  width: maskWidth.toString(),
3936
3963
  height: maskHeight.toString(),
3937
- "data-type": "pcb_soldermask"
3964
+ "data-type": "pcb_soldermask",
3965
+ "data-pcb-layer": "drill"
3938
3966
  }
3939
3967
  };
3940
3968
  return [coveredElement, exposedElement];
@@ -3952,7 +3980,7 @@ function createSvgObjectsFromPcbHole(hole, ctx) {
3952
3980
  width: maskWidth.toString(),
3953
3981
  height: maskHeight.toString(),
3954
3982
  "data-type": "pcb_soldermask_opening",
3955
- "data-pcb-layer": "soldermask-top"
3983
+ "data-pcb-layer": layer
3956
3984
  }
3957
3985
  };
3958
3986
  return [substrateElement, holeElement];
@@ -4025,7 +4053,8 @@ function createSvgObjectsFromPcbHole(hole, ctx) {
4025
4053
  class: "pcb-hole-exposed",
4026
4054
  fill: colorMap2.drill,
4027
4055
  d: maskPathD,
4028
- "data-type": "pcb_soldermask"
4056
+ "data-type": "pcb_soldermask",
4057
+ "data-pcb-layer": "drill"
4029
4058
  }
4030
4059
  };
4031
4060
  return [coveredElement, exposedElement];
@@ -4040,7 +4069,7 @@ function createSvgObjectsFromPcbHole(hole, ctx) {
4040
4069
  fill: colorMap2.substrate,
4041
4070
  d: maskPathD,
4042
4071
  "data-type": "pcb_soldermask_opening",
4043
- "data-pcb-layer": "soldermask-top"
4072
+ "data-pcb-layer": layer
4044
4073
  }
4045
4074
  };
4046
4075
  return [substrateElement, holeElement];
@@ -4117,7 +4146,8 @@ function createSvgObjectsFromPcbHole(hole, ctx) {
4117
4146
  fill: colorMap2.drill,
4118
4147
  d: maskPathD,
4119
4148
  transform: `translate(${x} ${y}) rotate(${-rotation})`,
4120
- "data-type": "pcb_soldermask"
4149
+ "data-type": "pcb_soldermask",
4150
+ "data-pcb-layer": "drill"
4121
4151
  }
4122
4152
  };
4123
4153
  return [coveredElement, exposedElement];
@@ -4132,7 +4162,7 @@ function createSvgObjectsFromPcbHole(hole, ctx) {
4132
4162
  fill: colorMap2.substrate,
4133
4163
  d: maskPathD,
4134
4164
  "data-type": "pcb_soldermask_opening",
4135
- "data-pcb-layer": "soldermask-top"
4165
+ "data-pcb-layer": layer
4136
4166
  }
4137
4167
  };
4138
4168
  return [substrateElement, holeElement];
@@ -4397,40 +4427,118 @@ function ringToPathD(vertices, transform) {
4397
4427
  return d;
4398
4428
  }
4399
4429
 
4430
+ // lib/pcb/svg-object-fns/create-soldermask-cutout-element.ts
4431
+ function createSoldermaskCutoutElement({
4432
+ elementType,
4433
+ shapeAttributes,
4434
+ layer,
4435
+ colorMap: colorMap2,
4436
+ additionalAttributes
4437
+ }) {
4438
+ const baseAttributes = {
4439
+ class: "pcb-soldermask-cutout",
4440
+ fill: colorMap2.substrate,
4441
+ "data-type": "pcb_soldermask_opening",
4442
+ "data-pcb-layer": layer,
4443
+ ...shapeAttributes,
4444
+ ...additionalAttributes
4445
+ };
4446
+ return {
4447
+ name: elementType,
4448
+ type: "element",
4449
+ value: "",
4450
+ children: [],
4451
+ attributes: baseAttributes
4452
+ };
4453
+ }
4454
+
4455
+ // lib/pcb/svg-object-fns/create-soldermask-overlay-element.ts
4456
+ function createSoldermaskOverlayElement({
4457
+ elementType,
4458
+ shapeAttributes,
4459
+ layer,
4460
+ fillColor,
4461
+ fillOpacity,
4462
+ className,
4463
+ additionalAttributes
4464
+ }) {
4465
+ const baseAttributes = {
4466
+ class: className,
4467
+ fill: fillColor,
4468
+ "fill-opacity": fillOpacity,
4469
+ "data-type": "pcb_soldermask",
4470
+ "data-pcb-layer": layer,
4471
+ ...shapeAttributes,
4472
+ ...additionalAttributes
4473
+ };
4474
+ return {
4475
+ name: elementType,
4476
+ type: "element",
4477
+ value: "",
4478
+ children: [],
4479
+ attributes: baseAttributes
4480
+ };
4481
+ }
4482
+
4400
4483
  // lib/pcb/svg-object-fns/create-svg-objects-from-pcb-copper-pour.ts
4401
4484
  function createSvgObjectsFromPcbCopperPour(pour, ctx) {
4402
- const { transform, layer: layerFilter, colorMap: colorMap2 } = ctx;
4485
+ const { transform, layer: layerFilter, colorMap: colorMap2, showSolderMask } = ctx;
4403
4486
  const { layer } = pour;
4404
4487
  if (layerFilter && layer !== layerFilter) return [];
4405
4488
  const color = layerNameToColor(layer, colorMap2);
4406
4489
  const opacity = "0.5";
4490
+ const isCoveredWithSolderMask = pour.covered_with_solder_mask !== false;
4491
+ const maskOverlayColor = layer === "bottom" ? colorMap2.soldermaskOverCopper.bottom : colorMap2.soldermaskOverCopper.top;
4492
+ const maskOverlayOpacity = "0.9";
4407
4493
  if (pour.shape === "rect") {
4408
4494
  const [cx, cy] = applyToPoint28(transform, [pour.center.x, pour.center.y]);
4409
4495
  const scaledWidth = pour.width * Math.abs(transform.a);
4410
4496
  const scaledHeight = pour.height * Math.abs(transform.d);
4411
4497
  const svgRotation = -(pour.rotation ?? 0);
4412
- return [
4413
- {
4414
- name: "rect",
4415
- type: "element",
4416
- attributes: {
4417
- class: "pcb-copper-pour pcb-copper-pour-rect",
4418
- x: (-scaledWidth / 2).toString(),
4419
- y: (-scaledHeight / 2).toString(),
4420
- width: scaledWidth.toString(),
4421
- height: scaledHeight.toString(),
4422
- fill: color,
4423
- "fill-opacity": opacity,
4424
- transform: matrixToString7(
4425
- compose4(translate4(cx, cy), rotate4(svgRotation * Math.PI / 180))
4426
- ),
4427
- "data-type": "pcb_copper_pour",
4428
- "data-pcb-layer": layer
4429
- },
4430
- children: [],
4431
- value: ""
4498
+ const rectAttributes = {
4499
+ x: (-scaledWidth / 2).toString(),
4500
+ y: (-scaledHeight / 2).toString(),
4501
+ width: scaledWidth.toString(),
4502
+ height: scaledHeight.toString(),
4503
+ transform: matrixToString7(
4504
+ compose4(translate4(cx, cy), rotate4(svgRotation * Math.PI / 180))
4505
+ )
4506
+ };
4507
+ const copperRect = {
4508
+ name: "rect",
4509
+ type: "element",
4510
+ value: "",
4511
+ children: [],
4512
+ attributes: {
4513
+ class: "pcb-copper-pour pcb-copper-pour-rect",
4514
+ ...rectAttributes,
4515
+ fill: color,
4516
+ "fill-opacity": opacity,
4517
+ "data-type": "pcb_copper_pour",
4518
+ "data-pcb-layer": layer
4432
4519
  }
4433
- ];
4520
+ };
4521
+ const maskRect = showSolderMask ? isCoveredWithSolderMask ? createSoldermaskOverlayElement({
4522
+ elementType: "rect",
4523
+ shapeAttributes: rectAttributes,
4524
+ layer,
4525
+ fillColor: maskOverlayColor,
4526
+ fillOpacity: maskOverlayOpacity,
4527
+ className: "pcb-soldermask-covered-pour"
4528
+ }) : createSoldermaskCutoutElement({
4529
+ elementType: "rect",
4530
+ shapeAttributes: rectAttributes,
4531
+ layer,
4532
+ colorMap: colorMap2
4533
+ }) : null;
4534
+ if (!maskRect) {
4535
+ return [copperRect];
4536
+ }
4537
+ const isSubstrateOnly = !isCoveredWithSolderMask && pour.pcb_copper_pour_id?.includes("substrate_only");
4538
+ if (isSubstrateOnly) {
4539
+ return [maskRect];
4540
+ }
4541
+ return [copperRect, maskRect];
4434
4542
  }
4435
4543
  if (pour.shape === "polygon") {
4436
4544
  if (!pour.points || pour.points.length === 0) return [];
@@ -4438,22 +4546,41 @@ function createSvgObjectsFromPcbCopperPour(pour, ctx) {
4438
4546
  (p) => applyToPoint28(transform, [p.x, p.y])
4439
4547
  );
4440
4548
  const pointsString = transformedPoints.map((p) => `${p[0]},${p[1]}`).join(" ");
4441
- return [
4442
- {
4443
- name: "polygon",
4444
- type: "element",
4445
- attributes: {
4446
- class: "pcb-copper-pour pcb-copper-pour-polygon",
4447
- points: pointsString,
4448
- fill: color,
4449
- "fill-opacity": opacity,
4450
- "data-type": "pcb_copper_pour",
4451
- "data-pcb-layer": layer
4452
- },
4453
- children: [],
4454
- value: ""
4549
+ const copperPolygon = {
4550
+ name: "polygon",
4551
+ type: "element",
4552
+ value: "",
4553
+ children: [],
4554
+ attributes: {
4555
+ class: "pcb-copper-pour pcb-copper-pour-polygon",
4556
+ points: pointsString,
4557
+ fill: color,
4558
+ "fill-opacity": opacity,
4559
+ "data-type": "pcb_copper_pour",
4560
+ "data-pcb-layer": layer
4455
4561
  }
4456
- ];
4562
+ };
4563
+ const maskPolygon = showSolderMask ? isCoveredWithSolderMask ? createSoldermaskOverlayElement({
4564
+ elementType: "polygon",
4565
+ shapeAttributes: { points: pointsString },
4566
+ layer,
4567
+ fillColor: maskOverlayColor,
4568
+ fillOpacity: maskOverlayOpacity,
4569
+ className: "pcb-soldermask-covered-pour"
4570
+ }) : createSoldermaskCutoutElement({
4571
+ elementType: "polygon",
4572
+ shapeAttributes: { points: pointsString },
4573
+ layer,
4574
+ colorMap: colorMap2
4575
+ }) : null;
4576
+ if (!maskPolygon) {
4577
+ return [copperPolygon];
4578
+ }
4579
+ const isSubstrateOnly = !isCoveredWithSolderMask && pour.pcb_copper_pour_id?.includes("substrate_only");
4580
+ if (isSubstrateOnly) {
4581
+ return [maskPolygon];
4582
+ }
4583
+ return [copperPolygon, maskPolygon];
4457
4584
  }
4458
4585
  if (pour.shape === "brep") {
4459
4586
  const { brep_shape } = pour;
@@ -4461,23 +4588,42 @@ function createSvgObjectsFromPcbCopperPour(pour, ctx) {
4461
4588
  for (const inner_ring of brep_shape.inner_rings ?? []) {
4462
4589
  d += ` ${ringToPathD(inner_ring.vertices, transform)}`;
4463
4590
  }
4464
- return [
4465
- {
4466
- name: "path",
4467
- type: "element",
4468
- attributes: {
4469
- class: "pcb-copper-pour pcb-copper-pour-brep",
4470
- d,
4471
- fill: color,
4472
- "fill-rule": "evenodd",
4473
- "fill-opacity": opacity,
4474
- "data-type": "pcb_copper_pour",
4475
- "data-pcb-layer": layer
4476
- },
4477
- children: [],
4478
- value: ""
4591
+ const copperPath = {
4592
+ name: "path",
4593
+ type: "element",
4594
+ value: "",
4595
+ children: [],
4596
+ attributes: {
4597
+ class: "pcb-copper-pour pcb-copper-pour-brep",
4598
+ d,
4599
+ fill: color,
4600
+ "fill-rule": "evenodd",
4601
+ "fill-opacity": opacity,
4602
+ "data-type": "pcb_copper_pour",
4603
+ "data-pcb-layer": layer
4479
4604
  }
4480
- ];
4605
+ };
4606
+ const maskPath = showSolderMask ? isCoveredWithSolderMask ? createSoldermaskOverlayElement({
4607
+ elementType: "path",
4608
+ shapeAttributes: { d, "fill-rule": "evenodd" },
4609
+ layer,
4610
+ fillColor: maskOverlayColor,
4611
+ fillOpacity: maskOverlayOpacity,
4612
+ className: "pcb-soldermask-covered-pour"
4613
+ }) : createSoldermaskCutoutElement({
4614
+ elementType: "path",
4615
+ shapeAttributes: { d, "fill-rule": "evenodd" },
4616
+ layer,
4617
+ colorMap: colorMap2
4618
+ }) : null;
4619
+ if (!maskPath) {
4620
+ return [copperPath];
4621
+ }
4622
+ const isSubstrateOnly = !isCoveredWithSolderMask && pour.pcb_copper_pour_id?.includes("substrate_only");
4623
+ if (isSubstrateOnly) {
4624
+ return [maskPath];
4625
+ }
4626
+ return [copperPath, maskPath];
4481
4627
  }
4482
4628
  return [];
4483
4629
  }
@@ -5074,7 +5220,7 @@ function getSoftwareUsedString(circuitJson) {
5074
5220
  var package_default = {
5075
5221
  name: "circuit-to-svg",
5076
5222
  type: "module",
5077
- version: "0.0.279",
5223
+ version: "0.0.281",
5078
5224
  description: "Convert Circuit JSON to SVG",
5079
5225
  main: "dist/index.js",
5080
5226
  files: [
@@ -5136,7 +5282,7 @@ var TYPE_PRIORITY = {
5136
5282
  pcb_copper_pour: 35,
5137
5283
  pcb_via: 36,
5138
5284
  pcb_soldermask: 40,
5139
- pcb_soldermask_opening: 41,
5285
+ pcb_soldermask_opening: 25,
5140
5286
  pcb_solder_paste: 45,
5141
5287
  pcb_silkscreen_text: 50,
5142
5288
  pcb_silkscreen_path: 50,
@@ -5181,7 +5327,7 @@ function getLayerPriority(layer) {
5181
5327
  if (!layer) return 500;
5182
5328
  const normalized = layer.toLowerCase();
5183
5329
  if (normalized === "global") return -100;
5184
- if (normalized === "bottom") return 0;
5330
+ if (normalized === "bottom") return 4;
5185
5331
  if (normalized === "board") return 2;
5186
5332
  if (normalized === "soldermask-top" || normalized === "soldermask-bottom")
5187
5333
  return 3;
@@ -5275,6 +5421,10 @@ function convertCircuitJsonToPcbSvg(circuitJson, options) {
5275
5421
  top: colorOverrides?.soldermask?.top ?? DEFAULT_PCB_COLOR_MAP.soldermask.top,
5276
5422
  bottom: colorOverrides?.soldermask?.bottom ?? DEFAULT_PCB_COLOR_MAP.soldermask.bottom
5277
5423
  },
5424
+ soldermaskOverCopper: {
5425
+ top: colorOverrides?.soldermaskOverCopper?.top ?? DEFAULT_PCB_COLOR_MAP.soldermaskOverCopper.top,
5426
+ bottom: colorOverrides?.soldermaskOverCopper?.bottom ?? DEFAULT_PCB_COLOR_MAP.soldermaskOverCopper.bottom
5427
+ },
5278
5428
  soldermaskWithCopperUnderneath: {
5279
5429
  top: colorOverrides?.soldermaskWithCopperUnderneath?.top ?? DEFAULT_PCB_COLOR_MAP.soldermaskWithCopperUnderneath.top,
5280
5430
  bottom: colorOverrides?.soldermaskWithCopperUnderneath?.bottom ?? DEFAULT_PCB_COLOR_MAP.soldermaskWithCopperUnderneath.bottom
@@ -5424,10 +5574,9 @@ function convertCircuitJsonToPcbSvg(circuitJson, options) {
5424
5574
  showAnchorOffsets: options?.showAnchorOffsets,
5425
5575
  circuitJson
5426
5576
  };
5427
- const unsortedSvgObjects = circuitJson.flatMap(
5577
+ let unsortedSvgObjects = circuitJson.flatMap(
5428
5578
  (elm) => createSvgObjects({ elm, circuitJson, ctx })
5429
5579
  );
5430
- let svgObjects = sortSvgObjectsByPcbLayer(unsortedSvgObjects);
5431
5580
  let strokeWidth = String(0.05 * scaleFactor);
5432
5581
  for (const element of circuitJson) {
5433
5582
  if ("stroke_width" in element) {
@@ -5437,8 +5586,9 @@ function convertCircuitJsonToPcbSvg(circuitJson, options) {
5437
5586
  }
5438
5587
  if (options?.shouldDrawRatsNest) {
5439
5588
  const ratsNestObjects = createSvgObjectsForRatsNest(circuitJson, ctx);
5440
- svgObjects = sortSvgObjectsByPcbLayer([...svgObjects, ...ratsNestObjects]);
5589
+ unsortedSvgObjects = [...unsortedSvgObjects, ...ratsNestObjects];
5441
5590
  }
5591
+ const svgObjects = sortSvgObjectsByPcbLayer(unsortedSvgObjects);
5442
5592
  const children = [
5443
5593
  {
5444
5594
  name: "style",