@tscircuit/3d-viewer 0.0.590 → 0.0.592

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.d.ts CHANGED
@@ -64,7 +64,14 @@ interface LayerVisibilityState {
64
64
  pcbNotes: boolean;
65
65
  backgroundStart: boolean;
66
66
  backgroundEnd: boolean;
67
+ /**
68
+ * Three-state display for the single assembled enclosure CAD entity. This is
69
+ * viewer state, not Circuit JSON: hidden to work unobstructed, translucent to
70
+ * check openings against the board, opaque to inspect the print itself.
71
+ */
72
+ enclosure: EnclosureVisibility;
67
73
  }
74
+ type EnclosureVisibility = "hidden" | "translucent" | "opaque";
68
75
 
69
76
  interface CombinedBoardTextures {
70
77
  topBoard?: THREE.CanvasTexture | null;
package/dist/index.js CHANGED
@@ -14452,6 +14452,12 @@ import {
14452
14452
  useMemo
14453
14453
  } from "react";
14454
14454
  import { jsx } from "react/jsx-runtime";
14455
+ var ENCLOSURE_VISIBILITY_CYCLE = [
14456
+ "translucent",
14457
+ "opaque",
14458
+ "hidden"
14459
+ ];
14460
+ var nextEnclosureVisibility = (current) => ENCLOSURE_VISIBILITY_CYCLE[(ENCLOSURE_VISIBILITY_CYCLE.indexOf(current) + 1) % ENCLOSURE_VISIBILITY_CYCLE.length];
14455
14461
  var defaultVisibility = {
14456
14462
  boardBody: true,
14457
14463
  topCopper: true,
@@ -14472,7 +14478,8 @@ var defaultVisibility = {
14472
14478
  threedAxis: false,
14473
14479
  pcbNotes: false,
14474
14480
  backgroundStart: true,
14475
- backgroundEnd: true
14481
+ backgroundEnd: true,
14482
+ enclosure: "translucent"
14476
14483
  };
14477
14484
  var LayerVisibilityContext = createContext(void 0);
14478
14485
  var LayerVisibilityProvider = ({ children }) => {
@@ -28151,6 +28158,79 @@ var SOD123W = () => {
28151
28158
  )
28152
28159
  ] });
28153
28160
  };
28161
+ var SOD123 = ({
28162
+ fullWidth = 3.7,
28163
+ fullLength: fullLength10 = 1.55
28164
+ } = {}) => {
28165
+ const bodyWidth = fullWidth - 1;
28166
+ const bodyLength10 = fullLength10;
28167
+ const packageHeight = 1.175;
28168
+ const bodyStandoff = 0.1;
28169
+ const bodyHeight = packageHeight - bodyStandoff;
28170
+ const leadWidth = 0.55;
28171
+ const leadThickness = 0.12;
28172
+ const leadHeight = 0.35;
28173
+ const bodyDistance = (fullWidth - bodyWidth) / 2;
28174
+ const padContactLength = 0.25;
28175
+ const leadCurveLength = 0.2;
28176
+ return /* @__PURE__ */ jsxs(Fragment2, { children: [
28177
+ /* @__PURE__ */ jsx2(
28178
+ SmdChipLead,
28179
+ {
28180
+ position: {
28181
+ x: -fullWidth / 2,
28182
+ y: 0,
28183
+ z: leadThickness / 2
28184
+ },
28185
+ width: leadWidth,
28186
+ thickness: leadThickness,
28187
+ padContactLength,
28188
+ bodyDistance,
28189
+ curveLength: leadCurveLength,
28190
+ height: leadHeight
28191
+ }
28192
+ ),
28193
+ /* @__PURE__ */ jsx2(
28194
+ SmdChipLead,
28195
+ {
28196
+ rotation: Math.PI,
28197
+ position: {
28198
+ x: fullWidth / 2,
28199
+ y: 0,
28200
+ z: leadThickness / 2
28201
+ },
28202
+ width: leadWidth,
28203
+ thickness: leadThickness,
28204
+ padContactLength,
28205
+ bodyDistance,
28206
+ curveLength: leadCurveLength,
28207
+ height: leadHeight
28208
+ }
28209
+ ),
28210
+ /* @__PURE__ */ jsx2(
28211
+ ChipBody,
28212
+ {
28213
+ center: { x: 0, y: 0, z: 0 },
28214
+ width: bodyWidth,
28215
+ length: bodyLength10,
28216
+ height: bodyHeight,
28217
+ heightAboveSurface: bodyStandoff,
28218
+ includeNotch: false,
28219
+ color: "#222",
28220
+ taperRatio: 0.06,
28221
+ straightHeightRatio: 0.6
28222
+ }
28223
+ ),
28224
+ /* @__PURE__ */ jsx2(
28225
+ Cuboid,
28226
+ {
28227
+ color: "#777",
28228
+ size: [0.45, bodyLength10 - 0.15, 0.02],
28229
+ center: [-bodyWidth / 4, 0, packageHeight]
28230
+ }
28231
+ )
28232
+ ] });
28233
+ };
28154
28234
  var SOD128 = () => {
28155
28235
  const fullWidth = 3.8;
28156
28236
  const bodyLength10 = 2.5;
@@ -30384,6 +30464,822 @@ var JSTZH1_5mm = ({
30384
30464
  })
30385
30465
  ] });
30386
30466
  };
30467
+ var getTerminalPoints = ([centerX, centerY], width10, length64, chamfer, isPinOne) => {
30468
+ const xDirection = Math.sign(centerX);
30469
+ const yDirection = Math.sign(centerY);
30470
+ const halfWidth = width10 / 2;
30471
+ const halfLength = length64 / 2;
30472
+ const innerChamfer = isPinOne ? Math.min(0.32, length64 * 0.36) : 0;
30473
+ const outerChamfer = Math.min(chamfer, halfWidth, halfLength);
30474
+ const points = [
30475
+ [-halfWidth, -halfLength],
30476
+ [halfWidth, -halfLength],
30477
+ [halfWidth, halfLength - outerChamfer],
30478
+ [halfWidth - outerChamfer, halfLength],
30479
+ [-halfWidth, halfLength]
30480
+ ];
30481
+ if (innerChamfer) {
30482
+ points[0] = [-halfWidth + innerChamfer, -halfLength];
30483
+ points.push([-halfWidth, -halfLength + innerChamfer]);
30484
+ }
30485
+ const oriented = points.map(
30486
+ ([x, y]) => [centerX + x * xDirection, centerY + y * yDirection]
30487
+ );
30488
+ return xDirection * yDirection < 0 ? oriented.reverse() : oriented;
30489
+ };
30490
+ var getRoundedRectProfile = ({
30491
+ width: width10,
30492
+ length: length64,
30493
+ radius,
30494
+ height: height10,
30495
+ z: z21
30496
+ }) => {
30497
+ const x = width10 / 2 - radius;
30498
+ const y = length64 / 2 - radius;
30499
+ return [
30500
+ [-x, -y],
30501
+ [x, -y],
30502
+ [x, y],
30503
+ [-x, y]
30504
+ ].map(([cornerX, cornerY], index2) => /* @__PURE__ */ jsx2(
30505
+ Cylinder,
30506
+ {
30507
+ center: [cornerX, cornerY, z21 + height10 / 2],
30508
+ height: height10,
30509
+ radius
30510
+ },
30511
+ `${z21}-${index2}`
30512
+ ));
30513
+ };
30514
+ var Crystal = ({
30515
+ horizontalPadPitch = 2.2,
30516
+ verticalPadPitch = 1.7,
30517
+ padWidth = 1.4,
30518
+ padHeight = 1.2,
30519
+ bodyHeight = 0.7
30520
+ }) => {
30521
+ const bodyWidth = horizontalPadPitch + padWidth * (5 / 7);
30522
+ const bodyLength10 = verticalPadPitch + padHeight * (2 / 3);
30523
+ const terminalThickness = Math.min(0.01, bodyHeight * 0.02);
30524
+ const terminalWidth = padWidth * (5 / 7);
30525
+ const terminalLength = padHeight * 0.75;
30526
+ const ceramicTopZ = bodyHeight * (5 / 7);
30527
+ const baseHeight = ceramicTopZ - terminalThickness;
30528
+ const sealHeight = bodyHeight * (2 / 35);
30529
+ const sealWidth = bodyWidth * 0.95;
30530
+ const sealLength = bodyLength10 * 0.94;
30531
+ const lidShoulderWidth = bodyWidth * 0.905;
30532
+ const lidShoulderLength = bodyLength10 * 0.9;
30533
+ const lidTopWidth = bodyWidth * 0.83;
30534
+ const lidTopLength = bodyLength10 * 0.82;
30535
+ const lidBaseZ = ceramicTopZ + sealHeight;
30536
+ const lidProfileHeight = Math.min(0.01, bodyHeight * 0.015);
30537
+ const bodyChamfer = Math.min(0.12, bodyLength10 * 0.05);
30538
+ const terminalX = (bodyWidth - terminalWidth) / 2;
30539
+ const terminalY = (bodyLength10 - terminalLength) / 2;
30540
+ const terminalPositions = [
30541
+ [-terminalX, -terminalY],
30542
+ [terminalX, -terminalY],
30543
+ [terminalX, terminalY],
30544
+ [-terminalX, terminalY]
30545
+ ];
30546
+ const sealProfile = getRoundedRectProfile({
30547
+ width: sealWidth,
30548
+ length: sealLength,
30549
+ radius: Math.min(0.13, sealLength * 0.08),
30550
+ height: sealHeight,
30551
+ z: ceramicTopZ
30552
+ });
30553
+ const lidProfiles = [
30554
+ ...getRoundedRectProfile({
30555
+ width: lidShoulderWidth,
30556
+ length: lidShoulderLength,
30557
+ radius: Math.min(0.14, lidShoulderLength * 0.08),
30558
+ height: lidProfileHeight,
30559
+ z: lidBaseZ
30560
+ }),
30561
+ ...getRoundedRectProfile({
30562
+ width: lidTopWidth,
30563
+ length: lidTopLength,
30564
+ radius: Math.min(0.15, lidTopLength * 0.09),
30565
+ height: lidProfileHeight,
30566
+ z: bodyHeight - lidProfileHeight
30567
+ })
30568
+ ];
30569
+ return /* @__PURE__ */ jsxs(Fragment2, { children: [
30570
+ terminalPositions.map((center, index2) => /* @__PURE__ */ jsx2(Colorize, { color: "#d6a258", children: /* @__PURE__ */ jsx2(ExtrudeLinear, { height: terminalThickness, children: /* @__PURE__ */ jsx2(
30571
+ Polygon,
30572
+ {
30573
+ points: getTerminalPoints(
30574
+ center,
30575
+ terminalWidth,
30576
+ terminalLength,
30577
+ bodyChamfer,
30578
+ index2 === 0
30579
+ )
30580
+ }
30581
+ ) }) }, index2)),
30582
+ /* @__PURE__ */ jsx2(
30583
+ ChipBody,
30584
+ {
30585
+ center: { x: 0, y: 0, z: terminalThickness },
30586
+ width: bodyWidth,
30587
+ length: bodyLength10,
30588
+ height: baseHeight - 5e-3,
30589
+ heightAboveSurface: 0,
30590
+ color: "#34343d",
30591
+ taperRatio: 0,
30592
+ straightHeightRatio: 1,
30593
+ includeNotch: false,
30594
+ chamferSize: bodyChamfer
30595
+ }
30596
+ ),
30597
+ /* @__PURE__ */ jsx2(Colorize, { color: "#d2a057", children: /* @__PURE__ */ jsx2(Hull, { children: sealProfile }) }),
30598
+ /* @__PURE__ */ jsx2(Colorize, { color: "#b9bec2", children: /* @__PURE__ */ jsx2(Hull, { children: lidProfiles }) })
30599
+ ] });
30600
+ };
30601
+ var HOUSING_COLOR = "#303339";
30602
+ var HOUSING_SHADOW = "#1f2227";
30603
+ var ACTUATOR_COLOR = "#eee8d8";
30604
+ var ACTUATOR_HIGHLIGHT = "#f8f3e7";
30605
+ var TIN_COLOR = "#b7bdc2";
30606
+ var TIN_HIGHLIGHT = "#d2d6d9";
30607
+ var HOLD_DOWN_COLOR = "#767d82";
30608
+ var HOLD_DOWN_HIGHLIGHT = "#9ba1a5";
30609
+ var FPC = ({
30610
+ pinCount = 12,
30611
+ pitch = 0.5,
30612
+ padWidth = 0.3,
30613
+ padLength = 1.25,
30614
+ staggered = false,
30615
+ reverse = false,
30616
+ rowPitch = 2.4,
30617
+ topPadLength = padLength,
30618
+ bottomPadLength = padLength,
30619
+ mountPadPitchX,
30620
+ mountPadOffsetY = 2.575,
30621
+ mountTop = false,
30622
+ mountPadWidth = 2,
30623
+ mountPadLength = 2.5
30624
+ }) => {
30625
+ const contactSpan = Math.max((pinCount - 1) * pitch, pitch);
30626
+ const contactStartX = -contactSpan / 2;
30627
+ const resolvedMountPitch = mountPadPitchX ?? contactSpan + (staggered ? 3.5 : 3.38);
30628
+ const mountY = mountPadOffsetY === 0 ? 0 : (mountTop ? 1 : -1) * mountPadOffsetY;
30629
+ const contactRows = Array.from({ length: pinCount }, (_, index2) => {
30630
+ const isUpperRow = staggered && index2 % 2 === 1 !== reverse;
30631
+ const y = staggered ? isUpperRow ? rowPitch / 2 : -rowPitch / 2 : 0;
30632
+ const length64 = isUpperRow ? topPadLength : bottomPadLength;
30633
+ return {
30634
+ index: index2,
30635
+ x: contactStartX + index2 * pitch,
30636
+ y,
30637
+ length: length64
30638
+ };
30639
+ });
30640
+ const contactMaxY = Math.max(
30641
+ ...contactRows.map((contact) => contact.y + contact.length / 2)
30642
+ );
30643
+ const contactMinY = Math.min(
30644
+ ...contactRows.map((contact) => contact.y - contact.length / 2)
30645
+ );
30646
+ const mountingMinY = mountY - mountPadLength / 2;
30647
+ const mountingMaxY = mountY + mountPadLength / 2;
30648
+ const signalSideY = mountTop ? contactMinY : contactMaxY;
30649
+ const cableSideY = mountTop ? Math.max(mountingMaxY, contactMaxY) + 0.67 : Math.min(mountingMinY, contactMinY) - 0.67;
30650
+ const directionToSignal = mountTop ? -1 : 1;
30651
+ const housingSignalY = signalSideY - directionToSignal * Math.max(padLength * 0.86, 1.05);
30652
+ const housingCableY = cableSideY + directionToSignal * 0.22;
30653
+ const housingDepth = Math.abs(housingSignalY - housingCableY);
30654
+ const housingCenterY = (housingSignalY + housingCableY) / 2;
30655
+ const cableEdgeY = housingCableY - directionToSignal * 0.01;
30656
+ const bodyWidth = Math.max(
30657
+ contactSpan + 4.9,
30658
+ resolvedMountPitch + mountPadWidth * 0.76
30659
+ );
30660
+ const openingWidth = Math.min(bodyWidth - 2.3, contactSpan + 1.1);
30661
+ const housingBaseHeight = 0.3;
30662
+ const housingHeight = 1.42;
30663
+ const overallHeight = 2;
30664
+ const throatDepth = Math.min(0.92, housingDepth * 0.28);
30665
+ const throatCenterY = cableEdgeY + directionToSignal * (throatDepth / 2 - 0.04);
30666
+ const throatHeight = 1.6;
30667
+ const throatCenterZ = 1.1;
30668
+ const actuatorDepth = Math.max(housingDepth - 0.78, 1.5);
30669
+ const actuatorCenterY = cableEdgeY + directionToSignal * (actuatorDepth / 2 + 0.68);
30670
+ const actuatorWidth = bodyWidth - 0.72;
30671
+ const actuatorHeight = 0.34;
30672
+ const actuatorCenterZ = overallHeight - actuatorHeight / 2;
30673
+ const hingeY = cableEdgeY + directionToSignal * Math.min(0.68, housingDepth * 0.22);
30674
+ const hingeZ = 1.48;
30675
+ const terminalWidth = Math.max(padWidth * 0.82, 0.15);
30676
+ const terminalOuterY = signalSideY;
30677
+ const terminalLength = Math.abs(terminalOuterY - housingSignalY);
30678
+ const terminalCenterY = (terminalOuterY + housingSignalY) / 2;
30679
+ const springLength = Math.max(throatDepth * 0.8, 0.5);
30680
+ const springCenterY = cableEdgeY + directionToSignal * (springLength / 2 + 0.08);
30681
+ const endClipX = resolvedMountPitch / 2;
30682
+ const clipHeight = 0.75;
30683
+ const clipWallX = bodyWidth / 2 - 0.04;
30684
+ const clipCapX = bodyWidth / 2 - 0.23;
30685
+ const sideBossX = bodyWidth / 2 - 0.32;
30686
+ const sideBossWidth = 0.68;
30687
+ return /* @__PURE__ */ jsxs(Fragment2, { children: [
30688
+ [-1, 1].map((direction) => /* @__PURE__ */ jsx2(
30689
+ Cuboid,
30690
+ {
30691
+ color: TIN_COLOR,
30692
+ center: [direction * endClipX, mountY, 0.07],
30693
+ size: [mountPadWidth, mountPadLength, 0.14]
30694
+ },
30695
+ `mount-pad:${direction}`
30696
+ )),
30697
+ contactRows.map((contact) => /* @__PURE__ */ jsx2(
30698
+ Cuboid,
30699
+ {
30700
+ color: TIN_COLOR,
30701
+ center: [contact.x, terminalCenterY, 0.065],
30702
+ size: [terminalWidth, terminalLength, 0.13]
30703
+ },
30704
+ `terminal:${contact.index}`
30705
+ )),
30706
+ /* @__PURE__ */ jsx2(
30707
+ RoundedCuboid,
30708
+ {
30709
+ color: HOUSING_SHADOW,
30710
+ center: [0, housingCenterY, housingBaseHeight / 2],
30711
+ size: [bodyWidth, housingDepth, housingBaseHeight],
30712
+ roundRadius: 0.1
30713
+ }
30714
+ ),
30715
+ /* @__PURE__ */ jsx2(Colorize, { color: HOUSING_COLOR, children: /* @__PURE__ */ jsxs(Subtract, { children: [
30716
+ /* @__PURE__ */ jsx2(
30717
+ RoundedCuboid,
30718
+ {
30719
+ center: [0, housingCenterY, housingBaseHeight + housingHeight / 2],
30720
+ size: [bodyWidth - 0.2, housingDepth - 0.12, housingHeight],
30721
+ roundRadius: 0.14
30722
+ }
30723
+ ),
30724
+ /* @__PURE__ */ jsx2(
30725
+ Cuboid,
30726
+ {
30727
+ center: [0, throatCenterY, throatCenterZ],
30728
+ size: [openingWidth, throatDepth, throatHeight]
30729
+ }
30730
+ ),
30731
+ /* @__PURE__ */ jsx2(
30732
+ Cuboid,
30733
+ {
30734
+ center: [0, actuatorCenterY, overallHeight - actuatorHeight * 0.72],
30735
+ size: [actuatorWidth - 0.32, actuatorDepth - 0.16, actuatorHeight]
30736
+ }
30737
+ )
30738
+ ] }) }),
30739
+ contactRows.map((contact) => /* @__PURE__ */ jsx2(
30740
+ RoundedCuboid,
30741
+ {
30742
+ color: TIN_HIGHLIGHT,
30743
+ center: [contact.x, springCenterY, housingBaseHeight + 0.82],
30744
+ size: [terminalWidth * 0.82, springLength, 0.14],
30745
+ roundRadius: 0.035
30746
+ },
30747
+ `spring:${contact.index}`
30748
+ )),
30749
+ contactRows.map((contact) => /* @__PURE__ */ jsx2(
30750
+ Cuboid,
30751
+ {
30752
+ color: TIN_COLOR,
30753
+ center: [
30754
+ contact.x,
30755
+ housingSignalY - directionToSignal * 0.03,
30756
+ housingBaseHeight + 0.32
30757
+ ],
30758
+ size: [terminalWidth, 0.13, 0.62]
30759
+ },
30760
+ `terminal-rise:${contact.index}`
30761
+ )),
30762
+ /* @__PURE__ */ jsx2(
30763
+ Cuboid,
30764
+ {
30765
+ color: HOUSING_SHADOW,
30766
+ center: [
30767
+ 0,
30768
+ cableEdgeY + directionToSignal * 0.1,
30769
+ housingBaseHeight + 0.71
30770
+ ],
30771
+ size: [openingWidth + 0.18, 0.16, 0.8]
30772
+ }
30773
+ ),
30774
+ /* @__PURE__ */ jsx2(
30775
+ RoundedCuboid,
30776
+ {
30777
+ color: ACTUATOR_COLOR,
30778
+ center: [0, actuatorCenterY, actuatorCenterZ],
30779
+ size: [actuatorWidth, actuatorDepth, actuatorHeight],
30780
+ roundRadius: 0.11
30781
+ }
30782
+ ),
30783
+ /* @__PURE__ */ jsx2(
30784
+ Cuboid,
30785
+ {
30786
+ color: ACTUATOR_HIGHLIGHT,
30787
+ center: [
30788
+ 0,
30789
+ actuatorCenterY - directionToSignal * (actuatorDepth / 2 - 0.12),
30790
+ overallHeight - 0.035
30791
+ ],
30792
+ size: [actuatorWidth - 0.36, 0.24, 0.07]
30793
+ }
30794
+ ),
30795
+ [-1, 1].map((direction) => /* @__PURE__ */ jsx2(
30796
+ RoundedCuboid,
30797
+ {
30798
+ color: ACTUATOR_COLOR,
30799
+ center: [direction * sideBossX, hingeY, hingeZ],
30800
+ size: [sideBossWidth, 0.92, 0.72],
30801
+ roundRadius: 0.1
30802
+ },
30803
+ `actuator-ear:${direction}`
30804
+ )),
30805
+ [-1, 1].map((direction) => /* @__PURE__ */ jsx2(
30806
+ Translate,
30807
+ {
30808
+ x: direction * sideBossX,
30809
+ y: hingeY,
30810
+ z: hingeZ,
30811
+ children: /* @__PURE__ */ jsx2(Rotate, { rotation: [0, Math.PI / 2, 0], children: /* @__PURE__ */ jsx2(
30812
+ Cylinder,
30813
+ {
30814
+ color: ACTUATOR_HIGHLIGHT,
30815
+ height: sideBossWidth + 0.12,
30816
+ radius: 0.24
30817
+ }
30818
+ ) })
30819
+ },
30820
+ `hinge:${direction}`
30821
+ )),
30822
+ [-1, 1].map((direction) => /* @__PURE__ */ jsx2(
30823
+ RoundedCuboid,
30824
+ {
30825
+ color: HOLD_DOWN_COLOR,
30826
+ center: [direction * clipWallX, mountY, clipHeight / 2],
30827
+ size: [0.17, Math.min(mountPadLength * 0.3, 0.7), clipHeight],
30828
+ roundRadius: 0.04
30829
+ },
30830
+ `hold-down-wall:${direction}`
30831
+ )),
30832
+ [-1, 1].map((direction) => /* @__PURE__ */ jsx2(
30833
+ RoundedCuboid,
30834
+ {
30835
+ color: HOLD_DOWN_HIGHLIGHT,
30836
+ center: [direction * clipCapX, mountY, clipHeight - 0.05],
30837
+ size: [0.42, Math.min(mountPadLength * 0.3, 0.7), 0.1],
30838
+ roundRadius: 0.035
30839
+ },
30840
+ `hold-down-cap:${direction}`
30841
+ )),
30842
+ /* @__PURE__ */ jsx2(
30843
+ Cuboid,
30844
+ {
30845
+ color: HOUSING_SHADOW,
30846
+ center: [0, housingCenterY, 0.025],
30847
+ size: [openingWidth + 0.7, housingDepth * 0.58, 0.05]
30848
+ }
30849
+ ),
30850
+ /* @__PURE__ */ jsx2(
30851
+ Cuboid,
30852
+ {
30853
+ color: HOUSING_SHADOW,
30854
+ center: [
30855
+ 0,
30856
+ housingSignalY - directionToSignal * 0.06,
30857
+ housingBaseHeight + 0.82
30858
+ ],
30859
+ size: [openingWidth + 0.4, 0.15, 0.92]
30860
+ }
30861
+ )
30862
+ ] });
30863
+ };
30864
+ var SmdPinHeader = ({
30865
+ numberOfPins,
30866
+ pitch = 2.54,
30867
+ pinThickness = 0.64,
30868
+ bodyWidth = 2.5,
30869
+ bodyHeight = 2.54,
30870
+ standoffHeight = 1.27,
30871
+ matingPinLength = 5.8,
30872
+ tailSpan = 5.08
30873
+ }) => {
30874
+ const xStart = -((numberOfPins - 1) * pitch) / 2;
30875
+ const bodyTop = standoffHeight + bodyHeight;
30876
+ const tailLength = tailSpan / 2;
30877
+ const tipChamferHeight = pinThickness * 0.35;
30878
+ return /* @__PURE__ */ jsx2(Fragment2, { children: Array.from({ length: numberOfPins }, (_, index2) => {
30879
+ const x = xStart + index2 * pitch;
30880
+ const tailDirection = index2 % 2 === 0 ? 1 : -1;
30881
+ const postBodyLength = matingPinLength - tipChamferHeight;
30882
+ const verticalTailLength = standoffHeight - pinThickness / 2;
30883
+ return /* @__PURE__ */ jsxs(Translate, { x, children: [
30884
+ /* @__PURE__ */ jsx2(
30885
+ Cuboid,
30886
+ {
30887
+ color: "#222",
30888
+ size: [pitch, bodyWidth, bodyHeight],
30889
+ center: [0, 0, standoffHeight + bodyHeight / 2]
30890
+ }
30891
+ ),
30892
+ /* @__PURE__ */ jsxs(Colorize, { color: "#d4af37", children: [
30893
+ /* @__PURE__ */ jsx2(
30894
+ Cuboid,
30895
+ {
30896
+ size: [pinThickness, tailLength, pinThickness],
30897
+ center: [0, tailDirection * (tailLength / 2), pinThickness / 2]
30898
+ }
30899
+ ),
30900
+ /* @__PURE__ */ jsx2(
30901
+ Cuboid,
30902
+ {
30903
+ size: [pinThickness, pinThickness, verticalTailLength],
30904
+ center: [0, 0, pinThickness / 2 + verticalTailLength / 2]
30905
+ }
30906
+ ),
30907
+ /* @__PURE__ */ jsx2(
30908
+ Cuboid,
30909
+ {
30910
+ size: [pinThickness, pinThickness, postBodyLength],
30911
+ center: [0, 0, bodyTop + postBodyLength / 2]
30912
+ }
30913
+ ),
30914
+ /* @__PURE__ */ jsxs(Hull, { children: [
30915
+ /* @__PURE__ */ jsx2(
30916
+ Cuboid,
30917
+ {
30918
+ size: [pinThickness, pinThickness, 0.01],
30919
+ center: [0, 0, bodyTop + postBodyLength]
30920
+ }
30921
+ ),
30922
+ /* @__PURE__ */ jsx2(
30923
+ Cuboid,
30924
+ {
30925
+ size: [pinThickness * 0.65, pinThickness * 0.65, 0.01],
30926
+ center: [0, 0, bodyTop + matingPinLength]
30927
+ }
30928
+ )
30929
+ ] })
30930
+ ] })
30931
+ ] }, index2);
30932
+ }) });
30933
+ };
30934
+ var ParametricChip = ({
30935
+ padPitch,
30936
+ padHeight,
30937
+ color = "#333"
30938
+ }) => {
30939
+ const fullLength10 = padPitch;
30940
+ const width10 = padHeight * 0.85;
30941
+ const height10 = width10;
30942
+ const terminatorWidth9 = fullLength10 * 0.2;
30943
+ const bodyLength10 = fullLength10 - terminatorWidth9 * 2;
30944
+ return /* @__PURE__ */ jsxs(Fragment2, { children: [
30945
+ /* @__PURE__ */ jsx2(
30946
+ Cuboid,
30947
+ {
30948
+ size: [bodyLength10, width10, height10],
30949
+ offset: [0, 0, height10 / 2],
30950
+ color
30951
+ }
30952
+ ),
30953
+ /* @__PURE__ */ jsx2(
30954
+ Cuboid,
30955
+ {
30956
+ size: [terminatorWidth9, height10, width10],
30957
+ offset: [fullLength10 / 2 - terminatorWidth9 / 2, 0, height10 / 2],
30958
+ color: "#ccc"
30959
+ }
30960
+ ),
30961
+ /* @__PURE__ */ jsx2(
30962
+ Cuboid,
30963
+ {
30964
+ size: [terminatorWidth9, height10, width10],
30965
+ offset: [-fullLength10 / 2 + terminatorWidth9 / 2, 0, height10 / 2],
30966
+ color: "#ccc"
30967
+ }
30968
+ )
30969
+ ] });
30970
+ };
30971
+ var Led5050 = ({
30972
+ color = "#ffff00",
30973
+ bodyColor = "#ffffff",
30974
+ leadColor = "#dedede"
30975
+ }) => {
30976
+ const bodySize = 5;
30977
+ const leadSpan = 5.4;
30978
+ const bodyBottom = 0.2;
30979
+ const bodyHeight = 1.3;
30980
+ const bodyTop = bodyBottom + bodyHeight;
30981
+ const leadLength = 1.4;
30982
+ const leadWidth = 1;
30983
+ const leadThickness = 0.2;
30984
+ const leadCenterX = leadSpan / 2 - leadLength / 2;
30985
+ const lensRadius = 2;
30986
+ const lensHeight = 0.25;
30987
+ const lensTop = 1.55;
30988
+ const cornerCutDepth = 0.3;
30989
+ const leadYPositions = [-1.7, 0, 1.7];
30990
+ const leadSides = [-1, 1];
30991
+ return /* @__PURE__ */ jsxs(Fragment2, { children: [
30992
+ leadYPositions.flatMap(
30993
+ (y) => leadSides.map((side) => /* @__PURE__ */ jsx2(
30994
+ Cuboid,
30995
+ {
30996
+ color: leadColor,
30997
+ size: [leadLength, leadWidth, leadThickness],
30998
+ center: [side * leadCenterX, y, leadThickness / 2]
30999
+ },
31000
+ `${side}-${y}`
31001
+ ))
31002
+ ),
31003
+ /* @__PURE__ */ jsx2(Colorize, { color: bodyColor, children: /* @__PURE__ */ jsxs(Subtract, { children: [
31004
+ /* @__PURE__ */ jsx2(
31005
+ ChipBody,
31006
+ {
31007
+ width: bodySize,
31008
+ length: bodySize,
31009
+ height: bodyHeight,
31010
+ heightAboveSurface: bodyBottom,
31011
+ center: { x: 0, y: 0, z: 0 },
31012
+ color: bodyColor,
31013
+ taperRatio: 0.036,
31014
+ straightHeightRatio: 0.01,
31015
+ includeNotch: false
31016
+ }
31017
+ ),
31018
+ /* @__PURE__ */ jsx2(
31019
+ Cylinder,
31020
+ {
31021
+ radius: lensRadius,
31022
+ height: lensHeight,
31023
+ center: [0, 0, bodyTop - lensHeight / 2]
31024
+ }
31025
+ ),
31026
+ /* @__PURE__ */ jsx2(
31027
+ Translate,
31028
+ {
31029
+ offset: [
31030
+ -bodySize / 2,
31031
+ bodySize / 2,
31032
+ bodyTop - cornerCutDepth / 2 + 5e-3
31033
+ ],
31034
+ children: /* @__PURE__ */ jsx2(Rotate, { rotation: [0, 0, Math.PI / 4], children: /* @__PURE__ */ jsx2(Cuboid, { size: [0.9, 0.9, cornerCutDepth + 0.01] }) })
31035
+ }
31036
+ )
31037
+ ] }) }),
31038
+ /* @__PURE__ */ jsx2(
31039
+ Cylinder,
31040
+ {
31041
+ color,
31042
+ radius: lensRadius,
31043
+ height: lensHeight,
31044
+ center: [0, 0, lensTop - lensHeight / 2]
31045
+ }
31046
+ )
31047
+ ] });
31048
+ };
31049
+ var range2 = (length64) => Array.from({ length: length64 }, (_, index2) => index2);
31050
+ var RJ45 = ({
31051
+ bodyWidth = 16.26,
31052
+ bodyDepth = 15.88,
31053
+ bodyHeight = 13.5,
31054
+ bodyCenterY = -0.96,
31055
+ ledPins = false,
31056
+ firstPinLeft = false,
31057
+ firstPinTop = false,
31058
+ signalPitch = 1.02,
31059
+ signalRowPitch = 1.78,
31060
+ signalHoleDiameter = 0.9144,
31061
+ shieldPinX = 8.13,
31062
+ shieldPinY = 0.13,
31063
+ shieldHoleDiameter = 1.8,
31064
+ locatorHoleX = 6.35,
31065
+ locatorHoleY = -3.43,
31066
+ locatorHoleDiameter = 3.25,
31067
+ ledPinX = 4.57,
31068
+ ledPinPitch = 2.29,
31069
+ ledPinY = 5.7,
31070
+ openingDirection,
31071
+ shellColor = "#b7bdc2",
31072
+ housingColor = "#20242a",
31073
+ contactColor = "#d6a928"
31074
+ }) => {
31075
+ const frontDirection = openingDirection ?? (bodyCenterY > 0 ? 1 : -1);
31076
+ const frontY = bodyCenterY + frontDirection * bodyDepth / 2;
31077
+ const shellThickness = Math.min(0.38, bodyWidth * 0.024);
31078
+ const openingWidth = Math.max(bodyWidth - 2.5, bodyWidth * 0.72);
31079
+ const openingHeight = Math.min(bodyHeight - 2.4, 9.6);
31080
+ const openingCenterZ = 1.3 + openingHeight / 2;
31081
+ const cavityDepth = Math.min(4.4, bodyDepth * 0.34);
31082
+ const cavityCenterY = frontY - frontDirection * cavityDepth / 2;
31083
+ const backWallY = frontY - frontDirection * (cavityDepth + shellThickness * 0.7);
31084
+ const signalLeadRadius = Math.max(
31085
+ 0.22,
31086
+ Math.min(signalHoleDiameter * 0.36, 0.38)
31087
+ );
31088
+ const signalPinPositions = range2(8).map((index2) => {
31089
+ const defaultX = (3.5 - index2) * signalPitch;
31090
+ const defaultY = index2 % 2 === 0 ? -signalRowPitch / 2 : signalRowPitch / 2;
31091
+ return {
31092
+ x: firstPinLeft ? -defaultX : defaultX,
31093
+ y: firstPinTop ? -defaultY : defaultY
31094
+ };
31095
+ });
31096
+ const ledPinPositions = [
31097
+ -ledPinX - ledPinPitch,
31098
+ -ledPinX,
31099
+ ledPinX,
31100
+ ledPinX + ledPinPitch
31101
+ ];
31102
+ const contactPitch = openingWidth / 10;
31103
+ const contactY = frontY - frontDirection * Math.max(cavityDepth * 0.48, 1.2);
31104
+ const contactZ = openingCenterZ + openingHeight * 0.18;
31105
+ const frontLipY = frontY + frontDirection * shellThickness * 0.2;
31106
+ return /* @__PURE__ */ jsxs(Fragment2, { children: [
31107
+ /* @__PURE__ */ jsxs(Colorize, { color: shellColor, children: [
31108
+ /* @__PURE__ */ jsxs(Subtract, { children: [
31109
+ /* @__PURE__ */ jsx2(
31110
+ Cuboid,
31111
+ {
31112
+ center: [0, bodyCenterY, bodyHeight / 2],
31113
+ size: [bodyWidth, bodyDepth, bodyHeight]
31114
+ }
31115
+ ),
31116
+ /* @__PURE__ */ jsx2(
31117
+ Cuboid,
31118
+ {
31119
+ center: [0, cavityCenterY, openingCenterZ],
31120
+ size: [
31121
+ openingWidth,
31122
+ cavityDepth + shellThickness * 2,
31123
+ openingHeight
31124
+ ]
31125
+ }
31126
+ )
31127
+ ] }),
31128
+ /* @__PURE__ */ jsx2(
31129
+ Cuboid,
31130
+ {
31131
+ center: [0, frontLipY, 0.72],
31132
+ size: [openingWidth + 0.5, shellThickness * 1.25, 1.05]
31133
+ }
31134
+ ),
31135
+ [-1, 1].map((direction) => /* @__PURE__ */ jsx2(
31136
+ Cuboid,
31137
+ {
31138
+ center: [direction * shieldPinX, shieldPinY, 0.25],
31139
+ size: [
31140
+ Math.max(shieldHoleDiameter * 0.46, 0.65),
31141
+ Math.max(shieldHoleDiameter * 0.72, 1.1),
31142
+ 3.4
31143
+ ]
31144
+ },
31145
+ `shield-tab:${direction}`
31146
+ )),
31147
+ [-1, 1].map((direction) => /* @__PURE__ */ jsx2(
31148
+ Cuboid,
31149
+ {
31150
+ center: [
31151
+ direction * bodyWidth * 0.24,
31152
+ bodyCenterY - frontDirection * bodyDepth * 0.08,
31153
+ bodyHeight + 0.04
31154
+ ],
31155
+ size: [bodyWidth * 0.22, bodyDepth * 0.42, 0.1]
31156
+ },
31157
+ `top-seam:${direction}`
31158
+ ))
31159
+ ] }),
31160
+ /* @__PURE__ */ jsxs(Colorize, { color: housingColor, children: [
31161
+ /* @__PURE__ */ jsxs(Subtract, { children: [
31162
+ /* @__PURE__ */ jsx2(
31163
+ RoundedCuboid,
31164
+ {
31165
+ center: [0, cavityCenterY, openingCenterZ],
31166
+ size: [
31167
+ openingWidth - 0.2,
31168
+ cavityDepth + shellThickness * 0.5,
31169
+ openingHeight - 0.2
31170
+ ],
31171
+ roundRadius: 0.22
31172
+ }
31173
+ ),
31174
+ /* @__PURE__ */ jsx2(
31175
+ Cuboid,
31176
+ {
31177
+ center: [
31178
+ 0,
31179
+ cavityCenterY - frontDirection * shellThickness * 0.2,
31180
+ openingCenterZ - 0.05
31181
+ ],
31182
+ size: [
31183
+ openingWidth - 1.25,
31184
+ cavityDepth + shellThickness,
31185
+ openingHeight - 1.35
31186
+ ]
31187
+ }
31188
+ )
31189
+ ] }),
31190
+ /* @__PURE__ */ jsx2(
31191
+ Cuboid,
31192
+ {
31193
+ center: [0, backWallY, openingCenterZ],
31194
+ size: [openingWidth - 1.15, shellThickness, openingHeight - 1.25]
31195
+ }
31196
+ ),
31197
+ /* @__PURE__ */ jsx2(
31198
+ RoundedCuboid,
31199
+ {
31200
+ center: [0, frontY - frontDirection * cavityDepth * 0.28, 1.55],
31201
+ size: [openingWidth - 2.6, cavityDepth * 0.5, 1.15],
31202
+ roundRadius: 0.16
31203
+ }
31204
+ ),
31205
+ [-1, 1].map((direction) => /* @__PURE__ */ jsx2(
31206
+ Cylinder,
31207
+ {
31208
+ center: [direction * locatorHoleX, locatorHoleY, -0.25],
31209
+ radius: Math.max(locatorHoleDiameter * 0.41, 0.65),
31210
+ height: 2.7
31211
+ },
31212
+ `locator:${direction}`
31213
+ ))
31214
+ ] }),
31215
+ /* @__PURE__ */ jsxs(Colorize, { color: contactColor, children: [
31216
+ signalPinPositions.map(({ x, y }, index2) => /* @__PURE__ */ jsx2(
31217
+ Cylinder,
31218
+ {
31219
+ center: [x, y, 0.15],
31220
+ radius: signalLeadRadius,
31221
+ height: 3.1
31222
+ },
31223
+ `signal-lead:${index2}`
31224
+ )),
31225
+ range2(8).map((index2) => /* @__PURE__ */ jsx2(
31226
+ Translate,
31227
+ {
31228
+ offset: [
31229
+ (index2 - 3.5) * contactPitch,
31230
+ contactY,
31231
+ contactZ + (index2 % 2 === 0 ? 0.03 : -0.03)
31232
+ ],
31233
+ children: /* @__PURE__ */ jsx2(Rotate, { rotation: [frontDirection * 0.2, 0, 0], children: /* @__PURE__ */ jsx2(
31234
+ RoundedCuboid,
31235
+ {
31236
+ size: [Math.max(contactPitch * 0.28, 0.28), 3.25, 0.16],
31237
+ roundRadius: 0.05
31238
+ }
31239
+ ) })
31240
+ },
31241
+ `socket-contact:${index2}`
31242
+ )),
31243
+ ledPins && ledPinPositions.map((x, index2) => /* @__PURE__ */ jsx2(
31244
+ Cylinder,
31245
+ {
31246
+ center: [x, ledPinY, 0.15],
31247
+ radius: signalLeadRadius,
31248
+ height: 3.1
31249
+ },
31250
+ `led-lead:${index2}`
31251
+ ))
31252
+ ] }),
31253
+ ledPins && /* @__PURE__ */ jsxs(Fragment2, { children: [
31254
+ /* @__PURE__ */ jsx2(
31255
+ RoundedCuboid,
31256
+ {
31257
+ color: "#73b744",
31258
+ center: [
31259
+ -bodyWidth / 2 + 2.05,
31260
+ frontY + frontDirection * shellThickness * 0.35,
31261
+ bodyHeight - 2.05
31262
+ ],
31263
+ size: [2.15, shellThickness * 1.55, 1.45],
31264
+ roundRadius: 0.18
31265
+ }
31266
+ ),
31267
+ /* @__PURE__ */ jsx2(
31268
+ RoundedCuboid,
31269
+ {
31270
+ color: "#e0aa35",
31271
+ center: [
31272
+ bodyWidth / 2 - 2.05,
31273
+ frontY + frontDirection * shellThickness * 0.35,
31274
+ bodyHeight - 2.05
31275
+ ],
31276
+ size: [2.15, shellThickness * 1.55, 1.45],
31277
+ roundRadius: 0.18
31278
+ }
31279
+ )
31280
+ ] })
31281
+ ] });
31282
+ };
30387
31283
  var Footprinter3d = ({ footprint }) => {
30388
31284
  let normalizedFootprint = footprint;
30389
31285
  if (footprint.startsWith("jstzh1_5mm")) {
@@ -30392,7 +31288,19 @@ var Footprinter3d = ({ footprint }) => {
30392
31288
  normalizedFootprint = `zh${numPins}`;
30393
31289
  }
30394
31290
  const fpJson = fp.string(normalizedFootprint).json();
31291
+ const colorMatch = footprint.match(/_color\(([^)]+)\)/);
31292
+ const color = colorMatch ? colorMatch[1] : void 0;
30395
31293
  switch (fpJson.fn) {
31294
+ case "crystal":
31295
+ return /* @__PURE__ */ jsx2(
31296
+ Crystal,
31297
+ {
31298
+ horizontalPadPitch: fpJson.px,
31299
+ verticalPadPitch: fpJson.py,
31300
+ padWidth: fpJson.pw,
31301
+ padHeight: fpJson.ph
31302
+ }
31303
+ );
30396
31304
  case "dip":
30397
31305
  return /* @__PURE__ */ jsx2(Dip, { numPins: fpJson.num_pins, pitch: fpJson.p, bodyWidth: fpJson.w });
30398
31306
  case "axial":
@@ -30508,6 +31416,17 @@ var Footprinter3d = ({ footprint }) => {
30508
31416
  }
30509
31417
  );
30510
31418
  }
31419
+ case "smdpinheader":
31420
+ return /* @__PURE__ */ jsx2(
31421
+ SmdPinHeader,
31422
+ {
31423
+ numberOfPins: fpJson.num_pins,
31424
+ pitch: fpJson.p,
31425
+ bodyWidth: fpJson.bh
31426
+ }
31427
+ );
31428
+ case "led5050":
31429
+ return /* @__PURE__ */ jsx2(Led5050, { color });
30511
31430
  case "cap": {
30512
31431
  switch (fpJson.imperial) {
30513
31432
  case "0402":
@@ -30529,6 +31448,7 @@ var Footprinter3d = ({ footprint }) => {
30529
31448
  case "2512":
30530
31449
  return /* @__PURE__ */ jsx2(A2512, { color: "#856c4d" });
30531
31450
  }
31451
+ break;
30532
31452
  }
30533
31453
  case "sot235":
30534
31454
  return /* @__PURE__ */ jsx2(SOT_235_default, {});
@@ -30564,6 +31484,50 @@ var Footprinter3d = ({ footprint }) => {
30564
31484
  return /* @__PURE__ */ jsx2(JSTZH1_5mm, { numPins: fpJson.num_pins });
30565
31485
  }
30566
31486
  break;
31487
+ case "fpc":
31488
+ return /* @__PURE__ */ jsx2(
31489
+ FPC,
31490
+ {
31491
+ pinCount: fpJson.num_pins,
31492
+ pitch: fpJson.p,
31493
+ padWidth: fpJson.pw,
31494
+ padLength: fpJson.pl,
31495
+ staggered: fpJson.staggered,
31496
+ reverse: fpJson.reverse,
31497
+ rowPitch: fpJson.py,
31498
+ topPadLength: fpJson.toppl,
31499
+ bottomPadLength: fpJson.bottompl,
31500
+ mountPadPitchX: fpJson.mpx,
31501
+ mountPadOffsetY: fpJson.mpy,
31502
+ mountTop: fpJson.mounttop,
31503
+ mountPadWidth: fpJson.mpw,
31504
+ mountPadLength: fpJson.mpl
31505
+ }
31506
+ );
31507
+ case "rj45":
31508
+ return /* @__PURE__ */ jsx2(
31509
+ RJ45,
31510
+ {
31511
+ bodyWidth: fpJson.w,
31512
+ bodyDepth: fpJson.h,
31513
+ bodyCenterY: fpJson.bodyy,
31514
+ ledPins: fpJson.ledpins || fpJson.num_pins === 14,
31515
+ firstPinLeft: fpJson.firstpinleft,
31516
+ firstPinTop: fpJson.firstpintop,
31517
+ signalPitch: fpJson.p,
31518
+ signalRowPitch: fpJson.py,
31519
+ signalHoleDiameter: fpJson.id,
31520
+ shieldPinX: fpJson.shieldx,
31521
+ shieldPinY: fpJson.shieldy,
31522
+ shieldHoleDiameter: fpJson.shieldid,
31523
+ locatorHoleX: fpJson.holex,
31524
+ locatorHoleY: fpJson.holey,
31525
+ locatorHoleDiameter: fpJson.holed,
31526
+ ledPinX: fpJson.ledx,
31527
+ ledPinPitch: fpJson.ledp,
31528
+ ledPinY: fpJson.ledy
31529
+ }
31530
+ );
30567
31531
  case "soic":
30568
31532
  return /* @__PURE__ */ jsx2(
30569
31533
  SOIC,
@@ -30589,6 +31553,8 @@ var Footprinter3d = ({ footprint }) => {
30589
31553
  return /* @__PURE__ */ jsx2(SMC, {});
30590
31554
  case "smf":
30591
31555
  return /* @__PURE__ */ jsx2(SMF, {});
31556
+ case "sod123":
31557
+ return /* @__PURE__ */ jsx2(SOD123, {});
30592
31558
  case "sod123f":
30593
31559
  return /* @__PURE__ */ jsx2(SOD123F, {});
30594
31560
  case "sod123fl":
@@ -30686,8 +31652,6 @@ var Footprinter3d = ({ footprint }) => {
30686
31652
  );
30687
31653
  }
30688
31654
  }
30689
- const colorMatch = footprint.match(/_color\(([^)]+)\)/);
30690
- const color = colorMatch ? colorMatch[1] : void 0;
30691
31655
  switch (fpJson.imperial) {
30692
31656
  case "0402":
30693
31657
  return /* @__PURE__ */ jsx2(A0402, { color });
@@ -30708,6 +31672,20 @@ var Footprinter3d = ({ footprint }) => {
30708
31672
  case "2512":
30709
31673
  return /* @__PURE__ */ jsx2(A2512, { color });
30710
31674
  }
31675
+ if ((fpJson.fn === "res" || fpJson.fn === "cap") && fpJson.p !== void 0 && fpJson.ph !== void 0) {
31676
+ const padPitch = mm(fpJson.p);
31677
+ const padHeight = mm(fpJson.ph);
31678
+ if (Number.isFinite(padPitch) && Number.isFinite(padHeight)) {
31679
+ return /* @__PURE__ */ jsx2(
31680
+ ParametricChip,
31681
+ {
31682
+ padPitch,
31683
+ padHeight,
31684
+ color: color ?? (fpJson.fn === "cap" ? "#856c4d" : void 0)
31685
+ }
31686
+ );
31687
+ }
31688
+ }
30711
31689
  return null;
30712
31690
  };
30713
31691
  var isVNode = (n) => n && typeof n === "object" && "type" in n;
@@ -32389,6 +33367,19 @@ var getRenderedCadModelType = (modelType) => {
32389
33367
  return modelType === "step" ? "glb" : modelType;
32390
33368
  };
32391
33369
 
33370
+ // src/utils/is-legacy-fdm-enclosure.ts
33371
+ var isLegacyFdmEnclosure = (cadComponent, circuitJson) => {
33372
+ if (!cadComponent.model_jscad || cadComponent.model_origin_alignment !== "bottom_center_of_component") {
33373
+ return false;
33374
+ }
33375
+ const pcbComponent = circuitJson.find(
33376
+ (element) => element.type === "pcb_component" && element.pcb_component_id === cadComponent.pcb_component_id
33377
+ );
33378
+ return Boolean(
33379
+ pcbComponent && pcbComponent.do_not_place && pcbComponent.is_allowed_to_be_off_board && pcbComponent.obstructs_within_bounds === false
33380
+ );
33381
+ };
33382
+
32392
33383
  // src/utils/resolve-model-url.ts
32393
33384
  var resolveModelUrl = (modelUrl, resolveStaticAsset) => {
32394
33385
  if (!modelUrl) return void 0;
@@ -32483,6 +33474,11 @@ var AnyCadComponent = ({
32483
33474
  (elm) => elm.type === "pcb_component" && elm.source_component_id === cad_component.source_component_id
32484
33475
  );
32485
33476
  const layer = pcbComponent?.layer ?? "top";
33477
+ const isEnclosure = useMemo8(
33478
+ () => isLegacyFdmEnclosure(cad_component, circuitJson),
33479
+ [cad_component, circuitJson]
33480
+ );
33481
+ const isTranslucent = isEnclosure ? visibility.enclosure === "translucent" : Boolean(cad_component.show_as_translucent_model);
32486
33482
  const sourceModelType = getCadModelType(cad_component);
32487
33483
  const renderedModelType = getRenderedCadModelType(sourceModelType);
32488
33484
  const gltfModelType = cad_component.model_glb_url ? "glb" : "gltf";
@@ -32518,7 +33514,7 @@ var AnyCadComponent = ({
32518
33514
  onHover: handleHover,
32519
33515
  onUnhover: handleUnhover,
32520
33516
  isHovered,
32521
- isTranslucent: cad_component.show_as_translucent_model
33517
+ isTranslucent
32522
33518
  },
32523
33519
  `${cad_component.cad_component_id}-gltf-${gltfUrl}`
32524
33520
  )
@@ -32543,7 +33539,7 @@ var AnyCadComponent = ({
32543
33539
  onHover: handleHover,
32544
33540
  onUnhover: handleUnhover,
32545
33541
  isHovered,
32546
- isTranslucent: cad_component.show_as_translucent_model
33542
+ isTranslucent
32547
33543
  },
32548
33544
  `${cad_component.cad_component_id}-mixed-${url}`
32549
33545
  )
@@ -32568,7 +33564,7 @@ var AnyCadComponent = ({
32568
33564
  onHover: handleHover,
32569
33565
  onUnhover: handleUnhover,
32570
33566
  isHovered,
32571
- isTranslucent: cad_component.show_as_translucent_model
33567
+ isTranslucent
32572
33568
  },
32573
33569
  `${cad_component.cad_component_id}-step-${stepUrl}`
32574
33570
  )
@@ -32580,7 +33576,7 @@ var AnyCadComponent = ({
32580
33576
  cad_component.cad_component_id,
32581
33577
  cad_component.footprinter_string,
32582
33578
  cad_component.model_jscad,
32583
- cad_component.show_as_translucent_model,
33579
+ isTranslucent,
32584
33580
  gltfUrl,
32585
33581
  gltfModelType,
32586
33582
  handleHover,
@@ -32642,7 +33638,7 @@ var AnyCadComponent = ({
32642
33638
  onHover: handleHover,
32643
33639
  onUnhover: handleUnhover,
32644
33640
  isHovered,
32645
- isTranslucent: cad_component.show_as_translucent_model
33641
+ isTranslucent
32646
33642
  },
32647
33643
  cad_component.cad_component_id
32648
33644
  );
@@ -32657,21 +33653,17 @@ var AnyCadComponent = ({
32657
33653
  onHover: handleHover,
32658
33654
  onUnhover: handleUnhover,
32659
33655
  isHovered,
32660
- isTranslucent: cad_component.show_as_translucent_model
33656
+ isTranslucent
32661
33657
  }
32662
33658
  );
32663
33659
  }
32664
- if (cad_component.show_as_translucent_model) {
32665
- if (!visibility.translucentModels) {
32666
- return null;
32667
- }
33660
+ if (isEnclosure) {
33661
+ if (visibility.enclosure === "hidden") return null;
33662
+ } else if (cad_component.show_as_translucent_model) {
33663
+ if (!visibility.translucentModels) return null;
32668
33664
  } else {
32669
- if (isThroughHole && !visibility.throughHoleModels) {
32670
- return null;
32671
- }
32672
- if (!isThroughHole && !visibility.smtModels) {
32673
- return null;
32674
- }
33665
+ if (isThroughHole && !visibility.throughHoleModels) return null;
33666
+ if (!isThroughHole && !visibility.smtModels) return null;
32675
33667
  }
32676
33668
  return /* @__PURE__ */ jsxs2(Fragment4, { children: [
32677
33669
  modelComponent,
@@ -32704,7 +33696,7 @@ import * as THREE23 from "three";
32704
33696
  // package.json
32705
33697
  var package_default = {
32706
33698
  name: "@tscircuit/3d-viewer",
32707
- version: "0.0.589",
33699
+ version: "0.0.591",
32708
33700
  main: "./dist/index.js",
32709
33701
  module: "./dist/index.js",
32710
33702
  type: "module",
@@ -32765,7 +33757,7 @@ var package_default = {
32765
33757
  "bun-match-svg": "^0.0.9",
32766
33758
  "bun-types": "1.2.1",
32767
33759
  debug: "^4.4.0",
32768
- "jscad-electronics": "^0.0.138",
33760
+ "jscad-electronics": "^0.0.146",
32769
33761
  "jscad-planner": "^0.0.13",
32770
33762
  jsdom: "^26.0.0",
32771
33763
  "manifold-3d": "^3.2.1",
@@ -46668,6 +47660,21 @@ var ChevronRightIcon = ({ isOpen }) => /* @__PURE__ */ jsx32(
46668
47660
  children: /* @__PURE__ */ jsx32("path", { d: "m9 18 6-6-6-6" })
46669
47661
  }
46670
47662
  );
47663
+ var CheckMinusIcon = () => /* @__PURE__ */ jsx32(
47664
+ "svg",
47665
+ {
47666
+ xmlns: "http://www.w3.org/2000/svg",
47667
+ width: "14",
47668
+ height: "14",
47669
+ viewBox: "0 0 24 24",
47670
+ fill: "none",
47671
+ stroke: "currentColor",
47672
+ strokeWidth: "2",
47673
+ strokeLinecap: "round",
47674
+ strokeLinejoin: "round",
47675
+ children: /* @__PURE__ */ jsx32("path", { d: "M5 12h14" })
47676
+ }
47677
+ );
46671
47678
  var DotIcon = () => /* @__PURE__ */ jsx32(
46672
47679
  "svg",
46673
47680
  {
@@ -47060,6 +48067,35 @@ var AppearanceMenu = () => {
47060
48067
  /* @__PURE__ */ jsx33("span", { style: { display: "flex", alignItems: "center" }, children: "Through-Hole Components" })
47061
48068
  ]
47062
48069
  }
48070
+ ),
48071
+ /* @__PURE__ */ jsx33(Separator2, { style: separatorStyles }),
48072
+ /* @__PURE__ */ jsxs7(
48073
+ Item22,
48074
+ {
48075
+ style: {
48076
+ ...itemStyles,
48077
+ backgroundColor: hoveredItem === "enclosure" ? "#404040" : "transparent"
48078
+ },
48079
+ onSelect: (e) => e.preventDefault(),
48080
+ onPointerDown: (e) => {
48081
+ e.preventDefault();
48082
+ setLayerVisibility(
48083
+ "enclosure",
48084
+ nextEnclosureVisibility(visibility.enclosure)
48085
+ );
48086
+ },
48087
+ onMouseEnter: () => setHoveredItem("enclosure"),
48088
+ onMouseLeave: () => setHoveredItem(null),
48089
+ onTouchStart: () => setHoveredItem("enclosure"),
48090
+ title: `Enclosure: ${visibility.enclosure}`,
48091
+ children: [
48092
+ /* @__PURE__ */ jsxs7("span", { style: iconContainerStyles, children: [
48093
+ visibility.enclosure === "opaque" && /* @__PURE__ */ jsx33(CheckIcon, {}),
48094
+ visibility.enclosure === "translucent" && /* @__PURE__ */ jsx33(CheckMinusIcon, {})
48095
+ ] }),
48096
+ /* @__PURE__ */ jsx33("span", { style: { display: "flex", alignItems: "center" }, children: "Enclosure" })
48097
+ ]
48098
+ }
47063
48099
  )
47064
48100
  ]
47065
48101
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/3d-viewer",
3
- "version": "0.0.590",
3
+ "version": "0.0.592",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.js",
6
6
  "type": "module",
@@ -61,7 +61,7 @@
61
61
  "bun-match-svg": "^0.0.9",
62
62
  "bun-types": "1.2.1",
63
63
  "debug": "^4.4.0",
64
- "jscad-electronics": "^0.0.138",
64
+ "jscad-electronics": "^0.0.146",
65
65
  "jscad-planner": "^0.0.13",
66
66
  "jsdom": "^26.0.0",
67
67
  "manifold-3d": "^3.2.1",