@tscircuit/3d-viewer 0.0.414 → 0.0.416

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 +635 -284
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -14228,15 +14228,15 @@ var require_browser = __commonJS({
14228
14228
  });
14229
14229
 
14230
14230
  // src/CadViewer.tsx
14231
- import { useState as useState16, useCallback as useCallback8, useRef as useRef9, useEffect as useEffect23 } from "react";
14231
+ import { useState as useState18, useCallback as useCallback9, useRef as useRef9, useEffect as useEffect24 } from "react";
14232
14232
 
14233
14233
  // src/CadViewerJscad.tsx
14234
14234
  import { su as su4 } from "@tscircuit/circuit-json-util";
14235
- import { forwardRef as forwardRef3, useMemo as useMemo17 } from "react";
14235
+ import { forwardRef as forwardRef3, useMemo as useMemo18 } from "react";
14236
14236
 
14237
14237
  // src/AnyCadComponent.tsx
14238
14238
  import { su } from "@tscircuit/circuit-json-util";
14239
- import { useMemo as useMemo6, useState as useState5, useCallback as useCallback2 } from "react";
14239
+ import { useMemo as useMemo7, useState as useState6, useCallback as useCallback3 } from "react";
14240
14240
 
14241
14241
  // src/ContainerWithTooltip.tsx
14242
14242
  import { useEffect as useEffect2 } from "react";
@@ -26440,15 +26440,87 @@ var Html = ({ children, position, style }) => {
26440
26440
  return portal;
26441
26441
  };
26442
26442
 
26443
+ // src/contexts/LayerVisibilityContext.tsx
26444
+ import {
26445
+ createContext as createContext3,
26446
+ useContext as useContext3,
26447
+ useState as useState5,
26448
+ useCallback as useCallback2,
26449
+ useMemo as useMemo6
26450
+ } from "react";
26451
+ import { jsx as jsx8 } from "react/jsx-runtime";
26452
+ var defaultVisibility = {
26453
+ boardBody: true,
26454
+ topCopper: true,
26455
+ bottomCopper: true,
26456
+ adhesive: false,
26457
+ solderPaste: false,
26458
+ topSilkscreen: true,
26459
+ bottomSilkscreen: true,
26460
+ topMask: true,
26461
+ bottomMask: true,
26462
+ throughHoleModels: true,
26463
+ smtModels: true,
26464
+ virtualModels: false,
26465
+ modelsNotInPosFile: false,
26466
+ modelsMarkedDNP: false,
26467
+ modelBoundingBoxes: false,
26468
+ threedAxis: false,
26469
+ backgroundStart: true,
26470
+ backgroundEnd: true
26471
+ };
26472
+ var LayerVisibilityContext = createContext3(void 0);
26473
+ var LayerVisibilityProvider = ({ children }) => {
26474
+ const [visibility, setVisibility] = useState5(defaultVisibility);
26475
+ const toggleLayer = useCallback2((layer) => {
26476
+ setVisibility((prev) => ({
26477
+ ...prev,
26478
+ [layer]: !prev[layer]
26479
+ }));
26480
+ }, []);
26481
+ const setLayerVisibility = useCallback2(
26482
+ (layer, visible) => {
26483
+ setVisibility((prev) => ({
26484
+ ...prev,
26485
+ [layer]: visible
26486
+ }));
26487
+ },
26488
+ []
26489
+ );
26490
+ const resetToDefaults = useCallback2(() => {
26491
+ setVisibility(defaultVisibility);
26492
+ }, []);
26493
+ const value = useMemo6(
26494
+ () => ({
26495
+ visibility,
26496
+ toggleLayer,
26497
+ setLayerVisibility,
26498
+ resetToDefaults
26499
+ }),
26500
+ [visibility, toggleLayer, setLayerVisibility, resetToDefaults]
26501
+ );
26502
+ return /* @__PURE__ */ jsx8(LayerVisibilityContext.Provider, { value, children });
26503
+ };
26504
+ var useLayerVisibility = () => {
26505
+ const context = useContext3(LayerVisibilityContext);
26506
+ if (!context) {
26507
+ throw new Error(
26508
+ "useLayerVisibility must be used within a LayerVisibilityProvider"
26509
+ );
26510
+ }
26511
+ return context;
26512
+ };
26513
+
26443
26514
  // src/AnyCadComponent.tsx
26444
- import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs2 } from "react/jsx-runtime";
26515
+ import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs2 } from "react/jsx-runtime";
26445
26516
  var AnyCadComponent = ({
26446
26517
  cad_component: cad_component2,
26447
26518
  circuitJson
26448
26519
  }) => {
26449
- const [isHovered, setIsHovered] = useState5(false);
26450
- const [hoverPosition, setHoverPosition] = useState5(null);
26451
- const handleHover = useCallback2((e) => {
26520
+ const [isHovered, setIsHovered] = useState6(false);
26521
+ const { visibility } = useLayerVisibility();
26522
+ const [hoverPosition, setHoverPosition] = useState6(null);
26523
+ const handleHover = useCallback3((e) => {
26452
26524
  if (e?.mousePosition) {
26453
26525
  setIsHovered(true);
26454
26526
  setHoverPosition(e.mousePosition);
@@ -26457,11 +26529,11 @@ var AnyCadComponent = ({
26457
26529
  setHoverPosition(null);
26458
26530
  }
26459
26531
  }, []);
26460
- const handleUnhover = useCallback2(() => {
26532
+ const handleUnhover = useCallback3(() => {
26461
26533
  setIsHovered(false);
26462
26534
  setHoverPosition(null);
26463
26535
  }, []);
26464
- const componentName = useMemo6(() => {
26536
+ const componentName = useMemo7(() => {
26465
26537
  return su(circuitJson).source_component.getUsing({
26466
26538
  source_component_id: cad_component2.source_component_id
26467
26539
  })?.name;
@@ -26475,7 +26547,7 @@ var AnyCadComponent = ({
26475
26547
  ) : void 0;
26476
26548
  let modelComponent = null;
26477
26549
  if (url) {
26478
- modelComponent = /* @__PURE__ */ jsx8(
26550
+ modelComponent = /* @__PURE__ */ jsx9(
26479
26551
  MixedStlModel,
26480
26552
  {
26481
26553
  url,
@@ -26493,7 +26565,7 @@ var AnyCadComponent = ({
26493
26565
  cad_component2.cad_component_id
26494
26566
  );
26495
26567
  } else if (gltfUrl) {
26496
- modelComponent = /* @__PURE__ */ jsx8(
26568
+ modelComponent = /* @__PURE__ */ jsx9(
26497
26569
  GltfModel,
26498
26570
  {
26499
26571
  gltfUrl,
@@ -26511,7 +26583,7 @@ var AnyCadComponent = ({
26511
26583
  cad_component2.cad_component_id
26512
26584
  );
26513
26585
  } else if (cad_component2.model_jscad) {
26514
- modelComponent = /* @__PURE__ */ jsx8(
26586
+ modelComponent = /* @__PURE__ */ jsx9(
26515
26587
  JscadModel,
26516
26588
  {
26517
26589
  jscadPlan: cad_component2.model_jscad,
@@ -26524,7 +26596,7 @@ var AnyCadComponent = ({
26524
26596
  cad_component2.cad_component_id
26525
26597
  );
26526
26598
  } else if (cad_component2.footprinter_string) {
26527
- modelComponent = /* @__PURE__ */ jsx8(
26599
+ modelComponent = /* @__PURE__ */ jsx9(
26528
26600
  FootprinterModel,
26529
26601
  {
26530
26602
  positionOffset: cad_component2.position ? [
@@ -26541,9 +26613,12 @@ var AnyCadComponent = ({
26541
26613
  }
26542
26614
  );
26543
26615
  }
26616
+ if (!visibility.smtModels) {
26617
+ return null;
26618
+ }
26544
26619
  return /* @__PURE__ */ jsxs2(Fragment3, { children: [
26545
26620
  modelComponent,
26546
- isHovered && hoverPosition ? /* @__PURE__ */ jsx8(
26621
+ isHovered && hoverPosition ? /* @__PURE__ */ jsx9(
26547
26622
  Html,
26548
26623
  {
26549
26624
  position: hoverPosition,
@@ -26568,15 +26643,15 @@ var AnyCadComponent = ({
26568
26643
  // src/CadViewerContainer.tsx
26569
26644
  import {
26570
26645
  forwardRef as forwardRef2,
26571
- useMemo as useMemo13,
26572
- useState as useState7
26646
+ useMemo as useMemo14,
26647
+ useState as useState8
26573
26648
  } from "react";
26574
26649
  import * as THREE13 from "three";
26575
26650
 
26576
26651
  // package.json
26577
26652
  var package_default = {
26578
26653
  name: "@tscircuit/3d-viewer",
26579
- version: "0.0.413",
26654
+ version: "0.0.415",
26580
26655
  main: "./dist/index.js",
26581
26656
  module: "./dist/index.js",
26582
26657
  type: "module",
@@ -26655,11 +26730,11 @@ var package_default = {
26655
26730
  };
26656
26731
 
26657
26732
  // src/three-components/cube-with-labeled-sides.tsx
26658
- import { useEffect as useEffect10, useMemo as useMemo8 } from "react";
26733
+ import { useEffect as useEffect11, useMemo as useMemo9 } from "react";
26659
26734
  import * as THREE8 from "three";
26660
26735
 
26661
26736
  // src/react-three/Text.tsx
26662
- import { useEffect as useEffect9, useMemo as useMemo7 } from "react";
26737
+ import { useEffect as useEffect10, useMemo as useMemo8 } from "react";
26663
26738
  import { Text as TroikaText } from "troika-three-text";
26664
26739
  var Text = ({
26665
26740
  children,
@@ -26674,7 +26749,7 @@ var Text = ({
26674
26749
  depthOffset
26675
26750
  }) => {
26676
26751
  const { rootObject } = useThree();
26677
- const mesh = useMemo7(() => {
26752
+ const mesh = useMemo8(() => {
26678
26753
  const textMesh = new TroikaText();
26679
26754
  textMesh.text = children;
26680
26755
  if (position) textMesh.position.fromArray(position);
@@ -26699,7 +26774,7 @@ var Text = ({
26699
26774
  anchorY,
26700
26775
  depthOffset
26701
26776
  ]);
26702
- useEffect9(() => {
26777
+ useEffect10(() => {
26703
26778
  const parentObject = parent || rootObject;
26704
26779
  if (!parentObject || !mesh) return;
26705
26780
  parentObject.add(mesh);
@@ -26712,7 +26787,7 @@ var Text = ({
26712
26787
  };
26713
26788
 
26714
26789
  // src/three-components/cube-with-labeled-sides.tsx
26715
- import { Fragment as Fragment4, jsx as jsx9, jsxs as jsxs3 } from "react/jsx-runtime";
26790
+ import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs3 } from "react/jsx-runtime";
26716
26791
  if (typeof window !== "undefined") {
26717
26792
  window.TSCI_MAIN_CAMERA_ROTATION = new THREE8.Euler(0, 0, 0);
26718
26793
  }
@@ -26727,7 +26802,7 @@ function computePointInFront(rotationVector, distance2) {
26727
26802
  }
26728
26803
  var CubeWithLabeledSides = ({}) => {
26729
26804
  const { camera, scene } = useThree();
26730
- useEffect10(() => {
26805
+ useEffect11(() => {
26731
26806
  if (!scene) return;
26732
26807
  const ambientLight = new THREE8.AmbientLight(16777215, Math.PI / 2);
26733
26808
  scene.add(ambientLight);
@@ -26742,7 +26817,7 @@ var CubeWithLabeledSides = ({}) => {
26742
26817
  camera.position.copy(cameraPosition);
26743
26818
  camera.lookAt(0, 0, 0);
26744
26819
  });
26745
- const group = useMemo8(() => {
26820
+ const group = useMemo9(() => {
26746
26821
  const g = new THREE8.Group();
26747
26822
  g.rotation.fromArray([Math.PI / 2, 0, 0]);
26748
26823
  const box = new THREE8.Mesh(
@@ -26757,7 +26832,7 @@ var CubeWithLabeledSides = ({}) => {
26757
26832
  g.add(edges);
26758
26833
  return g;
26759
26834
  }, []);
26760
- useEffect10(() => {
26835
+ useEffect11(() => {
26761
26836
  if (!scene) return;
26762
26837
  scene.add(group);
26763
26838
  return () => {
@@ -26765,7 +26840,7 @@ var CubeWithLabeledSides = ({}) => {
26765
26840
  };
26766
26841
  }, [scene, group]);
26767
26842
  return /* @__PURE__ */ jsxs3(Fragment4, { children: [
26768
- /* @__PURE__ */ jsx9(
26843
+ /* @__PURE__ */ jsx10(
26769
26844
  Text,
26770
26845
  {
26771
26846
  parent: group,
@@ -26775,7 +26850,7 @@ var CubeWithLabeledSides = ({}) => {
26775
26850
  children: "Front"
26776
26851
  }
26777
26852
  ),
26778
- /* @__PURE__ */ jsx9(
26853
+ /* @__PURE__ */ jsx10(
26779
26854
  Text,
26780
26855
  {
26781
26856
  parent: group,
@@ -26786,7 +26861,7 @@ var CubeWithLabeledSides = ({}) => {
26786
26861
  children: "Back"
26787
26862
  }
26788
26863
  ),
26789
- /* @__PURE__ */ jsx9(
26864
+ /* @__PURE__ */ jsx10(
26790
26865
  Text,
26791
26866
  {
26792
26867
  parent: group,
@@ -26797,7 +26872,7 @@ var CubeWithLabeledSides = ({}) => {
26797
26872
  children: "Right"
26798
26873
  }
26799
26874
  ),
26800
- /* @__PURE__ */ jsx9(
26875
+ /* @__PURE__ */ jsx10(
26801
26876
  Text,
26802
26877
  {
26803
26878
  parent: group,
@@ -26808,7 +26883,7 @@ var CubeWithLabeledSides = ({}) => {
26808
26883
  children: "Left"
26809
26884
  }
26810
26885
  ),
26811
- /* @__PURE__ */ jsx9(
26886
+ /* @__PURE__ */ jsx10(
26812
26887
  Text,
26813
26888
  {
26814
26889
  parent: group,
@@ -26819,7 +26894,7 @@ var CubeWithLabeledSides = ({}) => {
26819
26894
  children: "Top"
26820
26895
  }
26821
26896
  ),
26822
- /* @__PURE__ */ jsx9(
26897
+ /* @__PURE__ */ jsx10(
26823
26898
  Text,
26824
26899
  {
26825
26900
  parent: group,
@@ -26836,12 +26911,12 @@ var CubeWithLabeledSides = ({}) => {
26836
26911
  // src/react-three/Canvas.tsx
26837
26912
  import {
26838
26913
  useRef as useRef4,
26839
- useEffect as useEffect11,
26840
- useState as useState6,
26841
- useCallback as useCallback3,
26914
+ useEffect as useEffect12,
26915
+ useState as useState7,
26916
+ useCallback as useCallback4,
26842
26917
  forwardRef,
26843
26918
  useImperativeHandle,
26844
- useMemo as useMemo9
26919
+ useMemo as useMemo10
26845
26920
  } from "react";
26846
26921
  import * as THREE10 from "three";
26847
26922
 
@@ -26859,23 +26934,23 @@ var configureRenderer = (renderer) => {
26859
26934
  };
26860
26935
 
26861
26936
  // src/react-three/Canvas.tsx
26862
- import { jsx as jsx10 } from "react/jsx-runtime";
26937
+ import { jsx as jsx11 } from "react/jsx-runtime";
26863
26938
  var Canvas = forwardRef(
26864
26939
  ({ children, scene: sceneProps, camera: cameraProps, style }, ref) => {
26865
26940
  const mountRef = useRef4(null);
26866
- const [contextState, setContextState] = useState6(
26941
+ const [contextState, setContextState] = useState7(
26867
26942
  null
26868
26943
  );
26869
26944
  const frameListeners = useRef4(
26870
26945
  []
26871
26946
  );
26872
- const addFrameListener = useCallback3(
26947
+ const addFrameListener = useCallback4(
26873
26948
  (listener) => {
26874
26949
  frameListeners.current.push(listener);
26875
26950
  },
26876
26951
  []
26877
26952
  );
26878
- const removeFrameListener = useCallback3(
26953
+ const removeFrameListener = useCallback4(
26879
26954
  (listener) => {
26880
26955
  frameListeners.current = frameListeners.current.filter(
26881
26956
  (l) => l !== listener
@@ -26883,13 +26958,13 @@ var Canvas = forwardRef(
26883
26958
  },
26884
26959
  []
26885
26960
  );
26886
- const scene = useMemo9(() => new THREE10.Scene(), []);
26961
+ const scene = useMemo10(() => new THREE10.Scene(), []);
26887
26962
  if (sceneProps?.up) {
26888
26963
  scene.up.set(sceneProps.up.x, sceneProps.up.y, sceneProps.up.z);
26889
26964
  }
26890
26965
  const rootObject = useRef4(new THREE10.Object3D());
26891
26966
  useImperativeHandle(ref, () => rootObject.current);
26892
- useEffect11(() => {
26967
+ useEffect12(() => {
26893
26968
  if (!mountRef.current) return;
26894
26969
  removeExistingCanvases(mountRef.current);
26895
26970
  const renderer = new THREE10.WebGLRenderer({ antialias: true, alpha: true });
@@ -26961,12 +27036,12 @@ var Canvas = forwardRef(
26961
27036
  }
26962
27037
  };
26963
27038
  }, [scene, addFrameListener, removeFrameListener]);
26964
- return /* @__PURE__ */ jsx10("div", { ref: mountRef, style: { width: "100%", height: "100%", ...style }, children: contextState && /* @__PURE__ */ jsx10(ThreeContext.Provider, { value: contextState, children: /* @__PURE__ */ jsx10(HoverProvider, { children }) }) });
27039
+ return /* @__PURE__ */ jsx11("div", { ref: mountRef, style: { width: "100%", height: "100%", ...style }, children: contextState && /* @__PURE__ */ jsx11(ThreeContext.Provider, { value: contextState, children: /* @__PURE__ */ jsx11(HoverProvider, { children }) }) });
26965
27040
  }
26966
27041
  );
26967
27042
 
26968
27043
  // src/react-three/OrbitControls.tsx
26969
- import { useEffect as useEffect12, useMemo as useMemo10 } from "react";
27044
+ import { useEffect as useEffect13, useMemo as useMemo11 } from "react";
26970
27045
  import { OrbitControls as ThreeOrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
26971
27046
  var OrbitControls = ({
26972
27047
  autoRotate,
@@ -26980,11 +27055,11 @@ var OrbitControls = ({
26980
27055
  target
26981
27056
  }) => {
26982
27057
  const { camera, renderer } = useThree();
26983
- const controls = useMemo10(() => {
27058
+ const controls = useMemo11(() => {
26984
27059
  if (!camera || !renderer) return null;
26985
27060
  return new ThreeOrbitControls(camera, renderer.domElement);
26986
27061
  }, [camera, renderer]);
26987
- useEffect12(() => {
27062
+ useEffect13(() => {
26988
27063
  if (!controls) return;
26989
27064
  controls.autoRotate = autoRotate || false;
26990
27065
  controls.autoRotateSpeed = autoRotateSpeed || 1;
@@ -27009,14 +27084,14 @@ var OrbitControls = ({
27009
27084
  dampingFactor,
27010
27085
  target
27011
27086
  ]);
27012
- useEffect12(() => {
27087
+ useEffect13(() => {
27013
27088
  if (!controls || !onStart) return;
27014
27089
  controls.addEventListener("start", onStart);
27015
27090
  return () => {
27016
27091
  controls.removeEventListener("start", onStart);
27017
27092
  };
27018
27093
  }, [controls, onStart]);
27019
- useEffect12(() => {
27094
+ useEffect13(() => {
27020
27095
  if (!controls) return;
27021
27096
  return () => {
27022
27097
  controls.dispose();
@@ -27029,7 +27104,7 @@ var OrbitControls = ({
27029
27104
  };
27030
27105
 
27031
27106
  // src/react-three/Grid.tsx
27032
- import { useEffect as useEffect13, useMemo as useMemo11 } from "react";
27107
+ import { useEffect as useEffect14, useMemo as useMemo12 } from "react";
27033
27108
  import * as THREE11 from "three";
27034
27109
  var vertexShader = `
27035
27110
  varying vec3 worldPosition;
@@ -27075,7 +27150,7 @@ var Grid = ({
27075
27150
  }) => {
27076
27151
  const { scene, camera } = useThree();
27077
27152
  const size2 = 1e3;
27078
- const gridMesh = useMemo11(() => {
27153
+ const gridMesh = useMemo12(() => {
27079
27154
  const geometry = new THREE11.PlaneGeometry(size2, size2);
27080
27155
  geometry.rotateX(-Math.PI / 2);
27081
27156
  const material = new THREE11.ShaderMaterial({
@@ -27104,7 +27179,7 @@ var Grid = ({
27104
27179
  gridMesh.position.set(camera.position.x, camera.position.y, 0);
27105
27180
  }
27106
27181
  });
27107
- useEffect13(() => {
27182
+ useEffect14(() => {
27108
27183
  if (!scene || !gridMesh) return;
27109
27184
  scene.add(gridMesh);
27110
27185
  return () => {
@@ -27121,21 +27196,21 @@ var Grid = ({
27121
27196
  };
27122
27197
 
27123
27198
  // src/react-three/Lights.tsx
27124
- import { useEffect as useEffect14, useMemo as useMemo12 } from "react";
27199
+ import { useEffect as useEffect15, useMemo as useMemo13 } from "react";
27125
27200
  import * as THREE12 from "three";
27126
27201
  var Lights = () => {
27127
27202
  const { scene } = useThree();
27128
- const ambientLight = useMemo12(
27203
+ const ambientLight = useMemo13(
27129
27204
  () => new THREE12.AmbientLight(16777215, Math.PI / 2),
27130
27205
  []
27131
27206
  );
27132
- const pointLight = useMemo12(() => {
27207
+ const pointLight = useMemo13(() => {
27133
27208
  const light = new THREE12.PointLight(16777215, Math.PI / 4);
27134
27209
  light.position.set(-10, -10, 10);
27135
27210
  light.decay = 0;
27136
27211
  return light;
27137
27212
  }, []);
27138
- useEffect14(() => {
27213
+ useEffect15(() => {
27139
27214
  if (!scene) return;
27140
27215
  scene.add(ambientLight);
27141
27216
  scene.add(pointLight);
@@ -27148,7 +27223,7 @@ var Lights = () => {
27148
27223
  };
27149
27224
 
27150
27225
  // src/CadViewerContainer.tsx
27151
- import { jsx as jsx11, jsxs as jsxs4 } from "react/jsx-runtime";
27226
+ import { jsx as jsx12, jsxs as jsxs4 } from "react/jsx-runtime";
27152
27227
  var RotationTracker = () => {
27153
27228
  const { camera } = useThree();
27154
27229
  useFrame(() => {
@@ -27168,10 +27243,10 @@ var CadViewerContainer = forwardRef2(
27168
27243
  boardCenter,
27169
27244
  onUserInteraction
27170
27245
  }, ref) => {
27171
- const [isInteractionEnabled, setIsInteractionEnabled] = useState7(
27246
+ const [isInteractionEnabled, setIsInteractionEnabled] = useState8(
27172
27247
  !clickToInteractEnabled
27173
27248
  );
27174
- const gridSectionSize = useMemo13(() => {
27249
+ const gridSectionSize = useMemo14(() => {
27175
27250
  if (!boardDimensions) return 10;
27176
27251
  const width10 = boardDimensions.width ?? 0;
27177
27252
  const height10 = boardDimensions.height ?? 0;
@@ -27179,12 +27254,12 @@ var CadViewerContainer = forwardRef2(
27179
27254
  const desired = largest * 1.5;
27180
27255
  return desired > 10 ? desired : 10;
27181
27256
  }, [boardDimensions]);
27182
- const orbitTarget = useMemo13(() => {
27257
+ const orbitTarget = useMemo14(() => {
27183
27258
  if (!boardCenter) return void 0;
27184
27259
  return [boardCenter.x, boardCenter.y, 0];
27185
27260
  }, [boardCenter]);
27186
27261
  return /* @__PURE__ */ jsxs4("div", { style: { position: "relative", width: "100%", height: "100%" }, children: [
27187
- /* @__PURE__ */ jsx11(
27262
+ /* @__PURE__ */ jsx12(
27188
27263
  "div",
27189
27264
  {
27190
27265
  style: {
@@ -27194,7 +27269,7 @@ var CadViewerContainer = forwardRef2(
27194
27269
  width: 120,
27195
27270
  height: 120
27196
27271
  },
27197
- children: /* @__PURE__ */ jsx11(
27272
+ children: /* @__PURE__ */ jsx12(
27198
27273
  Canvas,
27199
27274
  {
27200
27275
  camera: {
@@ -27202,7 +27277,7 @@ var CadViewerContainer = forwardRef2(
27202
27277
  position: [1, 1, 1]
27203
27278
  },
27204
27279
  style: { zIndex: 10 },
27205
- children: /* @__PURE__ */ jsx11(CubeWithLabeledSides, {})
27280
+ children: /* @__PURE__ */ jsx12(CubeWithLabeledSides, {})
27206
27281
  }
27207
27282
  )
27208
27283
  }
@@ -27214,8 +27289,8 @@ var CadViewerContainer = forwardRef2(
27214
27289
  scene: { up: new THREE13.Vector3(0, 0, 1) },
27215
27290
  camera: { up: [0, 0, 1], position: initialCameraPosition },
27216
27291
  children: [
27217
- /* @__PURE__ */ jsx11(RotationTracker, {}),
27218
- isInteractionEnabled && /* @__PURE__ */ jsx11(
27292
+ /* @__PURE__ */ jsx12(RotationTracker, {}),
27293
+ isInteractionEnabled && /* @__PURE__ */ jsx12(
27219
27294
  OrbitControls,
27220
27295
  {
27221
27296
  autoRotate: !autoRotateDisabled,
@@ -27229,8 +27304,8 @@ var CadViewerContainer = forwardRef2(
27229
27304
  target: orbitTarget
27230
27305
  }
27231
27306
  ),
27232
- /* @__PURE__ */ jsx11(Lights, {}),
27233
- /* @__PURE__ */ jsx11(
27307
+ /* @__PURE__ */ jsx12(Lights, {}),
27308
+ /* @__PURE__ */ jsx12(
27234
27309
  Grid,
27235
27310
  {
27236
27311
  rotation: [Math.PI / 2, 0, 0],
@@ -27262,7 +27337,7 @@ var CadViewerContainer = forwardRef2(
27262
27337
  ]
27263
27338
  }
27264
27339
  ),
27265
- clickToInteractEnabled && !isInteractionEnabled && /* @__PURE__ */ jsx11(
27340
+ clickToInteractEnabled && !isInteractionEnabled && /* @__PURE__ */ jsx12(
27266
27341
  "button",
27267
27342
  {
27268
27343
  type: "button",
@@ -27281,7 +27356,7 @@ var CadViewerContainer = forwardRef2(
27281
27356
  alignItems: "center",
27282
27357
  justifyContent: "center"
27283
27358
  },
27284
- children: /* @__PURE__ */ jsx11(
27359
+ children: /* @__PURE__ */ jsx12(
27285
27360
  "div",
27286
27361
  {
27287
27362
  style: {
@@ -27304,9 +27379,9 @@ var CadViewerContainer = forwardRef2(
27304
27379
 
27305
27380
  // src/hooks/use-convert-children-to-soup.ts
27306
27381
  import { Circuit } from "@tscircuit/core";
27307
- import { useMemo as useMemo14 } from "react";
27382
+ import { useMemo as useMemo15 } from "react";
27308
27383
  var useConvertChildrenToCircuitJson = (children) => {
27309
- return useMemo14(() => {
27384
+ return useMemo15(() => {
27310
27385
  if (!children) return [];
27311
27386
  const circuit = new Circuit();
27312
27387
  circuit.add(children);
@@ -27316,21 +27391,23 @@ var useConvertChildrenToCircuitJson = (children) => {
27316
27391
  };
27317
27392
 
27318
27393
  // src/hooks/use-stls-from-geom.ts
27319
- import { useState as useState8, useEffect as useEffect16 } from "react";
27394
+ import { useState as useState9, useEffect as useEffect17 } from "react";
27320
27395
  import stlSerializer from "@jscad/stl-serializer";
27321
27396
  var useStlsFromGeom = (geom) => {
27322
- const [stls, setStls] = useState8([]);
27323
- const [loading, setLoading] = useState8(true);
27324
- useEffect16(() => {
27397
+ const [stls, setStls] = useState9([]);
27398
+ const [loading, setLoading] = useState9(true);
27399
+ useEffect17(() => {
27325
27400
  if (!geom) return;
27326
27401
  const generateStls = async () => {
27327
27402
  setLoading(true);
27328
27403
  const geometries = Array.isArray(geom) ? geom : [geom];
27329
- const stlPromises = geometries.map(async (g) => {
27404
+ const stlPromises = geometries.map(async (g, index) => {
27330
27405
  const rawParts = stlSerializer.serialize({ binary: true }, [g]);
27331
27406
  const blob = new Blob(rawParts);
27332
27407
  const stlData = await blob.arrayBuffer();
27333
- return { stlData, color: g.color };
27408
+ const layerType = g.layerType;
27409
+ const inferredLayerType = layerType || (index === 0 ? "board" : void 0);
27410
+ return { stlData, color: g.color, layerType: inferredLayerType };
27334
27411
  });
27335
27412
  try {
27336
27413
  const generatedStls = await Promise.all(stlPromises);
@@ -27348,7 +27425,7 @@ var useStlsFromGeom = (geom) => {
27348
27425
  };
27349
27426
 
27350
27427
  // src/hooks/useBoardGeomBuilder.ts
27351
- import { useState as useState9, useEffect as useEffect17, useRef as useRef6 } from "react";
27428
+ import { useState as useState10, useEffect as useEffect18, useRef as useRef6 } from "react";
27352
27429
 
27353
27430
  // src/soup-to-3d/index.ts
27354
27431
  var import_primitives2 = __toESM(require_primitives(), 1);
@@ -27475,7 +27552,7 @@ function extractRectBorderRadius(source) {
27475
27552
  }
27476
27553
 
27477
27554
  // src/geoms/plated-hole.ts
27478
- var platedHoleLipHeight = 0.05;
27555
+ var platedHoleLipHeight = 0.02;
27479
27556
  var RECT_PAD_SEGMENTS = 64;
27480
27557
  var maybeClip = (geom, clipGeom) => clipGeom ? (0, import_booleans.intersect)(clipGeom, geom) : geom;
27481
27558
  var createRectPadGeom = ({
@@ -27504,7 +27581,7 @@ var platedHole = (plated_hole, ctx, options = {}) => {
27504
27581
  const throughDrillHeight = ctx.pcbThickness + 2 * platedHoleLipHeight + 4 * M;
27505
27582
  if (plated_hole.shape === "circle") {
27506
27583
  const outerDiameter = plated_hole.outer_diameter ?? Math.max(plated_hole.hole_diameter, 0);
27507
- const copperHeight = ctx.pcbThickness + 2 * (platedHoleLipHeight + M);
27584
+ const copperHeight = ctx.pcbThickness + 2 * platedHoleLipHeight;
27508
27585
  const copperBody = (0, import_primitives3.cylinder)({
27509
27586
  center: [plated_hole.x, plated_hole.y, 0],
27510
27587
  radius: outerDiameter / 2,
@@ -27530,7 +27607,7 @@ var platedHole = (plated_hole, ctx, options = {}) => {
27530
27607
  createRectPadGeom({
27531
27608
  width: padWidth,
27532
27609
  height: padHeight,
27533
- thickness: platedHoleLipHeight + 0.1,
27610
+ thickness: platedHoleLipHeight,
27534
27611
  // Slightly thicker to ensure connection
27535
27612
  center: [
27536
27613
  plated_hole.x,
@@ -27544,7 +27621,7 @@ var platedHole = (plated_hole, ctx, options = {}) => {
27544
27621
  createRectPadGeom({
27545
27622
  width: padWidth,
27546
27623
  height: padHeight,
27547
- thickness: platedHoleLipHeight + 0.1,
27624
+ thickness: platedHoleLipHeight,
27548
27625
  // Slightly thicker to ensure connection
27549
27626
  center: [
27550
27627
  plated_hole.x,
@@ -27696,11 +27773,11 @@ var platedHole = (plated_hole, ctx, options = {}) => {
27696
27773
  size: shouldRotate ? [
27697
27774
  holeHeight + 2 * barrelMargin,
27698
27775
  rectLength + 2 * barrelMargin,
27699
- ctx.pcbThickness + 0.2
27776
+ ctx.pcbThickness + 0.02
27700
27777
  ] : [
27701
27778
  rectLength + 2 * barrelMargin,
27702
27779
  holeHeight + 2 * barrelMargin,
27703
- ctx.pcbThickness + 0.2
27780
+ ctx.pcbThickness
27704
27781
  ]
27705
27782
  }),
27706
27783
  (0, import_primitives3.cylinder)({
@@ -27714,8 +27791,7 @@ var platedHole = (plated_hole, ctx, options = {}) => {
27714
27791
  0
27715
27792
  ],
27716
27793
  radius: holeRadius + barrelMargin,
27717
- height: ctx.pcbThickness + 0.2
27718
- // extend slightly above/below PCB
27794
+ height: ctx.pcbThickness + 0.02
27719
27795
  }),
27720
27796
  (0, import_primitives3.cylinder)({
27721
27797
  center: shouldRotate ? [
@@ -27728,7 +27804,7 @@ var platedHole = (plated_hole, ctx, options = {}) => {
27728
27804
  0
27729
27805
  ],
27730
27806
  radius: holeRadius + barrelMargin,
27731
- height: ctx.pcbThickness + 0.2
27807
+ height: ctx.pcbThickness + 0.02
27732
27808
  })
27733
27809
  );
27734
27810
  const holeCut = (0, import_booleans.union)(
@@ -27763,30 +27839,41 @@ var platedHole = (plated_hole, ctx, options = {}) => {
27763
27839
  height: throughDrillHeight * 1.1
27764
27840
  })
27765
27841
  );
27766
- const mainFill = createRectPadGeom({
27842
+ const copperTopPad = createRectPadGeom({
27767
27843
  width: padWidth,
27768
27844
  height: padHeight,
27769
- thickness: ctx.pcbThickness - 2 * platedHoleLipHeight - M * 2 + 0.1,
27770
- center: [plated_hole.x, plated_hole.y, 0],
27845
+ thickness: platedHoleLipHeight,
27846
+ center: [
27847
+ plated_hole.x,
27848
+ plated_hole.y,
27849
+ ctx.pcbThickness / 2 + platedHoleLipHeight / 2 + M - 0.05
27850
+ ],
27771
27851
  borderRadius: rectBorderRadius
27772
27852
  });
27773
- const createPadWithHole = (zOffset) => {
27774
- const pad2 = createRectPadGeom({
27775
- width: padWidth,
27776
- height: padHeight,
27777
- thickness: platedHoleLipHeight + 0.1,
27778
- center: [plated_hole.x, plated_hole.y, zOffset],
27779
- borderRadius: rectBorderRadius
27853
+ const copperBottomPad = createRectPadGeom({
27854
+ width: padWidth,
27855
+ height: padHeight,
27856
+ thickness: platedHoleLipHeight,
27857
+ center: [
27858
+ plated_hole.x,
27859
+ plated_hole.y,
27860
+ -ctx.pcbThickness / 2 - platedHoleLipHeight / 2 - M + 0.05
27861
+ ],
27862
+ borderRadius: rectBorderRadius
27863
+ });
27864
+ const copperFill = (() => {
27865
+ const height10 = ctx.pcbThickness - platedHoleLipHeight * 2 - M * 2 + 0.1;
27866
+ const rect2d = (0, import_primitives3.roundedRectangle)({
27867
+ size: [padWidth, padHeight],
27868
+ roundRadius: rectBorderRadius || 0,
27869
+ segments: RECT_PAD_SEGMENTS
27780
27870
  });
27781
- return (0, import_booleans.subtract)(pad2, holeCut);
27782
- };
27783
- const topPad = createPadWithHole(
27784
- ctx.pcbThickness / 2 - platedHoleLipHeight / 2 + 0.05
27785
- );
27786
- const bottomPad = createPadWithHole(
27787
- -ctx.pcbThickness / 2 + platedHoleLipHeight / 2 - 0.05
27788
- );
27789
- const filledArea = (0, import_booleans.subtract)(mainFill, holeCut);
27871
+ const extruded = (0, import_extrusions2.extrudeLinear)({ height: height10 }, rect2d);
27872
+ return (0, import_transforms2.translate)([plated_hole.x, plated_hole.y, -height10 / 2], extruded);
27873
+ })();
27874
+ const copperTopPadCut = (0, import_booleans.subtract)(copperTopPad, holeCut);
27875
+ const copperBottomPadCut = (0, import_booleans.subtract)(copperBottomPad, holeCut);
27876
+ const copperFillCut = (0, import_booleans.subtract)(copperFill, holeCut);
27790
27877
  const barrelHoleCut = (0, import_booleans.union)(
27791
27878
  (0, import_primitives3.cuboid)({
27792
27879
  center: [plated_hole.x + holeOffsetX, plated_hole.y + holeOffsetY, 0],
@@ -27820,9 +27907,11 @@ var platedHole = (plated_hole, ctx, options = {}) => {
27820
27907
  })
27821
27908
  );
27822
27909
  const barrelWithHole = (0, import_booleans.subtract)(barrel, barrelHoleCut);
27823
- const finalCopper = (0, import_booleans.union)(filledArea, barrelWithHole, topPad, bottomPad);
27824
- let result = maybeClip(finalCopper, clipGeom);
27825
- return (0, import_colors2.colorize)(colors.copper, result);
27910
+ const finalCopper = maybeClip(
27911
+ (0, import_booleans.union)(copperTopPadCut, copperBottomPadCut, copperFillCut, barrelWithHole),
27912
+ clipGeom
27913
+ );
27914
+ return (0, import_colors2.colorize)(colors.copper, finalCopper);
27826
27915
  } else {
27827
27916
  throw new Error(`Unsupported plated hole shape: ${plated_hole.shape}`);
27828
27917
  }
@@ -28660,111 +28749,80 @@ var BoardGeomBuilder = class {
28660
28749
  }
28661
28750
  processHole(hole) {
28662
28751
  if (!this.boardGeom) return;
28752
+ const holeDepth = this.ctx.pcbThickness * 1.5;
28753
+ const copperInset = 0.02;
28663
28754
  if (hole.hole_shape === "round" || hole.hole_shape === "circle") {
28664
28755
  const cyGeom = (0, import_primitives6.cylinder)({
28665
28756
  center: [hole.x, hole.y, 0],
28666
28757
  radius: hole.hole_diameter / 2 + M,
28667
- // Add margin for subtraction
28668
- height: this.ctx.pcbThickness * 1.5
28669
- // Ensure it cuts through
28758
+ height: holeDepth
28670
28759
  });
28671
28760
  this.boardGeom = (0, import_booleans3.subtract)(this.boardGeom, cyGeom);
28672
28761
  this.padGeoms = this.padGeoms.map(
28673
28762
  (pg) => (0, import_colors4.colorize)(colors.copper, (0, import_booleans3.subtract)(pg, cyGeom))
28674
28763
  );
28675
- } else if (hole.hole_shape === "pill") {
28764
+ const copperCut = (0, import_primitives6.cylinder)({
28765
+ center: [hole.x, hole.y, 0],
28766
+ radius: hole.hole_diameter / 2 + M / 2,
28767
+ height: holeDepth
28768
+ });
28769
+ this.platedHoleGeoms = this.platedHoleGeoms.map(
28770
+ (phg) => (0, import_colors4.colorize)(colors.copper, (0, import_booleans3.subtract)(phg, copperCut))
28771
+ );
28772
+ } else if (hole.hole_shape === "pill" || hole.hole_shape === "rotated_pill") {
28676
28773
  const holeWidth = hole.hole_width;
28677
28774
  const holeHeight = hole.hole_height;
28678
28775
  const holeRadius = Math.min(holeWidth, holeHeight) / 2;
28679
28776
  const rectLength = Math.abs(holeWidth - holeHeight);
28777
+ const isRotated = hole.hole_shape === "rotated_pill";
28680
28778
  let pillHole;
28681
28779
  if (holeWidth > holeHeight) {
28682
28780
  pillHole = (0, import_booleans3.union)(
28683
28781
  (0, import_primitives6.cuboid)({
28684
28782
  center: [hole.x, hole.y, 0],
28685
- size: [rectLength, holeHeight, this.ctx.pcbThickness * 1.5]
28783
+ size: [rectLength, holeHeight, holeDepth]
28686
28784
  }),
28687
28785
  (0, import_primitives6.cylinder)({
28688
28786
  center: [hole.x - rectLength / 2, hole.y, 0],
28689
28787
  radius: holeRadius,
28690
- height: this.ctx.pcbThickness * 1.5
28788
+ height: holeDepth
28691
28789
  }),
28692
28790
  (0, import_primitives6.cylinder)({
28693
28791
  center: [hole.x + rectLength / 2, hole.y, 0],
28694
28792
  radius: holeRadius,
28695
- height: this.ctx.pcbThickness * 1.5
28793
+ height: holeDepth
28696
28794
  })
28697
28795
  );
28698
28796
  } else {
28699
28797
  pillHole = (0, import_booleans3.union)(
28700
28798
  (0, import_primitives6.cuboid)({
28701
28799
  center: [hole.x, hole.y, 0],
28702
- size: [holeWidth, rectLength, this.ctx.pcbThickness * 1.5]
28800
+ size: [holeWidth, rectLength, holeDepth]
28703
28801
  }),
28704
28802
  (0, import_primitives6.cylinder)({
28705
28803
  center: [hole.x, hole.y - rectLength / 2, 0],
28706
28804
  radius: holeRadius,
28707
- height: this.ctx.pcbThickness * 1.5
28805
+ height: holeDepth
28708
28806
  }),
28709
28807
  (0, import_primitives6.cylinder)({
28710
28808
  center: [hole.x, hole.y + rectLength / 2, 0],
28711
28809
  radius: holeRadius,
28712
- height: this.ctx.pcbThickness * 1.5
28810
+ height: holeDepth
28713
28811
  })
28714
28812
  );
28715
28813
  }
28716
- this.boardGeom = (0, import_booleans3.subtract)(this.boardGeom, pillHole);
28717
- this.padGeoms = this.padGeoms.map(
28718
- (pg) => (0, import_colors4.colorize)(colors.copper, (0, import_booleans3.subtract)(pg, pillHole))
28719
- );
28720
- } else if (hole.hole_shape === "rotated_pill") {
28721
- const holeWidth = hole.hole_width;
28722
- const holeHeight = hole.hole_height;
28723
- const holeRadius = Math.min(holeWidth, holeHeight) / 2;
28724
- const rectLength = Math.abs(holeWidth - holeHeight);
28725
- let pillHole;
28726
- if (holeWidth > holeHeight) {
28727
- pillHole = (0, import_booleans3.union)(
28728
- (0, import_primitives6.cuboid)({
28729
- center: [0, 0, 0],
28730
- size: [rectLength, holeHeight, this.ctx.pcbThickness * 1.5]
28731
- }),
28732
- (0, import_primitives6.cylinder)({
28733
- center: [-rectLength / 2, 0, 0],
28734
- radius: holeRadius,
28735
- height: this.ctx.pcbThickness * 1.5
28736
- }),
28737
- (0, import_primitives6.cylinder)({
28738
- center: [rectLength / 2, 0, 0],
28739
- radius: holeRadius,
28740
- height: this.ctx.pcbThickness * 1.5
28741
- })
28742
- );
28743
- } else {
28744
- pillHole = (0, import_booleans3.union)(
28745
- (0, import_primitives6.cuboid)({
28746
- center: [0, 0, 0],
28747
- size: [holeWidth, rectLength, this.ctx.pcbThickness * 1.5]
28748
- }),
28749
- (0, import_primitives6.cylinder)({
28750
- center: [0, -rectLength / 2, 0],
28751
- radius: holeRadius,
28752
- height: this.ctx.pcbThickness * 1.5
28753
- }),
28754
- (0, import_primitives6.cylinder)({
28755
- center: [0, rectLength / 2, 0],
28756
- radius: holeRadius,
28757
- height: this.ctx.pcbThickness * 1.5
28758
- })
28759
- );
28814
+ if (isRotated) {
28815
+ const rotationRadians = hole.ccw_rotation * Math.PI / 180;
28816
+ pillHole = (0, import_transforms4.rotateZ)(rotationRadians, pillHole);
28760
28817
  }
28761
- const rotationRadians = hole.ccw_rotation * Math.PI / 180;
28762
- pillHole = (0, import_transforms4.rotateZ)(rotationRadians, pillHole);
28763
- pillHole = (0, import_transforms4.translate)([hole.x, hole.y, 0], pillHole);
28764
28818
  this.boardGeom = (0, import_booleans3.subtract)(this.boardGeom, pillHole);
28765
28819
  this.padGeoms = this.padGeoms.map(
28766
28820
  (pg) => (0, import_colors4.colorize)(colors.copper, (0, import_booleans3.subtract)(pg, pillHole))
28767
28821
  );
28822
+ const copperPill = (0, import_expansions3.expand)({ delta: -copperInset }, pillHole);
28823
+ this.platedHoleGeoms = this.platedHoleGeoms.map(
28824
+ (phg) => (0, import_colors4.colorize)(colors.copper, (0, import_booleans3.subtract)(phg, copperPill))
28825
+ );
28768
28826
  }
28769
28827
  }
28770
28828
  processPad(pad2) {
@@ -28986,9 +29044,9 @@ var BoardGeomBuilder = class {
28986
29044
 
28987
29045
  // src/hooks/useBoardGeomBuilder.ts
28988
29046
  var useBoardGeomBuilder = (circuitJson) => {
28989
- const [boardGeom, setBoardGeom] = useState9(null);
29047
+ const [boardGeom, setBoardGeom] = useState10(null);
28990
29048
  const isProcessingRef = useRef6(false);
28991
- useEffect17(() => {
29049
+ useEffect18(() => {
28992
29050
  let isCancelled = false;
28993
29051
  if (!circuitJson) {
28994
29052
  setBoardGeom(null);
@@ -29031,17 +29089,17 @@ var useBoardGeomBuilder = (circuitJson) => {
29031
29089
  };
29032
29090
 
29033
29091
  // src/three-components/Error3d.tsx
29034
- import { useState as useState10, useCallback as useCallback4, useEffect as useEffect18, useMemo as useMemo15 } from "react";
29092
+ import { useState as useState11, useCallback as useCallback5, useEffect as useEffect19, useMemo as useMemo16 } from "react";
29035
29093
  import * as THREE14 from "three";
29036
- import { Fragment as Fragment5, jsx as jsx12, jsxs as jsxs5 } from "react/jsx-runtime";
29094
+ import { Fragment as Fragment5, jsx as jsx13, jsxs as jsxs5 } from "react/jsx-runtime";
29037
29095
  var Error3d = ({
29038
29096
  error,
29039
29097
  cad_component: cad_component2
29040
29098
  }) => {
29041
29099
  const { rootObject } = useThree();
29042
- const [isHovered, setIsHovered] = useState10(false);
29043
- const [hoverPosition, setHoverPosition] = useState10(null);
29044
- const handleHover = useCallback4((e) => {
29100
+ const [isHovered, setIsHovered] = useState11(false);
29101
+ const [hoverPosition, setHoverPosition] = useState11(null);
29102
+ const handleHover = useCallback5((e) => {
29045
29103
  if (e?.mousePosition) {
29046
29104
  setIsHovered(true);
29047
29105
  setHoverPosition(e.mousePosition);
@@ -29050,11 +29108,11 @@ var Error3d = ({
29050
29108
  setHoverPosition(null);
29051
29109
  }
29052
29110
  }, []);
29053
- const handleUnhover = useCallback4(() => {
29111
+ const handleUnhover = useCallback5(() => {
29054
29112
  setIsHovered(false);
29055
29113
  setHoverPosition(null);
29056
29114
  }, []);
29057
- const position = useMemo15(() => {
29115
+ const position = useMemo16(() => {
29058
29116
  if (cad_component2?.position) {
29059
29117
  const p = [
29060
29118
  cad_component2.position.x,
@@ -29065,12 +29123,12 @@ var Error3d = ({
29065
29123
  }
29066
29124
  return [0, 0, 0];
29067
29125
  }, [cad_component2]);
29068
- const group = useMemo15(() => {
29126
+ const group = useMemo16(() => {
29069
29127
  const g = new THREE14.Group();
29070
29128
  g.position.fromArray(position);
29071
29129
  return g;
29072
29130
  }, [position]);
29073
- useEffect18(() => {
29131
+ useEffect19(() => {
29074
29132
  if (!rootObject) return;
29075
29133
  rootObject.add(group);
29076
29134
  return () => {
@@ -29086,8 +29144,8 @@ var Error3d = ({
29086
29144
  onUnhover: handleUnhover,
29087
29145
  object: group,
29088
29146
  children: [
29089
- /* @__PURE__ */ jsx12(ErrorBox, { parent: group }),
29090
- /* @__PURE__ */ jsx12(
29147
+ /* @__PURE__ */ jsx13(ErrorBox, { parent: group }),
29148
+ /* @__PURE__ */ jsx13(
29091
29149
  Text,
29092
29150
  {
29093
29151
  parent: group,
@@ -29102,7 +29160,7 @@ var Error3d = ({
29102
29160
  ]
29103
29161
  }
29104
29162
  ),
29105
- isHovered && hoverPosition ? /* @__PURE__ */ jsx12(
29163
+ isHovered && hoverPosition ? /* @__PURE__ */ jsx13(
29106
29164
  Html,
29107
29165
  {
29108
29166
  position: hoverPosition,
@@ -29125,7 +29183,7 @@ var Error3d = ({
29125
29183
  ] });
29126
29184
  };
29127
29185
  var ErrorBox = ({ parent }) => {
29128
- const mesh = useMemo15(() => {
29186
+ const mesh = useMemo16(() => {
29129
29187
  const m = new THREE14.Mesh(
29130
29188
  new THREE14.BoxGeometry(0.5, 0.5, 0.5),
29131
29189
  new THREE14.MeshStandardMaterial({
@@ -29139,7 +29197,7 @@ var ErrorBox = ({ parent }) => {
29139
29197
  m.rotation.fromArray([Math.PI / 4, Math.PI / 4, 0]);
29140
29198
  return m;
29141
29199
  }, []);
29142
- useEffect18(() => {
29200
+ useEffect19(() => {
29143
29201
  parent.add(mesh);
29144
29202
  return () => {
29145
29203
  parent.remove(mesh);
@@ -29149,7 +29207,7 @@ var ErrorBox = ({ parent }) => {
29149
29207
  };
29150
29208
 
29151
29209
  // src/three-components/STLModel.tsx
29152
- import { useState as useState11, useEffect as useEffect19, useMemo as useMemo16 } from "react";
29210
+ import { useState as useState12, useEffect as useEffect20, useMemo as useMemo17 } from "react";
29153
29211
  import * as THREE15 from "three";
29154
29212
  import { STLLoader } from "three-stdlib";
29155
29213
  function STLModel({
@@ -29160,8 +29218,8 @@ function STLModel({
29160
29218
  opacity = 1
29161
29219
  }) {
29162
29220
  const { rootObject } = useThree();
29163
- const [geom, setGeom] = useState11(null);
29164
- useEffect19(() => {
29221
+ const [geom, setGeom] = useState12(null);
29222
+ useEffect20(() => {
29165
29223
  const loader = new STLLoader();
29166
29224
  if (stlData) {
29167
29225
  try {
@@ -29179,7 +29237,7 @@ function STLModel({
29179
29237
  });
29180
29238
  }
29181
29239
  }, [stlUrl, stlData]);
29182
- const mesh = useMemo16(() => {
29240
+ const mesh = useMemo17(() => {
29183
29241
  if (!geom) return null;
29184
29242
  const material = new THREE15.MeshStandardMaterial({
29185
29243
  color: Array.isArray(color) ? new THREE15.Color(color[0], color[1], color[2]) : color,
@@ -29188,7 +29246,7 @@ function STLModel({
29188
29246
  });
29189
29247
  return new THREE15.Mesh(geom, material);
29190
29248
  }, [geom, color, opacity]);
29191
- useEffect19(() => {
29249
+ useEffect20(() => {
29192
29250
  if (!rootObject || !mesh) return;
29193
29251
  rootObject.add(mesh);
29194
29252
  return () => {
@@ -29204,9 +29262,36 @@ function STLModel({
29204
29262
  return null;
29205
29263
  }
29206
29264
 
29265
+ // src/three-components/VisibleSTLModel.tsx
29266
+ import { jsx as jsx14 } from "react/jsx-runtime";
29267
+ function VisibleSTLModel({
29268
+ stlData,
29269
+ color,
29270
+ opacity = 1,
29271
+ layerType
29272
+ }) {
29273
+ const { visibility } = useLayerVisibility();
29274
+ let shouldShow = true;
29275
+ if (layerType === "board") {
29276
+ shouldShow = visibility.boardBody;
29277
+ } else if (layerType === "top-copper") {
29278
+ shouldShow = visibility.topCopper;
29279
+ } else if (layerType === "bottom-copper") {
29280
+ shouldShow = visibility.bottomCopper;
29281
+ } else if (layerType === "top-silkscreen") {
29282
+ shouldShow = visibility.topSilkscreen;
29283
+ } else if (layerType === "bottom-silkscreen") {
29284
+ shouldShow = visibility.bottomSilkscreen;
29285
+ }
29286
+ if (!shouldShow) {
29287
+ return null;
29288
+ }
29289
+ return /* @__PURE__ */ jsx14(STLModel, { stlData, color, opacity });
29290
+ }
29291
+
29207
29292
  // src/three-components/ThreeErrorBoundary.tsx
29208
- import React10 from "react";
29209
- var ThreeErrorBoundary = class extends React10.Component {
29293
+ import React11 from "react";
29294
+ var ThreeErrorBoundary = class extends React11.Component {
29210
29295
  constructor(props) {
29211
29296
  super(props);
29212
29297
  this.state = { hasError: false, error: null };
@@ -29223,7 +29308,7 @@ var ThreeErrorBoundary = class extends React10.Component {
29223
29308
  };
29224
29309
 
29225
29310
  // src/CadViewerJscad.tsx
29226
- import { jsx as jsx13, jsxs as jsxs6 } from "react/jsx-runtime";
29311
+ import { jsx as jsx15, jsxs as jsxs6 } from "react/jsx-runtime";
29227
29312
  var CadViewerJscad = forwardRef3(
29228
29313
  ({
29229
29314
  soup,
@@ -29234,12 +29319,12 @@ var CadViewerJscad = forwardRef3(
29234
29319
  onUserInteraction
29235
29320
  }, ref) => {
29236
29321
  const childrenSoup = useConvertChildrenToCircuitJson(children);
29237
- const internalCircuitJson = useMemo17(() => {
29322
+ const internalCircuitJson = useMemo18(() => {
29238
29323
  const cj = soup ?? circuitJson;
29239
29324
  return cj ?? childrenSoup;
29240
29325
  }, [soup, circuitJson, childrenSoup]);
29241
29326
  const boardGeom = useBoardGeomBuilder(internalCircuitJson);
29242
- const initialCameraPosition = useMemo17(() => {
29327
+ const initialCameraPosition = useMemo18(() => {
29243
29328
  if (!internalCircuitJson) return [5, 5, 5];
29244
29329
  try {
29245
29330
  const board = su4(internalCircuitJson).pcb_board.list()[0];
@@ -29258,7 +29343,7 @@ var CadViewerJscad = forwardRef3(
29258
29343
  return [5, 5, 5];
29259
29344
  }
29260
29345
  }, [internalCircuitJson]);
29261
- const boardDimensions = useMemo17(() => {
29346
+ const boardDimensions = useMemo18(() => {
29262
29347
  if (!internalCircuitJson) return void 0;
29263
29348
  try {
29264
29349
  const board = su4(internalCircuitJson).pcb_board.list()[0];
@@ -29269,7 +29354,7 @@ var CadViewerJscad = forwardRef3(
29269
29354
  return void 0;
29270
29355
  }
29271
29356
  }, [internalCircuitJson]);
29272
- const boardCenter = useMemo17(() => {
29357
+ const boardCenter = useMemo18(() => {
29273
29358
  if (!internalCircuitJson) return void 0;
29274
29359
  try {
29275
29360
  const board = su4(internalCircuitJson).pcb_board.list()[0];
@@ -29293,20 +29378,21 @@ var CadViewerJscad = forwardRef3(
29293
29378
  boardCenter,
29294
29379
  onUserInteraction,
29295
29380
  children: [
29296
- boardStls.map(({ stlData, color }, index) => /* @__PURE__ */ jsx13(
29297
- STLModel,
29381
+ boardStls.map(({ stlData, color, layerType }, index) => /* @__PURE__ */ jsx15(
29382
+ VisibleSTLModel,
29298
29383
  {
29299
29384
  stlData,
29300
29385
  color,
29301
- opacity: index === 0 ? 0.95 : 1
29386
+ opacity: index === 0 ? 0.95 : 1,
29387
+ layerType
29302
29388
  },
29303
- `board-${index - boardStls.length}`
29389
+ `board-${index}`
29304
29390
  )),
29305
- cad_components.map((cad_component2) => /* @__PURE__ */ jsx13(
29391
+ cad_components.map((cad_component2) => /* @__PURE__ */ jsx15(
29306
29392
  ThreeErrorBoundary,
29307
29393
  {
29308
- fallback: ({ error }) => /* @__PURE__ */ jsx13(Error3d, { cad_component: cad_component2, error }),
29309
- children: /* @__PURE__ */ jsx13(
29394
+ fallback: ({ error }) => /* @__PURE__ */ jsx15(Error3d, { cad_component: cad_component2, error }),
29395
+ children: /* @__PURE__ */ jsx15(
29310
29396
  AnyCadComponent,
29311
29397
  {
29312
29398
  cad_component: cad_component2,
@@ -29325,10 +29411,10 @@ var CadViewerJscad = forwardRef3(
29325
29411
 
29326
29412
  // src/CadViewerManifold.tsx
29327
29413
  import { su as su13 } from "@tscircuit/circuit-json-util";
29328
- import { useEffect as useEffect21, useMemo as useMemo19, useState as useState14 } from "react";
29414
+ import { useEffect as useEffect22, useMemo as useMemo20, useState as useState15 } from "react";
29329
29415
 
29330
29416
  // src/hooks/useManifoldBoardBuilder.ts
29331
- import { useState as useState13, useEffect as useEffect20, useMemo as useMemo18, useRef as useRef7 } from "react";
29417
+ import { useState as useState14, useEffect as useEffect21, useMemo as useMemo19, useRef as useRef7 } from "react";
29332
29418
  import { su as su12 } from "@tscircuit/circuit-json-util";
29333
29419
  import * as THREE23 from "three";
29334
29420
 
@@ -29771,6 +29857,7 @@ function processPlatedHolesForManifold(Manifold, circuitJson, pcbThickness, mani
29771
29857
  const platedHoleBoardDrills = [];
29772
29858
  const pcbPlatedHoles = su8(circuitJson).pcb_plated_hole.list();
29773
29859
  const platedHoleCopperGeoms = [];
29860
+ const platedHoleCopperOpsForSubtract = [];
29774
29861
  const createPillOp = (width10, height10, depth) => {
29775
29862
  const pillOp = createRoundedRectPrism({
29776
29863
  Manifold,
@@ -29827,6 +29914,7 @@ function processPlatedHolesForManifold(Manifold, circuitJson, pcbThickness, mani
29827
29914
  manifoldInstancesForCleanup.push(clipped);
29828
29915
  finalCopperOp = clipped;
29829
29916
  }
29917
+ platedHoleCopperOpsForSubtract.push(finalCopperOp);
29830
29918
  const threeGeom = manifoldMeshToThreeGeometry(finalCopperOp.getMesh());
29831
29919
  platedHoleCopperGeoms.push({
29832
29920
  key: `ph-${ph.pcb_plated_hole_id || index}`,
@@ -29878,9 +29966,17 @@ function processPlatedHolesForManifold(Manifold, circuitJson, pcbThickness, mani
29878
29966
  }
29879
29967
  const translatedPlatedPart = finalPlatedPartOp.translate([ph.x, ph.y, 0]);
29880
29968
  manifoldInstancesForCleanup.push(translatedPlatedPart);
29881
- const threeGeom = manifoldMeshToThreeGeometry(
29882
- translatedPlatedPart.getMesh()
29883
- );
29969
+ let finalCopperOp = translatedPlatedPart;
29970
+ if (boardClipVolume) {
29971
+ const clipped = Manifold.intersection([
29972
+ translatedPlatedPart,
29973
+ boardClipVolume
29974
+ ]);
29975
+ manifoldInstancesForCleanup.push(clipped);
29976
+ finalCopperOp = clipped;
29977
+ }
29978
+ platedHoleCopperOpsForSubtract.push(finalCopperOp);
29979
+ const threeGeom = manifoldMeshToThreeGeometry(finalCopperOp.getMesh());
29884
29980
  platedHoleCopperGeoms.push({
29885
29981
  key: `ph-${ph.pcb_plated_hole_id || index}`,
29886
29982
  geometry: threeGeom,
@@ -29921,14 +30017,14 @@ function processPlatedHolesForManifold(Manifold, circuitJson, pcbThickness, mani
29921
30017
  Manifold,
29922
30018
  width: padWidth,
29923
30019
  height: padHeight,
29924
- thickness: padThickness + 0.1,
30020
+ thickness: padThickness,
29925
30021
  borderRadius: rectBorderRadius
29926
30022
  }).translate([0, 0, pcbThickness / 2 - padThickness / 2 + 0.05]);
29927
30023
  const bottomPad = createRoundedRectPrism({
29928
30024
  Manifold,
29929
30025
  width: padWidth,
29930
30026
  height: padHeight,
29931
- thickness: padThickness + 0.1,
30027
+ thickness: padThickness,
29932
30028
  borderRadius: rectBorderRadius
29933
30029
  }).translate([0, 0, -pcbThickness / 2 + padThickness / 2 - 0.05]);
29934
30030
  manifoldInstancesForCleanup.push(topPad, bottomPad);
@@ -29966,6 +30062,7 @@ function processPlatedHolesForManifold(Manifold, circuitJson, pcbThickness, mani
29966
30062
  manifoldInstancesForCleanup.push(clipped);
29967
30063
  finalCopperOp = clipped;
29968
30064
  }
30065
+ platedHoleCopperOpsForSubtract.push(finalCopperOp);
29969
30066
  const threeGeom = manifoldMeshToThreeGeometry(finalCopperOp.getMesh());
29970
30067
  platedHoleCopperGeoms.push({
29971
30068
  key: `ph-${ph.pcb_plated_hole_id || index}`,
@@ -30005,14 +30102,14 @@ function processPlatedHolesForManifold(Manifold, circuitJson, pcbThickness, mani
30005
30102
  Manifold,
30006
30103
  width: padWidth,
30007
30104
  height: padHeight,
30008
- thickness: padThickness + 0.1,
30105
+ thickness: padThickness,
30009
30106
  borderRadius: rectBorderRadius
30010
30107
  }).translate([0, 0, pcbThickness / 2 - padThickness / 2 + 0.05]);
30011
30108
  const bottomPad = createRoundedRectPrism({
30012
30109
  Manifold,
30013
30110
  width: padWidth,
30014
30111
  height: padHeight,
30015
- thickness: padThickness + 0.1,
30112
+ thickness: padThickness,
30016
30113
  borderRadius: rectBorderRadius
30017
30114
  }).translate([0, 0, -pcbThickness / 2 + padThickness / 2 - 0.05]);
30018
30115
  manifoldInstancesForCleanup.push(topPad, bottomPad);
@@ -30054,6 +30151,7 @@ function processPlatedHolesForManifold(Manifold, circuitJson, pcbThickness, mani
30054
30151
  manifoldInstancesForCleanup.push(clipped);
30055
30152
  finalCopperOp = clipped;
30056
30153
  }
30154
+ platedHoleCopperOpsForSubtract.push(finalCopperOp);
30057
30155
  const threeGeom = manifoldMeshToThreeGeometry(finalCopperOp.getMesh());
30058
30156
  platedHoleCopperGeoms.push({
30059
30157
  key: `ph-${ph.pcb_plated_hole_id || index}`,
@@ -30062,7 +30160,12 @@ function processPlatedHolesForManifold(Manifold, circuitJson, pcbThickness, mani
30062
30160
  });
30063
30161
  }
30064
30162
  });
30065
- return { platedHoleBoardDrills, platedHoleCopperGeoms };
30163
+ let platedHoleSubtractOp = void 0;
30164
+ if (platedHoleCopperOpsForSubtract.length > 0) {
30165
+ platedHoleSubtractOp = Manifold.union(platedHoleCopperOpsForSubtract);
30166
+ manifoldInstancesForCleanup.push(platedHoleSubtractOp);
30167
+ }
30168
+ return { platedHoleBoardDrills, platedHoleCopperGeoms, platedHoleSubtractOp };
30066
30169
  }
30067
30170
 
30068
30171
  // src/utils/manifold/process-vias.ts
@@ -30182,7 +30285,7 @@ function processSmtPadsForManifold(Manifold, circuitJson, pcbThickness, manifold
30182
30285
  }
30183
30286
  const threeGeom = manifoldMeshToThreeGeometry(finalPadOp.getMesh());
30184
30287
  smtPadGeoms.push({
30185
- key: `pad-${pad2.pcb_smtpad_id || index}`,
30288
+ key: `smt_pad-${pad2.layer || "top"}-${pad2.pcb_smtpad_id || index}`,
30186
30289
  geometry: threeGeom,
30187
30290
  color: COPPER_COLOR3
30188
30291
  });
@@ -30521,20 +30624,20 @@ function processCutoutsForManifold(Manifold, CrossSection, circuitJson, pcbThick
30521
30624
 
30522
30625
  // src/hooks/useManifoldBoardBuilder.ts
30523
30626
  var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
30524
- const [geoms, setGeoms] = useState13(null);
30525
- const [textures, setTextures] = useState13(null);
30526
- const [pcbThickness, setPcbThickness] = useState13(null);
30527
- const [error, setError] = useState13(null);
30528
- const [isLoading, setIsLoading] = useState13(true);
30627
+ const [geoms, setGeoms] = useState14(null);
30628
+ const [textures, setTextures] = useState14(null);
30629
+ const [pcbThickness, setPcbThickness] = useState14(null);
30630
+ const [error, setError] = useState14(null);
30631
+ const [isLoading, setIsLoading] = useState14(true);
30529
30632
  const manifoldInstancesForCleanup = useRef7([]);
30530
- const boardData = useMemo18(() => {
30633
+ const boardData = useMemo19(() => {
30531
30634
  const boards = su12(circuitJson).pcb_board.list();
30532
30635
  if (boards.length === 0) {
30533
30636
  return null;
30534
30637
  }
30535
30638
  return boards[0];
30536
30639
  }, [circuitJson]);
30537
- useEffect20(() => {
30640
+ useEffect21(() => {
30538
30641
  if (!manifoldJSModule || !boardData) {
30539
30642
  setGeoms(null);
30540
30643
  setTextures(null);
@@ -30615,7 +30718,12 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
30615
30718
  manifoldInstancesForCleanup.current
30616
30719
  );
30617
30720
  allBoardDrills.push(...nonPlatedHoleBoardDrills);
30618
- const { platedHoleBoardDrills, platedHoleCopperGeoms } = processPlatedHolesForManifold(
30721
+ const {
30722
+ platedHoleBoardDrills,
30723
+ platedHoleCopperGeoms,
30724
+ // NEW: bring in platedHoleSubtractOp
30725
+ platedHoleSubtractOp
30726
+ } = processPlatedHolesForManifold(
30619
30727
  Manifold,
30620
30728
  circuitJson,
30621
30729
  currentPcbThickness,
@@ -30636,9 +30744,28 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
30636
30744
  if (allBoardDrills.length > 0) {
30637
30745
  holeUnion = Manifold.union(allBoardDrills);
30638
30746
  manifoldInstancesForCleanup.current.push(holeUnion);
30639
- const nextBoardAfterDrills = currentBoardOp.subtract(holeUnion);
30747
+ const totalSubtractionOps = platedHoleSubtractOp ? Manifold.union([holeUnion, platedHoleSubtractOp]) : holeUnion;
30748
+ manifoldInstancesForCleanup.current.push(totalSubtractionOps);
30749
+ const nextBoardAfterDrills = currentBoardOp.subtract(totalSubtractionOps);
30640
30750
  manifoldInstancesForCleanup.current.push(nextBoardAfterDrills);
30641
30751
  currentBoardOp = nextBoardAfterDrills;
30752
+ if (platedHoleSubtractOp) {
30753
+ const cutPlatedCopper = platedHoleSubtractOp.subtract(holeUnion);
30754
+ manifoldInstancesForCleanup.current.push(cutPlatedCopper);
30755
+ const cutPlatedMesh = cutPlatedCopper.getMesh();
30756
+ const cutPlatedGeom = manifoldMeshToThreeGeometry(cutPlatedMesh);
30757
+ currentGeoms.platedHoles = [
30758
+ {
30759
+ key: "plated-holes-union",
30760
+ geometry: cutPlatedGeom,
30761
+ color: new THREE23.Color(
30762
+ colors.copper[0],
30763
+ colors.copper[1],
30764
+ colors.copper[2]
30765
+ )
30766
+ }
30767
+ ];
30768
+ }
30642
30769
  }
30643
30770
  const { cutoutOps } = processCutoutsForManifold(
30644
30771
  Manifold,
@@ -30880,21 +31007,64 @@ function createTextureMeshes(textures, boardData, pcbThickness) {
30880
31007
  }
30881
31008
 
30882
31009
  // src/CadViewerManifold.tsx
30883
- import { jsx as jsx14, jsxs as jsxs7 } from "react/jsx-runtime";
31010
+ import { jsx as jsx16, jsxs as jsxs7 } from "react/jsx-runtime";
30884
31011
  var BoardMeshes = ({
30885
31012
  geometryMeshes,
30886
31013
  textureMeshes
30887
31014
  }) => {
30888
31015
  const { rootObject } = useThree();
30889
- useEffect21(() => {
31016
+ const { visibility } = useLayerVisibility();
31017
+ useEffect22(() => {
30890
31018
  if (!rootObject) return;
30891
- geometryMeshes.forEach((mesh) => rootObject.add(mesh));
30892
- textureMeshes.forEach((mesh) => rootObject.add(mesh));
31019
+ geometryMeshes.forEach((mesh) => {
31020
+ let shouldShow = true;
31021
+ if (mesh.name === "board-geom") {
31022
+ shouldShow = visibility.boardBody;
31023
+ } else if (mesh.name.includes("smt_pad")) {
31024
+ if (mesh.name.includes("smt_pad-top")) {
31025
+ shouldShow = visibility.topCopper;
31026
+ } else if (mesh.name.includes("smt_pad-bottom")) {
31027
+ shouldShow = visibility.bottomCopper;
31028
+ } else {
31029
+ shouldShow = visibility.topCopper || visibility.bottomCopper;
31030
+ }
31031
+ } else if (mesh.name.includes("plated_hole") || mesh.name.includes("via")) {
31032
+ shouldShow = visibility.topCopper || visibility.bottomCopper;
31033
+ } else if (mesh.name.includes("copper_pour")) {
31034
+ shouldShow = visibility.topCopper || visibility.bottomCopper;
31035
+ }
31036
+ if (shouldShow) {
31037
+ rootObject.add(mesh);
31038
+ }
31039
+ });
31040
+ textureMeshes.forEach((mesh) => {
31041
+ let shouldShow = true;
31042
+ if (mesh.name.includes("top-trace")) {
31043
+ shouldShow = visibility.topCopper;
31044
+ } else if (mesh.name.includes("bottom-trace")) {
31045
+ shouldShow = visibility.bottomCopper;
31046
+ } else if (mesh.name.includes("top-silkscreen")) {
31047
+ shouldShow = visibility.topSilkscreen;
31048
+ } else if (mesh.name.includes("bottom-silkscreen")) {
31049
+ shouldShow = visibility.bottomSilkscreen;
31050
+ }
31051
+ if (shouldShow) {
31052
+ rootObject.add(mesh);
31053
+ }
31054
+ });
30893
31055
  return () => {
30894
- geometryMeshes.forEach((mesh) => rootObject.remove(mesh));
30895
- textureMeshes.forEach((mesh) => rootObject.remove(mesh));
31056
+ geometryMeshes.forEach((mesh) => {
31057
+ if (mesh.parent === rootObject) {
31058
+ rootObject.remove(mesh);
31059
+ }
31060
+ });
31061
+ textureMeshes.forEach((mesh) => {
31062
+ if (mesh.parent === rootObject) {
31063
+ rootObject.remove(mesh);
31064
+ }
31065
+ });
30896
31066
  };
30897
- }, [rootObject, geometryMeshes, textureMeshes]);
31067
+ }, [rootObject, geometryMeshes, textureMeshes, visibility]);
30898
31068
  return null;
30899
31069
  };
30900
31070
  var MANIFOLD_CDN_BASE_URL = "https://cdn.jsdelivr.net/npm/manifold-3d@3.2.1";
@@ -30906,12 +31076,12 @@ var CadViewerManifold = ({
30906
31076
  children
30907
31077
  }) => {
30908
31078
  const childrenCircuitJson = useConvertChildrenToCircuitJson(children);
30909
- const circuitJson = useMemo19(() => {
31079
+ const circuitJson = useMemo20(() => {
30910
31080
  return circuitJsonProp ?? childrenCircuitJson;
30911
31081
  }, [circuitJsonProp, childrenCircuitJson]);
30912
- const [manifoldJSModule, setManifoldJSModule] = useState14(null);
30913
- const [manifoldLoadingError, setManifoldLoadingError] = useState14(null);
30914
- useEffect21(() => {
31082
+ const [manifoldJSModule, setManifoldJSModule] = useState15(null);
31083
+ const [manifoldLoadingError, setManifoldLoadingError] = useState15(null);
31084
+ useEffect22(() => {
30915
31085
  if (window.ManifoldModule && typeof window.ManifoldModule === "object" && window.ManifoldModule.setup) {
30916
31086
  setManifoldJSModule(window.ManifoldModule);
30917
31087
  return;
@@ -30981,27 +31151,27 @@ try {
30981
31151
  isLoading: builderIsLoading,
30982
31152
  boardData
30983
31153
  } = useManifoldBoardBuilder(manifoldJSModule, circuitJson);
30984
- const geometryMeshes = useMemo19(() => createGeometryMeshes(geoms), [geoms]);
30985
- const textureMeshes = useMemo19(
31154
+ const geometryMeshes = useMemo20(() => createGeometryMeshes(geoms), [geoms]);
31155
+ const textureMeshes = useMemo20(
30986
31156
  () => createTextureMeshes(textures, boardData, pcbThickness),
30987
31157
  [textures, boardData, pcbThickness]
30988
31158
  );
30989
- const cadComponents = useMemo19(
31159
+ const cadComponents = useMemo20(
30990
31160
  () => su13(circuitJson).cad_component.list(),
30991
31161
  [circuitJson]
30992
31162
  );
30993
- const boardDimensions = useMemo19(() => {
31163
+ const boardDimensions = useMemo20(() => {
30994
31164
  if (!boardData) return void 0;
30995
31165
  const { width: width10 = 0, height: height10 = 0 } = boardData;
30996
31166
  return { width: width10, height: height10 };
30997
31167
  }, [boardData]);
30998
- const boardCenter = useMemo19(() => {
31168
+ const boardCenter = useMemo20(() => {
30999
31169
  if (!boardData) return void 0;
31000
31170
  const { center } = boardData;
31001
31171
  if (!center) return void 0;
31002
31172
  return { x: center.x, y: center.y };
31003
31173
  }, [boardData]);
31004
- const initialCameraPosition = useMemo19(() => {
31174
+ const initialCameraPosition = useMemo20(() => {
31005
31175
  if (!boardData) return [5, 5, 5];
31006
31176
  const { width: width10 = 0, height: height10 = 0 } = boardData;
31007
31177
  const safeWidth = Math.max(width10, 1);
@@ -31027,7 +31197,7 @@ try {
31027
31197
  );
31028
31198
  }
31029
31199
  if (!manifoldJSModule) {
31030
- return /* @__PURE__ */ jsx14("div", { style: { padding: "1em" }, children: "Loading Manifold module..." });
31200
+ return /* @__PURE__ */ jsx16("div", { style: { padding: "1em" }, children: "Loading Manifold module..." });
31031
31201
  }
31032
31202
  if (builderError) {
31033
31203
  return /* @__PURE__ */ jsxs7(
@@ -31047,7 +31217,7 @@ try {
31047
31217
  );
31048
31218
  }
31049
31219
  if (builderIsLoading) {
31050
- return /* @__PURE__ */ jsx14("div", { style: { padding: "1em" }, children: "Processing board geometry..." });
31220
+ return /* @__PURE__ */ jsx16("div", { style: { padding: "1em" }, children: "Processing board geometry..." });
31051
31221
  }
31052
31222
  return /* @__PURE__ */ jsxs7(
31053
31223
  CadViewerContainer,
@@ -31059,18 +31229,18 @@ try {
31059
31229
  boardCenter,
31060
31230
  onUserInteraction,
31061
31231
  children: [
31062
- /* @__PURE__ */ jsx14(
31232
+ /* @__PURE__ */ jsx16(
31063
31233
  BoardMeshes,
31064
31234
  {
31065
31235
  geometryMeshes,
31066
31236
  textureMeshes
31067
31237
  }
31068
31238
  ),
31069
- cadComponents.map((cad_component2) => /* @__PURE__ */ jsx14(
31239
+ cadComponents.map((cad_component2) => /* @__PURE__ */ jsx16(
31070
31240
  ThreeErrorBoundary,
31071
31241
  {
31072
- fallback: ({ error }) => /* @__PURE__ */ jsx14(Error3d, { cad_component: cad_component2, error }),
31073
- children: /* @__PURE__ */ jsx14(
31242
+ fallback: ({ error }) => /* @__PURE__ */ jsx16(Error3d, { cad_component: cad_component2, error }),
31243
+ children: /* @__PURE__ */ jsx16(
31074
31244
  AnyCadComponent,
31075
31245
  {
31076
31246
  cad_component: cad_component2,
@@ -31087,10 +31257,10 @@ try {
31087
31257
  var CadViewerManifold_default = CadViewerManifold;
31088
31258
 
31089
31259
  // src/hooks/useContextMenu.ts
31090
- import { useState as useState15, useCallback as useCallback6, useRef as useRef8, useEffect as useEffect22 } from "react";
31260
+ import { useState as useState16, useCallback as useCallback7, useRef as useRef8, useEffect as useEffect23 } from "react";
31091
31261
  var useContextMenu = ({ containerRef }) => {
31092
- const [menuVisible, setMenuVisible] = useState15(false);
31093
- const [menuPos, setMenuPos] = useState15({
31262
+ const [menuVisible, setMenuVisible] = useState16(false);
31263
+ const [menuPos, setMenuPos] = useState16({
31094
31264
  x: 0,
31095
31265
  y: 0
31096
31266
  });
@@ -31104,7 +31274,7 @@ var useContextMenu = ({ containerRef }) => {
31104
31274
  longPressTimeoutRef.current = null;
31105
31275
  }
31106
31276
  };
31107
- const handleContextMenu = useCallback6(
31277
+ const handleContextMenu = useCallback7(
31108
31278
  (e) => {
31109
31279
  e.preventDefault();
31110
31280
  const eventX = typeof e.clientX === "number" ? e.clientX : 0;
@@ -31130,7 +31300,7 @@ var useContextMenu = ({ containerRef }) => {
31130
31300
  },
31131
31301
  [setMenuPos, setMenuVisible]
31132
31302
  );
31133
- const handleTouchStart = useCallback6(
31303
+ const handleTouchStart = useCallback7(
31134
31304
  (e) => {
31135
31305
  if (e.touches.length === 1) {
31136
31306
  const touch = e.touches[0];
@@ -31163,7 +31333,7 @@ var useContextMenu = ({ containerRef }) => {
31163
31333
  },
31164
31334
  [containerRef]
31165
31335
  );
31166
- const handleTouchMove = useCallback6((e) => {
31336
+ const handleTouchMove = useCallback7((e) => {
31167
31337
  if (!interactionOriginPosRef.current || e.touches.length !== 1) {
31168
31338
  return;
31169
31339
  }
@@ -31181,7 +31351,7 @@ var useContextMenu = ({ containerRef }) => {
31181
31351
  clearLongPressTimeout();
31182
31352
  }
31183
31353
  }, []);
31184
- const handleTouchEnd = useCallback6(() => {
31354
+ const handleTouchEnd = useCallback7(() => {
31185
31355
  clearLongPressTimeout();
31186
31356
  setTimeout(() => {
31187
31357
  if (interactionOriginPosRef.current) {
@@ -31189,13 +31359,13 @@ var useContextMenu = ({ containerRef }) => {
31189
31359
  }
31190
31360
  }, 0);
31191
31361
  }, []);
31192
- const handleClickAway = useCallback6((e) => {
31362
+ const handleClickAway = useCallback7((e) => {
31193
31363
  const target = e.target;
31194
31364
  if (menuRef.current && !menuRef.current.contains(target)) {
31195
31365
  setMenuVisible(false);
31196
31366
  }
31197
31367
  }, []);
31198
- useEffect22(() => {
31368
+ useEffect23(() => {
31199
31369
  if (menuVisible) {
31200
31370
  document.addEventListener("mousedown", handleClickAway);
31201
31371
  document.addEventListener("touchstart", handleClickAway);
@@ -31229,10 +31399,10 @@ var useContextMenu = ({ containerRef }) => {
31229
31399
  };
31230
31400
 
31231
31401
  // src/hooks/useGlobalDownloadGltf.ts
31232
- import { useCallback as useCallback7 } from "react";
31402
+ import { useCallback as useCallback8 } from "react";
31233
31403
  import { GLTFExporter } from "three-stdlib";
31234
31404
  var useGlobalDownloadGltf = () => {
31235
- return useCallback7(() => {
31405
+ return useCallback8(() => {
31236
31406
  const root = window.__TSCIRCUIT_THREE_OBJECT;
31237
31407
  if (!root) return;
31238
31408
  const exporter = new GLTFExporter();
@@ -31257,13 +31427,190 @@ var useGlobalDownloadGltf = () => {
31257
31427
  }, []);
31258
31428
  };
31259
31429
 
31430
+ // src/components/AppearanceMenu.tsx
31431
+ import { useState as useState17 } from "react";
31432
+ import { Fragment as Fragment6, jsx as jsx17, jsxs as jsxs8 } from "react/jsx-runtime";
31433
+ var menuItemStyle = {
31434
+ padding: "8px 18px",
31435
+ cursor: "pointer",
31436
+ display: "flex",
31437
+ alignItems: "center",
31438
+ gap: 10,
31439
+ color: "#f5f6fa",
31440
+ fontWeight: 400,
31441
+ fontSize: 14,
31442
+ transition: "background 0.1s"
31443
+ };
31444
+ var checkmarkStyle = {
31445
+ width: 20
31446
+ };
31447
+ var handleMouseOver = (e) => {
31448
+ e.currentTarget.style.background = "#2d313a";
31449
+ };
31450
+ var handleMouseOut = (e) => {
31451
+ e.currentTarget.style.background = "transparent";
31452
+ };
31453
+ var AppearanceMenu = () => {
31454
+ const { visibility, toggleLayer } = useLayerVisibility();
31455
+ const [showSubmenu, setShowSubmenu] = useState17(false);
31456
+ return /* @__PURE__ */ jsxs8(Fragment6, { children: [
31457
+ /* @__PURE__ */ jsx17(
31458
+ "div",
31459
+ {
31460
+ style: {
31461
+ borderTop: "1px solid rgba(255, 255, 255, 0.1)",
31462
+ margin: "8px 0"
31463
+ }
31464
+ }
31465
+ ),
31466
+ /* @__PURE__ */ jsxs8(
31467
+ "div",
31468
+ {
31469
+ style: {
31470
+ padding: "8px 18px",
31471
+ fontSize: 14,
31472
+ color: "#f5f6fa",
31473
+ fontWeight: 400,
31474
+ cursor: "pointer",
31475
+ display: "flex",
31476
+ alignItems: "center",
31477
+ justifyContent: "space-between",
31478
+ transition: "background 0.1s",
31479
+ position: "relative"
31480
+ },
31481
+ onMouseEnter: () => setShowSubmenu(true),
31482
+ onMouseLeave: () => setShowSubmenu(false),
31483
+ onMouseOver: handleMouseOver,
31484
+ onMouseOut: handleMouseOut,
31485
+ children: [
31486
+ /* @__PURE__ */ jsx17("span", { children: "Appearance" }),
31487
+ /* @__PURE__ */ jsx17(
31488
+ "span",
31489
+ {
31490
+ style: {
31491
+ fontSize: 10,
31492
+ transform: showSubmenu ? "rotate(90deg)" : "rotate(0deg)",
31493
+ transition: "transform 0.2s",
31494
+ display: "inline-block"
31495
+ },
31496
+ children: "\u25B6"
31497
+ }
31498
+ ),
31499
+ showSubmenu && /* @__PURE__ */ jsxs8(
31500
+ "div",
31501
+ {
31502
+ style: {
31503
+ position: "absolute",
31504
+ left: "100%",
31505
+ top: 0,
31506
+ minWidth: 200,
31507
+ background: "#23272f",
31508
+ border: "1px solid rgba(255, 255, 255, 0.1)",
31509
+ borderRadius: 6,
31510
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.4)",
31511
+ zIndex: 1e3,
31512
+ marginTop: 8,
31513
+ marginBottom: 8
31514
+ },
31515
+ onMouseEnter: () => setShowSubmenu(true),
31516
+ onMouseLeave: () => setShowSubmenu(false),
31517
+ onClick: (e) => e.stopPropagation(),
31518
+ children: [
31519
+ /* @__PURE__ */ jsxs8(
31520
+ "div",
31521
+ {
31522
+ style: menuItemStyle,
31523
+ onClick: () => toggleLayer("boardBody"),
31524
+ onMouseOver: handleMouseOver,
31525
+ onMouseOut: handleMouseOut,
31526
+ children: [
31527
+ /* @__PURE__ */ jsx17("span", { style: checkmarkStyle, children: visibility.boardBody ? "\u2714" : "" }),
31528
+ "Board Body"
31529
+ ]
31530
+ }
31531
+ ),
31532
+ /* @__PURE__ */ jsxs8(
31533
+ "div",
31534
+ {
31535
+ style: menuItemStyle,
31536
+ onClick: () => toggleLayer("topCopper"),
31537
+ onMouseOver: handleMouseOver,
31538
+ onMouseOut: handleMouseOut,
31539
+ children: [
31540
+ /* @__PURE__ */ jsx17("span", { style: checkmarkStyle, children: visibility.topCopper ? "\u2714" : "" }),
31541
+ "Top Copper"
31542
+ ]
31543
+ }
31544
+ ),
31545
+ /* @__PURE__ */ jsxs8(
31546
+ "div",
31547
+ {
31548
+ style: menuItemStyle,
31549
+ onClick: () => toggleLayer("bottomCopper"),
31550
+ onMouseOver: handleMouseOver,
31551
+ onMouseOut: handleMouseOut,
31552
+ children: [
31553
+ /* @__PURE__ */ jsx17("span", { style: checkmarkStyle, children: visibility.bottomCopper ? "\u2714" : "" }),
31554
+ "Bottom Copper"
31555
+ ]
31556
+ }
31557
+ ),
31558
+ /* @__PURE__ */ jsxs8(
31559
+ "div",
31560
+ {
31561
+ style: menuItemStyle,
31562
+ onClick: () => toggleLayer("topSilkscreen"),
31563
+ onMouseOver: handleMouseOver,
31564
+ onMouseOut: handleMouseOut,
31565
+ children: [
31566
+ /* @__PURE__ */ jsx17("span", { style: checkmarkStyle, children: visibility.topSilkscreen ? "\u2714" : "" }),
31567
+ "Top Silkscreen"
31568
+ ]
31569
+ }
31570
+ ),
31571
+ /* @__PURE__ */ jsxs8(
31572
+ "div",
31573
+ {
31574
+ style: menuItemStyle,
31575
+ onClick: () => toggleLayer("bottomSilkscreen"),
31576
+ onMouseOver: handleMouseOver,
31577
+ onMouseOut: handleMouseOut,
31578
+ children: [
31579
+ /* @__PURE__ */ jsx17("span", { style: checkmarkStyle, children: visibility.bottomSilkscreen ? "\u2714" : "" }),
31580
+ "Bottom Silkscreen"
31581
+ ]
31582
+ }
31583
+ ),
31584
+ /* @__PURE__ */ jsxs8(
31585
+ "div",
31586
+ {
31587
+ style: menuItemStyle,
31588
+ onClick: () => toggleLayer("smtModels"),
31589
+ onMouseOver: handleMouseOver,
31590
+ onMouseOut: handleMouseOut,
31591
+ children: [
31592
+ /* @__PURE__ */ jsx17("span", { style: checkmarkStyle, children: visibility.smtModels ? "\u2714" : "" }),
31593
+ "CAD Models"
31594
+ ]
31595
+ }
31596
+ )
31597
+ ]
31598
+ }
31599
+ )
31600
+ ]
31601
+ }
31602
+ )
31603
+ ] });
31604
+ };
31605
+
31260
31606
  // src/CadViewer.tsx
31261
- import { jsx as jsx15, jsxs as jsxs8 } from "react/jsx-runtime";
31262
- var CadViewer = (props) => {
31263
- const [engine, setEngine] = useState16("manifold");
31607
+ import { jsx as jsx18, jsxs as jsxs9 } from "react/jsx-runtime";
31608
+ var CadViewerInner = (props) => {
31609
+ const [engine, setEngine] = useState18("manifold");
31264
31610
  const containerRef = useRef9(null);
31265
- const [autoRotate, setAutoRotate] = useState16(true);
31266
- const [autoRotateUserToggled, setAutoRotateUserToggled] = useState16(false);
31611
+ const [autoRotate, setAutoRotate] = useState18(true);
31612
+ const [autoRotateUserToggled, setAutoRotateUserToggled] = useState18(false);
31613
+ const { visibility, toggleLayer } = useLayerVisibility();
31267
31614
  const {
31268
31615
  menuVisible,
31269
31616
  menuPos,
@@ -31273,12 +31620,12 @@ var CadViewer = (props) => {
31273
31620
  } = useContextMenu({ containerRef });
31274
31621
  const autoRotateUserToggledRef = useRef9(autoRotateUserToggled);
31275
31622
  autoRotateUserToggledRef.current = autoRotateUserToggled;
31276
- const handleUserInteraction = useCallback8(() => {
31623
+ const handleUserInteraction = useCallback9(() => {
31277
31624
  if (!autoRotateUserToggledRef.current) {
31278
31625
  setAutoRotate(false);
31279
31626
  }
31280
31627
  }, []);
31281
- const toggleAutoRotate = useCallback8(() => {
31628
+ const toggleAutoRotate = useCallback9(() => {
31282
31629
  setAutoRotate((prev) => !prev);
31283
31630
  setAutoRotateUserToggled(true);
31284
31631
  }, []);
@@ -31287,17 +31634,17 @@ var CadViewer = (props) => {
31287
31634
  setEngine(newEngine);
31288
31635
  setMenuVisible(false);
31289
31636
  };
31290
- useEffect23(() => {
31637
+ useEffect24(() => {
31291
31638
  const stored = window.localStorage.getItem("cadViewerEngine");
31292
31639
  if (stored === "jscad" || stored === "manifold") {
31293
31640
  setEngine(stored);
31294
31641
  }
31295
31642
  }, []);
31296
- useEffect23(() => {
31643
+ useEffect24(() => {
31297
31644
  window.localStorage.setItem("cadViewerEngine", engine);
31298
31645
  }, [engine]);
31299
31646
  const viewerKey = props.circuitJson ? JSON.stringify(props.circuitJson) : void 0;
31300
- return /* @__PURE__ */ jsxs8(
31647
+ return /* @__PURE__ */ jsxs9(
31301
31648
  "div",
31302
31649
  {
31303
31650
  ref: containerRef,
@@ -31313,14 +31660,14 @@ var CadViewer = (props) => {
31313
31660
  },
31314
31661
  ...contextMenuEventHandlers,
31315
31662
  children: [
31316
- engine === "jscad" ? /* @__PURE__ */ jsx15(
31663
+ engine === "jscad" ? /* @__PURE__ */ jsx18(
31317
31664
  CadViewerJscad,
31318
31665
  {
31319
31666
  ...props,
31320
31667
  autoRotateDisabled: props.autoRotateDisabled || !autoRotate,
31321
31668
  onUserInteraction: handleUserInteraction
31322
31669
  }
31323
- ) : /* @__PURE__ */ jsx15(
31670
+ ) : /* @__PURE__ */ jsx18(
31324
31671
  CadViewerManifold_default,
31325
31672
  {
31326
31673
  ...props,
@@ -31328,7 +31675,7 @@ var CadViewer = (props) => {
31328
31675
  onUserInteraction: handleUserInteraction
31329
31676
  }
31330
31677
  ),
31331
- /* @__PURE__ */ jsxs8(
31678
+ /* @__PURE__ */ jsxs9(
31332
31679
  "div",
31333
31680
  {
31334
31681
  style: {
@@ -31345,11 +31692,11 @@ var CadViewer = (props) => {
31345
31692
  },
31346
31693
  children: [
31347
31694
  "Engine: ",
31348
- /* @__PURE__ */ jsx15("b", { children: engine === "jscad" ? "JSCAD" : "Manifold" })
31695
+ /* @__PURE__ */ jsx18("b", { children: engine === "jscad" ? "JSCAD" : "Manifold" })
31349
31696
  ]
31350
31697
  }
31351
31698
  ),
31352
- menuVisible && /* @__PURE__ */ jsxs8(
31699
+ menuVisible && /* @__PURE__ */ jsxs9(
31353
31700
  "div",
31354
31701
  {
31355
31702
  ref: menuRef,
@@ -31370,7 +31717,7 @@ var CadViewer = (props) => {
31370
31717
  transition: "opacity 0.1s"
31371
31718
  },
31372
31719
  children: [
31373
- /* @__PURE__ */ jsxs8(
31720
+ /* @__PURE__ */ jsxs9(
31374
31721
  "div",
31375
31722
  {
31376
31723
  style: {
@@ -31391,7 +31738,7 @@ var CadViewer = (props) => {
31391
31738
  "Switch to ",
31392
31739
  engine === "jscad" ? "Manifold" : "JSCAD",
31393
31740
  " Engine",
31394
- /* @__PURE__ */ jsx15(
31741
+ /* @__PURE__ */ jsx18(
31395
31742
  "span",
31396
31743
  {
31397
31744
  style: {
@@ -31406,7 +31753,7 @@ var CadViewer = (props) => {
31406
31753
  ]
31407
31754
  }
31408
31755
  ),
31409
- /* @__PURE__ */ jsxs8(
31756
+ /* @__PURE__ */ jsxs9(
31410
31757
  "div",
31411
31758
  {
31412
31759
  style: {
@@ -31427,12 +31774,12 @@ var CadViewer = (props) => {
31427
31774
  onMouseOver: (e) => e.currentTarget.style.background = "#2d313a",
31428
31775
  onMouseOut: (e) => e.currentTarget.style.background = "transparent",
31429
31776
  children: [
31430
- /* @__PURE__ */ jsx15("span", { style: { marginRight: 8 }, children: autoRotate ? "\u2714" : "" }),
31777
+ /* @__PURE__ */ jsx18("span", { style: { marginRight: 8 }, children: autoRotate ? "\u2714" : "" }),
31431
31778
  "Auto rotate"
31432
31779
  ]
31433
31780
  }
31434
31781
  ),
31435
- /* @__PURE__ */ jsx15(
31782
+ /* @__PURE__ */ jsx18(
31436
31783
  "div",
31437
31784
  {
31438
31785
  style: {
@@ -31455,7 +31802,8 @@ var CadViewer = (props) => {
31455
31802
  children: "Download GLTF"
31456
31803
  }
31457
31804
  ),
31458
- /* @__PURE__ */ jsx15(
31805
+ /* @__PURE__ */ jsx18(AppearanceMenu, {}),
31806
+ /* @__PURE__ */ jsx18(
31459
31807
  "div",
31460
31808
  {
31461
31809
  style: {
@@ -31465,7 +31813,7 @@ var CadViewer = (props) => {
31465
31813
  borderTop: "1px solid rgba(255, 255, 255, 0.1)",
31466
31814
  marginTop: "8px"
31467
31815
  },
31468
- children: /* @__PURE__ */ jsxs8(
31816
+ children: /* @__PURE__ */ jsxs9(
31469
31817
  "span",
31470
31818
  {
31471
31819
  style: {
@@ -31490,6 +31838,9 @@ var CadViewer = (props) => {
31490
31838
  viewerKey
31491
31839
  );
31492
31840
  };
31841
+ var CadViewer = (props) => {
31842
+ return /* @__PURE__ */ jsx18(LayerVisibilityProvider, { children: /* @__PURE__ */ jsx18(CadViewerInner, { ...props }) });
31843
+ };
31493
31844
 
31494
31845
  // src/convert-circuit-json-to-3d-svg.ts
31495
31846
  var import_debug = __toESM(require_browser(), 1);
@@ -31770,10 +32121,10 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
31770
32121
 
31771
32122
  // src/hooks/exporter/gltf.ts
31772
32123
  import { GLTFExporter as GLTFExporter2 } from "three-stdlib";
31773
- import { useEffect as useEffect24, useState as useState17, useMemo as useMemo20, useCallback as useCallback9 } from "react";
32124
+ import { useEffect as useEffect25, useState as useState19, useMemo as useMemo21, useCallback as useCallback10 } from "react";
31774
32125
  function useSaveGltfAs(options = {}) {
31775
32126
  const parse = useParser(options);
31776
- const link = useMemo20(() => document.createElement("a"), []);
32127
+ const link = useMemo21(() => document.createElement("a"), []);
31777
32128
  const saveAs = async (filename) => {
31778
32129
  const name = filename ?? options.filename ?? "";
31779
32130
  if (options.binary == null) options.binary = name.endsWith(".glb");
@@ -31783,7 +32134,7 @@ function useSaveGltfAs(options = {}) {
31783
32134
  link.dispatchEvent(new MouseEvent("click"));
31784
32135
  URL.revokeObjectURL(url);
31785
32136
  };
31786
- useEffect24(
32137
+ useEffect25(
31787
32138
  () => () => {
31788
32139
  link.remove();
31789
32140
  instance = null;
@@ -31791,24 +32142,24 @@ function useSaveGltfAs(options = {}) {
31791
32142
  []
31792
32143
  );
31793
32144
  let instance;
31794
- const ref = useCallback9((obj3D) => {
32145
+ const ref = useCallback10((obj3D) => {
31795
32146
  instance = obj3D;
31796
32147
  }, []);
31797
32148
  return [ref, saveAs];
31798
32149
  }
31799
32150
  function useExportGltfUrl(options = {}) {
31800
32151
  const parse = useParser(options);
31801
- const [url, setUrl] = useState17();
31802
- const [error, setError] = useState17();
31803
- const ref = useCallback9(
32152
+ const [url, setUrl] = useState19();
32153
+ const [error, setError] = useState19();
32154
+ const ref = useCallback10(
31804
32155
  (instance) => parse(instance).then(setUrl).catch(setError),
31805
32156
  []
31806
32157
  );
31807
- useEffect24(() => () => URL.revokeObjectURL(url), [url]);
32158
+ useEffect25(() => () => URL.revokeObjectURL(url), [url]);
31808
32159
  return [ref, url, error];
31809
32160
  }
31810
32161
  function useParser(options = {}) {
31811
- const exporter = useMemo20(() => new GLTFExporter2(), []);
32162
+ const exporter = useMemo21(() => new GLTFExporter2(), []);
31812
32163
  return (instance) => {
31813
32164
  const { promise, resolve, reject } = Promise.withResolvers();
31814
32165
  exporter.parse(