@tscircuit/3d-viewer 0.0.623 → 0.0.625

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -18979,8 +18979,8 @@ var useHiddenCadComponents = (circuitKey) => {
18979
18979
  };
18980
18980
 
18981
18981
  // src/CadViewer.tsx
18982
- import { useCallback as useCallback25, useContext as useContext11, useEffect as useEffect50, useRef as useRef29, useState as useState42 } from "react";
18983
- import * as THREE56 from "three";
18982
+ import { useCallback as useCallback25, useContext as useContext11, useEffect as useEffect51, useRef as useRef29, useState as useState42 } from "react";
18983
+ import * as THREE57 from "three";
18984
18984
 
18985
18985
  // src/hooks/use-convert-children-to-soup.ts
18986
18986
  import { Circuit } from "@tscircuit/core";
@@ -20945,13 +20945,13 @@ var AnyCadComponent = ({
20945
20945
  };
20946
20946
 
20947
20947
  // src/CadViewerContainer.tsx
20948
- import { forwardRef as forwardRef2, useEffect as useEffect21, useMemo as useMemo17, useState as useState13 } from "react";
20949
- import * as THREE26 from "three";
20948
+ import { forwardRef as forwardRef2, useEffect as useEffect22, useMemo as useMemo17, useState as useState13 } from "react";
20949
+ import * as THREE27 from "three";
20950
20950
 
20951
20951
  // package.json
20952
20952
  var package_default = {
20953
20953
  name: "@tscircuit/3d-viewer",
20954
- version: "0.0.622",
20954
+ version: "0.0.624",
20955
20955
  repository: {
20956
20956
  type: "git",
20957
20957
  url: "https://github.com/tscircuit/3d-viewer"
@@ -21018,8 +21018,8 @@ var package_default = {
21018
21018
  "@tscircuit/alphabet": "^0.0.25",
21019
21019
  "@tscircuit/circuit-json-util": "^0.0.119",
21020
21020
  "@tscircuit/copper-pour-solver": "^0.0.29",
21021
- "@tscircuit/core": "^0.0.2079",
21022
- "@tscircuit/props": "^0.0.685",
21021
+ "@tscircuit/core": "^0.0.2152",
21022
+ "@tscircuit/props": "^0.0.701",
21023
21023
  "@tscircuit/solver-utils": "^0.0.4",
21024
21024
  "@types/debug": "^4.1.13",
21025
21025
  "@types/jsdom": "^21.1.7",
@@ -21043,7 +21043,7 @@ var package_default = {
21043
21043
  "vite-tsconfig-paths": "^4.3.2",
21044
21044
  "circuit-json-to-gltf": "0.0.143",
21045
21045
  zod: "^3.25.67",
21046
- "@tscircuit/modelprinter": "^0.0.6"
21046
+ "@tscircuit/modelprinter": "^0.0.18"
21047
21047
  },
21048
21048
  engines: {
21049
21049
  node: "24.x"
@@ -21105,44 +21105,79 @@ import {
21105
21105
  useRef as useRef3,
21106
21106
  useState as useState11
21107
21107
  } from "react";
21108
+ import * as THREE16 from "three";
21109
+
21110
+ // src/utils/camera-session-storage.ts
21108
21111
  import * as THREE15 from "three";
21109
- import { jsx as jsx12 } from "react/jsx-runtime";
21110
- var CAMERA_KEY = "cadViewerCameraStateSession";
21111
- var saveCameraToSession = (camera, controls) => {
21112
+ var CAMERA_SESSION_STORAGE_KEY = "cadViewerCameraStateSession";
21113
+ function getCameraSessionStorageKey(cameraSessionScope) {
21114
+ if (!cameraSessionScope) return CAMERA_SESSION_STORAGE_KEY;
21115
+ return `${CAMERA_SESSION_STORAGE_KEY}:${cameraSessionScope}`;
21116
+ }
21117
+ function saveCameraSession({
21118
+ camera,
21119
+ controls,
21120
+ cameraSessionScope
21121
+ }) {
21112
21122
  try {
21113
- const savedCameraSession = {
21123
+ const storedCameraSession = {
21114
21124
  position: camera.position.toArray(),
21115
21125
  quaternion: camera.quaternion.toArray(),
21116
21126
  up: camera.up.toArray(),
21117
- fov: camera.fov ?? 50,
21127
+ fov: camera instanceof THREE15.PerspectiveCamera ? camera.fov : 50,
21118
21128
  target: controls.target.toArray()
21119
21129
  };
21120
- sessionStorage.setItem(CAMERA_KEY, JSON.stringify(savedCameraSession));
21121
- } catch (err) {
21122
- console.warn("Failed to save camera:", err);
21130
+ sessionStorage.setItem(
21131
+ getCameraSessionStorageKey(cameraSessionScope),
21132
+ JSON.stringify(storedCameraSession)
21133
+ );
21134
+ } catch (error) {
21135
+ console.warn("Failed to save camera:", error);
21123
21136
  }
21124
- };
21125
- var loadCameraFromSession = (camera, controls) => {
21137
+ }
21138
+ function loadCameraSession({
21139
+ camera,
21140
+ controls,
21141
+ cameraSessionScope
21142
+ }) {
21126
21143
  try {
21127
- const raw = sessionStorage.getItem(CAMERA_KEY);
21128
- if (!raw) return false;
21129
- const state = JSON.parse(raw);
21130
- camera.position.fromArray(state.position);
21131
- camera.quaternion.fromArray(state.quaternion);
21132
- camera.up.fromArray(state.up);
21133
- if ("fov" in camera) {
21134
- const persp = camera;
21135
- persp.fov = state.fov;
21136
- persp.updateProjectionMatrix?.();
21137
- }
21138
- controls.target.fromArray(state.target);
21144
+ const storedCameraSessionJson = sessionStorage.getItem(
21145
+ getCameraSessionStorageKey(cameraSessionScope)
21146
+ );
21147
+ if (!storedCameraSessionJson) return false;
21148
+ const storedCameraSession = JSON.parse(
21149
+ storedCameraSessionJson
21150
+ );
21151
+ camera.position.fromArray(storedCameraSession.position);
21152
+ camera.quaternion.fromArray(storedCameraSession.quaternion);
21153
+ camera.up.fromArray(storedCameraSession.up);
21154
+ if (camera instanceof THREE15.PerspectiveCamera) {
21155
+ camera.fov = storedCameraSession.fov;
21156
+ camera.updateProjectionMatrix();
21157
+ }
21158
+ controls.target.fromArray(storedCameraSession.target);
21139
21159
  controls.update();
21140
21160
  camera.updateMatrixWorld();
21141
21161
  return true;
21142
- } catch (err) {
21143
- console.warn("Failed to restore camera:", err);
21162
+ } catch (error) {
21163
+ console.warn("Failed to restore camera:", error);
21144
21164
  return false;
21145
21165
  }
21166
+ }
21167
+
21168
+ // src/contexts/CameraControllerContext.tsx
21169
+ import { jsx as jsx12 } from "react/jsx-runtime";
21170
+ function resolveCameraSessionContext(cameraSessionContext) {
21171
+ if ("controls" in cameraSessionContext) return cameraSessionContext;
21172
+ return { controls: cameraSessionContext };
21173
+ }
21174
+ var saveCameraToSession = (camera, cameraSessionContext) => {
21175
+ const { controls, cameraSessionScope } = resolveCameraSessionContext(cameraSessionContext);
21176
+ saveCameraSession({ camera, controls, cameraSessionScope });
21177
+ };
21178
+ var loadCameraFromSession = (camera, cameraSessionContext) => {
21179
+ const { controls, cameraSessionScope } = resolveCameraSessionContext(cameraSessionContext);
21180
+ return loadCameraSession({ camera, controls, cameraSessionScope });
21146
21181
  };
21147
21182
  var CameraControllerContext = createContext6(void 0);
21148
21183
  var CameraControllerProvider = ({ children, defaultTarget, initialCameraPosition, initialCameraType }) => {
@@ -21154,7 +21189,7 @@ var CameraControllerProvider = ({ children, defaultTarget, initialCameraPosition
21154
21189
  );
21155
21190
  const [cameraPosition, setCameraPosition] = useState11(initialCameraPosition ?? null);
21156
21191
  const [cameraRotation, setCameraRotation] = useState11(
21157
- new THREE15.Euler(0, 0, 0)
21192
+ new THREE16.Euler(0, 0, 0)
21158
21193
  );
21159
21194
  const baseDistance = useMemo11(() => {
21160
21195
  const [x, y, z] = initialCameraPosition ?? [5, -5, 5];
@@ -21308,7 +21343,7 @@ var useCameraController = () => {
21308
21343
 
21309
21344
  // src/hooks/cameraAnimation.ts
21310
21345
  import { useCallback as useCallback5, useEffect as useEffect14, useRef as useRef4 } from "react";
21311
- import * as THREE16 from "three";
21346
+ import * as THREE17 from "three";
21312
21347
  var easeInOutCubic = (t) => t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
21313
21348
  var CameraAnimatorWithContext = () => {
21314
21349
  const {
@@ -21319,24 +21354,24 @@ var CameraAnimatorWithContext = () => {
21319
21354
  getPresetConfig
21320
21355
  } = useCameraController();
21321
21356
  const animationRef = useRef4(null);
21322
- const tempQuaternion = useRef4(new THREE16.Quaternion());
21323
- const tempTarget = useRef4(new THREE16.Vector3());
21324
- const tempUp = useRef4(new THREE16.Vector3());
21325
- const tempRoll = useRef4(new THREE16.Quaternion());
21326
- const tempRollTarget = useRef4(new THREE16.Quaternion());
21327
- const baseOrientationHelper = useRef4(new THREE16.Object3D());
21328
- const orientationHelper = useRef4(new THREE16.Object3D());
21357
+ const tempQuaternion = useRef4(new THREE17.Quaternion());
21358
+ const tempTarget = useRef4(new THREE17.Vector3());
21359
+ const tempUp = useRef4(new THREE17.Vector3());
21360
+ const tempRoll = useRef4(new THREE17.Quaternion());
21361
+ const tempRollTarget = useRef4(new THREE17.Quaternion());
21362
+ const baseOrientationHelper = useRef4(new THREE17.Object3D());
21363
+ const orientationHelper = useRef4(new THREE17.Object3D());
21329
21364
  const animateTo = useCallback5(
21330
21365
  ({ position, target, up, durationMs = 600 }) => {
21331
21366
  if (!mainCameraRef.current) return;
21332
21367
  const currentTarget = controlsRef.current?.target ?? defaultTarget;
21333
- const toPosition = new THREE16.Vector3(
21368
+ const toPosition = new THREE17.Vector3(
21334
21369
  position[0],
21335
21370
  position[1],
21336
21371
  position[2]
21337
21372
  );
21338
- const resolvedTarget = target ? new THREE16.Vector3(target[0], target[1], target[2]) : defaultTarget.clone();
21339
- const resolvedUp = new THREE16.Vector3(...up ?? [0, 0, 1]).normalize();
21373
+ const resolvedTarget = target ? new THREE17.Vector3(target[0], target[1], target[2]) : defaultTarget.clone();
21374
+ const resolvedUp = new THREE17.Vector3(...up ?? [0, 0, 1]).normalize();
21340
21375
  const toOrientationHelper = orientationHelper.current;
21341
21376
  toOrientationHelper.position.copy(toPosition);
21342
21377
  toOrientationHelper.up.copy(resolvedUp);
@@ -21448,43 +21483,63 @@ var CameraAnimatorWithContext = () => {
21448
21483
  };
21449
21484
 
21450
21485
  // src/hooks/useCameraSession.ts
21451
- import { useCallback as useCallback6, useRef as useRef5 } from "react";
21452
- var useCameraSession = () => {
21486
+ import { useCallback as useCallback6, useEffect as useEffect15, useRef as useRef5 } from "react";
21487
+ var CAMERA_SESSION_NOT_RESTORED = /* @__PURE__ */ Symbol("camera-session-not-restored");
21488
+ var useCameraSession = ({
21489
+ cameraSessionScope
21490
+ } = {}) => {
21453
21491
  const { controlsRef } = useCameraController();
21454
21492
  const cameraRef = useRef5(null);
21455
- const cameraRestoredRef = useRef5(false);
21493
+ const restoredCameraSessionScopeRef = useRef5(CAMERA_SESSION_NOT_RESTORED);
21456
21494
  const saveTimeoutRef = useRef5(null);
21495
+ useEffect15(() => {
21496
+ return () => {
21497
+ if (saveTimeoutRef.current !== null) {
21498
+ clearTimeout(saveTimeoutRef.current);
21499
+ saveTimeoutRef.current = null;
21500
+ }
21501
+ };
21502
+ }, [cameraSessionScope]);
21457
21503
  const handleCameraCreated = useCallback6(
21458
21504
  (camera) => {
21459
21505
  cameraRef.current = camera;
21460
- if (!cameraRestoredRef.current && controlsRef.current) {
21461
- const restored = loadCameraFromSession(camera, controlsRef.current);
21506
+ if (restoredCameraSessionScopeRef.current !== cameraSessionScope && controlsRef.current) {
21507
+ const restored = loadCameraFromSession(camera, {
21508
+ controls: controlsRef.current,
21509
+ cameraSessionScope
21510
+ });
21511
+ restoredCameraSessionScopeRef.current = cameraSessionScope;
21462
21512
  if (restored) {
21463
- cameraRestoredRef.current = true;
21513
+ return;
21464
21514
  }
21465
21515
  }
21466
21516
  },
21467
- [controlsRef]
21517
+ [cameraSessionScope, controlsRef]
21468
21518
  );
21469
21519
  const handleControlsChange = useCallback6(() => {
21470
21520
  if (!cameraRef.current || !controlsRef.current) return;
21471
- if (!cameraRestoredRef.current) {
21472
- const restored = loadCameraFromSession(
21473
- cameraRef.current,
21474
- controlsRef.current
21475
- );
21521
+ if (restoredCameraSessionScopeRef.current !== cameraSessionScope) {
21522
+ const restored = loadCameraFromSession(cameraRef.current, {
21523
+ controls: controlsRef.current,
21524
+ cameraSessionScope
21525
+ });
21526
+ restoredCameraSessionScopeRef.current = cameraSessionScope;
21476
21527
  if (restored) {
21477
- cameraRestoredRef.current = true;
21478
21528
  return;
21479
21529
  }
21480
21530
  }
21481
- clearTimeout(saveTimeoutRef.current);
21531
+ if (saveTimeoutRef.current !== null) {
21532
+ clearTimeout(saveTimeoutRef.current);
21533
+ }
21482
21534
  saveTimeoutRef.current = setTimeout(() => {
21483
21535
  if (cameraRef.current && controlsRef.current) {
21484
- saveCameraToSession(cameraRef.current, controlsRef.current);
21536
+ saveCameraToSession(cameraRef.current, {
21537
+ controls: controlsRef.current,
21538
+ cameraSessionScope
21539
+ });
21485
21540
  }
21486
21541
  }, 150);
21487
- }, [controlsRef]);
21542
+ }, [cameraSessionScope, controlsRef]);
21488
21543
  return {
21489
21544
  handleCameraCreated,
21490
21545
  handleControlsChange
@@ -21494,14 +21549,14 @@ var useCameraSession = () => {
21494
21549
  // src/react-three/Canvas.tsx
21495
21550
  import {
21496
21551
  useRef as useRef6,
21497
- useEffect as useEffect15,
21552
+ useEffect as useEffect16,
21498
21553
  useState as useState12,
21499
21554
  useCallback as useCallback7,
21500
21555
  forwardRef,
21501
21556
  useImperativeHandle,
21502
21557
  useMemo as useMemo12
21503
21558
  } from "react";
21504
- import * as THREE18 from "three";
21559
+ import * as THREE19 from "three";
21505
21560
 
21506
21561
  // src/react-three/remove-existing-canvases.ts
21507
21562
  function removeExistingCanvases(container) {
@@ -21509,13 +21564,13 @@ function removeExistingCanvases(container) {
21509
21564
  }
21510
21565
 
21511
21566
  // src/react-three/configure-renderer.ts
21512
- import * as THREE17 from "three";
21567
+ import * as THREE18 from "three";
21513
21568
  var configureRenderer = (renderer) => {
21514
- renderer.outputColorSpace = THREE17.SRGBColorSpace;
21515
- renderer.toneMapping = THREE17.ACESFilmicToneMapping;
21569
+ renderer.outputColorSpace = THREE18.SRGBColorSpace;
21570
+ renderer.toneMapping = THREE18.ACESFilmicToneMapping;
21516
21571
  renderer.toneMappingExposure = 1;
21517
21572
  renderer.shadowMap.enabled = true;
21518
- renderer.shadowMap.type = THREE17.PCFSoftShadowMap;
21573
+ renderer.shadowMap.type = THREE18.PCFSoftShadowMap;
21519
21574
  };
21520
21575
 
21521
21576
  // src/react-three/Canvas.tsx
@@ -21547,16 +21602,16 @@ var Canvas = forwardRef(
21547
21602
  },
21548
21603
  []
21549
21604
  );
21550
- const scene = useMemo12(() => new THREE18.Scene(), []);
21605
+ const scene = useMemo12(() => new THREE19.Scene(), []);
21551
21606
  if (sceneProps?.up) {
21552
21607
  scene.up.set(sceneProps.up.x, sceneProps.up.y, sceneProps.up.z);
21553
21608
  }
21554
- const rootObject = useRef6(new THREE18.Object3D());
21609
+ const rootObject = useRef6(new THREE19.Object3D());
21555
21610
  useImperativeHandle(ref, () => rootObject.current);
21556
- useEffect15(() => {
21611
+ useEffect16(() => {
21557
21612
  if (!mountRef.current) return;
21558
21613
  removeExistingCanvases(mountRef.current);
21559
- const renderer = new THREE18.WebGLRenderer({ antialias: true, alpha: true });
21614
+ const renderer = new THREE19.WebGLRenderer({ antialias: true, alpha: true });
21560
21615
  configureRenderer(renderer);
21561
21616
  renderer.setSize(
21562
21617
  mountRef.current.clientWidth,
@@ -21565,7 +21620,7 @@ var Canvas = forwardRef(
21565
21620
  renderer.setPixelRatio(window.devicePixelRatio);
21566
21621
  mountRef.current.appendChild(renderer.domElement);
21567
21622
  const aspect = mountRef.current.clientWidth / mountRef.current.clientHeight;
21568
- const camera = cameraType === "perspective" ? new THREE18.PerspectiveCamera(75, aspect, 0.1, 1e3) : new THREE18.OrthographicCamera(
21623
+ const camera = cameraType === "perspective" ? new THREE19.PerspectiveCamera(75, aspect, 0.1, 1e3) : new THREE19.OrthographicCamera(
21569
21624
  -10 * aspect,
21570
21625
  10 * aspect,
21571
21626
  10,
@@ -21602,7 +21657,7 @@ var Canvas = forwardRef(
21602
21657
  });
21603
21658
  onCreatedRef.current?.({ camera, renderer });
21604
21659
  let animationFrameId;
21605
- const clock = new THREE18.Clock();
21660
+ const clock = new THREE19.Clock();
21606
21661
  let isVisible = true;
21607
21662
  const visibilityObserver = new IntersectionObserver(([entry]) => {
21608
21663
  isVisible = entry?.isIntersecting ?? false;
@@ -21621,9 +21676,9 @@ var Canvas = forwardRef(
21621
21676
  const handleResize = () => {
21622
21677
  if (mountRef.current?.clientWidth && mountRef.current.clientHeight) {
21623
21678
  const newAspect = mountRef.current.clientWidth / mountRef.current.clientHeight;
21624
- if (camera instanceof THREE18.PerspectiveCamera) {
21679
+ if (camera instanceof THREE19.PerspectiveCamera) {
21625
21680
  camera.aspect = newAspect;
21626
- } else if (camera instanceof THREE18.OrthographicCamera) {
21681
+ } else if (camera instanceof THREE19.OrthographicCamera) {
21627
21682
  camera.left = -10 * newAspect;
21628
21683
  camera.right = 10 * newAspect;
21629
21684
  camera.top = 10;
@@ -21661,8 +21716,8 @@ var Canvas = forwardRef(
21661
21716
  );
21662
21717
 
21663
21718
  // src/react-three/Grid.tsx
21664
- import { useEffect as useEffect16, useMemo as useMemo13 } from "react";
21665
- import * as THREE19 from "three";
21719
+ import { useEffect as useEffect17, useMemo as useMemo13 } from "react";
21720
+ import * as THREE20 from "three";
21666
21721
  var vertexShader = `
21667
21722
  varying vec3 worldPosition;
21668
21723
  void main() {
@@ -21708,24 +21763,24 @@ var Grid = ({
21708
21763
  const { scene, camera } = useThree();
21709
21764
  const size4 = 1e3;
21710
21765
  const gridMesh = useMemo13(() => {
21711
- const geometry = new THREE19.PlaneGeometry(size4, size4);
21766
+ const geometry = new THREE20.PlaneGeometry(size4, size4);
21712
21767
  geometry.rotateX(-Math.PI / 2);
21713
- const material = new THREE19.ShaderMaterial({
21768
+ const material = new THREE20.ShaderMaterial({
21714
21769
  vertexShader,
21715
21770
  fragmentShader,
21716
21771
  uniforms: {
21717
21772
  cellSize: { value: cellSize },
21718
21773
  sectionSize: { value: sectionSize },
21719
- gridColor: { value: new THREE19.Color(15658734) },
21720
- sectionColor: { value: new THREE19.Color(13421823) },
21774
+ gridColor: { value: new THREE20.Color(15658734) },
21775
+ sectionColor: { value: new THREE20.Color(13421823) },
21721
21776
  fadeDistance: { value: 100 },
21722
21777
  // Fade out based on sectionSize
21723
21778
  fadeStrength: { value: 1.5 }
21724
21779
  },
21725
21780
  transparent: true,
21726
- side: THREE19.DoubleSide
21781
+ side: THREE20.DoubleSide
21727
21782
  });
21728
- const mesh = new THREE19.Mesh(geometry, material);
21783
+ const mesh = new THREE20.Mesh(geometry, material);
21729
21784
  if (rotation) {
21730
21785
  mesh.rotation.fromArray(rotation);
21731
21786
  }
@@ -21736,7 +21791,7 @@ var Grid = ({
21736
21791
  gridMesh.position.set(camera.position.x, camera.position.y, 0);
21737
21792
  }
21738
21793
  });
21739
- useEffect16(() => {
21794
+ useEffect17(() => {
21740
21795
  if (!scene || !gridMesh) return;
21741
21796
  scene.add(gridMesh);
21742
21797
  return () => {
@@ -21753,8 +21808,8 @@ var Grid = ({
21753
21808
  };
21754
21809
 
21755
21810
  // src/react-three/Lights.tsx
21756
- import { useEffect as useEffect17, useMemo as useMemo14 } from "react";
21757
- import * as THREE20 from "three";
21811
+ import { useEffect as useEffect18, useMemo as useMemo14 } from "react";
21812
+ import * as THREE21 from "three";
21758
21813
  var UNDERSIDE_LIGHT_FACTOR = 0.75;
21759
21814
  var Lights = ({
21760
21815
  boardDimensions,
@@ -21764,7 +21819,7 @@ var Lights = ({
21764
21819
  }) => {
21765
21820
  const { scene } = useThree();
21766
21821
  const lightRig = useMemo14(() => {
21767
- const rig = new THREE20.Group();
21822
+ const rig = new THREE21.Group();
21768
21823
  rig.name = "cad-viewer-light-rig";
21769
21824
  const centerX = boardCenter?.x ?? 0;
21770
21825
  const centerY = boardCenter?.y ?? 0;
@@ -21776,14 +21831,14 @@ var Lights = ({
21776
21831
  const shadowHalfSize = largestBoardDimension * 0.8;
21777
21832
  const lightDistance = largestBoardDimension;
21778
21833
  const keyLightDistance = largestBoardDimension * 1.7;
21779
- const ambientLight = new THREE20.AmbientLight(16186360, 0.22);
21834
+ const ambientLight = new THREE21.AmbientLight(16186360, 0.22);
21780
21835
  ambientLight.name = "cad-viewer-soft-ambient";
21781
21836
  rig.add(ambientLight);
21782
- const hemisphereLight = new THREE20.HemisphereLight(15004141, 1581597, 0.2);
21837
+ const hemisphereLight = new THREE21.HemisphereLight(15004141, 1581597, 0.2);
21783
21838
  hemisphereLight.name = "cad-viewer-hemisphere";
21784
21839
  rig.add(hemisphereLight);
21785
21840
  const addDirectionalLight = (name, color, intensity, position, castShadow = false) => {
21786
- const light = new THREE20.DirectionalLight(color, intensity);
21841
+ const light = new THREE21.DirectionalLight(color, intensity);
21787
21842
  light.name = name;
21788
21843
  light.position.set(
21789
21844
  centerX + position[0],
@@ -21857,17 +21912,17 @@ var Lights = ({
21857
21912
  );
21858
21913
  return rig;
21859
21914
  }, [boardCenter, boardDimensions, shadowsEnabled]);
21860
- useEffect17(() => {
21915
+ useEffect18(() => {
21861
21916
  const previousBackground = scene.background;
21862
21917
  const previousEnvironment = scene.environment;
21863
- scene.background = darkBackgroundEnabled ? new THREE20.Color(1053456) : null;
21918
+ scene.background = darkBackgroundEnabled ? new THREE21.Color(1053456) : null;
21864
21919
  scene.environment = null;
21865
21920
  return () => {
21866
21921
  scene.background = previousBackground;
21867
21922
  scene.environment = previousEnvironment;
21868
21923
  };
21869
21924
  }, [darkBackgroundEnabled, scene]);
21870
- useEffect17(() => {
21925
+ useEffect18(() => {
21871
21926
  if (!scene) return;
21872
21927
  scene.add(lightRig);
21873
21928
  return () => {
@@ -21878,12 +21933,12 @@ var Lights = ({
21878
21933
  };
21879
21934
 
21880
21935
  // src/react-three/OrbitControls.tsx
21881
- import { useEffect as useEffect18, useMemo as useMemo15 } from "react";
21882
- import * as THREE22 from "three";
21936
+ import { useEffect as useEffect19, useMemo as useMemo15 } from "react";
21937
+ import * as THREE23 from "three";
21883
21938
  import { OrbitControls as ThreeOrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
21884
21939
 
21885
21940
  // src/react-three/infinite-dolly.ts
21886
- import * as THREE21 from "three";
21941
+ import * as THREE22 from "three";
21887
21942
  var MINIMUM_DOLLY_DISTANCE_RATIO = 0.05;
21888
21943
  var getMinimumDollyDistance = ({
21889
21944
  camera,
@@ -21897,12 +21952,12 @@ var applyInfiniteDolly = ({
21897
21952
  controls,
21898
21953
  minimumDollyDistance
21899
21954
  }) => {
21900
- if (!(camera instanceof THREE21.PerspectiveCamera)) return false;
21955
+ if (!(camera instanceof THREE22.PerspectiveCamera)) return false;
21901
21956
  const orbitDistance = controls.getDistance();
21902
21957
  if (Number.isFinite(orbitDistance) && orbitDistance >= minimumDollyDistance) {
21903
21958
  return false;
21904
21959
  }
21905
- const viewDirection = new THREE21.Vector3();
21960
+ const viewDirection = new THREE22.Vector3();
21906
21961
  camera.getWorldDirection(viewDirection);
21907
21962
  controls.target.copy(camera.position).addScaledVector(viewDirection, minimumDollyDistance);
21908
21963
  return true;
@@ -21927,7 +21982,7 @@ var OrbitControls = ({
21927
21982
  return new ThreeOrbitControls(camera, renderer.domElement);
21928
21983
  }, [camera, renderer]);
21929
21984
  const minimumDollyDistance = useMemo15(() => {
21930
- if (!controls || !(camera instanceof THREE22.PerspectiveCamera)) {
21985
+ if (!controls || !(camera instanceof THREE23.PerspectiveCamera)) {
21931
21986
  return Number.EPSILON;
21932
21987
  }
21933
21988
  const initialOrbitDistance = target ? Math.hypot(
@@ -21937,11 +21992,11 @@ var OrbitControls = ({
21937
21992
  ) : controls.getDistance();
21938
21993
  return getMinimumDollyDistance({ camera, initialOrbitDistance });
21939
21994
  }, [camera, controls, target]);
21940
- useEffect18(() => {
21995
+ useEffect19(() => {
21941
21996
  onControlsChange?.(controls ?? null);
21942
21997
  return () => onControlsChange?.(null);
21943
21998
  }, [controls, onControlsChange]);
21944
- useEffect18(() => {
21999
+ useEffect19(() => {
21945
22000
  if (!controls) return;
21946
22001
  const handleChange = () => {
21947
22002
  onControlsChange?.(controls);
@@ -21951,7 +22006,7 @@ var OrbitControls = ({
21951
22006
  controls.removeEventListener("change", handleChange);
21952
22007
  };
21953
22008
  }, [controls, onControlsChange]);
21954
- useEffect18(() => {
22009
+ useEffect19(() => {
21955
22010
  if (!controls) return;
21956
22011
  controls.autoRotate = autoRotate || false;
21957
22012
  controls.autoRotateSpeed = autoRotateSpeed || 1;
@@ -21962,9 +22017,9 @@ var OrbitControls = ({
21962
22017
  if (dampingFactor !== void 0) controls.dampingFactor = dampingFactor;
21963
22018
  controls.zoomToCursor = true;
21964
22019
  controls.mouseButtons = {
21965
- LEFT: THREE22.MOUSE.ROTATE,
22020
+ LEFT: THREE23.MOUSE.ROTATE,
21966
22021
  // Left click to rotate
21967
- MIDDLE: THREE22.MOUSE.PAN,
22022
+ MIDDLE: THREE23.MOUSE.PAN,
21968
22023
  // Middle click to pan
21969
22024
  RIGHT: null
21970
22025
  // Right-click always disabled - only context menu
@@ -21984,14 +22039,14 @@ var OrbitControls = ({
21984
22039
  dampingFactor,
21985
22040
  target
21986
22041
  ]);
21987
- useEffect18(() => {
22042
+ useEffect19(() => {
21988
22043
  if (!controls || !onStart) return;
21989
22044
  controls.addEventListener("start", onStart);
21990
22045
  return () => {
21991
22046
  controls.removeEventListener("start", onStart);
21992
22047
  };
21993
22048
  }, [controls, onStart]);
21994
- useEffect18(() => {
22049
+ useEffect19(() => {
21995
22050
  if (!controls) return;
21996
22051
  return () => {
21997
22052
  controls.dispose();
@@ -22087,15 +22142,15 @@ var getComparisonBounds = (type, boardDimensions, boardCenter) => {
22087
22142
  };
22088
22143
 
22089
22144
  // src/three-components/OrientationCubeCanvas.tsx
22090
- import { useEffect as useEffect19, useRef as useRef7 } from "react";
22091
- import * as THREE23 from "three";
22145
+ import { useEffect as useEffect20, useRef as useRef7 } from "react";
22146
+ import * as THREE24 from "three";
22092
22147
  import { Text as TroikaText } from "troika-three-text";
22093
22148
  import { jsx as jsx14 } from "react/jsx-runtime";
22094
22149
  function computePointInFront(rotationVector, distance5) {
22095
- const quaternion = new THREE23.Quaternion().setFromEuler(
22096
- new THREE23.Euler(rotationVector.x, rotationVector.y, rotationVector.z)
22150
+ const quaternion = new THREE24.Quaternion().setFromEuler(
22151
+ new THREE24.Euler(rotationVector.x, rotationVector.y, rotationVector.z)
22097
22152
  );
22098
- const forwardVector = new THREE23.Vector3(0, 0, 1);
22153
+ const forwardVector = new THREE24.Vector3(0, 0, 1);
22099
22154
  forwardVector.applyQuaternion(quaternion);
22100
22155
  const result = forwardVector.multiplyScalar(distance5);
22101
22156
  return result;
@@ -22103,36 +22158,36 @@ function computePointInFront(rotationVector, distance5) {
22103
22158
  var OrientationCubeCanvas = () => {
22104
22159
  const { mainCameraRef } = useCameraController();
22105
22160
  const containerRef = useRef7(null);
22106
- useEffect19(() => {
22161
+ useEffect20(() => {
22107
22162
  if (!containerRef.current) return;
22108
22163
  const container = containerRef.current;
22109
22164
  const canvas = document.createElement("canvas");
22110
22165
  container.appendChild(canvas);
22111
- const renderer = new THREE23.WebGLRenderer({
22166
+ const renderer = new THREE24.WebGLRenderer({
22112
22167
  canvas,
22113
22168
  antialias: true,
22114
22169
  alpha: true
22115
22170
  });
22116
22171
  renderer.setSize(120, 120);
22117
22172
  renderer.setPixelRatio(window.devicePixelRatio);
22118
- const scene = new THREE23.Scene();
22119
- const camera = new THREE23.PerspectiveCamera(75, 1, 0.1, 1e3);
22173
+ const scene = new THREE24.Scene();
22174
+ const camera = new THREE24.PerspectiveCamera(75, 1, 0.1, 1e3);
22120
22175
  camera.up.set(0, 0, 1);
22121
- const ambientLight = new THREE23.AmbientLight(16777215, Math.PI / 2);
22176
+ const ambientLight = new THREE24.AmbientLight(16777215, Math.PI / 2);
22122
22177
  scene.add(ambientLight);
22123
- const group = new THREE23.Group();
22178
+ const group = new THREE24.Group();
22124
22179
  group.rotation.fromArray([Math.PI / 2, 0, 0]);
22125
22180
  const cubeSize = 1;
22126
- const box = new THREE23.Mesh(
22127
- new THREE23.BoxGeometry(cubeSize, cubeSize, cubeSize),
22128
- new THREE23.MeshStandardMaterial({ color: "white" })
22181
+ const box = new THREE24.Mesh(
22182
+ new THREE24.BoxGeometry(cubeSize, cubeSize, cubeSize),
22183
+ new THREE24.MeshStandardMaterial({ color: "white" })
22129
22184
  );
22130
22185
  group.add(box);
22131
- const edges = new THREE23.LineSegments(
22132
- new THREE23.EdgesGeometry(
22133
- new THREE23.BoxGeometry(cubeSize, cubeSize, cubeSize)
22186
+ const edges = new THREE24.LineSegments(
22187
+ new THREE24.EdgesGeometry(
22188
+ new THREE24.BoxGeometry(cubeSize, cubeSize, cubeSize)
22134
22189
  ),
22135
- new THREE23.LineBasicMaterial({ color: 0, linewidth: 2 })
22190
+ new THREE24.LineBasicMaterial({ color: 0, linewidth: 2 })
22136
22191
  );
22137
22192
  group.add(edges);
22138
22193
  scene.add(group);
@@ -22194,7 +22249,7 @@ var OrientationCubeCanvas = () => {
22194
22249
  if (!isVisible) return;
22195
22250
  if (mainCameraRef.current) {
22196
22251
  const cameraPosition = computePointInFront(
22197
- mainCameraRef.current.rotation ?? new THREE23.Euler(0, 0, 0),
22252
+ mainCameraRef.current.rotation ?? new THREE24.Euler(0, 0, 0),
22198
22253
  2
22199
22254
  );
22200
22255
  if (!cameraPosition.equals(camera.position)) {
@@ -22243,15 +22298,15 @@ var OrientationCubeCanvas = () => {
22243
22298
  };
22244
22299
 
22245
22300
  // src/three-components/reference-object.tsx
22246
- import { useEffect as useEffect20, useMemo as useMemo16 } from "react";
22301
+ import { useEffect as useEffect21, useMemo as useMemo16 } from "react";
22247
22302
 
22248
22303
  // src/reference-objects/create-reference-object.ts
22249
- import * as THREE24 from "three";
22304
+ import * as THREE25 from "three";
22250
22305
  var createRoundedRectangleShape = (width, height, radius) => {
22251
22306
  const halfWidth = width / 2;
22252
22307
  const halfHeight = height / 2;
22253
22308
  const safeRadius = Math.min(radius, halfWidth, halfHeight);
22254
- const shape = new THREE24.Shape();
22309
+ const shape = new THREE25.Shape();
22255
22310
  shape.moveTo(-halfWidth + safeRadius, -halfHeight);
22256
22311
  shape.lineTo(halfWidth - safeRadius, -halfHeight);
22257
22312
  shape.quadraticCurveTo(
@@ -22290,7 +22345,7 @@ var createRoundedPrismGeometry = (width, height, depth, radius) => {
22290
22345
  );
22291
22346
  };
22292
22347
  var createPrismGeometryFromShape = (shape, depth) => {
22293
- const geometry = new THREE24.ExtrudeGeometry(shape, {
22348
+ const geometry = new THREE25.ExtrudeGeometry(shape, {
22294
22349
  depth,
22295
22350
  bevelEnabled: false,
22296
22351
  curveSegments: 24
@@ -22302,16 +22357,16 @@ var createPrismGeometryFromShape = (shape, depth) => {
22302
22357
  var normalizeObjectToSpec = (object, type) => {
22303
22358
  const spec = REFERENCE_OBJECT_SPECS[type];
22304
22359
  object.updateMatrixWorld(true);
22305
- const initialBounds = new THREE24.Box3().setFromObject(object);
22306
- const initialSize = initialBounds.getSize(new THREE24.Vector3());
22360
+ const initialBounds = new THREE25.Box3().setFromObject(object);
22361
+ const initialSize = initialBounds.getSize(new THREE25.Vector3());
22307
22362
  object.scale.set(
22308
22363
  spec.width / initialSize.x,
22309
22364
  spec.height / initialSize.y,
22310
22365
  spec.depth / initialSize.z
22311
22366
  );
22312
22367
  object.updateMatrixWorld(true);
22313
- const scaledBounds = new THREE24.Box3().setFromObject(object);
22314
- const scaledCenter = scaledBounds.getCenter(new THREE24.Vector3());
22368
+ const scaledBounds = new THREE25.Box3().setFromObject(object);
22369
+ const scaledCenter = scaledBounds.getCenter(new THREE25.Vector3());
22315
22370
  object.position.set(
22316
22371
  -scaledCenter.x,
22317
22372
  -scaledCenter.y,
@@ -22320,15 +22375,15 @@ var normalizeObjectToSpec = (object, type) => {
22320
22375
  object.updateMatrixWorld(true);
22321
22376
  };
22322
22377
  var createBananaGeometry = () => {
22323
- const curve = new THREE24.CatmullRomCurve3([
22324
- new THREE24.Vector3(-82, 18, 16),
22325
- new THREE24.Vector3(-67, 7, 15),
22326
- new THREE24.Vector3(-43, -9, 14),
22327
- new THREE24.Vector3(-15, -18, 14),
22328
- new THREE24.Vector3(16, -18, 14),
22329
- new THREE24.Vector3(47, -8, 14.5),
22330
- new THREE24.Vector3(72, 8, 16),
22331
- new THREE24.Vector3(84, 19, 17)
22378
+ const curve = new THREE25.CatmullRomCurve3([
22379
+ new THREE25.Vector3(-82, 18, 16),
22380
+ new THREE25.Vector3(-67, 7, 15),
22381
+ new THREE25.Vector3(-43, -9, 14),
22382
+ new THREE25.Vector3(-15, -18, 14),
22383
+ new THREE25.Vector3(16, -18, 14),
22384
+ new THREE25.Vector3(47, -8, 14.5),
22385
+ new THREE25.Vector3(72, 8, 16),
22386
+ new THREE25.Vector3(84, 19, 17)
22332
22387
  ]);
22333
22388
  const tubularSegments = 84;
22334
22389
  const radialSegments = 30;
@@ -22338,8 +22393,8 @@ var createBananaGeometry = () => {
22338
22393
  const colors2 = [];
22339
22394
  const uvs = [];
22340
22395
  const indices = [];
22341
- const ripeYellow = new THREE24.Color(16766023);
22342
- const stemGreen = new THREE24.Color(12038965);
22396
+ const ripeYellow = new THREE25.Color(16766023);
22397
+ const stemGreen = new THREE25.Color(12038965);
22343
22398
  for (let segment = 0; segment <= tubularSegments; segment++) {
22344
22399
  const t = segment / tubularSegments;
22345
22400
  const point = curve.getPointAt(t);
@@ -22354,7 +22409,7 @@ var createBananaGeometry = () => {
22354
22409
  const sin = Math.sin(angle3);
22355
22410
  const cos = Math.cos(angle3);
22356
22411
  const ridgeScale = 1 + Math.cos(angle3 * 5 + 0.35) * 0.035;
22357
- const radialNormal = new THREE24.Vector3().addScaledVector(normal, cos).addScaledVector(binormal, sin * 0.9).normalize();
22412
+ const radialNormal = new THREE25.Vector3().addScaledVector(normal, cos).addScaledVector(binormal, sin * 0.9).normalize();
22358
22413
  const vertex = point.clone().addScaledVector(normal, cos * radius * ridgeScale).addScaledVector(binormal, sin * radius * 0.9 * ridgeScale);
22359
22414
  positions.push(vertex.x, vertex.y, vertex.z);
22360
22415
  normals.push(radialNormal.x, radialNormal.y, radialNormal.z);
@@ -22372,26 +22427,26 @@ var createBananaGeometry = () => {
22372
22427
  indices.push(a, d, b, b, d, c);
22373
22428
  }
22374
22429
  }
22375
- const geometry = new THREE24.BufferGeometry();
22430
+ const geometry = new THREE25.BufferGeometry();
22376
22431
  geometry.setIndex(indices);
22377
22432
  geometry.setAttribute(
22378
22433
  "position",
22379
- new THREE24.Float32BufferAttribute(positions, 3)
22434
+ new THREE25.Float32BufferAttribute(positions, 3)
22380
22435
  );
22381
- geometry.setAttribute("normal", new THREE24.Float32BufferAttribute(normals, 3));
22382
- geometry.setAttribute("color", new THREE24.Float32BufferAttribute(colors2, 3));
22383
- geometry.setAttribute("uv", new THREE24.Float32BufferAttribute(uvs, 2));
22436
+ geometry.setAttribute("normal", new THREE25.Float32BufferAttribute(normals, 3));
22437
+ geometry.setAttribute("color", new THREE25.Float32BufferAttribute(colors2, 3));
22438
+ geometry.setAttribute("uv", new THREE25.Float32BufferAttribute(uvs, 2));
22384
22439
  geometry.computeBoundingBox();
22385
22440
  geometry.computeBoundingSphere();
22386
22441
  return { geometry, curve };
22387
22442
  };
22388
22443
  var createBanana = () => {
22389
- const group = new THREE24.Group();
22390
- const banana = new THREE24.Group();
22444
+ const group = new THREE25.Group();
22445
+ const banana = new THREE25.Group();
22391
22446
  const { geometry, curve } = createBananaGeometry();
22392
- const peel = new THREE24.Mesh(
22447
+ const peel = new THREE25.Mesh(
22393
22448
  geometry,
22394
- new THREE24.MeshStandardMaterial({
22449
+ new THREE25.MeshStandardMaterial({
22395
22450
  color: 16777215,
22396
22451
  roughness: 0.72,
22397
22452
  metalness: 0,
@@ -22400,9 +22455,9 @@ var createBanana = () => {
22400
22455
  );
22401
22456
  peel.name = "banana-peel";
22402
22457
  banana.add(peel);
22403
- const blossomTip = new THREE24.Mesh(
22404
- new THREE24.SphereGeometry(3.4, 20, 12),
22405
- new THREE24.MeshStandardMaterial({
22458
+ const blossomTip = new THREE25.Mesh(
22459
+ new THREE25.SphereGeometry(3.4, 20, 12),
22460
+ new THREE25.MeshStandardMaterial({
22406
22461
  color: 6242844,
22407
22462
  roughness: 0.92
22408
22463
  })
@@ -22413,20 +22468,20 @@ var createBanana = () => {
22413
22468
  banana.add(blossomTip);
22414
22469
  const stemLength = 11;
22415
22470
  const stemTangent = curve.getTangentAt(1).normalize();
22416
- const stem = new THREE24.Mesh(
22417
- new THREE24.CylinderGeometry(2.5, 4.1, stemLength, 18),
22418
- new THREE24.MeshStandardMaterial({
22471
+ const stem = new THREE25.Mesh(
22472
+ new THREE25.CylinderGeometry(2.5, 4.1, stemLength, 18),
22473
+ new THREE25.MeshStandardMaterial({
22419
22474
  color: 8483625,
22420
22475
  roughness: 0.82
22421
22476
  })
22422
22477
  );
22423
- stem.quaternion.setFromUnitVectors(new THREE24.Vector3(0, 1, 0), stemTangent);
22478
+ stem.quaternion.setFromUnitVectors(new THREE25.Vector3(0, 1, 0), stemTangent);
22424
22479
  stem.position.copy(curve.getPointAt(1)).addScaledVector(stemTangent, stemLength / 2);
22425
22480
  stem.name = "banana-stem";
22426
22481
  banana.add(stem);
22427
- const stemTip = new THREE24.Mesh(
22428
- new THREE24.SphereGeometry(2.55, 18, 10),
22429
- new THREE24.MeshStandardMaterial({
22482
+ const stemTip = new THREE25.Mesh(
22483
+ new THREE25.SphereGeometry(2.55, 18, 10),
22484
+ new THREE25.MeshStandardMaterial({
22430
22485
  color: 5981470,
22431
22486
  roughness: 0.9
22432
22487
  })
@@ -22440,7 +22495,7 @@ var createBanana = () => {
22440
22495
  };
22441
22496
  var createMacbookLidGeometry = (width, height, depth, radius, indentRadius) => {
22442
22497
  const lidShape = createRoundedRectangleShape(width, height, radius);
22443
- const indent = new THREE24.Path();
22498
+ const indent = new THREE25.Path();
22444
22499
  indent.absarc(0, 0, indentRadius, 0, Math.PI * 2, true);
22445
22500
  lidShape.holes.push(indent);
22446
22501
  return createPrismGeometryFromShape(lidShape, depth);
@@ -22448,9 +22503,9 @@ var createMacbookLidGeometry = (width, height, depth, radius, indentRadius) => {
22448
22503
  var createMacbookIndent = (topZ, radius) => {
22449
22504
  const indentDepth = 0.35;
22450
22505
  const diskDepth = 0.25;
22451
- const disk = new THREE24.Mesh(
22452
- new THREE24.CylinderGeometry(radius - 0.15, radius - 0.15, diskDepth, 48),
22453
- new THREE24.MeshStandardMaterial({
22506
+ const disk = new THREE25.Mesh(
22507
+ new THREE25.CylinderGeometry(radius - 0.15, radius - 0.15, diskDepth, 48),
22508
+ new THREE25.MeshStandardMaterial({
22454
22509
  color: 10199202,
22455
22510
  roughness: 0.48,
22456
22511
  metalness: 0.28
@@ -22463,10 +22518,10 @@ var createMacbookIndent = (topZ, radius) => {
22463
22518
  };
22464
22519
  var createCreditCard = () => {
22465
22520
  const spec = REFERENCE_OBJECT_SPECS["credit-card"];
22466
- const group = new THREE24.Group();
22467
- const body = new THREE24.Mesh(
22521
+ const group = new THREE25.Group();
22522
+ const body = new THREE25.Mesh(
22468
22523
  createRoundedPrismGeometry(spec.width, spec.height, spec.depth, 3.18),
22469
- new THREE24.MeshStandardMaterial({
22524
+ new THREE25.MeshStandardMaterial({
22470
22525
  color: 2383272,
22471
22526
  roughness: 0.38,
22472
22527
  metalness: 0.08
@@ -22475,9 +22530,9 @@ var createCreditCard = () => {
22475
22530
  body.name = "credit-card-body";
22476
22531
  group.add(body);
22477
22532
  const surfaceZ = spec.depth / 2 + 0.08;
22478
- const chip = new THREE24.Mesh(
22533
+ const chip = new THREE25.Mesh(
22479
22534
  createRoundedPrismGeometry(12, 9, 0.14, 1.2),
22480
- new THREE24.MeshStandardMaterial({
22535
+ new THREE25.MeshStandardMaterial({
22481
22536
  color: 14003525,
22482
22537
  roughness: 0.3,
22483
22538
  metalness: 0.62
@@ -22486,14 +22541,14 @@ var createCreditCard = () => {
22486
22541
  chip.position.set(-21, 3, surfaceZ);
22487
22542
  chip.name = "credit-card-chip";
22488
22543
  group.add(chip);
22489
- const stripeMaterial = new THREE24.MeshStandardMaterial({
22544
+ const stripeMaterial = new THREE25.MeshStandardMaterial({
22490
22545
  color: 15331061,
22491
22546
  roughness: 0.45,
22492
22547
  metalness: 0.05
22493
22548
  });
22494
22549
  for (let index2 = 0; index2 < 4; index2++) {
22495
- const stripe = new THREE24.Mesh(
22496
- new THREE24.BoxGeometry(index2 === 3 ? 8 : 12, 0.8, 0.1),
22550
+ const stripe = new THREE25.Mesh(
22551
+ new THREE25.BoxGeometry(index2 === 3 ? 8 : 12, 0.8, 0.1),
22497
22552
  stripeMaterial
22498
22553
  );
22499
22554
  stripe.position.set(-20 + index2 * 14, -14, surfaceZ + 0.08);
@@ -22504,13 +22559,13 @@ var createCreditCard = () => {
22504
22559
  };
22505
22560
  var createMacbook = () => {
22506
22561
  const spec = REFERENCE_OBJECT_SPECS["14in-macbook"];
22507
- const group = new THREE24.Group();
22508
- const aluminumMaterial = new THREE24.MeshStandardMaterial({
22562
+ const group = new THREE25.Group();
22563
+ const aluminumMaterial = new THREE25.MeshStandardMaterial({
22509
22564
  color: 12896201,
22510
22565
  roughness: 0.3,
22511
22566
  metalness: 0.38
22512
22567
  });
22513
- const body = new THREE24.Mesh(
22568
+ const body = new THREE25.Mesh(
22514
22569
  createRoundedPrismGeometry(spec.width, spec.height, 13.5, 9),
22515
22570
  aluminumMaterial
22516
22571
  );
@@ -22521,7 +22576,7 @@ var createMacbook = () => {
22521
22576
  const lidCenterZ = 6.75;
22522
22577
  const lidTopZ = lidCenterZ + lidDepth / 2;
22523
22578
  const indentRadius = 12;
22524
- const lid = new THREE24.Mesh(
22579
+ const lid = new THREE25.Mesh(
22525
22580
  createMacbookLidGeometry(
22526
22581
  spec.width - 1.8,
22527
22582
  spec.height - 1.8,
@@ -22534,9 +22589,9 @@ var createMacbook = () => {
22534
22589
  lid.position.z = lidCenterZ;
22535
22590
  lid.name = "macbook-lid";
22536
22591
  group.add(lid);
22537
- const hinge = new THREE24.Mesh(
22538
- new THREE24.BoxGeometry(spec.width - 42, 3.2, 1.2),
22539
- new THREE24.MeshStandardMaterial({
22592
+ const hinge = new THREE25.Mesh(
22593
+ new THREE25.BoxGeometry(spec.width - 42, 3.2, 1.2),
22594
+ new THREE25.MeshStandardMaterial({
22540
22595
  color: 3158838,
22541
22596
  roughness: 0.55,
22542
22597
  metalness: 0.45
@@ -22546,9 +22601,9 @@ var createMacbook = () => {
22546
22601
  hinge.name = "macbook-hinge";
22547
22602
  group.add(hinge);
22548
22603
  group.add(createMacbookIndent(lidTopZ, indentRadius));
22549
- const frontNotch = new THREE24.Mesh(
22550
- new THREE24.BoxGeometry(54, 1.2, 0.8),
22551
- new THREE24.MeshStandardMaterial({
22604
+ const frontNotch = new THREE25.Mesh(
22605
+ new THREE25.BoxGeometry(54, 1.2, 0.8),
22606
+ new THREE25.MeshStandardMaterial({
22552
22607
  color: 6712174,
22553
22608
  roughness: 0.45,
22554
22609
  metalness: 0.5
@@ -22571,7 +22626,7 @@ var disposeReferenceObject = (object) => {
22571
22626
  const geometries = /* @__PURE__ */ new Set();
22572
22627
  const materials = /* @__PURE__ */ new Set();
22573
22628
  object.traverse((child) => {
22574
- if (!(child instanceof THREE24.Mesh)) return;
22629
+ if (!(child instanceof THREE25.Mesh)) return;
22575
22630
  geometries.add(child.geometry);
22576
22631
  const childMaterials = Array.isArray(child.material) ? child.material : [child.material];
22577
22632
  for (const material of childMaterials) materials.add(material);
@@ -22581,28 +22636,28 @@ var disposeReferenceObject = (object) => {
22581
22636
  };
22582
22637
 
22583
22638
  // src/reference-objects/fit-camera-to-bounds.ts
22584
- import * as THREE25 from "three";
22639
+ import * as THREE26 from "three";
22585
22640
  var fitCameraToBounds = (camera, controls, bounds, padding = 1.18) => {
22586
22641
  const width = Math.max(bounds.maxX - bounds.minX, 0);
22587
22642
  const height = Math.max(bounds.maxY - bounds.minY, 0);
22588
22643
  const depth = Math.max(bounds.maxZ - bounds.minZ, 0);
22589
- const center = new THREE25.Vector3(
22644
+ const center = new THREE26.Vector3(
22590
22645
  (bounds.minX + bounds.maxX) / 2,
22591
22646
  (bounds.minY + bounds.maxY) / 2,
22592
22647
  (bounds.minZ + bounds.maxZ) / 2
22593
22648
  );
22594
22649
  const radius = Math.max(Math.hypot(width, height, depth) / 2, 1);
22595
- const previousTarget = controls?.target ?? new THREE25.Vector3();
22596
- const direction = new THREE25.Vector3(0, -0.75, 0.9).normalize();
22650
+ const previousTarget = controls?.target ?? new THREE26.Vector3();
22651
+ const direction = new THREE26.Vector3(0, -0.75, 0.9).normalize();
22597
22652
  let distance5 = Math.max(camera.position.distanceTo(previousTarget), 5);
22598
- if (camera instanceof THREE25.PerspectiveCamera) {
22599
- const verticalFov = THREE25.MathUtils.degToRad(camera.fov);
22653
+ if (camera instanceof THREE26.PerspectiveCamera) {
22654
+ const verticalFov = THREE26.MathUtils.degToRad(camera.fov);
22600
22655
  const horizontalFov = 2 * Math.atan(Math.tan(verticalFov / 2) * camera.aspect);
22601
22656
  const limitingFov = Math.min(verticalFov, horizontalFov);
22602
22657
  distance5 = radius * padding / Math.sin(limitingFov / 2);
22603
22658
  camera.far = Math.max(camera.far, distance5 + radius * padding * 3);
22604
22659
  camera.updateProjectionMatrix();
22605
- } else if (camera instanceof THREE25.OrthographicCamera) {
22660
+ } else if (camera instanceof THREE26.OrthographicCamera) {
22606
22661
  const halfViewWidth = Math.abs(camera.right - camera.left) / 2;
22607
22662
  const halfViewHeight = Math.abs(camera.top - camera.bottom) / 2;
22608
22663
  camera.zoom = Math.min(
@@ -22639,7 +22694,7 @@ var ReferenceObject = ({
22639
22694
  nextObject.position.set(position.x, position.y, position.z);
22640
22695
  return nextObject;
22641
22696
  }, [type, boardDimensions, boardCenter]);
22642
- useEffect20(() => {
22697
+ useEffect21(() => {
22643
22698
  scene.add(object);
22644
22699
  return () => {
22645
22700
  scene.remove(object);
@@ -22651,7 +22706,7 @@ var ReferenceObject = ({
22651
22706
  var FitCameraToComparison = ({ bounds }) => {
22652
22707
  const { camera } = useThree();
22653
22708
  const { controlsRef } = useCameraController();
22654
- useEffect20(() => {
22709
+ useEffect21(() => {
22655
22710
  fitCameraToBounds(camera, controlsRef.current, bounds);
22656
22711
  }, [bounds, camera, controlsRef]);
22657
22712
  return null;
@@ -22677,6 +22732,7 @@ var CadViewerContainer = forwardRef2(
22677
22732
  clickToInteractEnabled = false,
22678
22733
  boardDimensions,
22679
22734
  boardCenter,
22735
+ cameraSessionScope,
22680
22736
  referenceObject,
22681
22737
  onUserInteraction,
22682
22738
  onCameraControllerReady
@@ -22689,8 +22745,8 @@ var CadViewerContainer = forwardRef2(
22689
22745
  const {
22690
22746
  handleCameraCreated,
22691
22747
  handleControlsChange: handleSessionControlsChange
22692
- } = useCameraSession();
22693
- useEffect21(() => {
22748
+ } = useCameraSession({ cameraSessionScope });
22749
+ useEffect22(() => {
22694
22750
  if (onCameraControllerReady) {
22695
22751
  onCameraControllerReady(controller);
22696
22752
  }
@@ -22722,7 +22778,7 @@ var CadViewerContainer = forwardRef2(
22722
22778
  Canvas,
22723
22779
  {
22724
22780
  ref,
22725
- scene: { up: new THREE26.Vector3(0, 0, 1) },
22781
+ scene: { up: new THREE27.Vector3(0, 0, 1) },
22726
22782
  camera: { up: [0, 0, 1], position: initialCameraPosition },
22727
22783
  onCreated: ({ camera }) => {
22728
22784
  mainCameraRef.current = camera;
@@ -22779,7 +22835,8 @@ var CadViewerContainer = forwardRef2(
22779
22835
  ),
22780
22836
  children
22781
22837
  ]
22782
- }
22838
+ },
22839
+ cameraSessionScope
22783
22840
  ),
22784
22841
  /* @__PURE__ */ jsxs2(
22785
22842
  "div",
@@ -22840,12 +22897,12 @@ var CadViewerContainer = forwardRef2(
22840
22897
  );
22841
22898
 
22842
22899
  // src/hooks/use-stls-from-geom.ts
22843
- import { useState as useState14, useEffect as useEffect22 } from "react";
22900
+ import { useState as useState14, useEffect as useEffect23 } from "react";
22844
22901
  import stlSerializer from "@jscad/stl-serializer";
22845
22902
  var useStlsFromGeom = (geom) => {
22846
22903
  const [stls, setStls] = useState14([]);
22847
22904
  const [loading, setLoading] = useState14(true);
22848
- useEffect22(() => {
22905
+ useEffect23(() => {
22849
22906
  if (!geom) return;
22850
22907
  const generateStls = async () => {
22851
22908
  setLoading(true);
@@ -22874,7 +22931,7 @@ var useStlsFromGeom = (geom) => {
22874
22931
  };
22875
22932
 
22876
22933
  // src/hooks/useBoardGeomBuilder.ts
22877
- import { useState as useState15, useEffect as useEffect23, useRef as useRef8 } from "react";
22934
+ import { useState as useState15, useEffect as useEffect24, useRef as useRef8 } from "react";
22878
22935
 
22879
22936
  // src/soup-to-3d/index.ts
22880
22937
  var import_colors = __toESM(require_colors(), 1);
@@ -22913,7 +22970,7 @@ var createBoardGeomWithOutline = (board, depth = 1.2, options = {}) => {
22913
22970
  };
22914
22971
 
22915
22972
  // src/utils/get-board-edge-color.ts
22916
- import * as THREE28 from "three";
22973
+ import * as THREE29 from "three";
22917
22974
 
22918
22975
  // src/geoms/constants.ts
22919
22976
  var M = 0.01;
@@ -22946,7 +23003,7 @@ var soldermaskColors = {
22946
23003
  };
22947
23004
 
22948
23005
  // src/utils/soldermask-color.ts
22949
- import * as THREE27 from "three";
23006
+ import * as THREE28 from "three";
22950
23007
  var SOLDERMASK_PRESET_HEX = {
22951
23008
  red: "#650202",
22952
23009
  blue: "#003f7d",
@@ -22977,9 +23034,9 @@ var resolveSoldermaskColor = (requestedColor) => {
22977
23034
  }
22978
23035
  const presetName = lowercaseColor;
22979
23036
  const presetColor = SOLDERMASK_PRESET_HEX[presetName];
22980
- if (presetColor) return new THREE27.Color(presetColor);
22981
- const isCssColor = Object.hasOwn(THREE27.Color.NAMES, lowercaseColor) || CSS_HEX_COLOR_PATTERN.test(normalizedColor) || CSS_RGB_INTEGER_PATTERN.test(normalizedColor) || CSS_RGB_PERCENT_PATTERN.test(normalizedColor) || CSS_HSL_PATTERN.test(normalizedColor);
22982
- return isCssColor ? new THREE27.Color(lowercaseColor) : null;
23037
+ if (presetColor) return new THREE28.Color(presetColor);
23038
+ const isCssColor = Object.hasOwn(THREE28.Color.NAMES, lowercaseColor) || CSS_HEX_COLOR_PATTERN.test(normalizedColor) || CSS_RGB_INTEGER_PATTERN.test(normalizedColor) || CSS_RGB_PERCENT_PATTERN.test(normalizedColor) || CSS_HSL_PATTERN.test(normalizedColor);
23039
+ return isCssColor ? new THREE28.Color(lowercaseColor) : null;
22983
23040
  };
22984
23041
  var resolveSoldermaskOpacity = (requestedColor) => {
22985
23042
  const presetName = requestedColor?.trim().toLowerCase();
@@ -23006,7 +23063,7 @@ var soldermaskColorToCss = (color) => {
23006
23063
  };
23007
23064
 
23008
23065
  // src/utils/get-board-edge-color.ts
23009
- var LEGACY_FR4_EDGE_COLOR = new THREE28.Color(1063462);
23066
+ var LEGACY_FR4_EDGE_COLOR = new THREE29.Color(1063462);
23010
23067
  var getBoardEdgeColor = ({
23011
23068
  material,
23012
23069
  solder_mask_color
@@ -23015,7 +23072,7 @@ var getBoardEdgeColor = ({
23015
23072
  if (soldermaskColor) return soldermaskColor;
23016
23073
  if (material === "fr4") return LEGACY_FR4_EDGE_COLOR.clone();
23017
23074
  const materialColor = boardMaterialColors[material] ?? colors.fr4Tan;
23018
- return new THREE28.Color(materialColor[0], materialColor[1], materialColor[2]);
23075
+ return new THREE29.Color(materialColor[0], materialColor[1], materialColor[2]);
23019
23076
  };
23020
23077
 
23021
23078
  // src/soup-to-3d/index.ts
@@ -24363,7 +24420,7 @@ var BoardGeomBuilder = class {
24363
24420
  var useBoardGeomBuilder = (circuitJson) => {
24364
24421
  const [boardGeom, setBoardGeom] = useState15(null);
24365
24422
  const isProcessingRef = useRef8(false);
24366
- useEffect23(() => {
24423
+ useEffect24(() => {
24367
24424
  let isCancelled = false;
24368
24425
  if (!circuitJson) {
24369
24426
  setBoardGeom(null);
@@ -24409,10 +24466,10 @@ var useBoardGeomBuilder = (circuitJson) => {
24409
24466
  };
24410
24467
 
24411
24468
  // src/three-components/Error3d.tsx
24412
- import { useState as useState16, useCallback as useCallback8, useEffect as useEffect25, useMemo as useMemo19 } from "react";
24469
+ import { useState as useState16, useCallback as useCallback8, useEffect as useEffect26, useMemo as useMemo19 } from "react";
24413
24470
 
24414
24471
  // src/react-three/Text.tsx
24415
- import { useEffect as useEffect24, useMemo as useMemo18 } from "react";
24472
+ import { useEffect as useEffect25, useMemo as useMemo18 } from "react";
24416
24473
  import { Text as TroikaText2 } from "troika-three-text";
24417
24474
  var Text = ({
24418
24475
  children,
@@ -24452,7 +24509,7 @@ var Text = ({
24452
24509
  anchorY,
24453
24510
  depthOffset
24454
24511
  ]);
24455
- useEffect24(() => {
24512
+ useEffect25(() => {
24456
24513
  const parentObject = parent || rootObject;
24457
24514
  if (!parentObject || !mesh) return;
24458
24515
  parentObject.add(mesh);
@@ -24465,7 +24522,7 @@ var Text = ({
24465
24522
  };
24466
24523
 
24467
24524
  // src/three-components/Error3d.tsx
24468
- import * as THREE29 from "three";
24525
+ import * as THREE30 from "three";
24469
24526
  import { Fragment as Fragment3, jsx as jsx16, jsxs as jsxs3 } from "react/jsx-runtime";
24470
24527
  var Error3d = ({
24471
24528
  error,
@@ -24499,13 +24556,13 @@ var Error3d = ({
24499
24556
  return [0, 0, 0];
24500
24557
  }, [cad_component]);
24501
24558
  const group = useMemo19(() => {
24502
- const g = new THREE29.Group();
24559
+ const g = new THREE30.Group();
24503
24560
  g.position.fromArray(position);
24504
24561
  return g;
24505
24562
  }, [position]);
24506
24563
  group.userData.cad_component_id = cad_component?.cad_component_id;
24507
24564
  group.userData.pcb_component_id = cad_component?.pcb_component_id;
24508
- useEffect25(() => {
24565
+ useEffect26(() => {
24509
24566
  if (!rootObject) return;
24510
24567
  rootObject.add(group);
24511
24568
  return () => {
@@ -24561,9 +24618,9 @@ var Error3d = ({
24561
24618
  };
24562
24619
  var ErrorBox = ({ parent }) => {
24563
24620
  const mesh = useMemo19(() => {
24564
- const m = new THREE29.Mesh(
24565
- new THREE29.BoxGeometry(0.5, 0.5, 0.5),
24566
- new THREE29.MeshStandardMaterial({
24621
+ const m = new THREE30.Mesh(
24622
+ new THREE30.BoxGeometry(0.5, 0.5, 0.5),
24623
+ new THREE30.MeshStandardMaterial({
24567
24624
  depthTest: false,
24568
24625
  transparent: true,
24569
24626
  color: "red",
@@ -24574,7 +24631,7 @@ var ErrorBox = ({ parent }) => {
24574
24631
  m.rotation.fromArray([Math.PI / 4, Math.PI / 4, 0]);
24575
24632
  return m;
24576
24633
  }, []);
24577
- useEffect25(() => {
24634
+ useEffect26(() => {
24578
24635
  parent.add(mesh);
24579
24636
  return () => {
24580
24637
  parent.remove(mesh);
@@ -24585,7 +24642,7 @@ var ErrorBox = ({ parent }) => {
24585
24642
 
24586
24643
  // src/three-components/JscadBoardTextures.tsx
24587
24644
  import { su as su9 } from "@tscircuit/circuit-json-util";
24588
- import { useEffect as useEffect26, useMemo as useMemo21 } from "react";
24645
+ import { useEffect as useEffect27, useMemo as useMemo21 } from "react";
24589
24646
 
24590
24647
  // src/textures/open-via-holes-at-pads.ts
24591
24648
  import { CircuitToCanvasDrawer } from "circuit-to-canvas";
@@ -24740,12 +24797,12 @@ function clearViaHolesFromSurface({
24740
24797
  }
24741
24798
 
24742
24799
  // src/textures/create-combined-board-textures.ts
24743
- import * as THREE42 from "three";
24800
+ import * as THREE43 from "three";
24744
24801
 
24745
24802
  // src/utils/pad-texture.ts
24746
24803
  import { su as su6 } from "@tscircuit/circuit-json-util";
24747
24804
  import { CircuitToCanvasDrawer as CircuitToCanvasDrawer2 } from "circuit-to-canvas";
24748
- import * as THREE30 from "three";
24805
+ import * as THREE31 from "three";
24749
24806
  function createPadTextureForLayer({
24750
24807
  layer,
24751
24808
  circuitJson,
@@ -24825,10 +24882,10 @@ function createPadTextureForLayer({
24825
24882
  drawSoldermaskTop: false,
24826
24883
  drawSoldermaskBottom: false
24827
24884
  });
24828
- const texture = new THREE30.CanvasTexture(canvas);
24885
+ const texture = new THREE31.CanvasTexture(canvas);
24829
24886
  texture.generateMipmaps = true;
24830
- texture.minFilter = THREE30.LinearMipmapLinearFilter;
24831
- texture.magFilter = THREE30.LinearFilter;
24887
+ texture.minFilter = THREE31.LinearMipmapLinearFilter;
24888
+ texture.magFilter = THREE31.LinearFilter;
24832
24889
  texture.anisotropy = 16;
24833
24890
  texture.needsUpdate = true;
24834
24891
  return texture;
@@ -24836,7 +24893,7 @@ function createPadTextureForLayer({
24836
24893
 
24837
24894
  // src/utils/panel-outline-texture.ts
24838
24895
  import { su as su7 } from "@tscircuit/circuit-json-util";
24839
- import * as THREE31 from "three";
24896
+ import * as THREE32 from "three";
24840
24897
  var resolvePanelIdForTexture = (circuitJson) => {
24841
24898
  const panels = circuitJson.filter(
24842
24899
  (e) => e.type === "pcb_panel"
@@ -24904,17 +24961,17 @@ function createPanelOutlineTextureForLayer({
24904
24961
  );
24905
24962
  }
24906
24963
  });
24907
- const texture = new THREE31.CanvasTexture(canvas);
24964
+ const texture = new THREE32.CanvasTexture(canvas);
24908
24965
  texture.generateMipmaps = true;
24909
- texture.minFilter = THREE31.LinearMipmapLinearFilter;
24910
- texture.magFilter = THREE31.LinearFilter;
24966
+ texture.minFilter = THREE32.LinearMipmapLinearFilter;
24967
+ texture.magFilter = THREE32.LinearFilter;
24911
24968
  texture.anisotropy = 16;
24912
24969
  texture.needsUpdate = true;
24913
24970
  return texture;
24914
24971
  }
24915
24972
 
24916
24973
  // src/utils/trace-texture.ts
24917
- import * as THREE32 from "three";
24974
+ import * as THREE33 from "three";
24918
24975
  import { CircuitToCanvasDrawer as CircuitToCanvasDrawer3 } from "circuit-to-canvas";
24919
24976
  import { getElementRenderLayers, su as su8 } from "@tscircuit/circuit-json-util";
24920
24977
  function createTraceTextureForLayer({
@@ -25000,10 +25057,10 @@ function createTraceTextureForLayer({
25000
25057
  drawSoldermaskTop: false,
25001
25058
  drawSoldermaskBottom: false
25002
25059
  });
25003
- const texture = new THREE32.CanvasTexture(canvas);
25060
+ const texture = new THREE33.CanvasTexture(canvas);
25004
25061
  texture.generateMipmaps = true;
25005
- texture.minFilter = THREE32.LinearMipmapLinearFilter;
25006
- texture.magFilter = THREE32.LinearFilter;
25062
+ texture.minFilter = THREE33.LinearMipmapLinearFilter;
25063
+ texture.magFilter = THREE33.LinearFilter;
25007
25064
  texture.anisotropy = 16;
25008
25065
  texture.needsUpdate = true;
25009
25066
  return texture;
@@ -25011,7 +25068,7 @@ function createTraceTextureForLayer({
25011
25068
 
25012
25069
  // src/textures/create-copper-pour-texture-for-layer.ts
25013
25070
  import { CircuitToCanvasDrawer as CircuitToCanvasDrawer4 } from "circuit-to-canvas";
25014
- import * as THREE33 from "three";
25071
+ import * as THREE34 from "three";
25015
25072
  var toRgb = (colorArr) => {
25016
25073
  const [r = 0, g = 0, b = 0] = colorArr;
25017
25074
  return `rgb(${Math.round(r * 255)}, ${Math.round(g * 255)}, ${Math.round(
@@ -25135,17 +25192,17 @@ function createCopperPourTextureForLayer({
25135
25192
  if (!onlyCoveredBySoldermask) {
25136
25193
  setColorAndDraw(uncoveredPours, uncoveredColor);
25137
25194
  }
25138
- const texture = new THREE33.CanvasTexture(canvas);
25195
+ const texture = new THREE34.CanvasTexture(canvas);
25139
25196
  texture.generateMipmaps = true;
25140
- texture.minFilter = THREE33.LinearMipmapLinearFilter;
25141
- texture.magFilter = THREE33.LinearFilter;
25197
+ texture.minFilter = THREE34.LinearMipmapLinearFilter;
25198
+ texture.magFilter = THREE34.LinearFilter;
25142
25199
  texture.anisotropy = 16;
25143
25200
  texture.needsUpdate = true;
25144
25201
  return texture;
25145
25202
  }
25146
25203
 
25147
25204
  // src/textures/create-copper-text-texture-for-layer.ts
25148
- import * as THREE34 from "three";
25205
+ import * as THREE35 from "three";
25149
25206
 
25150
25207
  // src/textures/copper-text/copper-text-drawing.ts
25151
25208
  import { CircuitToCanvasDrawer as CircuitToCanvasDrawer5 } from "circuit-to-canvas";
@@ -25260,17 +25317,17 @@ function createCopperTextTextureForLayer({
25260
25317
  elements,
25261
25318
  copperColor
25262
25319
  });
25263
- const texture = new THREE34.CanvasTexture(canvas);
25320
+ const texture = new THREE35.CanvasTexture(canvas);
25264
25321
  texture.generateMipmaps = true;
25265
- texture.minFilter = THREE34.LinearMipmapLinearFilter;
25266
- texture.magFilter = THREE34.LinearFilter;
25322
+ texture.minFilter = THREE35.LinearMipmapLinearFilter;
25323
+ texture.magFilter = THREE35.LinearFilter;
25267
25324
  texture.anisotropy = 16;
25268
25325
  texture.needsUpdate = true;
25269
25326
  return texture;
25270
25327
  }
25271
25328
 
25272
25329
  // src/textures/create-fabrication-note-texture-for-layer.ts
25273
- import * as THREE35 from "three";
25330
+ import * as THREE36 from "three";
25274
25331
 
25275
25332
  // src/textures/fabrication-note/fabrication-note-drawing.ts
25276
25333
  import { CircuitToCanvasDrawer as CircuitToCanvasDrawer6 } from "circuit-to-canvas";
@@ -25500,17 +25557,17 @@ function createFabricationNoteTextureForLayer({
25500
25557
  bounds,
25501
25558
  elements
25502
25559
  });
25503
- const texture = new THREE35.CanvasTexture(canvas);
25560
+ const texture = new THREE36.CanvasTexture(canvas);
25504
25561
  texture.generateMipmaps = true;
25505
- texture.minFilter = THREE35.LinearMipmapLinearFilter;
25506
- texture.magFilter = THREE35.LinearFilter;
25562
+ texture.minFilter = THREE36.LinearMipmapLinearFilter;
25563
+ texture.magFilter = THREE36.LinearFilter;
25507
25564
  texture.anisotropy = 16;
25508
25565
  texture.needsUpdate = true;
25509
25566
  return texture;
25510
25567
  }
25511
25568
 
25512
25569
  // src/textures/create-keepout-texture-for-layer.ts
25513
- import * as THREE36 from "three";
25570
+ import * as THREE37 from "three";
25514
25571
 
25515
25572
  // src/textures/keepout/keepout-drawing.ts
25516
25573
  import { CircuitToCanvasDrawer as CircuitToCanvasDrawer7 } from "circuit-to-canvas";
@@ -25585,17 +25642,17 @@ function createKeepoutTextureForLayer({
25585
25642
  elements,
25586
25643
  keepoutColor
25587
25644
  });
25588
- const texture = new THREE36.CanvasTexture(canvas);
25645
+ const texture = new THREE37.CanvasTexture(canvas);
25589
25646
  texture.generateMipmaps = true;
25590
- texture.minFilter = THREE36.LinearMipmapLinearFilter;
25591
- texture.magFilter = THREE36.LinearFilter;
25647
+ texture.minFilter = THREE37.LinearMipmapLinearFilter;
25648
+ texture.magFilter = THREE37.LinearFilter;
25592
25649
  texture.anisotropy = 16;
25593
25650
  texture.needsUpdate = true;
25594
25651
  return texture;
25595
25652
  }
25596
25653
 
25597
25654
  // src/textures/create-pcb-note-texture-for-layer.ts
25598
- import * as THREE37 from "three";
25655
+ import * as THREE38 from "three";
25599
25656
 
25600
25657
  // src/textures/pcb-note/pcb-note-drawing.ts
25601
25658
  import { CircuitToCanvasDrawer as CircuitToCanvasDrawer8 } from "circuit-to-canvas";
@@ -25749,17 +25806,17 @@ function createPcbNoteTextureForLayer({
25749
25806
  bounds,
25750
25807
  elements
25751
25808
  });
25752
- const texture = new THREE37.CanvasTexture(canvas);
25809
+ const texture = new THREE38.CanvasTexture(canvas);
25753
25810
  texture.generateMipmaps = true;
25754
- texture.minFilter = THREE37.LinearMipmapLinearFilter;
25755
- texture.magFilter = THREE37.LinearFilter;
25811
+ texture.minFilter = THREE38.LinearMipmapLinearFilter;
25812
+ texture.magFilter = THREE38.LinearFilter;
25756
25813
  texture.anisotropy = 16;
25757
25814
  texture.needsUpdate = true;
25758
25815
  return texture;
25759
25816
  }
25760
25817
 
25761
25818
  // src/textures/create-silkscreen-texture-for-layer.ts
25762
- import * as THREE38 from "three";
25819
+ import * as THREE39 from "three";
25763
25820
 
25764
25821
  // src/textures/silkscreen/silkscreen-drawing.ts
25765
25822
  import { CircuitToCanvasDrawer as CircuitToCanvasDrawer9 } from "circuit-to-canvas";
@@ -25910,21 +25967,21 @@ function createSilkscreenTextureForLayer({
25910
25967
  silkscreenColor,
25911
25968
  soldermaskVisible
25912
25969
  });
25913
- const texture = new THREE38.CanvasTexture(canvas);
25970
+ const texture = new THREE39.CanvasTexture(canvas);
25914
25971
  texture.generateMipmaps = true;
25915
- texture.minFilter = THREE38.LinearMipmapLinearFilter;
25916
- texture.magFilter = THREE38.LinearFilter;
25972
+ texture.minFilter = THREE39.LinearMipmapLinearFilter;
25973
+ texture.magFilter = THREE39.LinearFilter;
25917
25974
  texture.anisotropy = 16;
25918
25975
  texture.needsUpdate = true;
25919
25976
  return texture;
25920
25977
  }
25921
25978
 
25922
25979
  // src/textures/create-soldermask-texture-for-layer.ts
25923
- import * as THREE40 from "three";
25980
+ import * as THREE41 from "three";
25924
25981
 
25925
25982
  // src/textures/soldermask/soldermask-drawing.ts
25926
25983
  import { CircuitToCanvasDrawer as CircuitToCanvasDrawer10 } from "circuit-to-canvas";
25927
- import * as THREE39 from "three";
25984
+ import * as THREE40 from "three";
25928
25985
  var toRgb2 = (colorArr) => {
25929
25986
  const [r = 0, g = 0, b = 0] = colorArr;
25930
25987
  return `rgb(${Math.round(r * 255)}, ${Math.round(g * 255)}, ${Math.round(
@@ -25947,11 +26004,11 @@ var getSoldermaskPalette = (boardData) => {
25947
26004
  transparent: "rgba(0,0,0,0)"
25948
26005
  };
25949
26006
  }
25950
- const copperColor = new THREE39.Color().setRGB(
26007
+ const copperColor = new THREE40.Color().setRGB(
25951
26008
  colors.copper[0],
25952
26009
  colors.copper[1],
25953
26010
  colors.copper[2],
25954
- THREE39.SRGBColorSpace
26011
+ THREE40.SRGBColorSpace
25955
26012
  );
25956
26013
  return {
25957
26014
  soldermask: soldermaskColorToCss(requestedSoldermaskColor),
@@ -26086,17 +26143,17 @@ function createSoldermaskTextureForLayer({
26086
26143
  elements,
26087
26144
  boardData
26088
26145
  });
26089
- const texture = new THREE40.CanvasTexture(canvas);
26146
+ const texture = new THREE41.CanvasTexture(canvas);
26090
26147
  texture.generateMipmaps = true;
26091
- texture.minFilter = THREE40.LinearMipmapLinearFilter;
26092
- texture.magFilter = THREE40.LinearFilter;
26148
+ texture.minFilter = THREE41.LinearMipmapLinearFilter;
26149
+ texture.magFilter = THREE41.LinearFilter;
26093
26150
  texture.anisotropy = 16;
26094
26151
  texture.needsUpdate = true;
26095
26152
  return texture;
26096
26153
  }
26097
26154
 
26098
26155
  // src/textures/create-through-hole-texture-for-layer.ts
26099
- import * as THREE41 from "three";
26156
+ import * as THREE42 from "three";
26100
26157
 
26101
26158
  // src/textures/through-hole/through-hole-drawing.ts
26102
26159
  import { CircuitToCanvasDrawer as CircuitToCanvasDrawer11 } from "circuit-to-canvas";
@@ -26191,10 +26248,10 @@ function createThroughHoleTextureForLayer({
26191
26248
  elements,
26192
26249
  copperColor
26193
26250
  });
26194
- const texture = new THREE41.CanvasTexture(canvas);
26251
+ const texture = new THREE42.CanvasTexture(canvas);
26195
26252
  texture.generateMipmaps = true;
26196
- texture.minFilter = THREE41.LinearMipmapLinearFilter;
26197
- texture.magFilter = THREE41.LinearFilter;
26253
+ texture.minFilter = THREE42.LinearMipmapLinearFilter;
26254
+ texture.magFilter = THREE42.LinearFilter;
26198
26255
  texture.anisotropy = 16;
26199
26256
  texture.needsUpdate = true;
26200
26257
  return texture;
@@ -26291,10 +26348,10 @@ var createCombinedTexture = ({
26291
26348
  applySoldermaskSurfaceFilter(ctx, canvasWidth, canvasHeight, {
26292
26349
  includeReflection: layer === "top"
26293
26350
  });
26294
- const combinedTexture = new THREE42.CanvasTexture(canvas);
26351
+ const combinedTexture = new THREE43.CanvasTexture(canvas);
26295
26352
  combinedTexture.generateMipmaps = false;
26296
- combinedTexture.minFilter = THREE42.LinearFilter;
26297
- combinedTexture.magFilter = THREE42.LinearFilter;
26353
+ combinedTexture.minFilter = THREE43.LinearFilter;
26354
+ combinedTexture.magFilter = THREE43.LinearFilter;
26298
26355
  combinedTexture.premultiplyAlpha = true;
26299
26356
  combinedTexture.anisotropy = 16;
26300
26357
  combinedTexture.needsUpdate = true;
@@ -26330,11 +26387,11 @@ var createMaskedCopperMask = ({
26330
26387
  height
26331
26388
  );
26332
26389
  ctx.globalCompositeOperation = "source-over";
26333
- const maskTexture = new THREE42.CanvasTexture(canvas);
26334
- maskTexture.colorSpace = THREE42.NoColorSpace;
26390
+ const maskTexture = new THREE43.CanvasTexture(canvas);
26391
+ maskTexture.colorSpace = THREE43.NoColorSpace;
26335
26392
  maskTexture.generateMipmaps = false;
26336
- maskTexture.minFilter = THREE42.LinearFilter;
26337
- maskTexture.magFilter = THREE42.LinearFilter;
26393
+ maskTexture.minFilter = THREE43.LinearFilter;
26394
+ maskTexture.magFilter = THREE43.LinearFilter;
26338
26395
  maskTexture.premultiplyAlpha = false;
26339
26396
  maskTexture.needsUpdate = true;
26340
26397
  return maskTexture;
@@ -26480,7 +26537,7 @@ function createCombinedBoardTextures({
26480
26537
  }
26481
26538
 
26482
26539
  // src/textures/create-three-texture-meshes.ts
26483
- import * as THREE44 from "three";
26540
+ import * as THREE45 from "three";
26484
26541
 
26485
26542
  // src/board-surface-textures.ts
26486
26543
  var REALISTIC_BOARD_SURFACE_MATERIAL = {
@@ -26503,7 +26560,7 @@ var PAD_COPPER_TEXTURE_MATERIAL = {
26503
26560
  };
26504
26561
 
26505
26562
  // src/utils/create-board-relief-textures.ts
26506
- import * as THREE43 from "three";
26563
+ import * as THREE44 from "three";
26507
26564
  var PLAIN_SOLDERMASK_HEIGHT = 0.22;
26508
26565
  var MASKED_COPPER_HEIGHT = 0.7;
26509
26566
  var EXPOSED_COPPER_HEIGHT = 0.86;
@@ -26598,13 +26655,13 @@ var getBoardSurfaceProfile = (r, g, b, hasMaskedCopper) => {
26598
26655
  return PLAIN_SOLDERMASK_PROFILE;
26599
26656
  };
26600
26657
  var createDataTexture = (canvas) => {
26601
- const texture = new THREE43.CanvasTexture(canvas);
26602
- texture.colorSpace = THREE43.NoColorSpace;
26658
+ const texture = new THREE44.CanvasTexture(canvas);
26659
+ texture.colorSpace = THREE44.NoColorSpace;
26603
26660
  texture.generateMipmaps = false;
26604
- texture.minFilter = THREE43.LinearFilter;
26605
- texture.magFilter = THREE43.LinearFilter;
26606
- texture.wrapS = THREE43.ClampToEdgeWrapping;
26607
- texture.wrapT = THREE43.ClampToEdgeWrapping;
26661
+ texture.minFilter = THREE44.LinearFilter;
26662
+ texture.magFilter = THREE44.LinearFilter;
26663
+ texture.wrapS = THREE44.ClampToEdgeWrapping;
26664
+ texture.wrapT = THREE44.ClampToEdgeWrapping;
26608
26665
  texture.needsUpdate = true;
26609
26666
  return texture;
26610
26667
  };
@@ -26728,16 +26785,16 @@ function createTexturePlane(config, boardData) {
26728
26785
  } = config;
26729
26786
  if (!texture) return null;
26730
26787
  const boardOutlineBounds = calculateOutlineBounds(boardData);
26731
- const planeGeom = new THREE44.PlaneGeometry(
26788
+ const planeGeom = new THREE45.PlaneGeometry(
26732
26789
  boardOutlineBounds.width,
26733
26790
  boardOutlineBounds.height
26734
26791
  );
26735
- texture.colorSpace = THREE44.SRGBColorSpace;
26792
+ texture.colorSpace = THREE45.SRGBColorSpace;
26736
26793
  const sharedMaterialOptions = {
26737
26794
  map: texture,
26738
26795
  transparent: true,
26739
26796
  alphaTest: 0.08,
26740
- side: THREE44.FrontSide,
26797
+ side: THREE45.FrontSide,
26741
26798
  depthWrite: true,
26742
26799
  polygonOffset: usePolygonOffset,
26743
26800
  polygonOffsetFactor: usePolygonOffset ? -4 : 0,
@@ -26746,12 +26803,12 @@ function createTexturePlane(config, boardData) {
26746
26803
  opacity: isFaux ? FAUX_BOARD_OPACITY : 1
26747
26804
  };
26748
26805
  const reliefTextures = createBoardReliefTextures(texture, maskedCopperMask);
26749
- const material = new THREE44.MeshPhysicalMaterial({
26806
+ const material = new THREE45.MeshPhysicalMaterial({
26750
26807
  ...sharedMaterialOptions,
26751
26808
  bumpMap: reliefTextures?.bumpMap ?? null,
26752
26809
  bumpScale: REALISTIC_BOARD_SURFACE_MATERIAL.bumpScale,
26753
26810
  normalMap: reliefTextures?.normalMap ?? null,
26754
- normalScale: new THREE44.Vector2(
26811
+ normalScale: new THREE45.Vector2(
26755
26812
  REALISTIC_BOARD_SURFACE_MATERIAL.normalScale,
26756
26813
  REALISTIC_BOARD_SURFACE_MATERIAL.normalScale
26757
26814
  ),
@@ -26765,7 +26822,7 @@ function createTexturePlane(config, boardData) {
26765
26822
  clearcoatRoughness: REALISTIC_BOARD_SURFACE_MATERIAL.clearcoatRoughness,
26766
26823
  envMapIntensity: 0.18
26767
26824
  });
26768
- const mesh = new THREE44.Mesh(planeGeom, material);
26825
+ const mesh = new THREE45.Mesh(planeGeom, material);
26769
26826
  mesh.position.set(
26770
26827
  boardOutlineBounds.centerX,
26771
26828
  boardOutlineBounds.centerY,
@@ -26813,7 +26870,7 @@ function createTextureMeshes(textures, boardData, pcbThickness, isFaux = false)
26813
26870
  }
26814
26871
 
26815
26872
  // src/three-components/JscadBoardTextures.tsx
26816
- import * as THREE45 from "three";
26873
+ import * as THREE46 from "three";
26817
26874
 
26818
26875
  // src/hooks/useBoardTextureVisibility.ts
26819
26876
  import { useMemo as useMemo20 } from "react";
@@ -26931,7 +26988,7 @@ function JscadBoardTextures({
26931
26988
  visibility: textureVisibility
26932
26989
  });
26933
26990
  }, [circuitJson, boardData, traceTextureResolution, textureVisibility]);
26934
- useEffect26(() => {
26991
+ useEffect27(() => {
26935
26992
  if (!rootObject || !boardData || !textures) return;
26936
26993
  const meshes = [];
26937
26994
  const disposeTextureMaterial = (material) => {
@@ -26951,7 +27008,7 @@ function JscadBoardTextures({
26951
27008
  const typedMaterial = material;
26952
27009
  for (const prop of textureProps) {
26953
27010
  const texture = typedMaterial[prop];
26954
- if (texture && texture instanceof THREE45.Texture) {
27011
+ if (texture && texture instanceof THREE46.Texture) {
26955
27012
  texture.dispose();
26956
27013
  typedMaterial[prop] = null;
26957
27014
  }
@@ -26970,16 +27027,16 @@ function JscadBoardTextures({
26970
27027
  }) => {
26971
27028
  if (!texture) return null;
26972
27029
  const boardOutlineBounds = calculateOutlineBounds(boardData);
26973
- const planeGeom = new THREE45.PlaneGeometry(
27030
+ const planeGeom = new THREE46.PlaneGeometry(
26974
27031
  boardOutlineBounds.width,
26975
27032
  boardOutlineBounds.height
26976
27033
  );
26977
- texture.colorSpace = THREE45.SRGBColorSpace;
27034
+ texture.colorSpace = THREE46.SRGBColorSpace;
26978
27035
  const sharedMaterialOptions = {
26979
27036
  map: texture,
26980
27037
  transparent: true,
26981
27038
  alphaTest: 0.08,
26982
- side: THREE45.FrontSide,
27039
+ side: THREE46.FrontSide,
26983
27040
  depthWrite,
26984
27041
  polygonOffset: usePolygonOffset,
26985
27042
  polygonOffsetFactor: usePolygonOffset ? -4 : 0,
@@ -26990,12 +27047,12 @@ function JscadBoardTextures({
26990
27047
  texture,
26991
27048
  maskedCopperMask
26992
27049
  );
26993
- const material = new THREE45.MeshPhysicalMaterial({
27050
+ const material = new THREE46.MeshPhysicalMaterial({
26994
27051
  ...sharedMaterialOptions,
26995
27052
  bumpMap: reliefTextures?.bumpMap ?? null,
26996
27053
  bumpScale: REALISTIC_BOARD_SURFACE_MATERIAL.bumpScale,
26997
27054
  normalMap: reliefTextures?.normalMap ?? null,
26998
- normalScale: new THREE45.Vector2(
27055
+ normalScale: new THREE46.Vector2(
26999
27056
  REALISTIC_BOARD_SURFACE_MATERIAL.normalScale,
27000
27057
  REALISTIC_BOARD_SURFACE_MATERIAL.normalScale
27001
27058
  ),
@@ -27007,7 +27064,7 @@ function JscadBoardTextures({
27007
27064
  clearcoatRoughness: REALISTIC_BOARD_SURFACE_MATERIAL.clearcoatRoughness,
27008
27065
  envMapIntensity: 0.18
27009
27066
  });
27010
- const mesh = new THREE45.Mesh(planeGeom, material);
27067
+ const mesh = new THREE46.Mesh(planeGeom, material);
27011
27068
  mesh.position.set(
27012
27069
  boardOutlineBounds.centerX,
27013
27070
  boardOutlineBounds.centerY,
@@ -27057,7 +27114,7 @@ function JscadBoardTextures({
27057
27114
  for (const material of mesh.material) {
27058
27115
  disposeTextureMaterial(material);
27059
27116
  }
27060
- } else if (mesh.material instanceof THREE45.Material) {
27117
+ } else if (mesh.material instanceof THREE46.Material) {
27061
27118
  disposeTextureMaterial(mesh.material);
27062
27119
  }
27063
27120
  }
@@ -27069,8 +27126,8 @@ function JscadBoardTextures({
27069
27126
  }
27070
27127
 
27071
27128
  // src/three-components/STLModel.tsx
27072
- import { useState as useState17, useEffect as useEffect27, useMemo as useMemo22 } from "react";
27073
- import * as THREE46 from "three";
27129
+ import { useState as useState17, useEffect as useEffect28, useMemo as useMemo22 } from "react";
27130
+ import * as THREE47 from "three";
27074
27131
  import { STLLoader } from "three-stdlib";
27075
27132
  function STLModel({
27076
27133
  stlUrl,
@@ -27082,7 +27139,7 @@ function STLModel({
27082
27139
  }) {
27083
27140
  const { rootObject } = useThree();
27084
27141
  const [geom, setGeom] = useState17(null);
27085
- useEffect27(() => {
27142
+ useEffect28(() => {
27086
27143
  const loader = new STLLoader();
27087
27144
  if (stlData) {
27088
27145
  try {
@@ -27103,15 +27160,15 @@ function STLModel({
27103
27160
  const mesh = useMemo22(() => {
27104
27161
  if (!geom) return null;
27105
27162
  const isBoardLayer = layerType === "board";
27106
- const material = new THREE46.MeshStandardMaterial({
27107
- color: Array.isArray(color) ? new THREE46.Color(color[0], color[1], color[2]) : color,
27163
+ const material = new THREE47.MeshStandardMaterial({
27164
+ color: Array.isArray(color) ? new THREE47.Color(color[0], color[1], color[2]) : color,
27108
27165
  transparent: opacity !== 1,
27109
27166
  opacity,
27110
27167
  polygonOffset: isBoardLayer,
27111
27168
  polygonOffsetFactor: isBoardLayer ? 6 : 0,
27112
27169
  polygonOffsetUnits: isBoardLayer ? 6 : 0
27113
27170
  });
27114
- const createdMesh = new THREE46.Mesh(geom, material);
27171
+ const createdMesh = new THREE47.Mesh(geom, material);
27115
27172
  createdMesh.renderOrder = isBoardLayer ? -1 : 1;
27116
27173
  configureObjectShadows(createdMesh, {
27117
27174
  castShadow: !isBoardLayer && opacity === 1,
@@ -27119,7 +27176,7 @@ function STLModel({
27119
27176
  });
27120
27177
  return createdMesh;
27121
27178
  }, [geom, color, opacity, layerType]);
27122
- useEffect27(() => {
27179
+ useEffect28(() => {
27123
27180
  if (!rootObject || !mesh) return;
27124
27181
  rootObject.add(mesh);
27125
27182
  return () => {
@@ -27173,8 +27230,8 @@ function VisibleSTLModel({
27173
27230
  // src/three-components/CadCable.tsx
27174
27231
  import { parseCableString } from "@tscircuit/cableprinter";
27175
27232
  import { createCableMeshes } from "jscad-electronics/cables";
27176
- import { useEffect as useEffect28, useMemo as useMemo23 } from "react";
27177
- import * as THREE47 from "three";
27233
+ import { useEffect as useEffect29, useMemo as useMemo23 } from "react";
27234
+ import * as THREE48 from "three";
27178
27235
  var isCadCableElement = (element) => {
27179
27236
  if (!element || typeof element !== "object") return false;
27180
27237
  const candidate = element;
@@ -27191,14 +27248,14 @@ var getConnectorPin1Side = ({
27191
27248
  const endpoint = end === "start" ? path[0] : path[path.length - 1];
27192
27249
  const adjacent = end === "start" ? path[1] : path[path.length - 2];
27193
27250
  if (!endpoint || !adjacent) return void 0;
27194
- const cableAxis = new THREE47.Vector3(
27251
+ const cableAxis = new THREE48.Vector3(
27195
27252
  adjacent.x - endpoint.x,
27196
27253
  adjacent.y - endpoint.y,
27197
27254
  adjacent.z - endpoint.z
27198
27255
  );
27199
27256
  if (cableAxis.lengthSq() < 1e-12) return void 0;
27200
27257
  cableAxis.normalize();
27201
- const pin1Side = new THREE47.Vector3(
27258
+ const pin1Side = new THREE48.Vector3(
27202
27259
  pin1Position.x - endpoint.x,
27203
27260
  pin1Position.y - endpoint.y,
27204
27261
  pin1Position.z - endpoint.z
@@ -27224,28 +27281,28 @@ var createCadCableObject = (cable) => {
27224
27281
  end: "end"
27225
27282
  })
27226
27283
  });
27227
- const group = new THREE47.Group();
27284
+ const group = new THREE48.Group();
27228
27285
  group.name = `cad-cable-${cable.cad_cable_id}`;
27229
27286
  group.userData = { cadCableId: cable.cad_cable_id, name: cable.name };
27230
27287
  for (const cableMesh of cableMeshes) {
27231
- let geometry = new THREE47.BufferGeometry();
27288
+ let geometry = new THREE48.BufferGeometry();
27232
27289
  geometry.setAttribute(
27233
27290
  "position",
27234
- new THREE47.Float32BufferAttribute(cableMesh.positions, 3)
27291
+ new THREE48.Float32BufferAttribute(cableMesh.positions, 3)
27235
27292
  );
27236
27293
  geometry.setIndex(cableMesh.indices);
27237
27294
  if (!cableMesh.smooth) geometry = geometry.toNonIndexed();
27238
27295
  geometry.computeVertexNormals();
27239
27296
  const [red, green, blue, alpha] = cableMesh.color;
27240
- const material = new THREE47.MeshStandardMaterial({
27241
- color: new THREE47.Color(red, green, blue),
27297
+ const material = new THREE48.MeshStandardMaterial({
27298
+ color: new THREE48.Color(red, green, blue),
27242
27299
  metalness: cableMesh.material?.metalness ?? 0,
27243
27300
  roughness: cableMesh.material?.roughness ?? 0.7,
27244
27301
  opacity: alpha,
27245
27302
  transparent: alpha < 1,
27246
- side: THREE47.DoubleSide
27303
+ side: THREE48.DoubleSide
27247
27304
  });
27248
- const mesh = new THREE47.Mesh(geometry, material);
27305
+ const mesh = new THREE48.Mesh(geometry, material);
27249
27306
  mesh.name = `${group.name}:${cableMesh.name}`;
27250
27307
  configureObjectShadows(mesh, { castShadow: true, receiveShadow: true });
27251
27308
  group.add(mesh);
@@ -27254,7 +27311,7 @@ var createCadCableObject = (cable) => {
27254
27311
  };
27255
27312
  var disposeCadCableObject = (group) => {
27256
27313
  group.traverse((object) => {
27257
- if (!(object instanceof THREE47.Mesh)) return;
27314
+ if (!(object instanceof THREE48.Mesh)) return;
27258
27315
  object.geometry.dispose();
27259
27316
  const materials = Array.isArray(object.material) ? object.material : [object.material];
27260
27317
  for (const material of materials) material.dispose();
@@ -27270,7 +27327,7 @@ var CadCable = ({ cable }) => {
27270
27327
  return null;
27271
27328
  }
27272
27329
  }, [cable]);
27273
- useEffect28(() => {
27330
+ useEffect29(() => {
27274
27331
  if (!cableObject) return;
27275
27332
  rootObject.add(cableObject);
27276
27333
  return () => {
@@ -27281,6 +27338,22 @@ var CadCable = ({ cable }) => {
27281
27338
  return null;
27282
27339
  };
27283
27340
 
27341
+ // src/utils/get-initial-camera-position.ts
27342
+ function getInitialCameraPosition({
27343
+ boardDimensions,
27344
+ boardCenter
27345
+ }) {
27346
+ if (!boardDimensions || !boardCenter) return [5, -5, 5];
27347
+ const safeWidth = Math.max(boardDimensions.width ?? 0, 1);
27348
+ const safeHeight = Math.max(boardDimensions.height ?? 0, 1);
27349
+ const largestDimension = Math.max(safeWidth, safeHeight, 5);
27350
+ return [
27351
+ boardCenter.x + largestDimension * 0.4,
27352
+ boardCenter.y - largestDimension * 0.7,
27353
+ largestDimension * 0.9
27354
+ ];
27355
+ }
27356
+
27284
27357
  // src/utils/preprocess-circuit-json.ts
27285
27358
  import { su as su11 } from "@tscircuit/circuit-json-util";
27286
27359
 
@@ -27390,32 +27463,6 @@ var CadViewerJscad = forwardRef3(
27390
27463
  );
27391
27464
  }, [circuitJson, childrenSoup]);
27392
27465
  const boardGeom = useBoardGeomBuilder(internalCircuitJson);
27393
- const initialCameraPosition = useMemo24(() => {
27394
- if (!internalCircuitJson) return [5, -5, 5];
27395
- try {
27396
- const board = su12(internalCircuitJson).pcb_board.list()[0];
27397
- if (!board) return [5, -5, 5];
27398
- const { width, height } = board;
27399
- if (!width && !height) {
27400
- return [5, -5, 5];
27401
- }
27402
- const minCameraDistance = 5;
27403
- const adjustedBoardWidth = Math.max(width, minCameraDistance);
27404
- const adjustedBoardHeight = Math.max(height, minCameraDistance);
27405
- const largestDim = Math.max(adjustedBoardWidth, adjustedBoardHeight);
27406
- return [
27407
- largestDim * 0.4,
27408
- // Move right
27409
- -largestDim * 0.7,
27410
- // Move back (negative Y)
27411
- largestDim * 0.9
27412
- // Keep height but slightly lower than top-down
27413
- ];
27414
- } catch (e) {
27415
- console.error(e);
27416
- return [5, -5, 5];
27417
- }
27418
- }, [internalCircuitJson]);
27419
27466
  const isFauxBoard = useMemo24(() => {
27420
27467
  if (!internalCircuitJson) return false;
27421
27468
  try {
@@ -27449,6 +27496,19 @@ var CadViewerJscad = forwardRef3(
27449
27496
  return void 0;
27450
27497
  }
27451
27498
  }, [internalCircuitJson]);
27499
+ const cameraSessionScope = useMemo24(() => {
27500
+ if (!internalCircuitJson) return void 0;
27501
+ const board = su12(internalCircuitJson).pcb_board.list()[0];
27502
+ if (!board) return void 0;
27503
+ return JSON.stringify({
27504
+ pcbBoardId: board.pcb_board_id,
27505
+ center: boardCenter,
27506
+ dimensions: boardDimensions
27507
+ });
27508
+ }, [internalCircuitJson, boardCenter, boardDimensions]);
27509
+ const initialCameraPosition = useMemo24(() => {
27510
+ return getInitialCameraPosition({ boardDimensions, boardCenter });
27511
+ }, [boardDimensions, boardCenter]);
27452
27512
  const pcbThickness = usePcbThickness(internalCircuitJson);
27453
27513
  const { stls: boardStls, loading } = useStlsFromGeom(boardGeom);
27454
27514
  const cad_components = su12(internalCircuitJson).cad_component.list().filter((cad) => !hiddenCadComponentIds?.has(cad.cad_component_id));
@@ -27462,6 +27522,7 @@ var CadViewerJscad = forwardRef3(
27462
27522
  clickToInteractEnabled,
27463
27523
  boardDimensions,
27464
27524
  boardCenter,
27525
+ cameraSessionScope,
27465
27526
  referenceObject,
27466
27527
  onUserInteraction,
27467
27528
  onCameraControllerReady,
@@ -27507,6 +27568,9 @@ var CadViewerJscad = forwardRef3(
27507
27568
  }
27508
27569
  );
27509
27570
 
27571
+ // src/CadViewerManifold.tsx
27572
+ import { su as su17 } from "@tscircuit/circuit-json-util";
27573
+
27510
27574
  // node_modules/earcut/src/earcut.js
27511
27575
  var steiners = /* @__PURE__ */ new Set();
27512
27576
  var filteredOut = false;
@@ -28445,207 +28509,61 @@ function extrudePolygon({
28445
28509
  pcbFace: "side"
28446
28510
  });
28447
28511
  }
28448
- return { triangles, boundingBox: boundsOfTriangles(triangles) };
28449
- }
28450
- function createStiffenerMesh({
28451
- stiffener,
28452
- boardThickness,
28453
- fold
28454
- }) {
28455
- const adhesive = stiffener.adhesive_thickness ?? 0;
28456
- if (!Number.isFinite(adhesive) || adhesive < 0 || !Number.isFinite(stiffener.thickness) || stiffener.thickness <= 0 || !["top", "bottom"].includes(stiffener.layer))
28457
- throw new Error(`Invalid PCB stiffener ${stiffener.pcb_stiffener_id}`);
28458
- const outline = stiffener.shape === "polygon" ? stiffener.outline : (() => {
28459
- if (!(stiffener.width > 0 && stiffener.height > 0))
28460
- throw new Error("Invalid stiffener dimensions");
28461
- const a = (stiffener.rotation ?? 0) * Math.PI / 180;
28462
- return [
28463
- [-1, -1],
28464
- [1, -1],
28465
- [1, 1],
28466
- [-1, 1]
28467
- ].map(([x, y]) => ({
28468
- x: stiffener.center.x + x * stiffener.width / 2 * Math.cos(a) - y * stiffener.height / 2 * Math.sin(a),
28469
- y: stiffener.center.y + x * stiffener.width / 2 * Math.sin(a) + y * stiffener.height / 2 * Math.cos(a)
28470
- }));
28471
- })();
28472
- const near = boardThickness / 2 + adhesive, far = near + stiffener.thickness;
28473
- const mesh = extrudePolygon({
28474
- outline,
28475
- bottom: stiffener.layer === "top" ? near : -far,
28476
- top: stiffener.layer === "top" ? far : -near
28477
- });
28478
- if (!fold) return mesh;
28479
- fold.assertRigid(
28480
- mesh.triangles.flatMap((t) => t.vertices),
28481
- stiffener.pcb_stiffener_id
28482
- );
28483
- const anchor = {
28484
- x: outline.reduce((s, p) => s + p.x, 0) / outline.length,
28485
- y: outline.reduce((s, p) => s + p.y, 0) / outline.length,
28486
- z: 0
28487
- };
28488
- const triangles = mesh.triangles.map((t) => ({
28489
- ...t,
28490
- vertices: t.vertices.map((p) => fold.point(p, anchor)),
28491
- normal: fold.direction(t.normal, anchor)
28492
- }));
28493
- return { ...mesh, triangles, boundingBox: boundsOfTriangles(triangles) };
28494
- }
28495
-
28496
- // src/utils/flex-meshes.ts
28497
- import * as THREE48 from "three";
28498
- function meshToSurface(mesh, center) {
28499
- mesh.updateMatrix();
28500
- const geometry = mesh.geometry.index ? mesh.geometry.toNonIndexed() : mesh.geometry;
28501
- const position = geometry.getAttribute("position"), uv = geometry.getAttribute("uv");
28502
- const triangles = [];
28503
- for (let i = 0; i < position.count; i += 3) {
28504
- const vertices = [0, 1, 2].map((j) => {
28505
- const v = new THREE48.Vector3().fromBufferAttribute(position, i + j).applyMatrix4(mesh.matrix);
28506
- return { x: v.x - center.x, y: v.y - center.y, z: v.z };
28507
- });
28508
- const [a, b, c] = vertices;
28509
- const n = new THREE48.Vector3(b.x - a.x, b.y - a.y, b.z - a.z).cross(new THREE48.Vector3(c.x - a.x, c.y - a.y, c.z - a.z)).normalize();
28510
- triangles.push({
28511
- vertices,
28512
- normal: { x: n.x, y: n.y, z: n.z },
28513
- ...uv ? {
28514
- uvs: [0, 1, 2].map((j) => ({
28515
- u: uv.getX(i + j),
28516
- v: uv.getY(i + j)
28517
- }))
28518
- } : {}
28519
- });
28520
- }
28521
- if (geometry !== mesh.geometry) geometry.dispose();
28522
- return { triangles, boundingBox: boundsOfTriangles(triangles) };
28523
- }
28524
- function surfaceToGeometry(surface, center) {
28525
- const positions = [], normals = [], uvs = [];
28526
- for (const triangle of surface.triangles)
28527
- triangle.vertices.forEach((p, i) => {
28528
- positions.push(p.x + center.x, p.y + center.y, p.z);
28529
- normals.push(triangle.normal.x, triangle.normal.y, triangle.normal.z);
28530
- uvs.push(triangle.uvs?.[i]?.u ?? 0, triangle.uvs?.[i]?.v ?? 0);
28531
- });
28532
- const geometry = new THREE48.BufferGeometry();
28533
- geometry.setAttribute(
28534
- "position",
28535
- new THREE48.Float32BufferAttribute(positions, 3)
28536
- );
28537
- geometry.setAttribute("normal", new THREE48.Float32BufferAttribute(normals, 3));
28538
- geometry.setAttribute("uv", new THREE48.Float32BufferAttribute(uvs, 2));
28539
- geometry.computeBoundingBox();
28540
- geometry.computeBoundingSphere();
28541
- return geometry;
28542
- }
28543
- function replaceGeometry(mesh, surface, board) {
28544
- const output = mesh.clone();
28545
- output.geometry = surfaceToGeometry(surface, board.center);
28546
- output.position.set(0, 0, 0);
28547
- output.rotation.set(0, 0, 0);
28548
- output.scale.set(1, 1, 1);
28549
- output.updateMatrix();
28550
- return output;
28551
- }
28552
- function createFlexMeshes(geometryMeshes, textureMeshes, json, foldPcbs) {
28553
- const boards = json.filter((e) => e.type === "pcb_board");
28554
- const bends = json.filter((e) => e.type === "pcb_bend"), stiffeners = json.filter((e) => e.type === "pcb_stiffener");
28555
- if (!bends.length && !stiffeners.length)
28556
- return { geometryMeshes, textureMeshes };
28557
- const board = boards[0];
28558
- if (!board || boards.length !== 1 || json.some((e) => e.type === "pcb_panel") || [...bends, ...stiffeners].some((e) => e.pcb_board_id !== board.pcb_board_id))
28559
- throw new Error(
28560
- "Flex rendering requires one board, matching board references, and no panel"
28561
- );
28562
- const fold = foldPcbs ? createPcbFold(bends, board.thickness ?? 1.6) : void 0;
28563
- const body = geometryMeshes.find((m) => m.name === "board-geom");
28564
- const flatBody = body ? meshToSurface(body, board.center) : void 0;
28565
- const geometry = fold ? geometryMeshes.map(
28566
- (mesh) => replaceGeometry(
28567
- mesh,
28568
- foldSurfaceMesh(meshToSurface(mesh, board.center), fold),
28569
- board
28570
- )
28571
- ) : [...geometryMeshes];
28572
- const textures = fold && flatBody ? textureMeshes.map((mesh) => {
28573
- mesh.updateMatrix();
28574
- const inverse4 = mesh.matrix.clone().invert();
28575
- const bottom = mesh.name.startsWith("bottom");
28576
- const dimensions = mesh.geometry.parameters;
28577
- const triangles = flatBody.triangles.filter((t) => bottom ? t.normal.z < -0.9 : t.normal.z > 0.9).map((t) => {
28578
- const vertices = t.vertices.map((p) => ({
28579
- ...p,
28580
- z: mesh.position.z
28581
- }));
28582
- const uvs = vertices.map((p) => {
28583
- const local = new THREE48.Vector3(
28584
- p.x + board.center.x,
28585
- p.y + board.center.y,
28586
- p.z
28587
- ).applyMatrix4(inverse4);
28588
- return {
28589
- u: local.x / dimensions.width + 0.5,
28590
- v: local.y / dimensions.height + 0.5
28591
- };
28592
- });
28593
- return { ...t, vertices, uvs };
28594
- });
28595
- const result = replaceGeometry(
28596
- mesh,
28597
- foldSurfaceMesh(
28598
- { triangles, boundingBox: boundsOfTriangles(triangles) },
28599
- fold
28600
- ),
28601
- board
28602
- );
28603
- mesh.geometry.dispose();
28604
- return result;
28605
- }) : textureMeshes;
28606
- for (const stiffener of stiffeners) {
28607
- const mesh = new THREE48.Mesh(
28608
- surfaceToGeometry(
28609
- createStiffenerMesh({
28610
- stiffener,
28611
- boardThickness: board.thickness ?? 1.6,
28612
- fold
28613
- }),
28614
- board.center
28615
- ),
28616
- new THREE48.MeshStandardMaterial({
28617
- color: stiffener.material === "fr4" ? "#879568" : stiffener.material === "polyimide" ? "#bd7f27" : "#b8bdc4",
28618
- side: THREE48.DoubleSide
28619
- })
28620
- );
28621
- mesh.name = "board-stiffener";
28622
- configureObjectShadows(mesh);
28623
- geometry.push(mesh);
28624
- }
28625
- const bounds = new THREE48.Box3();
28626
- for (const mesh of [...geometry, ...textures]) bounds.expandByObject(mesh);
28627
- return {
28628
- geometryMeshes: geometry,
28629
- textureMeshes: textures,
28630
- bounds: {
28631
- minX: bounds.min.x,
28632
- maxX: bounds.max.x,
28633
- minY: bounds.min.y,
28634
- maxY: bounds.max.y,
28635
- minZ: bounds.min.z,
28636
- maxZ: bounds.max.z
28637
- }
28512
+ return { triangles, boundingBox: boundsOfTriangles(triangles) };
28513
+ }
28514
+ function createStiffenerMesh({
28515
+ stiffener,
28516
+ boardThickness,
28517
+ fold
28518
+ }) {
28519
+ const adhesive = stiffener.adhesive_thickness ?? 0;
28520
+ if (!Number.isFinite(adhesive) || adhesive < 0 || !Number.isFinite(stiffener.thickness) || stiffener.thickness <= 0 || !["top", "bottom"].includes(stiffener.layer))
28521
+ throw new Error(`Invalid PCB stiffener ${stiffener.pcb_stiffener_id}`);
28522
+ const outline = stiffener.shape === "polygon" ? stiffener.outline : (() => {
28523
+ if (!(stiffener.width > 0 && stiffener.height > 0))
28524
+ throw new Error("Invalid stiffener dimensions");
28525
+ const a = (stiffener.rotation ?? 0) * Math.PI / 180;
28526
+ return [
28527
+ [-1, -1],
28528
+ [1, -1],
28529
+ [1, 1],
28530
+ [-1, 1]
28531
+ ].map(([x, y]) => ({
28532
+ x: stiffener.center.x + x * stiffener.width / 2 * Math.cos(a) - y * stiffener.height / 2 * Math.sin(a),
28533
+ y: stiffener.center.y + x * stiffener.width / 2 * Math.sin(a) + y * stiffener.height / 2 * Math.cos(a)
28534
+ }));
28535
+ })();
28536
+ const near = boardThickness / 2 + adhesive, far = near + stiffener.thickness;
28537
+ const mesh = extrudePolygon({
28538
+ outline,
28539
+ bottom: stiffener.layer === "top" ? near : -far,
28540
+ top: stiffener.layer === "top" ? far : -near
28541
+ });
28542
+ if (!fold) return mesh;
28543
+ fold.assertRigid(
28544
+ mesh.triangles.flatMap((t) => t.vertices),
28545
+ stiffener.pcb_stiffener_id
28546
+ );
28547
+ const anchor = {
28548
+ x: outline.reduce((s, p) => s + p.x, 0) / outline.length,
28549
+ y: outline.reduce((s, p) => s + p.y, 0) / outline.length,
28550
+ z: 0
28638
28551
  };
28552
+ const triangles = mesh.triangles.map((t) => ({
28553
+ ...t,
28554
+ vertices: t.vertices.map((p) => fold.point(p, anchor)),
28555
+ normal: fold.direction(t.normal, anchor)
28556
+ }));
28557
+ return { ...mesh, triangles, boundingBox: boundsOfTriangles(triangles) };
28639
28558
  }
28640
28559
 
28641
28560
  // src/CadViewerManifold.tsx
28642
- import { su as su17 } from "@tscircuit/circuit-json-util";
28643
- import { useEffect as useEffect30, useMemo as useMemo26, useState as useState19 } from "react";
28644
- import * as THREE55 from "three";
28561
+ import { useEffect as useEffect31, useMemo as useMemo26, useState as useState19 } from "react";
28562
+ import * as THREE56 from "three";
28645
28563
 
28646
28564
  // src/hooks/useManifoldBoardBuilder.ts
28647
28565
  import { su as su16 } from "@tscircuit/circuit-json-util";
28648
- import { useEffect as useEffect29, useMemo as useMemo25, useRef as useRef9, useState as useState18 } from "react";
28566
+ import { useEffect as useEffect30, useMemo as useMemo25, useRef as useRef9, useState as useState18 } from "react";
28649
28567
  import * as THREE52 from "three";
28650
28568
 
28651
28569
  // src/utils/manifold/create-manifold-board.ts
@@ -29824,7 +29742,7 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson, visibility) => {
29824
29742
  if (!boardData) return TRACE_TEXTURE_RESOLUTION;
29825
29743
  return getLayerTextureResolution(boardData, TRACE_TEXTURE_RESOLUTION);
29826
29744
  }, [boardData]);
29827
- useEffect29(() => {
29745
+ useEffect30(() => {
29828
29746
  if (!manifoldJSModule || !boardData) {
29829
29747
  setGeoms(null);
29830
29748
  setPcbThickness(null);
@@ -30024,12 +29942,157 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson, visibility) => {
30024
29942
  };
30025
29943
  };
30026
29944
 
29945
+ // src/utils/flex-meshes.ts
29946
+ import * as THREE53 from "three";
29947
+ function meshToSurface(mesh, center) {
29948
+ mesh.updateMatrix();
29949
+ const geometry = mesh.geometry.index ? mesh.geometry.toNonIndexed() : mesh.geometry;
29950
+ const position = geometry.getAttribute("position"), uv = geometry.getAttribute("uv");
29951
+ const triangles = [];
29952
+ for (let i = 0; i < position.count; i += 3) {
29953
+ const vertices = [0, 1, 2].map((j) => {
29954
+ const v = new THREE53.Vector3().fromBufferAttribute(position, i + j).applyMatrix4(mesh.matrix);
29955
+ return { x: v.x - center.x, y: v.y - center.y, z: v.z };
29956
+ });
29957
+ const [a, b, c] = vertices;
29958
+ const n = new THREE53.Vector3(b.x - a.x, b.y - a.y, b.z - a.z).cross(new THREE53.Vector3(c.x - a.x, c.y - a.y, c.z - a.z)).normalize();
29959
+ triangles.push({
29960
+ vertices,
29961
+ normal: { x: n.x, y: n.y, z: n.z },
29962
+ ...uv ? {
29963
+ uvs: [0, 1, 2].map((j) => ({
29964
+ u: uv.getX(i + j),
29965
+ v: uv.getY(i + j)
29966
+ }))
29967
+ } : {}
29968
+ });
29969
+ }
29970
+ if (geometry !== mesh.geometry) geometry.dispose();
29971
+ return { triangles, boundingBox: boundsOfTriangles(triangles) };
29972
+ }
29973
+ function surfaceToGeometry(surface, center) {
29974
+ const positions = [], normals = [], uvs = [];
29975
+ for (const triangle of surface.triangles)
29976
+ triangle.vertices.forEach((p, i) => {
29977
+ positions.push(p.x + center.x, p.y + center.y, p.z);
29978
+ normals.push(triangle.normal.x, triangle.normal.y, triangle.normal.z);
29979
+ uvs.push(triangle.uvs?.[i]?.u ?? 0, triangle.uvs?.[i]?.v ?? 0);
29980
+ });
29981
+ const geometry = new THREE53.BufferGeometry();
29982
+ geometry.setAttribute(
29983
+ "position",
29984
+ new THREE53.Float32BufferAttribute(positions, 3)
29985
+ );
29986
+ geometry.setAttribute("normal", new THREE53.Float32BufferAttribute(normals, 3));
29987
+ geometry.setAttribute("uv", new THREE53.Float32BufferAttribute(uvs, 2));
29988
+ geometry.computeBoundingBox();
29989
+ geometry.computeBoundingSphere();
29990
+ return geometry;
29991
+ }
29992
+ function replaceGeometry(mesh, surface, board) {
29993
+ const output = mesh.clone();
29994
+ output.geometry = surfaceToGeometry(surface, board.center);
29995
+ output.position.set(0, 0, 0);
29996
+ output.rotation.set(0, 0, 0);
29997
+ output.scale.set(1, 1, 1);
29998
+ output.updateMatrix();
29999
+ return output;
30000
+ }
30001
+ function createFlexMeshes(geometryMeshes, textureMeshes, json, foldPcbs) {
30002
+ const boards = json.filter((e) => e.type === "pcb_board");
30003
+ const bends = json.filter((e) => e.type === "pcb_bend"), stiffeners = json.filter((e) => e.type === "pcb_stiffener");
30004
+ if (!bends.length && !stiffeners.length)
30005
+ return { geometryMeshes, textureMeshes };
30006
+ const board = boards[0];
30007
+ if (!board || boards.length !== 1 || json.some((e) => e.type === "pcb_panel") || [...bends, ...stiffeners].some((e) => e.pcb_board_id !== board.pcb_board_id))
30008
+ throw new Error(
30009
+ "Flex rendering requires one board, matching board references, and no panel"
30010
+ );
30011
+ const fold = foldPcbs ? createPcbFold(bends, board.thickness ?? 1.6) : void 0;
30012
+ const body = geometryMeshes.find((m) => m.name === "board-geom");
30013
+ const flatBody = body ? meshToSurface(body, board.center) : void 0;
30014
+ const geometry = fold ? geometryMeshes.map(
30015
+ (mesh) => replaceGeometry(
30016
+ mesh,
30017
+ foldSurfaceMesh(meshToSurface(mesh, board.center), fold),
30018
+ board
30019
+ )
30020
+ ) : [...geometryMeshes];
30021
+ const textures = fold && flatBody ? textureMeshes.map((mesh) => {
30022
+ mesh.updateMatrix();
30023
+ const inverse4 = mesh.matrix.clone().invert();
30024
+ const bottom = mesh.name.startsWith("bottom");
30025
+ const dimensions = mesh.geometry.parameters;
30026
+ const triangles = flatBody.triangles.filter((t) => bottom ? t.normal.z < -0.9 : t.normal.z > 0.9).map((t) => {
30027
+ const vertices = t.vertices.map((p) => ({
30028
+ ...p,
30029
+ z: mesh.position.z
30030
+ }));
30031
+ const uvs = vertices.map((p) => {
30032
+ const local = new THREE53.Vector3(
30033
+ p.x + board.center.x,
30034
+ p.y + board.center.y,
30035
+ p.z
30036
+ ).applyMatrix4(inverse4);
30037
+ return {
30038
+ u: local.x / dimensions.width + 0.5,
30039
+ v: local.y / dimensions.height + 0.5
30040
+ };
30041
+ });
30042
+ return { ...t, vertices, uvs };
30043
+ });
30044
+ const result = replaceGeometry(
30045
+ mesh,
30046
+ foldSurfaceMesh(
30047
+ { triangles, boundingBox: boundsOfTriangles(triangles) },
30048
+ fold
30049
+ ),
30050
+ board
30051
+ );
30052
+ mesh.geometry.dispose();
30053
+ return result;
30054
+ }) : textureMeshes;
30055
+ for (const stiffener of stiffeners) {
30056
+ const mesh = new THREE53.Mesh(
30057
+ surfaceToGeometry(
30058
+ createStiffenerMesh({
30059
+ stiffener,
30060
+ boardThickness: board.thickness ?? 1.6,
30061
+ fold
30062
+ }),
30063
+ board.center
30064
+ ),
30065
+ new THREE53.MeshStandardMaterial({
30066
+ color: stiffener.material === "fr4" ? "#879568" : stiffener.material === "polyimide" ? "#bd7f27" : "#b8bdc4",
30067
+ side: THREE53.DoubleSide
30068
+ })
30069
+ );
30070
+ mesh.name = "board-stiffener";
30071
+ configureObjectShadows(mesh);
30072
+ geometry.push(mesh);
30073
+ }
30074
+ const bounds = new THREE53.Box3();
30075
+ for (const mesh of [...geometry, ...textures]) bounds.expandByObject(mesh);
30076
+ return {
30077
+ geometryMeshes: geometry,
30078
+ textureMeshes: textures,
30079
+ bounds: {
30080
+ minX: bounds.min.x,
30081
+ maxX: bounds.max.x,
30082
+ minY: bounds.min.y,
30083
+ maxY: bounds.max.y,
30084
+ minZ: bounds.min.z,
30085
+ maxZ: bounds.max.z
30086
+ }
30087
+ };
30088
+ }
30089
+
30027
30090
  // src/utils/manifold/create-three-geometry-meshes.ts
30028
- import * as THREE54 from "three";
30091
+ import * as THREE55 from "three";
30029
30092
 
30030
30093
  // src/utils/create-board-material.ts
30031
- import * as THREE53 from "three";
30032
- var DEFAULT_SIDE = THREE53.DoubleSide;
30094
+ import * as THREE54 from "three";
30095
+ var DEFAULT_SIDE = THREE54.DoubleSide;
30033
30096
  var createBoardMaterial = ({
30034
30097
  material,
30035
30098
  color,
@@ -30037,7 +30100,7 @@ var createBoardMaterial = ({
30037
30100
  isFaux = false
30038
30101
  }) => {
30039
30102
  if (material === "fr4") {
30040
- return new THREE53.MeshPhysicalMaterial({
30103
+ return new THREE54.MeshPhysicalMaterial({
30041
30104
  color,
30042
30105
  side,
30043
30106
  metalness: 0,
@@ -30055,7 +30118,7 @@ var createBoardMaterial = ({
30055
30118
  polygonOffsetUnits: 1
30056
30119
  });
30057
30120
  }
30058
- return new THREE53.MeshStandardMaterial({
30121
+ return new THREE54.MeshStandardMaterial({
30059
30122
  color,
30060
30123
  side,
30061
30124
  flatShading: true,
@@ -30074,12 +30137,12 @@ function createGeometryMeshes(geoms) {
30074
30137
  const meshes = [];
30075
30138
  if (!geoms) return meshes;
30076
30139
  if (geoms.board?.geometry) {
30077
- const mesh = new THREE54.Mesh(
30140
+ const mesh = new THREE55.Mesh(
30078
30141
  geoms.board.geometry,
30079
30142
  createBoardMaterial({
30080
30143
  material: geoms.board.material,
30081
30144
  color: geoms.board.color,
30082
- side: THREE54.DoubleSide,
30145
+ side: THREE55.DoubleSide,
30083
30146
  isFaux: geoms.board.isFaux
30084
30147
  })
30085
30148
  );
@@ -30090,11 +30153,11 @@ function createGeometryMeshes(geoms) {
30090
30153
  const createMeshesFromArray = (geomArray) => {
30091
30154
  if (geomArray) {
30092
30155
  for (const comp of geomArray) {
30093
- const mesh = new THREE54.Mesh(
30156
+ const mesh = new THREE55.Mesh(
30094
30157
  comp.geometry,
30095
- new THREE54.MeshStandardMaterial({
30158
+ new THREE55.MeshStandardMaterial({
30096
30159
  color: comp.color,
30097
- side: THREE54.DoubleSide,
30160
+ side: THREE55.DoubleSide,
30098
30161
  flatShading: true
30099
30162
  // Consistent with board
30100
30163
  })
@@ -30139,14 +30202,14 @@ var BoardMeshes = ({
30139
30202
  const typedMaterial = material;
30140
30203
  for (const prop of textureProps) {
30141
30204
  const texture = typedMaterial[prop];
30142
- if (texture && texture instanceof THREE55.Texture) {
30205
+ if (texture && texture instanceof THREE56.Texture) {
30143
30206
  texture.dispose();
30144
30207
  }
30145
30208
  }
30146
30209
  material.dispose();
30147
30210
  }
30148
30211
  };
30149
- useEffect30(() => {
30212
+ useEffect31(() => {
30150
30213
  if (!rootObject) return;
30151
30214
  for (const mesh of geometryMeshes) {
30152
30215
  let shouldShow = true;
@@ -30168,7 +30231,7 @@ var BoardMeshes = ({
30168
30231
  }
30169
30232
  };
30170
30233
  }, [rootObject, geometryMeshes, visibility]);
30171
- useEffect30(() => {
30234
+ useEffect31(() => {
30172
30235
  if (!rootObject) return;
30173
30236
  for (const mesh of textureMeshes) {
30174
30237
  rootObject.add(mesh);
@@ -30205,7 +30268,7 @@ var CadViewerManifold = ({
30205
30268
  const [manifoldJSModule, setManifoldJSModule] = useState19(null);
30206
30269
  const [manifoldLoadingError, setManifoldLoadingError] = useState19(null);
30207
30270
  const { visibility } = useLayerVisibility();
30208
- useEffect30(() => {
30271
+ useEffect31(() => {
30209
30272
  if (window.ManifoldModule && typeof window.ManifoldModule === "object" && window.ManifoldModule.setup) {
30210
30273
  setManifoldJSModule(window.ManifoldModule);
30211
30274
  return;
@@ -30326,20 +30389,16 @@ try {
30326
30389
  return { x: bounds.centerX, y: bounds.centerY };
30327
30390
  }, [boardData]);
30328
30391
  const initialCameraPosition = useMemo26(() => {
30329
- if (!boardData) return [5, -5, 5];
30330
- const { width = 0, height = 0 } = boardData;
30331
- const safeWidth = Math.max(width, 1);
30332
- const safeHeight = Math.max(height, 1);
30333
- const largestDim = Math.max(safeWidth, safeHeight, 5);
30334
- return [
30335
- largestDim * 0.4,
30336
- // Move right
30337
- -largestDim * 0.7,
30338
- // Move back (negative Y)
30339
- largestDim * 0.9
30340
- // Keep height but slightly lower than top-down
30341
- ];
30342
- }, [boardData]);
30392
+ return getInitialCameraPosition({ boardDimensions, boardCenter });
30393
+ }, [boardDimensions, boardCenter]);
30394
+ const cameraSessionScope = useMemo26(() => {
30395
+ if (!boardData) return void 0;
30396
+ return JSON.stringify({
30397
+ pcbBoardId: boardData.pcb_board_id,
30398
+ center: boardCenter,
30399
+ dimensions: boardDimensions
30400
+ });
30401
+ }, [boardData, boardCenter, boardDimensions]);
30343
30402
  if (manifoldLoadingError) {
30344
30403
  return /* @__PURE__ */ jsxs5(
30345
30404
  "div",
@@ -30389,6 +30448,7 @@ try {
30389
30448
  clickToInteractEnabled,
30390
30449
  boardDimensions,
30391
30450
  boardCenter,
30451
+ cameraSessionScope,
30392
30452
  referenceObject,
30393
30453
  onUserInteraction,
30394
30454
  onCameraControllerReady,
@@ -37871,10 +37931,10 @@ var ContextMenu = ({
37871
37931
  };
37872
37932
 
37873
37933
  // src/components/KeyboardShortcutsDialog.tsx
37874
- import { useEffect as useEffect48, useMemo as useMemo36, useRef as useRef27, useState as useState40 } from "react";
37934
+ import { useEffect as useEffect49, useMemo as useMemo36, useRef as useRef27, useState as useState40 } from "react";
37875
37935
 
37876
37936
  // src/hooks/useRegisteredHotkey.ts
37877
- import { useEffect as useEffect47, useMemo as useMemo35, useRef as useRef26, useState as useState39 } from "react";
37937
+ import { useEffect as useEffect48, useMemo as useMemo35, useRef as useRef26, useState as useState39 } from "react";
37878
37938
  var hotkeyRegistry = /* @__PURE__ */ new Map();
37879
37939
  var subscribers = /* @__PURE__ */ new Set();
37880
37940
  var isListenerAttached = false;
@@ -38005,7 +38065,7 @@ var useRegisteredHotkey = (id, handler, metadata) => {
38005
38065
  }),
38006
38066
  [metadata.shortcut, metadata.description]
38007
38067
  );
38008
- useEffect47(() => {
38068
+ useEffect48(() => {
38009
38069
  const registration = {
38010
38070
  id,
38011
38071
  ...normalizedMetadata,
@@ -38021,7 +38081,7 @@ var useHotkeyRegistry = () => {
38021
38081
  const [entries, setEntries] = useState39(
38022
38082
  () => Array.from(hotkeyRegistry.values())
38023
38083
  );
38024
- useEffect47(() => subscribeToRegistry(setEntries), []);
38084
+ useEffect48(() => subscribeToRegistry(setEntries), []);
38025
38085
  return entries;
38026
38086
  };
38027
38087
  var registerHotkeyViewer = (element) => {
@@ -38038,7 +38098,7 @@ var KeyboardShortcutsDialog = ({
38038
38098
  const [query, setQuery] = useState40("");
38039
38099
  const inputRef = useRef27(null);
38040
38100
  const hotkeys = useHotkeyRegistry();
38041
- useEffect48(() => {
38101
+ useEffect49(() => {
38042
38102
  if (!open) return void 0;
38043
38103
  const handleKeyDown = (event) => {
38044
38104
  if (event.key === "Escape") {
@@ -38049,7 +38109,7 @@ var KeyboardShortcutsDialog = ({
38049
38109
  window.addEventListener("keydown", handleKeyDown);
38050
38110
  return () => window.removeEventListener("keydown", handleKeyDown);
38051
38111
  }, [open, onClose]);
38052
- useEffect48(() => {
38112
+ useEffect49(() => {
38053
38113
  if (open) {
38054
38114
  setTimeout(() => {
38055
38115
  inputRef.current?.focus();
@@ -38278,7 +38338,7 @@ function useCameraPreset({
38278
38338
  }
38279
38339
 
38280
38340
  // src/hooks/useContextMenu.ts
38281
- import { useState as useState41, useCallback as useCallback23, useRef as useRef28, useEffect as useEffect49 } from "react";
38341
+ import { useState as useState41, useCallback as useCallback23, useRef as useRef28, useEffect as useEffect50 } from "react";
38282
38342
  var useContextMenu = ({ containerRef, onOpen }) => {
38283
38343
  const [menuVisible, setMenuVisible] = useState41(false);
38284
38344
  const [menuPos, setMenuPos] = useState41({
@@ -38395,7 +38455,7 @@ var useContextMenu = ({ containerRef, onOpen }) => {
38395
38455
  }
38396
38456
  setMenuVisible(false);
38397
38457
  }, []);
38398
- useEffect49(() => {
38458
+ useEffect50(() => {
38399
38459
  if (menuVisible) {
38400
38460
  document.addEventListener("mousedown", handleClickAway);
38401
38461
  document.addEventListener("touchstart", handleClickAway);
@@ -38459,7 +38519,7 @@ var useGlobalDownloadGltf = () => {
38459
38519
 
38460
38520
  // src/CadViewer.tsx
38461
38521
  import { jsx as jsx38, jsxs as jsxs10 } from "react/jsx-runtime";
38462
- var DEFAULT_TARGET = new THREE56.Vector3(0, 0, 0);
38522
+ var DEFAULT_TARGET = new THREE57.Vector3(0, 0, 0);
38463
38523
  var INITIAL_CAMERA_POSITION = [5, -5, 5];
38464
38524
  var readStoredCameraType = () => {
38465
38525
  if (typeof window === "undefined") return void 0;
@@ -38626,24 +38686,24 @@ var CadViewerInner = (props) => {
38626
38686
  description: "Toggle translucent components"
38627
38687
  }
38628
38688
  );
38629
- useEffect50(() => {
38689
+ useEffect51(() => {
38630
38690
  if (containerRef.current) {
38631
38691
  registerHotkeyViewer(containerRef.current);
38632
38692
  }
38633
38693
  }, []);
38634
- useEffect50(() => {
38694
+ useEffect51(() => {
38635
38695
  window.localStorage.setItem("cadViewerEngine", engine);
38636
38696
  }, [engine]);
38637
- useEffect50(() => {
38697
+ useEffect51(() => {
38638
38698
  window.localStorage.setItem("cadViewerAutoRotate", String(autoRotate));
38639
38699
  }, [autoRotate]);
38640
- useEffect50(() => {
38700
+ useEffect51(() => {
38641
38701
  window.localStorage.setItem(
38642
38702
  "cadViewerAutoRotateUserToggled",
38643
38703
  String(autoRotateUserToggled)
38644
38704
  );
38645
38705
  }, [autoRotateUserToggled]);
38646
- useEffect50(() => {
38706
+ useEffect51(() => {
38647
38707
  window.localStorage.setItem("cadViewerCameraType", cameraType);
38648
38708
  }, [cameraType]);
38649
38709
  const viewerKey = props.circuitJson ? circuitKey : void 0;
@@ -38782,11 +38842,11 @@ var CadViewer = (props) => {
38782
38842
  // src/convert-circuit-json-to-3d-svg.ts
38783
38843
  var import_debug = __toESM(require_browser(), 1);
38784
38844
  import { su as su18 } from "@tscircuit/circuit-json-util";
38785
- import * as THREE60 from "three";
38845
+ import * as THREE61 from "three";
38786
38846
  import { SVGRenderer } from "three/examples/jsm/renderers/SVGRenderer.js";
38787
38847
 
38788
38848
  // src/utils/create-geometry-from-polygons.ts
38789
- import * as THREE57 from "three";
38849
+ import * as THREE58 from "three";
38790
38850
  import { BufferGeometry as BufferGeometry6, Float32BufferAttribute as Float32BufferAttribute6 } from "three";
38791
38851
  function createGeometryFromPolygons(polygons) {
38792
38852
  const geometry = new BufferGeometry6();
@@ -38800,12 +38860,12 @@ function createGeometryFromPolygons(polygons) {
38800
38860
  ...polygon2.vertices[i + 1]
38801
38861
  // Third vertex
38802
38862
  );
38803
- const v1 = new THREE57.Vector3(...polygon2.vertices[0]);
38804
- const v2 = new THREE57.Vector3(...polygon2.vertices[i]);
38805
- const v3 = new THREE57.Vector3(...polygon2.vertices[i + 1]);
38806
- const normal = new THREE57.Vector3().crossVectors(
38807
- new THREE57.Vector3().subVectors(v2, v1),
38808
- new THREE57.Vector3().subVectors(v3, v1)
38863
+ const v1 = new THREE58.Vector3(...polygon2.vertices[0]);
38864
+ const v2 = new THREE58.Vector3(...polygon2.vertices[i]);
38865
+ const v3 = new THREE58.Vector3(...polygon2.vertices[i + 1]);
38866
+ const normal = new THREE58.Vector3().crossVectors(
38867
+ new THREE58.Vector3().subVectors(v2, v1),
38868
+ new THREE58.Vector3().subVectors(v3, v1)
38809
38869
  ).normalize();
38810
38870
  normals.push(
38811
38871
  normal.x,
@@ -38833,10 +38893,10 @@ import {
38833
38893
  convertCSGToThreeGeom as convertCSGToThreeGeom3,
38834
38894
  getJscadModelForFootprint as getJscadModelForFootprint2
38835
38895
  } from "jscad-electronics/vanilla";
38836
- import * as THREE59 from "three";
38896
+ import * as THREE60 from "three";
38837
38897
 
38838
38898
  // src/utils/load-model.ts
38839
- import * as THREE58 from "three";
38899
+ import * as THREE59 from "three";
38840
38900
  import { GLTFLoader as GLTFLoader2 } from "three/examples/jsm/loaders/GLTFLoader.js";
38841
38901
  import { OBJLoader as OBJLoader2 } from "three/examples/jsm/loaders/OBJLoader.js";
38842
38902
  import { STLLoader as STLLoader2 } from "three/examples/jsm/loaders/STLLoader.js";
@@ -38844,12 +38904,12 @@ async function load3DModel(url) {
38844
38904
  if (url.endsWith(".stl")) {
38845
38905
  const loader = new STLLoader2();
38846
38906
  const geometry = await loader.loadAsync(url);
38847
- const material = new THREE58.MeshStandardMaterial({
38907
+ const material = new THREE59.MeshStandardMaterial({
38848
38908
  color: 8947848,
38849
38909
  metalness: 0.5,
38850
38910
  roughness: 0.5
38851
38911
  });
38852
- return new THREE58.Mesh(geometry, material);
38912
+ return new THREE59.Mesh(geometry, material);
38853
38913
  }
38854
38914
  if (url.endsWith(".obj")) {
38855
38915
  const loader = new OBJLoader2();
@@ -38882,9 +38942,9 @@ async function renderComponent(component, scene) {
38882
38942
  }
38883
38943
  if (component.rotation) {
38884
38944
  model.rotation.set(
38885
- THREE59.MathUtils.degToRad(component.rotation.x ?? 0),
38886
- THREE59.MathUtils.degToRad(component.rotation.y ?? 0),
38887
- THREE59.MathUtils.degToRad(component.rotation.z ?? 0)
38945
+ THREE60.MathUtils.degToRad(component.rotation.x ?? 0),
38946
+ THREE60.MathUtils.degToRad(component.rotation.y ?? 0),
38947
+ THREE60.MathUtils.degToRad(component.rotation.z ?? 0)
38888
38948
  );
38889
38949
  }
38890
38950
  scene.add(model);
@@ -38898,13 +38958,13 @@ async function renderComponent(component, scene) {
38898
38958
  );
38899
38959
  if (jscadObject && (jscadObject.polygons || jscadObject.sides)) {
38900
38960
  const threeGeom = convertCSGToThreeGeom3(jscadObject);
38901
- const material2 = new THREE59.MeshStandardMaterial({
38961
+ const material2 = new THREE60.MeshStandardMaterial({
38902
38962
  color: 8947848,
38903
38963
  metalness: 0.5,
38904
38964
  roughness: 0.5,
38905
- side: THREE59.DoubleSide
38965
+ side: THREE60.DoubleSide
38906
38966
  });
38907
- const mesh2 = new THREE59.Mesh(threeGeom, material2);
38967
+ const mesh2 = new THREE60.Mesh(threeGeom, material2);
38908
38968
  if (component.position) {
38909
38969
  mesh2.position.set(
38910
38970
  component.position.x ?? 0,
@@ -38914,9 +38974,9 @@ async function renderComponent(component, scene) {
38914
38974
  }
38915
38975
  if (component.rotation) {
38916
38976
  mesh2.rotation.set(
38917
- THREE59.MathUtils.degToRad(component.rotation.x ?? 0),
38918
- THREE59.MathUtils.degToRad(component.rotation.y ?? 0),
38919
- THREE59.MathUtils.degToRad(component.rotation.z ?? 0)
38977
+ THREE60.MathUtils.degToRad(component.rotation.x ?? 0),
38978
+ THREE60.MathUtils.degToRad(component.rotation.y ?? 0),
38979
+ THREE60.MathUtils.degToRad(component.rotation.z ?? 0)
38920
38980
  );
38921
38981
  }
38922
38982
  scene.add(mesh2);
@@ -38933,17 +38993,17 @@ async function renderComponent(component, scene) {
38933
38993
  if (!geom || !geom.polygons && !geom.sides) {
38934
38994
  continue;
38935
38995
  }
38936
- const color = new THREE59.Color(geomInfo.color);
38996
+ const color = new THREE60.Color(geomInfo.color);
38937
38997
  color.convertLinearToSRGB();
38938
38998
  const geomWithColor = { ...geom, color: [color.r, color.g, color.b] };
38939
38999
  const threeGeom = convertCSGToThreeGeom3(geomWithColor);
38940
- const material2 = new THREE59.MeshStandardMaterial({
39000
+ const material2 = new THREE60.MeshStandardMaterial({
38941
39001
  vertexColors: true,
38942
39002
  metalness: 0.2,
38943
39003
  roughness: 0.8,
38944
- side: THREE59.DoubleSide
39004
+ side: THREE60.DoubleSide
38945
39005
  });
38946
- const mesh2 = new THREE59.Mesh(threeGeom, material2);
39006
+ const mesh2 = new THREE60.Mesh(threeGeom, material2);
38947
39007
  if (component.position) {
38948
39008
  mesh2.position.set(
38949
39009
  component.position.x ?? 0,
@@ -38953,22 +39013,22 @@ async function renderComponent(component, scene) {
38953
39013
  }
38954
39014
  if (component.rotation) {
38955
39015
  mesh2.rotation.set(
38956
- THREE59.MathUtils.degToRad(component.rotation.x ?? 0),
38957
- THREE59.MathUtils.degToRad(component.rotation.y ?? 0),
38958
- THREE59.MathUtils.degToRad(component.rotation.z ?? 0)
39016
+ THREE60.MathUtils.degToRad(component.rotation.x ?? 0),
39017
+ THREE60.MathUtils.degToRad(component.rotation.y ?? 0),
39018
+ THREE60.MathUtils.degToRad(component.rotation.z ?? 0)
38959
39019
  );
38960
39020
  }
38961
39021
  scene.add(mesh2);
38962
39022
  }
38963
39023
  return;
38964
39024
  }
38965
- const geometry = new THREE59.BoxGeometry(0.5, 0.5, 0.5);
38966
- const material = new THREE59.MeshStandardMaterial({
39025
+ const geometry = new THREE60.BoxGeometry(0.5, 0.5, 0.5);
39026
+ const material = new THREE60.MeshStandardMaterial({
38967
39027
  color: 16711680,
38968
39028
  transparent: true,
38969
39029
  opacity: 0.25
38970
39030
  });
38971
- const mesh = new THREE59.Mesh(geometry, material);
39031
+ const mesh = new THREE60.Mesh(geometry, material);
38972
39032
  if (component.position) {
38973
39033
  mesh.position.set(
38974
39034
  component.position.x ?? 0,
@@ -38989,11 +39049,11 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
38989
39049
  padding = 20,
38990
39050
  zoom = 1.5
38991
39051
  } = options;
38992
- const scene = new THREE60.Scene();
39052
+ const scene = new THREE61.Scene();
38993
39053
  const renderer = new SVGRenderer();
38994
39054
  renderer.setSize(width, height);
38995
- renderer.setClearColor(new THREE60.Color(backgroundColor), 1);
38996
- const camera = new THREE60.OrthographicCamera();
39055
+ renderer.setClearColor(new THREE61.Color(backgroundColor), 1);
39056
+ const camera = new THREE61.OrthographicCamera();
38997
39057
  const aspect = width / height;
38998
39058
  const frustumSize = 100;
38999
39059
  const halfFrustumSize = frustumSize / 2 / zoom;
@@ -39007,11 +39067,11 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
39007
39067
  camera.position.set(position.x, position.y, position.z);
39008
39068
  camera.up.set(0, 1, 0);
39009
39069
  const lookAt2 = options.camera?.lookAt ?? { x: 0, y: 0, z: 0 };
39010
- camera.lookAt(new THREE60.Vector3(lookAt2.x, lookAt2.y, lookAt2.z));
39070
+ camera.lookAt(new THREE61.Vector3(lookAt2.x, lookAt2.y, lookAt2.z));
39011
39071
  camera.updateProjectionMatrix();
39012
- const ambientLight = new THREE60.AmbientLight(16777215, Math.PI / 2);
39072
+ const ambientLight = new THREE61.AmbientLight(16777215, Math.PI / 2);
39013
39073
  scene.add(ambientLight);
39014
- const pointLight = new THREE60.PointLight(16777215, Math.PI / 4);
39074
+ const pointLight = new THREE61.PointLight(16777215, Math.PI / 4);
39015
39075
  pointLight.position.set(-10, -10, 10);
39016
39076
  scene.add(pointLight);
39017
39077
  const components = su18(circuitJson).cad_component.list();
@@ -39043,28 +39103,28 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
39043
39103
  const material = createBoardMaterial({
39044
39104
  material: boardData?.material,
39045
39105
  color: edgeColor,
39046
- side: THREE60.DoubleSide
39106
+ side: THREE61.DoubleSide
39047
39107
  });
39048
- const mesh = new THREE60.Mesh(geometry, material);
39108
+ const mesh = new THREE61.Mesh(geometry, material);
39049
39109
  scene.add(mesh);
39050
39110
  }
39051
39111
  }
39052
- const gridColor = new THREE60.Color(8947848);
39053
- const gridHelper = new THREE60.GridHelper(100, 100, gridColor, gridColor);
39112
+ const gridColor = new THREE61.Color(8947848);
39113
+ const gridHelper = new THREE61.GridHelper(100, 100, gridColor, gridColor);
39054
39114
  gridHelper.rotation.x = Math.PI / 2;
39055
39115
  const materials = Array.isArray(gridHelper.material) ? gridHelper.material : [gridHelper.material];
39056
39116
  for (const mat of materials) {
39057
39117
  mat.transparent = true;
39058
39118
  mat.opacity = 0.3;
39059
- if (mat instanceof THREE60.LineBasicMaterial) {
39119
+ if (mat instanceof THREE61.LineBasicMaterial) {
39060
39120
  mat.color = gridColor;
39061
39121
  mat.vertexColors = false;
39062
39122
  }
39063
39123
  }
39064
39124
  scene.add(gridHelper);
39065
- const box = new THREE60.Box3().setFromObject(scene);
39066
- const center = box.getCenter(new THREE60.Vector3());
39067
- const size4 = box.getSize(new THREE60.Vector3());
39125
+ const box = new THREE61.Box3().setFromObject(scene);
39126
+ const center = box.getCenter(new THREE61.Vector3());
39127
+ const size4 = box.getSize(new THREE61.Vector3());
39068
39128
  scene.position.sub(center);
39069
39129
  const maxDim = Math.max(size4.x, size4.y, size4.z);
39070
39130
  if (maxDim > 0) {
@@ -39082,7 +39142,7 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
39082
39142
 
39083
39143
  // src/hooks/exporter/gltf.ts
39084
39144
  import { GLTFExporter as GLTFExporter3 } from "three-stdlib";
39085
- import { useEffect as useEffect51, useState as useState43, useMemo as useMemo37, useCallback as useCallback26 } from "react";
39145
+ import { useEffect as useEffect52, useState as useState43, useMemo as useMemo37, useCallback as useCallback26 } from "react";
39086
39146
  function useSaveGltfAs(options = {}) {
39087
39147
  const parse2 = useParser(options);
39088
39148
  const link = useMemo37(() => document.createElement("a"), []);
@@ -39095,7 +39155,7 @@ function useSaveGltfAs(options = {}) {
39095
39155
  link.dispatchEvent(new MouseEvent("click"));
39096
39156
  URL.revokeObjectURL(url);
39097
39157
  };
39098
- useEffect51(
39158
+ useEffect52(
39099
39159
  () => () => {
39100
39160
  link.remove();
39101
39161
  instance = null;
@@ -39116,7 +39176,7 @@ function useExportGltfUrl(options = {}) {
39116
39176
  (instance) => parse2(instance).then(setUrl).catch(setError),
39117
39177
  []
39118
39178
  );
39119
- useEffect51(() => () => URL.revokeObjectURL(url), [url]);
39179
+ useEffect52(() => () => URL.revokeObjectURL(url), [url]);
39120
39180
  return [ref, url, error];
39121
39181
  }
39122
39182
  function useParser(options = {}) {