jscad-electronics 0.0.158 → 0.0.160

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/vanilla.js CHANGED
@@ -49,8 +49,18 @@ var FootprintPad = ({
49
49
  isPin1
50
50
  }) => {
51
51
  const color = isPin1 ? [0, 255, 0] : [255, 0, 0];
52
- if (pad.shape === "rect") {
53
- return /* @__PURE__ */ jsx(Colorize, { color, children: /* @__PURE__ */ jsx(Translate, { offset: [pad.x, pad.y, -5e-3], children: /* @__PURE__ */ jsx(Cuboid, { size: [pad.width, pad.height, PAD_THICKNESS] }) }) });
52
+ if (pad.shape === "rect" || pad.shape === "rotated_rect") {
53
+ return /* @__PURE__ */ jsx(Colorize, { color, children: /* @__PURE__ */ jsx(Translate, { offset: [pad.x, pad.y, -5e-3], children: /* @__PURE__ */ jsx(
54
+ Rotate,
55
+ {
56
+ angles: [
57
+ 0,
58
+ 0,
59
+ pad.shape === "rotated_rect" ? pad.ccw_rotation * Math.PI / 180 : 0
60
+ ],
61
+ children: /* @__PURE__ */ jsx(Cuboid, { size: [pad.width, pad.height, PAD_THICKNESS] })
62
+ }
63
+ ) }) });
54
64
  }
55
65
  if (pad.shape === "circle") {
56
66
  const radius = pad.radius ?? pad.r ?? 0.25;
@@ -184,7 +194,7 @@ var ExtrudedPads = ({
184
194
  };
185
195
 
186
196
  // lib/Footprinter3d.tsx
187
- import { fp as fp5 } from "@tscircuit/footprinter";
197
+ import { fp as fp8 } from "@tscircuit/footprinter";
188
198
  import { mp } from "@tscircuit/modelprinter";
189
199
 
190
200
  // lib/ChipBody.tsx
@@ -5169,6 +5179,135 @@ var JSTPH2_0mm = ({
5169
5179
  ] });
5170
5180
  };
5171
5181
 
5182
+ // lib/JSTXH2_5mm.tsx
5183
+ import { fp as fp2 } from "@tscircuit/footprinter";
5184
+ var JSTXH2_5mm = ({
5185
+ numPins = 4,
5186
+ showPins = true,
5187
+ showFootprint = true,
5188
+ bodyColor = "#f8fafc",
5189
+ // Natural white PA 66 nylon housing per spec
5190
+ pinColor = "#635959"
5191
+ // Tin-plated metallic gray posts
5192
+ }) => {
5193
+ const pitch = 2.5;
5194
+ const bodyHeight = 7;
5195
+ const bodyDepth = 5.75;
5196
+ const wallThickness = 0.85;
5197
+ const floorThickness = 1.65;
5198
+ const hollowHeight = bodyHeight - floorThickness;
5199
+ const pinLength = 8.75;
5200
+ const bodyWidth = (numPins - 1) * pitch + 4.9;
5201
+ const startX = -((numPins - 1) * pitch) / 2;
5202
+ const keySlotWidth = 0.8;
5203
+ const keySlotDepth = wallThickness + 0.2;
5204
+ const keySlotHeight = 3.5;
5205
+ const keySlotX = bodyWidth / 2 - 1.3;
5206
+ const lockNotchWidth = Math.min(
5207
+ bodyWidth - 3.4,
5208
+ Math.max(3, (numPins - 1) * pitch * 0.4 + 2.2)
5209
+ );
5210
+ const lockNotchHeight = 2.4;
5211
+ return /* @__PURE__ */ jsxs(Fragment2, { children: [
5212
+ /* @__PURE__ */ jsx(Translate, { offset: [0, 0, bodyHeight / 2], children: /* @__PURE__ */ jsx(Colorize, { color: bodyColor, children: /* @__PURE__ */ jsxs(Subtract, { children: [
5213
+ /* @__PURE__ */ jsx(Cuboid, { size: [bodyWidth, bodyDepth, bodyHeight] }),
5214
+ /* @__PURE__ */ jsx(Translate, { offset: [0, 0, (bodyHeight - hollowHeight) / 2 + 0.1], children: /* @__PURE__ */ jsx(
5215
+ Cuboid,
5216
+ {
5217
+ size: [
5218
+ bodyWidth - wallThickness * 2,
5219
+ bodyDepth - wallThickness * 2,
5220
+ hollowHeight + 0.2
5221
+ ]
5222
+ }
5223
+ ) }),
5224
+ /* @__PURE__ */ jsx(
5225
+ Translate,
5226
+ {
5227
+ offset: [
5228
+ 0,
5229
+ -bodyDepth / 2 + wallThickness / 2,
5230
+ bodyHeight / 2 - lockNotchHeight / 2 + 0.1
5231
+ ],
5232
+ children: /* @__PURE__ */ jsx(
5233
+ Cuboid,
5234
+ {
5235
+ size: [
5236
+ lockNotchWidth,
5237
+ wallThickness + 0.2,
5238
+ lockNotchHeight + 0.2
5239
+ ]
5240
+ }
5241
+ )
5242
+ }
5243
+ ),
5244
+ /* @__PURE__ */ jsx(
5245
+ Translate,
5246
+ {
5247
+ offset: [
5248
+ -keySlotX,
5249
+ -bodyDepth / 2 + wallThickness / 2,
5250
+ bodyHeight / 2 - keySlotHeight / 2 + 0.1
5251
+ ],
5252
+ children: /* @__PURE__ */ jsx(
5253
+ Cuboid,
5254
+ {
5255
+ size: [keySlotWidth, keySlotDepth, keySlotHeight + 0.2]
5256
+ }
5257
+ )
5258
+ }
5259
+ ),
5260
+ /* @__PURE__ */ jsx(
5261
+ Translate,
5262
+ {
5263
+ offset: [
5264
+ keySlotX,
5265
+ -bodyDepth / 2 + wallThickness / 2,
5266
+ bodyHeight / 2 - keySlotHeight / 2 + 0.1
5267
+ ],
5268
+ children: /* @__PURE__ */ jsx(
5269
+ Cuboid,
5270
+ {
5271
+ size: [keySlotWidth, keySlotDepth, keySlotHeight + 0.2]
5272
+ }
5273
+ )
5274
+ }
5275
+ ),
5276
+ Array.from({ length: numPins }).map((_, i) => /* @__PURE__ */ jsx(
5277
+ Translate,
5278
+ {
5279
+ offset: [
5280
+ startX + i * pitch,
5281
+ -bodyDepth / 2 + 0.3,
5282
+ -bodyHeight / 2 + 0.25
5283
+ ],
5284
+ children: /* @__PURE__ */ jsx(Cuboid, { size: [1, 0.8, 0.5] })
5285
+ },
5286
+ `vent_${i}`
5287
+ ))
5288
+ ] }) }) }),
5289
+ showPins && Array.from({ length: numPins }).map((_, i) => /* @__PURE__ */ jsx(Colorize, { color: pinColor, children: /* @__PURE__ */ jsx(Translate, { offset: [startX + i * pitch, 0, pinLength / 2 - 3.4], children: /* @__PURE__ */ jsx(Cuboid, { size: [0.64, 0.64, pinLength] }) }) }, i)),
5290
+ showFootprint && (() => {
5291
+ try {
5292
+ const circuitJson = fp2.string(`jst${numPins}_xh`).circuitJson();
5293
+ const platedHoles = circuitJson.filter(
5294
+ (e) => e.type === "pcb_plated_hole"
5295
+ );
5296
+ return platedHoles.map((hole, i) => /* @__PURE__ */ jsx(
5297
+ FootprintPlatedHole,
5298
+ {
5299
+ hole,
5300
+ isPin1: i === 0
5301
+ },
5302
+ `footprint_${i}`
5303
+ ));
5304
+ } catch {
5305
+ return null;
5306
+ }
5307
+ })()
5308
+ ] });
5309
+ };
5310
+
5172
5311
  // lib/Crystal.tsx
5173
5312
  var getTerminalPoints = ([centerX, centerY], width10, length, chamfer, isPinOne) => {
5174
5313
  const xDirection = Math.sign(centerX);
@@ -5646,9 +5785,9 @@ var SmdPinHeader = ({
5646
5785
  import { mm } from "@tscircuit/mm";
5647
5786
 
5648
5787
  // lib/utils/getPlatedHoleCenters.ts
5649
- import { fp as fp2 } from "@tscircuit/footprinter";
5788
+ import { fp as fp3 } from "@tscircuit/footprinter";
5650
5789
  var getPlatedHoleCenters = (footprint) => {
5651
- const elements = fp2.string(footprint).circuitJson();
5790
+ const elements = fp3.string(footprint).circuitJson();
5652
5791
  return elements.filter(
5653
5792
  (element) => element.type === "pcb_plated_hole" && Number.isFinite(element.x) && Number.isFinite(element.y)
5654
5793
  ).map((element) => ({
@@ -5659,9 +5798,9 @@ var getPlatedHoleCenters = (footprint) => {
5659
5798
  };
5660
5799
 
5661
5800
  // lib/utils/getSmtPadRects.ts
5662
- import { fp as fp3 } from "@tscircuit/footprinter";
5801
+ import { fp as fp4 } from "@tscircuit/footprinter";
5663
5802
  var getSmtPadRects = (footprint) => {
5664
- const elements = fp3.string(footprint).circuitJson();
5803
+ const elements = fp4.string(footprint).circuitJson();
5665
5804
  return elements.filter(
5666
5805
  (element) => element.type === "pcb_smtpad" && element.shape === "rect" && Number.isFinite(element.x) && Number.isFinite(element.y)
5667
5806
  ).map((element) => ({
@@ -6417,7 +6556,7 @@ var SOT563 = ({ fullWidth = 1.94, fullLength: fullLength10 = 1.6 }) => {
6417
6556
  };
6418
6557
 
6419
6558
  // lib/BGA.tsx
6420
- import { fp as fp4 } from "@tscircuit/footprinter";
6559
+ import { fp as fp5 } from "@tscircuit/footprinter";
6421
6560
  var BGA = ({
6422
6561
  packageWidth = 10,
6423
6562
  packageLength = 10,
@@ -6433,7 +6572,7 @@ var BGA = ({
6433
6572
  const bodyHeight = packageHeight - standoffHeight;
6434
6573
  const bodyOffset = standoffHeight + bodyHeight / 2;
6435
6574
  const ballOffset = Math.max(standoffHeight / 2, ballDiameter / 2);
6436
- const ballsSoup = footprintString ? fp4.string(footprintString).circuitJson() : null;
6575
+ const ballsSoup = footprintString ? fp5.string(footprintString).circuitJson() : null;
6437
6576
  return /* @__PURE__ */ jsxs(Fragment2, { children: [
6438
6577
  /* @__PURE__ */ jsx(Translate, { z: bodyOffset, children: /* @__PURE__ */ jsx(Colorize, { color: "#555", children: /* @__PURE__ */ jsx(Cuboid, { size: [packageWidth, packageLength, bodyHeight] }) }) }),
6439
6578
  !footprintString && Array.from({ length: ballRows * ballColumns }).map((_, index) => {
@@ -6462,6 +6601,160 @@ var BGA = ({
6462
6601
  ] });
6463
6602
  };
6464
6603
 
6604
+ // lib/UsbCMidmount.tsx
6605
+ import { fp as fp6 } from "@tscircuit/footprinter";
6606
+ var Capsule = ({
6607
+ width: width10,
6608
+ height: height10,
6609
+ depth
6610
+ }) => /* @__PURE__ */ jsx(Hull, { children: [-1, 1].map((side) => /* @__PURE__ */ jsx(Translate, { offset: [side * (width10 - height10) / 2, 0, 0], children: /* @__PURE__ */ jsx(Rotate, { rotation: [Math.PI / 2, 0, 0], children: /* @__PURE__ */ jsx(Cylinder, { radius: height10 / 2, height: depth }) }) }, side)) });
6611
+ var UsbCMidmount = ({
6612
+ footprint = "usbcmidmount16"
6613
+ }) => {
6614
+ const canonical = footprint.replace(/_pin1location\([^)]*\)/g, "");
6615
+ const params = fp6.string(canonical).json();
6616
+ const elements = fp6.string(canonical).circuitJson();
6617
+ const pads = elements.filter(
6618
+ (e) => e.type === "pcb_smtpad" && e.shape === "rect"
6619
+ );
6620
+ const slots = elements.filter((e) => e.type === "pcb_plated_hole");
6621
+ const holes = elements.filter((e) => e.type === "pcb_hole");
6622
+ const target = fp6.string(footprint).circuitJson().find((e) => e.type === "pcb_plated_hole");
6623
+ const first = slots[0];
6624
+ const angle = first && target && "x" in target ? Math.atan2(target.y, target.x) - Math.atan2(first.y, first.x) : 0;
6625
+ const width10 = 8.94, height10 = 3.2, wall = 0.22;
6626
+ const back = params.rowy + 0.23, front = -params.bodybottom;
6627
+ const depth = back - front, centerY = (back + front) / 2, centerZ = 1.65;
6628
+ if (!Number.isFinite(depth) || depth < 3 || slots.length !== 4)
6629
+ throw new Error(
6630
+ "UsbCMidmount requires four mounting slots and a positive body depth"
6631
+ );
6632
+ const tabBottom = -0.9, tabTop = centerZ + 0.1;
6633
+ return /* @__PURE__ */ jsxs(Rotate, { rotation: [0, 0, angle], children: [
6634
+ /* @__PURE__ */ jsx(Colorize, { color: "#b8bdc4", children: /* @__PURE__ */ jsx(Translate, { offset: [0, centerY, centerZ], children: /* @__PURE__ */ jsxs(Subtract, { children: [
6635
+ /* @__PURE__ */ jsx(Capsule, { width: width10, height: height10, depth }),
6636
+ /* @__PURE__ */ jsx(
6637
+ Capsule,
6638
+ {
6639
+ width: width10 - wall * 2,
6640
+ height: height10 - wall * 2,
6641
+ depth: depth + 0.2
6642
+ }
6643
+ )
6644
+ ] }) }) }),
6645
+ /* @__PURE__ */ jsxs(Colorize, { color: "#242529", children: [
6646
+ /* @__PURE__ */ jsx(
6647
+ Cuboid,
6648
+ {
6649
+ size: [6.65, depth - 1.1, 0.7],
6650
+ center: [0, centerY + 0.3, centerZ]
6651
+ }
6652
+ ),
6653
+ /* @__PURE__ */ jsx(Cuboid, { size: [7.6, 1, 2.45], center: [0, back - 0.65, centerZ] }),
6654
+ holes.map(
6655
+ (hole, i) => "x" in hole && "hole_diameter" in hole ? /* @__PURE__ */ jsx(
6656
+ Cylinder,
6657
+ {
6658
+ radius: hole.hole_diameter * 0.42,
6659
+ height: 0.8,
6660
+ center: [hole.x, hole.y, -0.3]
6661
+ },
6662
+ i
6663
+ ) : null
6664
+ )
6665
+ ] }),
6666
+ /* @__PURE__ */ jsxs(Colorize, { color: "#d3ad57", children: [
6667
+ [-1, 1].flatMap(
6668
+ (side) => [-2.75, -2.25, -1.25, -0.25, 0.25, 1.25, 2.25, 2.75].map((x) => /* @__PURE__ */ jsx(
6669
+ Cuboid,
6670
+ {
6671
+ size: [0.24, depth - 2, 0.04],
6672
+ center: [x, centerY + 0.1, centerZ + side * 0.365]
6673
+ },
6674
+ `${side}-${x}`
6675
+ ))
6676
+ ),
6677
+ pads.map((pad, i) => /* @__PURE__ */ jsx(
6678
+ Cuboid,
6679
+ {
6680
+ size: [
6681
+ Math.min(pad.width * 0.7, 0.35),
6682
+ pad.height * 0.8 + 0.35,
6683
+ 0.15
6684
+ ],
6685
+ center: [pad.x, pad.y - 0.175, 0.075]
6686
+ },
6687
+ i
6688
+ ))
6689
+ ] }),
6690
+ /* @__PURE__ */ jsx(Colorize, { color: "#b8bdc4", children: slots.map((slot, i) => /* @__PURE__ */ jsx(
6691
+ Cuboid,
6692
+ {
6693
+ size: [
6694
+ 0.4,
6695
+ "hole_height" in slot ? Math.max(0.3, slot.hole_height - 0.2) : 1,
6696
+ tabTop - tabBottom
6697
+ ],
6698
+ center: [slot.x, slot.y, (tabTop + tabBottom) / 2]
6699
+ },
6700
+ i
6701
+ )) })
6702
+ ] });
6703
+ };
6704
+
6705
+ // lib/SOT143.tsx
6706
+ import { fp as fp7 } from "@tscircuit/footprinter";
6707
+ var getPads = (footprint) => fp7.string(footprint).circuitJson().filter(
6708
+ (element) => element.type === "pcb_smtpad" && (element.shape === "rect" || element.shape === "rotated_rect")
6709
+ ).map((pad) => ({ x: pad.x, y: pad.y, pin: pad.port_hints?.[0] }));
6710
+ var SOT143 = ({ footprint = "sot143" }) => {
6711
+ const pads = getPads(footprint);
6712
+ if (pads.length !== 4) throw new Error("SOT143 requires four signal pads");
6713
+ const canonical = getPads("sot143");
6714
+ const options = fp7.string(footprint).json();
6715
+ const origin = canonical[1];
6716
+ const target = pads.find((pad) => pad.pin === "2");
6717
+ const angle = options.pin1location ? Math.round(
6718
+ (Math.atan2(target.y, target.x) - Math.atan2(origin.y, origin.x)) / (Math.PI / 2)
6719
+ ) * (Math.PI / 2) : 0;
6720
+ const local = pads.map((pad) => ({
6721
+ ...pad,
6722
+ x: pad.x * Math.cos(angle) + pad.y * Math.sin(angle),
6723
+ y: -pad.x * Math.sin(angle) + pad.y * Math.cos(angle)
6724
+ }));
6725
+ return /* @__PURE__ */ jsxs(Rotate, { rotation: [0, 0, angle], children: [
6726
+ /* @__PURE__ */ jsx(
6727
+ ChipBody,
6728
+ {
6729
+ width: 2.9,
6730
+ length: 1.3,
6731
+ height: 0.95,
6732
+ heightAboveSurface: 0.05,
6733
+ center: { x: 0, y: 0, z: 0 },
6734
+ includeNotch: false,
6735
+ taperRatio: 0.06
6736
+ }
6737
+ ),
6738
+ local.map((pad) => {
6739
+ const side = pad.y < 0 ? -1 : 1;
6740
+ const leadWidth = pad.pin === "1" ? 0.83 : 0.43;
6741
+ return /* @__PURE__ */ jsx(
6742
+ SmdChipLead,
6743
+ {
6744
+ width: leadWidth,
6745
+ thickness: 0.12,
6746
+ height: 0.45,
6747
+ padContactLength: 0.3,
6748
+ bodyDistance: 0.6,
6749
+ rotation: side < 0 ? Math.PI / 2 : -Math.PI / 2,
6750
+ position: { x: pad.x, y: side * 1.15, z: 0.06 }
6751
+ },
6752
+ pad.pin
6753
+ );
6754
+ })
6755
+ ] });
6756
+ };
6757
+
6465
6758
  // lib/FlexScreen.tsx
6466
6759
  var DEFAULT_ASPECT_RATIO = 16 / 9;
6467
6760
  var DEFAULT_DIAGONAL = 40;
@@ -7024,8 +7317,12 @@ var Footprinter3d = ({ footprint }) => {
7024
7317
  const pinMatch = footprint.match(/jstph2_0mm(\d+)?/);
7025
7318
  const numPins = pinMatch && pinMatch[1] ? pinMatch[1] : "2";
7026
7319
  normalizedFootprint = `jst${numPins}_ph`;
7320
+ } else if (footprint.startsWith("jstxh2_5mm")) {
7321
+ const pinMatch = footprint.match(/jstxh2_5mm(\d+)?/);
7322
+ const numPins = pinMatch && pinMatch[1] ? pinMatch[1] : "2";
7323
+ normalizedFootprint = `jst${numPins}_xh`;
7027
7324
  }
7028
- const fpJson = fp5.string(normalizedFootprint).json();
7325
+ const fpJson = fp8.string(normalizedFootprint).json();
7029
7326
  const colorMatch = footprint.match(/_color\(([^)]+)\)/);
7030
7327
  const color = colorMatch ? colorMatch[1] : void 0;
7031
7328
  const dim = (value, fallback) => {
@@ -7235,6 +7532,10 @@ var Footprinter3d = ({ footprint }) => {
7235
7532
  }
7236
7533
  case "sot457":
7237
7534
  return /* @__PURE__ */ jsx(SOT457, {});
7535
+ case "usbcmidmount":
7536
+ return /* @__PURE__ */ jsx(UsbCMidmount, { footprint: normalizedFootprint });
7537
+ case "sot143":
7538
+ return /* @__PURE__ */ jsx(SOT143, { footprint: normalizedFootprint });
7238
7539
  case "sot223":
7239
7540
  return /* @__PURE__ */ jsx(SOT223, {});
7240
7541
  case "sot23w":
@@ -7267,6 +7568,9 @@ var Footprinter3d = ({ footprint }) => {
7267
7568
  if (fpJson.ph) {
7268
7569
  return /* @__PURE__ */ jsx(JSTPH2_0mm, { numPins: fpJson.num_pins });
7269
7570
  }
7571
+ if (fpJson.xh) {
7572
+ return /* @__PURE__ */ jsx(JSTXH2_5mm, { numPins: fpJson.num_pins });
7573
+ }
7270
7574
  break;
7271
7575
  case "fpc":
7272
7576
  return /* @__PURE__ */ jsx(