jscad-electronics 0.0.199 → 0.0.201

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.d.ts CHANGED
@@ -3,7 +3,7 @@ import { BufferGeometry } from 'three';
3
3
  import * as jscadModeling from '@jscad/modeling';
4
4
  import * as react_jsx_runtime from 'react/jsx-runtime';
5
5
  import * as _jscad_modeling_src_geometries_types from '@jscad/modeling/src/geometries/types';
6
- import { ButtonScrewModelPropsInput, FlangedBushingModelPropsInput, FlatHeadScrewModelPropsInput, SpurGearModelPropsInput, HelicalGearModelPropsInput, HexBoltModelPropsInput, HexSocketBoltModelPropsInput, NemaMotorModelPropsInput, PanScrewModelPropsInput, PlainBushingModelPropsInput, SheetMetalModelPropsInput, WormGearModelPropsInput } from '@tscircuit/modelprinter';
6
+ import { ButtonScrewModelPropsInput, CableGrommetModelPropsInput, FlangedBushingModelPropsInput, FlatHeadScrewModelPropsInput, SpurGearModelPropsInput, HelicalGearModelPropsInput, HexBoltModelPropsInput, HexNutModelPropsInput, HexSocketBoltModelPropsInput, NemaMotorModelPropsInput, PanScrewModelPropsInput, PlainBushingModelPropsInput, SheetMetalModelPropsInput, WormGearModelPropsInput } from '@tscircuit/modelprinter';
7
7
 
8
8
  type VNode = {
9
9
  type: any;
@@ -45,6 +45,23 @@ type ButtonScrewProps = ButtonScrewModelPropsInput & {
45
45
  declare function createButtonScrewGeom(input: ButtonScrewModelPropsInput, resolution?: ButtonScrewMeshOptions): _jscad_modeling_src_geometries_types.Geom3;
46
46
  declare function ButtonScrew({ color, ...props }: ButtonScrewProps): react_jsx_runtime.JSX.Element;
47
47
 
48
+ interface CableGrommetMesh {
49
+ positions: number[];
50
+ indices: number[];
51
+ }
52
+ interface CableGrommetMeshOptions {
53
+ /** Requested minimum; thin root walls can require more circular segments. */
54
+ radialSegments?: number;
55
+ }
56
+ /** Square-shouldered annulus centered on Z=0, with an open axial cable bore. */
57
+ declare function createCableGrommetMesh(input: CableGrommetModelPropsInput, options?: CableGrommetMeshOptions): CableGrommetMesh;
58
+
59
+ type CableGrommetProps = CableGrommetModelPropsInput & {
60
+ color?: string;
61
+ };
62
+ declare function createCableGrommetGeom(input: CableGrommetModelPropsInput): _jscad_modeling_src_geometries_types.Geom3;
63
+ declare function CableGrommet({ color, ...props }: CableGrommetProps): react_jsx_runtime.JSX.Element;
64
+
48
65
  /** Shared ring vertices and outward counterclockwise triangles, in millimeters. */
49
66
  interface FlangedBushingMesh {
50
67
  positions: number[];
@@ -123,6 +140,25 @@ type HexBoltProps = HexBoltModelPropsInput & {
123
140
  declare function createHexBoltGeom(input: HexBoltModelPropsInput, options?: HexBoltMeshOptions): _jscad_modeling_src_geometries_types.Geom3;
124
141
  declare function HexBolt({ color, ...props }: HexBoltProps): react_jsx_runtime.JSX.Element;
125
142
 
143
+ /** Indexed counterclockwise triangles in millimeters. */
144
+ interface HexNutMesh {
145
+ positions: number[];
146
+ indices: number[];
147
+ }
148
+ /** Renderer resolution affects tessellation only, never model specifications. */
149
+ interface HexNutMeshOptions {
150
+ radialSegments?: number;
151
+ segmentsPerPitch?: number;
152
+ }
153
+ /** Closed annular surface with a through internal thread and both conical mouths. */
154
+ declare function createHexNutMesh(input: HexNutModelPropsInput, options?: HexNutMeshOptions): HexNutMesh;
155
+
156
+ type HexNutProps = HexNutModelPropsInput & {
157
+ color?: string;
158
+ };
159
+ declare function createHexNutGeom(input: HexNutModelPropsInput, resolution?: HexNutMeshOptions): _jscad_modeling_src_geometries_types.Geom3;
160
+ declare function HexNut({ color, ...props }: HexNutProps): react_jsx_runtime.JSX.Element;
161
+
126
162
  /** Indexed triangles, counterclockwise from outside; millimeters, Z up. */
127
163
  interface HexSocketBoltMesh {
128
164
  positions: number[];
@@ -244,4 +280,4 @@ declare function createJSCADRenderer(jscad: typeof jscadModeling): {
244
280
  };
245
281
  };
246
282
 
247
- export { ButtonScrew, type ButtonScrewMesh, type ButtonScrewMeshOptions, type ButtonScrewProps, type ColoredGeom, FlangedBushing, type FlangedBushingMesh, type FlangedBushingProps, FlatHeadScrew, type FlatHeadScrewMesh, type FlatHeadScrewMeshOptions, type FlatHeadScrewProps, Fragment, HelicalGear, type HelicalGearMesh, type HelicalGearProps, HexBolt, type HexBoltMesh, type HexBoltMeshOptions, type HexBoltProps, HexSocketBolt, type HexSocketBoltMesh, type HexSocketBoltProps, NEMA17, NEMA23, NEMA8, type NemaFrameMotorProps, NemaMotor, type NemaMotorProps, PanScrew, type PanScrewMesh, type PanScrewMeshOptions, type PanScrewProps, PlainBushing, type PlainBushingMesh, type PlainBushingProps, type RenderResult, SheetMetal, type SheetMetalMesh, type SheetMetalProps, SpurGear, type SpurGearMesh, type SpurGearProps, type VNode, WormGear, type WormGearMesh, type WormGearProps, convertCSGToThreeGeom, createButtonScrewGeom, createButtonScrewMesh, createFlangedBushingGeom, createFlangedBushingMesh, createFlatHeadScrewGeom, createFlatHeadScrewMesh, createHelicalGearGeom, createHelicalGearMesh, createHexBoltGeom, createHexBoltMesh, createHexSocketBoltGeom, createHexSocketBoltMesh, createJSCADRenderer, createPanScrewGeom, createPanScrewMesh, createPlainBushingGeom, createPlainBushingMesh, createSheetMetalGeom, createSheetMetalMesh, createSpurGearGeom, createSpurGearMesh, createWormGearGeom, createWormGearMesh, getJscadModelForFootprint, getJscadModelForFootprintWithPads, h };
283
+ export { ButtonScrew, type ButtonScrewMesh, type ButtonScrewMeshOptions, type ButtonScrewProps, CableGrommet, type CableGrommetMesh, type CableGrommetMeshOptions, type CableGrommetProps, type ColoredGeom, FlangedBushing, type FlangedBushingMesh, type FlangedBushingProps, FlatHeadScrew, type FlatHeadScrewMesh, type FlatHeadScrewMeshOptions, type FlatHeadScrewProps, Fragment, HelicalGear, type HelicalGearMesh, type HelicalGearProps, HexBolt, type HexBoltMesh, type HexBoltMeshOptions, type HexBoltProps, HexNut, type HexNutMesh, type HexNutMeshOptions, type HexNutProps, HexSocketBolt, type HexSocketBoltMesh, type HexSocketBoltProps, NEMA17, NEMA23, NEMA8, type NemaFrameMotorProps, NemaMotor, type NemaMotorProps, PanScrew, type PanScrewMesh, type PanScrewMeshOptions, type PanScrewProps, PlainBushing, type PlainBushingMesh, type PlainBushingProps, type RenderResult, SheetMetal, type SheetMetalMesh, type SheetMetalProps, SpurGear, type SpurGearMesh, type SpurGearProps, type VNode, WormGear, type WormGearMesh, type WormGearProps, convertCSGToThreeGeom, createButtonScrewGeom, createButtonScrewMesh, createCableGrommetGeom, createCableGrommetMesh, createFlangedBushingGeom, createFlangedBushingMesh, createFlatHeadScrewGeom, createFlatHeadScrewMesh, createHelicalGearGeom, createHelicalGearMesh, createHexBoltGeom, createHexBoltMesh, createHexNutGeom, createHexNutMesh, createHexSocketBoltGeom, createHexSocketBoltMesh, createJSCADRenderer, createPanScrewGeom, createPanScrewMesh, createPlainBushingGeom, createPlainBushingMesh, createSheetMetalGeom, createSheetMetalMesh, createSpurGearGeom, createSpurGearMesh, createWormGearGeom, createWormGearMesh, getJscadModelForFootprint, getJscadModelForFootprintWithPads, h };
package/dist/vanilla.js CHANGED
@@ -183,24 +183,24 @@ var FootprintPlatedHole = ({
183
183
  import { buttonScrewModelDefinitionSchema } from "@tscircuit/modelprinter";
184
184
 
185
185
  // lib/model-registry.ts
186
- function defineModelRenderer(model14) {
187
- return model14;
186
+ function defineModelRenderer(model16) {
187
+ return model16;
188
188
  }
189
189
  var ModelRendererRegistry = class {
190
190
  models = /* @__PURE__ */ new Map();
191
- register(model14) {
192
- if (typeof model14.name !== "string" || !/^[a-z]+$/.test(model14.name)) {
191
+ register(model16) {
192
+ if (typeof model16.name !== "string" || !/^[a-z]+$/.test(model16.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(model14.name)) {
198
- throw new Error(`Model renderer "${model14.name}" is already registered`);
197
+ if (this.models.has(model16.name)) {
198
+ throw new Error(`Model renderer "${model16.name}" is already registered`);
199
199
  }
200
- if (model14.pads !== "none" && model14.pads !== "footprinter") {
200
+ if (model16.pads !== "none" && model16.pads !== "footprinter") {
201
201
  throw new Error('Model renderer pads must be "none" or "footprinter"');
202
202
  }
203
- const { name, schema, render: render2, pads } = model14;
203
+ const { name, schema, render: render2, pads } = model16;
204
204
  this.models.set(name, {
205
205
  name,
206
206
  schema,
@@ -354,8 +354,8 @@ function indexedMeshToGeom3(mesh) {
354
354
  }
355
355
 
356
356
  // lib/models/buttonscrew/ButtonScrew.tsx
357
- function createButtonScrewGeom(input, resolution2) {
358
- return indexedMeshToGeom3(createButtonScrewMesh(input, resolution2));
357
+ function createButtonScrewGeom(input, resolution3) {
358
+ return indexedMeshToGeom3(createButtonScrewMesh(input, resolution3));
359
359
  }
360
360
  function ButtonScrew({ color = "#737e8f", ...props }) {
361
361
  return /* @__PURE__ */ jsx(Colorize, { color, children: /* @__PURE__ */ jsx(Custom, { geometry: createButtonScrewGeom(props) }) });
@@ -372,6 +372,88 @@ function register(registry) {
372
372
  registry.register(model);
373
373
  }
374
374
 
375
+ // lib/models/cablegrommet/register.tsx
376
+ import { cableGrommetModelDefinitionSchema } from "@tscircuit/modelprinter";
377
+
378
+ // lib/models/cablegrommet/mesh.ts
379
+ import {
380
+ cableGrommetModelPropsSchema,
381
+ getCableGrommetDimensions
382
+ } from "@tscircuit/modelprinter";
383
+ function createCableGrommetMesh(input, options = {}) {
384
+ const props = cableGrommetModelPropsSchema.parse(input);
385
+ const dimensions = getCableGrommetDimensions(props);
386
+ const inner = props.innerDiameter / 2;
387
+ const root = dimensions.grooveRootDiameter / 2;
388
+ const outer = props.outerDiameter / 2;
389
+ const requested = options.radialSegments ?? 96;
390
+ if (!Number.isInteger(requested) || requested < 12 || requested > 4096 || requested % 4 !== 0)
391
+ throw new Error(
392
+ "Grommet radial segments must be a multiple of four in [12,4096]"
393
+ );
394
+ const wallAngle = Math.acos((inner + root) / (2 * root));
395
+ const segments = Math.max(requested, 4 * Math.ceil(Math.PI / wallAngle / 4));
396
+ if (!Number.isFinite(segments) || segments > 4096)
397
+ throw new Error(
398
+ "Grommet wall exceeds mesh resolution limit (4096 segments)"
399
+ );
400
+ const section = [
401
+ [inner, -props.height / 2],
402
+ [outer, -props.height / 2],
403
+ [outer, dimensions.grooveStartZ],
404
+ [root, dimensions.grooveStartZ],
405
+ [root, dimensions.grooveEndZ],
406
+ [outer, dimensions.grooveEndZ],
407
+ [outer, props.height / 2],
408
+ [inner, props.height / 2]
409
+ ];
410
+ const positions = [];
411
+ const indices = [];
412
+ for (const [radius, z] of section)
413
+ for (let sample = 0; sample < segments; sample++) {
414
+ const angle = sample * 2 * Math.PI / segments;
415
+ positions.push(radius * Math.cos(angle), radius * Math.sin(angle), z);
416
+ }
417
+ for (let ring = 0; ring < section.length; ring++) {
418
+ const a = ring * segments;
419
+ const b = (ring + 1) % section.length * segments;
420
+ for (let sample = 0; sample < segments; sample++) {
421
+ const next = (sample + 1) % segments;
422
+ indices.push(
423
+ a + sample,
424
+ a + next,
425
+ b + next,
426
+ a + sample,
427
+ b + next,
428
+ b + sample
429
+ );
430
+ }
431
+ }
432
+ return { positions, indices };
433
+ }
434
+
435
+ // lib/models/cablegrommet/CableGrommet.tsx
436
+ function createCableGrommetGeom(input) {
437
+ return indexedMeshToGeom3(createCableGrommetMesh(input));
438
+ }
439
+ function CableGrommet({
440
+ color = "#343943",
441
+ ...props
442
+ }) {
443
+ return /* @__PURE__ */ jsx(Colorize, { color, children: /* @__PURE__ */ jsx(Custom, { geometry: createCableGrommetGeom(props) }) });
444
+ }
445
+
446
+ // lib/models/cablegrommet/register.tsx
447
+ var model2 = defineModelRenderer({
448
+ name: "cablegrommet",
449
+ schema: cableGrommetModelDefinitionSchema,
450
+ render: ({ fn, ...props }) => /* @__PURE__ */ jsx(CableGrommet, { ...props }),
451
+ pads: "none"
452
+ });
453
+ function register2(registry) {
454
+ registry.register(model2);
455
+ }
456
+
375
457
  // lib/models/flangedbushing/register.tsx
376
458
  import { flangedBushingModelDefinitionSchema } from "@tscircuit/modelprinter";
377
459
 
@@ -425,14 +507,14 @@ function FlangedBushing({
425
507
  }
426
508
 
427
509
  // lib/models/flangedbushing/register.tsx
428
- var model2 = defineModelRenderer({
510
+ var model3 = defineModelRenderer({
429
511
  name: "flangedbushing",
430
512
  schema: flangedBushingModelDefinitionSchema,
431
513
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(FlangedBushing, { ...props }),
432
514
  pads: "none"
433
515
  });
434
- function register2(registry) {
435
- registry.register(model2);
516
+ function register3(registry) {
517
+ registry.register(model3);
436
518
  }
437
519
 
438
520
  // lib/models/flatheadscrew/register.tsx
@@ -541,14 +623,14 @@ function createFlatHeadScrewMesh(input, options = {}) {
541
623
  filletCenterZ + p.underHeadRadius * Math.sin(angle)
542
624
  );
543
625
  }
544
- const hexRadius2 = (theta) => p.socketAcrossFlats / 2 / Math.max(
626
+ const hexRadius3 = (theta) => p.socketAcrossFlats / 2 / Math.max(
545
627
  Math.abs(Math.sin(theta)),
546
628
  Math.abs(Math.sin(theta + 2 * Math.PI / 3)),
547
629
  Math.abs(Math.sin(theta + 4 * Math.PI / 3))
548
630
  );
549
631
  add(() => p.headDiameter / 2, 0);
550
- add(hexRadius2, 0);
551
- add(hexRadius2, -p.socketDepth);
632
+ add(hexRadius3, 0);
633
+ add(hexRadius3, -p.socketDepth);
552
634
  cap(previous, -p.socketDepth, true);
553
635
  return { positions, indices };
554
636
  }
@@ -565,14 +647,14 @@ function FlatHeadScrew({
565
647
  }
566
648
 
567
649
  // lib/models/flatheadscrew/register.tsx
568
- var model3 = defineModelRenderer({
650
+ var model4 = defineModelRenderer({
569
651
  name: "flatheadscrew",
570
652
  schema: flatHeadScrewModelDefinitionSchema,
571
653
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(FlatHeadScrew, { ...props }),
572
654
  pads: "none"
573
655
  });
574
- function register3(registry) {
575
- registry.register(model3);
656
+ function register4(registry) {
657
+ registry.register(model4);
576
658
  }
577
659
 
578
660
  // lib/models/flexscreen/register.tsx
@@ -1250,14 +1332,14 @@ var FlexScreen = (props) => {
1250
1332
  };
1251
1333
 
1252
1334
  // lib/models/flexscreen/register.tsx
1253
- var model4 = defineModelRenderer({
1335
+ var model5 = defineModelRenderer({
1254
1336
  name: "flexscreen",
1255
1337
  schema: flexScreenModelDefinitionSchema,
1256
1338
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(FlexScreen, { ...props }),
1257
1339
  pads: "footprinter"
1258
1340
  });
1259
- function register4(registry) {
1260
- registry.register(model4);
1341
+ function register5(registry) {
1342
+ registry.register(model5);
1261
1343
  }
1262
1344
 
1263
1345
  // lib/models/helicalgear/register.tsx
@@ -1463,14 +1545,14 @@ function HelicalGear({ color = "#737e8f", ...props }) {
1463
1545
  }
1464
1546
 
1465
1547
  // lib/models/helicalgear/register.tsx
1466
- var model5 = defineModelRenderer({
1548
+ var model6 = defineModelRenderer({
1467
1549
  name: "helicalgear",
1468
1550
  schema: helicalGearModelDefinitionSchema,
1469
1551
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(HelicalGear, { ...props }),
1470
1552
  pads: "none"
1471
1553
  });
1472
- function register5(registry) {
1473
- registry.register(model5);
1554
+ function register6(registry) {
1555
+ registry.register(model6);
1474
1556
  }
1475
1557
 
1476
1558
  // lib/models/hexbolt/register.tsx
@@ -1579,20 +1661,20 @@ function createHexBoltMesh(input, options = {}) {
1579
1661
  filletCenterZ + p.underHeadRadius * Math.sin(angle)
1580
1662
  );
1581
1663
  }
1582
- const hexRadius2 = (theta) => p.headAcrossFlats / 2 / Math.max(
1664
+ const hexRadius3 = (theta) => p.headAcrossFlats / 2 / Math.max(
1583
1665
  Math.abs(Math.sin(theta)),
1584
1666
  Math.abs(Math.sin(theta + 2 * Math.PI / 3)),
1585
1667
  Math.abs(Math.sin(theta + 4 * Math.PI / 3))
1586
1668
  );
1587
- add(hexRadius2, 0);
1669
+ add(hexRadius3, 0);
1588
1670
  const slope = Math.tan(p.headChamferAngle * Math.PI / 180);
1589
1671
  const start = p.headHeight - (p.headCornerDiameter - p.headChamferDiameter) / 2 * slope;
1590
- add(hexRadius2, start);
1672
+ add(hexRadius3, start);
1591
1673
  for (let i = 1; i <= 12; i++) {
1592
1674
  const z = start + (p.headHeight - start) * i / 12;
1593
1675
  add(
1594
1676
  (theta) => Math.min(
1595
- hexRadius2(theta),
1677
+ hexRadius3(theta),
1596
1678
  p.headChamferDiameter / 2 + (p.headHeight - z) / slope
1597
1679
  ),
1598
1680
  z
@@ -1611,14 +1693,144 @@ function HexBolt({ color = "#737e8f", ...props }) {
1611
1693
  }
1612
1694
 
1613
1695
  // lib/models/hexbolt/register.tsx
1614
- var model6 = defineModelRenderer({
1696
+ var model7 = defineModelRenderer({
1615
1697
  name: "hexbolt",
1616
1698
  schema: hexBoltModelDefinitionSchema,
1617
1699
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(HexBolt, { ...props }),
1618
1700
  pads: "none"
1619
1701
  });
1620
- function register6(registry) {
1621
- registry.register(model6);
1702
+ function register7(registry) {
1703
+ registry.register(model7);
1704
+ }
1705
+
1706
+ // lib/models/hexnut/register.tsx
1707
+ import { hexNutModelDefinitionSchema } from "@tscircuit/modelprinter";
1708
+
1709
+ // lib/models/hexnut/mesh.ts
1710
+ import {
1711
+ hexNutModelPropsSchema,
1712
+ getHexNutDimensions
1713
+ } from "@tscircuit/modelprinter";
1714
+ function resolution2(options) {
1715
+ const radial = options.radialSegments ?? 96;
1716
+ const axial = options.segmentsPerPitch ?? 32;
1717
+ if (!Number.isInteger(radial) || radial < 24 || radial > 192 || radial % 12 !== 0 || !Number.isInteger(axial) || axial < 8 || axial > 64)
1718
+ throw new Error(
1719
+ "Mesh resolution limit: radial segments must be a multiple of 12 in [24,192], pitch segments an integer in [8,64]"
1720
+ );
1721
+ return { radial, axial };
1722
+ }
1723
+ function surface2(segments) {
1724
+ const positions = [], indices = [];
1725
+ const ring = (z, radius) => {
1726
+ const start = positions.length / 3;
1727
+ for (let i = 0; i < segments; i++) {
1728
+ const angle = i * 2 * Math.PI / segments;
1729
+ const r = radius(angle);
1730
+ positions.push(r * Math.cos(angle), r * Math.sin(angle), z);
1731
+ }
1732
+ return start;
1733
+ };
1734
+ const connect = (a, b) => {
1735
+ for (let i = 0; i < segments; i++) {
1736
+ const n = (i + 1) % segments;
1737
+ indices.push(a + i, a + n, b + n, a + i, b + n, b + i);
1738
+ }
1739
+ };
1740
+ const cap = (start, z, up) => {
1741
+ const center = positions.length / 3;
1742
+ positions.push(0, 0, z);
1743
+ for (let i = 0; i < segments; i++) {
1744
+ const n = (i + 1) % segments;
1745
+ indices.push(center, start + (up ? i : n), start + (up ? n : i));
1746
+ }
1747
+ };
1748
+ return { positions, indices, ring, connect, cap };
1749
+ }
1750
+ function hexRadius2(angle, acrossFlats) {
1751
+ const period = Math.PI / 3;
1752
+ const distance2 = ((angle - Math.PI / 2 + period / 2) % period + period) % period - period / 2;
1753
+ return acrossFlats / 2 / Math.cos(distance2);
1754
+ }
1755
+ function threadDistance2(z, angle, pitch, hand = 1) {
1756
+ const phase = ((z / pitch - hand * angle / (2 * Math.PI)) % 1 + 1) % 1;
1757
+ return Math.min(phase, 1 - phase);
1758
+ }
1759
+ function createHexNutMesh(input, options = {}) {
1760
+ const props = hexNutModelPropsSchema.parse(input);
1761
+ const d = getHexNutDimensions(input);
1762
+ const { radial, axial } = resolution2(options);
1763
+ const steps = Math.max(2, Math.ceil(d.height / d.threadPitch * axial));
1764
+ if (steps > 24e3 || !Number.isFinite(steps))
1765
+ throw new Error("Mesh resolution limit: too many thread turns");
1766
+ const m = surface2(radial);
1767
+ const outer = (z, angle) => Math.min(
1768
+ hexRadius2(angle, d.acrossFlats),
1769
+ d.faceDiameter / 2 + Math.min(z, d.height - z) * Math.sqrt(3)
1770
+ );
1771
+ const outerLevels = [
1772
+ 0,
1773
+ d.outerChamferDepth,
1774
+ d.height - d.outerChamferDepth,
1775
+ d.height
1776
+ ];
1777
+ for (let index = 0; index < radial; index++) {
1778
+ const angle = index * 2 * Math.PI / radial;
1779
+ const height10 = (hexRadius2(angle, d.acrossFlats) - d.faceDiameter / 2) / Math.sqrt(3);
1780
+ if (height10 > 1e-9 && height10 < d.outerChamferDepth - 1e-9)
1781
+ outerLevels.push(height10, d.height - height10);
1782
+ }
1783
+ const outerZ = outerLevels.sort((a, b) => a - b).filter((z, index, sorted) => index === 0 || z - sorted[index - 1] > 1e-10);
1784
+ const first = m.ring(0, (angle) => outer(0, angle));
1785
+ let previous = first;
1786
+ for (const z of outerZ.slice(1)) {
1787
+ const current = m.ring(z, (angle) => outer(z, angle));
1788
+ m.connect(previous, current);
1789
+ previous = current;
1790
+ }
1791
+ const levels = new Set(
1792
+ props.showThreads ? Array.from({ length: steps + 1 }, (_, i) => d.height * i / steps) : [0, d.height]
1793
+ );
1794
+ levels.add(d.boreChamferDepth);
1795
+ levels.add(d.height - d.boreChamferDepth);
1796
+ const minor = d.boreMinorDiameter / 2;
1797
+ const depth = (d.diameter - d.boreMinorDiameter) / 2;
1798
+ for (const z of [...levels].sort((a, b) => b - a)) {
1799
+ const current = m.ring(z, (angle) => {
1800
+ const groove = Math.min(
1801
+ depth,
1802
+ Math.max(
1803
+ 0,
1804
+ (threadDistance2(z, angle, d.threadPitch) - 1 / 8) * d.threadPitch * Math.sqrt(3)
1805
+ )
1806
+ );
1807
+ const threaded = minor + (props.showThreads ? groove : 0);
1808
+ return Math.max(threaded, d.mouthDiameter / 2 - Math.min(z, d.height - z));
1809
+ });
1810
+ m.connect(previous, current);
1811
+ previous = current;
1812
+ }
1813
+ m.connect(previous, first);
1814
+ return { positions: m.positions, indices: m.indices };
1815
+ }
1816
+
1817
+ // lib/models/hexnut/HexNut.tsx
1818
+ function createHexNutGeom(input, resolution3) {
1819
+ return indexedMeshToGeom3(createHexNutMesh(input, resolution3));
1820
+ }
1821
+ function HexNut({ color = "#737e8f", ...props }) {
1822
+ return /* @__PURE__ */ jsx(Colorize, { color, children: /* @__PURE__ */ jsx(Custom, { geometry: createHexNutGeom(props) }) });
1823
+ }
1824
+
1825
+ // lib/models/hexnut/register.tsx
1826
+ var model8 = defineModelRenderer({
1827
+ name: "hexnut",
1828
+ schema: hexNutModelDefinitionSchema,
1829
+ render: ({ fn, ...props }) => /* @__PURE__ */ jsx(HexNut, { ...props }),
1830
+ pads: "none"
1831
+ });
1832
+ function register8(registry) {
1833
+ registry.register(model8);
1622
1834
  }
1623
1835
 
1624
1836
  // lib/models/hexsocketbolt/register.tsx
@@ -1710,10 +1922,10 @@ var createHexSocketBoltMesh = (input) => {
1710
1922
  addRing(bevel, () => headDiameter / 2);
1711
1923
  addRing(headHeight - bevel, () => headDiameter / 2);
1712
1924
  addRing(headHeight, () => headDiameter / 2 - bevel);
1713
- const hexRadius2 = (angle, acrossFlats) => acrossFlats / 2 / Math.cos((angle + Math.PI / 6) % (Math.PI / 3) - Math.PI / 6);
1714
- addRing(headHeight, (angle) => hexRadius2(angle, socketWidth + bevel));
1715
- addRing(headHeight - bevel / 2, (angle) => hexRadius2(angle, socketWidth));
1716
- addRing(headHeight - socketDepth, (angle) => hexRadius2(angle, socketWidth));
1925
+ const hexRadius3 = (angle, acrossFlats) => acrossFlats / 2 / Math.cos((angle + Math.PI / 6) % (Math.PI / 3) - Math.PI / 6);
1926
+ addRing(headHeight, (angle) => hexRadius3(angle, socketWidth + bevel));
1927
+ addRing(headHeight - bevel / 2, (angle) => hexRadius3(angle, socketWidth));
1928
+ addRing(headHeight - socketDepth, (angle) => hexRadius3(angle, socketWidth));
1717
1929
  cap(previous, headHeight - socketDepth, true);
1718
1930
  return { positions, indices };
1719
1931
  };
@@ -1730,14 +1942,14 @@ function HexSocketBolt({
1730
1942
  }
1731
1943
 
1732
1944
  // lib/models/hexsocketbolt/register.tsx
1733
- var model7 = defineModelRenderer({
1945
+ var model9 = defineModelRenderer({
1734
1946
  name: "hexsocketbolt",
1735
1947
  schema: hexSocketBoltModelDefinitionSchema,
1736
1948
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(HexSocketBolt, { ...props }),
1737
1949
  pads: "none"
1738
1950
  });
1739
- function register7(registry) {
1740
- registry.register(model7);
1951
+ function register9(registry) {
1952
+ registry.register(model9);
1741
1953
  }
1742
1954
 
1743
1955
  // lib/models/nema/register.tsx
@@ -2006,14 +2218,14 @@ var NEMA17 = (props) => /* @__PURE__ */ jsx(NemaMotor, { ...props, nemaSize: 17
2006
2218
  var NEMA23 = (props) => /* @__PURE__ */ jsx(NemaMotor, { ...props, nemaSize: 23 });
2007
2219
 
2008
2220
  // lib/models/nema/register.tsx
2009
- var model8 = defineModelRenderer({
2221
+ var model10 = defineModelRenderer({
2010
2222
  name: "nema",
2011
2223
  schema: nemaMotorModelDefinitionSchema,
2012
2224
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(NemaMotor, { ...props }),
2013
2225
  pads: "none"
2014
2226
  });
2015
- function register8(registry) {
2016
- registry.register(model8);
2227
+ function register10(registry) {
2228
+ registry.register(model10);
2017
2229
  }
2018
2230
 
2019
2231
  // lib/models/panscrew/register.tsx
@@ -2225,14 +2437,14 @@ function PanScrew({ color = "#737e8f", ...props }) {
2225
2437
  }
2226
2438
 
2227
2439
  // lib/models/panscrew/register.tsx
2228
- var model9 = defineModelRenderer({
2440
+ var model11 = defineModelRenderer({
2229
2441
  name: "panscrew",
2230
2442
  schema: panScrewModelDefinitionSchema,
2231
2443
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(PanScrew, { ...props }),
2232
2444
  pads: "none"
2233
2445
  });
2234
- function register9(registry) {
2235
- registry.register(model9);
2446
+ function register11(registry) {
2447
+ registry.register(model11);
2236
2448
  }
2237
2449
 
2238
2450
  // lib/models/plainbushing/register.tsx
@@ -2295,14 +2507,14 @@ function PlainBushing({
2295
2507
  }
2296
2508
 
2297
2509
  // lib/models/plainbushing/register.tsx
2298
- var model10 = defineModelRenderer({
2510
+ var model12 = defineModelRenderer({
2299
2511
  name: "plainbushing",
2300
2512
  schema: plainBushingModelDefinitionSchema,
2301
2513
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(PlainBushing, { ...props }),
2302
2514
  pads: "none"
2303
2515
  });
2304
- function register10(registry) {
2305
- registry.register(model10);
2516
+ function register12(registry) {
2517
+ registry.register(model12);
2306
2518
  }
2307
2519
 
2308
2520
  // lib/models/sheetmetal/register.tsx
@@ -2462,14 +2674,14 @@ function SheetMetal({ color = "#737e8f", ...props }) {
2462
2674
  }
2463
2675
 
2464
2676
  // lib/models/sheetmetal/register.tsx
2465
- var model11 = defineModelRenderer({
2677
+ var model13 = defineModelRenderer({
2466
2678
  name: "sheetmetal",
2467
2679
  schema: sheetMetalModelDefinitionSchema,
2468
2680
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(SheetMetal, { ...props }),
2469
2681
  pads: "none"
2470
2682
  });
2471
- function register11(registry) {
2472
- registry.register(model11);
2683
+ function register13(registry) {
2684
+ registry.register(model13);
2473
2685
  }
2474
2686
 
2475
2687
  // lib/models/spurgear/register.tsx
@@ -2484,14 +2696,14 @@ function SpurGear({ color = "#737e8f", ...props }) {
2484
2696
  }
2485
2697
 
2486
2698
  // lib/models/spurgear/register.tsx
2487
- var model12 = defineModelRenderer({
2699
+ var model14 = defineModelRenderer({
2488
2700
  name: "spurgear",
2489
2701
  schema: spurGearModelDefinitionSchema,
2490
2702
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(SpurGear, { ...props }),
2491
2703
  pads: "none"
2492
2704
  });
2493
- function register12(registry) {
2494
- registry.register(model12);
2705
+ function register14(registry) {
2706
+ registry.register(model14);
2495
2707
  }
2496
2708
 
2497
2709
  // lib/models/wormgear/register.tsx
@@ -2683,14 +2895,14 @@ function WormGear({ color = "#737e8f", ...props }) {
2683
2895
  }
2684
2896
 
2685
2897
  // lib/models/wormgear/register.tsx
2686
- var model13 = defineModelRenderer({
2898
+ var model15 = defineModelRenderer({
2687
2899
  name: "wormgear",
2688
2900
  schema: wormGearModelDefinitionSchema,
2689
2901
  render: ({ fn, ...props }) => /* @__PURE__ */ jsx(WormGear, { ...props }),
2690
2902
  pads: "none"
2691
2903
  });
2692
- function register13(registry) {
2693
- registry.register(model13);
2904
+ function register15(registry) {
2905
+ registry.register(model15);
2694
2906
  }
2695
2907
 
2696
2908
  // lib/generated/model-renderers.ts
@@ -2708,6 +2920,8 @@ function registerAllModelRenderers(registry) {
2708
2920
  register11(registry);
2709
2921
  register12(registry);
2710
2922
  register13(registry);
2923
+ register14(registry);
2924
+ register15(registry);
2711
2925
  }
2712
2926
 
2713
2927
  // lib/default-model-registry.ts
@@ -10264,10 +10478,10 @@ var SOT143 = ({ footprint = "sot143" }) => {
10264
10478
  var Footprinter3d = ({ footprint }) => {
10265
10479
  const modelFn = mp3.string(footprint.split("_", 1)[0]).params().fn;
10266
10480
  if (mp3.getModelNames().includes(modelFn)) {
10267
- const model14 = mp3.string(footprint).json();
10268
- const renderer = modelRendererRegistry.get(model14.fn);
10481
+ const model16 = mp3.string(footprint).json();
10482
+ const renderer = modelRendererRegistry.get(model16.fn);
10269
10483
  if (renderer) {
10270
- return renderer.render(model14);
10484
+ return renderer.render(model16);
10271
10485
  }
10272
10486
  }
10273
10487
  let normalizedFootprint = footprint;
@@ -11219,11 +11433,13 @@ function createJSCADRenderer(jscad4) {
11219
11433
  }
11220
11434
  export {
11221
11435
  ButtonScrew,
11436
+ CableGrommet,
11222
11437
  FlangedBushing,
11223
11438
  FlatHeadScrew,
11224
11439
  Fragment,
11225
11440
  HelicalGear,
11226
11441
  HexBolt,
11442
+ HexNut,
11227
11443
  HexSocketBolt,
11228
11444
  NEMA17,
11229
11445
  NEMA23,
@@ -11237,6 +11453,8 @@ export {
11237
11453
  convertCSGToThreeGeom,
11238
11454
  createButtonScrewGeom,
11239
11455
  createButtonScrewMesh,
11456
+ createCableGrommetGeom,
11457
+ createCableGrommetMesh,
11240
11458
  createFlangedBushingGeom,
11241
11459
  createFlangedBushingMesh,
11242
11460
  createFlatHeadScrewGeom,
@@ -11245,6 +11463,8 @@ export {
11245
11463
  createHelicalGearMesh,
11246
11464
  createHexBoltGeom,
11247
11465
  createHexBoltMesh,
11466
+ createHexNutGeom,
11467
+ createHexNutMesh,
11248
11468
  createHexSocketBoltGeom,
11249
11469
  createHexSocketBoltMesh,
11250
11470
  createJSCADRenderer,