@tscircuit/3d-viewer 0.0.527 → 0.0.529

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.
Files changed (2) hide show
  1. package/dist/index.js +250 -342
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -11357,7 +11357,7 @@ var require_unionGeom3 = __commonJS({
11357
11357
  var flatten = require_flatten();
11358
11358
  var retessellate = require_retessellate();
11359
11359
  var unionSub = require_unionGeom3Sub();
11360
- var union5 = (...geometries) => {
11360
+ var union4 = (...geometries) => {
11361
11361
  geometries = flatten(geometries);
11362
11362
  let i;
11363
11363
  for (i = 1; i < geometries.length; i += 2) {
@@ -11367,7 +11367,7 @@ var require_unionGeom3 = __commonJS({
11367
11367
  newgeometry = retessellate(newgeometry);
11368
11368
  return newgeometry;
11369
11369
  };
11370
- module.exports = union5;
11370
+ module.exports = union4;
11371
11371
  }
11372
11372
  });
11373
11373
 
@@ -11698,14 +11698,14 @@ var require_unionGeom2 = __commonJS({
11698
11698
  var fromFakePolygons = require_fromFakePolygons();
11699
11699
  var to3DWalls = require_to3DWalls();
11700
11700
  var unionGeom3 = require_unionGeom3();
11701
- var union5 = (...geometries) => {
11701
+ var union4 = (...geometries) => {
11702
11702
  geometries = flatten(geometries);
11703
11703
  const newgeometries = geometries.map((geometry) => to3DWalls({ z0: -1, z1: 1 }, geometry));
11704
11704
  const newgeom3 = unionGeom3(newgeometries);
11705
11705
  const epsilon = measureEpsilon(newgeom3);
11706
11706
  return fromFakePolygons(epsilon, geom3.toPolygons(newgeom3));
11707
11707
  };
11708
- module.exports = union5;
11708
+ module.exports = union4;
11709
11709
  }
11710
11710
  });
11711
11711
 
@@ -11719,7 +11719,7 @@ var require_union = __commonJS({
11719
11719
  var geom3 = require_geom3();
11720
11720
  var unionGeom2 = require_unionGeom2();
11721
11721
  var unionGeom3 = require_unionGeom3();
11722
- var union5 = (...geometries) => {
11722
+ var union4 = (...geometries) => {
11723
11723
  geometries = flatten(geometries);
11724
11724
  if (geometries.length === 0) throw new Error("wrong number of arguments");
11725
11725
  if (!areAllShapesTheSameType(geometries)) {
@@ -11730,7 +11730,7 @@ var require_union = __commonJS({
11730
11730
  if (geom3.isA(geometry)) return unionGeom3(geometries);
11731
11731
  return geometry;
11732
11732
  };
11733
- module.exports = union5;
11733
+ module.exports = union4;
11734
11734
  }
11735
11735
  });
11736
11736
 
@@ -12121,7 +12121,7 @@ var require_expandGeom3 = __commonJS({
12121
12121
  "node_modules/@jscad/modeling/src/operations/expansions/expandGeom3.js"(exports, module) {
12122
12122
  "use strict";
12123
12123
  var geom3 = require_geom3();
12124
- var union5 = require_union();
12124
+ var union4 = require_union();
12125
12125
  var expandShell = require_expandShell();
12126
12126
  var expandGeom3 = (options, geometry) => {
12127
12127
  const defaults = {
@@ -12137,7 +12137,7 @@ var require_expandGeom3 = __commonJS({
12137
12137
  if (polygons.length === 0) throw new Error("the given geometry cannot be empty");
12138
12138
  options = { delta, corners, segments };
12139
12139
  const expanded = expandShell(options, geometry);
12140
- return union5(geometry, expanded);
12140
+ return union4(geometry, expanded);
12141
12141
  };
12142
12142
  module.exports = expandGeom3;
12143
12143
  }
@@ -12831,7 +12831,7 @@ var require_hullChain = __commonJS({
12831
12831
  "node_modules/@jscad/modeling/src/operations/hulls/hullChain.js"(exports, module) {
12832
12832
  "use strict";
12833
12833
  var flatten = require_flatten();
12834
- var union5 = require_union();
12834
+ var union4 = require_union();
12835
12835
  var hull = require_hull();
12836
12836
  var hullChain = (...geometries) => {
12837
12837
  geometries = flatten(geometries);
@@ -12840,7 +12840,7 @@ var require_hullChain = __commonJS({
12840
12840
  for (let i = 1; i < geometries.length; i++) {
12841
12841
  hulls.push(hull(geometries[i - 1], geometries[i]));
12842
12842
  }
12843
- return union5(hulls);
12843
+ return union4(hulls);
12844
12844
  };
12845
12845
  module.exports = hullChain;
12846
12846
  }
@@ -14433,7 +14433,7 @@ var require_browser = __commonJS({
14433
14433
 
14434
14434
  // src/CadViewer.tsx
14435
14435
  import { useState as useState36, useCallback as useCallback21, useRef as useRef26, useEffect as useEffect44 } from "react";
14436
- import * as THREE38 from "three";
14436
+ import * as THREE39 from "three";
14437
14437
 
14438
14438
  // src/CadViewerJscad.tsx
14439
14439
  import { su as su11 } from "@tscircuit/circuit-json-util";
@@ -28769,7 +28769,7 @@ import * as THREE16 from "three";
28769
28769
  // package.json
28770
28770
  var package_default = {
28771
28771
  name: "@tscircuit/3d-viewer",
28772
- version: "0.0.526",
28772
+ version: "0.0.528",
28773
28773
  main: "./dist/index.js",
28774
28774
  module: "./dist/index.js",
28775
28775
  type: "module",
@@ -28798,8 +28798,8 @@ var package_default = {
28798
28798
  dependencies: {
28799
28799
  "@jscad/regl-renderer": "^2.6.12",
28800
28800
  "@jscad/stl-serializer": "^2.1.20",
28801
- "circuit-json": "^0.0.372",
28802
- "circuit-to-canvas": "^0.0.87",
28801
+ "circuit-json": "^0.0.391",
28802
+ "circuit-to-canvas": "^0.0.89",
28803
28803
  "react-hot-toast": "^2.6.0",
28804
28804
  three: "^0.165.0",
28805
28805
  "three-stdlib": "^2.36.0",
@@ -30216,26 +30216,6 @@ function extractRectBorderRadius(source) {
30216
30216
  var PLATED_HOLE_DRILL_OVERREACH = 0.05;
30217
30217
  var RECT_PAD_SEGMENTS = 64;
30218
30218
  var maybeClip = (geom, clipGeom) => clipGeom ? (0, import_booleans2.intersect)(clipGeom, geom) : geom;
30219
- var createRectPadGeom = ({
30220
- width: width10,
30221
- height: height10,
30222
- thickness,
30223
- center,
30224
- borderRadius
30225
- }) => {
30226
- const clampedRadius = clampRectBorderRadius(width10, height10, borderRadius);
30227
- if (clampedRadius <= 0) {
30228
- return (0, import_primitives4.cuboid)({ center, size: [width10, height10, thickness] });
30229
- }
30230
- const rect2d = (0, import_primitives4.roundedRectangle)({
30231
- size: [width10, height10],
30232
- roundRadius: clampedRadius,
30233
- segments: RECT_PAD_SEGMENTS
30234
- });
30235
- const extruded = (0, import_extrusions3.extrudeLinear)({ height: thickness }, rect2d);
30236
- const offsetZ = center[2] - thickness / 2;
30237
- return (0, import_transforms4.translate)([center[0], center[1], offsetZ], extruded);
30238
- };
30239
30219
  var platedHole = (plated_hole, ctx, options = {}) => {
30240
30220
  const { clipGeom } = options;
30241
30221
  if (!plated_hole.shape) plated_hole.shape = "circle";
@@ -30243,9 +30223,6 @@ var platedHole = (plated_hole, ctx, options = {}) => {
30243
30223
  const surfaceClearance = Math.max(ctx.pcbThickness * 3e-4, M / 20);
30244
30224
  const fillClearance = Math.max(ctx.pcbThickness * 25e-4, M / 4);
30245
30225
  const throughDrillHeight = ctx.pcbThickness + 2 * PLATED_HOLE_DRILL_OVERREACH + 4 * M;
30246
- const topSurfaceZ = ctx.pcbThickness / 2 + surfaceClearance + padThickness / 2;
30247
- const bottomSurfaceZ = -ctx.pcbThickness / 2 - surfaceClearance - padThickness / 2;
30248
- const copperSurfaceSpan = ctx.pcbThickness + 2 * surfaceClearance;
30249
30226
  const copperFillHeight = Math.max(
30250
30227
  ctx.pcbThickness - 2 * (padThickness + surfaceClearance + fillClearance),
30251
30228
  M
@@ -30253,7 +30230,7 @@ var platedHole = (plated_hole, ctx, options = {}) => {
30253
30230
  const barrelHeight = Math.max(copperFillHeight, M);
30254
30231
  if (plated_hole.shape === "circle") {
30255
30232
  const outerDiameter = plated_hole.outer_diameter ?? Math.max(plated_hole.hole_diameter, 0);
30256
- const copperHeight = copperSurfaceSpan;
30233
+ const copperHeight = copperFillHeight;
30257
30234
  const copperBody = (0, import_primitives4.cylinder)({
30258
30235
  center: [plated_hole.x, plated_hole.y, 0],
30259
30236
  radius: outerDiameter / 2,
@@ -30276,7 +30253,7 @@ var platedHole = (plated_hole, ctx, options = {}) => {
30276
30253
  const circle = (0, import_primitives4.cylinder)({
30277
30254
  center: [0, 0, 0],
30278
30255
  radius: 1,
30279
- height: copperSurfaceSpan,
30256
+ height: copperFillHeight,
30280
30257
  segments: 64
30281
30258
  // High segment count for smooth ellipse
30282
30259
  });
@@ -30308,22 +30285,6 @@ var platedHole = (plated_hole, ctx, options = {}) => {
30308
30285
  const rectBorderRadius = extractRectBorderRadius(plated_hole);
30309
30286
  const copperSolid = maybeClip(
30310
30287
  (0, import_booleans2.union)(
30311
- // Top rectangular pad (thicker to ensure connection)
30312
- createRectPadGeom({
30313
- width: padWidth,
30314
- height: padHeight,
30315
- thickness: padThickness,
30316
- center: [plated_hole.x, plated_hole.y, topSurfaceZ],
30317
- borderRadius: rectBorderRadius
30318
- }),
30319
- // Bottom rectangular pad (thicker to ensure connection)
30320
- createRectPadGeom({
30321
- width: padWidth,
30322
- height: padHeight,
30323
- thickness: padThickness,
30324
- center: [plated_hole.x, plated_hole.y, bottomSurfaceZ],
30325
- borderRadius: rectBorderRadius
30326
- }),
30327
30288
  // Main copper fill between pads with rounded corners
30328
30289
  (() => {
30329
30290
  const rect2d = (0, import_primitives4.roundedRectangle)({
@@ -30385,7 +30346,7 @@ var platedHole = (plated_hole, ctx, options = {}) => {
30385
30346
  const outerRadius = outerPillHeight / 2;
30386
30347
  const rectLength = Math.abs(holeWidth - holeHeight);
30387
30348
  const outerRectLength = Math.abs(outerPillWidth - outerPillHeight);
30388
- const copperHeight = copperSurfaceSpan;
30349
+ const copperHeight = copperFillHeight;
30389
30350
  const createPillSection = (width10, height10, thickness) => {
30390
30351
  const radius = height10 / 2;
30391
30352
  const length51 = Math.abs(width10 - height10);
@@ -30525,20 +30486,6 @@ var platedHole = (plated_hole, ctx, options = {}) => {
30525
30486
  height: throughDrillHeight
30526
30487
  })
30527
30488
  );
30528
- const copperTopPad = createRectPadGeom({
30529
- width: padWidth,
30530
- height: padHeight,
30531
- thickness: padThickness,
30532
- center: [plated_hole.x, plated_hole.y, topSurfaceZ],
30533
- borderRadius: rectBorderRadius
30534
- });
30535
- const copperBottomPad = createRectPadGeom({
30536
- width: padWidth,
30537
- height: padHeight,
30538
- thickness: padThickness,
30539
- center: [plated_hole.x, plated_hole.y, bottomSurfaceZ],
30540
- borderRadius: rectBorderRadius
30541
- });
30542
30489
  const copperFill = (() => {
30543
30490
  const rect2d = (0, import_primitives4.roundedRectangle)({
30544
30491
  size: [padWidth, padHeight],
@@ -30551,8 +30498,6 @@ var platedHole = (plated_hole, ctx, options = {}) => {
30551
30498
  extruded
30552
30499
  );
30553
30500
  })();
30554
- const copperTopPadCut = (0, import_booleans2.subtract)(copperTopPad, holeCut);
30555
- const copperBottomPadCut = (0, import_booleans2.subtract)(copperBottomPad, holeCut);
30556
30501
  const copperFillCut = (0, import_booleans2.subtract)(copperFill, holeCut);
30557
30502
  const barrelHoleCut = (0, import_booleans2.union)(
30558
30503
  (0, import_primitives4.cuboid)({
@@ -30588,7 +30533,7 @@ var platedHole = (plated_hole, ctx, options = {}) => {
30588
30533
  );
30589
30534
  const barrelWithHole = (0, import_booleans2.subtract)(barrel, barrelHoleCut);
30590
30535
  const finalCopper = maybeClip(
30591
- (0, import_booleans2.union)(copperTopPadCut, copperBottomPadCut, copperFillCut, barrelWithHole),
30536
+ (0, import_booleans2.union)(copperFillCut, barrelWithHole),
30592
30537
  clipGeom
30593
30538
  );
30594
30539
  return (0, import_colors2.colorize)(colors.copper, finalCopper);
@@ -30672,24 +30617,6 @@ var platedHole = (plated_hole, ctx, options = {}) => {
30672
30617
  })
30673
30618
  )
30674
30619
  );
30675
- const copperTopPad = rotateRectPad(
30676
- createRectPadGeom({
30677
- width: padWidth,
30678
- height: padHeight,
30679
- thickness: padThickness,
30680
- center: [plated_hole.x, plated_hole.y, topSurfaceZ],
30681
- borderRadius: rectBorderRadius
30682
- })
30683
- );
30684
- const copperBottomPad = rotateRectPad(
30685
- createRectPadGeom({
30686
- width: padWidth,
30687
- height: padHeight,
30688
- thickness: padThickness,
30689
- center: [plated_hole.x, plated_hole.y, bottomSurfaceZ],
30690
- borderRadius: rectBorderRadius
30691
- })
30692
- );
30693
30620
  const copperFill = rotateRectPad(
30694
30621
  (() => {
30695
30622
  const rect2d = (0, import_primitives4.roundedRectangle)({
@@ -30704,8 +30631,6 @@ var platedHole = (plated_hole, ctx, options = {}) => {
30704
30631
  );
30705
30632
  })()
30706
30633
  );
30707
- const copperTopPadCut = (0, import_booleans2.subtract)(copperTopPad, holeCut);
30708
- const copperBottomPadCut = (0, import_booleans2.subtract)(copperBottomPad, holeCut);
30709
30634
  const copperFillCut = (0, import_booleans2.subtract)(copperFill, holeCut);
30710
30635
  const barrelHoleCut = rotateHole(
30711
30636
  (0, import_booleans2.union)(
@@ -30727,7 +30652,7 @@ var platedHole = (plated_hole, ctx, options = {}) => {
30727
30652
  );
30728
30653
  const barrelWithHole = (0, import_booleans2.subtract)(barrel, barrelHoleCut);
30729
30654
  const finalCopper = maybeClip(
30730
- (0, import_booleans2.union)(copperTopPadCut, copperBottomPadCut, copperFillCut, barrelWithHole),
30655
+ (0, import_booleans2.union)(copperFillCut, barrelWithHole),
30731
30656
  clipGeom
30732
30657
  );
30733
30658
  return (0, import_colors2.colorize)(colors.copper, finalCopper);
@@ -30753,9 +30678,7 @@ var platedHole = (plated_hole, ctx, options = {}) => {
30753
30678
  );
30754
30679
  };
30755
30680
  const mainFill = createPolygonPad(copperFillHeight, centerZ);
30756
- const topPad = createPolygonPad(padThickness, topSurfaceZ);
30757
- const bottomPad = createPolygonPad(padThickness, bottomSurfaceZ);
30758
- const copperSolid = maybeClip((0, import_booleans2.union)(mainFill, topPad, bottomPad), clipGeom);
30681
+ const copperSolid = maybeClip(mainFill, clipGeom);
30759
30682
  const barrel = createHoleWithPolygonPadHoleGeom(plated_hole, barrelHeight);
30760
30683
  if (!barrel) return (0, import_colors2.colorize)(colors.copper, copperSolid);
30761
30684
  const drill = createHoleWithPolygonPadHoleGeom(plated_hole, throughDrillHeight, {
@@ -30789,7 +30712,6 @@ function createViaCopper({
30789
30712
  `Invalid via geometry: outerDiameter (${outerDiameter}) must be > holeDiameter (${holeDiameter})`
30790
30713
  );
30791
30714
  }
30792
- const padThickness = M;
30793
30715
  const platingThickness = M;
30794
30716
  const barrelRadius = Math.min(
30795
30717
  outerDiameter / 2,
@@ -30801,20 +30723,8 @@ function createViaCopper({
30801
30723
  height: thickness,
30802
30724
  segments: SMOOTH_CIRCLE_SEGMENTS
30803
30725
  });
30804
- const topPad = (0, import_primitives5.cylinder)({
30805
- center: [0, 0, thickness / 2],
30806
- radius: outerDiameter / 2,
30807
- height: padThickness,
30808
- segments: SMOOTH_CIRCLE_SEGMENTS
30809
- });
30810
- const bottomPad = (0, import_primitives5.cylinder)({
30811
- center: [0, 0, -thickness / 2],
30812
- radius: outerDiameter / 2,
30813
- height: padThickness,
30814
- segments: SMOOTH_CIRCLE_SEGMENTS
30815
- });
30816
- const viaSolid = (0, import_booleans3.union)([barrel, topPad, bottomPad]);
30817
- const drillHeight = thickness + padThickness * 2;
30726
+ const viaSolid = barrel;
30727
+ const drillHeight = thickness + 2 * M;
30818
30728
  const drill = (0, import_primitives5.cylinder)({
30819
30729
  center: [0, 0, 0],
30820
30730
  radius: holeDiameter / 2,
@@ -31738,7 +31648,7 @@ import { su as su8 } from "@tscircuit/circuit-json-util";
31738
31648
  import { useEffect as useEffect23, useMemo as useMemo19 } from "react";
31739
31649
 
31740
31650
  // src/textures/create-combined-board-textures.ts
31741
- import * as THREE27 from "three";
31651
+ import * as THREE28 from "three";
31742
31652
 
31743
31653
  // node_modules/@tscircuit/math-utils/dist/chunk-5N7UJNVK.js
31744
31654
  var getBoundsFromPoints = (points) => {
@@ -31925,8 +31835,16 @@ function createPadTextureForLayer({
31925
31835
  }
31926
31836
 
31927
31837
  // src/utils/panel-outline-texture.ts
31928
- import * as THREE20 from "three";
31929
31838
  import { su as su6 } from "@tscircuit/circuit-json-util";
31839
+ import * as THREE20 from "three";
31840
+ var resolvePanelIdForTexture = (circuitJson) => {
31841
+ const panels = circuitJson.filter(
31842
+ (e) => e.type === "pcb_panel"
31843
+ );
31844
+ if (panels.length === 0) return null;
31845
+ if (panels.length === 1) return panels[0].pcb_panel_id;
31846
+ return null;
31847
+ };
31930
31848
  function createPanelOutlineTextureForLayer({
31931
31849
  layer,
31932
31850
  circuitJson,
@@ -31934,7 +31852,12 @@ function createPanelOutlineTextureForLayer({
31934
31852
  outlineColor = "black",
31935
31853
  traceTextureResolution
31936
31854
  }) {
31937
- const boardsInPanel = su6(circuitJson).pcb_board.list().filter((b) => b.pcb_panel_id === panelData.pcb_board_id);
31855
+ const panelId = resolvePanelIdForTexture(circuitJson);
31856
+ if (!panelId) return null;
31857
+ const allBoards = su6(circuitJson).pcb_board.list();
31858
+ const boardsInPanel = allBoards.filter(
31859
+ (b) => b.pcb_panel_id === panelId || b.position_mode === "relative_to_panel_anchor" && !b.pcb_panel_id
31860
+ );
31938
31861
  if (boardsInPanel.length === 0) {
31939
31862
  return null;
31940
31863
  }
@@ -32893,6 +32816,109 @@ function createSoldermaskTextureForLayer({
32893
32816
  return texture;
32894
32817
  }
32895
32818
 
32819
+ // src/textures/create-through-hole-texture-for-layer.ts
32820
+ import * as THREE27 from "three";
32821
+
32822
+ // src/textures/through-hole/through-hole-drawing.ts
32823
+ import { CircuitToCanvasDrawer as CircuitToCanvasDrawer6 } from "circuit-to-canvas";
32824
+ var setDrawerBounds6 = (drawer, bounds) => {
32825
+ drawer.setCameraBounds({
32826
+ minX: bounds.minX,
32827
+ maxX: bounds.maxX,
32828
+ minY: bounds.minY,
32829
+ maxY: bounds.maxY
32830
+ });
32831
+ };
32832
+ var drawThroughHoleLayer = ({
32833
+ ctx,
32834
+ layer,
32835
+ bounds,
32836
+ elements,
32837
+ copperColor
32838
+ }) => {
32839
+ const renderLayer = layer === "top" ? "top_copper" : "bottom_copper";
32840
+ const transparent = "rgba(0,0,0,0)";
32841
+ const drawer = new CircuitToCanvasDrawer6(ctx);
32842
+ drawer.configure({
32843
+ colorOverrides: {
32844
+ copper: {
32845
+ top: copperColor,
32846
+ bottom: copperColor,
32847
+ inner1: copperColor,
32848
+ inner2: copperColor,
32849
+ inner3: copperColor,
32850
+ inner4: copperColor,
32851
+ inner5: copperColor,
32852
+ inner6: copperColor
32853
+ },
32854
+ drill: transparent,
32855
+ boardOutline: transparent,
32856
+ substrate: transparent,
32857
+ keepout: transparent,
32858
+ fabricationNote: transparent,
32859
+ silkscreen: { top: transparent, bottom: transparent },
32860
+ courtyard: { top: transparent, bottom: transparent },
32861
+ soldermask: { top: transparent, bottom: transparent },
32862
+ soldermaskWithCopperUnderneath: {
32863
+ top: transparent,
32864
+ bottom: transparent
32865
+ },
32866
+ soldermaskOverCopper: {
32867
+ top: transparent,
32868
+ bottom: transparent
32869
+ }
32870
+ }
32871
+ });
32872
+ setDrawerBounds6(drawer, bounds);
32873
+ drawer.drawElements(elements, {
32874
+ layers: [renderLayer]
32875
+ });
32876
+ };
32877
+
32878
+ // src/textures/create-through-hole-texture-for-layer.ts
32879
+ function createThroughHoleTextureForLayer({
32880
+ layer,
32881
+ circuitJson,
32882
+ boardData,
32883
+ copperColor = "rgb(230, 153, 51)",
32884
+ traceTextureResolution = TRACE_TEXTURE_RESOLUTION
32885
+ }) {
32886
+ const elements = circuitJson.filter((element) => {
32887
+ if (element.type === "pcb_via") return true;
32888
+ if (element.type !== "pcb_plated_hole") return false;
32889
+ const platedHole2 = element;
32890
+ return !Array.isArray(platedHole2.layers) || platedHole2.layers.includes(layer);
32891
+ });
32892
+ if (elements.length === 0) return null;
32893
+ const bounds = calculateOutlineBounds(boardData);
32894
+ const canvasWidth = Math.floor(bounds.width * traceTextureResolution);
32895
+ const canvasHeight = Math.floor(bounds.height * traceTextureResolution);
32896
+ if (canvasWidth <= 0 || canvasHeight <= 0) return null;
32897
+ const canvas = document.createElement("canvas");
32898
+ canvas.width = canvasWidth;
32899
+ canvas.height = canvasHeight;
32900
+ const ctx = canvas.getContext("2d");
32901
+ if (!ctx) return null;
32902
+ if (layer === "bottom") {
32903
+ ctx.translate(0, canvasHeight);
32904
+ ctx.scale(1, -1);
32905
+ }
32906
+ drawThroughHoleLayer({
32907
+ ctx,
32908
+ layer,
32909
+ bounds,
32910
+ elements,
32911
+ copperColor
32912
+ });
32913
+ const texture = new THREE27.CanvasTexture(canvas);
32914
+ texture.generateMipmaps = true;
32915
+ texture.minFilter = THREE27.LinearMipmapLinearFilter;
32916
+ texture.magFilter = THREE27.LinearFilter;
32917
+ texture.anisotropy = 16;
32918
+ texture.needsUpdate = true;
32919
+ return texture;
32920
+ }
32921
+
32896
32922
  // src/textures/create-combined-board-textures.ts
32897
32923
  var toRgb2 = (colorArr) => {
32898
32924
  const [r = 0, g = 0, b = 0] = colorArr;
@@ -32925,10 +32951,10 @@ var createCombinedTexture = ({
32925
32951
  const image = texture.image;
32926
32952
  ctx.drawImage(image, 0, 0, canvasWidth, canvasHeight);
32927
32953
  });
32928
- const combinedTexture = new THREE27.CanvasTexture(canvas);
32954
+ const combinedTexture = new THREE28.CanvasTexture(canvas);
32929
32955
  combinedTexture.generateMipmaps = false;
32930
- combinedTexture.minFilter = THREE27.LinearFilter;
32931
- combinedTexture.magFilter = THREE27.LinearFilter;
32956
+ combinedTexture.minFilter = THREE28.LinearFilter;
32957
+ combinedTexture.magFilter = THREE28.LinearFilter;
32932
32958
  combinedTexture.premultiplyAlpha = true;
32933
32959
  combinedTexture.anisotropy = 16;
32934
32960
  combinedTexture.needsUpdate = true;
@@ -32976,6 +33002,13 @@ function createCombinedBoardTextures({
32976
33002
  copperColor,
32977
33003
  traceTextureResolution
32978
33004
  }) : null;
33005
+ const throughHoleTexture = showCopper ? createThroughHoleTextureForLayer({
33006
+ layer,
33007
+ circuitJson,
33008
+ boardData,
33009
+ copperColor,
33010
+ traceTextureResolution
33011
+ }) : null;
32979
33012
  const silkscreenTexture = showSilkscreen ? createSilkscreenTextureForLayer({
32980
33013
  layer,
32981
33014
  circuitJson,
@@ -33006,6 +33039,7 @@ function createCombinedBoardTextures({
33006
33039
  textures: [
33007
33040
  traceTexture,
33008
33041
  padTexture,
33042
+ throughHoleTexture,
33009
33043
  soldermaskTexture,
33010
33044
  copperTextTexture,
33011
33045
  silkscreenTexture,
@@ -33025,15 +33059,15 @@ function createCombinedBoardTextures({
33025
33059
  }
33026
33060
 
33027
33061
  // src/textures/create-copper-pour-texture-for-layer.ts
33028
- import * as THREE28 from "three";
33029
- import { CircuitToCanvasDrawer as CircuitToCanvasDrawer6 } from "circuit-to-canvas";
33062
+ import * as THREE29 from "three";
33063
+ import { CircuitToCanvasDrawer as CircuitToCanvasDrawer7 } from "circuit-to-canvas";
33030
33064
 
33031
33065
  // src/geoms/brep-converter.ts
33032
33066
  var import_primitives7 = __toESM(require_primitives(), 1);
33033
33067
  var import_booleans5 = __toESM(require_booleans(), 1);
33034
33068
 
33035
33069
  // src/textures/create-three-texture-meshes.ts
33036
- import * as THREE29 from "three";
33070
+ import * as THREE30 from "three";
33037
33071
  function createTexturePlane(config, boardData) {
33038
33072
  const {
33039
33073
  texture,
@@ -33045,15 +33079,15 @@ function createTexturePlane(config, boardData) {
33045
33079
  } = config;
33046
33080
  if (!texture) return null;
33047
33081
  const boardOutlineBounds = calculateOutlineBounds(boardData);
33048
- const planeGeom = new THREE29.PlaneGeometry(
33082
+ const planeGeom = new THREE30.PlaneGeometry(
33049
33083
  boardOutlineBounds.width,
33050
33084
  boardOutlineBounds.height
33051
33085
  );
33052
- const material = new THREE29.MeshBasicMaterial({
33086
+ const material = new THREE30.MeshBasicMaterial({
33053
33087
  map: texture,
33054
33088
  transparent: true,
33055
33089
  alphaTest: 0.08,
33056
- side: THREE29.DoubleSide,
33090
+ side: THREE30.DoubleSide,
33057
33091
  depthWrite: true,
33058
33092
  polygonOffset: usePolygonOffset,
33059
33093
  polygonOffsetFactor: usePolygonOffset ? -4 : 0,
@@ -33061,7 +33095,7 @@ function createTexturePlane(config, boardData) {
33061
33095
  polygonOffsetUnits: usePolygonOffset ? -4 : 0,
33062
33096
  opacity: isFaux ? FAUX_BOARD_OPACITY : 1
33063
33097
  });
33064
- const mesh = new THREE29.Mesh(planeGeom, material);
33098
+ const mesh = new THREE30.Mesh(planeGeom, material);
33065
33099
  mesh.position.set(
33066
33100
  boardOutlineBounds.centerX,
33067
33101
  boardOutlineBounds.centerY,
@@ -33106,7 +33140,7 @@ function createTextureMeshes(textures, boardData, pcbThickness, isFaux = false)
33106
33140
  }
33107
33141
 
33108
33142
  // src/three-components/JscadBoardTextures.tsx
33109
- import * as THREE30 from "three";
33143
+ import * as THREE31 from "three";
33110
33144
 
33111
33145
  // src/utils/layer-texture-resolution.ts
33112
33146
  var DEFAULT_MAX_TEXTURE_PIXELS = 4e6;
@@ -33202,7 +33236,7 @@ function JscadBoardTextures({
33202
33236
  const typedMaterial = material;
33203
33237
  for (const prop of textureProps) {
33204
33238
  const texture = typedMaterial[prop];
33205
- if (texture && texture instanceof THREE30.Texture) {
33239
+ if (texture && texture instanceof THREE31.Texture) {
33206
33240
  texture.dispose();
33207
33241
  typedMaterial[prop] = null;
33208
33242
  }
@@ -33212,22 +33246,22 @@ function JscadBoardTextures({
33212
33246
  const createTexturePlane2 = (texture, zOffset, isBottomLayer, name, usePolygonOffset = false, depthWrite = true, renderOrder = 1) => {
33213
33247
  if (!texture) return null;
33214
33248
  const boardOutlineBounds = calculateOutlineBounds(boardData);
33215
- const planeGeom = new THREE30.PlaneGeometry(
33249
+ const planeGeom = new THREE31.PlaneGeometry(
33216
33250
  boardOutlineBounds.width,
33217
33251
  boardOutlineBounds.height
33218
33252
  );
33219
- const material = new THREE30.MeshBasicMaterial({
33253
+ const material = new THREE31.MeshBasicMaterial({
33220
33254
  map: texture,
33221
33255
  transparent: true,
33222
33256
  alphaTest: 0.08,
33223
- side: THREE30.DoubleSide,
33257
+ side: THREE31.DoubleSide,
33224
33258
  depthWrite,
33225
33259
  polygonOffset: usePolygonOffset,
33226
33260
  polygonOffsetFactor: usePolygonOffset ? -4 : 0,
33227
33261
  polygonOffsetUnits: usePolygonOffset ? -4 : 0,
33228
33262
  opacity: isFaux ? FAUX_BOARD_OPACITY : 1
33229
33263
  });
33230
- const mesh = new THREE30.Mesh(planeGeom, material);
33264
+ const mesh = new THREE31.Mesh(planeGeom, material);
33231
33265
  mesh.position.set(
33232
33266
  boardOutlineBounds.centerX,
33233
33267
  boardOutlineBounds.centerY,
@@ -33272,7 +33306,7 @@ function JscadBoardTextures({
33272
33306
  mesh.geometry.dispose();
33273
33307
  if (Array.isArray(mesh.material)) {
33274
33308
  mesh.material.forEach((material) => disposeTextureMaterial(material));
33275
- } else if (mesh.material instanceof THREE30.Material) {
33309
+ } else if (mesh.material instanceof THREE31.Material) {
33276
33310
  disposeTextureMaterial(mesh.material);
33277
33311
  }
33278
33312
  });
@@ -33505,12 +33539,12 @@ var CadViewerJscad = forwardRef3(
33505
33539
  // src/CadViewerManifold.tsx
33506
33540
  import { su as su17 } from "@tscircuit/circuit-json-util";
33507
33541
  import { useEffect as useEffect25, useMemo as useMemo22, useState as useState16 } from "react";
33508
- import * as THREE37 from "three";
33542
+ import * as THREE38 from "three";
33509
33543
 
33510
33544
  // src/hooks/useManifoldBoardBuilder.ts
33511
33545
  import { su as su16 } from "@tscircuit/circuit-json-util";
33512
33546
  import { useEffect as useEffect24, useMemo as useMemo21, useRef as useRef9, useState as useState15 } from "react";
33513
- import * as THREE34 from "three";
33547
+ import * as THREE35 from "three";
33514
33548
 
33515
33549
  // src/utils/manifold/create-manifold-board.ts
33516
33550
  var arePointsClockwise2 = (points) => {
@@ -33852,17 +33886,17 @@ function processNonPlatedHolesForManifold(Manifold, CrossSection, circuitJson, p
33852
33886
 
33853
33887
  // src/utils/manifold/process-plated-holes.ts
33854
33888
  import { su as su14 } from "@tscircuit/circuit-json-util";
33855
- import * as THREE32 from "three";
33889
+ import * as THREE33 from "three";
33856
33890
 
33857
33891
  // src/utils/manifold-mesh-to-three-geometry.ts
33858
- import * as THREE31 from "three";
33892
+ import * as THREE32 from "three";
33859
33893
  function manifoldMeshToThreeGeometry(manifoldMesh) {
33860
- const geometry = new THREE31.BufferGeometry();
33894
+ const geometry = new THREE32.BufferGeometry();
33861
33895
  geometry.setAttribute(
33862
33896
  "position",
33863
- new THREE31.Float32BufferAttribute(manifoldMesh.vertProperties, 3)
33897
+ new THREE32.Float32BufferAttribute(manifoldMesh.vertProperties, 3)
33864
33898
  );
33865
- geometry.setIndex(new THREE31.Uint32BufferAttribute(manifoldMesh.triVerts, 1));
33899
+ geometry.setIndex(new THREE32.Uint32BufferAttribute(manifoldMesh.triVerts, 1));
33866
33900
  if (manifoldMesh.runIndex && manifoldMesh.runIndex.length > 1 && manifoldMesh.runOriginalID) {
33867
33901
  for (let i = 0; i < manifoldMesh.runIndex.length - 1; i++) {
33868
33902
  const start = manifoldMesh.runIndex[i];
@@ -33896,7 +33930,7 @@ var createEllipsePoints = (width10, height10, segments) => {
33896
33930
  }
33897
33931
  return points;
33898
33932
  };
33899
- var COPPER_COLOR = new THREE32.Color(...colors.copper);
33933
+ var COPPER_COLOR = new THREE33.Color(...colors.copper);
33900
33934
  var PLATED_HOLE_LIP_HEIGHT = 0.05;
33901
33935
  var PLATED_HOLE_PAD_THICKNESS = 3e-3;
33902
33936
  var PLATED_HOLE_SURFACE_CLEARANCE = 5e-4;
@@ -33998,6 +34032,10 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
33998
34032
  return holeOp;
33999
34033
  };
34000
34034
  pcbPlatedHoles.forEach((ph, index2) => {
34035
+ const internalCopperThickness = Math.max(
34036
+ pcbThickness - 2 * (PLATED_HOLE_PAD_THICKNESS + PLATED_HOLE_SURFACE_CLEARANCE + PLATED_HOLE_FILL_CLEARANCE),
34037
+ M
34038
+ );
34001
34039
  if (ph.shape === "circle") {
34002
34040
  const translatedDrill = createPlatedHoleDrill({
34003
34041
  Manifold,
@@ -34010,7 +34048,7 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
34010
34048
  });
34011
34049
  manifoldInstancesForCleanup.push(translatedDrill);
34012
34050
  platedHoleBoardDrills.push(translatedDrill);
34013
- const copperPartThickness = pcbThickness + 2 * MANIFOLD_Z_OFFSET;
34051
+ const copperPartThickness = internalCopperThickness;
34014
34052
  const platedPart = Manifold.cylinder(
34015
34053
  copperPartThickness,
34016
34054
  ph.outer_diameter / 2,
@@ -34070,7 +34108,7 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
34070
34108
  ]);
34071
34109
  manifoldInstancesForCleanup.push(translatedBoardPillDrill);
34072
34110
  platedHoleBoardDrills.push(translatedBoardPillDrill);
34073
- const copperPartThickness = pcbThickness + 2 * MANIFOLD_Z_OFFSET;
34111
+ const copperPartThickness = internalCopperThickness;
34074
34112
  const outerCopperOpUnrotated = createPillOp(
34075
34113
  outerW,
34076
34114
  outerH,
@@ -34148,29 +34186,6 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
34148
34186
  borderRadius: rectBorderRadius
34149
34187
  });
34150
34188
  manifoldInstancesForCleanup.push(mainFill);
34151
- const topPad = createRoundedRectPrism({
34152
- Manifold,
34153
- width: padWidth,
34154
- height: padHeight,
34155
- thickness: padThickness,
34156
- borderRadius: rectBorderRadius
34157
- }).translate([
34158
- 0,
34159
- 0,
34160
- pcbThickness / 2 + PLATED_HOLE_SURFACE_CLEARANCE + padThickness / 2
34161
- ]);
34162
- const bottomPad = createRoundedRectPrism({
34163
- Manifold,
34164
- width: padWidth,
34165
- height: padHeight,
34166
- thickness: padThickness,
34167
- borderRadius: rectBorderRadius
34168
- }).translate([
34169
- 0,
34170
- 0,
34171
- -pcbThickness / 2 - PLATED_HOLE_SURFACE_CLEARANCE - padThickness / 2
34172
- ]);
34173
- manifoldInstancesForCleanup.push(topPad, bottomPad);
34174
34189
  const barrelPill = createPillOp(
34175
34190
  holeW,
34176
34191
  holeH,
@@ -34178,12 +34193,7 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
34178
34193
  // Slightly shorter than board
34179
34194
  ).translate([holeOffsetX, holeOffsetY, 0]);
34180
34195
  manifoldInstancesForCleanup.push(barrelPill);
34181
- const copperUnion = Manifold.union([
34182
- mainFill,
34183
- topPad,
34184
- bottomPad,
34185
- barrelPill
34186
- ]);
34196
+ const copperUnion = Manifold.union([mainFill, barrelPill]);
34187
34197
  manifoldInstancesForCleanup.push(copperUnion);
34188
34198
  const holeCutOp = createPillOp(
34189
34199
  Math.max(holeW - 2 * PLATED_HOLE_LIP_HEIGHT, 0.01),
@@ -34263,39 +34273,6 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
34263
34273
  manifoldInstancesForCleanup.push(rotatedMainFill);
34264
34274
  mainFill = rotatedMainFill;
34265
34275
  }
34266
- let topPad = createRoundedRectPrism({
34267
- Manifold,
34268
- width: padWidth,
34269
- height: padHeight,
34270
- thickness: padThickness,
34271
- borderRadius: rectBorderRadius
34272
- }).translate([
34273
- 0,
34274
- 0,
34275
- pcbThickness / 2 + PLATED_HOLE_SURFACE_CLEARANCE + padThickness / 2
34276
- ]);
34277
- if (ph.rect_ccw_rotation) {
34278
- const rotatedTopPad = topPad.rotate([0, 0, ph.rect_ccw_rotation]);
34279
- manifoldInstancesForCleanup.push(rotatedTopPad);
34280
- topPad = rotatedTopPad;
34281
- }
34282
- let bottomPad = createRoundedRectPrism({
34283
- Manifold,
34284
- width: padWidth,
34285
- height: padHeight,
34286
- thickness: padThickness,
34287
- borderRadius: rectBorderRadius
34288
- }).translate([
34289
- 0,
34290
- 0,
34291
- -pcbThickness / 2 - PLATED_HOLE_SURFACE_CLEARANCE - padThickness / 2
34292
- ]);
34293
- if (ph.rect_ccw_rotation) {
34294
- const rotatedBottomPad = bottomPad.rotate([0, 0, ph.rect_ccw_rotation]);
34295
- manifoldInstancesForCleanup.push(rotatedBottomPad);
34296
- bottomPad = rotatedBottomPad;
34297
- }
34298
- manifoldInstancesForCleanup.push(topPad, bottomPad);
34299
34276
  let barrelPill = createPillOp(
34300
34277
  holeW,
34301
34278
  holeH,
@@ -34308,12 +34285,7 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
34308
34285
  barrelPill = rotatedBarrel;
34309
34286
  }
34310
34287
  manifoldInstancesForCleanup.push(barrelPill);
34311
- const copperUnion = Manifold.union([
34312
- mainFill,
34313
- topPad,
34314
- bottomPad,
34315
- barrelPill
34316
- ]);
34288
+ const copperUnion = Manifold.union([mainFill, barrelPill]);
34317
34289
  manifoldInstancesForCleanup.push(copperUnion);
34318
34290
  let holeCutOp = createPillOp(
34319
34291
  Math.max(holeW - 2 * PLATED_HOLE_LIP_HEIGHT, 0.01),
@@ -34370,23 +34342,7 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
34370
34342
  padOutline,
34371
34343
  thickness: fillThickness
34372
34344
  });
34373
- const topPad = createPolygonPadOp({ padOutline, thickness: padThickness });
34374
- const bottomPad = createPolygonPadOp({
34375
- padOutline,
34376
- thickness: padThickness
34377
- });
34378
- if (!mainFill || !topPad || !bottomPad) return;
34379
- const topTranslated = topPad.translate([
34380
- 0,
34381
- 0,
34382
- pcbThickness / 2 + PLATED_HOLE_SURFACE_CLEARANCE + padThickness / 2
34383
- ]);
34384
- const bottomTranslated = bottomPad.translate([
34385
- 0,
34386
- 0,
34387
- -pcbThickness / 2 - PLATED_HOLE_SURFACE_CLEARANCE - padThickness / 2
34388
- ]);
34389
- manifoldInstancesForCleanup.push(topTranslated, bottomTranslated);
34345
+ if (!mainFill) return;
34390
34346
  const barrelOp = createHoleOpForPolygonPad({
34391
34347
  ph,
34392
34348
  depth: pcbThickness * 1.02
@@ -34397,12 +34353,7 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
34397
34353
  depth: pcbThickness * 0.8,
34398
34354
  sizeDelta: -2 * M
34399
34355
  }) || barrelOp;
34400
- const copperUnion = Manifold.union([
34401
- mainFill,
34402
- topTranslated,
34403
- bottomTranslated,
34404
- barrelOp
34405
- ]);
34356
+ const copperUnion = Manifold.union([mainFill, barrelOp]);
34406
34357
  manifoldInstancesForCleanup.push(copperUnion);
34407
34358
  const finalCopper = copperUnion.subtract(holeCutOp);
34408
34359
  manifoldInstancesForCleanup.push(finalCopper);
@@ -34459,7 +34410,7 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
34459
34410
  const translatedDrill = boardDrillOp.translate([ph.x, ph.y, 0]);
34460
34411
  manifoldInstancesForCleanup.push(translatedDrill);
34461
34412
  platedHoleBoardDrills.push(translatedDrill);
34462
- const copperPartThickness = pcbThickness + 2 * MANIFOLD_Z_OFFSET;
34413
+ const copperPartThickness = internalCopperThickness;
34463
34414
  let outerPoints = createEllipsePoints(
34464
34415
  outerW,
34465
34416
  outerH,
@@ -34558,29 +34509,6 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
34558
34509
  borderRadius: rectBorderRadius
34559
34510
  });
34560
34511
  manifoldInstancesForCleanup.push(mainFill);
34561
- const topPad = createRoundedRectPrism({
34562
- Manifold,
34563
- width: padWidth,
34564
- height: padHeight,
34565
- thickness: padThickness,
34566
- borderRadius: rectBorderRadius
34567
- }).translate([
34568
- 0,
34569
- 0,
34570
- pcbThickness / 2 + PLATED_HOLE_SURFACE_CLEARANCE + padThickness / 2
34571
- ]);
34572
- const bottomPad = createRoundedRectPrism({
34573
- Manifold,
34574
- width: padWidth,
34575
- height: padHeight,
34576
- thickness: padThickness,
34577
- borderRadius: rectBorderRadius
34578
- }).translate([
34579
- 0,
34580
- 0,
34581
- -pcbThickness / 2 - PLATED_HOLE_SURFACE_CLEARANCE - padThickness / 2
34582
- ]);
34583
- manifoldInstancesForCleanup.push(topPad, bottomPad);
34584
34512
  const barrelCylinder = Manifold.cylinder(
34585
34513
  pcbThickness * 0.8,
34586
34514
  // Slightly taller than board
@@ -34590,12 +34518,7 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
34590
34518
  true
34591
34519
  ).translate([holeOffsetX, holeOffsetY, 0]);
34592
34520
  manifoldInstancesForCleanup.push(barrelCylinder);
34593
- const copperUnion = Manifold.union([
34594
- mainFill,
34595
- topPad,
34596
- bottomPad,
34597
- barrelCylinder
34598
- ]);
34521
+ const copperUnion = Manifold.union([mainFill, barrelCylinder]);
34599
34522
  manifoldInstancesForCleanup.push(copperUnion);
34600
34523
  const holeDrill = Manifold.cylinder(
34601
34524
  pcbThickness * 1.2,
@@ -34638,7 +34561,7 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
34638
34561
 
34639
34562
  // src/utils/manifold/process-vias.ts
34640
34563
  import { su as su15 } from "@tscircuit/circuit-json-util";
34641
- import * as THREE33 from "three";
34564
+ import * as THREE34 from "three";
34642
34565
 
34643
34566
  // src/utils/via-geoms.ts
34644
34567
  function createViaCopper2({
@@ -34651,7 +34574,6 @@ function createViaCopper2({
34651
34574
  zOffset = 1e-3,
34652
34575
  segments = 32
34653
34576
  }) {
34654
- const padThickness = zOffset;
34655
34577
  const platingThickness = zOffset;
34656
34578
  if (outerDiameter < holeDiameter) {
34657
34579
  throw new Error(
@@ -34663,22 +34585,8 @@ function createViaCopper2({
34663
34585
  holeDiameter / 2 + platingThickness
34664
34586
  );
34665
34587
  const barrel = Manifold.cylinder(thickness, barrelRadius, -1, segments, true);
34666
- const topPad = Manifold.cylinder(
34667
- padThickness,
34668
- outerDiameter / 2,
34669
- -1,
34670
- segments,
34671
- true
34672
- ).translate([0, 0, thickness / 2]);
34673
- const bottomPad = Manifold.cylinder(
34674
- padThickness,
34675
- outerDiameter / 2,
34676
- -1,
34677
- segments,
34678
- true
34679
- ).translate([0, 0, -thickness / 2]);
34680
- const viaSolid = Manifold.union([barrel, topPad, bottomPad]);
34681
- const drillHeight = thickness + padThickness * 2;
34588
+ const viaSolid = barrel;
34589
+ const drillHeight = thickness + 2 * zOffset;
34682
34590
  const drill = Manifold.cylinder(
34683
34591
  drillHeight,
34684
34592
  holeDiameter / 2,
@@ -34691,7 +34599,7 @@ function createViaCopper2({
34691
34599
  }
34692
34600
 
34693
34601
  // src/utils/manifold/process-vias.ts
34694
- var COPPER_COLOR2 = new THREE33.Color(...colors.copper);
34602
+ var COPPER_COLOR2 = new THREE34.Color(...colors.copper);
34695
34603
  function processViasForManifold(Manifold, circuitJson, pcbThickness, manifoldInstancesForCleanup, boardClipVolume) {
34696
34604
  const viaBoardDrills = [];
34697
34605
  const pcbVias = su15(circuitJson).pcb_via.list();
@@ -34911,7 +34819,7 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson, visibility) => {
34911
34819
  {
34912
34820
  key: "plated-holes-union",
34913
34821
  geometry: cutPlatedGeom,
34914
- color: new THREE34.Color(
34822
+ color: new THREE35.Color(
34915
34823
  colors.copper[0],
34916
34824
  colors.copper[1],
34917
34825
  colors.copper[2]
@@ -34941,7 +34849,7 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson, visibility) => {
34941
34849
  const matColorArray = boardMaterialColors[boardData.material] ?? colors.fr4Tan;
34942
34850
  currentGeoms.board = {
34943
34851
  geometry: finalBoardGeom,
34944
- color: new THREE34.Color(
34852
+ color: new THREE35.Color(
34945
34853
  matColorArray[0],
34946
34854
  matColorArray[1],
34947
34855
  matColorArray[2]
@@ -34986,11 +34894,11 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson, visibility) => {
34986
34894
  };
34987
34895
 
34988
34896
  // src/utils/manifold/create-three-geometry-meshes.ts
34989
- import * as THREE36 from "three";
34897
+ import * as THREE37 from "three";
34990
34898
 
34991
34899
  // src/utils/create-board-material.ts
34992
- import * as THREE35 from "three";
34993
- var DEFAULT_SIDE = THREE35.DoubleSide;
34900
+ import * as THREE36 from "three";
34901
+ var DEFAULT_SIDE = THREE36.DoubleSide;
34994
34902
  var createBoardMaterial = ({
34995
34903
  material,
34996
34904
  color,
@@ -34998,7 +34906,7 @@ var createBoardMaterial = ({
34998
34906
  isFaux = false
34999
34907
  }) => {
35000
34908
  if (material === "fr4") {
35001
- return new THREE35.MeshPhysicalMaterial({
34909
+ return new THREE36.MeshPhysicalMaterial({
35002
34910
  color,
35003
34911
  side,
35004
34912
  metalness: 0,
@@ -35015,7 +34923,7 @@ var createBoardMaterial = ({
35015
34923
  polygonOffsetUnits: 1
35016
34924
  });
35017
34925
  }
35018
- return new THREE35.MeshStandardMaterial({
34926
+ return new THREE36.MeshStandardMaterial({
35019
34927
  color,
35020
34928
  side,
35021
34929
  flatShading: true,
@@ -35034,12 +34942,12 @@ function createGeometryMeshes(geoms) {
35034
34942
  const meshes = [];
35035
34943
  if (!geoms) return meshes;
35036
34944
  if (geoms.board && geoms.board.geometry) {
35037
- const mesh = new THREE36.Mesh(
34945
+ const mesh = new THREE37.Mesh(
35038
34946
  geoms.board.geometry,
35039
34947
  createBoardMaterial({
35040
34948
  material: geoms.board.material,
35041
34949
  color: geoms.board.color,
35042
- side: THREE36.DoubleSide,
34950
+ side: THREE37.DoubleSide,
35043
34951
  isFaux: geoms.board.isFaux
35044
34952
  })
35045
34953
  );
@@ -35049,11 +34957,11 @@ function createGeometryMeshes(geoms) {
35049
34957
  const createMeshesFromArray = (geomArray) => {
35050
34958
  if (geomArray) {
35051
34959
  geomArray.forEach((comp) => {
35052
- const mesh = new THREE36.Mesh(
34960
+ const mesh = new THREE37.Mesh(
35053
34961
  comp.geometry,
35054
- new THREE36.MeshStandardMaterial({
34962
+ new THREE37.MeshStandardMaterial({
35055
34963
  color: comp.color,
35056
- side: THREE36.DoubleSide,
34964
+ side: THREE37.DoubleSide,
35057
34965
  flatShading: true
35058
34966
  // Consistent with board
35059
34967
  })
@@ -35097,7 +35005,7 @@ var BoardMeshes = ({
35097
35005
  const typedMaterial = material;
35098
35006
  for (const prop of textureProps) {
35099
35007
  const texture = typedMaterial[prop];
35100
- if (texture && texture instanceof THREE37.Texture) {
35008
+ if (texture && texture instanceof THREE38.Texture) {
35101
35009
  texture.dispose();
35102
35010
  typedMaterial[prop] = null;
35103
35011
  }
@@ -42039,7 +41947,7 @@ var KeyboardShortcutsDialog = ({
42039
41947
 
42040
41948
  // src/CadViewer.tsx
42041
41949
  import { jsx as jsx38, jsxs as jsxs11 } from "react/jsx-runtime";
42042
- var DEFAULT_TARGET = new THREE38.Vector3(0, 0, 0);
41950
+ var DEFAULT_TARGET = new THREE39.Vector3(0, 0, 0);
42043
41951
  var INITIAL_CAMERA_POSITION = [5, -5, 5];
42044
41952
  var CadViewerInner = (props) => {
42045
41953
  const [engine, setEngine] = useState36("manifold");
@@ -42306,11 +42214,11 @@ var CadViewer = (props) => {
42306
42214
  // src/convert-circuit-json-to-3d-svg.ts
42307
42215
  var import_debug = __toESM(require_browser(), 1);
42308
42216
  import { su as su18 } from "@tscircuit/circuit-json-util";
42309
- import * as THREE42 from "three";
42217
+ import * as THREE43 from "three";
42310
42218
  import { SVGRenderer } from "three/examples/jsm/renderers/SVGRenderer.js";
42311
42219
 
42312
42220
  // src/utils/create-geometry-from-polygons.ts
42313
- import * as THREE39 from "three";
42221
+ import * as THREE40 from "three";
42314
42222
  import { BufferGeometry as BufferGeometry4, Float32BufferAttribute as Float32BufferAttribute3 } from "three";
42315
42223
  function createGeometryFromPolygons(polygons) {
42316
42224
  const geometry = new BufferGeometry4();
@@ -42324,12 +42232,12 @@ function createGeometryFromPolygons(polygons) {
42324
42232
  ...polygon3.vertices[i + 1]
42325
42233
  // Third vertex
42326
42234
  );
42327
- const v1 = new THREE39.Vector3(...polygon3.vertices[0]);
42328
- const v2 = new THREE39.Vector3(...polygon3.vertices[i]);
42329
- const v3 = new THREE39.Vector3(...polygon3.vertices[i + 1]);
42330
- const normal = new THREE39.Vector3().crossVectors(
42331
- new THREE39.Vector3().subVectors(v2, v1),
42332
- new THREE39.Vector3().subVectors(v3, v1)
42235
+ const v1 = new THREE40.Vector3(...polygon3.vertices[0]);
42236
+ const v2 = new THREE40.Vector3(...polygon3.vertices[i]);
42237
+ const v3 = new THREE40.Vector3(...polygon3.vertices[i + 1]);
42238
+ const normal = new THREE40.Vector3().crossVectors(
42239
+ new THREE40.Vector3().subVectors(v2, v1),
42240
+ new THREE40.Vector3().subVectors(v3, v1)
42333
42241
  ).normalize();
42334
42242
  normals.push(
42335
42243
  normal.x,
@@ -42353,10 +42261,10 @@ function createGeometryFromPolygons(polygons) {
42353
42261
  var import_modeling2 = __toESM(require_src(), 1);
42354
42262
  var import_jscad_planner2 = __toESM(require_dist(), 1);
42355
42263
  var jscadModeling2 = __toESM(require_src(), 1);
42356
- import * as THREE41 from "three";
42264
+ import * as THREE42 from "three";
42357
42265
 
42358
42266
  // src/utils/load-model.ts
42359
- import * as THREE40 from "three";
42267
+ import * as THREE41 from "three";
42360
42268
  import { GLTFLoader as GLTFLoader2 } from "three/examples/jsm/loaders/GLTFLoader.js";
42361
42269
  import { OBJLoader as OBJLoader2 } from "three/examples/jsm/loaders/OBJLoader.js";
42362
42270
  import { STLLoader as STLLoader2 } from "three/examples/jsm/loaders/STLLoader.js";
@@ -42364,12 +42272,12 @@ async function load3DModel(url) {
42364
42272
  if (url.endsWith(".stl")) {
42365
42273
  const loader = new STLLoader2();
42366
42274
  const geometry = await loader.loadAsync(url);
42367
- const material = new THREE40.MeshStandardMaterial({
42275
+ const material = new THREE41.MeshStandardMaterial({
42368
42276
  color: 8947848,
42369
42277
  metalness: 0.5,
42370
42278
  roughness: 0.5
42371
42279
  });
42372
- return new THREE40.Mesh(geometry, material);
42280
+ return new THREE41.Mesh(geometry, material);
42373
42281
  }
42374
42282
  if (url.endsWith(".obj")) {
42375
42283
  const loader = new OBJLoader2();
@@ -42402,9 +42310,9 @@ async function renderComponent(component, scene) {
42402
42310
  }
42403
42311
  if (component.rotation) {
42404
42312
  model.rotation.set(
42405
- THREE41.MathUtils.degToRad(component.rotation.x ?? 0),
42406
- THREE41.MathUtils.degToRad(component.rotation.y ?? 0),
42407
- THREE41.MathUtils.degToRad(component.rotation.z ?? 0)
42313
+ THREE42.MathUtils.degToRad(component.rotation.x ?? 0),
42314
+ THREE42.MathUtils.degToRad(component.rotation.y ?? 0),
42315
+ THREE42.MathUtils.degToRad(component.rotation.z ?? 0)
42408
42316
  );
42409
42317
  }
42410
42318
  scene.add(model);
@@ -42418,13 +42326,13 @@ async function renderComponent(component, scene) {
42418
42326
  );
42419
42327
  if (jscadObject && (jscadObject.polygons || jscadObject.sides)) {
42420
42328
  const threeGeom = convertCSGToThreeGeom(jscadObject);
42421
- const material2 = new THREE41.MeshStandardMaterial({
42329
+ const material2 = new THREE42.MeshStandardMaterial({
42422
42330
  color: 8947848,
42423
42331
  metalness: 0.5,
42424
42332
  roughness: 0.5,
42425
- side: THREE41.DoubleSide
42333
+ side: THREE42.DoubleSide
42426
42334
  });
42427
- const mesh2 = new THREE41.Mesh(threeGeom, material2);
42335
+ const mesh2 = new THREE42.Mesh(threeGeom, material2);
42428
42336
  if (component.position) {
42429
42337
  mesh2.position.set(
42430
42338
  component.position.x ?? 0,
@@ -42434,9 +42342,9 @@ async function renderComponent(component, scene) {
42434
42342
  }
42435
42343
  if (component.rotation) {
42436
42344
  mesh2.rotation.set(
42437
- THREE41.MathUtils.degToRad(component.rotation.x ?? 0),
42438
- THREE41.MathUtils.degToRad(component.rotation.y ?? 0),
42439
- THREE41.MathUtils.degToRad(component.rotation.z ?? 0)
42345
+ THREE42.MathUtils.degToRad(component.rotation.x ?? 0),
42346
+ THREE42.MathUtils.degToRad(component.rotation.y ?? 0),
42347
+ THREE42.MathUtils.degToRad(component.rotation.z ?? 0)
42440
42348
  );
42441
42349
  }
42442
42350
  scene.add(mesh2);
@@ -42453,17 +42361,17 @@ async function renderComponent(component, scene) {
42453
42361
  if (!geom || !geom.polygons && !geom.sides) {
42454
42362
  continue;
42455
42363
  }
42456
- const color = new THREE41.Color(geomInfo.color);
42364
+ const color = new THREE42.Color(geomInfo.color);
42457
42365
  color.convertLinearToSRGB();
42458
42366
  const geomWithColor = { ...geom, color: [color.r, color.g, color.b] };
42459
42367
  const threeGeom = convertCSGToThreeGeom(geomWithColor);
42460
- const material2 = new THREE41.MeshStandardMaterial({
42368
+ const material2 = new THREE42.MeshStandardMaterial({
42461
42369
  vertexColors: true,
42462
42370
  metalness: 0.2,
42463
42371
  roughness: 0.8,
42464
- side: THREE41.DoubleSide
42372
+ side: THREE42.DoubleSide
42465
42373
  });
42466
- const mesh2 = new THREE41.Mesh(threeGeom, material2);
42374
+ const mesh2 = new THREE42.Mesh(threeGeom, material2);
42467
42375
  if (component.position) {
42468
42376
  mesh2.position.set(
42469
42377
  component.position.x ?? 0,
@@ -42473,22 +42381,22 @@ async function renderComponent(component, scene) {
42473
42381
  }
42474
42382
  if (component.rotation) {
42475
42383
  mesh2.rotation.set(
42476
- THREE41.MathUtils.degToRad(component.rotation.x ?? 0),
42477
- THREE41.MathUtils.degToRad(component.rotation.y ?? 0),
42478
- THREE41.MathUtils.degToRad(component.rotation.z ?? 0)
42384
+ THREE42.MathUtils.degToRad(component.rotation.x ?? 0),
42385
+ THREE42.MathUtils.degToRad(component.rotation.y ?? 0),
42386
+ THREE42.MathUtils.degToRad(component.rotation.z ?? 0)
42479
42387
  );
42480
42388
  }
42481
42389
  scene.add(mesh2);
42482
42390
  }
42483
42391
  return;
42484
42392
  }
42485
- const geometry = new THREE41.BoxGeometry(0.5, 0.5, 0.5);
42486
- const material = new THREE41.MeshStandardMaterial({
42393
+ const geometry = new THREE42.BoxGeometry(0.5, 0.5, 0.5);
42394
+ const material = new THREE42.MeshStandardMaterial({
42487
42395
  color: 16711680,
42488
42396
  transparent: true,
42489
42397
  opacity: 0.25
42490
42398
  });
42491
- const mesh = new THREE41.Mesh(geometry, material);
42399
+ const mesh = new THREE42.Mesh(geometry, material);
42492
42400
  if (component.position) {
42493
42401
  mesh.position.set(
42494
42402
  component.position.x ?? 0,
@@ -42509,11 +42417,11 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
42509
42417
  padding = 20,
42510
42418
  zoom = 1.5
42511
42419
  } = options;
42512
- const scene = new THREE42.Scene();
42420
+ const scene = new THREE43.Scene();
42513
42421
  const renderer = new SVGRenderer();
42514
42422
  renderer.setSize(width10, height10);
42515
- renderer.setClearColor(new THREE42.Color(backgroundColor), 1);
42516
- const camera = new THREE42.OrthographicCamera();
42423
+ renderer.setClearColor(new THREE43.Color(backgroundColor), 1);
42424
+ const camera = new THREE43.OrthographicCamera();
42517
42425
  const aspect = width10 / height10;
42518
42426
  const frustumSize = 100;
42519
42427
  const halfFrustumSize = frustumSize / 2 / zoom;
@@ -42527,11 +42435,11 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
42527
42435
  camera.position.set(position.x, position.y, position.z);
42528
42436
  camera.up.set(0, 1, 0);
42529
42437
  const lookAt = options.camera?.lookAt ?? { x: 0, y: 0, z: 0 };
42530
- camera.lookAt(new THREE42.Vector3(lookAt.x, lookAt.y, lookAt.z));
42438
+ camera.lookAt(new THREE43.Vector3(lookAt.x, lookAt.y, lookAt.z));
42531
42439
  camera.updateProjectionMatrix();
42532
- const ambientLight = new THREE42.AmbientLight(16777215, Math.PI / 2);
42440
+ const ambientLight = new THREE43.AmbientLight(16777215, Math.PI / 2);
42533
42441
  scene.add(ambientLight);
42534
- const pointLight = new THREE42.PointLight(16777215, Math.PI / 4);
42442
+ const pointLight = new THREE43.PointLight(16777215, Math.PI / 4);
42535
42443
  pointLight.position.set(-10, -10, 10);
42536
42444
  scene.add(pointLight);
42537
42445
  const components = su18(circuitJson).cad_component.list();
@@ -42542,7 +42450,7 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
42542
42450
  const boardGeom = createBoardGeomFromCircuitJson(circuitJson);
42543
42451
  if (boardGeom) {
42544
42452
  const solderMaskColor = colors.fr4SolderMaskGreen;
42545
- const baseColor = new THREE42.Color(
42453
+ const baseColor = new THREE43.Color(
42546
42454
  solderMaskColor[0],
42547
42455
  solderMaskColor[1],
42548
42456
  solderMaskColor[2]
@@ -42554,28 +42462,28 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
42554
42462
  const material = createBoardMaterial({
42555
42463
  material: boardData?.material,
42556
42464
  color: baseColor,
42557
- side: THREE42.DoubleSide
42465
+ side: THREE43.DoubleSide
42558
42466
  });
42559
- const mesh = new THREE42.Mesh(geometry, material);
42467
+ const mesh = new THREE43.Mesh(geometry, material);
42560
42468
  scene.add(mesh);
42561
42469
  }
42562
42470
  }
42563
- const gridColor = new THREE42.Color(8947848);
42564
- const gridHelper = new THREE42.GridHelper(100, 100, gridColor, gridColor);
42471
+ const gridColor = new THREE43.Color(8947848);
42472
+ const gridHelper = new THREE43.GridHelper(100, 100, gridColor, gridColor);
42565
42473
  gridHelper.rotation.x = Math.PI / 2;
42566
42474
  const materials = Array.isArray(gridHelper.material) ? gridHelper.material : [gridHelper.material];
42567
42475
  for (const mat of materials) {
42568
42476
  mat.transparent = true;
42569
42477
  mat.opacity = 0.3;
42570
- if (mat instanceof THREE42.LineBasicMaterial) {
42478
+ if (mat instanceof THREE43.LineBasicMaterial) {
42571
42479
  mat.color = gridColor;
42572
42480
  mat.vertexColors = false;
42573
42481
  }
42574
42482
  }
42575
42483
  scene.add(gridHelper);
42576
- const box = new THREE42.Box3().setFromObject(scene);
42577
- const center = box.getCenter(new THREE42.Vector3());
42578
- const size4 = box.getSize(new THREE42.Vector3());
42484
+ const box = new THREE43.Box3().setFromObject(scene);
42485
+ const center = box.getCenter(new THREE43.Vector3());
42486
+ const size4 = box.getSize(new THREE43.Vector3());
42579
42487
  scene.position.sub(center);
42580
42488
  const maxDim = Math.max(size4.x, size4.y, size4.z);
42581
42489
  if (maxDim > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/3d-viewer",
3
- "version": "0.0.527",
3
+ "version": "0.0.529",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.js",
6
6
  "type": "module",
@@ -29,8 +29,8 @@
29
29
  "dependencies": {
30
30
  "@jscad/regl-renderer": "^2.6.12",
31
31
  "@jscad/stl-serializer": "^2.1.20",
32
- "circuit-json": "^0.0.372",
33
- "circuit-to-canvas": "^0.0.87",
32
+ "circuit-json": "^0.0.391",
33
+ "circuit-to-canvas": "^0.0.89",
34
34
  "react-hot-toast": "^2.6.0",
35
35
  "three": "^0.165.0",
36
36
  "three-stdlib": "^2.36.0",