jscad-electronics 0.0.214 → 0.0.216

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;
@@ -2610,14 +2872,14 @@ function HexNut({ color = "#737e8f", ...props }) {
2610
2872
  }
2611
2873
 
2612
2874
  // lib/models/hexnut/register.tsx
2613
- var model11 = defineModelRenderer({
2875
+ var model12 = defineModelRenderer({
2614
2876
  name: "hexnut",
2615
2877
  schema: hexNutModelDefinitionSchema,
2616
2878
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(HexNut, { ...props }),
2617
2879
  pads: "none"
2618
2880
  });
2619
- function register11(registry) {
2620
- registry.register(model11);
2881
+ function register12(registry) {
2882
+ registry.register(model12);
2621
2883
  }
2622
2884
 
2623
2885
  // lib/models/hexsocketbolt/register.tsx
@@ -2666,7 +2928,7 @@ var createHexSocketBoltMesh = (input) => {
2666
2928
  indices.push(a + i, a + next, b + next, a + i, b + next, b + i);
2667
2929
  }
2668
2930
  };
2669
- const cap = (start, z, upward) => {
2931
+ const cap2 = (start, z, upward) => {
2670
2932
  const center = positions.length / 3;
2671
2933
  positions.push(0, 0, z);
2672
2934
  for (let i = 0; i < segments; i++) {
@@ -2696,7 +2958,7 @@ var createHexSocketBoltMesh = (input) => {
2696
2958
  const tipCut = tipBevel * Math.max(0, 1 - (z + length) / tipBevel);
2697
2959
  return radius - (showThreads ? groove * endRamp : 0) - tipCut;
2698
2960
  });
2699
- if (previous < 0) cap(current, z, false);
2961
+ if (previous < 0) cap2(current, z, false);
2700
2962
  else connect(previous, current);
2701
2963
  previous = current;
2702
2964
  }
@@ -2713,7 +2975,7 @@ var createHexSocketBoltMesh = (input) => {
2713
2975
  addRing(headHeight, (angle) => hexRadius3(angle, socketWidth + bevel));
2714
2976
  addRing(headHeight - bevel / 2, (angle) => hexRadius3(angle, socketWidth));
2715
2977
  addRing(headHeight - socketDepth, (angle) => hexRadius3(angle, socketWidth));
2716
- cap(previous, headHeight - socketDepth, true);
2978
+ cap2(previous, headHeight - socketDepth, true);
2717
2979
  return { positions, indices };
2718
2980
  };
2719
2981
 
@@ -2729,14 +2991,14 @@ function HexSocketBolt({
2729
2991
  }
2730
2992
 
2731
2993
  // lib/models/hexsocketbolt/register.tsx
2732
- var model12 = defineModelRenderer({
2994
+ var model13 = defineModelRenderer({
2733
2995
  name: "hexsocketbolt",
2734
2996
  schema: hexSocketBoltModelDefinitionSchema,
2735
2997
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(HexSocketBolt, { ...props }),
2736
2998
  pads: "none"
2737
2999
  });
2738
- function register12(registry) {
2739
- registry.register(model12);
3000
+ function register13(registry) {
3001
+ registry.register(model13);
2740
3002
  }
2741
3003
 
2742
3004
  // lib/models/hollowpositioningarmtube/register.tsx
@@ -2857,14 +3119,14 @@ function HollowPositioningArmTube({
2857
3119
  }
2858
3120
 
2859
3121
  // lib/models/hollowpositioningarmtube/register.tsx
2860
- var model13 = defineModelRenderer({
3122
+ var model14 = defineModelRenderer({
2861
3123
  name: "hollowpositioningarmtube",
2862
3124
  schema: hollowPositioningArmTubeModelDefinitionSchema,
2863
3125
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(HollowPositioningArmTube, { ...props }),
2864
3126
  pads: "none"
2865
3127
  });
2866
- function register13(registry) {
2867
- registry.register(model13);
3128
+ function register14(registry) {
3129
+ registry.register(model14);
2868
3130
  }
2869
3131
 
2870
3132
  // lib/models/nema/register.tsx
@@ -3133,14 +3395,14 @@ var NEMA17 = (props) => /* @__PURE__ */ jsx(NemaMotor, { ...props, nemaSize: 17
3133
3395
  var NEMA23 = (props) => /* @__PURE__ */ jsx(NemaMotor, { ...props, nemaSize: 23 });
3134
3396
 
3135
3397
  // lib/models/nema/register.tsx
3136
- var model14 = defineModelRenderer({
3398
+ var model15 = defineModelRenderer({
3137
3399
  name: "nema",
3138
3400
  schema: nemaMotorModelDefinitionSchema,
3139
3401
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(NemaMotor, { ...props }),
3140
3402
  pads: "none"
3141
3403
  });
3142
- function register14(registry) {
3143
- registry.register(model14);
3404
+ function register15(registry) {
3405
+ registry.register(model15);
3144
3406
  }
3145
3407
 
3146
3408
  // lib/models/panscrew/register.tsx
@@ -3196,7 +3458,7 @@ function createPanScrewMesh(input, options = {}) {
3196
3458
  triangle(a[i], b[n], b[i]);
3197
3459
  }
3198
3460
  };
3199
- const cap = (a, z, up) => {
3461
+ const cap2 = (a, z, up) => {
3200
3462
  const c = vertex(0, 0, z);
3201
3463
  for (let i = 0; i < segments; i++) {
3202
3464
  const n = (i + 1) % segments;
@@ -3237,7 +3499,7 @@ function createPanScrewMesh(input, options = {}) {
3237
3499
  major - Math.max(0, p.tipChamfer - (z + p.length))
3238
3500
  );
3239
3501
  }, z);
3240
- if (z === -p.length) cap(r, z, false);
3502
+ if (z === -p.length) cap2(r, z, false);
3241
3503
  }
3242
3504
  add(() => major, shaftEnd);
3243
3505
  const filletCenterR = major + p.underHeadRadius;
@@ -3352,14 +3614,14 @@ function PanScrew({ color = "#737e8f", ...props }) {
3352
3614
  }
3353
3615
 
3354
3616
  // lib/models/panscrew/register.tsx
3355
- var model15 = defineModelRenderer({
3617
+ var model16 = defineModelRenderer({
3356
3618
  name: "panscrew",
3357
3619
  schema: panScrewModelDefinitionSchema,
3358
3620
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(PanScrew, { ...props }),
3359
3621
  pads: "none"
3360
3622
  });
3361
- function register15(registry) {
3362
- registry.register(model15);
3623
+ function register16(registry) {
3624
+ registry.register(model16);
3363
3625
  }
3364
3626
 
3365
3627
  // lib/models/plainbushing/register.tsx
@@ -3422,14 +3684,14 @@ function PlainBushing({
3422
3684
  }
3423
3685
 
3424
3686
  // lib/models/plainbushing/register.tsx
3425
- var model16 = defineModelRenderer({
3687
+ var model17 = defineModelRenderer({
3426
3688
  name: "plainbushing",
3427
3689
  schema: plainBushingModelDefinitionSchema,
3428
3690
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(PlainBushing, { ...props }),
3429
3691
  pads: "none"
3430
3692
  });
3431
- function register16(registry) {
3432
- registry.register(model16);
3693
+ function register17(registry) {
3694
+ registry.register(model17);
3433
3695
  }
3434
3696
 
3435
3697
  // lib/models/rigidcoupler/register.tsx
@@ -3473,14 +3735,14 @@ function RigidCoupler({
3473
3735
  }
3474
3736
 
3475
3737
  // lib/models/rigidcoupler/register.tsx
3476
- var model17 = defineModelRenderer({
3738
+ var model18 = defineModelRenderer({
3477
3739
  name: "rigidcoupler",
3478
3740
  schema: rigidCouplerModelDefinitionSchema,
3479
3741
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(RigidCoupler, { ...props }),
3480
3742
  pads: "none"
3481
3743
  });
3482
- function register17(registry) {
3483
- registry.register(model17);
3744
+ function register18(registry) {
3745
+ registry.register(model18);
3484
3746
  }
3485
3747
 
3486
3748
  // lib/models/shaftcollar/register.tsx
@@ -3519,21 +3781,21 @@ function ShaftCollar({ color = "#737e8f", ...props }) {
3519
3781
  }
3520
3782
 
3521
3783
  // lib/models/shaftcollar/register.tsx
3522
- var model18 = defineModelRenderer({
3784
+ var model19 = defineModelRenderer({
3523
3785
  name: "shaftcollar",
3524
3786
  schema: shaftCollarModelDefinitionSchema,
3525
3787
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(ShaftCollar, { ...props }),
3526
3788
  pads: "none"
3527
3789
  });
3528
- function register18(registry) {
3529
- registry.register(model18);
3790
+ function register19(registry) {
3791
+ registry.register(model19);
3530
3792
  }
3531
3793
 
3532
3794
  // lib/models/sheetmetal/register.tsx
3533
3795
  import { sheetMetalModelDefinitionSchema } from "@tscircuit/modelprinter";
3534
3796
 
3535
3797
  // lib/mechanical/sheet-metal-mesh.ts
3536
- import earcut3 from "earcut";
3798
+ import earcut5 from "earcut";
3537
3799
  import {
3538
3800
  sheetMetalModelPropsSchema
3539
3801
  } from "@tscircuit/modelprinter";
@@ -3601,7 +3863,7 @@ function createSheetMetalMesh(input) {
3601
3863
  const loops = [outline, ...holes.map((hole) => [...hole].reverse())];
3602
3864
  const points = loops.flat();
3603
3865
  const starts = holes.map((_, i) => 4 + i * 64);
3604
- const triangles = earcut3(
3866
+ const triangles = earcut5(
3605
3867
  points.flatMap((p) => [p.u, p.v]),
3606
3868
  starts
3607
3869
  );
@@ -3686,14 +3948,14 @@ function SheetMetal({ color = "#737e8f", ...props }) {
3686
3948
  }
3687
3949
 
3688
3950
  // lib/models/sheetmetal/register.tsx
3689
- var model19 = defineModelRenderer({
3951
+ var model20 = defineModelRenderer({
3690
3952
  name: "sheetmetal",
3691
3953
  schema: sheetMetalModelDefinitionSchema,
3692
3954
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(SheetMetal, { ...props }),
3693
3955
  pads: "none"
3694
3956
  });
3695
- function register19(registry) {
3696
- registry.register(model19);
3957
+ function register20(registry) {
3958
+ registry.register(model20);
3697
3959
  }
3698
3960
 
3699
3961
  // lib/models/spurgear/register.tsx
@@ -3708,14 +3970,14 @@ function SpurGear({ color = "#737e8f", ...props }) {
3708
3970
  }
3709
3971
 
3710
3972
  // lib/models/spurgear/register.tsx
3711
- var model20 = defineModelRenderer({
3973
+ var model21 = defineModelRenderer({
3712
3974
  name: "spurgear",
3713
3975
  schema: spurGearModelDefinitionSchema,
3714
3976
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(SpurGear, { ...props }),
3715
3977
  pads: "none"
3716
3978
  });
3717
- function register20(registry) {
3718
- registry.register(model20);
3979
+ function register21(registry) {
3980
+ registry.register(model21);
3719
3981
  }
3720
3982
 
3721
3983
  // lib/models/threadedrod/register.tsx
@@ -3752,7 +4014,7 @@ function surface3(segments) {
3752
4014
  indices.push(a + i, a + n, b + n, a + i, b + n, b + i);
3753
4015
  }
3754
4016
  };
3755
- const cap = (start, z, up) => {
4017
+ const cap2 = (start, z, up) => {
3756
4018
  const center = positions.length / 3;
3757
4019
  positions.push(0, 0, z);
3758
4020
  for (let i = 0; i < segments; i++) {
@@ -3760,7 +4022,7 @@ function surface3(segments) {
3760
4022
  indices.push(center, start + (up ? i : n), start + (up ? n : i));
3761
4023
  }
3762
4024
  };
3763
- return { positions, indices, ring, connect, cap };
4025
+ return { positions, indices, ring, connect, cap: cap2 };
3764
4026
  }
3765
4027
  function threadDistance3(z, angle, pitch, hand = 1) {
3766
4028
  const phase = ((z / pitch - hand * angle / (2 * Math.PI)) % 1 + 1) % 1;
@@ -3789,12 +4051,7 @@ function createThreadedRodMesh(input, options = {}) {
3789
4051
  depth,
3790
4052
  Math.max(
3791
4053
  0,
3792
- (threadDistance3(
3793
- z,
3794
- angle,
3795
- d.threadPitch,
3796
- props.threadHand === "right" ? 1 : -1
3797
- ) - 1 / 16) * d.threadPitch * Math.sqrt(3)
4054
+ (threadDistance3(z, angle, d.threadPitch, props.leftHand ? -1 : 1) - 1 / 16) * d.threadPitch * Math.sqrt(3)
3798
4055
  )
3799
4056
  );
3800
4057
  const chamfer = radius - Math.max(0, props.chamfer - Math.min(z, d.length - z));
@@ -3817,14 +4074,14 @@ function ThreadedRod({ color = "#737e8f", ...props }) {
3817
4074
  }
3818
4075
 
3819
4076
  // lib/models/threadedrod/register.tsx
3820
- var model21 = defineModelRenderer({
4077
+ var model22 = defineModelRenderer({
3821
4078
  name: "threadedrod",
3822
4079
  schema: threadedRodModelDefinitionSchema,
3823
4080
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(ThreadedRod, { ...props }),
3824
4081
  pads: "none"
3825
4082
  });
3826
- function register21(registry) {
3827
- registry.register(model21);
4083
+ function register22(registry) {
4084
+ registry.register(model22);
3828
4085
  }
3829
4086
 
3830
4087
  // lib/models/torsionspring/register.tsx
@@ -3921,14 +4178,14 @@ function TorsionSpring({
3921
4178
  }
3922
4179
 
3923
4180
  // lib/models/torsionspring/register.tsx
3924
- var model22 = defineModelRenderer({
4181
+ var model23 = defineModelRenderer({
3925
4182
  name: "torsionspring",
3926
4183
  schema: torsionSpringModelDefinitionSchema,
3927
4184
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(TorsionSpring, { ...props }),
3928
4185
  pads: "none"
3929
4186
  });
3930
- function register22(registry) {
3931
- registry.register(model22);
4187
+ function register23(registry) {
4188
+ registry.register(model23);
3932
4189
  }
3933
4190
 
3934
4191
  // lib/models/tslotextrusion/register.tsx
@@ -3938,91 +4195,6 @@ import { tSlotExtrusionModelDefinitionSchema } from "@tscircuit/modelprinter";
3938
4195
  import {
3939
4196
  tSlotExtrusionModelPropsSchema
3940
4197
  } from "@tscircuit/modelprinter";
3941
-
3942
- // lib/mechanical/extrude-planar-profile.ts
3943
- import earcut4 from "earcut";
3944
- function extrudePlanarProfile({
3945
- outer,
3946
- holes = [],
3947
- start,
3948
- end,
3949
- project = (u, v, depth) => [u, v, depth],
3950
- reverse = false,
3951
- skipWall = () => false
3952
- }) {
3953
- const oriented = (loop, clockwise) => {
3954
- loop = loop.filter((point, index) => {
3955
- const previous = loop[(index + loop.length - 1) % loop.length];
3956
- return point[0] !== previous[0] || point[1] !== previous[1];
3957
- });
3958
- const area = loop.reduce((sum, a, index) => {
3959
- const b = loop[(index + 1) % loop.length];
3960
- return sum + a[0] * b[1] - a[1] * b[0];
3961
- }, 0);
3962
- if (!Number.isFinite(area) || area === 0)
3963
- throw new Error("Profile exceeds mesh resolution limits");
3964
- return area < 0 === clockwise ? loop : [...loop].reverse();
3965
- };
3966
- const loops = [oriented(outer, false), ...holes.map((h2) => oriented(h2, true))];
3967
- const points = loops.flat();
3968
- const holeStarts = [];
3969
- let count = loops[0].length;
3970
- for (const hole of loops.slice(1)) {
3971
- holeStarts.push(count);
3972
- count += hole.length;
3973
- }
3974
- const faces = earcut4(points.flat(), holeStarts);
3975
- const positions = [start, end].flatMap(
3976
- (depth) => points.flatMap(([u, v]) => project(u, v, depth))
3977
- );
3978
- const indices = [];
3979
- for (let i = 0; i < faces.length; i += 3) {
3980
- const [a, b, c] = faces.slice(i, i + 3);
3981
- indices.push(a, c, b, a + count, b + count, c + count);
3982
- }
3983
- let offset = 0;
3984
- for (const [loopIndex, loop] of loops.entries()) {
3985
- for (let i = 0; i < loop.length; i++) {
3986
- const next = (i + 1) % loop.length;
3987
- if (loopIndex === 0 && skipWall(loop[i], loop[next])) continue;
3988
- const a = offset + i;
3989
- const b = offset + next;
3990
- indices.push(a, b, b + count, a, b + count, a + count);
3991
- }
3992
- offset += loop.length;
3993
- }
3994
- if (reverse)
3995
- for (let i = 0; i < indices.length; i += 3)
3996
- [indices[i + 1], indices[i + 2]] = [indices[i + 2], indices[i + 1]];
3997
- return { positions, indices };
3998
- }
3999
- function joinProfileMeshes(meshes) {
4000
- const positions = [];
4001
- const indices = [];
4002
- const vertices = /* @__PURE__ */ new Map();
4003
- for (const mesh of meshes) {
4004
- for (const index of mesh.indices) {
4005
- const point = mesh.positions.slice(index * 3, index * 3 + 3);
4006
- const key = point.map((value) => value.toFixed(12)).join(",");
4007
- let shared = vertices.get(key);
4008
- if (shared === void 0) {
4009
- shared = positions.length / 3;
4010
- vertices.set(key, shared);
4011
- positions.push(...point);
4012
- }
4013
- indices.push(shared);
4014
- }
4015
- }
4016
- return { positions, indices };
4017
- }
4018
- function circularProfile(x, y, radius, segments = 96) {
4019
- return Array.from({ length: segments }, (_, index) => {
4020
- const angle = index * 2 * Math.PI / segments;
4021
- return [x + radius * Math.cos(angle), y + radius * Math.sin(angle)];
4022
- });
4023
- }
4024
-
4025
- // lib/models/tslotextrusion/mesh.ts
4026
4198
  function createTSlotExtrusionMesh(input = {}) {
4027
4199
  const props = tSlotExtrusionModelPropsSchema.parse(input);
4028
4200
  const { width: width10, height: height10, length, cornerRadius, lipThickness, pocketDepth } = props;
@@ -4078,14 +4250,14 @@ function TSlotExtrusion({
4078
4250
  }
4079
4251
 
4080
4252
  // lib/models/tslotextrusion/register.tsx
4081
- var model23 = defineModelRenderer({
4253
+ var model24 = defineModelRenderer({
4082
4254
  name: "tslotextrusion",
4083
4255
  schema: tSlotExtrusionModelDefinitionSchema,
4084
4256
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(TSlotExtrusion, { ...props }),
4085
4257
  pads: "none"
4086
4258
  });
4087
- function register23(registry) {
4088
- registry.register(model23);
4259
+ function register24(registry) {
4260
+ registry.register(model24);
4089
4261
  }
4090
4262
 
4091
4263
  // lib/models/tslotgusset/register.tsx
@@ -4138,14 +4310,14 @@ function TSlotGusset({ color = "#8995a3", ...props }) {
4138
4310
  }
4139
4311
 
4140
4312
  // lib/models/tslotgusset/register.tsx
4141
- var model24 = defineModelRenderer({
4313
+ var model25 = defineModelRenderer({
4142
4314
  name: "tslotgusset",
4143
4315
  schema: tSlotGussetModelDefinitionSchema,
4144
4316
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(TSlotGusset, { ...props }),
4145
4317
  pads: "none"
4146
4318
  });
4147
- function register24(registry) {
4148
- registry.register(model24);
4319
+ function register25(registry) {
4320
+ registry.register(model25);
4149
4321
  }
4150
4322
 
4151
4323
  // lib/models/tslotinsidecorner/register.tsx
@@ -4225,14 +4397,14 @@ function TSlotInsideCorner({
4225
4397
  }
4226
4398
 
4227
4399
  // lib/models/tslotinsidecorner/register.tsx
4228
- var model25 = defineModelRenderer({
4400
+ var model26 = defineModelRenderer({
4229
4401
  name: "tslotinsidecorner",
4230
4402
  schema: tSlotInsideCornerModelDefinitionSchema,
4231
4403
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(TSlotInsideCorner, { ...props }),
4232
4404
  pads: "none"
4233
4405
  });
4234
- function register25(registry) {
4235
- registry.register(model25);
4406
+ function register26(registry) {
4407
+ registry.register(model26);
4236
4408
  }
4237
4409
 
4238
4410
  // lib/models/wormgear/register.tsx
@@ -4243,7 +4415,7 @@ import {
4243
4415
  getWormGearDimensions,
4244
4416
  wormGearModelPropsSchema
4245
4417
  } from "@tscircuit/modelprinter";
4246
- import earcut5 from "earcut";
4418
+ import earcut6 from "earcut";
4247
4419
  var createWormGearMesh = (input) => {
4248
4420
  const props = wormGearModelPropsSchema.parse(input);
4249
4421
  const { outsideDiameter, rootDiameter, axialPitch, lead, toothThickness } = getWormGearDimensions(props);
@@ -4343,7 +4515,7 @@ var createWormGearMesh = (input) => {
4343
4515
  }
4344
4516
  const top = previous;
4345
4517
  if (props.boreDiameter === 0) {
4346
- const cap = (boundary, z, upward) => {
4518
+ const cap2 = (boundary, z, upward) => {
4347
4519
  const center = positions.length / 3;
4348
4520
  positions.push(0, 0, z);
4349
4521
  for (let index = 0; index < count; index++) {
@@ -4355,8 +4527,8 @@ var createWormGearMesh = (input) => {
4355
4527
  );
4356
4528
  }
4357
4529
  };
4358
- cap(bottom, 0, false);
4359
- cap(top, props.length, true);
4530
+ cap2(bottom, 0, false);
4531
+ cap2(top, props.length, true);
4360
4532
  } else {
4361
4533
  const holeCount = props.radialSegments;
4362
4534
  const boreRing = (z) => {
@@ -4384,7 +4556,7 @@ var createWormGearMesh = (input) => {
4384
4556
  holeTop + next
4385
4557
  );
4386
4558
  }
4387
- const cap = (boundary, hole, upward) => {
4559
+ const cap2 = (boundary, hole, upward) => {
4388
4560
  const vertices = Array.from(
4389
4561
  { length: count },
4390
4562
  (_, index) => boundary + index
@@ -4396,7 +4568,7 @@ var createWormGearMesh = (input) => {
4396
4568
  positions[vertex * 3],
4397
4569
  positions[vertex * 3 + 1]
4398
4570
  ]);
4399
- const triangles = earcut5(flat, [count], 2);
4571
+ const triangles = earcut6(flat, [count], 2);
4400
4572
  for (let index = 0; index < triangles.length; index += 3) {
4401
4573
  const a = vertices[triangles[index]];
4402
4574
  const b = vertices[triangles[index + 1]];
@@ -4409,8 +4581,8 @@ var createWormGearMesh = (input) => {
4409
4581
  );
4410
4582
  }
4411
4583
  };
4412
- cap(bottom, holeBottom, false);
4413
- cap(top, holeTop, true);
4584
+ cap2(bottom, holeBottom, false);
4585
+ cap2(top, holeTop, true);
4414
4586
  }
4415
4587
  return { positions, indices };
4416
4588
  };
@@ -4424,14 +4596,14 @@ function WormGear({ color = "#737e8f", ...props }) {
4424
4596
  }
4425
4597
 
4426
4598
  // lib/models/wormgear/register.tsx
4427
- var model26 = defineModelRenderer({
4599
+ var model27 = defineModelRenderer({
4428
4600
  name: "wormgear",
4429
4601
  schema: wormGearModelDefinitionSchema,
4430
4602
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(WormGear, { ...props }),
4431
4603
  pads: "none"
4432
4604
  });
4433
- function register26(registry) {
4434
- registry.register(model26);
4605
+ function register27(registry) {
4606
+ registry.register(model27);
4435
4607
  }
4436
4608
 
4437
4609
  // lib/generated/model-renderers.ts
@@ -4462,6 +4634,7 @@ function registerAllModelRenderers(registry) {
4462
4634
  register24(registry);
4463
4635
  register25(registry);
4464
4636
  register26(registry);
4637
+ register27(registry);
4465
4638
  }
4466
4639
 
4467
4640
  // lib/default-model-registry.ts
@@ -9999,6 +10172,8 @@ var JSTZH1_5mm = ({
9999
10172
  x: startX + i * pitch,
10000
10173
  y: 0,
10001
10174
  hole_diameter: 0.73,
10175
+ hole_offset_x: 0,
10176
+ hole_offset_y: 0,
10002
10177
  rect_pad_width: 1.03,
10003
10178
  rect_pad_height: 1.73,
10004
10179
  hole_shape: "circle",
@@ -10009,6 +10184,7 @@ var JSTZH1_5mm = ({
10009
10184
  type: "pcb_plated_hole",
10010
10185
  pcb_plated_hole_id: `jstzh_${i}`,
10011
10186
  shape: "pill",
10187
+ ccw_rotation: 0,
10012
10188
  x: startX + i * pitch,
10013
10189
  y: 0,
10014
10190
  hole_height: 0.73,
@@ -10193,6 +10369,8 @@ var JSTPH2_0mm = ({
10193
10369
  x: startX + i * pitch,
10194
10370
  y: 0,
10195
10371
  hole_diameter: 0.73,
10372
+ hole_offset_x: 0,
10373
+ hole_offset_y: 0,
10196
10374
  rect_pad_width: 1.2,
10197
10375
  rect_pad_height: 1.2,
10198
10376
  hole_shape: "circle",
@@ -10203,6 +10381,7 @@ var JSTPH2_0mm = ({
10203
10381
  type: "pcb_plated_hole",
10204
10382
  pcb_plated_hole_id: `jstph_${i}`,
10205
10383
  shape: "pill",
10384
+ ccw_rotation: 0,
10206
10385
  x: startX + i * pitch,
10207
10386
  y: 0,
10208
10387
  hole_height: 0.73,
@@ -11951,7 +12130,7 @@ var UsbCMidmount = ({
11951
12130
  {
11952
12131
  size: [
11953
12132
  0.4,
11954
- "hole_height" in slot ? Math.max(0.3, slot.hole_height - 0.2) : 1,
12133
+ "hole_height" in slot && slot.hole_height !== void 0 ? Math.max(0.3, slot.hole_height - 0.2) : 1,
11955
12134
  tabTop - tabBottom
11956
12135
  ],
11957
12136
  center: [slot.x, slot.y, (tabTop + tabBottom) / 2]
@@ -12018,10 +12197,10 @@ var SOT143 = ({ footprint = "sot143" }) => {
12018
12197
  var Footprinter3d = ({ footprint }) => {
12019
12198
  const modelFn = mp3.string(footprint.split("_", 1)[0]).params().fn;
12020
12199
  if (mp3.getModelNames().includes(modelFn)) {
12021
- const model27 = mp3.string(footprint).json();
12022
- const renderer = modelRendererRegistry.get(model27.fn);
12200
+ const model28 = mp3.string(footprint).json();
12201
+ const renderer = modelRendererRegistry.get(model28.fn);
12023
12202
  if (renderer) {
12024
- return renderer.render(model27);
12203
+ return renderer.render(model28);
12025
12204
  }
12026
12205
  }
12027
12206
  let normalizedFootprint = footprint;
@@ -12973,6 +13152,7 @@ function createJSCADRenderer(jscad8) {
12973
13152
  }
12974
13153
  export {
12975
13154
  BallBearing,
13155
+ BallTransferUnit,
12976
13156
  ButtonScrew,
12977
13157
  CableGrommet,
12978
13158
  ClampingShaftCollar,
@@ -13004,6 +13184,8 @@ export {
13004
13184
  convertCSGToThreeGeom,
13005
13185
  createBallBearingGeom,
13006
13186
  createBallBearingMesh,
13187
+ createBallTransferUnitGeom,
13188
+ createBallTransferUnitMesh,
13007
13189
  createButtonScrewGeom,
13008
13190
  createButtonScrewMesh,
13009
13191
  createCableGrommetGeom,