jscad-electronics 0.0.180 → 0.0.182

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
@@ -1,5 +1,8 @@
1
1
  import { BufferGeometry } from 'three';
2
2
  import * as jscadModeling from '@jscad/modeling';
3
+ import * as react_jsx_runtime from 'react/jsx-runtime';
4
+ import { NemaMotorModelPropsInput, HexSocketBoltModelPropsInput, SheetMetalModelPropsInput } from '@tscircuit/modelprinter';
5
+ import * as _jscad_modeling_src_geometries_types from '@jscad/modeling/src/geometries/types';
3
6
 
4
7
  type VNode = {
5
8
  type: any;
@@ -21,6 +24,59 @@ type RenderResult = {
21
24
 
22
25
  declare function convertCSGToThreeGeom(csg: any): BufferGeometry;
23
26
 
27
+ type NemaMotorProps = NemaMotorModelPropsInput & {
28
+ bodyColor?: string;
29
+ capColor?: string;
30
+ shaftColor?: string;
31
+ };
32
+ type NemaFrameMotorProps = Omit<NemaMotorProps, "nemaSize">;
33
+ /** Mounting face at Z=0, body along -Z, shaft along +Z; all lengths in mm.
34
+ * Parameters follow the modelprinter NEMA contract; JSCAD builds all geometry.
35
+ */
36
+ declare function NemaMotor({ bodyColor, capColor, shaftColor, ...props }: NemaMotorProps): react_jsx_runtime.JSX.Element;
37
+ declare const NEMA8: (props: NemaFrameMotorProps) => react_jsx_runtime.JSX.Element;
38
+ declare const NEMA17: (props: NemaFrameMotorProps) => react_jsx_runtime.JSX.Element;
39
+ declare const NEMA23: (props: NemaFrameMotorProps) => react_jsx_runtime.JSX.Element;
40
+
41
+ /** Indexed triangles, counterclockwise from outside; millimeters, Z up. */
42
+ interface HexSocketBoltMesh {
43
+ positions: number[];
44
+ indices: number[];
45
+ }
46
+ /**
47
+ * Head bearing plane at Z=0; tip at -length; head extends along +Z.
48
+ * Produces a closed surface with a blind hex socket and a right-hand,
49
+ * truncated 60-degree helical thread. Threads are a visual approximation.
50
+ * No renderer dependencies are needed to consume the indexed mesh.
51
+ */
52
+ declare const createHexSocketBoltMesh: (input: HexSocketBoltModelPropsInput) => HexSocketBoltMesh;
53
+
54
+ type HexSocketBoltProps = HexSocketBoltModelPropsInput & {
55
+ color?: string;
56
+ };
57
+ /** Bearing plane Z=0, tip along -Z, head along +Z. Threads are approximate. */
58
+ declare function createHexSocketBoltGeom(input: HexSocketBoltModelPropsInput): _jscad_modeling_src_geometries_types.Geom3;
59
+ declare function HexSocketBolt({ color, ...props }: HexSocketBoltProps): react_jsx_runtime.JSX.Element;
60
+
61
+ interface SheetMetalMesh {
62
+ positions: number[];
63
+ indices: number[];
64
+ }
65
+ /** Watertight sheet-metal plate, 90-degree angle or U-channel. Millimeters,
66
+ * right-handed +Z up. Base midsurface at Z=0, centered in X/Y; flanges rise
67
+ * above it. Lengths measure straight tangent-to-tangent sections. Bend skins
68
+ * use the specified inside radius and constant material thickness.
69
+ * Holes are through-cut on straight panels only; no bend allowance/unfolding.
70
+ */
71
+ declare function createSheetMetalMesh(input: SheetMetalModelPropsInput): SheetMetalMesh;
72
+
73
+ type SheetMetalProps = SheetMetalModelPropsInput & {
74
+ color?: string;
75
+ };
76
+ /** Base midsurface Z=0; bends and flanges rise along +Z. Dimensions in mm. */
77
+ declare function createSheetMetalGeom(input: SheetMetalModelPropsInput): _jscad_modeling_src_geometries_types.Geom3;
78
+ declare function SheetMetal({ color, ...props }: SheetMetalProps): react_jsx_runtime.JSX.Element;
79
+
24
80
  declare function getJscadModelForFootprint(footprint: string, jscad: typeof jscadModeling): RenderResult;
25
81
  declare function getJscadModelForFootprintWithPads(footprint: string, jscad: typeof jscadModeling): RenderResult;
26
82
  declare function createJSCADRenderer(jscad: typeof jscadModeling): {
@@ -29,4 +85,4 @@ declare function createJSCADRenderer(jscad: typeof jscadModeling): {
29
85
  };
30
86
  };
31
87
 
32
- export { type ColoredGeom, Fragment, type RenderResult, type VNode, convertCSGToThreeGeom, createJSCADRenderer, getJscadModelForFootprint, getJscadModelForFootprintWithPads, h };
88
+ export { type ColoredGeom, Fragment, HexSocketBolt, type HexSocketBoltMesh, type HexSocketBoltProps, NEMA17, NEMA23, NEMA8, type NemaFrameMotorProps, NemaMotor, type NemaMotorProps, type RenderResult, SheetMetal, type SheetMetalMesh, type SheetMetalProps, type VNode, convertCSGToThreeGeom, createHexSocketBoltGeom, createHexSocketBoltMesh, createJSCADRenderer, createSheetMetalGeom, createSheetMetalMesh, getJscadModelForFootprint, getJscadModelForFootprintWithPads, h };
package/dist/vanilla.js CHANGED
@@ -19,6 +19,7 @@ function h(type, props, ...restChildren) {
19
19
  }
20
20
 
21
21
  // lib/ExtrudedPads.tsx
22
+ import { mp } from "@tscircuit/modelprinter";
22
23
  import { fp } from "@tscircuit/footprinter";
23
24
 
24
25
  // lib/vanilla/primitives.ts
@@ -36,6 +37,7 @@ var Colorize = /* @__PURE__ */ Symbol("Colorize");
36
37
  var Polygon = /* @__PURE__ */ Symbol("Polygon");
37
38
  var ExtrudeLinear = /* @__PURE__ */ Symbol("ExtrudeLinear");
38
39
  var RoundedCylinder = /* @__PURE__ */ Symbol("RoundedCylinder");
40
+ var Custom = /* @__PURE__ */ Symbol("Custom");
39
41
 
40
42
  // lib/vanilla/react-shim.ts
41
43
  var Fragment2 = Fragment;
@@ -170,6 +172,12 @@ var ExtrudedPads = ({
170
172
  circuitJson,
171
173
  footprint
172
174
  }) => {
175
+ if (!circuitJson && footprint && ["nema", "hexsocketbolt", "sheetmetal"].includes(
176
+ mp.string(footprint.split("_", 1)[0]).params().fn
177
+ )) {
178
+ mp.string(footprint).json();
179
+ return null;
180
+ }
173
181
  if (!circuitJson && footprint) {
174
182
  circuitJson = fp.string(footprint).circuitJson();
175
183
  }
@@ -193,6 +201,395 @@ var ExtrudedPads = ({
193
201
  ] });
194
202
  };
195
203
 
204
+ // lib/mechanical/hex-socket-bolt-mesh.ts
205
+ import {
206
+ hexSocketBoltDimensions,
207
+ hexSocketBoltModelPropsSchema
208
+ } from "@tscircuit/modelprinter";
209
+ var createHexSocketBoltMesh = (input) => {
210
+ const props = hexSocketBoltModelPropsSchema.parse(input);
211
+ const {
212
+ diameter,
213
+ threadPitch: pitch,
214
+ headDiameter,
215
+ headHeight,
216
+ socketWidth,
217
+ socketDepth
218
+ } = hexSocketBoltDimensions[props.metricSize];
219
+ const { length, showThreads } = props;
220
+ const segments = 96;
221
+ const steps = Math.max(2, Math.ceil(length / pitch * 24));
222
+ if (steps > 24e3)
223
+ throw new Error(
224
+ "Bolt length exceeds mesh resolution limit (1000 thread turns)"
225
+ );
226
+ const positions = [];
227
+ const indices = [];
228
+ const radius = diameter / 2;
229
+ const depth = pitch * 0.61343;
230
+ const bevel = Math.min(0.2, headHeight * 0.08);
231
+ const tipBevel = Math.min(pitch * 0.6, length / 3);
232
+ const ring = (z, radiusAt) => {
233
+ const start = positions.length / 3;
234
+ for (let i = 0; i < segments; i++) {
235
+ const angle = i * Math.PI * 2 / segments;
236
+ const r = radiusAt(angle);
237
+ positions.push(r * Math.cos(angle), r * Math.sin(angle), z);
238
+ }
239
+ return start;
240
+ };
241
+ const connect = (a, b) => {
242
+ for (let i = 0; i < segments; i++) {
243
+ const next = (i + 1) % segments;
244
+ indices.push(a + i, a + next, b + next, a + i, b + next, b + i);
245
+ }
246
+ };
247
+ const cap = (start, z, upward) => {
248
+ const center = positions.length / 3;
249
+ positions.push(0, 0, z);
250
+ for (let i = 0; i < segments; i++) {
251
+ const a = start + i;
252
+ const b = start + (i + 1) % segments;
253
+ indices.push(center, upward ? a : b, upward ? b : a);
254
+ }
255
+ };
256
+ let previous = -1;
257
+ for (let step = 0; step <= steps; step++) {
258
+ const z = -length + length * step / steps;
259
+ const current = ring(z, (angle) => {
260
+ const phase = ((z / pitch - angle / (2 * Math.PI)) % 1 + 1) % 1;
261
+ const distance2 = Math.min(phase, 1 - phase);
262
+ const groove = Math.min(
263
+ depth,
264
+ Math.max(0, (distance2 - 1 / 16) * pitch * Math.sqrt(3))
265
+ );
266
+ const endRamp = Math.min(
267
+ 1,
268
+ (z + length) / tipBevel,
269
+ -z / Math.min(pitch / 2, length / 3)
270
+ );
271
+ const tipCut = tipBevel * Math.max(0, 1 - (z + length) / tipBevel);
272
+ return radius - (showThreads ? groove * endRamp : 0) - tipCut;
273
+ });
274
+ if (previous < 0) cap(current, z, false);
275
+ else connect(previous, current);
276
+ previous = current;
277
+ }
278
+ const addRing = (z, radiusAt) => {
279
+ const current = ring(z, radiusAt);
280
+ connect(previous, current);
281
+ previous = current;
282
+ };
283
+ addRing(0, () => headDiameter / 2 - bevel);
284
+ addRing(bevel, () => headDiameter / 2);
285
+ addRing(headHeight - bevel, () => headDiameter / 2);
286
+ addRing(headHeight, () => headDiameter / 2 - bevel);
287
+ const hexRadius = (angle, acrossFlats) => acrossFlats / 2 / Math.cos((angle + Math.PI / 6) % (Math.PI / 3) - Math.PI / 6);
288
+ addRing(headHeight, (angle) => hexRadius(angle, socketWidth + bevel));
289
+ addRing(headHeight - bevel / 2, (angle) => hexRadius(angle, socketWidth));
290
+ addRing(headHeight - socketDepth, (angle) => hexRadius(angle, socketWidth));
291
+ cap(previous, headHeight - socketDepth, true);
292
+ return { positions, indices };
293
+ };
294
+
295
+ // lib/mechanical/indexedMeshToGeom3.ts
296
+ import jscad from "@jscad/modeling";
297
+ function indexedMeshToGeom3(mesh) {
298
+ const polygons = [];
299
+ for (let i = 0; i < mesh.indices.length; i += 3)
300
+ polygons.push(
301
+ mesh.indices.slice(i, i + 3).map((index) => [
302
+ mesh.positions[index * 3],
303
+ mesh.positions[index * 3 + 1],
304
+ mesh.positions[index * 3 + 2]
305
+ ])
306
+ );
307
+ return jscad.geometries.geom3.fromPoints(polygons);
308
+ }
309
+
310
+ // lib/HexSocketBolt.tsx
311
+ function createHexSocketBoltGeom(input) {
312
+ return indexedMeshToGeom3(createHexSocketBoltMesh(input));
313
+ }
314
+ function HexSocketBolt({
315
+ color = "#737e8f",
316
+ ...props
317
+ }) {
318
+ return /* @__PURE__ */ jsx(Colorize, { color, children: /* @__PURE__ */ jsx(Custom, { geometry: createHexSocketBoltGeom(props) }) });
319
+ }
320
+
321
+ // lib/mechanical/sheet-metal-mesh.ts
322
+ import earcut from "earcut";
323
+ import {
324
+ sheetMetalModelPropsSchema
325
+ } from "@tscircuit/modelprinter";
326
+ function holeOutline(hole) {
327
+ const radius = (hole.shape === "round" ? hole.diameter : hole.width) / 2;
328
+ const straight = hole.shape === "slot" ? (hole.length - hole.width) / 2 : 0;
329
+ if (straight < 0) throw new Error("Slot length must be at least its width");
330
+ return Array.from({ length: 64 }, (_, i) => {
331
+ if (hole.shape === "round") {
332
+ const angle2 = i * Math.PI / 32;
333
+ return {
334
+ u: hole.u + radius * Math.cos(angle2),
335
+ v: hole.v + radius * Math.sin(angle2)
336
+ };
337
+ }
338
+ const half = i < 32 ? 1 : -1;
339
+ const angle = -Math.PI / 2 + (i < 32 ? i : i - 32) * Math.PI / 31 + (i < 32 ? 0 : Math.PI);
340
+ const along = half * straight + radius * Math.cos(angle);
341
+ const across = radius * Math.sin(angle);
342
+ return hole.shape === "slot" && hole.axis === "v" ? { u: hole.u - across, v: hole.v + along } : { u: hole.u + along, v: hole.v + across };
343
+ });
344
+ }
345
+ function createSheetMetalMesh(input) {
346
+ const props = sheetMetalModelPropsSchema.parse(input);
347
+ const { width: width10, baseLength, flangeHeight, thickness, profile } = props;
348
+ const radius = props.insideBendRadius + thickness / 2;
349
+ const positions = [];
350
+ const indices = [];
351
+ const addTriangle = (vertices, reverse = false) => {
352
+ const start = positions.length / 3;
353
+ for (const vertex of vertices) positions.push(...vertex);
354
+ indices.push(start, start + (reverse ? 2 : 1), start + (reverse ? 1 : 2));
355
+ };
356
+ const addQuad = (vertices, reverse = false) => {
357
+ addTriangle([vertices[0], vertices[1], vertices[2]], reverse);
358
+ addTriangle([vertices[0], vertices[2], vertices[3]], reverse);
359
+ };
360
+ const panels = profile === "plate" ? ["base"] : profile === "angle" ? ["base", "right"] : ["base", "left", "right"];
361
+ for (const hole of props.holes) {
362
+ if (!panels.includes(hole.panel))
363
+ throw new Error(`No ${hole.panel} panel on ${profile}`);
364
+ }
365
+ for (const panel of panels) {
366
+ const length = panel === "base" ? baseLength : flangeHeight;
367
+ const holes = props.holes.filter((hole) => hole.panel === panel).map(holeOutline);
368
+ const bounds = holes.map((outline2) => ({
369
+ minU: Math.min(...outline2.map((p) => p.u)),
370
+ maxU: Math.max(...outline2.map((p) => p.u)),
371
+ minV: Math.min(...outline2.map((p) => p.v)),
372
+ maxV: Math.max(...outline2.map((p) => p.v))
373
+ }));
374
+ for (const [i, box] of bounds.entries()) {
375
+ if (box.minU <= -length / 2 || box.maxU >= length / 2 || box.minV <= -width10 / 2 || box.maxV >= width10 / 2)
376
+ throw new Error(`Hole crosses ${panel} panel edge or bend tangent`);
377
+ for (const previous of bounds.slice(0, i))
378
+ if (box.minU <= previous.maxU && box.maxU >= previous.minU && box.minV <= previous.maxV && box.maxV >= previous.minV)
379
+ throw new Error("Hole bounding boxes must not overlap");
380
+ }
381
+ const outline = [
382
+ { u: -length / 2, v: -width10 / 2 },
383
+ { u: length / 2, v: -width10 / 2 },
384
+ { u: length / 2, v: width10 / 2 },
385
+ { u: -length / 2, v: width10 / 2 }
386
+ ];
387
+ const loops = [outline, ...holes.map((hole) => [...hole].reverse())];
388
+ const points = loops.flat();
389
+ const starts = holes.map((_, i) => 4 + i * 64);
390
+ const triangles = earcut(
391
+ points.flatMap((p) => [p.u, p.v]),
392
+ starts
393
+ );
394
+ const project = (point, offset) => panel === "base" ? [point.u, point.v, offset] : [
395
+ (panel === "left" ? -1 : 1) * (baseLength / 2 + radius - offset),
396
+ point.v,
397
+ radius + flangeHeight / 2 + point.u
398
+ ];
399
+ const reverse = panel === "left";
400
+ for (let i = 0; i < triangles.length; i += 3) {
401
+ const face2 = triangles.slice(i, i + 3).map((index) => points[index]);
402
+ addTriangle(
403
+ face2.map((p) => project(p, thickness / 2)),
404
+ reverse
405
+ );
406
+ addTriangle(
407
+ face2.map((p) => project(p, -thickness / 2)),
408
+ !reverse
409
+ );
410
+ }
411
+ for (const [loopIndex, loop] of loops.entries())
412
+ for (let i = 0; i < loop.length; i++) {
413
+ const a = loop[i], b = loop[(i + 1) % loop.length];
414
+ if (loopIndex === 0 && a.u === b.u && (panel === "base" && (a.u > 0 && profile !== "plate" || a.u < 0 && profile === "channel") || panel !== "base" && a.u < 0))
415
+ continue;
416
+ addQuad(
417
+ [
418
+ project(a, -thickness / 2),
419
+ project(b, -thickness / 2),
420
+ project(b, thickness / 2),
421
+ project(a, thickness / 2)
422
+ ],
423
+ reverse
424
+ );
425
+ }
426
+ }
427
+ const sides = profile === "plate" ? [] : profile === "angle" ? [1] : [-1, 1];
428
+ for (const side of sides) {
429
+ const project = (angle, crossSection) => {
430
+ const r = radius - crossSection.offset;
431
+ return [
432
+ side * (baseLength / 2 + r * Math.sin(angle)),
433
+ crossSection.y,
434
+ radius - r * Math.cos(angle)
435
+ ];
436
+ };
437
+ for (let i = 0; i < 32; i++) {
438
+ const a = i * Math.PI / 64, b = (i + 1) * Math.PI / 64;
439
+ for (const offset of [-thickness / 2, thickness / 2]) {
440
+ addQuad(
441
+ [
442
+ project(a, { y: -width10 / 2, offset }),
443
+ project(b, { y: -width10 / 2, offset }),
444
+ project(b, { y: width10 / 2, offset }),
445
+ project(a, { y: width10 / 2, offset })
446
+ ],
447
+ offset < 0 !== side < 0
448
+ );
449
+ }
450
+ for (const y of [-width10 / 2, width10 / 2]) {
451
+ addQuad(
452
+ [
453
+ project(a, { y, offset: -thickness / 2 }),
454
+ project(b, { y, offset: -thickness / 2 }),
455
+ project(b, { y, offset: thickness / 2 }),
456
+ project(a, { y, offset: thickness / 2 })
457
+ ],
458
+ y > 0 !== side < 0
459
+ );
460
+ }
461
+ }
462
+ }
463
+ return { positions, indices };
464
+ }
465
+
466
+ // lib/SheetMetal.tsx
467
+ function createSheetMetalGeom(input) {
468
+ return indexedMeshToGeom3(createSheetMetalMesh(input));
469
+ }
470
+ function SheetMetal({ color = "#737e8f", ...props }) {
471
+ return /* @__PURE__ */ jsx(Colorize, { color, children: /* @__PURE__ */ jsx(Custom, { geometry: createSheetMetalGeom(props) }) });
472
+ }
473
+
474
+ // lib/NemaMotor.tsx
475
+ import jscad2 from "@jscad/modeling";
476
+
477
+ // lib/utils/nemaMotorParameters.ts
478
+ import { mp as mp2, nemaMotorModelPropsSchema } from "@tscircuit/modelprinter";
479
+ var resolveNemaMotorProps = nemaMotorModelPropsSchema.parse.bind(
480
+ nemaMotorModelPropsSchema
481
+ );
482
+
483
+ // lib/utils/nemaMotorGeometry.ts
484
+ var circle = (radius, x = 0, y = 0) => Array.from({ length: 96 }, (_, i) => [
485
+ x + radius * Math.cos(i * Math.PI / 48),
486
+ y + radius * Math.sin(i * Math.PI / 48)
487
+ ]);
488
+ var face = (width10, chamfer) => {
489
+ const h2 = width10 / 2, c = chamfer;
490
+ if (c === 0)
491
+ return [
492
+ [-h2, -h2],
493
+ [h2, -h2],
494
+ [h2, h2],
495
+ [-h2, h2]
496
+ ];
497
+ return [
498
+ [-h2 + c, -h2],
499
+ [h2 - c, -h2],
500
+ [h2, -h2 + c],
501
+ [h2, h2 - c],
502
+ [h2 - c, h2],
503
+ [-h2 + c, h2],
504
+ [-h2, h2 - c],
505
+ [-h2, -h2 + c]
506
+ ];
507
+ };
508
+ function createNemaMotorSections(input) {
509
+ const p = resolveNemaMotorProps(input);
510
+ const sections = [];
511
+ const add = (name, outline, zMin, zMax, holes2 = []) => {
512
+ if (zMax > zMin) sections.push({ name, outline, holes: holes2, zMin, zMax });
513
+ };
514
+ const front = face(p.bodyWidth, p.faceCornerChamfer);
515
+ const core = face(p.bodyWidth, p.bodyCornerChamfer);
516
+ const h2 = p.mountingHoleSpacing / 2;
517
+ const centers = [
518
+ [-h2, -h2],
519
+ [h2, -h2],
520
+ [h2, h2],
521
+ [-h2, h2]
522
+ ];
523
+ const holes = centers.map(
524
+ ([x, y]) => circle(p.mountingHoleDiameter / 2, x, y)
525
+ );
526
+ const holeDepth = p.mountingHoleThrough ? p.frontCapLength : p.mountingHoleDepth;
527
+ add("frontCap", front, -holeDepth, 0, holes);
528
+ add("frontCap", front, -p.frontCapLength, -holeDepth);
529
+ add("body", core, -p.bodyLength + p.rearCapLength, -p.frontCapLength);
530
+ add(
531
+ "rearCap",
532
+ p.mountingHoleThrough ? core : front,
533
+ -p.bodyLength,
534
+ -p.bodyLength + p.rearCapLength
535
+ );
536
+ add("pilot", circle(p.pilotDiameter / 2), 0, p.pilotLength);
537
+ const r = p.shaftDiameter / 2;
538
+ const round = circle(r);
539
+ if (p.shaftShape === "round")
540
+ add("shaft", round, p.pilotLength, p.shaftLength);
541
+ else {
542
+ const cut = r - p.shaftFlatDepth;
543
+ const angle = Math.acos(cut / r);
544
+ const profile = Array.from({ length: 97 }, (_, i) => {
545
+ const a = angle + (2 * Math.PI - 2 * angle) * i / 96;
546
+ return [r * Math.cos(a), r * Math.sin(a)];
547
+ });
548
+ const rotation = p.shaftFlatAngle * Math.PI / 180;
549
+ const d = profile.map(([x, y]) => [
550
+ x * Math.cos(rotation) - y * Math.sin(rotation),
551
+ x * Math.sin(rotation) + y * Math.cos(rotation)
552
+ ]);
553
+ add("shaft", round, p.pilotLength, p.shaftLength - p.shaftFlatLength);
554
+ add("shaft", d, p.shaftLength - p.shaftFlatLength, p.shaftLength);
555
+ }
556
+ return sections;
557
+ }
558
+
559
+ // lib/NemaMotor.tsx
560
+ function NemaMotor({
561
+ bodyColor = "#242830",
562
+ capColor = "#aeb5bd",
563
+ shaftColor = "#b8bec6",
564
+ ...props
565
+ }) {
566
+ return /* @__PURE__ */ jsx(Fragment2, { children: createNemaMotorSections(props).map((section, index) => {
567
+ const outline = jscad2.geometries.geom2.fromPoints(section.outline);
568
+ const profile = section.holes.length ? jscad2.booleans.subtract(
569
+ outline,
570
+ ...section.holes.map((h2) => jscad2.geometries.geom2.fromPoints(h2))
571
+ ) : outline;
572
+ const geometry = jscad2.transforms.translate(
573
+ [0, 0, section.zMin],
574
+ jscad2.extrusions.extrudeLinear(
575
+ { height: section.zMax - section.zMin },
576
+ profile
577
+ )
578
+ );
579
+ return /* @__PURE__ */ jsx(
580
+ Colorize,
581
+ {
582
+ color: section.name === "body" ? bodyColor : section.name === "shaft" ? shaftColor : capColor,
583
+ children: /* @__PURE__ */ jsx(Custom, { geometry })
584
+ },
585
+ `${section.name}-${index}`
586
+ );
587
+ }) });
588
+ }
589
+ var NEMA8 = (props) => /* @__PURE__ */ jsx(NemaMotor, { ...props, nemaSize: 8 });
590
+ var NEMA17 = (props) => /* @__PURE__ */ jsx(NemaMotor, { ...props, nemaSize: 17 });
591
+ var NEMA23 = (props) => /* @__PURE__ */ jsx(NemaMotor, { ...props, nemaSize: 23 });
592
+
196
593
  // lib/LGA.tsx
197
594
  function LGA(p) {
198
595
  for (const k of [
@@ -489,7 +886,7 @@ function renderFootprinterBodyModel(p) {
489
886
 
490
887
  // lib/Footprinter3d.tsx
491
888
  import { fp as fp10 } from "@tscircuit/footprinter";
492
- import { mp } from "@tscircuit/modelprinter";
889
+ import { mp as mp3 } from "@tscircuit/modelprinter";
493
890
 
494
891
  // lib/ChipBody.tsx
495
892
  var ChipBody = ({
@@ -8195,10 +8592,22 @@ var FlexScreen = (props) => {
8195
8592
 
8196
8593
  // lib/Footprinter3d.tsx
8197
8594
  var Footprinter3d = ({ footprint }) => {
8198
- const modelFn = mp.string(footprint.split("_", 1)[0]).params().fn;
8199
- if (mp.getModelNames().includes(modelFn)) {
8200
- const model = mp.string(footprint).json();
8595
+ const modelFn = mp3.string(footprint.split("_", 1)[0]).params().fn;
8596
+ if (mp3.getModelNames().includes(modelFn)) {
8597
+ const model = mp3.string(footprint).json();
8201
8598
  switch (model.fn) {
8599
+ case "nema": {
8600
+ const { fn, ...props } = model;
8601
+ return /* @__PURE__ */ jsx(NemaMotor, { ...props });
8602
+ }
8603
+ case "hexsocketbolt": {
8604
+ const { fn, ...props } = model;
8605
+ return /* @__PURE__ */ jsx(HexSocketBolt, { ...props });
8606
+ }
8607
+ case "sheetmetal": {
8608
+ const { fn, ...props } = model;
8609
+ return /* @__PURE__ */ jsx(SheetMetal, { ...props });
8610
+ }
8202
8611
  case "flexscreen": {
8203
8612
  const { fn: _, ...flexScreenProps } = model;
8204
8613
  return /* @__PURE__ */ jsx(FlexScreen, { ...flexScreenProps });
@@ -8942,6 +9351,9 @@ function renderNode(node, colorCtx, renderCtx) {
8942
9351
  else geom = hulls.hull(geoms);
8943
9352
  return [{ geom, color: colorCtx }];
8944
9353
  }
9354
+ if (type === Custom) {
9355
+ return [{ geom: props.geometry, color: colorCtx }];
9356
+ }
8945
9357
  if (type === Polygon) {
8946
9358
  const points = props?.points ?? [];
8947
9359
  const g2 = geometries.geom2.fromPoints(points);
@@ -9002,8 +9414,8 @@ function renderNode(node, colorCtx, renderCtx) {
9002
9414
  }
9003
9415
  return (children ?? []).flatMap((c) => renderNode(c, colorCtx, renderCtx));
9004
9416
  }
9005
- function render(root, jscad) {
9006
- const geometries = renderNode(root, void 0, { jscad });
9417
+ function render(root, jscad3) {
9418
+ const geometries = renderNode(root, void 0, { jscad: jscad3 });
9007
9419
  return { geometries };
9008
9420
  }
9009
9421
 
@@ -9091,24 +9503,24 @@ function convertCSGToThreeGeom(csg) {
9091
9503
  }
9092
9504
 
9093
9505
  // lib/vanilla/index.ts
9094
- function getJscadModelForFootprint(footprint, jscad) {
9506
+ function getJscadModelForFootprint(footprint, jscad3) {
9095
9507
  const vnode = h(Footprinter3d, { footprint });
9096
- return render(vnode, jscad);
9508
+ return render(vnode, jscad3);
9097
9509
  }
9098
- function getJscadModelForFootprintWithPads(footprint, jscad) {
9510
+ function getJscadModelForFootprintWithPads(footprint, jscad3) {
9099
9511
  const vnode = h(
9100
9512
  Fragment,
9101
9513
  {},
9102
9514
  h(Footprinter3d, { footprint }),
9103
9515
  h(ExtrudedPads, { footprint })
9104
9516
  );
9105
- return render(vnode, jscad);
9517
+ return render(vnode, jscad3);
9106
9518
  }
9107
- function createJSCADRenderer(jscad) {
9519
+ function createJSCADRenderer(jscad3) {
9108
9520
  function createJSCADRoot(container) {
9109
9521
  return {
9110
9522
  render(element) {
9111
- const { geometries } = render(element, jscad);
9523
+ const { geometries } = render(element, jscad3);
9112
9524
  container.splice(0, container.length, ...geometries);
9113
9525
  }
9114
9526
  };
@@ -9117,8 +9529,18 @@ function createJSCADRenderer(jscad) {
9117
9529
  }
9118
9530
  export {
9119
9531
  Fragment,
9532
+ HexSocketBolt,
9533
+ NEMA17,
9534
+ NEMA23,
9535
+ NEMA8,
9536
+ NemaMotor,
9537
+ SheetMetal,
9120
9538
  convertCSGToThreeGeom,
9539
+ createHexSocketBoltGeom,
9540
+ createHexSocketBoltMesh,
9121
9541
  createJSCADRenderer,
9542
+ createSheetMetalGeom,
9543
+ createSheetMetalMesh,
9122
9544
  getJscadModelForFootprint,
9123
9545
  getJscadModelForFootprintWithPads,
9124
9546
  h