@tscircuit/3d-viewer 0.0.644 → 0.0.645

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 +399 -235
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -19351,15 +19351,83 @@ function configureRuntimeFont() {
19351
19351
  }
19352
19352
 
19353
19353
  // src/CadViewer.tsx
19354
- import { useCallback as useCallback25, useContext as useContext13, useEffect as useEffect57, useRef as useRef30, useState as useState46 } from "react";
19354
+ import {
19355
+ useCallback as useCallback25,
19356
+ useContext as useContext13,
19357
+ useEffect as useEffect58,
19358
+ useMemo as useMemo41,
19359
+ useRef as useRef31,
19360
+ useState as useState47
19361
+ } from "react";
19355
19362
  import * as THREE64 from "three";
19356
19363
 
19357
19364
  // src/assembly-explosion/use-assembly-explosion.ts
19365
+ import { Circuit } from "@tscircuit/core";
19366
+ import { useEffect as useEffect2, useMemo as useMemo2, useState as useState3 } from "react";
19367
+
19368
+ // src/assembly-explosion/create-explosion-evaluator.ts
19358
19369
  import {
19359
- Circuit,
19360
19370
  getCircuitJsonAssemblyExplosion
19361
19371
  } from "@tscircuit/core";
19362
- import { useEffect as useEffect2, useMemo as useMemo2, useState as useState3 } from "react";
19372
+ function createExplosionEvaluator(assembled) {
19373
+ const motion = [];
19374
+ const visible = assembled.filter(
19375
+ (element) => element.type !== "cad_explosion_stage" && element.type !== "cad_explosion_move"
19376
+ );
19377
+ for (const element of assembled) {
19378
+ switch (element.type) {
19379
+ case "cad_component":
19380
+ motion.push({
19381
+ type: element.type,
19382
+ cad_component_id: element.cad_component_id,
19383
+ source_component_id: element.source_component_id,
19384
+ pcb_component_id: element.pcb_component_id,
19385
+ position: element.position,
19386
+ rotation: element.rotation,
19387
+ layer: element.layer,
19388
+ anchor_alignment: element.anchor_alignment,
19389
+ model_object_fit: element.model_object_fit
19390
+ });
19391
+ break;
19392
+ case "cad_reference_surface":
19393
+ motion.push(element);
19394
+ break;
19395
+ case "cad_explosion_stage":
19396
+ case "cad_explosion_move":
19397
+ motion.push(element);
19398
+ break;
19399
+ }
19400
+ }
19401
+ return (options) => {
19402
+ const view = getCircuitJsonAssemblyExplosion(motion, options);
19403
+ const positions = /* @__PURE__ */ new Map();
19404
+ const centers = /* @__PURE__ */ new Map();
19405
+ for (const element of view.circuitJson) {
19406
+ if (element.type === "cad_component")
19407
+ positions.set(element.cad_component_id, element.position);
19408
+ if (element.type === "cad_reference_surface")
19409
+ centers.set(element.cad_reference_surface_id, element.center);
19410
+ }
19411
+ return {
19412
+ ...view,
19413
+ circuitJson: visible.map((element) => {
19414
+ if (element.type === "cad_component")
19415
+ return {
19416
+ ...element,
19417
+ position: positions.get(element.cad_component_id)
19418
+ };
19419
+ if (element.type === "cad_reference_surface")
19420
+ return {
19421
+ ...element,
19422
+ center: centers.get(element.cad_reference_surface_id)
19423
+ };
19424
+ return element;
19425
+ })
19426
+ };
19427
+ };
19428
+ }
19429
+
19430
+ // src/assembly-explosion/use-assembly-explosion.ts
19363
19431
  var EMPTY = [];
19364
19432
  function useAssemblyExplosion(children, circuit, circuitJson) {
19365
19433
  const [rendered, setRendered] = useState3();
@@ -19399,7 +19467,8 @@ function useAssemblyExplosion(children, circuit, circuitJson) {
19399
19467
  const assembled = source.assembled;
19400
19468
  const authored = useMemo2(() => {
19401
19469
  try {
19402
- return { stages: getCircuitJsonAssemblyExplosion(assembled).stages };
19470
+ const evaluate2 = createExplosionEvaluator(assembled);
19471
+ return { stages: evaluate2().stages, evaluate: evaluate2 };
19403
19472
  } catch (error) {
19404
19473
  return {
19405
19474
  stages: [],
@@ -19410,12 +19479,13 @@ function useAssemblyExplosion(children, circuit, circuitJson) {
19410
19479
  const [selection, setSelection] = useState3({ source: assembled, amount: 0 });
19411
19480
  const amount = selection.source === assembled ? selection.amount : 0;
19412
19481
  const view = useMemo2(() => {
19413
- if (!authored.stages.length || amount === 0) return void 0;
19482
+ if (!authored.evaluate || !authored.stages.length || amount === 0)
19483
+ return void 0;
19414
19484
  const stageIndex = Math.min(
19415
19485
  Math.ceil(amount) - 1,
19416
19486
  authored.stages.length - 1
19417
19487
  );
19418
- return getCircuitJsonAssemblyExplosion(assembled, {
19488
+ return authored.evaluate({
19419
19489
  throughStageRef: authored.stages[stageIndex],
19420
19490
  stageProgress: amount - stageIndex
19421
19491
  });
@@ -19525,7 +19595,7 @@ function AssemblyExplosionScene() {
19525
19595
  }
19526
19596
 
19527
19597
  // src/assembly-explosion/AssemblyExplosionControl.tsx
19528
- import { useId } from "react";
19598
+ import { useEffect as useEffect4, useId, useRef, useState as useState4 } from "react";
19529
19599
  import { Fragment, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
19530
19600
  function AssemblyExplosionControl({
19531
19601
  stages,
@@ -19535,6 +19605,32 @@ function AssemblyExplosionControl({
19535
19605
  onClose
19536
19606
  }) {
19537
19607
  const id = useId();
19608
+ const [playing, setPlaying] = useState4(false);
19609
+ const [stageDuration, setStageDuration] = useState4(2);
19610
+ const playback = useRef({ amount, onChange });
19611
+ playback.current = { amount, onChange };
19612
+ useEffect4(() => {
19613
+ if (!playing || error || !stages.length) return;
19614
+ let frame;
19615
+ let previous = performance.now();
19616
+ const tick = (now) => {
19617
+ const next = Math.min(
19618
+ stages.length,
19619
+ playback.current.amount + (now - previous) / (stageDuration * 1e3)
19620
+ );
19621
+ previous = now;
19622
+ playback.current.amount = next;
19623
+ playback.current.onChange(next);
19624
+ if (next >= stages.length) setPlaying(false);
19625
+ else frame = requestAnimationFrame(tick);
19626
+ };
19627
+ frame = requestAnimationFrame(tick);
19628
+ return () => cancelAnimationFrame(frame);
19629
+ }, [playing, stageDuration, stages.length, error]);
19630
+ const seek = (value) => {
19631
+ setPlaying(false);
19632
+ onChange(value);
19633
+ };
19538
19634
  if (!stages.length && !error) return null;
19539
19635
  const stage = amount === 0 ? "Assembled" : stages[Math.ceil(amount) - 1];
19540
19636
  return /* @__PURE__ */ jsxs2(
@@ -19560,7 +19656,10 @@ function AssemblyExplosionControl({
19560
19656
  {
19561
19657
  type: "button",
19562
19658
  "aria-label": "Close exploded view",
19563
- onClick: onClose,
19659
+ onClick: () => {
19660
+ setPlaying(false);
19661
+ onClose();
19662
+ },
19564
19663
  style: { float: "right", marginLeft: 12 },
19565
19664
  children: "\xD7"
19566
19665
  }
@@ -19585,19 +19684,81 @@ function AssemblyExplosionControl({
19585
19684
  max: stages.length,
19586
19685
  step: 0.01,
19587
19686
  value: amount,
19588
- onChange: (event) => onChange(Number(event.target.value))
19687
+ onChange: (event) => seek(Number(event.target.value))
19589
19688
  }
19590
19689
  ),
19591
19690
  /* @__PURE__ */ jsx4(
19592
19691
  "button",
19593
19692
  {
19594
19693
  type: "button",
19595
- onClick: () => onChange(0),
19596
- disabled: amount === 0,
19694
+ onClick: () => seek(0),
19695
+ disabled: amount === 0 && !playing,
19597
19696
  children: "Reset"
19598
19697
  }
19599
19698
  )
19600
- ] })
19699
+ ] }),
19700
+ /* @__PURE__ */ jsxs2(
19701
+ "div",
19702
+ {
19703
+ style: {
19704
+ display: "flex",
19705
+ gap: 8,
19706
+ alignItems: "center",
19707
+ marginTop: 8,
19708
+ flexWrap: "wrap"
19709
+ },
19710
+ children: [
19711
+ /* @__PURE__ */ jsx4(
19712
+ "button",
19713
+ {
19714
+ type: "button",
19715
+ "aria-label": "Previous explosion stage",
19716
+ disabled: amount === 0,
19717
+ onClick: () => seek(Math.max(0, Math.ceil(amount) - 1)),
19718
+ children: "Previous"
19719
+ }
19720
+ ),
19721
+ /* @__PURE__ */ jsx4(
19722
+ "button",
19723
+ {
19724
+ type: "button",
19725
+ onClick: () => {
19726
+ if (!playing && amount >= stages.length) onChange(0);
19727
+ setPlaying(!playing);
19728
+ },
19729
+ children: playing ? "Pause" : amount >= stages.length ? "Replay" : "Play"
19730
+ }
19731
+ ),
19732
+ /* @__PURE__ */ jsx4(
19733
+ "button",
19734
+ {
19735
+ type: "button",
19736
+ "aria-label": "Next explosion stage",
19737
+ disabled: amount >= stages.length,
19738
+ onClick: () => seek(Math.min(stages.length, Math.floor(amount) + 1)),
19739
+ children: "Next"
19740
+ }
19741
+ ),
19742
+ /* @__PURE__ */ jsx4("label", { htmlFor: `${id}-duration`, children: "Seconds per stage" }),
19743
+ /* @__PURE__ */ jsx4(
19744
+ "input",
19745
+ {
19746
+ id: `${id}-duration`,
19747
+ type: "number",
19748
+ min: 0.1,
19749
+ step: 0.1,
19750
+ value: stageDuration,
19751
+ style: { width: 60 },
19752
+ onChange: (event) => {
19753
+ const value = Number(event.target.value);
19754
+ if (Number.isFinite(value) && value >= 0.1)
19755
+ setStageDuration(value);
19756
+ }
19757
+ }
19758
+ )
19759
+ ]
19760
+ }
19761
+ )
19601
19762
  ] })
19602
19763
  ]
19603
19764
  }
@@ -19626,13 +19787,13 @@ var getCadPcbContext = (cad, circuitJson) => {
19626
19787
 
19627
19788
  // src/AnyCadComponent.tsx
19628
19789
  import { su as su2 } from "@tscircuit/circuit-json-util";
19629
- import { useCallback as useCallback3, useEffect as useEffect14, useMemo as useMemo10, useState as useState11 } from "react";
19790
+ import { useCallback as useCallback3, useEffect as useEffect15, useMemo as useMemo10, useState as useState12 } from "react";
19630
19791
 
19631
19792
  // src/contexts/LayerVisibilityContext.tsx
19632
19793
  import {
19633
19794
  createContext as createContext5,
19634
19795
  useContext as useContext5,
19635
- useState as useState4,
19796
+ useState as useState5,
19636
19797
  useCallback,
19637
19798
  useMemo as useMemo4
19638
19799
  } from "react";
@@ -19669,7 +19830,7 @@ var defaultVisibility = {
19669
19830
  };
19670
19831
  var LayerVisibilityContext = createContext5(void 0);
19671
19832
  var LayerVisibilityProvider = ({ children }) => {
19672
- const [visibility, setVisibility] = useState4(defaultVisibility);
19833
+ const [visibility, setVisibility] = useState5(defaultVisibility);
19673
19834
  const setLayerVisibility = useCallback(
19674
19835
  (layer, visible) => {
19675
19836
  setVisibility((prev) => ({
@@ -19719,14 +19880,14 @@ function usePcbThickness(circuitJson) {
19719
19880
  }
19720
19881
 
19721
19882
  // src/react-three/Html.tsx
19722
- import { useRef, useEffect as useEffect5, useState as useState5 } from "react";
19883
+ import { useRef as useRef2, useEffect as useEffect6, useState as useState6 } from "react";
19723
19884
  import ReactDOM from "react-dom";
19724
19885
  import * as THREE6 from "three";
19725
19886
  var Html = ({ children, position, style }) => {
19726
19887
  const { camera, renderer } = useThree();
19727
- const el = useRef(document.createElement("div"));
19728
- const [portal, setPortal] = useState5(null);
19729
- useEffect5(() => {
19888
+ const el = useRef2(document.createElement("div"));
19889
+ const [portal, setPortal] = useState6(null);
19890
+ useEffect6(() => {
19730
19891
  const rendererNode = renderer?.domElement.parentNode;
19731
19892
  if (!rendererNode) return;
19732
19893
  if (rendererNode.style.position !== "relative" && rendererNode.style.position !== "absolute") {
@@ -19765,21 +19926,21 @@ import {
19765
19926
  convertCSGToThreeGeom,
19766
19927
  getJscadModelForFootprint
19767
19928
  } from "jscad-electronics/vanilla";
19768
- import { useMemo as useMemo7, useEffect as useEffect8 } from "react";
19929
+ import { useMemo as useMemo7, useEffect as useEffect9 } from "react";
19769
19930
  import * as THREE8 from "three";
19770
19931
 
19771
19932
  // src/ContainerWithTooltip.tsx
19772
- import { useEffect as useEffect7 } from "react";
19933
+ import { useEffect as useEffect8 } from "react";
19773
19934
 
19774
19935
  // src/react-three/HoverContext.tsx
19775
19936
  import {
19776
19937
  createContext as createContext6,
19777
19938
  useContext as useContext6,
19778
- useState as useState6,
19939
+ useState as useState7,
19779
19940
  useCallback as useCallback2,
19780
19941
  useMemo as useMemo6,
19781
- useEffect as useEffect6,
19782
- useRef as useRef2
19942
+ useEffect as useEffect7,
19943
+ useRef as useRef3
19783
19944
  } from "react";
19784
19945
  import * as THREE7 from "three";
19785
19946
  import { jsx as jsx6 } from "react/jsx-runtime";
@@ -19793,12 +19954,12 @@ var useHover = () => {
19793
19954
  };
19794
19955
  var HoverProvider = ({ children }) => {
19795
19956
  const { camera, renderer } = useThree();
19796
- const [hoverables, setHoverables] = useState6([]);
19957
+ const [hoverables, setHoverables] = useState7([]);
19797
19958
  const raycaster = useMemo6(() => new THREE7.Raycaster(), []);
19798
19959
  const mouse = useMemo6(() => new THREE7.Vector2(), []);
19799
- const hoverablesRef = useRef2(hoverables);
19960
+ const hoverablesRef = useRef3(hoverables);
19800
19961
  hoverablesRef.current = hoverables;
19801
- const hoveredObjectRef = useRef2(null);
19962
+ const hoveredObjectRef = useRef3(null);
19802
19963
  const addHoverable = useCallback2((hoverable) => {
19803
19964
  setHoverables((prev) => [...prev, hoverable]);
19804
19965
  }, []);
@@ -19881,7 +20042,7 @@ var HoverProvider = ({ children }) => {
19881
20042
  },
19882
20043
  [camera, renderer, raycaster, mouse, findHoverable]
19883
20044
  );
19884
- useEffect6(() => {
20045
+ useEffect7(() => {
19885
20046
  const domElement = renderer.domElement;
19886
20047
  domElement.addEventListener("mousemove", onMouseMove);
19887
20048
  return () => {
@@ -19908,7 +20069,7 @@ var ContainerWithTooltip = ({
19908
20069
  isHovered
19909
20070
  }) => {
19910
20071
  const { addHoverable, removeHoverable } = useHover();
19911
- useEffect7(() => {
20072
+ useEffect8(() => {
19912
20073
  if (!object) return;
19913
20074
  const hoverable = {
19914
20075
  object,
@@ -19967,14 +20128,14 @@ var FootprinterModel = ({
19967
20128
  }
19968
20129
  return group2;
19969
20130
  }, [footprint, isTranslucent]);
19970
- useEffect8(() => {
20131
+ useEffect9(() => {
19971
20132
  if (!group || !rootObject) return;
19972
20133
  rootObject.add(group);
19973
20134
  return () => {
19974
20135
  rootObject.remove(group);
19975
20136
  };
19976
20137
  }, [rootObject, group]);
19977
- useEffect8(() => {
20138
+ useEffect9(() => {
19978
20139
  if (!group) return;
19979
20140
  if (positionOffset) group.position.fromArray(positionOffset);
19980
20141
  if (rotationOffset) group.rotation.fromArray(rotationOffset);
@@ -19989,7 +20150,7 @@ var FootprinterModel = ({
19989
20150
  rotationOffset?.[2],
19990
20151
  scale11
19991
20152
  ]);
19992
- useEffect8(() => {
20153
+ useEffect9(() => {
19993
20154
  if (!group) return;
19994
20155
  group.traverse((child) => {
19995
20156
  if (child instanceof THREE8.Mesh && child.material instanceof THREE8.MeshStandardMaterial) {
@@ -20015,7 +20176,7 @@ var FootprinterModel = ({
20015
20176
  };
20016
20177
 
20017
20178
  // src/three-components/GltfModel.tsx
20018
- import { useState as useState7, useEffect as useEffect10 } from "react";
20179
+ import { useState as useState8, useEffect as useEffect11 } from "react";
20019
20180
  import * as THREE12 from "three";
20020
20181
  import { GLTFLoader as GLTFLoader2 } from "three-stdlib";
20021
20182
 
@@ -20047,7 +20208,7 @@ var getDefaultEnvironmentMap = (renderer) => {
20047
20208
  };
20048
20209
 
20049
20210
  // src/three-components/useCadModelTransformGraph.ts
20050
- import { useEffect as useEffect9, useMemo as useMemo8 } from "react";
20211
+ import { useEffect as useEffect10, useMemo as useMemo8 } from "react";
20051
20212
  import * as THREE11 from "three";
20052
20213
 
20053
20214
  // src/utils/cad-model-fit.ts
@@ -20119,25 +20280,25 @@ var useCadModelTransformGraph = ({
20119
20280
  const fitTransformGroup = useMemo8(() => new THREE11.Group(), []);
20120
20281
  const modelTransformGroup = useMemo8(() => new THREE11.Group(), []);
20121
20282
  const loaderTransformGroup = useMemo8(() => new THREE11.Group(), []);
20122
- useEffect9(() => {
20283
+ useEffect10(() => {
20123
20284
  boardTransformGroup.add(fitTransformGroup);
20124
20285
  return () => {
20125
20286
  boardTransformGroup.remove(fitTransformGroup);
20126
20287
  };
20127
20288
  }, [boardTransformGroup, fitTransformGroup]);
20128
- useEffect9(() => {
20289
+ useEffect10(() => {
20129
20290
  fitTransformGroup.add(modelTransformGroup);
20130
20291
  return () => {
20131
20292
  fitTransformGroup.remove(modelTransformGroup);
20132
20293
  };
20133
20294
  }, [fitTransformGroup, modelTransformGroup]);
20134
- useEffect9(() => {
20295
+ useEffect10(() => {
20135
20296
  modelTransformGroup.add(loaderTransformGroup);
20136
20297
  return () => {
20137
20298
  modelTransformGroup.remove(loaderTransformGroup);
20138
20299
  };
20139
20300
  }, [modelTransformGroup, loaderTransformGroup]);
20140
- useEffect9(() => {
20301
+ useEffect10(() => {
20141
20302
  while (loaderTransformGroup.children.length > 0) {
20142
20303
  const firstChild = loaderTransformGroup.children[0];
20143
20304
  if (!firstChild) break;
@@ -20147,7 +20308,7 @@ var useCadModelTransformGraph = ({
20147
20308
  loaderTransformGroup.add(model);
20148
20309
  }
20149
20310
  }, [loaderTransformGroup, model]);
20150
- useEffect9(() => {
20311
+ useEffect10(() => {
20151
20312
  if (!sourceCoordinateTransform) {
20152
20313
  loaderTransformGroup.matrixAutoUpdate = true;
20153
20314
  loaderTransformGroup.position.set(0, 0, 0);
@@ -20160,14 +20321,14 @@ var useCadModelTransformGraph = ({
20160
20321
  loaderTransformGroup.matrix.copy(sourceCoordinateTransform);
20161
20322
  loaderTransformGroup.matrixWorldNeedsUpdate = true;
20162
20323
  }, [loaderTransformGroup, sourceCoordinateTransform]);
20163
- useEffect9(() => {
20324
+ useEffect10(() => {
20164
20325
  if (!rootObject) return;
20165
20326
  rootObject.add(boardTransformGroup);
20166
20327
  return () => {
20167
20328
  rootObject.remove(boardTransformGroup);
20168
20329
  };
20169
20330
  }, [rootObject, boardTransformGroup]);
20170
- useEffect9(() => {
20331
+ useEffect10(() => {
20171
20332
  if (position) {
20172
20333
  boardTransformGroup.position.fromArray(position);
20173
20334
  } else {
@@ -20229,8 +20390,8 @@ function GltfModel({
20229
20390
  isTranslucent = false
20230
20391
  }) {
20231
20392
  const { renderer } = useThree();
20232
- const [model, setModel] = useState7(null);
20233
- const [loadError, setLoadError] = useState7(null);
20393
+ const [model, setModel] = useState8(null);
20394
+ const [loadError, setLoadError] = useState8(null);
20234
20395
  const { boardTransformGroup } = useCadModelTransformGraph({
20235
20396
  model,
20236
20397
  position,
@@ -20242,7 +20403,7 @@ function GltfModel({
20242
20403
  modelFitMode,
20243
20404
  scale: scale11
20244
20405
  });
20245
- useEffect10(() => {
20406
+ useEffect11(() => {
20246
20407
  if (!gltfUrl) return;
20247
20408
  const loader = new GLTFLoader2();
20248
20409
  let isMounted = true;
@@ -20285,7 +20446,7 @@ function GltfModel({
20285
20446
  isMounted = false;
20286
20447
  };
20287
20448
  }, [gltfUrl, isTranslucent]);
20288
- useEffect10(() => {
20449
+ useEffect11(() => {
20289
20450
  if (!model || !renderer) return;
20290
20451
  const environmentMap = getDefaultEnvironmentMap(renderer);
20291
20452
  if (!environmentMap) return;
@@ -20320,7 +20481,7 @@ function GltfModel({
20320
20481
  });
20321
20482
  };
20322
20483
  }, [model, renderer]);
20323
- useEffect10(() => {
20484
+ useEffect11(() => {
20324
20485
  if (!model) return;
20325
20486
  model.traverse((child) => {
20326
20487
  if (!(child instanceof THREE12.Mesh)) return;
@@ -20356,7 +20517,7 @@ var import_jscad_planner = __toESM(require_dist(), 1);
20356
20517
  var import_modeling = __toESM(require_src(), 1);
20357
20518
  import { convertCSGToThreeGeom as convertCSGToThreeGeom2 } from "jscad-electronics/vanilla";
20358
20519
  import * as THREE13 from "three";
20359
- import { useState as useState8, useEffect as useEffect11 } from "react";
20520
+ import { useState as useState9, useEffect as useEffect12 } from "react";
20360
20521
  import { jsx as jsx10 } from "react/jsx-runtime";
20361
20522
  var JscadModel = ({
20362
20523
  jscadPlan,
@@ -20374,8 +20535,8 @@ var JscadModel = ({
20374
20535
  scale: scale11,
20375
20536
  isTranslucent = false
20376
20537
  }) => {
20377
- const [mesh, setMesh] = useState8(null);
20378
- useEffect11(() => {
20538
+ const [mesh, setMesh] = useState9(null);
20539
+ useEffect12(() => {
20379
20540
  const jscadObject = (0, import_jscad_planner.executeJscadOperations)(import_modeling.default, jscadPlan);
20380
20541
  if (!jscadObject || !jscadObject.polygons && !jscadObject.sides) {
20381
20542
  setMesh(null);
@@ -20393,7 +20554,7 @@ var JscadModel = ({
20393
20554
  material2.dispose();
20394
20555
  };
20395
20556
  }, [jscadPlan]);
20396
- useEffect11(() => {
20557
+ useEffect12(() => {
20397
20558
  if (!mesh) return;
20398
20559
  const material2 = mesh.material;
20399
20560
  material2.color.set(color ?? "#ffffff");
@@ -20420,7 +20581,7 @@ var JscadModel = ({
20420
20581
  modelFitMode,
20421
20582
  scale: scale11
20422
20583
  });
20423
- useEffect11(() => {
20584
+ useEffect12(() => {
20424
20585
  if (!material) return;
20425
20586
  if (isHovered) {
20426
20587
  const color2 = new THREE13.Color(material.color.getHex());
@@ -20444,7 +20605,7 @@ var JscadModel = ({
20444
20605
  };
20445
20606
 
20446
20607
  // src/hooks/use-global-model-loader.ts
20447
- import { useEffect as useEffect12, useState as useState9 } from "react";
20608
+ import { useEffect as useEffect13, useState as useState10 } from "react";
20448
20609
 
20449
20610
  // src/utils/vrml.ts
20450
20611
  import { VRMLLoader } from "three-stdlib";
@@ -20472,8 +20633,8 @@ if (typeof window !== "undefined" && !window.TSCIRCUIT_MODEL_LOADER_CACHE) {
20472
20633
  window.TSCIRCUIT_MODEL_LOADER_CACHE = /* @__PURE__ */ new Map();
20473
20634
  }
20474
20635
  function useGlobalModelLoader(url, modelType) {
20475
- const [obj, setObj] = useState9(null);
20476
- useEffect12(() => {
20636
+ const [obj, setObj] = useState10(null);
20637
+ useEffect13(() => {
20477
20638
  if (!url) return;
20478
20639
  const cleanUrl = url.replace(/&cachebust_origin=$/, "");
20479
20640
  const cachesByModelType = window.TSCIRCUIT_MODEL_LOADER_CACHE;
@@ -20634,7 +20795,7 @@ function MixedStlModel({
20634
20795
  }
20635
20796
 
20636
20797
  // src/three-components/StepModel.tsx
20637
- import { useEffect as useEffect13, useState as useState10 } from "react";
20798
+ import { useEffect as useEffect14, useState as useState11 } from "react";
20638
20799
  import { GLTFExporter } from "three-stdlib";
20639
20800
 
20640
20801
  // src/three-components/step-mesh-to-group.ts
@@ -20853,8 +21014,8 @@ var StepModel = ({
20853
21014
  isHovered,
20854
21015
  isTranslucent
20855
21016
  }) => {
20856
- const [stepGltfUrl, setStepGltfUrl] = useState10(null);
20857
- useEffect13(() => {
21017
+ const [stepGltfUrl, setStepGltfUrl] = useState11(null);
21018
+ useEffect14(() => {
20858
21019
  let isActive = true;
20859
21020
  let objectUrl = null;
20860
21021
  let shouldRevokeObjectUrl = true;
@@ -21280,7 +21441,7 @@ var ModelLoadErrorReporter = ({
21280
21441
  error,
21281
21442
  onError
21282
21443
  }) => {
21283
- useEffect14(() => {
21444
+ useEffect15(() => {
21284
21445
  onError(error);
21285
21446
  }, [error, onError]);
21286
21447
  return null;
@@ -21291,9 +21452,9 @@ var AnyCadComponent = ({
21291
21452
  resolveStaticAsset
21292
21453
  }) => {
21293
21454
  const pcbThickness = usePcbThickness(circuitJson);
21294
- const [isHovered, setIsHovered] = useState11(false);
21455
+ const [isHovered, setIsHovered] = useState12(false);
21295
21456
  const { visibility } = useLayerVisibility();
21296
- const [hoverPosition, setHoverPosition] = useState11(null);
21457
+ const [hoverPosition, setHoverPosition] = useState12(null);
21297
21458
  const handleHover = useCallback3((e) => {
21298
21459
  if (e?.mousePosition) {
21299
21460
  setIsHovered(true);
@@ -21329,9 +21490,9 @@ var AnyCadComponent = ({
21329
21490
  const stepUrl = resolveModelUrlWithStaticResolver(
21330
21491
  cad_component.model_step_url
21331
21492
  );
21332
- const [fallbackModelIndex, setFallbackModelIndex] = useState11(0);
21333
- const [lastModelError, setLastModelError] = useState11(null);
21334
- useEffect14(() => {
21493
+ const [fallbackModelIndex, setFallbackModelIndex] = useState12(0);
21494
+ const [lastModelError, setLastModelError] = useState12(null);
21495
+ useEffect15(() => {
21335
21496
  setFallbackModelIndex(0);
21336
21497
  setLastModelError(null);
21337
21498
  }, [cad_component.cad_component_id, url, gltfUrl, stepUrl]);
@@ -21554,7 +21715,7 @@ var AnyCadComponent = ({
21554
21715
  };
21555
21716
 
21556
21717
  // src/sections/SectionScene.tsx
21557
- import { useEffect as useEffect15, useRef as useRef4 } from "react";
21718
+ import { useEffect as useEffect16, useRef as useRef5 } from "react";
21558
21719
  import * as THREE20 from "three";
21559
21720
 
21560
21721
  // src/contexts/CameraControllerContext.tsx
@@ -21563,8 +21724,8 @@ import {
21563
21724
  useCallback as useCallback4,
21564
21725
  useContext as useContext7,
21565
21726
  useMemo as useMemo11,
21566
- useRef as useRef3,
21567
- useState as useState12
21727
+ useRef as useRef4,
21728
+ useState as useState13
21568
21729
  } from "react";
21569
21730
  import * as THREE18 from "three";
21570
21731
 
@@ -21642,14 +21803,14 @@ var loadCameraFromSession = (camera, cameraSessionContext) => {
21642
21803
  };
21643
21804
  var CameraControllerContext = createContext7(void 0);
21644
21805
  var CameraControllerProvider = ({ children, defaultTarget, initialCameraPosition, initialCameraType }) => {
21645
- const controlsRef = useRef3(null);
21646
- const mainCameraRef = useRef3(null);
21647
- const [controller, setController] = useState12(null);
21648
- const [cameraType, setCameraType] = useState12(
21806
+ const controlsRef = useRef4(null);
21807
+ const mainCameraRef = useRef4(null);
21808
+ const [controller, setController] = useState13(null);
21809
+ const [cameraType, setCameraType] = useState13(
21649
21810
  initialCameraType ?? "perspective"
21650
21811
  );
21651
- const [cameraPosition, setCameraPosition] = useState12(initialCameraPosition ?? null);
21652
- const [cameraRotation, setCameraRotation] = useState12(
21812
+ const [cameraPosition, setCameraPosition] = useState13(initialCameraPosition ?? null);
21813
+ const [cameraRotation, setCameraRotation] = useState13(
21653
21814
  new THREE18.Euler(0, 0, 0)
21654
21815
  );
21655
21816
  const baseDistance = useMemo11(() => {
@@ -21974,14 +22135,14 @@ var attributeVersion = (a) => "version" in a ? a.version : a.data.version;
21974
22135
  var materials = (value) => Array.isArray(value) ? value : [value];
21975
22136
  function SectionScene() {
21976
22137
  const section = useSection();
21977
- const latest = useRef4(section);
22138
+ const latest = useRef5(section);
21978
22139
  latest.current = section;
21979
22140
  const { scene, rootObject, camera, renderer } = useThree();
21980
22141
  const { controlsRef } = useCameraController();
21981
- const tick = useRef4(() => {
22142
+ const tick = useRef5(() => {
21982
22143
  });
21983
22144
  useFrame(() => tick.current());
21984
- useEffect15(() => {
22145
+ useEffect16(() => {
21985
22146
  if (!section) return;
21986
22147
  const canvas = renderer.domElement;
21987
22148
  const clipping = new THREE20.Plane();
@@ -22339,13 +22500,13 @@ function SectionScene() {
22339
22500
  }
22340
22501
 
22341
22502
  // src/CadViewerContainer.tsx
22342
- import { forwardRef as forwardRef2, useEffect as useEffect25, useMemo as useMemo18, useState as useState15 } from "react";
22503
+ import { forwardRef as forwardRef2, useEffect as useEffect26, useMemo as useMemo18, useState as useState16 } from "react";
22343
22504
  import * as THREE31 from "three";
22344
22505
 
22345
22506
  // package.json
22346
22507
  var package_default = {
22347
22508
  name: "@tscircuit/3d-viewer",
22348
- version: "0.0.643",
22509
+ version: "0.0.644",
22349
22510
  repository: {
22350
22511
  type: "git",
22351
22512
  url: "https://github.com/tscircuit/3d-viewer"
@@ -22452,7 +22613,7 @@ var package_default = {
22452
22613
  };
22453
22614
 
22454
22615
  // src/contexts/appearance-context.tsx
22455
- import { createContext as createContext8, useContext as useContext8, useEffect as useEffect16, useMemo as useMemo12, useState as useState13 } from "react";
22616
+ import { createContext as createContext8, useContext as useContext8, useEffect as useEffect17, useMemo as useMemo12, useState as useState14 } from "react";
22456
22617
  import { jsx as jsx15 } from "react/jsx-runtime";
22457
22618
  var LIGHTING_STORAGE_KEY = "cadViewerLightingEnabled";
22458
22619
  var readStoredLightingEnabled = () => {
@@ -22465,12 +22626,12 @@ var AppearanceContext = createContext8(
22465
22626
  var AppearanceProvider = ({
22466
22627
  children
22467
22628
  }) => {
22468
- const [darkBackgroundEnabled, setDarkBackgroundEnabled] = useState13(false);
22469
- const [gridEnabled, setGridEnabled] = useState13(false);
22470
- const [lightingEnabled, setLightingEnabled] = useState13(
22629
+ const [darkBackgroundEnabled, setDarkBackgroundEnabled] = useState14(false);
22630
+ const [gridEnabled, setGridEnabled] = useState14(false);
22631
+ const [lightingEnabled, setLightingEnabled] = useState14(
22471
22632
  readStoredLightingEnabled
22472
22633
  );
22473
- useEffect16(() => {
22634
+ useEffect17(() => {
22474
22635
  window.localStorage.setItem(
22475
22636
  LIGHTING_STORAGE_KEY,
22476
22637
  lightingEnabled ? "true" : "false"
@@ -22498,7 +22659,7 @@ var useAppearance = () => {
22498
22659
  };
22499
22660
 
22500
22661
  // src/hooks/cameraAnimation.ts
22501
- import { useCallback as useCallback5, useEffect as useEffect17, useRef as useRef5 } from "react";
22662
+ import { useCallback as useCallback5, useEffect as useEffect18, useRef as useRef6 } from "react";
22502
22663
  import * as THREE21 from "three";
22503
22664
  var easeInOutCubic = (t) => t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
22504
22665
  var CameraAnimatorWithContext = () => {
@@ -22509,14 +22670,14 @@ var CameraAnimatorWithContext = () => {
22509
22670
  setController,
22510
22671
  getPresetConfig
22511
22672
  } = useCameraController();
22512
- const animationRef = useRef5(null);
22513
- const tempQuaternion = useRef5(new THREE21.Quaternion());
22514
- const tempTarget = useRef5(new THREE21.Vector3());
22515
- const tempUp = useRef5(new THREE21.Vector3());
22516
- const tempRoll = useRef5(new THREE21.Quaternion());
22517
- const tempRollTarget = useRef5(new THREE21.Quaternion());
22518
- const baseOrientationHelper = useRef5(new THREE21.Object3D());
22519
- const orientationHelper = useRef5(new THREE21.Object3D());
22673
+ const animationRef = useRef6(null);
22674
+ const tempQuaternion = useRef6(new THREE21.Quaternion());
22675
+ const tempTarget = useRef6(new THREE21.Vector3());
22676
+ const tempUp = useRef6(new THREE21.Vector3());
22677
+ const tempRoll = useRef6(new THREE21.Quaternion());
22678
+ const tempRollTarget = useRef6(new THREE21.Quaternion());
22679
+ const baseOrientationHelper = useRef6(new THREE21.Object3D());
22680
+ const orientationHelper = useRef6(new THREE21.Object3D());
22520
22681
  const animateTo = useCallback5(
22521
22682
  ({ position, target, up, durationMs = 600 }) => {
22522
22683
  if (!mainCameraRef.current) return;
@@ -22570,7 +22731,7 @@ var CameraAnimatorWithContext = () => {
22570
22731
  },
22571
22732
  [animateTo, getPresetConfig]
22572
22733
  );
22573
- useEffect17(() => {
22734
+ useEffect18(() => {
22574
22735
  if (!mainCameraRef.current) return;
22575
22736
  const controller = {
22576
22737
  animateTo,
@@ -22639,16 +22800,16 @@ var CameraAnimatorWithContext = () => {
22639
22800
  };
22640
22801
 
22641
22802
  // src/hooks/useCameraSession.ts
22642
- import { useCallback as useCallback6, useEffect as useEffect18, useRef as useRef6 } from "react";
22803
+ import { useCallback as useCallback6, useEffect as useEffect19, useRef as useRef7 } from "react";
22643
22804
  var CAMERA_SESSION_NOT_RESTORED = /* @__PURE__ */ Symbol("camera-session-not-restored");
22644
22805
  var useCameraSession = ({
22645
22806
  cameraSessionScope
22646
22807
  } = {}) => {
22647
22808
  const { controlsRef } = useCameraController();
22648
- const cameraRef = useRef6(null);
22649
- const restoredCameraSessionScopeRef = useRef6(CAMERA_SESSION_NOT_RESTORED);
22650
- const saveTimeoutRef = useRef6(null);
22651
- useEffect18(() => {
22809
+ const cameraRef = useRef7(null);
22810
+ const restoredCameraSessionScopeRef = useRef7(CAMERA_SESSION_NOT_RESTORED);
22811
+ const saveTimeoutRef = useRef7(null);
22812
+ useEffect19(() => {
22652
22813
  return () => {
22653
22814
  if (saveTimeoutRef.current !== null) {
22654
22815
  clearTimeout(saveTimeoutRef.current);
@@ -22704,9 +22865,9 @@ var useCameraSession = ({
22704
22865
 
22705
22866
  // src/react-three/Canvas.tsx
22706
22867
  import {
22707
- useRef as useRef7,
22708
- useEffect as useEffect19,
22709
- useState as useState14,
22868
+ useRef as useRef8,
22869
+ useEffect as useEffect20,
22870
+ useState as useState15,
22710
22871
  useCallback as useCallback7,
22711
22872
  forwardRef,
22712
22873
  useImperativeHandle,
@@ -22734,16 +22895,16 @@ import { jsx as jsx16 } from "react/jsx-runtime";
22734
22895
  var Canvas = forwardRef(
22735
22896
  ({ children, scene: sceneProps, camera: cameraProps, style, onCreated }, ref) => {
22736
22897
  const { cameraType } = useCameraController();
22737
- const mountRef = useRef7(null);
22738
- const [contextState, setContextState] = useState14(
22898
+ const mountRef = useRef8(null);
22899
+ const [contextState, setContextState] = useState15(
22739
22900
  null
22740
22901
  );
22741
- const frameListeners = useRef7(
22902
+ const frameListeners = useRef8(
22742
22903
  []
22743
22904
  );
22744
- const onCreatedRef = useRef7(void 0);
22905
+ const onCreatedRef = useRef8(void 0);
22745
22906
  onCreatedRef.current = onCreated;
22746
- const savedCameraStateRef = useRef7(null);
22907
+ const savedCameraStateRef = useRef8(null);
22747
22908
  const addFrameListener = useCallback7(
22748
22909
  (listener) => {
22749
22910
  frameListeners.current.push(listener);
@@ -22762,9 +22923,9 @@ var Canvas = forwardRef(
22762
22923
  if (sceneProps?.up) {
22763
22924
  scene.up.set(sceneProps.up.x, sceneProps.up.y, sceneProps.up.z);
22764
22925
  }
22765
- const rootObject = useRef7(new THREE23.Object3D());
22926
+ const rootObject = useRef8(new THREE23.Object3D());
22766
22927
  useImperativeHandle(ref, () => rootObject.current);
22767
- useEffect19(() => {
22928
+ useEffect20(() => {
22768
22929
  if (!mountRef.current) return;
22769
22930
  removeExistingCanvases(mountRef.current);
22770
22931
  const renderer = new THREE23.WebGLRenderer({ antialias: true, alpha: true });
@@ -22873,7 +23034,7 @@ var Canvas = forwardRef(
22873
23034
  );
22874
23035
 
22875
23036
  // src/react-three/Grid.tsx
22876
- import { useEffect as useEffect20, useMemo as useMemo14 } from "react";
23037
+ import { useEffect as useEffect21, useMemo as useMemo14 } from "react";
22877
23038
  import * as THREE24 from "three";
22878
23039
  var vertexShader = `
22879
23040
  varying vec3 worldPosition;
@@ -22948,7 +23109,7 @@ var Grid = ({
22948
23109
  gridMesh.position.set(camera.position.x, camera.position.y, 0);
22949
23110
  }
22950
23111
  });
22951
- useEffect20(() => {
23112
+ useEffect21(() => {
22952
23113
  if (!scene || !gridMesh) return;
22953
23114
  scene.add(gridMesh);
22954
23115
  return () => {
@@ -22965,7 +23126,7 @@ var Grid = ({
22965
23126
  };
22966
23127
 
22967
23128
  // src/react-three/Lights.tsx
22968
- import { useEffect as useEffect21, useMemo as useMemo15 } from "react";
23129
+ import { useEffect as useEffect22, useMemo as useMemo15 } from "react";
22969
23130
  import * as THREE25 from "three";
22970
23131
  var UNDERSIDE_LIGHT_FACTOR = 0.75;
22971
23132
  var Lights = ({
@@ -23069,7 +23230,7 @@ var Lights = ({
23069
23230
  );
23070
23231
  return rig;
23071
23232
  }, [boardCenter, boardDimensions, shadowsEnabled]);
23072
- useEffect21(() => {
23233
+ useEffect22(() => {
23073
23234
  const previousBackground = scene.background;
23074
23235
  const previousEnvironment = scene.environment;
23075
23236
  scene.background = darkBackgroundEnabled ? new THREE25.Color(1053456) : null;
@@ -23079,7 +23240,7 @@ var Lights = ({
23079
23240
  scene.environment = previousEnvironment;
23080
23241
  };
23081
23242
  }, [darkBackgroundEnabled, scene]);
23082
- useEffect21(() => {
23243
+ useEffect22(() => {
23083
23244
  if (!scene) return;
23084
23245
  scene.add(lightRig);
23085
23246
  return () => {
@@ -23090,7 +23251,7 @@ var Lights = ({
23090
23251
  };
23091
23252
 
23092
23253
  // src/react-three/OrbitControls.tsx
23093
- import { useEffect as useEffect22, useMemo as useMemo16 } from "react";
23254
+ import { useEffect as useEffect23, useMemo as useMemo16 } from "react";
23094
23255
  import * as THREE27 from "three";
23095
23256
  import { OrbitControls as ThreeOrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
23096
23257
 
@@ -23149,11 +23310,11 @@ var OrbitControls = ({
23149
23310
  ) : controls.getDistance();
23150
23311
  return getMinimumDollyDistance({ camera, initialOrbitDistance });
23151
23312
  }, [camera, controls, target]);
23152
- useEffect22(() => {
23313
+ useEffect23(() => {
23153
23314
  onControlsChange?.(controls ?? null);
23154
23315
  return () => onControlsChange?.(null);
23155
23316
  }, [controls, onControlsChange]);
23156
- useEffect22(() => {
23317
+ useEffect23(() => {
23157
23318
  if (!controls) return;
23158
23319
  const handleChange = () => {
23159
23320
  onControlsChange?.(controls);
@@ -23163,7 +23324,7 @@ var OrbitControls = ({
23163
23324
  controls.removeEventListener("change", handleChange);
23164
23325
  };
23165
23326
  }, [controls, onControlsChange]);
23166
- useEffect22(() => {
23327
+ useEffect23(() => {
23167
23328
  if (!controls) return;
23168
23329
  controls.autoRotate = autoRotate || false;
23169
23330
  controls.autoRotateSpeed = autoRotateSpeed || 1;
@@ -23196,14 +23357,14 @@ var OrbitControls = ({
23196
23357
  dampingFactor,
23197
23358
  target
23198
23359
  ]);
23199
- useEffect22(() => {
23360
+ useEffect23(() => {
23200
23361
  if (!controls || !onStart) return;
23201
23362
  controls.addEventListener("start", onStart);
23202
23363
  return () => {
23203
23364
  controls.removeEventListener("start", onStart);
23204
23365
  };
23205
23366
  }, [controls, onStart]);
23206
- useEffect22(() => {
23367
+ useEffect23(() => {
23207
23368
  if (!controls) return;
23208
23369
  return () => {
23209
23370
  controls.dispose();
@@ -23299,7 +23460,7 @@ var getComparisonBounds = (type, boardDimensions, boardCenter) => {
23299
23460
  };
23300
23461
 
23301
23462
  // src/three-components/OrientationCubeCanvas.tsx
23302
- import { useEffect as useEffect23, useRef as useRef8 } from "react";
23463
+ import { useEffect as useEffect24, useRef as useRef9 } from "react";
23303
23464
  import * as THREE28 from "three";
23304
23465
  import { Text as TroikaText } from "troika-three-text";
23305
23466
  import { jsx as jsx17 } from "react/jsx-runtime";
@@ -23314,8 +23475,8 @@ function computePointInFront(rotationVector, distance5) {
23314
23475
  }
23315
23476
  var OrientationCubeCanvas = () => {
23316
23477
  const { mainCameraRef } = useCameraController();
23317
- const containerRef = useRef8(null);
23318
- useEffect23(() => {
23478
+ const containerRef = useRef9(null);
23479
+ useEffect24(() => {
23319
23480
  if (!containerRef.current) return;
23320
23481
  const container = containerRef.current;
23321
23482
  const canvas = document.createElement("canvas");
@@ -23455,7 +23616,7 @@ var OrientationCubeCanvas = () => {
23455
23616
  };
23456
23617
 
23457
23618
  // src/three-components/reference-object.tsx
23458
- import { useEffect as useEffect24, useMemo as useMemo17 } from "react";
23619
+ import { useEffect as useEffect25, useMemo as useMemo17 } from "react";
23459
23620
 
23460
23621
  // src/reference-objects/create-reference-object.ts
23461
23622
  import * as THREE29 from "three";
@@ -23851,7 +24012,7 @@ var ReferenceObject = ({
23851
24012
  nextObject.position.set(position.x, position.y, position.z);
23852
24013
  return nextObject;
23853
24014
  }, [type, boardDimensions, boardCenter]);
23854
- useEffect24(() => {
24015
+ useEffect25(() => {
23855
24016
  scene.add(object);
23856
24017
  return () => {
23857
24018
  scene.remove(object);
@@ -23863,7 +24024,7 @@ var ReferenceObject = ({
23863
24024
  var FitCameraToComparison = ({ bounds }) => {
23864
24025
  const { camera } = useThree();
23865
24026
  const { controlsRef } = useCameraController();
23866
- useEffect24(() => {
24027
+ useEffect25(() => {
23867
24028
  fitCameraToBounds(camera, controlsRef.current, bounds);
23868
24029
  }, [bounds, camera, controlsRef]);
23869
24030
  return null;
@@ -23895,7 +24056,7 @@ var CadViewerContainer = forwardRef2(
23895
24056
  onCameraControllerReady
23896
24057
  }, ref) => {
23897
24058
  const section = useSection();
23898
- const [isInteractionEnabled, setIsInteractionEnabled] = useState15(
24059
+ const [isInteractionEnabled, setIsInteractionEnabled] = useState16(
23899
24060
  !clickToInteractEnabled
23900
24061
  );
23901
24062
  const { mainCameraRef, handleControlsChange, controller } = useCameraController();
@@ -23904,7 +24065,7 @@ var CadViewerContainer = forwardRef2(
23904
24065
  handleCameraCreated,
23905
24066
  handleControlsChange: handleSessionControlsChange
23906
24067
  } = useCameraSession({ cameraSessionScope });
23907
- useEffect25(() => {
24068
+ useEffect26(() => {
23908
24069
  if (onCameraControllerReady) {
23909
24070
  onCameraControllerReady(controller);
23910
24071
  }
@@ -24070,12 +24231,12 @@ var useConvertChildrenToCircuitJson = (children) => {
24070
24231
  };
24071
24232
 
24072
24233
  // src/hooks/use-stls-from-geom.ts
24073
- import { useState as useState16, useEffect as useEffect26 } from "react";
24234
+ import { useState as useState17, useEffect as useEffect27 } from "react";
24074
24235
  import stlSerializer from "@jscad/stl-serializer";
24075
24236
  var useStlsFromGeom = (geom) => {
24076
- const [stls, setStls] = useState16([]);
24077
- const [loading, setLoading] = useState16(true);
24078
- useEffect26(() => {
24237
+ const [stls, setStls] = useState17([]);
24238
+ const [loading, setLoading] = useState17(true);
24239
+ useEffect27(() => {
24079
24240
  if (!geom) return;
24080
24241
  const generateStls = async () => {
24081
24242
  setLoading(true);
@@ -24104,7 +24265,7 @@ var useStlsFromGeom = (geom) => {
24104
24265
  };
24105
24266
 
24106
24267
  // src/hooks/useBoardGeomBuilder.ts
24107
- import { useState as useState17, useEffect as useEffect27, useRef as useRef9 } from "react";
24268
+ import { useState as useState18, useEffect as useEffect28, useRef as useRef10 } from "react";
24108
24269
 
24109
24270
  // src/soup-to-3d/index.ts
24110
24271
  var import_colors = __toESM(require_colors(), 1);
@@ -25596,9 +25757,9 @@ var BoardGeomBuilder = class {
25596
25757
 
25597
25758
  // src/hooks/useBoardGeomBuilder.ts
25598
25759
  var useBoardGeomBuilder = (circuitJson) => {
25599
- const [boardGeom, setBoardGeom] = useState17(null);
25600
- const isProcessingRef = useRef9(false);
25601
- useEffect27(() => {
25760
+ const [boardGeom, setBoardGeom] = useState18(null);
25761
+ const isProcessingRef = useRef10(false);
25762
+ useEffect28(() => {
25602
25763
  let isCancelled = false;
25603
25764
  if (!circuitJson) {
25604
25765
  setBoardGeom(null);
@@ -25644,10 +25805,10 @@ var useBoardGeomBuilder = (circuitJson) => {
25644
25805
  };
25645
25806
 
25646
25807
  // src/three-components/Error3d.tsx
25647
- import { useState as useState18, useCallback as useCallback8, useEffect as useEffect29, useMemo as useMemo21 } from "react";
25808
+ import { useState as useState19, useCallback as useCallback8, useEffect as useEffect30, useMemo as useMemo21 } from "react";
25648
25809
 
25649
25810
  // src/react-three/Text.tsx
25650
- import { useEffect as useEffect28, useMemo as useMemo20 } from "react";
25811
+ import { useEffect as useEffect29, useMemo as useMemo20 } from "react";
25651
25812
  import { Text as TroikaText2 } from "troika-three-text";
25652
25813
  var Text = ({
25653
25814
  children,
@@ -25687,7 +25848,7 @@ var Text = ({
25687
25848
  anchorY,
25688
25849
  depthOffset
25689
25850
  ]);
25690
- useEffect28(() => {
25851
+ useEffect29(() => {
25691
25852
  const parentObject = parent || rootObject;
25692
25853
  if (!parentObject || !mesh) return;
25693
25854
  parentObject.add(mesh);
@@ -25707,8 +25868,8 @@ var Error3d = ({
25707
25868
  cad_component
25708
25869
  }) => {
25709
25870
  const { rootObject } = useThree();
25710
- const [isHovered, setIsHovered] = useState18(false);
25711
- const [hoverPosition, setHoverPosition] = useState18(null);
25871
+ const [isHovered, setIsHovered] = useState19(false);
25872
+ const [hoverPosition, setHoverPosition] = useState19(null);
25712
25873
  const handleHover = useCallback8((e) => {
25713
25874
  if (e?.mousePosition) {
25714
25875
  setIsHovered(true);
@@ -25740,7 +25901,7 @@ var Error3d = ({
25740
25901
  }, [position]);
25741
25902
  group.userData.cad_component_id = cad_component?.cad_component_id;
25742
25903
  group.userData.pcb_component_id = cad_component?.pcb_component_id;
25743
- useEffect29(() => {
25904
+ useEffect30(() => {
25744
25905
  if (!rootObject) return;
25745
25906
  rootObject.add(group);
25746
25907
  return () => {
@@ -25809,7 +25970,7 @@ var ErrorBox = ({ parent }) => {
25809
25970
  m.rotation.fromArray([Math.PI / 4, Math.PI / 4, 0]);
25810
25971
  return m;
25811
25972
  }, []);
25812
- useEffect29(() => {
25973
+ useEffect30(() => {
25813
25974
  parent.add(mesh);
25814
25975
  return () => {
25815
25976
  parent.remove(mesh);
@@ -25819,7 +25980,7 @@ var ErrorBox = ({ parent }) => {
25819
25980
  };
25820
25981
 
25821
25982
  // src/three-components/BoardGroup.tsx
25822
- import { useEffect as useEffect30, useMemo as useMemo22 } from "react";
25983
+ import { useEffect as useEffect31, useMemo as useMemo22 } from "react";
25823
25984
  import * as THREE35 from "three";
25824
25985
  import { jsx as jsx20 } from "react/jsx-runtime";
25825
25986
  var BoardGroup = ({
@@ -25832,7 +25993,7 @@ var BoardGroup = ({
25832
25993
  group.name = "board";
25833
25994
  group.userData.pcb_board_id = pcbBoardId;
25834
25995
  group.visible = !hidden;
25835
- useEffect30(() => {
25996
+ useEffect31(() => {
25836
25997
  scene.rootObject.add(group);
25837
25998
  return () => {
25838
25999
  scene.rootObject.remove(group);
@@ -25847,7 +26008,7 @@ var BoardGroup = ({
25847
26008
 
25848
26009
  // src/three-components/JscadBoardTextures.tsx
25849
26010
  import { su as su9 } from "@tscircuit/circuit-json-util";
25850
- import { useEffect as useEffect31, useMemo as useMemo24 } from "react";
26011
+ import { useEffect as useEffect32, useMemo as useMemo24 } from "react";
25851
26012
 
25852
26013
  // src/textures/open-via-holes-at-pads.ts
25853
26014
  import { CircuitToCanvasDrawer } from "circuit-to-canvas";
@@ -28213,7 +28374,7 @@ function JscadBoardTextures({
28213
28374
  visibility: textureVisibility
28214
28375
  });
28215
28376
  }, [circuitJson, boardData, traceTextureResolution, textureVisibility]);
28216
- useEffect31(() => {
28377
+ useEffect32(() => {
28217
28378
  if (!rootObject || !boardData || !textures) return;
28218
28379
  const meshes = [];
28219
28380
  const disposeTextureMaterial = (material) => {
@@ -28351,7 +28512,7 @@ function JscadBoardTextures({
28351
28512
  }
28352
28513
 
28353
28514
  // src/three-components/STLModel.tsx
28354
- import { useState as useState19, useEffect as useEffect32, useMemo as useMemo25 } from "react";
28515
+ import { useState as useState20, useEffect as useEffect33, useMemo as useMemo25 } from "react";
28355
28516
  import * as THREE52 from "three";
28356
28517
  import { STLLoader as STLLoader2 } from "three-stdlib";
28357
28518
  function STLModel({
@@ -28363,8 +28524,8 @@ function STLModel({
28363
28524
  layerType
28364
28525
  }) {
28365
28526
  const { rootObject } = useThree();
28366
- const [geom, setGeom] = useState19(null);
28367
- useEffect32(() => {
28527
+ const [geom, setGeom] = useState20(null);
28528
+ useEffect33(() => {
28368
28529
  const loader = new STLLoader2();
28369
28530
  if (stlData) {
28370
28531
  try {
@@ -28401,7 +28562,7 @@ function STLModel({
28401
28562
  });
28402
28563
  return createdMesh;
28403
28564
  }, [geom, color, opacity, layerType]);
28404
- useEffect32(() => {
28565
+ useEffect33(() => {
28405
28566
  if (!rootObject || !mesh) return;
28406
28567
  rootObject.add(mesh);
28407
28568
  return () => {
@@ -28455,7 +28616,7 @@ function VisibleSTLModel({
28455
28616
  // src/three-components/CadCable.tsx
28456
28617
  import { parseCableString } from "@tscircuit/cableprinter";
28457
28618
  import { createCableMeshes } from "jscad-electronics/cables";
28458
- import { useEffect as useEffect33, useMemo as useMemo26 } from "react";
28619
+ import { useEffect as useEffect34, useMemo as useMemo26 } from "react";
28459
28620
  import * as THREE53 from "three";
28460
28621
  var isCadCableElement = (element) => {
28461
28622
  if (!element || typeof element !== "object") return false;
@@ -28552,7 +28713,7 @@ var CadCable = ({ cable }) => {
28552
28713
  return null;
28553
28714
  }
28554
28715
  }, [cable]);
28555
- useEffect33(() => {
28716
+ useEffect34(() => {
28556
28717
  if (!cableObject) return;
28557
28718
  rootObject.add(cableObject);
28558
28719
  return () => {
@@ -30063,12 +30224,12 @@ function createStiffenerMesh({
30063
30224
  }
30064
30225
 
30065
30226
  // src/CadViewerManifold.tsx
30066
- import { useEffect as useEffect35, useMemo as useMemo29, useState as useState21 } from "react";
30227
+ import { useEffect as useEffect36, useMemo as useMemo29, useState as useState22 } from "react";
30067
30228
  import * as THREE61 from "three";
30068
30229
 
30069
30230
  // src/hooks/useManifoldBoardBuilder.ts
30070
30231
  import { su as su16 } from "@tscircuit/circuit-json-util";
30071
- import { useEffect as useEffect34, useMemo as useMemo28, useRef as useRef10, useState as useState20 } from "react";
30232
+ import { useEffect as useEffect35, useMemo as useMemo28, useRef as useRef11, useState as useState21 } from "react";
30072
30233
  import * as THREE57 from "three";
30073
30234
 
30074
30235
  // src/utils/manifold/create-manifold-board.ts
@@ -31219,11 +31380,11 @@ function processViasForManifold(Manifold, circuitJson, pcbThickness, manifoldIns
31219
31380
  // src/hooks/useManifoldBoardBuilder.ts
31220
31381
  var useManifoldBoardBuilder = (manifoldJSModule, circuitJson, visibility) => {
31221
31382
  const textureVisibility = useBoardTextureVisibility(visibility);
31222
- const [geoms, setGeoms] = useState20(null);
31223
- const [pcbThickness, setPcbThickness] = useState20(null);
31224
- const [error, setError] = useState20(null);
31225
- const [isLoading, setIsLoading] = useState20(true);
31226
- const manifoldInstancesForCleanup = useRef10([]);
31383
+ const [geoms, setGeoms] = useState21(null);
31384
+ const [pcbThickness, setPcbThickness] = useState21(null);
31385
+ const [error, setError] = useState21(null);
31386
+ const [isLoading, setIsLoading] = useState21(true);
31387
+ const manifoldInstancesForCleanup = useRef11([]);
31227
31388
  const boardData = useMemo28(() => {
31228
31389
  const panels = circuitJson.filter(
31229
31390
  (e) => e.type === "pcb_panel"
@@ -31257,7 +31418,7 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson, visibility) => {
31257
31418
  if (!boardData) return TRACE_TEXTURE_RESOLUTION;
31258
31419
  return getLayerTextureResolution(boardData, TRACE_TEXTURE_RESOLUTION);
31259
31420
  }, [boardData]);
31260
- useEffect34(() => {
31421
+ useEffect35(() => {
31261
31422
  if (!manifoldJSModule || !boardData) {
31262
31423
  setGeoms(null);
31263
31424
  setPcbThickness(null);
@@ -31805,7 +31966,7 @@ var BoardMeshes = ({
31805
31966
  material.dispose();
31806
31967
  }
31807
31968
  };
31808
- useEffect35(() => {
31969
+ useEffect36(() => {
31809
31970
  if (!rootObject) return;
31810
31971
  for (const mesh of geometryMeshes) {
31811
31972
  let shouldShow = true;
@@ -31827,7 +31988,7 @@ var BoardMeshes = ({
31827
31988
  }
31828
31989
  };
31829
31990
  }, [rootObject, geometryMeshes, visibility]);
31830
- useEffect35(() => {
31991
+ useEffect36(() => {
31831
31992
  if (!rootObject) return;
31832
31993
  for (const mesh of textureMeshes) {
31833
31994
  rootObject.add(mesh);
@@ -31860,10 +32021,10 @@ var CadViewerManifold = ({
31860
32021
  const rawCircuitJson = circuitJsonProp ?? childrenCircuitJson;
31861
32022
  return addFauxBoardIfNeeded(rawCircuitJson);
31862
32023
  }, [circuitJsonProp, childrenCircuitJson]);
31863
- const [manifoldJSModule, setManifoldJSModule] = useState21(null);
31864
- const [manifoldLoadingError, setManifoldLoadingError] = useState21(null);
32024
+ const [manifoldJSModule, setManifoldJSModule] = useState22(null);
32025
+ const [manifoldLoadingError, setManifoldLoadingError] = useState22(null);
31865
32026
  const { visibility } = useLayerVisibility();
31866
- useEffect35(() => {
32027
+ useEffect36(() => {
31867
32028
  let isActive = true;
31868
32029
  loadManifold().then((module) => {
31869
32030
  if (isActive) setManifoldJSModule(module);
@@ -32044,18 +32205,18 @@ var CadViewerManifold_default = CadViewerManifold;
32044
32205
 
32045
32206
  // src/CadViewerGlb.tsx
32046
32207
  import {
32047
- useEffect as useEffect37,
32208
+ useEffect as useEffect38,
32048
32209
  useLayoutEffect as useLayoutEffect2,
32049
- useState as useState23
32210
+ useState as useState24
32050
32211
  } from "react";
32051
32212
 
32052
32213
  // src/hooks/useGlbModel.ts
32053
- import { useEffect as useEffect36, useLayoutEffect, useMemo as useMemo30, useState as useState22 } from "react";
32214
+ import { useEffect as useEffect37, useLayoutEffect, useMemo as useMemo30, useState as useState23 } from "react";
32054
32215
  function useGlbModel(source) {
32055
32216
  const request = useMemo30(() => ({ source }), [source]);
32056
- const [result, setResult] = useState22();
32217
+ const [result, setResult] = useState23();
32057
32218
  const displayedGlb = result?.loadedGlb;
32058
- useEffect36(() => {
32219
+ useEffect37(() => {
32059
32220
  const controller = new AbortController();
32060
32221
  let loadedGlb;
32061
32222
  loadGlbScene(request.source, controller.signal).then((model) => {
@@ -32099,14 +32260,14 @@ function GlbScene({
32099
32260
  }) {
32100
32261
  const { rootObject } = useThree();
32101
32262
  const { addHoverable, removeHoverable } = useHover();
32102
- const [hover, setHover] = useState23();
32263
+ const [hover, setHover] = useState24();
32103
32264
  useLayoutEffect2(() => {
32104
32265
  rootObject.add(model);
32105
32266
  return () => {
32106
32267
  rootObject.remove(model);
32107
32268
  };
32108
32269
  }, [rootObject, model]);
32109
- useEffect37(() => {
32270
+ useEffect38(() => {
32110
32271
  setHover(void 0);
32111
32272
  const applyVisibility = (object, inObject) => {
32112
32273
  const id = object.userData.cad_component_id ?? object.userData.pcb_board_id;
@@ -32119,7 +32280,7 @@ function GlbScene({
32119
32280
  };
32120
32281
  applyVisibility(model, false);
32121
32282
  }, [model, objectVisibility]);
32122
- useEffect37(() => {
32283
+ useEffect38(() => {
32123
32284
  const meshes = [];
32124
32285
  model.traverse((mesh) => {
32125
32286
  if (!(mesh instanceof THREE62.Mesh)) return;
@@ -32193,8 +32354,8 @@ function GlbViewport({
32193
32354
  objectVisibility,
32194
32355
  ...containerProps
32195
32356
  }) {
32196
- const [framing, setFraming] = useState23(() => getGlbFraming(model));
32197
- useEffect37(() => {
32357
+ const [framing, setFraming] = useState24(() => getGlbFraming(model));
32358
+ useEffect38(() => {
32198
32359
  if (framing) return;
32199
32360
  const nextFraming = getGlbFraming(model);
32200
32361
  if (nextFraming) setFraming(nextFraming);
@@ -37017,9 +37178,9 @@ function assignRef(ref, value) {
37017
37178
  }
37018
37179
 
37019
37180
  // node_modules/use-callback-ref/dist/es2015/useRef.js
37020
- import { useState as useState36 } from "react";
37181
+ import { useState as useState37 } from "react";
37021
37182
  function useCallbackRef2(initialValue, callback) {
37022
- var ref = useState36(function() {
37183
+ var ref = useState37(function() {
37023
37184
  return {
37024
37185
  // value
37025
37186
  value: initialValue,
@@ -38634,11 +38795,11 @@ var DropdownMenuSubContent = /* @__PURE__ */ React42.forwardRef(/* @__PURE__ */
38634
38795
  }, "DropdownMenuSubContent"));
38635
38796
 
38636
38797
  // src/components/ViewportSubContent.tsx
38637
- import { useLayoutEffect as useLayoutEffect6, useState as useState40 } from "react";
38798
+ import { useLayoutEffect as useLayoutEffect6, useState as useState41 } from "react";
38638
38799
  import { jsx as jsx37 } from "react/jsx-runtime";
38639
38800
  var ViewportSubContent = (props) => {
38640
- const [content, setContent] = useState40(null);
38641
- const [overlapWidth, setOverlapWidth] = useState40();
38801
+ const [content, setContent] = useState41(null);
38802
+ const [overlapWidth, setOverlapWidth] = useState41();
38642
38803
  useLayoutEffect6(() => {
38643
38804
  if (!content) return;
38644
38805
  const trigger = document.getElementById(
@@ -38693,10 +38854,10 @@ var menuViewportStyles = {
38693
38854
  };
38694
38855
 
38695
38856
  // src/components/ContextMenu.tsx
38696
- import { useState as useState42 } from "react";
38857
+ import { useState as useState43 } from "react";
38697
38858
 
38698
38859
  // src/components/AppearanceMenu.tsx
38699
- import { useState as useState41 } from "react";
38860
+ import { useState as useState42 } from "react";
38700
38861
 
38701
38862
  // src/components/Icons.tsx
38702
38863
  import { jsx as jsx38 } from "react/jsx-runtime";
@@ -38826,8 +38987,8 @@ var AppearanceMenu = ({
38826
38987
  lightingEnabled,
38827
38988
  setLightingEnabled
38828
38989
  } = useAppearance();
38829
- const [appearanceSubOpen, setAppearanceSubOpen] = useState41(false);
38830
- const [hoveredItem, setHoveredItem] = useState41(null);
38990
+ const [appearanceSubOpen, setAppearanceSubOpen] = useState42(false);
38991
+ const [hoveredItem, setHoveredItem] = useState42(null);
38831
38992
  const assemblyStyles = { ...itemStyles };
38832
38993
  if (hoveredItem === "assembly") assemblyStyles.backgroundColor = "#404040";
38833
38994
  return /* @__PURE__ */ jsxs9(Fragment10, { children: [
@@ -39308,10 +39469,10 @@ var ContextMenu = ({
39308
39469
  }) => {
39309
39470
  const { cameraType, setCameraType } = useCameraController();
39310
39471
  const { gridEnabled, setGridEnabled } = useAppearance();
39311
- const [cameraSubOpen, setCameraSubOpen] = useState42(false);
39312
- const [advancedSubOpen, setAdvancedSubOpen] = useState42(false);
39313
- const [referenceObjectSubOpen, setReferenceObjectSubOpen] = useState42(false);
39314
- const [hoveredItem, setHoveredItem] = useState42(null);
39472
+ const [cameraSubOpen, setCameraSubOpen] = useState43(false);
39473
+ const [advancedSubOpen, setAdvancedSubOpen] = useState43(false);
39474
+ const [referenceObjectSubOpen, setReferenceObjectSubOpen] = useState43(false);
39475
+ const [hoveredItem, setHoveredItem] = useState43(null);
39315
39476
  return /* @__PURE__ */ jsx40(
39316
39477
  "div",
39317
39478
  {
@@ -39782,10 +39943,10 @@ var ContextMenu = ({
39782
39943
  };
39783
39944
 
39784
39945
  // src/components/KeyboardShortcutsDialog.tsx
39785
- import { useEffect as useEffect55, useMemo as useMemo40, useRef as useRef28, useState as useState44 } from "react";
39946
+ import { useEffect as useEffect56, useMemo as useMemo40, useRef as useRef29, useState as useState45 } from "react";
39786
39947
 
39787
39948
  // src/hooks/useRegisteredHotkey.ts
39788
- import { useEffect as useEffect54, useMemo as useMemo39, useRef as useRef27, useState as useState43 } from "react";
39949
+ import { useEffect as useEffect55, useMemo as useMemo39, useRef as useRef28, useState as useState44 } from "react";
39789
39950
  var hotkeyRegistry = /* @__PURE__ */ new Map();
39790
39951
  var subscribers = /* @__PURE__ */ new Set();
39791
39952
  var isListenerAttached = false;
@@ -39907,7 +40068,7 @@ var subscribeToRegistry = (subscriber) => {
39907
40068
  };
39908
40069
  };
39909
40070
  var useRegisteredHotkey = (id, handler, metadata) => {
39910
- const handlerRef = useRef27(handler);
40071
+ const handlerRef = useRef28(handler);
39911
40072
  handlerRef.current = handler;
39912
40073
  const normalizedMetadata = useMemo39(
39913
40074
  () => ({
@@ -39916,7 +40077,7 @@ var useRegisteredHotkey = (id, handler, metadata) => {
39916
40077
  }),
39917
40078
  [metadata.shortcut, metadata.description]
39918
40079
  );
39919
- useEffect54(() => {
40080
+ useEffect55(() => {
39920
40081
  const registration = {
39921
40082
  id,
39922
40083
  ...normalizedMetadata,
@@ -39929,10 +40090,10 @@ var useRegisteredHotkey = (id, handler, metadata) => {
39929
40090
  }, [id, normalizedMetadata]);
39930
40091
  };
39931
40092
  var useHotkeyRegistry = () => {
39932
- const [entries, setEntries] = useState43(
40093
+ const [entries, setEntries] = useState44(
39933
40094
  () => Array.from(hotkeyRegistry.values())
39934
40095
  );
39935
- useEffect54(() => subscribeToRegistry(setEntries), []);
40096
+ useEffect55(() => subscribeToRegistry(setEntries), []);
39936
40097
  return entries;
39937
40098
  };
39938
40099
  var registerHotkeyViewer = (element) => {
@@ -39946,10 +40107,10 @@ var KeyboardShortcutsDialog = ({
39946
40107
  open,
39947
40108
  onClose
39948
40109
  }) => {
39949
- const [query, setQuery] = useState44("");
39950
- const inputRef = useRef28(null);
40110
+ const [query, setQuery] = useState45("");
40111
+ const inputRef = useRef29(null);
39951
40112
  const hotkeys = useHotkeyRegistry();
39952
- useEffect55(() => {
40113
+ useEffect56(() => {
39953
40114
  if (!open) return void 0;
39954
40115
  const handleKeyDown = (event) => {
39955
40116
  if (event.key === "Escape") {
@@ -39960,7 +40121,7 @@ var KeyboardShortcutsDialog = ({
39960
40121
  window.addEventListener("keydown", handleKeyDown);
39961
40122
  return () => window.removeEventListener("keydown", handleKeyDown);
39962
40123
  }, [open, onClose]);
39963
- useEffect55(() => {
40124
+ useEffect56(() => {
39964
40125
  if (open) {
39965
40126
  setTimeout(() => {
39966
40127
  inputRef.current?.focus();
@@ -40189,17 +40350,17 @@ function useCameraPreset({
40189
40350
  }
40190
40351
 
40191
40352
  // src/hooks/useContextMenu.ts
40192
- import { useState as useState45, useCallback as useCallback23, useRef as useRef29, useEffect as useEffect56 } from "react";
40353
+ import { useState as useState46, useCallback as useCallback23, useRef as useRef30, useEffect as useEffect57 } from "react";
40193
40354
  var useContextMenu = ({ containerRef, onOpen }) => {
40194
- const [menuVisible, setMenuVisible] = useState45(false);
40195
- const [menuPos, setMenuPos] = useState45({
40355
+ const [menuVisible, setMenuVisible] = useState46(false);
40356
+ const [menuPos, setMenuPos] = useState46({
40196
40357
  x: 0,
40197
40358
  y: 0
40198
40359
  });
40199
- const menuRef = useRef29(null);
40200
- const interactionOriginPosRef = useRef29(null);
40201
- const longPressTimeoutRef = useRef29(null);
40202
- const ignoreNextContextMenuRef = useRef29(false);
40360
+ const menuRef = useRef30(null);
40361
+ const interactionOriginPosRef = useRef30(null);
40362
+ const longPressTimeoutRef = useRef30(null);
40363
+ const ignoreNextContextMenuRef = useRef30(false);
40203
40364
  const clearLongPressTimeout = () => {
40204
40365
  if (longPressTimeoutRef.current !== null) {
40205
40366
  clearTimeout(longPressTimeoutRef.current);
@@ -40306,7 +40467,7 @@ var useContextMenu = ({ containerRef, onOpen }) => {
40306
40467
  }
40307
40468
  setMenuVisible(false);
40308
40469
  }, []);
40309
- useEffect56(() => {
40470
+ useEffect57(() => {
40310
40471
  if (menuVisible) {
40311
40472
  document.addEventListener("mousedown", handleClickAway);
40312
40473
  document.addEventListener("touchstart", handleClickAway);
@@ -40522,19 +40683,22 @@ var CadViewerInner = (props) => {
40522
40683
  glbSource === void 0 ? props.circuitJson : void 0
40523
40684
  );
40524
40685
  const circuitJson = props.circuitJson ?? explosion.assembled;
40525
- const [explosionPanelSource, setExplosionPanelSource] = useState46(null);
40686
+ const [explosionPanelSource, setExplosionPanelSource] = useState47(null);
40526
40687
  const explosionPanelOpen = explosionPanelSource === circuitJson;
40527
40688
  const hasAssembly = circuitJson.some(
40528
40689
  (element) => element.type === "cad_component" && !element.pcb_component_id
40529
40690
  );
40530
40691
  const hasBends = circuitJson.some((element) => element.type === "pcb_bend");
40531
40692
  const hasFlexGeometry = hasBends || circuitJson.some((element) => element.type === "pcb_stiffener");
40532
- const [foldPcbsOverride, setFoldPcbs] = useState46(
40693
+ const [foldPcbsOverride, setFoldPcbs] = useState47(
40533
40694
  void 0
40534
40695
  );
40535
40696
  const foldPcbs = foldPcbsOverride ?? props.foldPcbs;
40536
40697
  const resolvedFoldPcbs = resolveFoldPcbs(circuitJson, foldPcbs);
40537
- const circuitJsonKey = glbSource === void 0 ? JSON.stringify(circuitJson) : void 0;
40698
+ const circuitJsonKey = useMemo41(
40699
+ () => glbSource === void 0 ? JSON.stringify(circuitJson) : void 0,
40700
+ [glbSource, circuitJson]
40701
+ );
40538
40702
  const circuitKey = glbSource ?? circuitJsonKey;
40539
40703
  const { objectVisibility, hideObject, isolateObject, unhideAllObjects } = useObjectVisibility(circuitKey);
40540
40704
  const resolvedProps = {
@@ -40543,31 +40707,31 @@ var CadViewerInner = (props) => {
40543
40707
  children: void 0,
40544
40708
  objectVisibility
40545
40709
  };
40546
- const [engine, setEngine] = useState46(() => {
40710
+ const [engine, setEngine] = useState47(() => {
40547
40711
  const stored = window.localStorage.getItem("cadViewerEngine");
40548
40712
  return stored === "jscad" || stored === "manifold" ? stored : "manifold";
40549
40713
  });
40550
- const containerRef = useRef30(null);
40551
- const [isKeyboardShortcutsDialogOpen, setIsKeyboardShortcutsDialogOpen] = useState46(false);
40552
- const [autoRotate, setAutoRotate] = useState46(() => {
40714
+ const containerRef = useRef31(null);
40715
+ const [isKeyboardShortcutsDialogOpen, setIsKeyboardShortcutsDialogOpen] = useState47(false);
40716
+ const [autoRotate, setAutoRotate] = useState47(() => {
40553
40717
  const stored = window.localStorage.getItem("cadViewerAutoRotate");
40554
40718
  return stored !== "false";
40555
40719
  });
40556
- const [autoRotateUserToggled, setAutoRotateUserToggled] = useState46(() => {
40720
+ const [autoRotateUserToggled, setAutoRotateUserToggled] = useState47(() => {
40557
40721
  const stored = window.localStorage.getItem("cadViewerAutoRotateUserToggled");
40558
40722
  return stored === "true";
40559
40723
  });
40560
- const [cameraPreset, setCameraPreset] = useState46("Custom");
40561
- const [referenceObject, setReferenceObject] = useState46(null);
40724
+ const [cameraPreset, setCameraPreset] = useState47("Custom");
40725
+ const [referenceObject, setReferenceObject] = useState47(null);
40562
40726
  const { cameraType } = useCameraController();
40563
40727
  const { visibility, setLayerVisibility } = useLayerVisibility();
40564
40728
  const { showToast } = useToast();
40565
- const cameraControllerRef = useRef30(null);
40729
+ const cameraControllerRef = useRef31(null);
40566
40730
  const externalCameraControllerReady = props.onCameraControllerReady;
40567
40731
  const sceneRef = useContext13(SchematicNavigationContext);
40568
- const [selectedComponent, setSelectedComponent] = useState46();
40569
- const [selectedObject, setSelectedObject] = useState46();
40570
- const [selectedModel, setSelectedModel] = useState46();
40732
+ const [selectedComponent, setSelectedComponent] = useState47();
40733
+ const [selectedObject, setSelectedObject] = useState47();
40734
+ const [selectedModel, setSelectedModel] = useState47();
40571
40735
  const handleMenuOpen = useCallback25(
40572
40736
  (position) => {
40573
40737
  const picked = pickSceneObject(sceneRef.current, position, circuitJson);
@@ -40588,10 +40752,10 @@ var CadViewerInner = (props) => {
40588
40752
  contextMenuEventHandlers,
40589
40753
  setMenuVisible
40590
40754
  } = useContextMenu({ containerRef, onOpen: handleMenuOpen });
40591
- const autoRotateUserToggledRef = useRef30(autoRotateUserToggled);
40755
+ const autoRotateUserToggledRef = useRef31(autoRotateUserToggled);
40592
40756
  autoRotateUserToggledRef.current = autoRotateUserToggled;
40593
- const isAnimatingRef = useRef30(false);
40594
- const lastPresetSelectTime = useRef30(0);
40757
+ const isAnimatingRef = useRef31(false);
40758
+ const lastPresetSelectTime = useRef31(0);
40595
40759
  const PRESET_COOLDOWN = 1e3;
40596
40760
  const handleUserInteraction = useCallback25(() => {
40597
40761
  if (isAnimatingRef.current || Date.now() - lastPresetSelectTime.current < PRESET_COOLDOWN) {
@@ -40686,24 +40850,24 @@ var CadViewerInner = (props) => {
40686
40850
  description: "Toggle translucent components"
40687
40851
  }
40688
40852
  );
40689
- useEffect57(() => {
40853
+ useEffect58(() => {
40690
40854
  if (containerRef.current) {
40691
40855
  registerHotkeyViewer(containerRef.current);
40692
40856
  }
40693
40857
  }, []);
40694
- useEffect57(() => {
40858
+ useEffect58(() => {
40695
40859
  window.localStorage.setItem("cadViewerEngine", engine);
40696
40860
  }, [engine]);
40697
- useEffect57(() => {
40861
+ useEffect58(() => {
40698
40862
  window.localStorage.setItem("cadViewerAutoRotate", String(autoRotate));
40699
40863
  }, [autoRotate]);
40700
- useEffect57(() => {
40864
+ useEffect58(() => {
40701
40865
  window.localStorage.setItem(
40702
40866
  "cadViewerAutoRotateUserToggled",
40703
40867
  String(autoRotateUserToggled)
40704
40868
  );
40705
40869
  }, [autoRotateUserToggled]);
40706
- useEffect57(() => {
40870
+ useEffect58(() => {
40707
40871
  window.localStorage.setItem("cadViewerCameraType", cameraType);
40708
40872
  }, [cameraType]);
40709
40873
  const viewerKey = props.circuitJson ? circuitJsonKey : void 0;
@@ -40877,7 +41041,7 @@ var CadViewerInner = (props) => {
40877
41041
  };
40878
41042
  var CadViewer = (props) => {
40879
41043
  configureRuntimeFont();
40880
- const sceneRef = useRef30(null);
41044
+ const sceneRef = useRef31(null);
40881
41045
  return /* @__PURE__ */ jsx43(SchematicNavigationContext.Provider, { value: sceneRef, children: /* @__PURE__ */ jsx43(
40882
41046
  CameraControllerProvider,
40883
41047
  {
@@ -41194,10 +41358,10 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
41194
41358
  import {
41195
41359
  GLTFExporter as GLTFExporter3
41196
41360
  } from "three/examples/jsm/exporters/GLTFExporter.js";
41197
- import { useEffect as useEffect58, useState as useState47, useMemo as useMemo41, useCallback as useCallback26 } from "react";
41361
+ import { useEffect as useEffect59, useState as useState48, useMemo as useMemo42, useCallback as useCallback26 } from "react";
41198
41362
  function useSaveGltfAs(options = {}) {
41199
41363
  const parse2 = useParser(options);
41200
- const link = useMemo41(() => document.createElement("a"), []);
41364
+ const link = useMemo42(() => document.createElement("a"), []);
41201
41365
  const saveAs = async (filename) => {
41202
41366
  const name = filename ?? options.filename ?? "";
41203
41367
  if (options.binary == null) options.binary = name.endsWith(".glb");
@@ -41207,7 +41371,7 @@ function useSaveGltfAs(options = {}) {
41207
41371
  link.dispatchEvent(new MouseEvent("click"));
41208
41372
  URL.revokeObjectURL(url);
41209
41373
  };
41210
- useEffect58(
41374
+ useEffect59(
41211
41375
  () => () => {
41212
41376
  link.remove();
41213
41377
  instance = null;
@@ -41222,17 +41386,17 @@ function useSaveGltfAs(options = {}) {
41222
41386
  }
41223
41387
  function useExportGltfUrl(options = {}) {
41224
41388
  const parse2 = useParser(options);
41225
- const [url, setUrl] = useState47();
41226
- const [error, setError] = useState47();
41389
+ const [url, setUrl] = useState48();
41390
+ const [error, setError] = useState48();
41227
41391
  const ref = useCallback26(
41228
41392
  (instance) => parse2(instance).then(setUrl).catch(setError),
41229
41393
  []
41230
41394
  );
41231
- useEffect58(() => () => URL.revokeObjectURL(url), [url]);
41395
+ useEffect59(() => () => URL.revokeObjectURL(url), [url]);
41232
41396
  return [ref, url, error];
41233
41397
  }
41234
41398
  function useParser(options = {}) {
41235
- const exporter = useMemo41(() => new GLTFExporter3(), []);
41399
+ const exporter = useMemo42(() => new GLTFExporter3(), []);
41236
41400
  return (instance) => {
41237
41401
  const { promise, resolve, reject } = Promise.withResolvers();
41238
41402
  exporter.parse(