@tscircuit/3d-viewer 0.0.406 → 0.0.408

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.d.ts CHANGED
@@ -47,6 +47,7 @@ interface ManifoldGeoms {
47
47
  board?: {
48
48
  geometry: THREE.BufferGeometry;
49
49
  color: THREE.Color;
50
+ material: PcbBoard["material"];
50
51
  };
51
52
  platedHoles?: Array<{
52
53
  key: string;
package/dist/index.js CHANGED
@@ -26100,7 +26100,7 @@ import * as THREE13 from "three";
26100
26100
  // package.json
26101
26101
  var package_default = {
26102
26102
  name: "@tscircuit/3d-viewer",
26103
- version: "0.0.405",
26103
+ version: "0.0.407",
26104
26104
  main: "./dist/index.js",
26105
26105
  module: "./dist/index.js",
26106
26106
  type: "module",
@@ -26879,7 +26879,7 @@ import { su as su2 } from "@tscircuit/circuit-json-util";
26879
26879
  var M = 0.01;
26880
26880
  var colors = {
26881
26881
  copper: [0.9, 0.6, 0.2],
26882
- fr4Green: [5 / 255, 163 / 255, 46 / 255],
26882
+ fr4Green: [0.04, 0.16, 0.08],
26883
26883
  fr4GreenSolderWithMask: [0 / 255, 152 / 255, 19 / 255],
26884
26884
  fr1Copper: [0.8, 0.4, 0.2],
26885
26885
  fr1CopperSolderWithMask: [0.9, 0.6, 0.2]
@@ -28930,6 +28930,20 @@ function createPadManifoldOp({
28930
28930
  thickness: padBaseThickness,
28931
28931
  borderRadius: rectBorderRadius
28932
28932
  });
28933
+ } else if (pad2.shape === "rotated_rect") {
28934
+ const rectBorderRadius = extractRectBorderRadius(pad2);
28935
+ let padOp = createRoundedRectPrism({
28936
+ Manifold,
28937
+ width: pad2.width,
28938
+ height: pad2.height,
28939
+ thickness: padBaseThickness,
28940
+ borderRadius: rectBorderRadius
28941
+ });
28942
+ const rotation2 = pad2.ccw_rotation ?? 0;
28943
+ if (rotation2) {
28944
+ padOp = padOp.rotate([0, 0, rotation2]);
28945
+ }
28946
+ return padOp;
28933
28947
  } else if (pad2.shape === "circle" && pad2.radius) {
28934
28948
  return Manifold.cylinder(padBaseThickness, pad2.radius, -1, 32, true);
28935
28949
  }
@@ -28938,10 +28952,22 @@ function createPadManifoldOp({
28938
28952
 
28939
28953
  // src/utils/manifold/process-plated-holes.ts
28940
28954
  var COPPER_COLOR = new THREE19.Color(...colors.copper);
28955
+ var PLATED_HOLE_LIP_HEIGHT = 0.05;
28941
28956
  function processPlatedHolesForManifold(Manifold, circuitJson, pcbThickness, manifoldInstancesForCleanup) {
28942
28957
  const platedHoleBoardDrills = [];
28943
28958
  const pcbPlatedHoles = su8(circuitJson).pcb_plated_hole.list();
28944
28959
  const platedHoleCopperGeoms = [];
28960
+ const createPillOp = (width10, height10, depth) => {
28961
+ const pillOp = createRoundedRectPrism({
28962
+ Manifold,
28963
+ width: width10,
28964
+ height: height10,
28965
+ thickness: depth,
28966
+ borderRadius: Math.min(width10, height10) / 2
28967
+ });
28968
+ manifoldInstancesForCleanup.push(pillOp);
28969
+ return pillOp;
28970
+ };
28945
28971
  pcbPlatedHoles.forEach((ph, index) => {
28946
28972
  if (ph.shape === "circle") {
28947
28973
  const translatedDrill = createPlatedHoleDrill({
@@ -28987,60 +29013,15 @@ function processPlatedHolesForManifold(Manifold, circuitJson, pcbThickness, mani
28987
29013
  color: COPPER_COLOR
28988
29014
  });
28989
29015
  } else if (ph.shape === "pill") {
28990
- const holeWidthRaw = ph.hole_width;
28991
- const holeHeightRaw = ph.hole_height;
28992
- const shouldRotate = holeHeightRaw > holeWidthRaw;
28993
- const holeW = shouldRotate ? holeHeightRaw : holeWidthRaw;
28994
- const holeH = shouldRotate ? holeWidthRaw : holeHeightRaw;
29016
+ const holeW = ph.hole_width;
29017
+ const holeH = ph.hole_height;
28995
29018
  const defaultPadExtension = 0.4;
28996
- const outerW = shouldRotate ? ph.outer_height ?? holeH + defaultPadExtension / 2 : ph.outer_width ?? holeW + defaultPadExtension / 2;
28997
- const outerH = shouldRotate ? ph.outer_width ?? holeW + defaultPadExtension / 2 : ph.outer_height ?? holeH + defaultPadExtension / 2;
28998
- const createPill = (width10, height10, depth) => {
28999
- const radius = height10 / 2;
29000
- const rectLength = width10 - height10;
29001
- let pillOp;
29002
- if (rectLength < 1e-9) {
29003
- pillOp = Manifold.cylinder(
29004
- depth,
29005
- radius,
29006
- radius,
29007
- SMOOTH_CIRCLE_SEGMENTS,
29008
- true
29009
- );
29010
- } else {
29011
- const rect = Manifold.cube(
29012
- [Math.max(0, rectLength), height10, depth],
29013
- true
29014
- );
29015
- const cap1 = Manifold.cylinder(
29016
- depth,
29017
- radius,
29018
- radius,
29019
- SMOOTH_CIRCLE_SEGMENTS,
29020
- true
29021
- ).translate([-rectLength / 2, 0, 0]);
29022
- const cap2 = Manifold.cylinder(
29023
- depth,
29024
- radius,
29025
- radius,
29026
- SMOOTH_CIRCLE_SEGMENTS,
29027
- true
29028
- ).translate([rectLength / 2, 0, 0]);
29029
- pillOp = Manifold.union([rect, cap1, cap2]);
29030
- manifoldInstancesForCleanup.push(rect, cap1, cap2);
29031
- }
29032
- manifoldInstancesForCleanup.push(pillOp);
29033
- return pillOp;
29034
- };
29019
+ const outerW = ph.outer_width ?? holeW + defaultPadExtension;
29020
+ const outerH = ph.outer_height ?? holeH + defaultPadExtension;
29035
29021
  const drillW = holeW + 2 * MANIFOLD_Z_OFFSET;
29036
29022
  const drillH = holeH + 2 * MANIFOLD_Z_OFFSET;
29037
29023
  const drillDepth = pcbThickness * 1.2;
29038
- let boardPillDrillOp = createPill(drillW, drillH, drillDepth);
29039
- if (shouldRotate) {
29040
- const rotatedOp = boardPillDrillOp.rotate([0, 0, 90]);
29041
- manifoldInstancesForCleanup.push(rotatedOp);
29042
- boardPillDrillOp = rotatedOp;
29043
- }
29024
+ let boardPillDrillOp = createPillOp(drillW, drillH, drillDepth);
29044
29025
  if (ph.ccw_rotation) {
29045
29026
  const rotatedOp = boardPillDrillOp.rotate([0, 0, ph.ccw_rotation]);
29046
29027
  manifoldInstancesForCleanup.push(rotatedOp);
@@ -29054,12 +29035,12 @@ function processPlatedHolesForManifold(Manifold, circuitJson, pcbThickness, mani
29054
29035
  manifoldInstancesForCleanup.push(translatedBoardPillDrill);
29055
29036
  platedHoleBoardDrills.push(translatedBoardPillDrill);
29056
29037
  const copperPartThickness = pcbThickness + 2 * MANIFOLD_Z_OFFSET;
29057
- const outerCopperOpUnrotated = createPill(
29038
+ const outerCopperOpUnrotated = createPillOp(
29058
29039
  outerW,
29059
29040
  outerH,
29060
29041
  copperPartThickness
29061
29042
  );
29062
- const innerDrillOpUnrotated = createPill(
29043
+ const innerDrillOpUnrotated = createPillOp(
29063
29044
  holeW,
29064
29045
  holeH,
29065
29046
  copperPartThickness * 1.05
@@ -29069,11 +29050,6 @@ function processPlatedHolesForManifold(Manifold, circuitJson, pcbThickness, mani
29069
29050
  innerDrillOpUnrotated
29070
29051
  );
29071
29052
  manifoldInstancesForCleanup.push(finalPlatedPartOp);
29072
- if (shouldRotate) {
29073
- const rotatedOp = finalPlatedPartOp.rotate([0, 0, 90]);
29074
- manifoldInstancesForCleanup.push(rotatedOp);
29075
- finalPlatedPartOp = rotatedOp;
29076
- }
29077
29053
  if (ph.ccw_rotation) {
29078
29054
  const rotatedOp = finalPlatedPartOp.rotate([0, 0, ph.ccw_rotation]);
29079
29055
  manifoldInstancesForCleanup.push(rotatedOp);
@@ -29089,6 +29065,73 @@ function processPlatedHolesForManifold(Manifold, circuitJson, pcbThickness, mani
29089
29065
  geometry: threeGeom,
29090
29066
  color: COPPER_COLOR
29091
29067
  });
29068
+ } else if (ph.shape === "pill_hole_with_rect_pad") {
29069
+ const holeW = ph.hole_width;
29070
+ const holeH = ph.hole_height;
29071
+ const padWidth = ph.rect_pad_width;
29072
+ const padHeight = ph.rect_pad_height;
29073
+ const rectBorderRadius = extractRectBorderRadius(ph);
29074
+ const padThickness = DEFAULT_SMT_PAD_THICKNESS;
29075
+ const drillW = holeW + 2 * MANIFOLD_Z_OFFSET;
29076
+ const drillH = holeH + 2 * MANIFOLD_Z_OFFSET;
29077
+ const drillDepth = pcbThickness * 1.2;
29078
+ let boardPillDrillOp = createPillOp(drillW, drillH, drillDepth);
29079
+ const translatedBoardPillDrill = boardPillDrillOp.translate([
29080
+ ph.x,
29081
+ ph.y,
29082
+ 0
29083
+ ]);
29084
+ manifoldInstancesForCleanup.push(translatedBoardPillDrill);
29085
+ platedHoleBoardDrills.push(translatedBoardPillDrill);
29086
+ let copperBarrelOp = createPillOp(
29087
+ holeW,
29088
+ holeH,
29089
+ pcbThickness + 2 * MANIFOLD_Z_OFFSET
29090
+ );
29091
+ let topPadOp = createRoundedRectPrism({
29092
+ Manifold,
29093
+ width: padWidth,
29094
+ height: padHeight,
29095
+ thickness: padThickness,
29096
+ borderRadius: rectBorderRadius
29097
+ });
29098
+ manifoldInstancesForCleanup.push(topPadOp);
29099
+ let bottomPadOp = createRoundedRectPrism({
29100
+ Manifold,
29101
+ width: padWidth,
29102
+ height: padHeight,
29103
+ thickness: padThickness,
29104
+ borderRadius: rectBorderRadius
29105
+ });
29106
+ manifoldInstancesForCleanup.push(bottomPadOp);
29107
+ const topPadZ = pcbThickness / 2 + padThickness / 2 + MANIFOLD_Z_OFFSET;
29108
+ const bottomPadZ = -pcbThickness / 2 - padThickness / 2 - MANIFOLD_Z_OFFSET;
29109
+ topPadOp = topPadOp.translate([0, 0, topPadZ]);
29110
+ manifoldInstancesForCleanup.push(topPadOp);
29111
+ bottomPadOp = bottomPadOp.translate([0, 0, bottomPadZ]);
29112
+ manifoldInstancesForCleanup.push(bottomPadOp);
29113
+ const copperUnionBeforeCut = Manifold.union([
29114
+ copperBarrelOp,
29115
+ topPadOp,
29116
+ bottomPadOp
29117
+ ]);
29118
+ manifoldInstancesForCleanup.push(copperUnionBeforeCut);
29119
+ const holeCutWidth = Math.max(holeW - 2 * PLATED_HOLE_LIP_HEIGHT, 0.01);
29120
+ const holeCutHeight = Math.max(holeH - 2 * PLATED_HOLE_LIP_HEIGHT, 0.01);
29121
+ const holeCutDepth = pcbThickness + 2 * padThickness + 4 * MANIFOLD_Z_OFFSET;
29122
+ let holeCutOp = createPillOp(holeCutWidth, holeCutHeight, holeCutDepth);
29123
+ const finalPlatedPartOp = copperUnionBeforeCut.subtract(holeCutOp);
29124
+ manifoldInstancesForCleanup.push(finalPlatedPartOp);
29125
+ const translatedPlatedPart = finalPlatedPartOp.translate([ph.x, ph.y, 0]);
29126
+ manifoldInstancesForCleanup.push(translatedPlatedPart);
29127
+ const threeGeom = manifoldMeshToThreeGeometry(
29128
+ translatedPlatedPart.getMesh()
29129
+ );
29130
+ platedHoleCopperGeoms.push({
29131
+ key: `ph-${ph.pcb_plated_hole_id || index}`,
29132
+ geometry: threeGeom,
29133
+ color: COPPER_COLOR
29134
+ });
29092
29135
  } else if (ph.shape === "circular_hole_with_rect_pad") {
29093
29136
  const translatedDrill = createCircleHoleDrill({
29094
29137
  Manifold,
@@ -29708,7 +29751,8 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
29708
29751
  matColorArray[0],
29709
29752
  matColorArray[1],
29710
29753
  matColorArray[2]
29711
- )
29754
+ ),
29755
+ material: boardData.material
29712
29756
  };
29713
29757
  }
29714
29758
  const { smtPadGeoms } = processSmtPadsForManifold(
@@ -29787,17 +29831,53 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
29787
29831
  };
29788
29832
 
29789
29833
  // src/utils/manifold/create-three-geometry-meshes.ts
29834
+ import * as THREE25 from "three";
29835
+
29836
+ // src/utils/create-board-material.ts
29790
29837
  import * as THREE24 from "three";
29838
+ var DEFAULT_SIDE = THREE24.DoubleSide;
29839
+ var createBoardMaterial = ({
29840
+ material,
29841
+ color,
29842
+ side = DEFAULT_SIDE
29843
+ }) => {
29844
+ if (material === "fr4") {
29845
+ return new THREE24.MeshPhysicalMaterial({
29846
+ color,
29847
+ side,
29848
+ metalness: 0,
29849
+ roughness: 0.8,
29850
+ specularIntensity: 0.2,
29851
+ ior: 1.45,
29852
+ sheen: 0,
29853
+ clearcoat: 0,
29854
+ transparent: false,
29855
+ opacity: 1,
29856
+ flatShading: true
29857
+ });
29858
+ }
29859
+ return new THREE24.MeshStandardMaterial({
29860
+ color,
29861
+ side,
29862
+ flatShading: true,
29863
+ metalness: 0.1,
29864
+ roughness: 0.8,
29865
+ transparent: true,
29866
+ opacity: 0.9
29867
+ });
29868
+ };
29869
+
29870
+ // src/utils/manifold/create-three-geometry-meshes.ts
29791
29871
  function createGeometryMeshes(geoms) {
29792
29872
  const meshes = [];
29793
29873
  if (!geoms) return meshes;
29794
29874
  if (geoms.board && geoms.board.geometry) {
29795
- const mesh = new THREE24.Mesh(
29875
+ const mesh = new THREE25.Mesh(
29796
29876
  geoms.board.geometry,
29797
- new THREE24.MeshStandardMaterial({
29877
+ createBoardMaterial({
29878
+ material: geoms.board.material,
29798
29879
  color: geoms.board.color,
29799
- side: THREE24.DoubleSide,
29800
- flatShading: true
29880
+ side: THREE25.DoubleSide
29801
29881
  })
29802
29882
  );
29803
29883
  mesh.name = "board-geom";
@@ -29806,11 +29886,11 @@ function createGeometryMeshes(geoms) {
29806
29886
  const createMeshesFromArray = (geomArray) => {
29807
29887
  if (geomArray) {
29808
29888
  geomArray.forEach((comp) => {
29809
- const mesh = new THREE24.Mesh(
29889
+ const mesh = new THREE25.Mesh(
29810
29890
  comp.geometry,
29811
- new THREE24.MeshStandardMaterial({
29891
+ new THREE25.MeshStandardMaterial({
29812
29892
  color: comp.color,
29813
- side: THREE24.DoubleSide,
29893
+ side: THREE25.DoubleSide,
29814
29894
  flatShading: true
29815
29895
  // Consistent with board
29816
29896
  })
@@ -29828,21 +29908,21 @@ function createGeometryMeshes(geoms) {
29828
29908
  }
29829
29909
 
29830
29910
  // src/utils/manifold/create-three-texture-meshes.ts
29831
- import * as THREE25 from "three";
29911
+ import * as THREE26 from "three";
29832
29912
  function createTextureMeshes(textures, boardData, pcbThickness) {
29833
29913
  const meshes = [];
29834
29914
  if (!textures || !boardData || pcbThickness === null) return meshes;
29835
29915
  const createTexturePlane = (texture, yOffset, isBottomLayer, keySuffix) => {
29836
29916
  if (!texture) return null;
29837
- const planeGeom = new THREE25.PlaneGeometry(boardData.width, boardData.height);
29838
- const material = new THREE25.MeshBasicMaterial({
29917
+ const planeGeom = new THREE26.PlaneGeometry(boardData.width, boardData.height);
29918
+ const material = new THREE26.MeshBasicMaterial({
29839
29919
  map: texture,
29840
29920
  transparent: true,
29841
- side: THREE25.DoubleSide,
29921
+ side: THREE26.DoubleSide,
29842
29922
  depthWrite: false
29843
29923
  // Important for layers to avoid z-fighting issues with board itself
29844
29924
  });
29845
- const mesh = new THREE25.Mesh(planeGeom, material);
29925
+ const mesh = new THREE26.Mesh(planeGeom, material);
29846
29926
  mesh.position.set(boardData.center.x, boardData.center.y, yOffset);
29847
29927
  if (isBottomLayer) {
29848
29928
  mesh.rotation.set(Math.PI, 0, 0);
@@ -30498,11 +30578,11 @@ var CadViewer = (props) => {
30498
30578
  // src/convert-circuit-json-to-3d-svg.ts
30499
30579
  var import_debug = __toESM(require_browser(), 1);
30500
30580
  import { su as su14 } from "@tscircuit/circuit-json-util";
30501
- import * as THREE29 from "three";
30581
+ import * as THREE30 from "three";
30502
30582
  import { SVGRenderer } from "three/examples/jsm/renderers/SVGRenderer.js";
30503
30583
 
30504
30584
  // src/utils/create-geometry-from-polygons.ts
30505
- import * as THREE26 from "three";
30585
+ import * as THREE27 from "three";
30506
30586
  import { BufferGeometry as BufferGeometry3, Float32BufferAttribute as Float32BufferAttribute2 } from "three";
30507
30587
  function createGeometryFromPolygons(polygons) {
30508
30588
  const geometry = new BufferGeometry3();
@@ -30516,12 +30596,12 @@ function createGeometryFromPolygons(polygons) {
30516
30596
  ...polygon3.vertices[i + 1]
30517
30597
  // Third vertex
30518
30598
  );
30519
- const v1 = new THREE26.Vector3(...polygon3.vertices[0]);
30520
- const v2 = new THREE26.Vector3(...polygon3.vertices[i]);
30521
- const v3 = new THREE26.Vector3(...polygon3.vertices[i + 1]);
30522
- const normal = new THREE26.Vector3().crossVectors(
30523
- new THREE26.Vector3().subVectors(v2, v1),
30524
- new THREE26.Vector3().subVectors(v3, v1)
30599
+ const v1 = new THREE27.Vector3(...polygon3.vertices[0]);
30600
+ const v2 = new THREE27.Vector3(...polygon3.vertices[i]);
30601
+ const v3 = new THREE27.Vector3(...polygon3.vertices[i + 1]);
30602
+ const normal = new THREE27.Vector3().crossVectors(
30603
+ new THREE27.Vector3().subVectors(v2, v1),
30604
+ new THREE27.Vector3().subVectors(v3, v1)
30525
30605
  ).normalize();
30526
30606
  normals.push(
30527
30607
  normal.x,
@@ -30544,10 +30624,10 @@ function createGeometryFromPolygons(polygons) {
30544
30624
  // src/utils/render-component.tsx
30545
30625
  var import_modeling3 = __toESM(require_src(), 1);
30546
30626
  var import_jscad_planner2 = __toESM(require_dist(), 1);
30547
- import * as THREE28 from "three";
30627
+ import * as THREE29 from "three";
30548
30628
 
30549
30629
  // src/utils/load-model.ts
30550
- import * as THREE27 from "three";
30630
+ import * as THREE28 from "three";
30551
30631
  import { GLTFLoader as GLTFLoader2 } from "three/examples/jsm/loaders/GLTFLoader.js";
30552
30632
  import { OBJLoader as OBJLoader2 } from "three/examples/jsm/loaders/OBJLoader.js";
30553
30633
  import { STLLoader as STLLoader2 } from "three/examples/jsm/loaders/STLLoader.js";
@@ -30555,12 +30635,12 @@ async function load3DModel(url) {
30555
30635
  if (url.endsWith(".stl")) {
30556
30636
  const loader = new STLLoader2();
30557
30637
  const geometry = await loader.loadAsync(url);
30558
- const material = new THREE27.MeshStandardMaterial({
30638
+ const material = new THREE28.MeshStandardMaterial({
30559
30639
  color: 8947848,
30560
30640
  metalness: 0.5,
30561
30641
  roughness: 0.5
30562
30642
  });
30563
- return new THREE27.Mesh(geometry, material);
30643
+ return new THREE28.Mesh(geometry, material);
30564
30644
  }
30565
30645
  if (url.endsWith(".obj")) {
30566
30646
  const loader = new OBJLoader2();
@@ -30593,9 +30673,9 @@ async function renderComponent(component, scene) {
30593
30673
  }
30594
30674
  if (component.rotation) {
30595
30675
  model.rotation.set(
30596
- THREE28.MathUtils.degToRad(component.rotation.x ?? 0),
30597
- THREE28.MathUtils.degToRad(component.rotation.y ?? 0),
30598
- THREE28.MathUtils.degToRad(component.rotation.z ?? 0)
30676
+ THREE29.MathUtils.degToRad(component.rotation.x ?? 0),
30677
+ THREE29.MathUtils.degToRad(component.rotation.y ?? 0),
30678
+ THREE29.MathUtils.degToRad(component.rotation.z ?? 0)
30599
30679
  );
30600
30680
  }
30601
30681
  scene.add(model);
@@ -30609,13 +30689,13 @@ async function renderComponent(component, scene) {
30609
30689
  );
30610
30690
  if (jscadObject && (jscadObject.polygons || jscadObject.sides)) {
30611
30691
  const threeGeom = convertCSGToThreeGeom(jscadObject);
30612
- const material2 = new THREE28.MeshStandardMaterial({
30692
+ const material2 = new THREE29.MeshStandardMaterial({
30613
30693
  color: 8947848,
30614
30694
  metalness: 0.5,
30615
30695
  roughness: 0.5,
30616
- side: THREE28.DoubleSide
30696
+ side: THREE29.DoubleSide
30617
30697
  });
30618
- const mesh2 = new THREE28.Mesh(threeGeom, material2);
30698
+ const mesh2 = new THREE29.Mesh(threeGeom, material2);
30619
30699
  if (component.position) {
30620
30700
  mesh2.position.set(
30621
30701
  component.position.x ?? 0,
@@ -30625,9 +30705,9 @@ async function renderComponent(component, scene) {
30625
30705
  }
30626
30706
  if (component.rotation) {
30627
30707
  mesh2.rotation.set(
30628
- THREE28.MathUtils.degToRad(component.rotation.x ?? 0),
30629
- THREE28.MathUtils.degToRad(component.rotation.y ?? 0),
30630
- THREE28.MathUtils.degToRad(component.rotation.z ?? 0)
30708
+ THREE29.MathUtils.degToRad(component.rotation.x ?? 0),
30709
+ THREE29.MathUtils.degToRad(component.rotation.y ?? 0),
30710
+ THREE29.MathUtils.degToRad(component.rotation.z ?? 0)
30631
30711
  );
30632
30712
  }
30633
30713
  scene.add(mesh2);
@@ -30643,17 +30723,17 @@ async function renderComponent(component, scene) {
30643
30723
  if (!geom || !geom.polygons && !geom.sides) {
30644
30724
  continue;
30645
30725
  }
30646
- const color = new THREE28.Color(geomInfo.color);
30726
+ const color = new THREE29.Color(geomInfo.color);
30647
30727
  color.convertLinearToSRGB();
30648
30728
  const geomWithColor = { ...geom, color: [color.r, color.g, color.b] };
30649
30729
  const threeGeom = convertCSGToThreeGeom(geomWithColor);
30650
- const material2 = new THREE28.MeshStandardMaterial({
30730
+ const material2 = new THREE29.MeshStandardMaterial({
30651
30731
  vertexColors: true,
30652
30732
  metalness: 0.2,
30653
30733
  roughness: 0.8,
30654
- side: THREE28.DoubleSide
30734
+ side: THREE29.DoubleSide
30655
30735
  });
30656
- const mesh2 = new THREE28.Mesh(threeGeom, material2);
30736
+ const mesh2 = new THREE29.Mesh(threeGeom, material2);
30657
30737
  if (component.position) {
30658
30738
  mesh2.position.set(
30659
30739
  component.position.x ?? 0,
@@ -30663,22 +30743,22 @@ async function renderComponent(component, scene) {
30663
30743
  }
30664
30744
  if (component.rotation) {
30665
30745
  mesh2.rotation.set(
30666
- THREE28.MathUtils.degToRad(component.rotation.x ?? 0),
30667
- THREE28.MathUtils.degToRad(component.rotation.y ?? 0),
30668
- THREE28.MathUtils.degToRad(component.rotation.z ?? 0)
30746
+ THREE29.MathUtils.degToRad(component.rotation.x ?? 0),
30747
+ THREE29.MathUtils.degToRad(component.rotation.y ?? 0),
30748
+ THREE29.MathUtils.degToRad(component.rotation.z ?? 0)
30669
30749
  );
30670
30750
  }
30671
30751
  scene.add(mesh2);
30672
30752
  }
30673
30753
  return;
30674
30754
  }
30675
- const geometry = new THREE28.BoxGeometry(0.5, 0.5, 0.5);
30676
- const material = new THREE28.MeshStandardMaterial({
30755
+ const geometry = new THREE29.BoxGeometry(0.5, 0.5, 0.5);
30756
+ const material = new THREE29.MeshStandardMaterial({
30677
30757
  color: 16711680,
30678
30758
  transparent: true,
30679
30759
  opacity: 0.25
30680
30760
  });
30681
- const mesh = new THREE28.Mesh(geometry, material);
30761
+ const mesh = new THREE29.Mesh(geometry, material);
30682
30762
  if (component.position) {
30683
30763
  mesh.position.set(
30684
30764
  component.position.x ?? 0,
@@ -30699,11 +30779,11 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
30699
30779
  padding = 20,
30700
30780
  zoom = 1.5
30701
30781
  } = options;
30702
- const scene = new THREE29.Scene();
30782
+ const scene = new THREE30.Scene();
30703
30783
  const renderer = new SVGRenderer();
30704
30784
  renderer.setSize(width10, height10);
30705
- renderer.setClearColor(new THREE29.Color(backgroundColor), 1);
30706
- const camera = new THREE29.OrthographicCamera();
30785
+ renderer.setClearColor(new THREE30.Color(backgroundColor), 1);
30786
+ const camera = new THREE30.OrthographicCamera();
30707
30787
  const aspect = width10 / height10;
30708
30788
  const frustumSize = 100;
30709
30789
  const halfFrustumSize = frustumSize / 2 / zoom;
@@ -30717,45 +30797,44 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
30717
30797
  camera.position.set(position.x, position.y, position.z);
30718
30798
  camera.up.set(0, 1, 0);
30719
30799
  const lookAt = options.camera?.lookAt ?? { x: 0, y: 0, z: 0 };
30720
- camera.lookAt(new THREE29.Vector3(lookAt.x, lookAt.y, lookAt.z));
30800
+ camera.lookAt(new THREE30.Vector3(lookAt.x, lookAt.y, lookAt.z));
30721
30801
  camera.updateProjectionMatrix();
30722
- const ambientLight = new THREE29.AmbientLight(16777215, Math.PI / 2);
30802
+ const ambientLight = new THREE30.AmbientLight(16777215, Math.PI / 2);
30723
30803
  scene.add(ambientLight);
30724
- const pointLight = new THREE29.PointLight(16777215, Math.PI / 4);
30804
+ const pointLight = new THREE30.PointLight(16777215, Math.PI / 4);
30725
30805
  pointLight.position.set(-10, -10, 10);
30726
30806
  scene.add(pointLight);
30727
30807
  const components = su14(circuitJson).cad_component.list();
30728
30808
  for (const component of components) {
30729
30809
  await renderComponent(component, scene);
30730
30810
  }
30811
+ const boardData = su14(circuitJson).pcb_board.list()[0];
30731
30812
  const boardGeom = createBoardGeomFromCircuitJson(circuitJson);
30732
30813
  if (boardGeom) {
30733
30814
  for (const geom of boardGeom) {
30734
30815
  const g = geom;
30735
30816
  if (!g.polygons || g.polygons.length === 0) continue;
30736
30817
  const geometry = createGeometryFromPolygons(g.polygons);
30737
- const material = new THREE29.MeshStandardMaterial({
30738
- color: new THREE29.Color(
30739
- g.color?.[0] ?? 0,
30740
- g.color?.[1] ?? 0,
30741
- g.color?.[2] ?? 0
30742
- ),
30743
- metalness: 0.1,
30744
- roughness: 0.8,
30745
- opacity: 0.9,
30746
- transparent: true,
30747
- side: THREE29.DoubleSide
30818
+ const baseColor = new THREE30.Color(
30819
+ g.color?.[0] ?? 0,
30820
+ g.color?.[1] ?? 0,
30821
+ g.color?.[2] ?? 0
30822
+ );
30823
+ const material = createBoardMaterial({
30824
+ material: boardData?.material,
30825
+ color: baseColor,
30826
+ side: THREE30.DoubleSide
30748
30827
  });
30749
- const mesh = new THREE29.Mesh(geometry, material);
30828
+ const mesh = new THREE30.Mesh(geometry, material);
30750
30829
  scene.add(mesh);
30751
30830
  }
30752
30831
  }
30753
- const gridHelper = new THREE29.GridHelper(100, 100);
30832
+ const gridHelper = new THREE30.GridHelper(100, 100);
30754
30833
  gridHelper.rotation.x = Math.PI / 2;
30755
30834
  scene.add(gridHelper);
30756
- const box = new THREE29.Box3().setFromObject(scene);
30757
- const center = box.getCenter(new THREE29.Vector3());
30758
- const size2 = box.getSize(new THREE29.Vector3());
30835
+ const box = new THREE30.Box3().setFromObject(scene);
30836
+ const center = box.getCenter(new THREE30.Vector3());
30837
+ const size2 = box.getSize(new THREE30.Vector3());
30759
30838
  scene.position.sub(center);
30760
30839
  const maxDim = Math.max(size2.x, size2.y, size2.z);
30761
30840
  if (maxDim > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/3d-viewer",
3
- "version": "0.0.406",
3
+ "version": "0.0.408",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.js",
6
6
  "type": "module",