jscad-electronics 0.0.188 → 0.0.190
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/cables.d.ts +4 -0
- package/dist/cables.js +26 -3
- package/dist/cables.js.map +1 -1
- package/dist/index.d.ts +182 -182
- package/dist/index.js +8318 -8030
- package/dist/index.js.map +1 -1
- package/dist/vanilla.d.ts +62 -60
- package/dist/vanilla.js +8285 -7971
- package/dist/vanilla.js.map +1 -1
- package/package.json +19 -13
package/dist/cables.d.ts
CHANGED
package/dist/cables.js
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
// lib/materials.ts
|
|
2
|
+
var componentMaterials = {
|
|
3
|
+
moldedPlastic: { metalness: 0, roughness: 0.7 },
|
|
4
|
+
rubber: { metalness: 0, roughness: 0.9 },
|
|
5
|
+
sleeve: { metalness: 0, roughness: 0.45 },
|
|
6
|
+
tinnedLead: { metalness: 0.8, roughness: 0.55 },
|
|
7
|
+
goldContact: { metalness: 1, roughness: 0.25 },
|
|
8
|
+
copper: { metalness: 1, roughness: 0.35 },
|
|
9
|
+
brushedMetal: { metalness: 1, roughness: 0.4 },
|
|
10
|
+
steel: { metalness: 1, roughness: 0.25 }
|
|
11
|
+
};
|
|
12
|
+
|
|
1
13
|
// lib/cables/connector-meshes.ts
|
|
2
14
|
import jscad2 from "@jscad/modeling";
|
|
3
15
|
|
|
@@ -73,7 +85,8 @@ function createCablePathFrames(path) {
|
|
|
73
85
|
function geometryToCableMesh({
|
|
74
86
|
geometry,
|
|
75
87
|
color,
|
|
76
|
-
name
|
|
88
|
+
name,
|
|
89
|
+
material
|
|
77
90
|
}) {
|
|
78
91
|
const triangles = jscad.geometries.geom3.toPolygons(geometry);
|
|
79
92
|
const positions = [];
|
|
@@ -99,7 +112,7 @@ function geometryToCableMesh({
|
|
|
99
112
|
);
|
|
100
113
|
}
|
|
101
114
|
}
|
|
102
|
-
return { name, positions, indices, color, smooth: false };
|
|
115
|
+
return { name, positions, indices, color, material, smooth: false };
|
|
103
116
|
}
|
|
104
117
|
function placeConnectorMesh({
|
|
105
118
|
mesh,
|
|
@@ -193,6 +206,7 @@ function createJstMeshes(connector) {
|
|
|
193
206
|
const contacts = Array.from({ length: pinCount }, (_, index) => {
|
|
194
207
|
const x = (index - (pinCount - 1) / 2) * pitch;
|
|
195
208
|
return geometryToCableMesh({
|
|
209
|
+
material: componentMaterials.goldContact,
|
|
196
210
|
name: `contact-${index + 1}`,
|
|
197
211
|
color: metal,
|
|
198
212
|
geometry: subtract2(
|
|
@@ -282,7 +296,12 @@ function createUsbMeshes(connector) {
|
|
|
282
296
|
);
|
|
283
297
|
return [
|
|
284
298
|
geometryToCableMesh({ geometry: body, color: plastic, name: "overmold" }),
|
|
285
|
-
geometryToCableMesh({
|
|
299
|
+
geometryToCableMesh({
|
|
300
|
+
geometry: shell,
|
|
301
|
+
color: metal,
|
|
302
|
+
material: componentMaterials.brushedMetal,
|
|
303
|
+
name: "shell"
|
|
304
|
+
}),
|
|
286
305
|
geometryToCableMesh({
|
|
287
306
|
geometry: liner,
|
|
288
307
|
color: [0.025, 0.026, 0.03, 1],
|
|
@@ -292,6 +311,7 @@ function createUsbMeshes(connector) {
|
|
|
292
311
|
(geometry, index) => geometryToCableMesh({
|
|
293
312
|
geometry,
|
|
294
313
|
color: brass,
|
|
314
|
+
material: componentMaterials.goldContact,
|
|
295
315
|
name: `contact-${index + 1}`
|
|
296
316
|
})
|
|
297
317
|
)
|
|
@@ -340,12 +360,14 @@ function createMainsMeshes(connector) {
|
|
|
340
360
|
(geometry, index) => geometryToCableMesh({
|
|
341
361
|
geometry,
|
|
342
362
|
color: brass,
|
|
363
|
+
material: componentMaterials.goldContact,
|
|
343
364
|
name: `blade-${index + 1}`
|
|
344
365
|
})
|
|
345
366
|
),
|
|
346
367
|
geometryToCableMesh({
|
|
347
368
|
geometry: ground,
|
|
348
369
|
color: brass,
|
|
370
|
+
material: componentMaterials.goldContact,
|
|
349
371
|
name: "ground-pin"
|
|
350
372
|
})
|
|
351
373
|
];
|
|
@@ -386,6 +408,7 @@ function createMainsMeshes(connector) {
|
|
|
386
408
|
([x, y], index) => geometryToCableMesh({
|
|
387
409
|
geometry: cuboid({ size: [0.15, 2.8, 6], center: [x - 1.05, y, 7.8] }),
|
|
388
410
|
color: brass,
|
|
411
|
+
material: componentMaterials.goldContact,
|
|
389
412
|
name: `socket-contact-${index + 1}`
|
|
390
413
|
})
|
|
391
414
|
)
|
package/dist/cables.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../lib/cables/connector-meshes.ts","../lib/cables/geometry-to-mesh.ts","../lib/cables/path-frames.ts","../lib/cables/sweep-round-cable.ts","../lib/cables/create-cable-meshes.ts"],"sourcesContent":["import jscad from \"@jscad/modeling\"\nimport { geometryToCableMesh } from \"./geometry-to-mesh\"\nimport type {\n CableColor,\n CableConnectorSpec,\n CableMesh,\n CablePoint,\n} from \"./types\"\n\nconst { cuboid, roundedCuboid, cylinder, roundedRectangle, polygon, sphere } =\n jscad.primitives\nconst { extrudeLinear } = jscad.extrusions\nconst { translate, rotateY } = jscad.transforms\nconst { subtract, union } = jscad.booleans\nconst plastic: CableColor = [0.055, 0.07, 0.09, 1]\nconst housing: CableColor = [0.86, 0.84, 0.75, 1]\nconst metal: CableColor = [0.6, 0.64, 0.7, 1]\nconst brass: CableColor = [0.66, 0.46, 0.18, 1]\n\nexport function connectorWireExitDepth(connector: CableConnectorSpec): number {\n if (connector.kind === \"usb_c_plug\")\n return connector.shellDepth + connector.bodyDepth\n if (connector.kind === \"nema_5_15p\") return 19.05 + connector.bodyDepth\n return connector.bodyDepth\n}\n\nfunction createJstMeshes(\n connector: Extract<\n CableConnectorSpec,\n { kind: \"jst_sh_housing\" | \"jst_ph_housing\" }\n >,\n): CableMesh[] {\n const {\n bodyWidth: width,\n bodyHeight: height,\n bodyDepth: depth,\n pinCount,\n pitch,\n } = connector\n const opening = pitch === 1 ? 0.55 : 1.05\n const holes = Array.from({ length: pinCount }, (_, index) => {\n const x = (index - (pinCount - 1) / 2) * pitch\n return cuboid({\n size: [opening, opening * 1.35, depth - 0.6],\n center: [x, 0, (depth - 0.6) / 2 - 0.02],\n })\n })\n const backHoles = Array.from({ length: pinCount }, (_, index) =>\n cylinder({\n radius: pitch * 0.34,\n height: 1.3,\n segments: 16,\n center: [(index - (pinCount - 1) / 2) * pitch, 0, depth - 0.5],\n }),\n )\n const latchCut = cuboid({\n size: [width * 0.45, 0.5, depth * 0.5],\n center: [0, height / 2, depth * 0.65],\n })\n const body = subtract(\n roundedCuboid({\n size: [width, height, depth],\n center: [0, 0, depth / 2],\n roundRadius: 0.1,\n segments: 8,\n }),\n ...holes,\n ...backHoles,\n latchCut,\n ...Array.from({ length: pinCount }, (_, index) =>\n cuboid({\n size: [opening * 0.8, height * 0.7, depth * 0.24],\n center: [(index - (pinCount - 1) / 2) * pitch, height / 2, depth * 0.7],\n }),\n ),\n )\n const contacts = Array.from({ length: pinCount }, (_, index) => {\n const x = (index - (pinCount - 1) / 2) * pitch\n return geometryToCableMesh({\n name: `contact-${index + 1}`,\n color: metal,\n geometry: subtract(\n cuboid({\n size: [opening * 0.92, opening * 1.25, depth * 0.65],\n center: [x, 0, depth * 0.45],\n }),\n cuboid({\n size: [\n opening * 0.92 - 0.12,\n opening * 1.25 - 0.12,\n depth * 0.65 + 0.2,\n ],\n center: [x, 0, depth * 0.45],\n }),\n ),\n })\n })\n return [\n geometryToCableMesh({ geometry: body, color: housing, name: \"housing\" }),\n ...contacts,\n ]\n}\n\nfunction createUsbMeshes(\n connector: Extract<CableConnectorSpec, { kind: \"usb_c_plug\" }>,\n): CableMesh[] {\n const {\n shellWidth,\n shellHeight,\n shellDepth,\n bodyWidth,\n bodyHeight,\n bodyDepth,\n } = connector\n const shell = subtract(\n extrudeLinear(\n { height: shellDepth },\n roundedRectangle({\n size: [shellWidth, shellHeight],\n roundRadius: shellHeight / 2 - 0.02,\n segments: 32,\n }),\n ),\n translate(\n [0, 0, -0.1],\n extrudeLinear(\n { height: shellDepth + 0.2 },\n roundedRectangle({\n size: [shellWidth - 0.4, shellHeight - 0.4],\n roundRadius: (shellHeight - 0.4) / 2 - 0.02,\n segments: 32,\n }),\n ),\n ),\n )\n const liner = subtract(\n extrudeLinear(\n { height: shellDepth },\n roundedRectangle({\n size: [shellWidth - 0.41, shellHeight - 0.41],\n roundRadius: 0.85,\n segments: 32,\n }),\n ),\n translate(\n [0, 0, -0.1],\n extrudeLinear(\n { height: shellDepth - 0.3 },\n roundedRectangle({\n size: [shellWidth - 0.8, shellHeight - 0.8],\n roundRadius: 0.65,\n segments: 32,\n }),\n ),\n ),\n )\n const body = roundedCuboid({\n size: [bodyWidth, bodyHeight, bodyDepth],\n center: [0, 0, shellDepth + bodyDepth / 2],\n roundRadius: Math.min(1.3, bodyHeight / 4),\n segments: 16,\n })\n const contacts = Array.from({ length: 24 }, (_, index) =>\n cuboid({\n size: [0.22, 0.08, 3.5],\n center: [((index % 12) - 5.5) * 0.5, index < 12 ? 0.77 : -0.77, 2.6],\n }),\n )\n return [\n geometryToCableMesh({ geometry: body, color: plastic, name: \"overmold\" }),\n geometryToCableMesh({ geometry: shell, color: metal, name: \"shell\" }),\n geometryToCableMesh({\n geometry: liner,\n color: [0.025, 0.026, 0.03, 1],\n name: \"liner\",\n }),\n ...contacts.map((geometry, index) =>\n geometryToCableMesh({\n geometry,\n color: brass,\n name: `contact-${index + 1}`,\n }),\n ),\n ]\n}\n\nfunction createMainsMeshes(connector: CableConnectorSpec): CableMesh[] {\n const { bodyWidth, bodyHeight, bodyDepth, kind } = connector\n const faceDepth = kind === \"nema_5_15p\" ? 19.05 : 0\n let body = roundedCuboid({\n size: [bodyWidth, bodyHeight, bodyDepth],\n center: [0, 0, faceDepth + bodyDepth / 2],\n roundRadius: 2,\n segments: 16,\n })\n if (kind === \"nema_5_15p\") {\n const blades = [-6.35, 6.35].map((x) => {\n const blade = cuboid({\n size: [1.524, 6.35, 15.875],\n center: [x, 2.7, 19.05 - 15.875 / 2],\n })\n const hole = translate(\n [x, 2.7, 7.3],\n rotateY(\n Math.PI / 2,\n cylinder({ radius: 1.1, height: 3, segments: 20 }),\n ),\n )\n return subtract(blade, hole)\n })\n const ground = union(\n cylinder({\n radius: 2.38125,\n height: 19.05 - 2.38125,\n center: [0, -9.20625, (19.05 + 2.38125) / 2],\n segments: 32,\n }),\n sphere({ radius: 2.38125, center: [0, -9.20625, 2.38125], segments: 32 }),\n )\n return [\n geometryToCableMesh({\n geometry: body,\n color: plastic,\n name: \"plug-body\",\n }),\n ...blades.map((geometry, index) =>\n geometryToCableMesh({\n geometry,\n color: brass,\n name: `blade-${index + 1}`,\n }),\n ),\n geometryToCableMesh({\n geometry: ground,\n color: brass,\n name: \"ground-pin\",\n }),\n ]\n }\n const recess = translate(\n [0, 0, -0.1],\n extrudeLinear(\n { height: 3.2 },\n polygon({\n points: [\n [-9, -6],\n [9, -6],\n [9, 2],\n [5, 6],\n [-5, 6],\n [-9, 2],\n ],\n }),\n ),\n )\n const sockets: CablePoint[] = [\n [-4.4, -1.8, 8],\n [4.4, -1.8, 8],\n [0, 3.1, 8],\n ]\n body = subtract(\n body,\n recess,\n ...sockets.map((center) => cuboid({ size: [2.3, 3.4, 16.2], center })),\n )\n return [\n geometryToCableMesh({\n geometry: body,\n color: plastic,\n name: \"appliance-body\",\n }),\n ...sockets.map(([x, y], index) =>\n geometryToCableMesh({\n geometry: cuboid({ size: [0.15, 2.8, 6], center: [x - 1.05, y, 7.8] }),\n color: brass,\n name: `socket-contact-${index + 1}`,\n }),\n ),\n ]\n}\n\nexport function createConnectorMeshes({\n connector,\n jacketDiameter,\n}: { connector: CableConnectorSpec; jacketDiameter?: number }): CableMesh[] {\n const meshes =\n connector.kind === \"usb_c_plug\"\n ? createUsbMeshes(connector)\n : \"pinCount\" in connector\n ? createJstMeshes(connector)\n : createMainsMeshes(connector)\n if (jacketDiameter !== undefined) {\n const exit = connectorWireExitDepth(connector)\n const boot = union(\n cylinder({\n radius: jacketDiameter / 2 + 0.15,\n height: 5,\n center: [0, 0, exit + 2.5],\n segments: 32,\n }),\n ...Array.from({ length: 7 }, (_, index) =>\n cylinder({\n radius: jacketDiameter / 2 + 0.8 - index * 0.06,\n height: 0.28,\n center: [0, 0, exit + 0.4 + index * 0.7],\n segments: 32,\n }),\n ),\n )\n meshes.push(\n geometryToCableMesh({\n geometry: boot,\n color: plastic,\n name: \"strain-relief\",\n }),\n )\n }\n return meshes\n}\n","import jscad from \"@jscad/modeling\"\nimport type { Geom3 } from \"@jscad/modeling/src/geometries/geom3\"\nimport type { CableMesh, CableColor, CableFrame, CablePoint } from \"./types\"\nimport { add, scale } from \"./path-frames\"\n\ntype VertexKey = string\n\nexport function geometryToCableMesh({\n geometry,\n color,\n name,\n}: { geometry: Geom3; color: CableColor; name: string }): CableMesh {\n const triangles = jscad.geometries.geom3.toPolygons(geometry)\n const positions: number[] = []\n const indices: number[] = []\n const vertices = new Map<VertexKey, number>()\n for (const triangle of triangles) {\n const polygonIndices: number[] = []\n for (const point of triangle.vertices) {\n const key = point.map((coordinate) => coordinate.toFixed(8)).join(\",\")\n let index = vertices.get(key)\n if (index === undefined) {\n index = positions.length / 3\n positions.push(...point)\n vertices.set(key, index)\n }\n polygonIndices.push(index)\n }\n // JSCAD CSG polygons are convex, so a fan preserves their outward winding.\n for (let side = 1; side < polygonIndices.length - 1; side++) {\n indices.push(\n polygonIndices[0]!,\n polygonIndices[side]!,\n polygonIndices[side + 1]!,\n )\n }\n }\n return { name, positions, indices, color, smooth: false }\n}\n\nexport function placeConnectorMesh({\n mesh,\n frame,\n wireExitDepth,\n isEnd,\n}: {\n mesh: CableMesh\n frame: CableFrame\n wireExitDepth: number\n isEnd: boolean\n}): CableMesh {\n const tangent = scale(frame.tangent, isEnd ? -1 : 1)\n const binormal: CablePoint = isEnd\n ? scale(frame.binormal, -1)\n : frame.binormal\n const origin = add(frame.point, scale(tangent, -wireExitDepth))\n const positions: number[] = []\n for (let index = 0; index < mesh.positions.length; index += 3) {\n positions.push(\n ...add(\n origin,\n add(\n add(\n scale(frame.normal, mesh.positions[index]!),\n scale(binormal, mesh.positions[index + 1]!),\n ),\n scale(tangent, mesh.positions[index + 2]!),\n ),\n ),\n )\n }\n return { ...mesh, positions }\n}\n","import type { CableFrame, CablePoint } from \"./types\"\n\nexport const add = (a: CablePoint, b: CablePoint): CablePoint => [\n a[0] + b[0],\n a[1] + b[1],\n a[2] + b[2],\n]\nexport const subtract = (a: CablePoint, b: CablePoint): CablePoint => [\n a[0] - b[0],\n a[1] - b[1],\n a[2] - b[2],\n]\nexport const scale = (point: CablePoint, factor: number): CablePoint => [\n point[0] * factor,\n point[1] * factor,\n point[2] * factor,\n]\nexport const dot = (a: CablePoint, b: CablePoint) =>\n a[0] * b[0] + a[1] * b[1] + a[2] * b[2]\nexport const cross = (a: CablePoint, b: CablePoint): CablePoint => [\n a[1] * b[2] - a[2] * b[1],\n a[2] * b[0] - a[0] * b[2],\n a[0] * b[1] - a[1] * b[0],\n]\nexport function normalize(point: CablePoint): CablePoint {\n const length = Math.hypot(...point)\n if (length < 1e-10)\n throw new Error(\n \"Cable path must not contain coincident points or a reversing tangent\",\n )\n return scale(point, 1 / length)\n}\n\n/** Parallel transport avoids a wire bundle flipping when its tangent crosses an axis. */\nexport function createCablePathFrames(path: CablePoint[]): CableFrame[] {\n if (\n path.length < 2 ||\n path.some((point) => point.length !== 3 || !point.every(Number.isFinite))\n ) {\n throw new Error(\"Cable path needs at least two finite 3D points\")\n }\n const segments = path\n .slice(1)\n .map((point, index) => normalize(subtract(point, path[index]!)))\n const tangents = path.map((_, index) =>\n index === 0\n ? segments[0]!\n : index === path.length - 1\n ? segments.at(-1)!\n : normalize(add(segments[index - 1]!, segments[index]!)),\n )\n const initialUp: CablePoint =\n Math.abs(tangents[0]![2]) > 0.95 ? [0, 1, 0] : [0, 0, 1]\n let normal = normalize(cross(initialUp, tangents[0]!))\n return tangents.map((tangent, index) => {\n if (index > 0) {\n const previousTangent = tangents[index - 1]!\n const axis = cross(previousTangent, tangent)\n const sine = Math.hypot(...axis)\n const cosine = Math.max(-1, Math.min(1, dot(previousTangent, tangent)))\n if (sine > 1e-10) {\n const unitAxis = scale(axis, 1 / sine)\n normal = normalize(\n add(\n add(scale(normal, cosine), scale(cross(unitAxis, normal), sine)),\n scale(unitAxis, dot(unitAxis, normal) * (1 - cosine)),\n ),\n )\n }\n }\n return {\n point: path[index]!,\n tangent,\n normal,\n binormal: normalize(cross(tangent, normal)),\n }\n })\n}\n","import { add, scale } from \"./path-frames\"\nimport type { CableFrame, CableMesh, CableColor } from \"./types\"\n\n/** Closed indexed sweep around a supplied centerline; this does not choose a route. */\nexport function sweepRoundCable({\n frames,\n diameter,\n offset = 0,\n radialSegments,\n color,\n name,\n}: {\n frames: CableFrame[]\n diameter: number\n offset?: number\n radialSegments: number\n color: CableColor\n name: string\n}): CableMesh {\n const positions: number[] = []\n const indices: number[] = []\n for (const frame of frames) {\n const center = add(frame.point, scale(frame.normal, offset))\n for (let side = 0; side < radialSegments; side++) {\n const angle = (side * Math.PI * 2) / radialSegments\n positions.push(\n ...add(\n center,\n add(\n scale(frame.normal, (diameter * Math.cos(angle)) / 2),\n scale(frame.binormal, (diameter * Math.sin(angle)) / 2),\n ),\n ),\n )\n }\n }\n for (let ring = 0; ring < frames.length - 1; ring++) {\n for (let side = 0; side < radialSegments; side++) {\n const a = ring * radialSegments + side\n const b = ring * radialSegments + ((side + 1) % radialSegments)\n const c = a + radialSegments\n const d = b + radialSegments\n indices.push(a, b, c, b, d, c)\n }\n }\n const startCenter = positions.length / 3\n positions.push(...add(frames[0]!.point, scale(frames[0]!.normal, offset)))\n const endCenter = positions.length / 3\n positions.push(\n ...add(frames.at(-1)!.point, scale(frames.at(-1)!.normal, offset)),\n )\n const lastRing = (frames.length - 1) * radialSegments\n for (let side = 0; side < radialSegments; side++) {\n const next = (side + 1) % radialSegments\n indices.push(\n startCenter,\n next,\n side,\n endCenter,\n lastRing + side,\n lastRing + next,\n )\n }\n return { name, positions, indices, color, smooth: true }\n}\n","import {\n createConnectorMeshes,\n connectorWireExitDepth,\n} from \"./connector-meshes\"\nimport { placeConnectorMesh } from \"./geometry-to-mesh\"\nimport { createCablePathFrames } from \"./path-frames\"\nimport { sweepRoundCable } from \"./sweep-round-cable\"\nimport type {\n CableColor,\n CableGeometryDefinition,\n CableMesh,\n CablePoint,\n} from \"./types\"\n\nfunction parseCableColor(color: string): CableColor {\n if (!/^#[a-f\\d]{6}$/i.test(color))\n throw new Error(\"Cable colors must be six-digit hex strings\")\n return [\n parseInt(color.slice(1, 3), 16) / 255,\n parseInt(color.slice(3, 5), 16) / 255,\n parseInt(color.slice(5, 7), 16) / 255,\n 1,\n ]\n}\n\nfunction validateCableDefinition(definition: CableGeometryDefinition) {\n for (const connector of [definition.connectorA, definition.connectorB]) {\n const dimensions = [\n connector.bodyWidth,\n connector.bodyHeight,\n connector.bodyDepth,\n ]\n if (connector.kind === \"usb_c_plug\")\n dimensions.push(\n connector.shellWidth,\n connector.shellHeight,\n connector.shellDepth,\n )\n if (\n dimensions.some(\n (dimension) => !Number.isFinite(dimension) || dimension <= 0,\n )\n )\n throw new Error(\"Connector dimensions must be finite and positive\")\n if (\n \"pinCount\" in connector &&\n (!Number.isInteger(connector.pinCount) ||\n connector.pinCount < 2 ||\n !Number.isFinite(connector.pitch) ||\n connector.pitch <= 0)\n )\n throw new Error(\n \"JST connectors need a positive pitch and at least two contacts\",\n )\n }\n const crossSection = definition.crossSection\n const diameters =\n crossSection.kind === \"round_jacket\"\n ? [crossSection.diameter]\n : crossSection.wires.map((wire) => wire.diameter)\n if (\n diameters.length === 0 ||\n diameters.some((diameter) => !Number.isFinite(diameter) || diameter <= 0)\n )\n throw new Error(\"Cable diameters must be finite and positive\")\n if (crossSection.kind === \"wire_bundle\") {\n if (\n !Number.isFinite(crossSection.wirePitch) ||\n crossSection.wires.some((wire) => wire.diameter > crossSection.wirePitch)\n )\n throw new Error(\"Insulated bundle wires must not overlap\")\n for (const connector of [definition.connectorA, definition.connectorB]) {\n if (\n !(\"pinCount\" in connector) ||\n connector.pinCount !== crossSection.wires.length\n )\n throw new Error(\"Bundle wire count must match connector contact count\")\n }\n }\n}\n\n/** Mesh generation only. Path samples are already resolved in world millimeters, +Z up. */\nexport function createCableMeshes({\n definition,\n path,\n radialSegments = 24,\n}: {\n definition: CableGeometryDefinition\n path: CablePoint[]\n radialSegments?: number\n}): CableMesh[] {\n validateCableDefinition(definition)\n if (\n !Number.isInteger(radialSegments) ||\n radialSegments < 8 ||\n radialSegments > 128\n )\n throw new Error(\"radialSegments must be an integer from 8 to 128\")\n const frames = createCablePathFrames(path)\n const crossSection = definition.crossSection\n const jacketDiameter =\n crossSection.kind === \"round_jacket\" ? crossSection.diameter : undefined\n const meshes =\n crossSection.kind === \"round_jacket\"\n ? [\n sweepRoundCable({\n frames,\n diameter: crossSection.diameter,\n radialSegments,\n color: parseCableColor(crossSection.color),\n name: \"jacket\",\n }),\n ]\n : crossSection.wires.map((wire, index) =>\n sweepRoundCable({\n frames,\n diameter: wire.diameter,\n offset:\n (index - (crossSection.wires.length - 1) / 2) *\n crossSection.wirePitch,\n radialSegments,\n color: parseCableColor(wire.color),\n name: `wire-${index + 1}`,\n }),\n )\n for (const [index, connector] of [\n definition.connectorA,\n definition.connectorB,\n ].entries()) {\n const frame = index === 0 ? frames[0]! : frames.at(-1)!\n const parts = createConnectorMeshes({ connector, jacketDiameter })\n meshes.push(\n ...parts.map((mesh) =>\n placeConnectorMesh({\n mesh: { ...mesh, name: `${index === 0 ? \"A\" : \"B\"}-${mesh.name}` },\n frame,\n isEnd: index === 1,\n wireExitDepth: connectorWireExitDepth(connector),\n }),\n ),\n )\n }\n return meshes\n}\n"],"mappings":"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","names":["jscad","jscad","subtract"]}
|
|
1
|
+
{"version":3,"sources":["../lib/materials.ts","../lib/cables/connector-meshes.ts","../lib/cables/geometry-to-mesh.ts","../lib/cables/path-frames.ts","../lib/cables/sweep-round-cable.ts","../lib/cables/create-cable-meshes.ts"],"sourcesContent":["/** Approximate visual finishes, not measured optical properties. */\nexport const componentMaterials = {\n moldedPlastic: { metalness: 0, roughness: 0.7 },\n rubber: { metalness: 0, roughness: 0.9 },\n sleeve: { metalness: 0, roughness: 0.45 },\n tinnedLead: { metalness: 0.8, roughness: 0.55 },\n goldContact: { metalness: 1, roughness: 0.25 },\n copper: { metalness: 1, roughness: 0.35 },\n brushedMetal: { metalness: 1, roughness: 0.4 },\n steel: { metalness: 1, roughness: 0.25 },\n} as const\n","import { componentMaterials } from \"../materials\"\nimport jscad from \"@jscad/modeling\"\nimport { geometryToCableMesh } from \"./geometry-to-mesh\"\nimport type {\n CableColor,\n CableConnectorSpec,\n CableMesh,\n CablePoint,\n} from \"./types\"\n\nconst { cuboid, roundedCuboid, cylinder, roundedRectangle, polygon, sphere } =\n jscad.primitives\nconst { extrudeLinear } = jscad.extrusions\nconst { translate, rotateY } = jscad.transforms\nconst { subtract, union } = jscad.booleans\nconst plastic: CableColor = [0.055, 0.07, 0.09, 1]\nconst housing: CableColor = [0.86, 0.84, 0.75, 1]\nconst metal: CableColor = [0.6, 0.64, 0.7, 1]\nconst brass: CableColor = [0.66, 0.46, 0.18, 1]\n\nexport function connectorWireExitDepth(connector: CableConnectorSpec): number {\n if (connector.kind === \"usb_c_plug\")\n return connector.shellDepth + connector.bodyDepth\n if (connector.kind === \"nema_5_15p\") return 19.05 + connector.bodyDepth\n return connector.bodyDepth\n}\n\nfunction createJstMeshes(\n connector: Extract<\n CableConnectorSpec,\n { kind: \"jst_sh_housing\" | \"jst_ph_housing\" }\n >,\n): CableMesh[] {\n const {\n bodyWidth: width,\n bodyHeight: height,\n bodyDepth: depth,\n pinCount,\n pitch,\n } = connector\n const opening = pitch === 1 ? 0.55 : 1.05\n const holes = Array.from({ length: pinCount }, (_, index) => {\n const x = (index - (pinCount - 1) / 2) * pitch\n return cuboid({\n size: [opening, opening * 1.35, depth - 0.6],\n center: [x, 0, (depth - 0.6) / 2 - 0.02],\n })\n })\n const backHoles = Array.from({ length: pinCount }, (_, index) =>\n cylinder({\n radius: pitch * 0.34,\n height: 1.3,\n segments: 16,\n center: [(index - (pinCount - 1) / 2) * pitch, 0, depth - 0.5],\n }),\n )\n const latchCut = cuboid({\n size: [width * 0.45, 0.5, depth * 0.5],\n center: [0, height / 2, depth * 0.65],\n })\n const body = subtract(\n roundedCuboid({\n size: [width, height, depth],\n center: [0, 0, depth / 2],\n roundRadius: 0.1,\n segments: 8,\n }),\n ...holes,\n ...backHoles,\n latchCut,\n ...Array.from({ length: pinCount }, (_, index) =>\n cuboid({\n size: [opening * 0.8, height * 0.7, depth * 0.24],\n center: [(index - (pinCount - 1) / 2) * pitch, height / 2, depth * 0.7],\n }),\n ),\n )\n const contacts = Array.from({ length: pinCount }, (_, index) => {\n const x = (index - (pinCount - 1) / 2) * pitch\n return geometryToCableMesh({\n material: componentMaterials.goldContact,\n name: `contact-${index + 1}`,\n color: metal,\n geometry: subtract(\n cuboid({\n size: [opening * 0.92, opening * 1.25, depth * 0.65],\n center: [x, 0, depth * 0.45],\n }),\n cuboid({\n size: [\n opening * 0.92 - 0.12,\n opening * 1.25 - 0.12,\n depth * 0.65 + 0.2,\n ],\n center: [x, 0, depth * 0.45],\n }),\n ),\n })\n })\n return [\n geometryToCableMesh({ geometry: body, color: housing, name: \"housing\" }),\n ...contacts,\n ]\n}\n\nfunction createUsbMeshes(\n connector: Extract<CableConnectorSpec, { kind: \"usb_c_plug\" }>,\n): CableMesh[] {\n const {\n shellWidth,\n shellHeight,\n shellDepth,\n bodyWidth,\n bodyHeight,\n bodyDepth,\n } = connector\n const shell = subtract(\n extrudeLinear(\n { height: shellDepth },\n roundedRectangle({\n size: [shellWidth, shellHeight],\n roundRadius: shellHeight / 2 - 0.02,\n segments: 32,\n }),\n ),\n translate(\n [0, 0, -0.1],\n extrudeLinear(\n { height: shellDepth + 0.2 },\n roundedRectangle({\n size: [shellWidth - 0.4, shellHeight - 0.4],\n roundRadius: (shellHeight - 0.4) / 2 - 0.02,\n segments: 32,\n }),\n ),\n ),\n )\n const liner = subtract(\n extrudeLinear(\n { height: shellDepth },\n roundedRectangle({\n size: [shellWidth - 0.41, shellHeight - 0.41],\n roundRadius: 0.85,\n segments: 32,\n }),\n ),\n translate(\n [0, 0, -0.1],\n extrudeLinear(\n { height: shellDepth - 0.3 },\n roundedRectangle({\n size: [shellWidth - 0.8, shellHeight - 0.8],\n roundRadius: 0.65,\n segments: 32,\n }),\n ),\n ),\n )\n const body = roundedCuboid({\n size: [bodyWidth, bodyHeight, bodyDepth],\n center: [0, 0, shellDepth + bodyDepth / 2],\n roundRadius: Math.min(1.3, bodyHeight / 4),\n segments: 16,\n })\n const contacts = Array.from({ length: 24 }, (_, index) =>\n cuboid({\n size: [0.22, 0.08, 3.5],\n center: [((index % 12) - 5.5) * 0.5, index < 12 ? 0.77 : -0.77, 2.6],\n }),\n )\n return [\n geometryToCableMesh({ geometry: body, color: plastic, name: \"overmold\" }),\n geometryToCableMesh({\n geometry: shell,\n color: metal,\n material: componentMaterials.brushedMetal,\n name: \"shell\",\n }),\n geometryToCableMesh({\n geometry: liner,\n color: [0.025, 0.026, 0.03, 1],\n name: \"liner\",\n }),\n ...contacts.map((geometry, index) =>\n geometryToCableMesh({\n geometry,\n color: brass,\n material: componentMaterials.goldContact,\n name: `contact-${index + 1}`,\n }),\n ),\n ]\n}\n\nfunction createMainsMeshes(connector: CableConnectorSpec): CableMesh[] {\n const { bodyWidth, bodyHeight, bodyDepth, kind } = connector\n const faceDepth = kind === \"nema_5_15p\" ? 19.05 : 0\n let body = roundedCuboid({\n size: [bodyWidth, bodyHeight, bodyDepth],\n center: [0, 0, faceDepth + bodyDepth / 2],\n roundRadius: 2,\n segments: 16,\n })\n if (kind === \"nema_5_15p\") {\n const blades = [-6.35, 6.35].map((x) => {\n const blade = cuboid({\n size: [1.524, 6.35, 15.875],\n center: [x, 2.7, 19.05 - 15.875 / 2],\n })\n const hole = translate(\n [x, 2.7, 7.3],\n rotateY(\n Math.PI / 2,\n cylinder({ radius: 1.1, height: 3, segments: 20 }),\n ),\n )\n return subtract(blade, hole)\n })\n const ground = union(\n cylinder({\n radius: 2.38125,\n height: 19.05 - 2.38125,\n center: [0, -9.20625, (19.05 + 2.38125) / 2],\n segments: 32,\n }),\n sphere({ radius: 2.38125, center: [0, -9.20625, 2.38125], segments: 32 }),\n )\n return [\n geometryToCableMesh({\n geometry: body,\n color: plastic,\n name: \"plug-body\",\n }),\n ...blades.map((geometry, index) =>\n geometryToCableMesh({\n geometry,\n color: brass,\n material: componentMaterials.goldContact,\n name: `blade-${index + 1}`,\n }),\n ),\n geometryToCableMesh({\n geometry: ground,\n color: brass,\n material: componentMaterials.goldContact,\n name: \"ground-pin\",\n }),\n ]\n }\n const recess = translate(\n [0, 0, -0.1],\n extrudeLinear(\n { height: 3.2 },\n polygon({\n points: [\n [-9, -6],\n [9, -6],\n [9, 2],\n [5, 6],\n [-5, 6],\n [-9, 2],\n ],\n }),\n ),\n )\n const sockets: CablePoint[] = [\n [-4.4, -1.8, 8],\n [4.4, -1.8, 8],\n [0, 3.1, 8],\n ]\n body = subtract(\n body,\n recess,\n ...sockets.map((center) => cuboid({ size: [2.3, 3.4, 16.2], center })),\n )\n return [\n geometryToCableMesh({\n geometry: body,\n color: plastic,\n name: \"appliance-body\",\n }),\n ...sockets.map(([x, y], index) =>\n geometryToCableMesh({\n geometry: cuboid({ size: [0.15, 2.8, 6], center: [x - 1.05, y, 7.8] }),\n color: brass,\n material: componentMaterials.goldContact,\n name: `socket-contact-${index + 1}`,\n }),\n ),\n ]\n}\n\nexport function createConnectorMeshes({\n connector,\n jacketDiameter,\n}: { connector: CableConnectorSpec; jacketDiameter?: number }): CableMesh[] {\n const meshes =\n connector.kind === \"usb_c_plug\"\n ? createUsbMeshes(connector)\n : \"pinCount\" in connector\n ? createJstMeshes(connector)\n : createMainsMeshes(connector)\n if (jacketDiameter !== undefined) {\n const exit = connectorWireExitDepth(connector)\n const boot = union(\n cylinder({\n radius: jacketDiameter / 2 + 0.15,\n height: 5,\n center: [0, 0, exit + 2.5],\n segments: 32,\n }),\n ...Array.from({ length: 7 }, (_, index) =>\n cylinder({\n radius: jacketDiameter / 2 + 0.8 - index * 0.06,\n height: 0.28,\n center: [0, 0, exit + 0.4 + index * 0.7],\n segments: 32,\n }),\n ),\n )\n meshes.push(\n geometryToCableMesh({\n geometry: boot,\n color: plastic,\n name: \"strain-relief\",\n }),\n )\n }\n return meshes\n}\n","import jscad from \"@jscad/modeling\"\nimport type { Geom3 } from \"@jscad/modeling/src/geometries/geom3\"\nimport type { CableMesh, CableColor, CableFrame, CablePoint } from \"./types\"\nimport { add, scale } from \"./path-frames\"\n\ntype VertexKey = string\n\nexport function geometryToCableMesh({\n geometry,\n color,\n name,\n material,\n}: {\n geometry: Geom3\n color: CableColor\n name: string\n material?: CableMesh[\"material\"]\n}): CableMesh {\n const triangles = jscad.geometries.geom3.toPolygons(geometry)\n const positions: number[] = []\n const indices: number[] = []\n const vertices = new Map<VertexKey, number>()\n for (const triangle of triangles) {\n const polygonIndices: number[] = []\n for (const point of triangle.vertices) {\n const key = point.map((coordinate) => coordinate.toFixed(8)).join(\",\")\n let index = vertices.get(key)\n if (index === undefined) {\n index = positions.length / 3\n positions.push(...point)\n vertices.set(key, index)\n }\n polygonIndices.push(index)\n }\n // JSCAD CSG polygons are convex, so a fan preserves their outward winding.\n for (let side = 1; side < polygonIndices.length - 1; side++) {\n indices.push(\n polygonIndices[0]!,\n polygonIndices[side]!,\n polygonIndices[side + 1]!,\n )\n }\n }\n return { name, positions, indices, color, material, smooth: false }\n}\n\nexport function placeConnectorMesh({\n mesh,\n frame,\n wireExitDepth,\n isEnd,\n}: {\n mesh: CableMesh\n frame: CableFrame\n wireExitDepth: number\n isEnd: boolean\n}): CableMesh {\n const tangent = scale(frame.tangent, isEnd ? -1 : 1)\n const binormal: CablePoint = isEnd\n ? scale(frame.binormal, -1)\n : frame.binormal\n const origin = add(frame.point, scale(tangent, -wireExitDepth))\n const positions: number[] = []\n for (let index = 0; index < mesh.positions.length; index += 3) {\n positions.push(\n ...add(\n origin,\n add(\n add(\n scale(frame.normal, mesh.positions[index]!),\n scale(binormal, mesh.positions[index + 1]!),\n ),\n scale(tangent, mesh.positions[index + 2]!),\n ),\n ),\n )\n }\n return { ...mesh, positions }\n}\n","import type { CableFrame, CablePoint } from \"./types\"\n\nexport const add = (a: CablePoint, b: CablePoint): CablePoint => [\n a[0] + b[0],\n a[1] + b[1],\n a[2] + b[2],\n]\nexport const subtract = (a: CablePoint, b: CablePoint): CablePoint => [\n a[0] - b[0],\n a[1] - b[1],\n a[2] - b[2],\n]\nexport const scale = (point: CablePoint, factor: number): CablePoint => [\n point[0] * factor,\n point[1] * factor,\n point[2] * factor,\n]\nexport const dot = (a: CablePoint, b: CablePoint) =>\n a[0] * b[0] + a[1] * b[1] + a[2] * b[2]\nexport const cross = (a: CablePoint, b: CablePoint): CablePoint => [\n a[1] * b[2] - a[2] * b[1],\n a[2] * b[0] - a[0] * b[2],\n a[0] * b[1] - a[1] * b[0],\n]\nexport function normalize(point: CablePoint): CablePoint {\n const length = Math.hypot(...point)\n if (length < 1e-10)\n throw new Error(\n \"Cable path must not contain coincident points or a reversing tangent\",\n )\n return scale(point, 1 / length)\n}\n\n/** Parallel transport avoids a wire bundle flipping when its tangent crosses an axis. */\nexport function createCablePathFrames(path: CablePoint[]): CableFrame[] {\n if (\n path.length < 2 ||\n path.some((point) => point.length !== 3 || !point.every(Number.isFinite))\n ) {\n throw new Error(\"Cable path needs at least two finite 3D points\")\n }\n const segments = path\n .slice(1)\n .map((point, index) => normalize(subtract(point, path[index]!)))\n const tangents = path.map((_, index) =>\n index === 0\n ? segments[0]!\n : index === path.length - 1\n ? segments.at(-1)!\n : normalize(add(segments[index - 1]!, segments[index]!)),\n )\n const initialUp: CablePoint =\n Math.abs(tangents[0]![2]) > 0.95 ? [0, 1, 0] : [0, 0, 1]\n let normal = normalize(cross(initialUp, tangents[0]!))\n return tangents.map((tangent, index) => {\n if (index > 0) {\n const previousTangent = tangents[index - 1]!\n const axis = cross(previousTangent, tangent)\n const sine = Math.hypot(...axis)\n const cosine = Math.max(-1, Math.min(1, dot(previousTangent, tangent)))\n if (sine > 1e-10) {\n const unitAxis = scale(axis, 1 / sine)\n normal = normalize(\n add(\n add(scale(normal, cosine), scale(cross(unitAxis, normal), sine)),\n scale(unitAxis, dot(unitAxis, normal) * (1 - cosine)),\n ),\n )\n }\n }\n return {\n point: path[index]!,\n tangent,\n normal,\n binormal: normalize(cross(tangent, normal)),\n }\n })\n}\n","import { add, scale } from \"./path-frames\"\nimport type { CableFrame, CableMesh, CableColor } from \"./types\"\n\n/** Closed indexed sweep around a supplied centerline; this does not choose a route. */\nexport function sweepRoundCable({\n frames,\n diameter,\n offset = 0,\n radialSegments,\n color,\n name,\n}: {\n frames: CableFrame[]\n diameter: number\n offset?: number\n radialSegments: number\n color: CableColor\n name: string\n}): CableMesh {\n const positions: number[] = []\n const indices: number[] = []\n for (const frame of frames) {\n const center = add(frame.point, scale(frame.normal, offset))\n for (let side = 0; side < radialSegments; side++) {\n const angle = (side * Math.PI * 2) / radialSegments\n positions.push(\n ...add(\n center,\n add(\n scale(frame.normal, (diameter * Math.cos(angle)) / 2),\n scale(frame.binormal, (diameter * Math.sin(angle)) / 2),\n ),\n ),\n )\n }\n }\n for (let ring = 0; ring < frames.length - 1; ring++) {\n for (let side = 0; side < radialSegments; side++) {\n const a = ring * radialSegments + side\n const b = ring * radialSegments + ((side + 1) % radialSegments)\n const c = a + radialSegments\n const d = b + radialSegments\n indices.push(a, b, c, b, d, c)\n }\n }\n const startCenter = positions.length / 3\n positions.push(...add(frames[0]!.point, scale(frames[0]!.normal, offset)))\n const endCenter = positions.length / 3\n positions.push(\n ...add(frames.at(-1)!.point, scale(frames.at(-1)!.normal, offset)),\n )\n const lastRing = (frames.length - 1) * radialSegments\n for (let side = 0; side < radialSegments; side++) {\n const next = (side + 1) % radialSegments\n indices.push(\n startCenter,\n next,\n side,\n endCenter,\n lastRing + side,\n lastRing + next,\n )\n }\n return { name, positions, indices, color, smooth: true }\n}\n","import {\n createConnectorMeshes,\n connectorWireExitDepth,\n} from \"./connector-meshes\"\nimport { placeConnectorMesh } from \"./geometry-to-mesh\"\nimport { createCablePathFrames } from \"./path-frames\"\nimport { sweepRoundCable } from \"./sweep-round-cable\"\nimport type {\n CableColor,\n CableGeometryDefinition,\n CableMesh,\n CablePoint,\n} from \"./types\"\n\nfunction parseCableColor(color: string): CableColor {\n if (!/^#[a-f\\d]{6}$/i.test(color))\n throw new Error(\"Cable colors must be six-digit hex strings\")\n return [\n parseInt(color.slice(1, 3), 16) / 255,\n parseInt(color.slice(3, 5), 16) / 255,\n parseInt(color.slice(5, 7), 16) / 255,\n 1,\n ]\n}\n\nfunction validateCableDefinition(definition: CableGeometryDefinition) {\n for (const connector of [definition.connectorA, definition.connectorB]) {\n const dimensions = [\n connector.bodyWidth,\n connector.bodyHeight,\n connector.bodyDepth,\n ]\n if (connector.kind === \"usb_c_plug\")\n dimensions.push(\n connector.shellWidth,\n connector.shellHeight,\n connector.shellDepth,\n )\n if (\n dimensions.some(\n (dimension) => !Number.isFinite(dimension) || dimension <= 0,\n )\n )\n throw new Error(\"Connector dimensions must be finite and positive\")\n if (\n \"pinCount\" in connector &&\n (!Number.isInteger(connector.pinCount) ||\n connector.pinCount < 2 ||\n !Number.isFinite(connector.pitch) ||\n connector.pitch <= 0)\n )\n throw new Error(\n \"JST connectors need a positive pitch and at least two contacts\",\n )\n }\n const crossSection = definition.crossSection\n const diameters =\n crossSection.kind === \"round_jacket\"\n ? [crossSection.diameter]\n : crossSection.wires.map((wire) => wire.diameter)\n if (\n diameters.length === 0 ||\n diameters.some((diameter) => !Number.isFinite(diameter) || diameter <= 0)\n )\n throw new Error(\"Cable diameters must be finite and positive\")\n if (crossSection.kind === \"wire_bundle\") {\n if (\n !Number.isFinite(crossSection.wirePitch) ||\n crossSection.wires.some((wire) => wire.diameter > crossSection.wirePitch)\n )\n throw new Error(\"Insulated bundle wires must not overlap\")\n for (const connector of [definition.connectorA, definition.connectorB]) {\n if (\n !(\"pinCount\" in connector) ||\n connector.pinCount !== crossSection.wires.length\n )\n throw new Error(\"Bundle wire count must match connector contact count\")\n }\n }\n}\n\n/** Mesh generation only. Path samples are already resolved in world millimeters, +Z up. */\nexport function createCableMeshes({\n definition,\n path,\n radialSegments = 24,\n}: {\n definition: CableGeometryDefinition\n path: CablePoint[]\n radialSegments?: number\n}): CableMesh[] {\n validateCableDefinition(definition)\n if (\n !Number.isInteger(radialSegments) ||\n radialSegments < 8 ||\n radialSegments > 128\n )\n throw new Error(\"radialSegments must be an integer from 8 to 128\")\n const frames = createCablePathFrames(path)\n const crossSection = definition.crossSection\n const jacketDiameter =\n crossSection.kind === \"round_jacket\" ? crossSection.diameter : undefined\n const meshes =\n crossSection.kind === \"round_jacket\"\n ? [\n sweepRoundCable({\n frames,\n diameter: crossSection.diameter,\n radialSegments,\n color: parseCableColor(crossSection.color),\n name: \"jacket\",\n }),\n ]\n : crossSection.wires.map((wire, index) =>\n sweepRoundCable({\n frames,\n diameter: wire.diameter,\n offset:\n (index - (crossSection.wires.length - 1) / 2) *\n crossSection.wirePitch,\n radialSegments,\n color: parseCableColor(wire.color),\n name: `wire-${index + 1}`,\n }),\n )\n for (const [index, connector] of [\n definition.connectorA,\n definition.connectorB,\n ].entries()) {\n const frame = index === 0 ? frames[0]! : frames.at(-1)!\n const parts = createConnectorMeshes({ connector, jacketDiameter })\n meshes.push(\n ...parts.map((mesh) =>\n placeConnectorMesh({\n mesh: { ...mesh, name: `${index === 0 ? \"A\" : \"B\"}-${mesh.name}` },\n frame,\n isEnd: index === 1,\n wireExitDepth: connectorWireExitDepth(connector),\n }),\n ),\n )\n }\n return meshes\n}\n"],"mappings":"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","names":["jscad","jscad","subtract"]}
|