@tscircuit/3d-viewer 0.0.404 → 0.0.406

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 +438 -235
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1712,7 +1712,7 @@ var require_toString2 = __commonJS({
1712
1712
  var require_translate = __commonJS({
1713
1713
  "node_modules/@jscad/modeling/src/maths/mat4/translate.js"(exports, module) {
1714
1714
  "use strict";
1715
- var translate5 = (out, matrix, offsets) => {
1715
+ var translate6 = (out, matrix, offsets) => {
1716
1716
  const x = offsets[0];
1717
1717
  const y = offsets[1];
1718
1718
  const z105 = offsets[2];
@@ -1765,7 +1765,7 @@ var require_translate = __commonJS({
1765
1765
  }
1766
1766
  return out;
1767
1767
  };
1768
- module.exports = translate5;
1768
+ module.exports = translate6;
1769
1769
  }
1770
1770
  });
1771
1771
 
@@ -8397,7 +8397,7 @@ var require_roundedRectangle = __commonJS({
8397
8397
  var geom2 = require_geom2();
8398
8398
  var { isGTE, isNumberArray } = require_commonChecks();
8399
8399
  var rectangle = require_rectangle();
8400
- var roundedRectangle = (options) => {
8400
+ var roundedRectangle3 = (options) => {
8401
8401
  const defaults = {
8402
8402
  center: [0, 0],
8403
8403
  size: [2, 2],
@@ -8437,7 +8437,7 @@ var require_roundedRectangle = __commonJS({
8437
8437
  }
8438
8438
  return geom2.fromPoints(corner0Points.concat(corner1Points, corner2Points, corner3Points));
8439
8439
  };
8440
- module.exports = roundedRectangle;
8440
+ module.exports = roundedRectangle3;
8441
8441
  }
8442
8442
  });
8443
8443
 
@@ -9746,7 +9746,7 @@ var require_translate2 = __commonJS({
9746
9746
  var geom2 = require_geom2();
9747
9747
  var geom3 = require_geom3();
9748
9748
  var path2 = require_path2();
9749
- var translate5 = (offset, ...objects) => {
9749
+ var translate6 = (offset, ...objects) => {
9750
9750
  if (!Array.isArray(offset)) throw new Error("offset must be an array");
9751
9751
  objects = flatten(objects);
9752
9752
  if (objects.length === 0) throw new Error("wrong number of arguments");
@@ -9761,11 +9761,11 @@ var require_translate2 = __commonJS({
9761
9761
  });
9762
9762
  return results.length === 1 ? results[0] : results;
9763
9763
  };
9764
- var translateX = (offset, ...objects) => translate5([offset, 0, 0], objects);
9765
- var translateY = (offset, ...objects) => translate5([0, offset, 0], objects);
9766
- var translateZ = (offset, ...objects) => translate5([0, 0, offset], objects);
9764
+ var translateX = (offset, ...objects) => translate6([offset, 0, 0], objects);
9765
+ var translateY = (offset, ...objects) => translate6([0, offset, 0], objects);
9766
+ var translateZ = (offset, ...objects) => translate6([0, 0, offset], objects);
9767
9767
  module.exports = {
9768
- translate: translate5,
9768
+ translate: translate6,
9769
9769
  translateX,
9770
9770
  translateY,
9771
9771
  translateZ
@@ -9780,7 +9780,7 @@ var require_torus = __commonJS({
9780
9780
  var { TAU } = require_constants();
9781
9781
  var extrudeRotate = require_extrudeRotate();
9782
9782
  var { rotate: rotate2 } = require_rotate3();
9783
- var { translate: translate5 } = require_translate2();
9783
+ var { translate: translate6 } = require_translate2();
9784
9784
  var circle = require_circle();
9785
9785
  var { isGT, isGTE } = require_commonChecks();
9786
9786
  var torus = (options) => {
@@ -9805,7 +9805,7 @@ var require_torus = __commonJS({
9805
9805
  if (innerRotation !== 0) {
9806
9806
  innerCircle = rotate2([0, 0, innerRotation], innerCircle);
9807
9807
  }
9808
- innerCircle = translate5([outerRadius, 0], innerCircle);
9808
+ innerCircle = translate6([outerRadius, 0], innerCircle);
9809
9809
  const extrudeOptions = {
9810
9810
  startAngle,
9811
9811
  angle: outerRotation,
@@ -12451,7 +12451,7 @@ var require_extrudeLinear = __commonJS({
12451
12451
  var path2 = require_path2();
12452
12452
  var extrudeLinearGeom2 = require_extrudeLinearGeom2();
12453
12453
  var extrudeLinearPath2 = require_extrudeLinearPath2();
12454
- var extrudeLinear4 = (options, ...objects) => {
12454
+ var extrudeLinear5 = (options, ...objects) => {
12455
12455
  const defaults = {
12456
12456
  height: 1,
12457
12457
  twistAngle: 0,
@@ -12469,7 +12469,7 @@ var require_extrudeLinear = __commonJS({
12469
12469
  });
12470
12470
  return results.length === 1 ? results[0] : results;
12471
12471
  };
12472
- module.exports = extrudeLinear4;
12472
+ module.exports = extrudeLinear5;
12473
12473
  }
12474
12474
  });
12475
12475
 
@@ -13528,7 +13528,7 @@ var require_align = __commonJS({
13528
13528
  var flatten = require_flatten();
13529
13529
  var padArrayToLength = require_padArrayToLength();
13530
13530
  var measureAggregateBoundingBox = require_measureAggregateBoundingBox();
13531
- var { translate: translate5 } = require_translate2();
13531
+ var { translate: translate6 } = require_translate2();
13532
13532
  var validateOptions = (options) => {
13533
13533
  if (!Array.isArray(options.modes) || options.modes.length > 3) throw new Error("align(): modes must be an array of length <= 3");
13534
13534
  options.modes = padArrayToLength(options.modes, "none", 3);
@@ -13565,7 +13565,7 @@ var require_align = __commonJS({
13565
13565
  translation[i] = relativeTo[i] - bounds[0][i];
13566
13566
  }
13567
13567
  }
13568
- return translate5(translation, geometry);
13568
+ return translate6(translation, geometry);
13569
13569
  };
13570
13570
  var align = (options, ...geometries2) => {
13571
13571
  const defaults = {
@@ -13602,7 +13602,7 @@ var require_center = __commonJS({
13602
13602
  var geom3 = require_geom3();
13603
13603
  var path2 = require_path2();
13604
13604
  var measureBoundingBox = require_measureBoundingBox2();
13605
- var { translate: translate5 } = require_translate2();
13605
+ var { translate: translate6 } = require_translate2();
13606
13606
  var centerGeometry = (options, object) => {
13607
13607
  const defaults = {
13608
13608
  axes: [true, true, true],
@@ -13614,7 +13614,7 @@ var require_center = __commonJS({
13614
13614
  if (axes[0]) offset[0] = relativeTo[0] - (bounds[0][0] + (bounds[1][0] - bounds[0][0]) / 2);
13615
13615
  if (axes[1]) offset[1] = relativeTo[1] - (bounds[0][1] + (bounds[1][1] - bounds[0][1]) / 2);
13616
13616
  if (axes[2]) offset[2] = relativeTo[2] - (bounds[0][2] + (bounds[1][2] - bounds[0][2]) / 2);
13617
- return translate5(offset, object);
13617
+ return translate6(offset, object);
13618
13618
  };
13619
13619
  var center = (options, ...objects) => {
13620
13620
  const defaults = {
@@ -14598,9 +14598,39 @@ function MixedStlModel({
14598
14598
 
14599
14599
  // src/three-components/GltfModel.tsx
14600
14600
  import { useState as useState3, useEffect as useEffect5 } from "react";
14601
- import * as THREE3 from "three";
14601
+ import * as THREE4 from "three";
14602
14602
  import { GLTFLoader } from "three-stdlib";
14603
+
14604
+ // src/react-three/getDefaultEnvironmentMap.ts
14605
+ import * as THREE3 from "three";
14606
+ import { RoomEnvironment } from "three-stdlib";
14607
+ var environmentCache = /* @__PURE__ */ new WeakMap();
14608
+ var createFallbackEnvironmentMap = () => {
14609
+ const texture = new THREE3.Texture();
14610
+ texture.name = "fallback-environment-map";
14611
+ texture.mapping = THREE3.EquirectangularReflectionMapping;
14612
+ return texture;
14613
+ };
14614
+ var getDefaultEnvironmentMap = (renderer) => {
14615
+ if (!renderer) return null;
14616
+ const cacheKey = renderer;
14617
+ const cached = environmentCache.get(cacheKey);
14618
+ if (cached) return cached;
14619
+ let texture;
14620
+ if (renderer instanceof THREE3.WebGLRenderer) {
14621
+ const pmremGenerator = new THREE3.PMREMGenerator(renderer);
14622
+ texture = pmremGenerator.fromScene(RoomEnvironment(), 0.04).texture;
14623
+ pmremGenerator.dispose();
14624
+ } else {
14625
+ texture = createFallbackEnvironmentMap();
14626
+ }
14627
+ environmentCache.set(cacheKey, texture);
14628
+ return texture;
14629
+ };
14630
+
14631
+ // src/three-components/GltfModel.tsx
14603
14632
  import { jsx as jsx4 } from "react/jsx-runtime";
14633
+ var DEFAULT_ENV_MAP_INTENSITY = 1.25;
14604
14634
  function GltfModel({
14605
14635
  gltfUrl,
14606
14636
  position,
@@ -14610,7 +14640,7 @@ function GltfModel({
14610
14640
  isHovered,
14611
14641
  scale: scale2
14612
14642
  }) {
14613
- const { rootObject } = useThree();
14643
+ const { renderer, rootObject } = useThree();
14614
14644
  const [model, setModel] = useState3(null);
14615
14645
  useEffect5(() => {
14616
14646
  if (!gltfUrl) return;
@@ -14653,10 +14683,47 @@ function GltfModel({
14653
14683
  rootObject.remove(model);
14654
14684
  };
14655
14685
  }, [rootObject, model]);
14686
+ useEffect5(() => {
14687
+ if (!model || !renderer) return;
14688
+ const environmentMap = getDefaultEnvironmentMap(renderer);
14689
+ if (!environmentMap) return;
14690
+ const previousMaterialState = [];
14691
+ const applyEnvironmentToMaterial = (material) => {
14692
+ if (!(material instanceof THREE4.MeshStandardMaterial)) return;
14693
+ previousMaterialState.push({
14694
+ material,
14695
+ envMap: material.envMap ?? null,
14696
+ envMapIntensity: material.envMapIntensity ?? 1
14697
+ });
14698
+ if (!material.envMap) {
14699
+ material.envMap = environmentMap;
14700
+ }
14701
+ if (typeof material.envMapIntensity !== "number" || material.envMapIntensity < DEFAULT_ENV_MAP_INTENSITY) {
14702
+ material.envMapIntensity = DEFAULT_ENV_MAP_INTENSITY;
14703
+ }
14704
+ material.needsUpdate = true;
14705
+ };
14706
+ model.traverse((child) => {
14707
+ if (!(child instanceof THREE4.Mesh)) return;
14708
+ const material = child.material;
14709
+ if (Array.isArray(material)) {
14710
+ material.forEach(applyEnvironmentToMaterial);
14711
+ } else if (material) {
14712
+ applyEnvironmentToMaterial(material);
14713
+ }
14714
+ });
14715
+ return () => {
14716
+ previousMaterialState.forEach(({ material, envMap, envMapIntensity }) => {
14717
+ material.envMap = envMap;
14718
+ material.envMapIntensity = envMapIntensity;
14719
+ material.needsUpdate = true;
14720
+ });
14721
+ };
14722
+ }, [model, renderer]);
14656
14723
  useEffect5(() => {
14657
14724
  if (!model) return;
14658
14725
  model.traverse((child) => {
14659
- if (child instanceof THREE3.Mesh && child.material instanceof THREE3.MeshStandardMaterial) {
14726
+ if (child instanceof THREE4.Mesh && child.material instanceof THREE4.MeshStandardMaterial) {
14660
14727
  if (isHovered) {
14661
14728
  child.material.emissive.setHex(255);
14662
14729
  child.material.emissiveIntensity = 0.2;
@@ -23720,7 +23787,7 @@ var m2host = (raw_params) => {
23720
23787
  }
23721
23788
  const centerX = (minX + maxX) / 2;
23722
23789
  const centerY = (minY + maxY) / 2;
23723
- const translate5 = (el) => {
23790
+ const translate6 = (el) => {
23724
23791
  if (typeof el.x === "number") el.x -= centerX;
23725
23792
  if (typeof el.y === "number") el.y -= centerY;
23726
23793
  if (el.center) {
@@ -23734,9 +23801,9 @@ var m2host = (raw_params) => {
23734
23801
  }));
23735
23802
  }
23736
23803
  };
23737
- for (const pad2 of pads) translate5(pad2);
23738
- translate5(cutout);
23739
- translate5(pin1Marker);
23804
+ for (const pad2 of pads) translate6(pad2);
23805
+ translate6(cutout);
23806
+ translate6(pin1Marker);
23740
23807
  return {
23741
23808
  circuitJson: [
23742
23809
  ...pads,
@@ -25695,7 +25762,7 @@ function getJscadModelForFootprint(footprint) {
25695
25762
  }
25696
25763
 
25697
25764
  // src/three-components/JscadModel.tsx
25698
- import * as THREE4 from "three";
25765
+ import * as THREE5 from "three";
25699
25766
  import { useMemo as useMemo4, useEffect as useEffect6 } from "react";
25700
25767
  import { jsx as jsx6 } from "react/jsx-runtime";
25701
25768
  var JscadModel = ({
@@ -25714,16 +25781,16 @@ var JscadModel = ({
25714
25781
  return { threeGeom: null, material: null };
25715
25782
  }
25716
25783
  const threeGeom2 = convertCSGToThreeGeom(jscadObject);
25717
- const material2 = new THREE4.MeshStandardMaterial({
25784
+ const material2 = new THREE5.MeshStandardMaterial({
25718
25785
  vertexColors: true,
25719
- side: THREE4.DoubleSide
25786
+ side: THREE5.DoubleSide
25720
25787
  // Ensure both sides are visible
25721
25788
  });
25722
25789
  return { threeGeom: threeGeom2, material: material2 };
25723
25790
  }, [jscadPlan]);
25724
25791
  const mesh = useMemo4(() => {
25725
25792
  if (!threeGeom) return null;
25726
- return new THREE4.Mesh(threeGeom, material);
25793
+ return new THREE5.Mesh(threeGeom, material);
25727
25794
  }, [threeGeom, material]);
25728
25795
  useEffect6(() => {
25729
25796
  if (!mesh || !rootObject) return;
@@ -25750,7 +25817,7 @@ var JscadModel = ({
25750
25817
  useMemo4(() => {
25751
25818
  if (!material) return;
25752
25819
  if (isHovered) {
25753
- const color = new THREE4.Color(material.color.getHex());
25820
+ const color = new THREE5.Color(material.color.getHex());
25754
25821
  material.emissive.copy(color);
25755
25822
  material.emissive.setRGB(0, 0, 1);
25756
25823
  material.emissiveIntensity = 0.2;
@@ -25772,7 +25839,7 @@ var JscadModel = ({
25772
25839
 
25773
25840
  // src/three-components/FootprinterModel.tsx
25774
25841
  import { useMemo as useMemo5, useEffect as useEffect7 } from "react";
25775
- import * as THREE5 from "three";
25842
+ import * as THREE6 from "three";
25776
25843
  import { jsx as jsx7 } from "react/jsx-runtime";
25777
25844
  var FootprinterModel = ({
25778
25845
  positionOffset,
@@ -25787,21 +25854,21 @@ var FootprinterModel = ({
25787
25854
  const group = useMemo5(() => {
25788
25855
  if (!footprint) return null;
25789
25856
  const { geometries: geometries2 } = getJscadModelForFootprint(footprint);
25790
- const group2 = new THREE5.Group();
25857
+ const group2 = new THREE6.Group();
25791
25858
  for (const geomInfo of geometries2.flat(Infinity)) {
25792
25859
  const geom = geomInfo.geom;
25793
25860
  if (!geom || !geom.polygons && !geom.sides) {
25794
25861
  continue;
25795
25862
  }
25796
- const color = new THREE5.Color(geomInfo.color);
25863
+ const color = new THREE6.Color(geomInfo.color);
25797
25864
  color.convertLinearToSRGB();
25798
25865
  const geomWithColor = { ...geom, color: [color.r, color.g, color.b] };
25799
25866
  const threeGeom = convertCSGToThreeGeom(geomWithColor);
25800
- const material = new THREE5.MeshStandardMaterial({
25867
+ const material = new THREE6.MeshStandardMaterial({
25801
25868
  vertexColors: true,
25802
- side: THREE5.DoubleSide
25869
+ side: THREE6.DoubleSide
25803
25870
  });
25804
- const mesh = new THREE5.Mesh(threeGeom, material);
25871
+ const mesh = new THREE6.Mesh(threeGeom, material);
25805
25872
  group2.add(mesh);
25806
25873
  }
25807
25874
  return group2;
@@ -25831,7 +25898,7 @@ var FootprinterModel = ({
25831
25898
  useEffect7(() => {
25832
25899
  if (!group) return;
25833
25900
  group.traverse((child) => {
25834
- if (child instanceof THREE5.Mesh && child.material instanceof THREE5.MeshStandardMaterial) {
25901
+ if (child instanceof THREE6.Mesh && child.material instanceof THREE6.MeshStandardMaterial) {
25835
25902
  if (isHovered) {
25836
25903
  child.material.emissive.setHex(255);
25837
25904
  child.material.emissiveIntensity = 0.2;
@@ -25859,7 +25926,7 @@ var tuple = (...args) => args;
25859
25926
  // src/react-three/Html.tsx
25860
25927
  import { useRef as useRef2, useEffect as useEffect8, useState as useState4 } from "react";
25861
25928
  import ReactDOM from "react-dom";
25862
- import * as THREE6 from "three";
25929
+ import * as THREE7 from "three";
25863
25930
  var Html = ({ children, position, style }) => {
25864
25931
  const { camera, renderer } = useThree();
25865
25932
  const el = useRef2(document.createElement("div"));
@@ -25880,7 +25947,7 @@ var Html = ({ children, position, style }) => {
25880
25947
  }, [renderer, children]);
25881
25948
  useFrame(() => {
25882
25949
  if (!camera || !el.current || !renderer) return;
25883
- const vector = new THREE6.Vector3(...position);
25950
+ const vector = new THREE7.Vector3(...position);
25884
25951
  vector.project(camera);
25885
25952
  const rect = renderer.domElement.getBoundingClientRect();
25886
25953
  const x = Math.round((vector.x + 1) / 2 * rect.width);
@@ -26028,12 +26095,12 @@ import {
26028
26095
  useMemo as useMemo13,
26029
26096
  useState as useState7
26030
26097
  } from "react";
26031
- import * as THREE11 from "three";
26098
+ import * as THREE13 from "three";
26032
26099
 
26033
26100
  // package.json
26034
26101
  var package_default = {
26035
26102
  name: "@tscircuit/3d-viewer",
26036
- version: "0.0.403",
26103
+ version: "0.0.405",
26037
26104
  main: "./dist/index.js",
26038
26105
  module: "./dist/index.js",
26039
26106
  type: "module",
@@ -26109,7 +26176,7 @@ var package_default = {
26109
26176
 
26110
26177
  // src/three-components/cube-with-labeled-sides.tsx
26111
26178
  import { useEffect as useEffect10, useMemo as useMemo8 } from "react";
26112
- import * as THREE7 from "three";
26179
+ import * as THREE8 from "three";
26113
26180
 
26114
26181
  // src/react-three/Text.tsx
26115
26182
  import { useEffect as useEffect9, useMemo as useMemo7 } from "react";
@@ -26167,13 +26234,13 @@ var Text = ({
26167
26234
  // src/three-components/cube-with-labeled-sides.tsx
26168
26235
  import { Fragment as Fragment4, jsx as jsx9, jsxs as jsxs3 } from "react/jsx-runtime";
26169
26236
  if (typeof window !== "undefined") {
26170
- window.TSCI_MAIN_CAMERA_ROTATION = new THREE7.Euler(0, 0, 0);
26237
+ window.TSCI_MAIN_CAMERA_ROTATION = new THREE8.Euler(0, 0, 0);
26171
26238
  }
26172
26239
  function computePointInFront(rotationVector, distance2) {
26173
- const quaternion = new THREE7.Quaternion().setFromEuler(
26174
- new THREE7.Euler(rotationVector.x, rotationVector.y, rotationVector.z)
26240
+ const quaternion = new THREE8.Quaternion().setFromEuler(
26241
+ new THREE8.Euler(rotationVector.x, rotationVector.y, rotationVector.z)
26175
26242
  );
26176
- const forwardVector = new THREE7.Vector3(0, 0, 1);
26243
+ const forwardVector = new THREE8.Vector3(0, 0, 1);
26177
26244
  forwardVector.applyQuaternion(quaternion);
26178
26245
  const result = forwardVector.multiplyScalar(distance2);
26179
26246
  return result;
@@ -26182,7 +26249,7 @@ var CubeWithLabeledSides = ({}) => {
26182
26249
  const { camera, scene } = useThree();
26183
26250
  useEffect10(() => {
26184
26251
  if (!scene) return;
26185
- const ambientLight = new THREE7.AmbientLight(16777215, Math.PI / 2);
26252
+ const ambientLight = new THREE8.AmbientLight(16777215, Math.PI / 2);
26186
26253
  scene.add(ambientLight);
26187
26254
  return () => {
26188
26255
  scene.remove(ambientLight);
@@ -26196,16 +26263,16 @@ var CubeWithLabeledSides = ({}) => {
26196
26263
  camera.lookAt(0, 0, 0);
26197
26264
  });
26198
26265
  const group = useMemo8(() => {
26199
- const g = new THREE7.Group();
26266
+ const g = new THREE8.Group();
26200
26267
  g.rotation.fromArray([Math.PI / 2, 0, 0]);
26201
- const box = new THREE7.Mesh(
26202
- new THREE7.BoxGeometry(1, 1, 1),
26203
- new THREE7.MeshStandardMaterial({ color: "white" })
26268
+ const box = new THREE8.Mesh(
26269
+ new THREE8.BoxGeometry(1, 1, 1),
26270
+ new THREE8.MeshStandardMaterial({ color: "white" })
26204
26271
  );
26205
26272
  g.add(box);
26206
- const edges = new THREE7.LineSegments(
26207
- new THREE7.EdgesGeometry(new THREE7.BoxGeometry(1, 1, 1)),
26208
- new THREE7.LineBasicMaterial({ color: 0, linewidth: 2 })
26273
+ const edges = new THREE8.LineSegments(
26274
+ new THREE8.EdgesGeometry(new THREE8.BoxGeometry(1, 1, 1)),
26275
+ new THREE8.LineBasicMaterial({ color: 0, linewidth: 2 })
26209
26276
  );
26210
26277
  g.add(edges);
26211
26278
  return g;
@@ -26296,13 +26363,21 @@ import {
26296
26363
  useImperativeHandle,
26297
26364
  useMemo as useMemo9
26298
26365
  } from "react";
26299
- import * as THREE8 from "three";
26366
+ import * as THREE10 from "three";
26300
26367
 
26301
26368
  // src/react-three/remove-existing-canvases.ts
26302
26369
  function removeExistingCanvases(container) {
26303
26370
  container.querySelectorAll("canvas").forEach((existingCanvas) => existingCanvas.remove());
26304
26371
  }
26305
26372
 
26373
+ // src/react-three/configure-renderer.ts
26374
+ import * as THREE9 from "three";
26375
+ var configureRenderer = (renderer) => {
26376
+ renderer.outputColorSpace = THREE9.SRGBColorSpace;
26377
+ renderer.toneMapping = THREE9.ACESFilmicToneMapping;
26378
+ renderer.toneMappingExposure = 1;
26379
+ };
26380
+
26306
26381
  // src/react-three/Canvas.tsx
26307
26382
  import { jsx as jsx10 } from "react/jsx-runtime";
26308
26383
  var Canvas = forwardRef(
@@ -26328,23 +26403,24 @@ var Canvas = forwardRef(
26328
26403
  },
26329
26404
  []
26330
26405
  );
26331
- const scene = useMemo9(() => new THREE8.Scene(), []);
26406
+ const scene = useMemo9(() => new THREE10.Scene(), []);
26332
26407
  if (sceneProps?.up) {
26333
26408
  scene.up.set(sceneProps.up.x, sceneProps.up.y, sceneProps.up.z);
26334
26409
  }
26335
- const rootObject = useRef4(new THREE8.Object3D());
26410
+ const rootObject = useRef4(new THREE10.Object3D());
26336
26411
  useImperativeHandle(ref, () => rootObject.current);
26337
26412
  useEffect11(() => {
26338
26413
  if (!mountRef.current) return;
26339
26414
  removeExistingCanvases(mountRef.current);
26340
- const renderer = new THREE8.WebGLRenderer({ antialias: true, alpha: true });
26415
+ const renderer = new THREE10.WebGLRenderer({ antialias: true, alpha: true });
26416
+ configureRenderer(renderer);
26341
26417
  renderer.setSize(
26342
26418
  mountRef.current.clientWidth,
26343
26419
  mountRef.current.clientHeight
26344
26420
  );
26345
26421
  renderer.setPixelRatio(window.devicePixelRatio);
26346
26422
  mountRef.current.appendChild(renderer.domElement);
26347
- const camera = new THREE8.PerspectiveCamera(
26423
+ const camera = new THREE10.PerspectiveCamera(
26348
26424
  75,
26349
26425
  mountRef.current.clientWidth / mountRef.current.clientHeight,
26350
26426
  0.1,
@@ -26372,7 +26448,7 @@ var Canvas = forwardRef(
26372
26448
  removeFrameListener
26373
26449
  });
26374
26450
  let animationFrameId;
26375
- const clock = new THREE8.Clock();
26451
+ const clock = new THREE10.Clock();
26376
26452
  const animate = () => {
26377
26453
  const time2 = clock.getElapsedTime();
26378
26454
  const delta = clock.getDelta();
@@ -26474,7 +26550,7 @@ var OrbitControls = ({
26474
26550
 
26475
26551
  // src/react-three/Grid.tsx
26476
26552
  import { useEffect as useEffect13, useMemo as useMemo11 } from "react";
26477
- import * as THREE9 from "three";
26553
+ import * as THREE11 from "three";
26478
26554
  var vertexShader = `
26479
26555
  varying vec3 worldPosition;
26480
26556
  void main() {
@@ -26520,24 +26596,24 @@ var Grid = ({
26520
26596
  const { scene, camera } = useThree();
26521
26597
  const size2 = 1e3;
26522
26598
  const gridMesh = useMemo11(() => {
26523
- const geometry = new THREE9.PlaneGeometry(size2, size2);
26599
+ const geometry = new THREE11.PlaneGeometry(size2, size2);
26524
26600
  geometry.rotateX(-Math.PI / 2);
26525
- const material = new THREE9.ShaderMaterial({
26601
+ const material = new THREE11.ShaderMaterial({
26526
26602
  vertexShader,
26527
26603
  fragmentShader,
26528
26604
  uniforms: {
26529
26605
  cellSize: { value: cellSize },
26530
26606
  sectionSize: { value: sectionSize },
26531
- gridColor: { value: new THREE9.Color(15658734) },
26532
- sectionColor: { value: new THREE9.Color(13421823) },
26607
+ gridColor: { value: new THREE11.Color(15658734) },
26608
+ sectionColor: { value: new THREE11.Color(13421823) },
26533
26609
  fadeDistance: { value: 100 },
26534
26610
  // Fade out based on sectionSize
26535
26611
  fadeStrength: { value: 1.5 }
26536
26612
  },
26537
26613
  transparent: true,
26538
- side: THREE9.DoubleSide
26614
+ side: THREE11.DoubleSide
26539
26615
  });
26540
- const mesh = new THREE9.Mesh(geometry, material);
26616
+ const mesh = new THREE11.Mesh(geometry, material);
26541
26617
  if (rotation2) {
26542
26618
  mesh.rotation.fromArray(rotation2);
26543
26619
  }
@@ -26566,15 +26642,15 @@ var Grid = ({
26566
26642
 
26567
26643
  // src/react-three/Lights.tsx
26568
26644
  import { useEffect as useEffect14, useMemo as useMemo12 } from "react";
26569
- import * as THREE10 from "three";
26645
+ import * as THREE12 from "three";
26570
26646
  var Lights = () => {
26571
26647
  const { scene } = useThree();
26572
26648
  const ambientLight = useMemo12(
26573
- () => new THREE10.AmbientLight(16777215, Math.PI / 2),
26649
+ () => new THREE12.AmbientLight(16777215, Math.PI / 2),
26574
26650
  []
26575
26651
  );
26576
26652
  const pointLight = useMemo12(() => {
26577
- const light = new THREE10.PointLight(16777215, Math.PI / 4);
26653
+ const light = new THREE12.PointLight(16777215, Math.PI / 4);
26578
26654
  light.position.set(-10, -10, 10);
26579
26655
  light.decay = 0;
26580
26656
  return light;
@@ -26655,7 +26731,7 @@ var CadViewerContainer = forwardRef2(
26655
26731
  Canvas,
26656
26732
  {
26657
26733
  ref,
26658
- scene: { up: new THREE11.Vector3(0, 0, 1) },
26734
+ scene: { up: new THREE13.Vector3(0, 0, 1) },
26659
26735
  camera: { up: [0, 0, 1], position: initialCameraPosition },
26660
26736
  children: [
26661
26737
  /* @__PURE__ */ jsx11(RotationTracker, {}),
@@ -26883,7 +26959,7 @@ var createBoardGeomFromCircuitJson = (circuitJson, opts = {}) => {
26883
26959
  };
26884
26960
 
26885
26961
  // src/BoardGeomBuilder.ts
26886
- var import_transforms3 = __toESM(require_transforms(), 1);
26962
+ var import_transforms4 = __toESM(require_transforms(), 1);
26887
26963
  var import_primitives6 = __toESM(require_primitives(), 1);
26888
26964
  var import_colors4 = __toESM(require_colors(), 1);
26889
26965
  var import_booleans3 = __toESM(require_booleans(), 1);
@@ -26893,7 +26969,49 @@ import { su as su3 } from "@tscircuit/circuit-json-util";
26893
26969
  var import_primitives3 = __toESM(require_primitives(), 1);
26894
26970
  var import_colors2 = __toESM(require_colors(), 1);
26895
26971
  var import_booleans = __toESM(require_booleans(), 1);
26972
+ var import_extrusions2 = __toESM(require_extrusions(), 1);
26973
+ var import_transforms2 = __toESM(require_transforms(), 1);
26974
+
26975
+ // src/utils/rect-border-radius.ts
26976
+ function clampRectBorderRadius(width10, height10, rawRadius) {
26977
+ if (typeof rawRadius !== "number" || !Number.isFinite(rawRadius)) {
26978
+ return 0;
26979
+ }
26980
+ if (rawRadius <= 0) {
26981
+ return 0;
26982
+ }
26983
+ const halfWidth = width10 / 2;
26984
+ const halfHeight = height10 / 2;
26985
+ return Math.max(0, Math.min(rawRadius, halfWidth, halfHeight));
26986
+ }
26987
+ function extractRectBorderRadius(source) {
26988
+ if (!source || typeof source !== "object") return void 0;
26989
+ return source.rect_pad_border_radius ?? source.rectPadBorderRadius ?? source.rect_border_radius ?? source.rectBorderRadius ?? void 0;
26990
+ }
26991
+
26992
+ // src/geoms/plated-hole.ts
26896
26993
  var platedHoleLipHeight = 0.05;
26994
+ var RECT_PAD_SEGMENTS = 64;
26995
+ var createRectPadGeom = ({
26996
+ width: width10,
26997
+ height: height10,
26998
+ thickness,
26999
+ center,
27000
+ borderRadius
27001
+ }) => {
27002
+ const clampedRadius = clampRectBorderRadius(width10, height10, borderRadius);
27003
+ if (clampedRadius <= 0) {
27004
+ return (0, import_primitives3.cuboid)({ center, size: [width10, height10, thickness] });
27005
+ }
27006
+ const rect2d = (0, import_primitives3.roundedRectangle)({
27007
+ size: [width10, height10],
27008
+ roundRadius: clampedRadius,
27009
+ segments: RECT_PAD_SEGMENTS
27010
+ });
27011
+ const extruded = (0, import_extrusions2.extrudeLinear)({ height: thickness }, rect2d);
27012
+ const offsetZ = center[2] - thickness / 2;
27013
+ return (0, import_transforms2.translate)([center[0], center[1], offsetZ], extruded);
27014
+ };
26897
27015
  var platedHole = (plated_hole, ctx) => {
26898
27016
  if (!plated_hole.shape) plated_hole.shape = "circle";
26899
27017
  if (plated_hole.shape === "circle") {
@@ -26936,19 +27054,26 @@ var platedHole = (plated_hole, ctx) => {
26936
27054
  if (plated_hole.shape === "circular_hole_with_rect_pad") {
26937
27055
  const padWidth = plated_hole.rect_pad_width || plated_hole.hole_diameter;
26938
27056
  const padHeight = plated_hole.rect_pad_height || plated_hole.hole_diameter;
27057
+ const rectBorderRadius = extractRectBorderRadius(plated_hole);
26939
27058
  return (0, import_colors2.colorize)(
26940
27059
  colors.copper,
26941
27060
  (0, import_booleans.subtract)(
26942
27061
  (0, import_booleans.union)(
26943
27062
  // Top rectangular pad
26944
- (0, import_primitives3.cuboid)({
27063
+ createRectPadGeom({
27064
+ width: padWidth,
27065
+ height: padHeight,
27066
+ thickness: platedHoleLipHeight,
26945
27067
  center: [plated_hole.x, plated_hole.y, 1.2 / 2],
26946
- size: [padWidth, padHeight, platedHoleLipHeight]
27068
+ borderRadius: rectBorderRadius
26947
27069
  }),
26948
27070
  // Bottom rectangular pad
26949
- (0, import_primitives3.cuboid)({
27071
+ createRectPadGeom({
27072
+ width: padWidth,
27073
+ height: padHeight,
27074
+ thickness: platedHoleLipHeight,
26950
27075
  center: [plated_hole.x, plated_hole.y, -1.2 / 2],
26951
- size: [padWidth, padHeight, platedHoleLipHeight]
27076
+ borderRadius: rectBorderRadius
26952
27077
  }),
26953
27078
  // Plated barrel around hole
26954
27079
  (0, import_primitives3.cylinder)({
@@ -27055,6 +27180,7 @@ var platedHole = (plated_hole, ctx) => {
27055
27180
  const rectLength = Math.abs(holeWidth - holeHeight);
27056
27181
  const padWidth = plated_hole.rect_pad_width || holeWidth + 0.2;
27057
27182
  const padHeight = plated_hole.rect_pad_height || holeHeight + 0.2;
27183
+ const rectBorderRadius = extractRectBorderRadius(plated_hole);
27058
27184
  const mainRect = (0, import_primitives3.cuboid)({
27059
27185
  center: [plated_hole.x, plated_hole.y, 0],
27060
27186
  size: shouldRotate ? [holeHeight, rectLength, 1.2] : [rectLength, holeHeight, 1.2]
@@ -27069,13 +27195,19 @@ var platedHole = (plated_hole, ctx) => {
27069
27195
  radius: holeRadius,
27070
27196
  height: 1.2
27071
27197
  });
27072
- const topPad = (0, import_primitives3.cuboid)({
27198
+ const topPad = createRectPadGeom({
27199
+ width: padWidth,
27200
+ height: padHeight,
27201
+ thickness: platedHoleLipHeight,
27073
27202
  center: [plated_hole.x, plated_hole.y, 1.2 / 2],
27074
- size: [padWidth, padHeight, platedHoleLipHeight]
27203
+ borderRadius: rectBorderRadius
27075
27204
  });
27076
- const bottomPad = (0, import_primitives3.cuboid)({
27205
+ const bottomPad = createRectPadGeom({
27206
+ width: padWidth,
27207
+ height: padHeight,
27208
+ thickness: platedHoleLipHeight,
27077
27209
  center: [plated_hole.x, plated_hole.y, -1.2 / 2],
27078
- size: [padWidth, padHeight, platedHoleLipHeight]
27210
+ borderRadius: rectBorderRadius
27079
27211
  });
27080
27212
  const holeCut = (0, import_booleans.union)(
27081
27213
  (0, import_primitives3.cuboid)({
@@ -27103,7 +27235,7 @@ var platedHole = (plated_hole, ctx) => {
27103
27235
  };
27104
27236
 
27105
27237
  // src/BoardGeomBuilder.ts
27106
- var import_extrusions3 = __toESM(require_extrusions(), 1);
27238
+ var import_extrusions4 = __toESM(require_extrusions(), 1);
27107
27239
  var import_expansions2 = __toESM(require_expansions(), 1);
27108
27240
 
27109
27241
  // src/geoms/create-geoms-for-silkscreen-text.ts
@@ -27126,7 +27258,7 @@ function isUndefined(val) {
27126
27258
  }
27127
27259
 
27128
27260
  // node_modules/transformation-matrix/src/translate.js
27129
- function translate2(tx, ty = 0) {
27261
+ function translate3(tx, ty = 0) {
27130
27262
  return {
27131
27263
  a: 1,
27132
27264
  c: 0,
@@ -27185,9 +27317,9 @@ function rotate(angle, cx, cy) {
27185
27317
  return rotationMatrix;
27186
27318
  }
27187
27319
  return transform([
27188
- translate2(cx, cy),
27320
+ translate3(cx, cy),
27189
27321
  rotationMatrix,
27190
- translate2(-cx, -cy)
27322
+ translate3(-cx, -cy)
27191
27323
  ]);
27192
27324
  }
27193
27325
 
@@ -27375,19 +27507,19 @@ function createSilkscreenTextGeoms(silkscreenText) {
27375
27507
  const transforms2 = [];
27376
27508
  if (silkscreenText.layer === "bottom") {
27377
27509
  transforms2.push(
27378
- translate2(centerX, centerY),
27510
+ translate3(centerX, centerY),
27379
27511
  { a: -1, b: 0, c: 0, d: 1, e: 0, f: 0 },
27380
27512
  // horizontal flip matrix
27381
- translate2(-centerX, -centerY)
27513
+ translate3(-centerX, -centerY)
27382
27514
  );
27383
27515
  rotationDegrees = -rotationDegrees;
27384
27516
  }
27385
27517
  if (rotationDegrees) {
27386
27518
  const rad = rotationDegrees * Math.PI / 180;
27387
27519
  transforms2.push(
27388
- translate2(centerX, centerY),
27520
+ translate3(centerX, centerY),
27389
27521
  rotate(rad),
27390
- translate2(-centerX, -centerY)
27522
+ translate3(-centerX, -centerY)
27391
27523
  );
27392
27524
  }
27393
27525
  let transformedOutlines = textOutlines;
@@ -27410,8 +27542,8 @@ function createSilkscreenTextGeoms(silkscreenText) {
27410
27542
  // src/geoms/create-geoms-for-silkscreen-path.ts
27411
27543
  var import_primitives4 = __toESM(require_primitives(), 1);
27412
27544
  var import_expansions = __toESM(require_expansions(), 1);
27413
- var import_extrusions2 = __toESM(require_extrusions(), 1);
27414
- var import_transforms2 = __toESM(require_transforms(), 1);
27545
+ var import_extrusions3 = __toESM(require_extrusions(), 1);
27546
+ var import_transforms3 = __toESM(require_transforms(), 1);
27415
27547
  var import_colors3 = __toESM(require_colors(), 1);
27416
27548
  function createSilkscreenPathGeom(sp, ctx) {
27417
27549
  if (sp.route.length < 2) return void 0;
@@ -27424,9 +27556,9 @@ function createSilkscreenPathGeom(sp, ctx) {
27424
27556
  );
27425
27557
  const layerSign = sp.layer === "bottom" ? -1 : 1;
27426
27558
  const zPos = layerSign * ctx.pcbThickness / 2 + layerSign * M * 1.5;
27427
- let pathGeom = (0, import_transforms2.translate)(
27559
+ let pathGeom = (0, import_transforms3.translate)(
27428
27560
  [0, 0, zPos],
27429
- (0, import_extrusions2.extrudeLinear)({ height: 0.012 }, expandedPath)
27561
+ (0, import_extrusions3.extrudeLinear)({ height: 0.012 }, expandedPath)
27430
27562
  // Standard silkscreen thickness
27431
27563
  );
27432
27564
  pathGeom = (0, import_colors3.colorize)([1, 1, 1], pathGeom);
@@ -27519,6 +27651,20 @@ function createGeom2FromBRep(brep, arcSegments = 16) {
27519
27651
  }
27520
27652
 
27521
27653
  // src/BoardGeomBuilder.ts
27654
+ var PAD_ROUNDED_SEGMENTS = 64;
27655
+ var createCenteredRectPadGeom = (width10, height10, thickness, rectBorderRadius) => {
27656
+ const clampedRadius = clampRectBorderRadius(width10, height10, rectBorderRadius);
27657
+ if (clampedRadius <= 0) {
27658
+ return (0, import_primitives6.cuboid)({ center: [0, 0, 0], size: [width10, height10, thickness] });
27659
+ }
27660
+ const rect2d = (0, import_primitives6.roundedRectangle)({
27661
+ size: [width10, height10],
27662
+ roundRadius: clampedRadius,
27663
+ segments: PAD_ROUNDED_SEGMENTS
27664
+ });
27665
+ const extruded = (0, import_extrusions4.extrudeLinear)({ height: thickness }, rect2d);
27666
+ return (0, import_transforms4.translate)([0, 0, -thickness / 2], extruded);
27667
+ };
27522
27668
  var buildStateOrder = [
27523
27669
  "initializing",
27524
27670
  "processing_pads",
@@ -27715,7 +27861,7 @@ var BoardGeomBuilder = class {
27715
27861
  });
27716
27862
  if (cutout.rotation) {
27717
27863
  const rotationRadians = cutout.rotation * Math.PI / 180;
27718
- cutoutGeom = (0, import_transforms3.rotateZ)(rotationRadians, cutoutGeom);
27864
+ cutoutGeom = (0, import_transforms4.rotateZ)(rotationRadians, cutoutGeom);
27719
27865
  }
27720
27866
  break;
27721
27867
  case "circle":
@@ -27737,8 +27883,8 @@ var BoardGeomBuilder = class {
27737
27883
  pointsVec2 = pointsVec2.reverse();
27738
27884
  }
27739
27885
  const polygon2d = (0, import_primitives6.polygon)({ points: pointsVec2 });
27740
- cutoutGeom = (0, import_extrusions3.extrudeLinear)({ height: cutoutHeight }, polygon2d);
27741
- cutoutGeom = (0, import_transforms3.translate)([0, 0, -cutoutHeight / 2], cutoutGeom);
27886
+ cutoutGeom = (0, import_extrusions4.extrudeLinear)({ height: cutoutHeight }, polygon2d);
27887
+ cutoutGeom = (0, import_transforms4.translate)([0, 0, -cutoutHeight / 2], cutoutGeom);
27742
27888
  break;
27743
27889
  }
27744
27890
  if (cutoutGeom) {
@@ -27757,15 +27903,15 @@ var BoardGeomBuilder = class {
27757
27903
  });
27758
27904
  if ("rotation" in pour && pour.rotation) {
27759
27905
  const rotationRadians = pour.rotation * Math.PI / 180;
27760
- baseGeom = (0, import_transforms3.rotateZ)(rotationRadians, baseGeom);
27906
+ baseGeom = (0, import_transforms4.rotateZ)(rotationRadians, baseGeom);
27761
27907
  }
27762
- pourGeom = (0, import_transforms3.translate)([pour.center.x, pour.center.y, zPos], baseGeom);
27908
+ pourGeom = (0, import_transforms4.translate)([pour.center.x, pour.center.y, zPos], baseGeom);
27763
27909
  } else if (pour.shape === "brep") {
27764
27910
  const brepShape = pour.brep_shape;
27765
27911
  if (brepShape && brepShape.outer_ring) {
27766
27912
  const pourGeom2 = createGeom2FromBRep(brepShape);
27767
- pourGeom = (0, import_extrusions3.extrudeLinear)({ height: M }, pourGeom2);
27768
- pourGeom = (0, import_transforms3.translate)([0, 0, zPos], pourGeom);
27913
+ pourGeom = (0, import_extrusions4.extrudeLinear)({ height: M }, pourGeom2);
27914
+ pourGeom = (0, import_transforms4.translate)([0, 0, zPos], pourGeom);
27769
27915
  }
27770
27916
  } else if (pour.shape === "polygon") {
27771
27917
  let pointsVec2 = pour.points.map((p) => [p.x, p.y]);
@@ -27779,8 +27925,8 @@ var BoardGeomBuilder = class {
27779
27925
  pointsVec2 = pointsVec2.reverse();
27780
27926
  }
27781
27927
  const polygon2d = (0, import_primitives6.polygon)({ points: pointsVec2 });
27782
- pourGeom = (0, import_extrusions3.extrudeLinear)({ height: M }, polygon2d);
27783
- pourGeom = (0, import_transforms3.translate)([0, 0, zPos], pourGeom);
27928
+ pourGeom = (0, import_extrusions4.extrudeLinear)({ height: M }, polygon2d);
27929
+ pourGeom = (0, import_transforms4.translate)([0, 0, zPos], pourGeom);
27784
27930
  }
27785
27931
  if (pourGeom) {
27786
27932
  const coloredPourGeom = (0, import_colors4.colorize)(colors.copper, pourGeom);
@@ -27856,24 +28002,27 @@ var BoardGeomBuilder = class {
27856
28002
  processPad(pad2) {
27857
28003
  const layerSign = pad2.layer === "bottom" ? -1 : 1;
27858
28004
  const zPos = layerSign * this.ctx.pcbThickness / 2 + layerSign * M * 2;
28005
+ const rectBorderRadius = extractRectBorderRadius(pad2);
27859
28006
  if (pad2.shape === "rect") {
27860
- const padGeom = (0, import_colors4.colorize)(
27861
- colors.copper,
27862
- (0, import_primitives6.cuboid)({
27863
- center: [pad2.x, pad2.y, zPos],
27864
- size: [pad2.width, pad2.height, M]
27865
- })
28007
+ const basePadGeom = createCenteredRectPadGeom(
28008
+ pad2.width,
28009
+ pad2.height,
28010
+ M,
28011
+ rectBorderRadius
27866
28012
  );
28013
+ const positionedPadGeom = (0, import_transforms4.translate)([pad2.x, pad2.y, zPos], basePadGeom);
28014
+ const padGeom = (0, import_colors4.colorize)(colors.copper, positionedPadGeom);
27867
28015
  this.padGeoms.push(padGeom);
27868
28016
  } else if (pad2.shape === "rotated_rect") {
27869
- let basePadGeom = (0, import_primitives6.cuboid)({
27870
- // Create at origin for rotation, then translate
27871
- center: [0, 0, 0],
27872
- size: [pad2.width, pad2.height, M]
27873
- });
28017
+ let basePadGeom = createCenteredRectPadGeom(
28018
+ pad2.width,
28019
+ pad2.height,
28020
+ M,
28021
+ rectBorderRadius
28022
+ );
27874
28023
  const rotationRadians = pad2.ccw_rotation * Math.PI / 180;
27875
- basePadGeom = (0, import_transforms3.rotateZ)(rotationRadians, basePadGeom);
27876
- const positionedPadGeom = (0, import_transforms3.translate)([pad2.x, pad2.y, zPos], basePadGeom);
28024
+ basePadGeom = (0, import_transforms4.rotateZ)(rotationRadians, basePadGeom);
28025
+ const positionedPadGeom = (0, import_transforms4.translate)([pad2.x, pad2.y, zPos], basePadGeom);
27877
28026
  const padGeom = (0, import_colors4.colorize)(colors.copper, positionedPadGeom);
27878
28027
  this.padGeoms.push(padGeom);
27879
28028
  } else if (pad2.shape === "circle") {
@@ -27903,9 +28052,9 @@ var BoardGeomBuilder = class {
27903
28052
  { delta: currentWidth / 2, corners: "round" },
27904
28053
  linePath
27905
28054
  );
27906
- let traceGeom = (0, import_transforms3.translate)(
28055
+ let traceGeom = (0, import_transforms4.translate)(
27907
28056
  [0, 0, zPos],
27908
- (0, import_extrusions3.extrudeLinear)({ height: M }, expandedPath)
28057
+ (0, import_extrusions4.extrudeLinear)({ height: M }, expandedPath)
27909
28058
  );
27910
28059
  const startPointCoords = currentSegmentPoints[0];
27911
28060
  const endPointCoords = currentSegmentPoints[currentSegmentPoints.length - 1];
@@ -28010,16 +28159,16 @@ var BoardGeomBuilder = class {
28010
28159
  );
28011
28160
  let textGeom;
28012
28161
  if (st.layer === "bottom") {
28013
- textGeom = (0, import_transforms3.translate)(
28162
+ textGeom = (0, import_transforms4.translate)(
28014
28163
  [0, 0, -this.ctx.pcbThickness / 2 - M],
28015
28164
  // Position above board
28016
- (0, import_extrusions3.extrudeLinear)({ height: 0.012 }, expandedPath)
28165
+ (0, import_extrusions4.extrudeLinear)({ height: 0.012 }, expandedPath)
28017
28166
  );
28018
28167
  } else {
28019
- textGeom = (0, import_transforms3.translate)(
28168
+ textGeom = (0, import_transforms4.translate)(
28020
28169
  [0, 0, this.ctx.pcbThickness / 2 + M],
28021
28170
  // Position above board
28022
- (0, import_extrusions3.extrudeLinear)({ height: 0.012 }, expandedPath)
28171
+ (0, import_extrusions4.extrudeLinear)({ height: 0.012 }, expandedPath)
28023
28172
  );
28024
28173
  }
28025
28174
  textGeom = (0, import_colors4.colorize)([1, 1, 1], textGeom);
@@ -28103,7 +28252,7 @@ var useBoardGeomBuilder = (circuitJson) => {
28103
28252
 
28104
28253
  // src/three-components/Error3d.tsx
28105
28254
  import { useState as useState10, useCallback as useCallback4, useEffect as useEffect18, useMemo as useMemo15 } from "react";
28106
- import * as THREE12 from "three";
28255
+ import * as THREE14 from "three";
28107
28256
  import { Fragment as Fragment5, jsx as jsx12, jsxs as jsxs5 } from "react/jsx-runtime";
28108
28257
  var Error3d = ({
28109
28258
  error,
@@ -28137,7 +28286,7 @@ var Error3d = ({
28137
28286
  return [0, 0, 0];
28138
28287
  }, [cad_component2]);
28139
28288
  const group = useMemo15(() => {
28140
- const g = new THREE12.Group();
28289
+ const g = new THREE14.Group();
28141
28290
  g.position.fromArray(position);
28142
28291
  return g;
28143
28292
  }, [position]);
@@ -28197,9 +28346,9 @@ var Error3d = ({
28197
28346
  };
28198
28347
  var ErrorBox = ({ parent }) => {
28199
28348
  const mesh = useMemo15(() => {
28200
- const m = new THREE12.Mesh(
28201
- new THREE12.BoxGeometry(0.5, 0.5, 0.5),
28202
- new THREE12.MeshStandardMaterial({
28349
+ const m = new THREE14.Mesh(
28350
+ new THREE14.BoxGeometry(0.5, 0.5, 0.5),
28351
+ new THREE14.MeshStandardMaterial({
28203
28352
  depthTest: false,
28204
28353
  transparent: true,
28205
28354
  color: "red",
@@ -28221,7 +28370,7 @@ var ErrorBox = ({ parent }) => {
28221
28370
 
28222
28371
  // src/three-components/STLModel.tsx
28223
28372
  import { useState as useState11, useEffect as useEffect19, useMemo as useMemo16 } from "react";
28224
- import * as THREE13 from "three";
28373
+ import * as THREE15 from "three";
28225
28374
  import { STLLoader } from "three-stdlib";
28226
28375
  function STLModel({
28227
28376
  stlUrl,
@@ -28252,12 +28401,12 @@ function STLModel({
28252
28401
  }, [stlUrl, stlData]);
28253
28402
  const mesh = useMemo16(() => {
28254
28403
  if (!geom) return null;
28255
- const material = new THREE13.MeshStandardMaterial({
28256
- color: Array.isArray(color) ? new THREE13.Color(color[0], color[1], color[2]) : color,
28404
+ const material = new THREE15.MeshStandardMaterial({
28405
+ color: Array.isArray(color) ? new THREE15.Color(color[0], color[1], color[2]) : color,
28257
28406
  transparent: opacity !== 1,
28258
28407
  opacity
28259
28408
  });
28260
- return new THREE13.Mesh(geom, material);
28409
+ return new THREE15.Mesh(geom, material);
28261
28410
  }, [geom, color, opacity]);
28262
28411
  useEffect19(() => {
28263
28412
  if (!rootObject || !mesh) return;
@@ -28401,17 +28550,17 @@ import { useEffect as useEffect21, useMemo as useMemo19, useState as useState14
28401
28550
  // src/hooks/useManifoldBoardBuilder.ts
28402
28551
  import { useState as useState13, useEffect as useEffect20, useMemo as useMemo18, useRef as useRef7 } from "react";
28403
28552
  import { su as su12 } from "@tscircuit/circuit-json-util";
28404
- import * as THREE21 from "three";
28553
+ import * as THREE23 from "three";
28405
28554
 
28406
28555
  // src/utils/manifold-mesh-to-three-geometry.ts
28407
- import * as THREE14 from "three";
28556
+ import * as THREE16 from "three";
28408
28557
  function manifoldMeshToThreeGeometry(manifoldMesh) {
28409
- const geometry = new THREE14.BufferGeometry();
28558
+ const geometry = new THREE16.BufferGeometry();
28410
28559
  geometry.setAttribute(
28411
28560
  "position",
28412
- new THREE14.Float32BufferAttribute(manifoldMesh.vertProperties, 3)
28561
+ new THREE16.Float32BufferAttribute(manifoldMesh.vertProperties, 3)
28413
28562
  );
28414
- geometry.setIndex(new THREE14.Uint32BufferAttribute(manifoldMesh.triVerts, 1));
28563
+ geometry.setIndex(new THREE16.Uint32BufferAttribute(manifoldMesh.triVerts, 1));
28415
28564
  if (manifoldMesh.runIndex && manifoldMesh.runIndex.length > 1 && manifoldMesh.runOriginalID) {
28416
28565
  for (let i = 0; i < manifoldMesh.runIndex.length - 1; i++) {
28417
28566
  const start = manifoldMesh.runIndex[i];
@@ -28425,7 +28574,7 @@ function manifoldMeshToThreeGeometry(manifoldMesh) {
28425
28574
  }
28426
28575
 
28427
28576
  // src/utils/trace-texture.ts
28428
- import * as THREE15 from "three";
28577
+ import * as THREE17 from "three";
28429
28578
  import { su as su5 } from "@tscircuit/circuit-json-util";
28430
28579
  function isWireRoutePoint(point2) {
28431
28580
  return point2 && point2.route_type === "wire" && typeof point2.layer === "string" && typeof point2.width === "number";
@@ -28508,10 +28657,10 @@ function createTraceTextureForLayer({
28508
28657
  }
28509
28658
  });
28510
28659
  ctx.globalCompositeOperation = "source-over";
28511
- const texture = new THREE15.CanvasTexture(canvas);
28660
+ const texture = new THREE17.CanvasTexture(canvas);
28512
28661
  texture.generateMipmaps = true;
28513
- texture.minFilter = THREE15.LinearMipmapLinearFilter;
28514
- texture.magFilter = THREE15.LinearFilter;
28662
+ texture.minFilter = THREE17.LinearMipmapLinearFilter;
28663
+ texture.magFilter = THREE17.LinearFilter;
28515
28664
  texture.anisotropy = 16;
28516
28665
  texture.needsUpdate = true;
28517
28666
  return texture;
@@ -28519,7 +28668,7 @@ function createTraceTextureForLayer({
28519
28668
 
28520
28669
  // src/utils/silkscreen-texture.ts
28521
28670
  var import_text2 = __toESM(require_text(), 1);
28522
- import * as THREE16 from "three";
28671
+ import * as THREE18 from "three";
28523
28672
  import { su as su6 } from "@tscircuit/circuit-json-util";
28524
28673
  function createSilkscreenTextureForLayer({
28525
28674
  layer,
@@ -28616,18 +28765,18 @@ function createSilkscreenTextureForLayer({
28616
28765
  let rotationDeg = textS.ccw_rotation ?? 0;
28617
28766
  if (textS.layer === "bottom") {
28618
28767
  transformMatrices.push(
28619
- translate2(textCenterX, textCenterY),
28768
+ translate3(textCenterX, textCenterY),
28620
28769
  { a: -1, b: 0, c: 0, d: 1, e: 0, f: 0 },
28621
- translate2(-textCenterX, -textCenterY)
28770
+ translate3(-textCenterX, -textCenterY)
28622
28771
  );
28623
28772
  rotationDeg = -rotationDeg;
28624
28773
  }
28625
28774
  if (rotationDeg) {
28626
28775
  const rad = rotationDeg * Math.PI / 180;
28627
28776
  transformMatrices.push(
28628
- translate2(textCenterX, textCenterY),
28777
+ translate3(textCenterX, textCenterY),
28629
28778
  rotate(rad),
28630
- translate2(-textCenterX, -textCenterY)
28779
+ translate3(-textCenterX, -textCenterY)
28631
28780
  );
28632
28781
  }
28633
28782
  const finalTransformMatrix = transformMatrices.length > 0 ? compose(...transformMatrices) : void 0;
@@ -28648,10 +28797,10 @@ function createSilkscreenTextureForLayer({
28648
28797
  ctx.stroke();
28649
28798
  });
28650
28799
  });
28651
- const texture = new THREE16.CanvasTexture(canvas);
28800
+ const texture = new THREE18.CanvasTexture(canvas);
28652
28801
  texture.generateMipmaps = true;
28653
- texture.minFilter = THREE16.LinearMipmapLinearFilter;
28654
- texture.magFilter = THREE16.LinearFilter;
28802
+ texture.minFilter = THREE18.LinearMipmapLinearFilter;
28803
+ texture.magFilter = THREE18.LinearFilter;
28655
28804
  texture.anisotropy = 16;
28656
28805
  texture.needsUpdate = true;
28657
28806
  return texture;
@@ -28724,8 +28873,71 @@ function processNonPlatedHolesForManifold(Manifold, circuitJson, pcbThickness, m
28724
28873
 
28725
28874
  // src/utils/manifold/process-plated-holes.ts
28726
28875
  import { su as su8 } from "@tscircuit/circuit-json-util";
28727
- import * as THREE17 from "three";
28728
- var COPPER_COLOR = new THREE17.Color(...colors.copper);
28876
+ import * as THREE19 from "three";
28877
+
28878
+ // src/utils/pad-geoms.ts
28879
+ var RECT_PAD_SEGMENTS2 = 64;
28880
+ function createRoundedRectPrism({
28881
+ Manifold,
28882
+ width: width10,
28883
+ height: height10,
28884
+ thickness,
28885
+ borderRadius
28886
+ }) {
28887
+ const clampedRadius = clampRectBorderRadius(width10, height10, borderRadius);
28888
+ if (clampedRadius <= 0) {
28889
+ return Manifold.cube([width10, height10, thickness], true);
28890
+ }
28891
+ const shapes = [];
28892
+ const innerWidth = width10 - 2 * clampedRadius;
28893
+ const innerHeight = height10 - 2 * clampedRadius;
28894
+ if (innerWidth > 0) {
28895
+ shapes.push(Manifold.cube([innerWidth, height10, thickness], true));
28896
+ }
28897
+ if (innerHeight > 0) {
28898
+ shapes.push(Manifold.cube([width10, innerHeight, thickness], true));
28899
+ }
28900
+ const cornerOffsets = [
28901
+ [width10 / 2 - clampedRadius, height10 / 2 - clampedRadius],
28902
+ [-width10 / 2 + clampedRadius, height10 / 2 - clampedRadius],
28903
+ [-width10 / 2 + clampedRadius, -height10 / 2 + clampedRadius],
28904
+ [width10 / 2 - clampedRadius, -height10 / 2 + clampedRadius]
28905
+ ];
28906
+ cornerOffsets.forEach(([x, y]) => {
28907
+ shapes.push(
28908
+ Manifold.cylinder(
28909
+ thickness,
28910
+ clampedRadius,
28911
+ clampedRadius,
28912
+ RECT_PAD_SEGMENTS2,
28913
+ true
28914
+ ).translate([x, y, 0])
28915
+ );
28916
+ });
28917
+ return Manifold.union(shapes);
28918
+ }
28919
+ function createPadManifoldOp({
28920
+ Manifold,
28921
+ pad: pad2,
28922
+ padBaseThickness
28923
+ }) {
28924
+ if (pad2.shape === "rect") {
28925
+ const rectBorderRadius = extractRectBorderRadius(pad2);
28926
+ return createRoundedRectPrism({
28927
+ Manifold,
28928
+ width: pad2.width,
28929
+ height: pad2.height,
28930
+ thickness: padBaseThickness,
28931
+ borderRadius: rectBorderRadius
28932
+ });
28933
+ } else if (pad2.shape === "circle" && pad2.radius) {
28934
+ return Manifold.cylinder(padBaseThickness, pad2.radius, -1, 32, true);
28935
+ }
28936
+ return null;
28937
+ }
28938
+
28939
+ // src/utils/manifold/process-plated-holes.ts
28940
+ var COPPER_COLOR = new THREE19.Color(...colors.copper);
28729
28941
  function processPlatedHolesForManifold(Manifold, circuitJson, pcbThickness, manifoldInstancesForCleanup) {
28730
28942
  const platedHoleBoardDrills = [];
28731
28943
  const pcbPlatedHoles = su8(circuitJson).pcb_plated_hole.list();
@@ -28900,19 +29112,26 @@ function processPlatedHolesForManifold(Manifold, circuitJson, pcbThickness, mani
28900
29112
  manifoldInstancesForCleanup.push(barrelCylinder);
28901
29113
  const padWidth = ph.rect_pad_width ?? ph.hole_diameter;
28902
29114
  const padHeight = ph.rect_pad_height ?? ph.hole_diameter;
29115
+ const rectBorderRadius = extractRectBorderRadius(ph);
28903
29116
  const padThickness = DEFAULT_SMT_PAD_THICKNESS;
28904
- const topPad = Manifold.cube(
28905
- [padWidth, padHeight, padThickness],
28906
- true
28907
- ).translate([
29117
+ const topPad = createRoundedRectPrism({
29118
+ Manifold,
29119
+ width: padWidth,
29120
+ height: padHeight,
29121
+ thickness: padThickness,
29122
+ borderRadius: rectBorderRadius
29123
+ }).translate([
28908
29124
  0,
28909
29125
  0,
28910
29126
  pcbThickness / 2 + padThickness / 2 + MANIFOLD_Z_OFFSET
28911
29127
  ]);
28912
- const bottomPad = Manifold.cube(
28913
- [padWidth, padHeight, padThickness],
28914
- true
28915
- ).translate([
29128
+ const bottomPad = createRoundedRectPrism({
29129
+ Manifold,
29130
+ width: padWidth,
29131
+ height: padHeight,
29132
+ thickness: padThickness,
29133
+ borderRadius: rectBorderRadius
29134
+ }).translate([
28916
29135
  0,
28917
29136
  0,
28918
29137
  -pcbThickness / 2 - padThickness / 2 - MANIFOLD_Z_OFFSET
@@ -28950,7 +29169,7 @@ function processPlatedHolesForManifold(Manifold, circuitJson, pcbThickness, mani
28950
29169
 
28951
29170
  // src/utils/manifold/process-vias.ts
28952
29171
  import { su as su9 } from "@tscircuit/circuit-json-util";
28953
- import * as THREE18 from "three";
29172
+ import * as THREE20 from "three";
28954
29173
 
28955
29174
  // src/utils/via-geoms.ts
28956
29175
  function createViaCopper({
@@ -28983,7 +29202,7 @@ function createViaCopper({
28983
29202
  }
28984
29203
 
28985
29204
  // src/utils/manifold/process-vias.ts
28986
- var COPPER_COLOR2 = new THREE18.Color(...colors.copper);
29205
+ var COPPER_COLOR2 = new THREE20.Color(...colors.copper);
28987
29206
  function processViasForManifold(Manifold, circuitJson, pcbThickness, manifoldInstancesForCleanup) {
28988
29207
  const viaBoardDrills = [];
28989
29208
  const pcbVias = su9(circuitJson).pcb_via.list();
@@ -29029,24 +29248,8 @@ function processViasForManifold(Manifold, circuitJson, pcbThickness, manifoldIns
29029
29248
 
29030
29249
  // src/utils/manifold/process-smt-pads.ts
29031
29250
  import { su as su10 } from "@tscircuit/circuit-json-util";
29032
- import * as THREE19 from "three";
29033
-
29034
- // src/utils/pad-geoms.ts
29035
- function createPadManifoldOp({
29036
- Manifold,
29037
- pad: pad2,
29038
- padBaseThickness
29039
- }) {
29040
- if (pad2.shape === "rect") {
29041
- return Manifold.cube([pad2.width, pad2.height, padBaseThickness], true);
29042
- } else if (pad2.shape === "circle" && pad2.radius) {
29043
- return Manifold.cylinder(padBaseThickness, pad2.radius, -1, 32, true);
29044
- }
29045
- return null;
29046
- }
29047
-
29048
- // src/utils/manifold/process-smt-pads.ts
29049
- var COPPER_COLOR3 = new THREE19.Color(...colors.copper);
29251
+ import * as THREE21 from "three";
29252
+ var COPPER_COLOR3 = new THREE21.Color(...colors.copper);
29050
29253
  function processSmtPadsForManifold(Manifold, circuitJson, pcbThickness, manifoldInstancesForCleanup, holeUnion) {
29051
29254
  const smtPadGeoms = [];
29052
29255
  const smtPads = su10(circuitJson).pcb_smtpad.list();
@@ -29135,8 +29338,8 @@ function createManifoldBoard(Manifold, CrossSection, boardData, pcbThickness, ma
29135
29338
  }
29136
29339
 
29137
29340
  // src/utils/manifold/process-copper-pours.ts
29138
- import * as THREE20 from "three";
29139
- var COPPER_COLOR4 = new THREE20.Color(...colors.copper);
29341
+ import * as THREE22 from "three";
29342
+ var COPPER_COLOR4 = new THREE22.Color(...colors.copper);
29140
29343
  var arePointsClockwise4 = (points) => {
29141
29344
  let area = 0;
29142
29345
  for (let i = 0; i < points.length; i++) {
@@ -29501,7 +29704,7 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
29501
29704
  const matColorArray = boardMaterialColors[boardData.material] ?? colors.fr4Green;
29502
29705
  currentGeoms.board = {
29503
29706
  geometry: finalBoardGeom,
29504
- color: new THREE21.Color(
29707
+ color: new THREE23.Color(
29505
29708
  matColorArray[0],
29506
29709
  matColorArray[1],
29507
29710
  matColorArray[2]
@@ -29584,16 +29787,16 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
29584
29787
  };
29585
29788
 
29586
29789
  // src/utils/manifold/create-three-geometry-meshes.ts
29587
- import * as THREE22 from "three";
29790
+ import * as THREE24 from "three";
29588
29791
  function createGeometryMeshes(geoms) {
29589
29792
  const meshes = [];
29590
29793
  if (!geoms) return meshes;
29591
29794
  if (geoms.board && geoms.board.geometry) {
29592
- const mesh = new THREE22.Mesh(
29795
+ const mesh = new THREE24.Mesh(
29593
29796
  geoms.board.geometry,
29594
- new THREE22.MeshStandardMaterial({
29797
+ new THREE24.MeshStandardMaterial({
29595
29798
  color: geoms.board.color,
29596
- side: THREE22.DoubleSide,
29799
+ side: THREE24.DoubleSide,
29597
29800
  flatShading: true
29598
29801
  })
29599
29802
  );
@@ -29603,11 +29806,11 @@ function createGeometryMeshes(geoms) {
29603
29806
  const createMeshesFromArray = (geomArray) => {
29604
29807
  if (geomArray) {
29605
29808
  geomArray.forEach((comp) => {
29606
- const mesh = new THREE22.Mesh(
29809
+ const mesh = new THREE24.Mesh(
29607
29810
  comp.geometry,
29608
- new THREE22.MeshStandardMaterial({
29811
+ new THREE24.MeshStandardMaterial({
29609
29812
  color: comp.color,
29610
- side: THREE22.DoubleSide,
29813
+ side: THREE24.DoubleSide,
29611
29814
  flatShading: true
29612
29815
  // Consistent with board
29613
29816
  })
@@ -29625,21 +29828,21 @@ function createGeometryMeshes(geoms) {
29625
29828
  }
29626
29829
 
29627
29830
  // src/utils/manifold/create-three-texture-meshes.ts
29628
- import * as THREE23 from "three";
29831
+ import * as THREE25 from "three";
29629
29832
  function createTextureMeshes(textures, boardData, pcbThickness) {
29630
29833
  const meshes = [];
29631
29834
  if (!textures || !boardData || pcbThickness === null) return meshes;
29632
29835
  const createTexturePlane = (texture, yOffset, isBottomLayer, keySuffix) => {
29633
29836
  if (!texture) return null;
29634
- const planeGeom = new THREE23.PlaneGeometry(boardData.width, boardData.height);
29635
- const material = new THREE23.MeshBasicMaterial({
29837
+ const planeGeom = new THREE25.PlaneGeometry(boardData.width, boardData.height);
29838
+ const material = new THREE25.MeshBasicMaterial({
29636
29839
  map: texture,
29637
29840
  transparent: true,
29638
- side: THREE23.DoubleSide,
29841
+ side: THREE25.DoubleSide,
29639
29842
  depthWrite: false
29640
29843
  // Important for layers to avoid z-fighting issues with board itself
29641
29844
  });
29642
- const mesh = new THREE23.Mesh(planeGeom, material);
29845
+ const mesh = new THREE25.Mesh(planeGeom, material);
29643
29846
  mesh.position.set(boardData.center.x, boardData.center.y, yOffset);
29644
29847
  if (isBottomLayer) {
29645
29848
  mesh.rotation.set(Math.PI, 0, 0);
@@ -30295,11 +30498,11 @@ var CadViewer = (props) => {
30295
30498
  // src/convert-circuit-json-to-3d-svg.ts
30296
30499
  var import_debug = __toESM(require_browser(), 1);
30297
30500
  import { su as su14 } from "@tscircuit/circuit-json-util";
30298
- import * as THREE27 from "three";
30501
+ import * as THREE29 from "three";
30299
30502
  import { SVGRenderer } from "three/examples/jsm/renderers/SVGRenderer.js";
30300
30503
 
30301
30504
  // src/utils/create-geometry-from-polygons.ts
30302
- import * as THREE24 from "three";
30505
+ import * as THREE26 from "three";
30303
30506
  import { BufferGeometry as BufferGeometry3, Float32BufferAttribute as Float32BufferAttribute2 } from "three";
30304
30507
  function createGeometryFromPolygons(polygons) {
30305
30508
  const geometry = new BufferGeometry3();
@@ -30313,12 +30516,12 @@ function createGeometryFromPolygons(polygons) {
30313
30516
  ...polygon3.vertices[i + 1]
30314
30517
  // Third vertex
30315
30518
  );
30316
- const v1 = new THREE24.Vector3(...polygon3.vertices[0]);
30317
- const v2 = new THREE24.Vector3(...polygon3.vertices[i]);
30318
- const v3 = new THREE24.Vector3(...polygon3.vertices[i + 1]);
30319
- const normal = new THREE24.Vector3().crossVectors(
30320
- new THREE24.Vector3().subVectors(v2, v1),
30321
- new THREE24.Vector3().subVectors(v3, v1)
30519
+ const v1 = new THREE26.Vector3(...polygon3.vertices[0]);
30520
+ const v2 = new THREE26.Vector3(...polygon3.vertices[i]);
30521
+ const v3 = new THREE26.Vector3(...polygon3.vertices[i + 1]);
30522
+ const normal = new THREE26.Vector3().crossVectors(
30523
+ new THREE26.Vector3().subVectors(v2, v1),
30524
+ new THREE26.Vector3().subVectors(v3, v1)
30322
30525
  ).normalize();
30323
30526
  normals.push(
30324
30527
  normal.x,
@@ -30341,10 +30544,10 @@ function createGeometryFromPolygons(polygons) {
30341
30544
  // src/utils/render-component.tsx
30342
30545
  var import_modeling3 = __toESM(require_src(), 1);
30343
30546
  var import_jscad_planner2 = __toESM(require_dist(), 1);
30344
- import * as THREE26 from "three";
30547
+ import * as THREE28 from "three";
30345
30548
 
30346
30549
  // src/utils/load-model.ts
30347
- import * as THREE25 from "three";
30550
+ import * as THREE27 from "three";
30348
30551
  import { GLTFLoader as GLTFLoader2 } from "three/examples/jsm/loaders/GLTFLoader.js";
30349
30552
  import { OBJLoader as OBJLoader2 } from "three/examples/jsm/loaders/OBJLoader.js";
30350
30553
  import { STLLoader as STLLoader2 } from "three/examples/jsm/loaders/STLLoader.js";
@@ -30352,12 +30555,12 @@ async function load3DModel(url) {
30352
30555
  if (url.endsWith(".stl")) {
30353
30556
  const loader = new STLLoader2();
30354
30557
  const geometry = await loader.loadAsync(url);
30355
- const material = new THREE25.MeshStandardMaterial({
30558
+ const material = new THREE27.MeshStandardMaterial({
30356
30559
  color: 8947848,
30357
30560
  metalness: 0.5,
30358
30561
  roughness: 0.5
30359
30562
  });
30360
- return new THREE25.Mesh(geometry, material);
30563
+ return new THREE27.Mesh(geometry, material);
30361
30564
  }
30362
30565
  if (url.endsWith(".obj")) {
30363
30566
  const loader = new OBJLoader2();
@@ -30390,9 +30593,9 @@ async function renderComponent(component, scene) {
30390
30593
  }
30391
30594
  if (component.rotation) {
30392
30595
  model.rotation.set(
30393
- THREE26.MathUtils.degToRad(component.rotation.x ?? 0),
30394
- THREE26.MathUtils.degToRad(component.rotation.y ?? 0),
30395
- THREE26.MathUtils.degToRad(component.rotation.z ?? 0)
30596
+ THREE28.MathUtils.degToRad(component.rotation.x ?? 0),
30597
+ THREE28.MathUtils.degToRad(component.rotation.y ?? 0),
30598
+ THREE28.MathUtils.degToRad(component.rotation.z ?? 0)
30396
30599
  );
30397
30600
  }
30398
30601
  scene.add(model);
@@ -30406,13 +30609,13 @@ async function renderComponent(component, scene) {
30406
30609
  );
30407
30610
  if (jscadObject && (jscadObject.polygons || jscadObject.sides)) {
30408
30611
  const threeGeom = convertCSGToThreeGeom(jscadObject);
30409
- const material2 = new THREE26.MeshStandardMaterial({
30612
+ const material2 = new THREE28.MeshStandardMaterial({
30410
30613
  color: 8947848,
30411
30614
  metalness: 0.5,
30412
30615
  roughness: 0.5,
30413
- side: THREE26.DoubleSide
30616
+ side: THREE28.DoubleSide
30414
30617
  });
30415
- const mesh2 = new THREE26.Mesh(threeGeom, material2);
30618
+ const mesh2 = new THREE28.Mesh(threeGeom, material2);
30416
30619
  if (component.position) {
30417
30620
  mesh2.position.set(
30418
30621
  component.position.x ?? 0,
@@ -30422,9 +30625,9 @@ async function renderComponent(component, scene) {
30422
30625
  }
30423
30626
  if (component.rotation) {
30424
30627
  mesh2.rotation.set(
30425
- THREE26.MathUtils.degToRad(component.rotation.x ?? 0),
30426
- THREE26.MathUtils.degToRad(component.rotation.y ?? 0),
30427
- THREE26.MathUtils.degToRad(component.rotation.z ?? 0)
30628
+ THREE28.MathUtils.degToRad(component.rotation.x ?? 0),
30629
+ THREE28.MathUtils.degToRad(component.rotation.y ?? 0),
30630
+ THREE28.MathUtils.degToRad(component.rotation.z ?? 0)
30428
30631
  );
30429
30632
  }
30430
30633
  scene.add(mesh2);
@@ -30440,17 +30643,17 @@ async function renderComponent(component, scene) {
30440
30643
  if (!geom || !geom.polygons && !geom.sides) {
30441
30644
  continue;
30442
30645
  }
30443
- const color = new THREE26.Color(geomInfo.color);
30646
+ const color = new THREE28.Color(geomInfo.color);
30444
30647
  color.convertLinearToSRGB();
30445
30648
  const geomWithColor = { ...geom, color: [color.r, color.g, color.b] };
30446
30649
  const threeGeom = convertCSGToThreeGeom(geomWithColor);
30447
- const material2 = new THREE26.MeshStandardMaterial({
30650
+ const material2 = new THREE28.MeshStandardMaterial({
30448
30651
  vertexColors: true,
30449
30652
  metalness: 0.2,
30450
30653
  roughness: 0.8,
30451
- side: THREE26.DoubleSide
30654
+ side: THREE28.DoubleSide
30452
30655
  });
30453
- const mesh2 = new THREE26.Mesh(threeGeom, material2);
30656
+ const mesh2 = new THREE28.Mesh(threeGeom, material2);
30454
30657
  if (component.position) {
30455
30658
  mesh2.position.set(
30456
30659
  component.position.x ?? 0,
@@ -30460,22 +30663,22 @@ async function renderComponent(component, scene) {
30460
30663
  }
30461
30664
  if (component.rotation) {
30462
30665
  mesh2.rotation.set(
30463
- THREE26.MathUtils.degToRad(component.rotation.x ?? 0),
30464
- THREE26.MathUtils.degToRad(component.rotation.y ?? 0),
30465
- THREE26.MathUtils.degToRad(component.rotation.z ?? 0)
30666
+ THREE28.MathUtils.degToRad(component.rotation.x ?? 0),
30667
+ THREE28.MathUtils.degToRad(component.rotation.y ?? 0),
30668
+ THREE28.MathUtils.degToRad(component.rotation.z ?? 0)
30466
30669
  );
30467
30670
  }
30468
30671
  scene.add(mesh2);
30469
30672
  }
30470
30673
  return;
30471
30674
  }
30472
- const geometry = new THREE26.BoxGeometry(0.5, 0.5, 0.5);
30473
- const material = new THREE26.MeshStandardMaterial({
30675
+ const geometry = new THREE28.BoxGeometry(0.5, 0.5, 0.5);
30676
+ const material = new THREE28.MeshStandardMaterial({
30474
30677
  color: 16711680,
30475
30678
  transparent: true,
30476
30679
  opacity: 0.25
30477
30680
  });
30478
- const mesh = new THREE26.Mesh(geometry, material);
30681
+ const mesh = new THREE28.Mesh(geometry, material);
30479
30682
  if (component.position) {
30480
30683
  mesh.position.set(
30481
30684
  component.position.x ?? 0,
@@ -30496,11 +30699,11 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
30496
30699
  padding = 20,
30497
30700
  zoom = 1.5
30498
30701
  } = options;
30499
- const scene = new THREE27.Scene();
30702
+ const scene = new THREE29.Scene();
30500
30703
  const renderer = new SVGRenderer();
30501
30704
  renderer.setSize(width10, height10);
30502
- renderer.setClearColor(new THREE27.Color(backgroundColor), 1);
30503
- const camera = new THREE27.OrthographicCamera();
30705
+ renderer.setClearColor(new THREE29.Color(backgroundColor), 1);
30706
+ const camera = new THREE29.OrthographicCamera();
30504
30707
  const aspect = width10 / height10;
30505
30708
  const frustumSize = 100;
30506
30709
  const halfFrustumSize = frustumSize / 2 / zoom;
@@ -30514,11 +30717,11 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
30514
30717
  camera.position.set(position.x, position.y, position.z);
30515
30718
  camera.up.set(0, 1, 0);
30516
30719
  const lookAt = options.camera?.lookAt ?? { x: 0, y: 0, z: 0 };
30517
- camera.lookAt(new THREE27.Vector3(lookAt.x, lookAt.y, lookAt.z));
30720
+ camera.lookAt(new THREE29.Vector3(lookAt.x, lookAt.y, lookAt.z));
30518
30721
  camera.updateProjectionMatrix();
30519
- const ambientLight = new THREE27.AmbientLight(16777215, Math.PI / 2);
30722
+ const ambientLight = new THREE29.AmbientLight(16777215, Math.PI / 2);
30520
30723
  scene.add(ambientLight);
30521
- const pointLight = new THREE27.PointLight(16777215, Math.PI / 4);
30724
+ const pointLight = new THREE29.PointLight(16777215, Math.PI / 4);
30522
30725
  pointLight.position.set(-10, -10, 10);
30523
30726
  scene.add(pointLight);
30524
30727
  const components = su14(circuitJson).cad_component.list();
@@ -30531,8 +30734,8 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
30531
30734
  const g = geom;
30532
30735
  if (!g.polygons || g.polygons.length === 0) continue;
30533
30736
  const geometry = createGeometryFromPolygons(g.polygons);
30534
- const material = new THREE27.MeshStandardMaterial({
30535
- color: new THREE27.Color(
30737
+ const material = new THREE29.MeshStandardMaterial({
30738
+ color: new THREE29.Color(
30536
30739
  g.color?.[0] ?? 0,
30537
30740
  g.color?.[1] ?? 0,
30538
30741
  g.color?.[2] ?? 0
@@ -30541,18 +30744,18 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
30541
30744
  roughness: 0.8,
30542
30745
  opacity: 0.9,
30543
30746
  transparent: true,
30544
- side: THREE27.DoubleSide
30747
+ side: THREE29.DoubleSide
30545
30748
  });
30546
- const mesh = new THREE27.Mesh(geometry, material);
30749
+ const mesh = new THREE29.Mesh(geometry, material);
30547
30750
  scene.add(mesh);
30548
30751
  }
30549
30752
  }
30550
- const gridHelper = new THREE27.GridHelper(100, 100);
30753
+ const gridHelper = new THREE29.GridHelper(100, 100);
30551
30754
  gridHelper.rotation.x = Math.PI / 2;
30552
30755
  scene.add(gridHelper);
30553
- const box = new THREE27.Box3().setFromObject(scene);
30554
- const center = box.getCenter(new THREE27.Vector3());
30555
- const size2 = box.getSize(new THREE27.Vector3());
30756
+ const box = new THREE29.Box3().setFromObject(scene);
30757
+ const center = box.getCenter(new THREE29.Vector3());
30758
+ const size2 = box.getSize(new THREE29.Vector3());
30556
30759
  scene.position.sub(center);
30557
30760
  const maxDim = Math.max(size2.x, size2.y, size2.z);
30558
30761
  if (maxDim > 0) {