jscad-electronics 0.0.215 → 0.0.217

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
@@ -183,24 +183,24 @@ var FootprintPlatedHole = ({
183
183
  import { ballBearingModelDefinitionSchema } from "@tscircuit/modelprinter";
184
184
 
185
185
  // lib/model-registry.ts
186
- function defineModelRenderer(model27) {
187
- return model27;
186
+ function defineModelRenderer(model28) {
187
+ return model28;
188
188
  }
189
189
  var ModelRendererRegistry = class {
190
190
  models = /* @__PURE__ */ new Map();
191
- register(model27) {
192
- if (typeof model27.name !== "string" || !/^[a-z]+$/.test(model27.name)) {
191
+ register(model28) {
192
+ if (typeof model28.name !== "string" || !/^[a-z]+$/.test(model28.name)) {
193
193
  throw new Error(
194
194
  "Model renderer names must contain only lowercase letters"
195
195
  );
196
196
  }
197
- if (this.models.has(model27.name)) {
198
- throw new Error(`Model renderer "${model27.name}" is already registered`);
197
+ if (this.models.has(model28.name)) {
198
+ throw new Error(`Model renderer "${model28.name}" is already registered`);
199
199
  }
200
- if (model27.pads !== "none" && model27.pads !== "footprinter") {
200
+ if (model28.pads !== "none" && model28.pads !== "footprinter") {
201
201
  throw new Error('Model renderer pads must be "none" or "footprinter"');
202
202
  }
203
- const { name, schema, render: render2, pads } = model27;
203
+ const { name, schema, render: render2, pads } = model28;
204
204
  this.models.set(name, {
205
205
  name,
206
206
  schema,
@@ -504,6 +504,268 @@ function register(registry) {
504
504
  registry.register(model);
505
505
  }
506
506
 
507
+ // lib/models/balltransferunit/register.tsx
508
+ import { ballTransferUnitModelDefinitionSchema } from "@tscircuit/modelprinter";
509
+
510
+ // lib/models/balltransferunit/mesh.ts
511
+ import {
512
+ getBallTransferUnitDimensions
513
+ } from "@tscircuit/modelprinter";
514
+ import earcut2 from "earcut";
515
+
516
+ // lib/mechanical/extrude-planar-profile.ts
517
+ import earcut from "earcut";
518
+ function extrudePlanarProfile({
519
+ outer,
520
+ holes = [],
521
+ start,
522
+ end,
523
+ project = (u, v, depth) => [u, v, depth],
524
+ reverse = false,
525
+ skipWall = () => false
526
+ }) {
527
+ const oriented = (loop, clockwise) => {
528
+ loop = loop.filter((point, index) => {
529
+ const previous = loop[(index + loop.length - 1) % loop.length];
530
+ return point[0] !== previous[0] || point[1] !== previous[1];
531
+ });
532
+ const area = loop.reduce((sum, a, index) => {
533
+ const b = loop[(index + 1) % loop.length];
534
+ return sum + a[0] * b[1] - a[1] * b[0];
535
+ }, 0);
536
+ if (!Number.isFinite(area) || area === 0)
537
+ throw new Error("Profile exceeds mesh resolution limits");
538
+ return area < 0 === clockwise ? loop : [...loop].reverse();
539
+ };
540
+ const loops = [oriented(outer, false), ...holes.map((h2) => oriented(h2, true))];
541
+ const points = loops.flat();
542
+ const holeStarts = [];
543
+ let count = loops[0].length;
544
+ for (const hole of loops.slice(1)) {
545
+ holeStarts.push(count);
546
+ count += hole.length;
547
+ }
548
+ const faces = earcut(points.flat(), holeStarts);
549
+ const positions = [start, end].flatMap(
550
+ (depth) => points.flatMap(([u, v]) => project(u, v, depth))
551
+ );
552
+ const indices = [];
553
+ for (let i = 0; i < faces.length; i += 3) {
554
+ const [a, b, c] = faces.slice(i, i + 3);
555
+ indices.push(a, c, b, a + count, b + count, c + count);
556
+ }
557
+ let offset = 0;
558
+ for (const [loopIndex, loop] of loops.entries()) {
559
+ for (let i = 0; i < loop.length; i++) {
560
+ const next = (i + 1) % loop.length;
561
+ if (loopIndex === 0 && skipWall(loop[i], loop[next])) continue;
562
+ const a = offset + i;
563
+ const b = offset + next;
564
+ indices.push(a, b, b + count, a, b + count, a + count);
565
+ }
566
+ offset += loop.length;
567
+ }
568
+ if (reverse)
569
+ for (let i = 0; i < indices.length; i += 3)
570
+ [indices[i + 1], indices[i + 2]] = [indices[i + 2], indices[i + 1]];
571
+ return { positions, indices };
572
+ }
573
+ function joinProfileMeshes(meshes) {
574
+ const positions = [];
575
+ const indices = [];
576
+ const vertices = /* @__PURE__ */ new Map();
577
+ for (const mesh of meshes) {
578
+ for (const index of mesh.indices) {
579
+ const point = mesh.positions.slice(index * 3, index * 3 + 3);
580
+ const key = point.map((value) => value.toFixed(12)).join(",");
581
+ let shared = vertices.get(key);
582
+ if (shared === void 0) {
583
+ shared = positions.length / 3;
584
+ vertices.set(key, shared);
585
+ positions.push(...point);
586
+ }
587
+ indices.push(shared);
588
+ }
589
+ }
590
+ return { positions, indices };
591
+ }
592
+ function circularProfile(x, y, radius, segments = 96) {
593
+ return Array.from({ length: segments }, (_, index) => {
594
+ const angle = index * 2 * Math.PI / segments;
595
+ return [x + radius * Math.cos(angle), y + radius * Math.sin(angle)];
596
+ });
597
+ }
598
+
599
+ // lib/models/balltransferunit/mesh.ts
600
+ function createBallTransferUnitMesh(input = {}) {
601
+ const d = getBallTransferUnitDimensions(input);
602
+ const lengths = [
603
+ d.height,
604
+ d.flangeDiameter,
605
+ d.flangeThickness,
606
+ d.flangeBottomZ,
607
+ d.ballRadius,
608
+ d.ballProtrusion,
609
+ d.openingRadius,
610
+ d.holeDiameter,
611
+ d.socketBottomZ,
612
+ d.bodyRadius - d.socketRadius,
613
+ (d.pitchCircleDiameter - d.holeDiameter - d.bodyDiameter) / 2,
614
+ (d.flangeDiameter - d.pitchCircleDiameter - d.holeDiameter) / 2
615
+ ];
616
+ const largest = Math.max(...lengths);
617
+ const resolution4 = Math.max(1e-5, largest * 1e-7);
618
+ if (!lengths.every(Number.isFinite) || largest > 1e6 || Math.min(...lengths) < resolution4)
619
+ throw new Error(
620
+ "Ball transfer unit exceeds the renderer's numerical resolution"
621
+ );
622
+ const segments = 96;
623
+ const latitude = 48;
624
+ const profile = [
625
+ [d.bodyRadius, 0],
626
+ [d.bodyRadius, d.flangeBottomZ],
627
+ [d.flangeRadius, d.flangeBottomZ],
628
+ [d.flangeRadius, d.bodyHeight],
629
+ [d.openingRadius, d.bodyHeight]
630
+ ];
631
+ const openingAngle = Math.acos(
632
+ (d.bodyHeight - d.ballCenterZ) / d.socketRadius
633
+ );
634
+ for (let j = 1; j < latitude; j++) {
635
+ const angle = j * Math.PI / latitude;
636
+ if ((angle - openingAngle) * d.socketRadius > resolution4)
637
+ profile.push([
638
+ d.socketRadius * Math.sin(angle),
639
+ d.ballCenterZ + d.socketRadius * Math.cos(angle)
640
+ ]);
641
+ }
642
+ profile.push([0, d.socketBottomZ], [0, 0]);
643
+ const holes = d.mountingHoles.map(
644
+ ({ x, y, diameter }) => circularProfile(x, y, diameter / 2, segments)
645
+ );
646
+ const flangeOutline = circularProfile(0, 0, d.flangeRadius, segments);
647
+ const housing = joinProfileMeshes([
648
+ // Cap faces are triangulated with all openings, rather than covered by
649
+ // annular triangles and repaired afterward with Boolean subtraction.
650
+ revolve2(profile, segments, /* @__PURE__ */ new Set([1, 3])),
651
+ cap(
652
+ flangeOutline,
653
+ [circularProfile(0, 0, d.bodyRadius, segments), ...holes],
654
+ d.flangeBottomZ,
655
+ true
656
+ ),
657
+ cap(
658
+ flangeOutline,
659
+ [circularProfile(0, 0, d.openingRadius, segments), ...holes],
660
+ d.bodyHeight,
661
+ false
662
+ ),
663
+ ...holes.map((hole) => holeWall(hole, d.flangeBottomZ, d.bodyHeight))
664
+ ]);
665
+ const ball = revolve2(
666
+ Array.from({ length: latitude + 1 }, (_, j) => {
667
+ const angle = Math.PI - j * Math.PI / latitude;
668
+ return [
669
+ j === 0 || j === latitude ? 0 : d.ballRadius * Math.sin(angle),
670
+ d.ballCenterZ + d.ballRadius * Math.cos(angle)
671
+ ];
672
+ }),
673
+ segments
674
+ );
675
+ const parts = [
676
+ { name: "housing", color: "#9da4ac", mesh: housing },
677
+ { name: "load ball", color: "#d5d9df", mesh: ball }
678
+ ];
679
+ const positions = [...housing.positions, ...ball.positions];
680
+ const offset = housing.positions.length / 3;
681
+ const indices = [
682
+ ...housing.indices,
683
+ ...ball.indices.map((index) => index + offset)
684
+ ];
685
+ return { positions, indices, parts };
686
+ }
687
+ function revolve2(profile, segments, omittedEdges = /* @__PURE__ */ new Set()) {
688
+ const positions = [];
689
+ const indices = [];
690
+ const rings = profile.map(([radius, z]) => {
691
+ const start = positions.length / 3;
692
+ const count = radius === 0 ? 1 : segments;
693
+ for (let i = 0; i < count; i++) {
694
+ const angle = i * Math.PI * 2 / segments;
695
+ positions.push(radius * Math.cos(angle), radius * Math.sin(angle), z);
696
+ }
697
+ return { start, count };
698
+ });
699
+ for (let j = 0; j < rings.length; j++) {
700
+ if (omittedEdges.has(j)) continue;
701
+ const a = rings[j];
702
+ const b = rings[(j + 1) % rings.length];
703
+ if (a.count === 1 && b.count === 1) continue;
704
+ for (let i = 0; i < segments; i++) {
705
+ const next = (i + 1) % segments;
706
+ if (a.count === 1) indices.push(a.start, b.start + next, b.start + i);
707
+ else if (b.count === 1) indices.push(a.start + i, a.start + next, b.start);
708
+ else
709
+ indices.push(
710
+ a.start + i,
711
+ a.start + next,
712
+ b.start + next,
713
+ a.start + i,
714
+ b.start + next,
715
+ b.start + i
716
+ );
717
+ }
718
+ }
719
+ return { positions, indices };
720
+ }
721
+ function cap(outer, holes, z, reverse) {
722
+ const loops = [outer, ...holes];
723
+ const starts = [];
724
+ let count = outer.length;
725
+ for (const hole of holes) {
726
+ starts.push(count);
727
+ count += hole.length;
728
+ }
729
+ const points = loops.flat();
730
+ const indices = earcut2(points.flat(), starts);
731
+ if (reverse)
732
+ for (let i = 0; i < indices.length; i += 3)
733
+ [indices[i + 1], indices[i + 2]] = [indices[i + 2], indices[i + 1]];
734
+ return { positions: points.flatMap(([x, y]) => [x, y, z]), indices };
735
+ }
736
+ function holeWall(loop, bottom, top) {
737
+ const positions = [bottom, top].flatMap(
738
+ (z) => loop.flatMap(([x, y]) => [x, y, z])
739
+ );
740
+ const indices = [];
741
+ const count = loop.length;
742
+ for (let i = 0; i < count; i++) {
743
+ const next = (i + 1) % count;
744
+ indices.push(i, next + count, next, i, i + count, next + count);
745
+ }
746
+ return { positions, indices };
747
+ }
748
+
749
+ // lib/models/balltransferunit/BallTransferUnit.tsx
750
+ function createBallTransferUnitGeom(input = {}) {
751
+ return indexedMeshToGeom3(createBallTransferUnitMesh(input));
752
+ }
753
+ function BallTransferUnit({ color, ...props }) {
754
+ const { parts } = createBallTransferUnitMesh(props);
755
+ return /* @__PURE__ */ jsx(Fragment2, { children: parts.map((part) => /* @__PURE__ */ jsx(Colorize, { color: color ?? part.color, children: /* @__PURE__ */ jsx(Custom, { geometry: indexedMeshToGeom3(part.mesh) }) }, part.name)) });
756
+ }
757
+
758
+ // lib/models/balltransferunit/register.tsx
759
+ var model2 = defineModelRenderer({
760
+ name: "balltransferunit",
761
+ schema: ballTransferUnitModelDefinitionSchema,
762
+ render: ({ fn, ...props }) => /* @__PURE__ */ jsx(BallTransferUnit, { ...props }),
763
+ pads: "none"
764
+ });
765
+ function register2(registry) {
766
+ registry.register(model2);
767
+ }
768
+
507
769
  // lib/models/buttonscrew/register.tsx
508
770
  import { buttonScrewModelDefinitionSchema } from "@tscircuit/modelprinter";
509
771
 
@@ -538,7 +800,7 @@ function surface(segments) {
538
800
  indices.push(a + i, a + n, b + n, a + i, b + n, b + i);
539
801
  }
540
802
  };
541
- const cap = (start, z, up) => {
803
+ const cap2 = (start, z, up) => {
542
804
  const center = positions.length / 3;
543
805
  positions.push(0, 0, z);
544
806
  for (let i = 0; i < segments; i++) {
@@ -546,7 +808,7 @@ function surface(segments) {
546
808
  indices.push(center, start + (up ? i : n), start + (up ? n : i));
547
809
  }
548
810
  };
549
- return { positions, indices, ring, connect, cap };
811
+ return { positions, indices, ring, connect, cap: cap2 };
550
812
  }
551
813
  function hexRadius(angle, acrossFlats) {
552
814
  const period = Math.PI / 3;
@@ -628,14 +890,14 @@ function ButtonScrew({ color = "#737e8f", ...props }) {
628
890
  }
629
891
 
630
892
  // lib/models/buttonscrew/register.tsx
631
- var model2 = defineModelRenderer({
893
+ var model3 = defineModelRenderer({
632
894
  name: "buttonscrew",
633
895
  schema: buttonScrewModelDefinitionSchema,
634
896
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(ButtonScrew, { ...props }),
635
897
  pads: "none"
636
898
  });
637
- function register2(registry) {
638
- registry.register(model2);
899
+ function register3(registry) {
900
+ registry.register(model3);
639
901
  }
640
902
 
641
903
  // lib/models/cablegrommet/register.tsx
@@ -710,14 +972,14 @@ function CableGrommet({
710
972
  }
711
973
 
712
974
  // lib/models/cablegrommet/register.tsx
713
- var model3 = defineModelRenderer({
975
+ var model4 = defineModelRenderer({
714
976
  name: "cablegrommet",
715
977
  schema: cableGrommetModelDefinitionSchema,
716
978
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(CableGrommet, { ...props }),
717
979
  pads: "none"
718
980
  });
719
- function register3(registry) {
720
- registry.register(model3);
981
+ function register4(registry) {
982
+ registry.register(model4);
721
983
  }
722
984
 
723
985
  // lib/models/clampingshaftcollar/register.tsx
@@ -1018,14 +1280,14 @@ function ClampingShaftCollar({
1018
1280
  }
1019
1281
 
1020
1282
  // lib/models/clampingshaftcollar/register.tsx
1021
- var model4 = defineModelRenderer({
1283
+ var model5 = defineModelRenderer({
1022
1284
  name: "clampingshaftcollar",
1023
1285
  schema: clampingShaftCollarModelDefinitionSchema,
1024
1286
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(ClampingShaftCollar, { ...props }),
1025
1287
  pads: "none"
1026
1288
  });
1027
- function register4(registry) {
1028
- registry.register(model4);
1289
+ function register5(registry) {
1290
+ registry.register(model5);
1029
1291
  }
1030
1292
 
1031
1293
  // lib/models/compressionspring/register.tsx
@@ -1039,7 +1301,7 @@ import {
1039
1301
  } from "@tscircuit/modelprinter";
1040
1302
 
1041
1303
  // lib/mechanical/clip-mesh-to-z-range.ts
1042
- import earcut from "earcut";
1304
+ import earcut3 from "earcut";
1043
1305
  function clipMeshToZRange(mesh, lower, upper) {
1044
1306
  const originals = [];
1045
1307
  const tolerance = 32 * Number.EPSILON * (upper - lower);
@@ -1140,11 +1402,11 @@ function clipMeshToZRange(mesh, lower, upper) {
1140
1402
  positions[3 * i],
1141
1403
  positions[3 * i + 1]
1142
1404
  ]);
1143
- const cap = earcut(coordinates);
1144
- for (let index = 0; index < cap.length; index += 3) {
1145
- const a = loop[cap[index]];
1146
- let b = loop[cap[index + 1]];
1147
- let c = loop[cap[index + 2]];
1405
+ const cap2 = earcut3(coordinates);
1406
+ for (let index = 0; index < cap2.length; index += 3) {
1407
+ const a = loop[cap2[index]];
1408
+ let b = loop[cap2[index + 1]];
1409
+ let c = loop[cap2[index + 2]];
1148
1410
  const cross = (positions[b * 3] - positions[a * 3]) * (positions[c * 3 + 1] - positions[a * 3 + 1]) - (positions[b * 3 + 1] - positions[a * 3 + 1]) * (positions[c * 3] - positions[a * 3]);
1149
1411
  if (plane === lower && cross > 0 || plane === upper && cross < 0)
1150
1412
  [b, c] = [c, b];
@@ -1231,14 +1493,14 @@ function CompressionSpring({
1231
1493
  }
1232
1494
 
1233
1495
  // lib/models/compressionspring/register.tsx
1234
- var model5 = defineModelRenderer({
1496
+ var model6 = defineModelRenderer({
1235
1497
  name: "compressionspring",
1236
1498
  schema: compressionSpringModelDefinitionSchema,
1237
1499
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(CompressionSpring, { ...props }),
1238
1500
  pads: "none"
1239
1501
  });
1240
- function register5(registry) {
1241
- registry.register(model5);
1502
+ function register6(registry) {
1503
+ registry.register(model6);
1242
1504
  }
1243
1505
 
1244
1506
  // lib/models/flangedbushing/register.tsx
@@ -1294,14 +1556,14 @@ function FlangedBushing({
1294
1556
  }
1295
1557
 
1296
1558
  // lib/models/flangedbushing/register.tsx
1297
- var model6 = defineModelRenderer({
1559
+ var model7 = defineModelRenderer({
1298
1560
  name: "flangedbushing",
1299
1561
  schema: flangedBushingModelDefinitionSchema,
1300
1562
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(FlangedBushing, { ...props }),
1301
1563
  pads: "none"
1302
1564
  });
1303
- function register6(registry) {
1304
- registry.register(model6);
1565
+ function register7(registry) {
1566
+ registry.register(model7);
1305
1567
  }
1306
1568
 
1307
1569
  // lib/models/flatheadscrew/register.tsx
@@ -1357,7 +1619,7 @@ function createFlatHeadScrewMesh(input, options = {}) {
1357
1619
  triangle(a[i], b[n], b[i]);
1358
1620
  }
1359
1621
  };
1360
- const cap = (a, z, up) => {
1622
+ const cap2 = (a, z, up) => {
1361
1623
  const c = vertex(0, 0, z);
1362
1624
  for (let i = 0; i < segments; i++) {
1363
1625
  const n = (i + 1) % segments;
@@ -1398,7 +1660,7 @@ function createFlatHeadScrewMesh(input, options = {}) {
1398
1660
  major - Math.max(0, p.tipChamfer - (z + p.length))
1399
1661
  );
1400
1662
  }, z);
1401
- if (z === -p.length) cap(r, z, false);
1663
+ if (z === -p.length) cap2(r, z, false);
1402
1664
  }
1403
1665
  add(() => major, shaftEnd);
1404
1666
  const filletCenterR = major + p.underHeadRadius;
@@ -1418,7 +1680,7 @@ function createFlatHeadScrewMesh(input, options = {}) {
1418
1680
  add(() => p.headDiameter / 2, 0);
1419
1681
  add(hexRadius3, 0);
1420
1682
  add(hexRadius3, -p.socketDepth);
1421
- cap(previous, -p.socketDepth, true);
1683
+ cap2(previous, -p.socketDepth, true);
1422
1684
  return { positions, indices };
1423
1685
  }
1424
1686
 
@@ -1434,14 +1696,14 @@ function FlatHeadScrew({
1434
1696
  }
1435
1697
 
1436
1698
  // lib/models/flatheadscrew/register.tsx
1437
- var model7 = defineModelRenderer({
1699
+ var model8 = defineModelRenderer({
1438
1700
  name: "flatheadscrew",
1439
1701
  schema: flatHeadScrewModelDefinitionSchema,
1440
1702
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(FlatHeadScrew, { ...props }),
1441
1703
  pads: "none"
1442
1704
  });
1443
- function register7(registry) {
1444
- registry.register(model7);
1705
+ function register8(registry) {
1706
+ registry.register(model8);
1445
1707
  }
1446
1708
 
1447
1709
  // lib/models/flexscreen/register.tsx
@@ -2119,14 +2381,14 @@ var FlexScreen = (props) => {
2119
2381
  };
2120
2382
 
2121
2383
  // lib/models/flexscreen/register.tsx
2122
- var model8 = defineModelRenderer({
2384
+ var model9 = defineModelRenderer({
2123
2385
  name: "flexscreen",
2124
2386
  schema: flexScreenModelDefinitionSchema,
2125
2387
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(FlexScreen, { ...props }),
2126
2388
  pads: "footprinter"
2127
2389
  });
2128
- function register8(registry) {
2129
- registry.register(model8);
2390
+ function register9(registry) {
2391
+ registry.register(model9);
2130
2392
  }
2131
2393
 
2132
2394
  // lib/models/helicalgear/register.tsx
@@ -2143,7 +2405,7 @@ import {
2143
2405
  getSpurGearDimensions,
2144
2406
  spurGearModelPropsSchema
2145
2407
  } from "@tscircuit/modelprinter";
2146
- import earcut2 from "earcut";
2408
+ import earcut4 from "earcut";
2147
2409
  function createSpurGearMesh(input) {
2148
2410
  return createTwistedSpurGearMesh(input);
2149
2411
  }
@@ -2247,9 +2509,9 @@ function createTwistedSpurGearMesh(input, twist = 0, segmentsPerTurn = 32) {
2247
2509
  );
2248
2510
  }
2249
2511
  };
2250
- const cap = (outer, outerStart, upward, inner) => {
2512
+ const cap2 = (outer, outerStart, upward, inner) => {
2251
2513
  const points = inner ? [...outer, ...inner.points] : outer;
2252
- const triangles = earcut2(
2514
+ const triangles = earcut4(
2253
2515
  points.flatMap(([x, y]) => [x, y]),
2254
2516
  inner ? [outer.length] : []
2255
2517
  );
@@ -2287,7 +2549,7 @@ function createTwistedSpurGearMesh(input, twist = 0, segmentsPerTurn = 32) {
2287
2549
  const boreBottom = bore ? ring(bore, 0) : void 0;
2288
2550
  const boreTop = bore ? ring(bore, height10) : void 0;
2289
2551
  if (bore) connect(boreBottom, boreTop, bore.length, true);
2290
- cap(
2552
+ cap2(
2291
2553
  outline,
2292
2554
  bottom,
2293
2555
  false,
@@ -2297,12 +2559,12 @@ function createTwistedSpurGearMesh(input, twist = 0, segmentsPerTurn = 32) {
2297
2559
  const hub = circle2(props.hubDiameter / 2);
2298
2560
  const hubBottom = ring(hub, props.faceWidth);
2299
2561
  const hubTop = ring(hub, height10);
2300
- cap(topOutline, top, true, { points: hub, start: hubBottom });
2562
+ cap2(topOutline, top, true, { points: hub, start: hubBottom });
2301
2563
  connect(hubBottom, hubTop, hub.length);
2302
2564
  if (bore) connect(hubTop, boreTop, hub.length);
2303
- else cap(hub, hubTop, true);
2565
+ else cap2(hub, hubTop, true);
2304
2566
  } else
2305
- cap(
2567
+ cap2(
2306
2568
  topOutline,
2307
2569
  top,
2308
2570
  true,
@@ -2332,14 +2594,14 @@ function HelicalGear({ color = "#737e8f", ...props }) {
2332
2594
  }
2333
2595
 
2334
2596
  // lib/models/helicalgear/register.tsx
2335
- var model9 = defineModelRenderer({
2597
+ var model10 = defineModelRenderer({
2336
2598
  name: "helicalgear",
2337
2599
  schema: helicalGearModelDefinitionSchema,
2338
2600
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(HelicalGear, { ...props }),
2339
2601
  pads: "none"
2340
2602
  });
2341
- function register9(registry) {
2342
- registry.register(model9);
2603
+ function register10(registry) {
2604
+ registry.register(model10);
2343
2605
  }
2344
2606
 
2345
2607
  // lib/models/hexbolt/register.tsx
@@ -2395,7 +2657,7 @@ function createHexBoltMesh(input, options = {}) {
2395
2657
  triangle(a[i], b[n], b[i]);
2396
2658
  }
2397
2659
  };
2398
- const cap = (a, z, up) => {
2660
+ const cap2 = (a, z, up) => {
2399
2661
  const c = vertex(0, 0, z);
2400
2662
  for (let i = 0; i < segments; i++) {
2401
2663
  const n = (i + 1) % segments;
@@ -2436,7 +2698,7 @@ function createHexBoltMesh(input, options = {}) {
2436
2698
  major - Math.max(0, p.tipChamfer - (z + p.length))
2437
2699
  );
2438
2700
  }, z);
2439
- if (z === -p.length) cap(r, z, false);
2701
+ if (z === -p.length) cap2(r, z, false);
2440
2702
  }
2441
2703
  add(() => major, shaftEnd);
2442
2704
  const filletCenterR = major + p.underHeadRadius;
@@ -2467,7 +2729,7 @@ function createHexBoltMesh(input, options = {}) {
2467
2729
  z
2468
2730
  );
2469
2731
  }
2470
- cap(previous, p.headHeight, true);
2732
+ cap2(previous, p.headHeight, true);
2471
2733
  return { positions, indices };
2472
2734
  }
2473
2735
 
@@ -2480,14 +2742,14 @@ function HexBolt({ color = "#737e8f", ...props }) {
2480
2742
  }
2481
2743
 
2482
2744
  // lib/models/hexbolt/register.tsx
2483
- var model10 = defineModelRenderer({
2745
+ var model11 = defineModelRenderer({
2484
2746
  name: "hexbolt",
2485
2747
  schema: hexBoltModelDefinitionSchema,
2486
2748
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(HexBolt, { ...props }),
2487
2749
  pads: "none"
2488
2750
  });
2489
- function register10(registry) {
2490
- registry.register(model10);
2751
+ function register11(registry) {
2752
+ registry.register(model11);
2491
2753
  }
2492
2754
 
2493
2755
  // lib/models/hexnut/register.tsx
@@ -2524,7 +2786,7 @@ function surface2(segments) {
2524
2786
  indices.push(a + i, a + n, b + n, a + i, b + n, b + i);
2525
2787
  }
2526
2788
  };
2527
- const cap = (start, z, up) => {
2789
+ const cap2 = (start, z, up) => {
2528
2790
  const center = positions.length / 3;
2529
2791
  positions.push(0, 0, z);
2530
2792
  for (let i = 0; i < segments; i++) {
@@ -2532,7 +2794,7 @@ function surface2(segments) {
2532
2794
  indices.push(center, start + (up ? i : n), start + (up ? n : i));
2533
2795
  }
2534
2796
  };
2535
- return { positions, indices, ring, connect, cap };
2797
+ return { positions, indices, ring, connect, cap: cap2 };
2536
2798
  }
2537
2799
  function hexRadius2(angle, acrossFlats) {
2538
2800
  const period = Math.PI / 3;
@@ -2576,7 +2838,10 @@ function createHexNutMesh(input, options = {}) {
2576
2838
  previous = current;
2577
2839
  }
2578
2840
  const levels = new Set(
2579
- props.showThreads ? Array.from({ length: steps + 1 }, (_, i) => d.height * i / steps) : [0, d.height]
2841
+ props.showThreads ? Array.from(
2842
+ { length: steps + 1 },
2843
+ (_, i) => i === steps ? d.height : d.height * i / steps
2844
+ ) : [0, d.height]
2580
2845
  );
2581
2846
  levels.add(d.boreChamferDepth);
2582
2847
  levels.add(d.height - d.boreChamferDepth);
@@ -2610,14 +2875,14 @@ function HexNut({ color = "#737e8f", ...props }) {
2610
2875
  }
2611
2876
 
2612
2877
  // lib/models/hexnut/register.tsx
2613
- var model11 = defineModelRenderer({
2878
+ var model12 = defineModelRenderer({
2614
2879
  name: "hexnut",
2615
2880
  schema: hexNutModelDefinitionSchema,
2616
2881
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(HexNut, { ...props }),
2617
2882
  pads: "none"
2618
2883
  });
2619
- function register11(registry) {
2620
- registry.register(model11);
2884
+ function register12(registry) {
2885
+ registry.register(model12);
2621
2886
  }
2622
2887
 
2623
2888
  // lib/models/hexsocketbolt/register.tsx
@@ -2666,7 +2931,7 @@ var createHexSocketBoltMesh = (input) => {
2666
2931
  indices.push(a + i, a + next, b + next, a + i, b + next, b + i);
2667
2932
  }
2668
2933
  };
2669
- const cap = (start, z, upward) => {
2934
+ const cap2 = (start, z, upward) => {
2670
2935
  const center = positions.length / 3;
2671
2936
  positions.push(0, 0, z);
2672
2937
  for (let i = 0; i < segments; i++) {
@@ -2696,7 +2961,7 @@ var createHexSocketBoltMesh = (input) => {
2696
2961
  const tipCut = tipBevel * Math.max(0, 1 - (z + length) / tipBevel);
2697
2962
  return radius - (showThreads ? groove * endRamp : 0) - tipCut;
2698
2963
  });
2699
- if (previous < 0) cap(current, z, false);
2964
+ if (previous < 0) cap2(current, z, false);
2700
2965
  else connect(previous, current);
2701
2966
  previous = current;
2702
2967
  }
@@ -2713,7 +2978,7 @@ var createHexSocketBoltMesh = (input) => {
2713
2978
  addRing(headHeight, (angle) => hexRadius3(angle, socketWidth + bevel));
2714
2979
  addRing(headHeight - bevel / 2, (angle) => hexRadius3(angle, socketWidth));
2715
2980
  addRing(headHeight - socketDepth, (angle) => hexRadius3(angle, socketWidth));
2716
- cap(previous, headHeight - socketDepth, true);
2981
+ cap2(previous, headHeight - socketDepth, true);
2717
2982
  return { positions, indices };
2718
2983
  };
2719
2984
 
@@ -2729,14 +2994,14 @@ function HexSocketBolt({
2729
2994
  }
2730
2995
 
2731
2996
  // lib/models/hexsocketbolt/register.tsx
2732
- var model12 = defineModelRenderer({
2997
+ var model13 = defineModelRenderer({
2733
2998
  name: "hexsocketbolt",
2734
2999
  schema: hexSocketBoltModelDefinitionSchema,
2735
3000
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(HexSocketBolt, { ...props }),
2736
3001
  pads: "none"
2737
3002
  });
2738
- function register12(registry) {
2739
- registry.register(model12);
3003
+ function register13(registry) {
3004
+ registry.register(model13);
2740
3005
  }
2741
3006
 
2742
3007
  // lib/models/hollowpositioningarmtube/register.tsx
@@ -2857,14 +3122,14 @@ function HollowPositioningArmTube({
2857
3122
  }
2858
3123
 
2859
3124
  // lib/models/hollowpositioningarmtube/register.tsx
2860
- var model13 = defineModelRenderer({
3125
+ var model14 = defineModelRenderer({
2861
3126
  name: "hollowpositioningarmtube",
2862
3127
  schema: hollowPositioningArmTubeModelDefinitionSchema,
2863
3128
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(HollowPositioningArmTube, { ...props }),
2864
3129
  pads: "none"
2865
3130
  });
2866
- function register13(registry) {
2867
- registry.register(model13);
3131
+ function register14(registry) {
3132
+ registry.register(model14);
2868
3133
  }
2869
3134
 
2870
3135
  // lib/models/nema/register.tsx
@@ -3133,14 +3398,14 @@ var NEMA17 = (props) => /* @__PURE__ */ jsx(NemaMotor, { ...props, nemaSize: 17
3133
3398
  var NEMA23 = (props) => /* @__PURE__ */ jsx(NemaMotor, { ...props, nemaSize: 23 });
3134
3399
 
3135
3400
  // lib/models/nema/register.tsx
3136
- var model14 = defineModelRenderer({
3401
+ var model15 = defineModelRenderer({
3137
3402
  name: "nema",
3138
3403
  schema: nemaMotorModelDefinitionSchema,
3139
3404
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(NemaMotor, { ...props }),
3140
3405
  pads: "none"
3141
3406
  });
3142
- function register14(registry) {
3143
- registry.register(model14);
3407
+ function register15(registry) {
3408
+ registry.register(model15);
3144
3409
  }
3145
3410
 
3146
3411
  // lib/models/panscrew/register.tsx
@@ -3196,7 +3461,7 @@ function createPanScrewMesh(input, options = {}) {
3196
3461
  triangle(a[i], b[n], b[i]);
3197
3462
  }
3198
3463
  };
3199
- const cap = (a, z, up) => {
3464
+ const cap2 = (a, z, up) => {
3200
3465
  const c = vertex(0, 0, z);
3201
3466
  for (let i = 0; i < segments; i++) {
3202
3467
  const n = (i + 1) % segments;
@@ -3237,7 +3502,7 @@ function createPanScrewMesh(input, options = {}) {
3237
3502
  major - Math.max(0, p.tipChamfer - (z + p.length))
3238
3503
  );
3239
3504
  }, z);
3240
- if (z === -p.length) cap(r, z, false);
3505
+ if (z === -p.length) cap2(r, z, false);
3241
3506
  }
3242
3507
  add(() => major, shaftEnd);
3243
3508
  const filletCenterR = major + p.underHeadRadius;
@@ -3352,14 +3617,14 @@ function PanScrew({ color = "#737e8f", ...props }) {
3352
3617
  }
3353
3618
 
3354
3619
  // lib/models/panscrew/register.tsx
3355
- var model15 = defineModelRenderer({
3620
+ var model16 = defineModelRenderer({
3356
3621
  name: "panscrew",
3357
3622
  schema: panScrewModelDefinitionSchema,
3358
3623
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(PanScrew, { ...props }),
3359
3624
  pads: "none"
3360
3625
  });
3361
- function register15(registry) {
3362
- registry.register(model15);
3626
+ function register16(registry) {
3627
+ registry.register(model16);
3363
3628
  }
3364
3629
 
3365
3630
  // lib/models/plainbushing/register.tsx
@@ -3422,14 +3687,14 @@ function PlainBushing({
3422
3687
  }
3423
3688
 
3424
3689
  // lib/models/plainbushing/register.tsx
3425
- var model16 = defineModelRenderer({
3690
+ var model17 = defineModelRenderer({
3426
3691
  name: "plainbushing",
3427
3692
  schema: plainBushingModelDefinitionSchema,
3428
3693
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(PlainBushing, { ...props }),
3429
3694
  pads: "none"
3430
3695
  });
3431
- function register16(registry) {
3432
- registry.register(model16);
3696
+ function register17(registry) {
3697
+ registry.register(model17);
3433
3698
  }
3434
3699
 
3435
3700
  // lib/models/rigidcoupler/register.tsx
@@ -3473,14 +3738,14 @@ function RigidCoupler({
3473
3738
  }
3474
3739
 
3475
3740
  // lib/models/rigidcoupler/register.tsx
3476
- var model17 = defineModelRenderer({
3741
+ var model18 = defineModelRenderer({
3477
3742
  name: "rigidcoupler",
3478
3743
  schema: rigidCouplerModelDefinitionSchema,
3479
3744
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(RigidCoupler, { ...props }),
3480
3745
  pads: "none"
3481
3746
  });
3482
- function register17(registry) {
3483
- registry.register(model17);
3747
+ function register18(registry) {
3748
+ registry.register(model18);
3484
3749
  }
3485
3750
 
3486
3751
  // lib/models/shaftcollar/register.tsx
@@ -3519,21 +3784,21 @@ function ShaftCollar({ color = "#737e8f", ...props }) {
3519
3784
  }
3520
3785
 
3521
3786
  // lib/models/shaftcollar/register.tsx
3522
- var model18 = defineModelRenderer({
3787
+ var model19 = defineModelRenderer({
3523
3788
  name: "shaftcollar",
3524
3789
  schema: shaftCollarModelDefinitionSchema,
3525
3790
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(ShaftCollar, { ...props }),
3526
3791
  pads: "none"
3527
3792
  });
3528
- function register18(registry) {
3529
- registry.register(model18);
3793
+ function register19(registry) {
3794
+ registry.register(model19);
3530
3795
  }
3531
3796
 
3532
3797
  // lib/models/sheetmetal/register.tsx
3533
3798
  import { sheetMetalModelDefinitionSchema } from "@tscircuit/modelprinter";
3534
3799
 
3535
3800
  // lib/mechanical/sheet-metal-mesh.ts
3536
- import earcut3 from "earcut";
3801
+ import earcut5 from "earcut";
3537
3802
  import {
3538
3803
  sheetMetalModelPropsSchema
3539
3804
  } from "@tscircuit/modelprinter";
@@ -3601,7 +3866,7 @@ function createSheetMetalMesh(input) {
3601
3866
  const loops = [outline, ...holes.map((hole) => [...hole].reverse())];
3602
3867
  const points = loops.flat();
3603
3868
  const starts = holes.map((_, i) => 4 + i * 64);
3604
- const triangles = earcut3(
3869
+ const triangles = earcut5(
3605
3870
  points.flatMap((p) => [p.u, p.v]),
3606
3871
  starts
3607
3872
  );
@@ -3686,14 +3951,14 @@ function SheetMetal({ color = "#737e8f", ...props }) {
3686
3951
  }
3687
3952
 
3688
3953
  // lib/models/sheetmetal/register.tsx
3689
- var model19 = defineModelRenderer({
3954
+ var model20 = defineModelRenderer({
3690
3955
  name: "sheetmetal",
3691
3956
  schema: sheetMetalModelDefinitionSchema,
3692
3957
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(SheetMetal, { ...props }),
3693
3958
  pads: "none"
3694
3959
  });
3695
- function register19(registry) {
3696
- registry.register(model19);
3960
+ function register20(registry) {
3961
+ registry.register(model20);
3697
3962
  }
3698
3963
 
3699
3964
  // lib/models/spurgear/register.tsx
@@ -3708,14 +3973,14 @@ function SpurGear({ color = "#737e8f", ...props }) {
3708
3973
  }
3709
3974
 
3710
3975
  // lib/models/spurgear/register.tsx
3711
- var model20 = defineModelRenderer({
3976
+ var model21 = defineModelRenderer({
3712
3977
  name: "spurgear",
3713
3978
  schema: spurGearModelDefinitionSchema,
3714
3979
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(SpurGear, { ...props }),
3715
3980
  pads: "none"
3716
3981
  });
3717
- function register20(registry) {
3718
- registry.register(model20);
3982
+ function register21(registry) {
3983
+ registry.register(model21);
3719
3984
  }
3720
3985
 
3721
3986
  // lib/models/threadedrod/register.tsx
@@ -3752,7 +4017,7 @@ function surface3(segments) {
3752
4017
  indices.push(a + i, a + n, b + n, a + i, b + n, b + i);
3753
4018
  }
3754
4019
  };
3755
- const cap = (start, z, up) => {
4020
+ const cap2 = (start, z, up) => {
3756
4021
  const center = positions.length / 3;
3757
4022
  positions.push(0, 0, z);
3758
4023
  for (let i = 0; i < segments; i++) {
@@ -3760,7 +4025,7 @@ function surface3(segments) {
3760
4025
  indices.push(center, start + (up ? i : n), start + (up ? n : i));
3761
4026
  }
3762
4027
  };
3763
- return { positions, indices, ring, connect, cap };
4028
+ return { positions, indices, ring, connect, cap: cap2 };
3764
4029
  }
3765
4030
  function threadDistance3(z, angle, pitch, hand = 1) {
3766
4031
  const phase = ((z / pitch - hand * angle / (2 * Math.PI)) % 1 + 1) % 1;
@@ -3812,14 +4077,14 @@ function ThreadedRod({ color = "#737e8f", ...props }) {
3812
4077
  }
3813
4078
 
3814
4079
  // lib/models/threadedrod/register.tsx
3815
- var model21 = defineModelRenderer({
4080
+ var model22 = defineModelRenderer({
3816
4081
  name: "threadedrod",
3817
4082
  schema: threadedRodModelDefinitionSchema,
3818
4083
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(ThreadedRod, { ...props }),
3819
4084
  pads: "none"
3820
4085
  });
3821
- function register21(registry) {
3822
- registry.register(model21);
4086
+ function register22(registry) {
4087
+ registry.register(model22);
3823
4088
  }
3824
4089
 
3825
4090
  // lib/models/torsionspring/register.tsx
@@ -3916,14 +4181,14 @@ function TorsionSpring({
3916
4181
  }
3917
4182
 
3918
4183
  // lib/models/torsionspring/register.tsx
3919
- var model22 = defineModelRenderer({
4184
+ var model23 = defineModelRenderer({
3920
4185
  name: "torsionspring",
3921
4186
  schema: torsionSpringModelDefinitionSchema,
3922
4187
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(TorsionSpring, { ...props }),
3923
4188
  pads: "none"
3924
4189
  });
3925
- function register22(registry) {
3926
- registry.register(model22);
4190
+ function register23(registry) {
4191
+ registry.register(model23);
3927
4192
  }
3928
4193
 
3929
4194
  // lib/models/tslotextrusion/register.tsx
@@ -3933,91 +4198,6 @@ import { tSlotExtrusionModelDefinitionSchema } from "@tscircuit/modelprinter";
3933
4198
  import {
3934
4199
  tSlotExtrusionModelPropsSchema
3935
4200
  } from "@tscircuit/modelprinter";
3936
-
3937
- // lib/mechanical/extrude-planar-profile.ts
3938
- import earcut4 from "earcut";
3939
- function extrudePlanarProfile({
3940
- outer,
3941
- holes = [],
3942
- start,
3943
- end,
3944
- project = (u, v, depth) => [u, v, depth],
3945
- reverse = false,
3946
- skipWall = () => false
3947
- }) {
3948
- const oriented = (loop, clockwise) => {
3949
- loop = loop.filter((point, index) => {
3950
- const previous = loop[(index + loop.length - 1) % loop.length];
3951
- return point[0] !== previous[0] || point[1] !== previous[1];
3952
- });
3953
- const area = loop.reduce((sum, a, index) => {
3954
- const b = loop[(index + 1) % loop.length];
3955
- return sum + a[0] * b[1] - a[1] * b[0];
3956
- }, 0);
3957
- if (!Number.isFinite(area) || area === 0)
3958
- throw new Error("Profile exceeds mesh resolution limits");
3959
- return area < 0 === clockwise ? loop : [...loop].reverse();
3960
- };
3961
- const loops = [oriented(outer, false), ...holes.map((h2) => oriented(h2, true))];
3962
- const points = loops.flat();
3963
- const holeStarts = [];
3964
- let count = loops[0].length;
3965
- for (const hole of loops.slice(1)) {
3966
- holeStarts.push(count);
3967
- count += hole.length;
3968
- }
3969
- const faces = earcut4(points.flat(), holeStarts);
3970
- const positions = [start, end].flatMap(
3971
- (depth) => points.flatMap(([u, v]) => project(u, v, depth))
3972
- );
3973
- const indices = [];
3974
- for (let i = 0; i < faces.length; i += 3) {
3975
- const [a, b, c] = faces.slice(i, i + 3);
3976
- indices.push(a, c, b, a + count, b + count, c + count);
3977
- }
3978
- let offset = 0;
3979
- for (const [loopIndex, loop] of loops.entries()) {
3980
- for (let i = 0; i < loop.length; i++) {
3981
- const next = (i + 1) % loop.length;
3982
- if (loopIndex === 0 && skipWall(loop[i], loop[next])) continue;
3983
- const a = offset + i;
3984
- const b = offset + next;
3985
- indices.push(a, b, b + count, a, b + count, a + count);
3986
- }
3987
- offset += loop.length;
3988
- }
3989
- if (reverse)
3990
- for (let i = 0; i < indices.length; i += 3)
3991
- [indices[i + 1], indices[i + 2]] = [indices[i + 2], indices[i + 1]];
3992
- return { positions, indices };
3993
- }
3994
- function joinProfileMeshes(meshes) {
3995
- const positions = [];
3996
- const indices = [];
3997
- const vertices = /* @__PURE__ */ new Map();
3998
- for (const mesh of meshes) {
3999
- for (const index of mesh.indices) {
4000
- const point = mesh.positions.slice(index * 3, index * 3 + 3);
4001
- const key = point.map((value) => value.toFixed(12)).join(",");
4002
- let shared = vertices.get(key);
4003
- if (shared === void 0) {
4004
- shared = positions.length / 3;
4005
- vertices.set(key, shared);
4006
- positions.push(...point);
4007
- }
4008
- indices.push(shared);
4009
- }
4010
- }
4011
- return { positions, indices };
4012
- }
4013
- function circularProfile(x, y, radius, segments = 96) {
4014
- return Array.from({ length: segments }, (_, index) => {
4015
- const angle = index * 2 * Math.PI / segments;
4016
- return [x + radius * Math.cos(angle), y + radius * Math.sin(angle)];
4017
- });
4018
- }
4019
-
4020
- // lib/models/tslotextrusion/mesh.ts
4021
4201
  function createTSlotExtrusionMesh(input = {}) {
4022
4202
  const props = tSlotExtrusionModelPropsSchema.parse(input);
4023
4203
  const { width: width10, height: height10, length, cornerRadius, lipThickness, pocketDepth } = props;
@@ -4073,14 +4253,14 @@ function TSlotExtrusion({
4073
4253
  }
4074
4254
 
4075
4255
  // lib/models/tslotextrusion/register.tsx
4076
- var model23 = defineModelRenderer({
4256
+ var model24 = defineModelRenderer({
4077
4257
  name: "tslotextrusion",
4078
4258
  schema: tSlotExtrusionModelDefinitionSchema,
4079
4259
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(TSlotExtrusion, { ...props }),
4080
4260
  pads: "none"
4081
4261
  });
4082
- function register23(registry) {
4083
- registry.register(model23);
4262
+ function register24(registry) {
4263
+ registry.register(model24);
4084
4264
  }
4085
4265
 
4086
4266
  // lib/models/tslotgusset/register.tsx
@@ -4133,14 +4313,14 @@ function TSlotGusset({ color = "#8995a3", ...props }) {
4133
4313
  }
4134
4314
 
4135
4315
  // lib/models/tslotgusset/register.tsx
4136
- var model24 = defineModelRenderer({
4316
+ var model25 = defineModelRenderer({
4137
4317
  name: "tslotgusset",
4138
4318
  schema: tSlotGussetModelDefinitionSchema,
4139
4319
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(TSlotGusset, { ...props }),
4140
4320
  pads: "none"
4141
4321
  });
4142
- function register24(registry) {
4143
- registry.register(model24);
4322
+ function register25(registry) {
4323
+ registry.register(model25);
4144
4324
  }
4145
4325
 
4146
4326
  // lib/models/tslotinsidecorner/register.tsx
@@ -4220,14 +4400,14 @@ function TSlotInsideCorner({
4220
4400
  }
4221
4401
 
4222
4402
  // lib/models/tslotinsidecorner/register.tsx
4223
- var model25 = defineModelRenderer({
4403
+ var model26 = defineModelRenderer({
4224
4404
  name: "tslotinsidecorner",
4225
4405
  schema: tSlotInsideCornerModelDefinitionSchema,
4226
4406
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(TSlotInsideCorner, { ...props }),
4227
4407
  pads: "none"
4228
4408
  });
4229
- function register25(registry) {
4230
- registry.register(model25);
4409
+ function register26(registry) {
4410
+ registry.register(model26);
4231
4411
  }
4232
4412
 
4233
4413
  // lib/models/wormgear/register.tsx
@@ -4238,7 +4418,7 @@ import {
4238
4418
  getWormGearDimensions,
4239
4419
  wormGearModelPropsSchema
4240
4420
  } from "@tscircuit/modelprinter";
4241
- import earcut5 from "earcut";
4421
+ import earcut6 from "earcut";
4242
4422
  var createWormGearMesh = (input) => {
4243
4423
  const props = wormGearModelPropsSchema.parse(input);
4244
4424
  const { outsideDiameter, rootDiameter, axialPitch, lead, toothThickness } = getWormGearDimensions(props);
@@ -4338,7 +4518,7 @@ var createWormGearMesh = (input) => {
4338
4518
  }
4339
4519
  const top = previous;
4340
4520
  if (props.boreDiameter === 0) {
4341
- const cap = (boundary, z, upward) => {
4521
+ const cap2 = (boundary, z, upward) => {
4342
4522
  const center = positions.length / 3;
4343
4523
  positions.push(0, 0, z);
4344
4524
  for (let index = 0; index < count; index++) {
@@ -4350,8 +4530,8 @@ var createWormGearMesh = (input) => {
4350
4530
  );
4351
4531
  }
4352
4532
  };
4353
- cap(bottom, 0, false);
4354
- cap(top, props.length, true);
4533
+ cap2(bottom, 0, false);
4534
+ cap2(top, props.length, true);
4355
4535
  } else {
4356
4536
  const holeCount = props.radialSegments;
4357
4537
  const boreRing = (z) => {
@@ -4379,7 +4559,7 @@ var createWormGearMesh = (input) => {
4379
4559
  holeTop + next
4380
4560
  );
4381
4561
  }
4382
- const cap = (boundary, hole, upward) => {
4562
+ const cap2 = (boundary, hole, upward) => {
4383
4563
  const vertices = Array.from(
4384
4564
  { length: count },
4385
4565
  (_, index) => boundary + index
@@ -4391,7 +4571,7 @@ var createWormGearMesh = (input) => {
4391
4571
  positions[vertex * 3],
4392
4572
  positions[vertex * 3 + 1]
4393
4573
  ]);
4394
- const triangles = earcut5(flat, [count], 2);
4574
+ const triangles = earcut6(flat, [count], 2);
4395
4575
  for (let index = 0; index < triangles.length; index += 3) {
4396
4576
  const a = vertices[triangles[index]];
4397
4577
  const b = vertices[triangles[index + 1]];
@@ -4404,8 +4584,8 @@ var createWormGearMesh = (input) => {
4404
4584
  );
4405
4585
  }
4406
4586
  };
4407
- cap(bottom, holeBottom, false);
4408
- cap(top, holeTop, true);
4587
+ cap2(bottom, holeBottom, false);
4588
+ cap2(top, holeTop, true);
4409
4589
  }
4410
4590
  return { positions, indices };
4411
4591
  };
@@ -4419,14 +4599,14 @@ function WormGear({ color = "#737e8f", ...props }) {
4419
4599
  }
4420
4600
 
4421
4601
  // lib/models/wormgear/register.tsx
4422
- var model26 = defineModelRenderer({
4602
+ var model27 = defineModelRenderer({
4423
4603
  name: "wormgear",
4424
4604
  schema: wormGearModelDefinitionSchema,
4425
4605
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(WormGear, { ...props }),
4426
4606
  pads: "none"
4427
4607
  });
4428
- function register26(registry) {
4429
- registry.register(model26);
4608
+ function register27(registry) {
4609
+ registry.register(model27);
4430
4610
  }
4431
4611
 
4432
4612
  // lib/generated/model-renderers.ts
@@ -4457,6 +4637,7 @@ function registerAllModelRenderers(registry) {
4457
4637
  register24(registry);
4458
4638
  register25(registry);
4459
4639
  register26(registry);
4640
+ register27(registry);
4460
4641
  }
4461
4642
 
4462
4643
  // lib/default-model-registry.ts
@@ -9994,6 +10175,8 @@ var JSTZH1_5mm = ({
9994
10175
  x: startX + i * pitch,
9995
10176
  y: 0,
9996
10177
  hole_diameter: 0.73,
10178
+ hole_offset_x: 0,
10179
+ hole_offset_y: 0,
9997
10180
  rect_pad_width: 1.03,
9998
10181
  rect_pad_height: 1.73,
9999
10182
  hole_shape: "circle",
@@ -10004,6 +10187,7 @@ var JSTZH1_5mm = ({
10004
10187
  type: "pcb_plated_hole",
10005
10188
  pcb_plated_hole_id: `jstzh_${i}`,
10006
10189
  shape: "pill",
10190
+ ccw_rotation: 0,
10007
10191
  x: startX + i * pitch,
10008
10192
  y: 0,
10009
10193
  hole_height: 0.73,
@@ -10188,6 +10372,8 @@ var JSTPH2_0mm = ({
10188
10372
  x: startX + i * pitch,
10189
10373
  y: 0,
10190
10374
  hole_diameter: 0.73,
10375
+ hole_offset_x: 0,
10376
+ hole_offset_y: 0,
10191
10377
  rect_pad_width: 1.2,
10192
10378
  rect_pad_height: 1.2,
10193
10379
  hole_shape: "circle",
@@ -10198,6 +10384,7 @@ var JSTPH2_0mm = ({
10198
10384
  type: "pcb_plated_hole",
10199
10385
  pcb_plated_hole_id: `jstph_${i}`,
10200
10386
  shape: "pill",
10387
+ ccw_rotation: 0,
10201
10388
  x: startX + i * pitch,
10202
10389
  y: 0,
10203
10390
  hole_height: 0.73,
@@ -11946,7 +12133,7 @@ var UsbCMidmount = ({
11946
12133
  {
11947
12134
  size: [
11948
12135
  0.4,
11949
- "hole_height" in slot ? Math.max(0.3, slot.hole_height - 0.2) : 1,
12136
+ "hole_height" in slot && slot.hole_height !== void 0 ? Math.max(0.3, slot.hole_height - 0.2) : 1,
11950
12137
  tabTop - tabBottom
11951
12138
  ],
11952
12139
  center: [slot.x, slot.y, (tabTop + tabBottom) / 2]
@@ -12013,10 +12200,10 @@ var SOT143 = ({ footprint = "sot143" }) => {
12013
12200
  var Footprinter3d = ({ footprint }) => {
12014
12201
  const modelFn = mp3.string(footprint.split("_", 1)[0]).params().fn;
12015
12202
  if (mp3.getModelNames().includes(modelFn)) {
12016
- const model27 = mp3.string(footprint).json();
12017
- const renderer = modelRendererRegistry.get(model27.fn);
12203
+ const model28 = mp3.string(footprint).json();
12204
+ const renderer = modelRendererRegistry.get(model28.fn);
12018
12205
  if (renderer) {
12019
- return renderer.render(model27);
12206
+ return renderer.render(model28);
12020
12207
  }
12021
12208
  }
12022
12209
  let normalizedFootprint = footprint;
@@ -12968,6 +13155,7 @@ function createJSCADRenderer(jscad8) {
12968
13155
  }
12969
13156
  export {
12970
13157
  BallBearing,
13158
+ BallTransferUnit,
12971
13159
  ButtonScrew,
12972
13160
  CableGrommet,
12973
13161
  ClampingShaftCollar,
@@ -12999,6 +13187,8 @@ export {
12999
13187
  convertCSGToThreeGeom,
13000
13188
  createBallBearingGeom,
13001
13189
  createBallBearingMesh,
13190
+ createBallTransferUnitGeom,
13191
+ createBallTransferUnitMesh,
13002
13192
  createButtonScrewGeom,
13003
13193
  createButtonScrewMesh,
13004
13194
  createCableGrommetGeom,