@tscircuit/3d-viewer 0.0.476 → 0.0.478

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.d.ts +19 -21
  2. package/dist/index.js +694 -553
  3. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -805,13 +805,13 @@ var require_cross = __commonJS({
805
805
  var require_distance = __commonJS({
806
806
  "node_modules/@jscad/modeling/src/maths/vec3/distance.js"(exports, module) {
807
807
  "use strict";
808
- var distance2 = (a, b) => {
808
+ var distance3 = (a, b) => {
809
809
  const x = b[0] - a[0];
810
810
  const y = b[1] - a[1];
811
811
  const z138 = b[2] - a[2];
812
812
  return Math.sqrt(x * x + y * y + z138 * z138);
813
813
  };
814
- module.exports = distance2;
814
+ module.exports = distance3;
815
815
  }
816
816
  });
817
817
 
@@ -1933,12 +1933,12 @@ var require_cross2 = __commonJS({
1933
1933
  var require_distance2 = __commonJS({
1934
1934
  "node_modules/@jscad/modeling/src/maths/vec2/distance.js"(exports, module) {
1935
1935
  "use strict";
1936
- var distance2 = (a, b) => {
1936
+ var distance3 = (a, b) => {
1937
1937
  const x = b[0] - a[0];
1938
1938
  const y = b[1] - a[1];
1939
1939
  return Math.sqrt(x * x + y * y);
1940
1940
  };
1941
- module.exports = distance2;
1941
+ module.exports = distance3;
1942
1942
  }
1943
1943
  });
1944
1944
 
@@ -2861,7 +2861,7 @@ var require_Vertex = __commonJS({
2861
2861
  var require_HalfEdge = __commonJS({
2862
2862
  "node_modules/@jscad/modeling/src/operations/hulls/quickhull/HalfEdge.js"(exports, module) {
2863
2863
  "use strict";
2864
- var distance2 = require_distance();
2864
+ var distance3 = require_distance();
2865
2865
  var squaredDistance = require_squaredDistance();
2866
2866
  var HalfEdge = class {
2867
2867
  constructor(vertex, face) {
@@ -2879,7 +2879,7 @@ var require_HalfEdge = __commonJS({
2879
2879
  }
2880
2880
  length() {
2881
2881
  if (this.tail()) {
2882
- return distance2(
2882
+ return distance3(
2883
2883
  this.tail().point,
2884
2884
  this.head().point
2885
2885
  );
@@ -3216,8 +3216,8 @@ var require_QuickHull = __commonJS({
3216
3216
  let nextVertex;
3217
3217
  for (let vertex = faceVertices; vertex; vertex = nextVertex) {
3218
3218
  nextVertex = vertex.next;
3219
- const distance2 = absorbingFace.distanceToPlane(vertex.point);
3220
- if (distance2 > this.tolerance) {
3219
+ const distance3 = absorbingFace.distanceToPlane(vertex.point);
3220
+ if (distance3 > this.tolerance) {
3221
3221
  this.addVertexToFace(vertex, absorbingFace);
3222
3222
  } else {
3223
3223
  this.unclaimed.add(vertex);
@@ -3304,9 +3304,9 @@ var require_QuickHull = __commonJS({
3304
3304
  let maxDistance = 0;
3305
3305
  let indexMax = 0;
3306
3306
  for (i = 0; i < 3; i += 1) {
3307
- const distance2 = max2[i].point[i] - min2[i].point[i];
3308
- if (distance2 > maxDistance) {
3309
- maxDistance = distance2;
3307
+ const distance3 = max2[i].point[i] - min2[i].point[i];
3308
+ if (distance3 > maxDistance) {
3309
+ maxDistance = distance3;
3310
3310
  indexMax = i;
3311
3311
  }
3312
3312
  }
@@ -3316,13 +3316,13 @@ var require_QuickHull = __commonJS({
3316
3316
  for (i = 0; i < this.vertices.length; i += 1) {
3317
3317
  const vertex = this.vertices[i];
3318
3318
  if (vertex !== v0 && vertex !== v1) {
3319
- const distance2 = pointLineDistance(
3319
+ const distance3 = pointLineDistance(
3320
3320
  vertex.point,
3321
3321
  v0.point,
3322
3322
  v1.point
3323
3323
  );
3324
- if (distance2 > maxDistance) {
3325
- maxDistance = distance2;
3324
+ if (distance3 > maxDistance) {
3325
+ maxDistance = distance3;
3326
3326
  v2 = vertex;
3327
3327
  }
3328
3328
  }
@@ -3333,9 +3333,9 @@ var require_QuickHull = __commonJS({
3333
3333
  for (i = 0; i < this.vertices.length; i += 1) {
3334
3334
  const vertex = this.vertices[i];
3335
3335
  if (vertex !== v0 && vertex !== v1 && vertex !== v2) {
3336
- const distance2 = Math.abs(dot(normal, vertex.point) - distPO);
3337
- if (distance2 > maxDistance) {
3338
- maxDistance = distance2;
3336
+ const distance3 = Math.abs(dot(normal, vertex.point) - distPO);
3337
+ if (distance3 > maxDistance) {
3338
+ maxDistance = distance3;
3339
3339
  v3 = vertex;
3340
3340
  }
3341
3341
  }
@@ -3375,9 +3375,9 @@ var require_QuickHull = __commonJS({
3375
3375
  maxDistance = this.tolerance;
3376
3376
  let maxFace;
3377
3377
  for (j = 0; j < 4; j += 1) {
3378
- const distance2 = faces[j].distanceToPlane(vertex.point);
3379
- if (distance2 > maxDistance) {
3380
- maxDistance = distance2;
3378
+ const distance3 = faces[j].distanceToPlane(vertex.point);
3379
+ if (distance3 > maxDistance) {
3380
+ maxDistance = distance3;
3381
3381
  maxFace = faces[j];
3382
3382
  }
3383
3383
  }
@@ -3433,9 +3433,9 @@ var require_QuickHull = __commonJS({
3433
3433
  let maxDistance = 0;
3434
3434
  const eyeFace = this.claimed.first().face;
3435
3435
  for (vertex = eyeFace.outside; vertex && vertex.face === eyeFace; vertex = vertex.next) {
3436
- const distance2 = eyeFace.distanceToPlane(vertex.point);
3437
- if (distance2 > maxDistance) {
3438
- maxDistance = distance2;
3436
+ const distance3 = eyeFace.distanceToPlane(vertex.point);
3437
+ if (distance3 > maxDistance) {
3438
+ maxDistance = distance3;
3439
3439
  eyeVertex = vertex;
3440
3440
  }
3441
3441
  }
@@ -6069,13 +6069,13 @@ var require_arcLengthToT = __commonJS({
6069
6069
  distance: 0,
6070
6070
  segments: 100
6071
6071
  };
6072
- const { distance: distance2, segments } = Object.assign({}, defaults, options);
6072
+ const { distance: distance3, segments } = Object.assign({}, defaults, options);
6073
6073
  const arcLengths = lengths(segments, bezier);
6074
6074
  let startIndex = 0;
6075
6075
  let endIndex = segments;
6076
6076
  while (startIndex <= endIndex) {
6077
6077
  const middleIndex = Math.floor(startIndex + (endIndex - startIndex) / 2);
6078
- const diff = arcLengths[middleIndex] - distance2;
6078
+ const diff = arcLengths[middleIndex] - distance3;
6079
6079
  if (diff < 0) {
6080
6080
  startIndex = middleIndex + 1;
6081
6081
  } else if (diff > 0) {
@@ -6086,13 +6086,13 @@ var require_arcLengthToT = __commonJS({
6086
6086
  }
6087
6087
  }
6088
6088
  const targetIndex = endIndex;
6089
- if (arcLengths[targetIndex] === distance2) {
6089
+ if (arcLengths[targetIndex] === distance3) {
6090
6090
  return targetIndex / segments;
6091
6091
  }
6092
6092
  const lengthBefore = arcLengths[targetIndex];
6093
6093
  const lengthAfter = arcLengths[targetIndex + 1];
6094
6094
  const segmentLength = lengthAfter - lengthBefore;
6095
- const segmentFraction = (distance2 - lengthBefore) / segmentLength;
6095
+ const segmentFraction = (distance3 - lengthBefore) / segmentLength;
6096
6096
  return (targetIndex + segmentFraction) / segments;
6097
6097
  };
6098
6098
  module.exports = arcLengthToT;
@@ -6342,9 +6342,9 @@ var require_distanceToPoint = __commonJS({
6342
6342
  "use strict";
6343
6343
  var vec2 = require_vec2();
6344
6344
  var distanceToPoint = (line2, point2) => {
6345
- let distance2 = vec2.dot(point2, line2);
6346
- distance2 = Math.abs(distance2 - line2[2]);
6347
- return distance2;
6345
+ let distance3 = vec2.dot(point2, line2);
6346
+ distance3 = Math.abs(distance3 - line2[2]);
6347
+ return distance3;
6348
6348
  };
6349
6349
  module.exports = distanceToPoint;
6350
6350
  }
@@ -6368,10 +6368,10 @@ var require_fromPoints6 = __commonJS({
6368
6368
  const vector = vec2.subtract(vec2.create(), point2, point1);
6369
6369
  vec2.normal(vector, vector);
6370
6370
  vec2.normalize(vector, vector);
6371
- const distance2 = vec2.dot(point1, vector);
6371
+ const distance3 = vec2.dot(point1, vector);
6372
6372
  out[0] = vector[0];
6373
6373
  out[1] = vector[1];
6374
- out[2] = distance2;
6374
+ out[2] = distance3;
6375
6375
  return out;
6376
6376
  };
6377
6377
  module.exports = fromPoints;
@@ -6513,8 +6513,8 @@ var require_reverse3 = __commonJS({
6513
6513
  var fromValues = require_fromValues5();
6514
6514
  var reverse = (out, line2) => {
6515
6515
  const normal = vec2.negate(vec2.create(), line2);
6516
- const distance2 = -line2[2];
6517
- return copy(out, fromValues(normal[0], normal[1], distance2));
6516
+ const distance3 = -line2[2];
6517
+ return copy(out, fromValues(normal[0], normal[1], distance3));
6518
6518
  };
6519
6519
  module.exports = reverse;
6520
6520
  }
@@ -7862,7 +7862,7 @@ var require_polyhedron = __commonJS({
7862
7862
  colors: void 0,
7863
7863
  orientation: "outward"
7864
7864
  };
7865
- const { points, faces, colors: colors2, orientation } = Object.assign({}, defaults, options);
7865
+ const { points, faces, colors: colors2, orientation: orientation2 } = Object.assign({}, defaults, options);
7866
7866
  if (!(Array.isArray(points) && Array.isArray(faces))) {
7867
7867
  throw new Error("points and faces must be arrays");
7868
7868
  }
@@ -7887,7 +7887,7 @@ var require_polyhedron = __commonJS({
7887
7887
  if (face.length < 3) throw new Error(`face ${i} must contain 3 or more indexes`);
7888
7888
  if (!isNumberArray(face, face.length)) throw new Error(`face ${i} must be an array of numbers`);
7889
7889
  });
7890
- if (orientation !== "outward") {
7890
+ if (orientation2 !== "outward") {
7891
7891
  faces.forEach((face) => face.reverse());
7892
7892
  }
7893
7893
  const polygons = faces.map((face, findex) => {
@@ -8052,7 +8052,7 @@ var require_polygon = __commonJS({
8052
8052
  paths: [],
8053
8053
  orientation: "counterclockwise"
8054
8054
  };
8055
- const { points, paths, orientation } = Object.assign({}, defaults, options);
8055
+ const { points, paths, orientation: orientation2 } = Object.assign({}, defaults, options);
8056
8056
  if (!(Array.isArray(points) && Array.isArray(paths))) throw new Error("points and paths must be arrays");
8057
8057
  let listofpolys = points;
8058
8058
  if (Array.isArray(points[0])) {
@@ -8082,7 +8082,7 @@ var require_polygon = __commonJS({
8082
8082
  sides2 = sides2.concat(geom2.toSides(geometry2));
8083
8083
  });
8084
8084
  let geometry = geom2.create(sides2);
8085
- if (orientation === "clockwise") {
8085
+ if (orientation2 === "clockwise") {
8086
8086
  geometry = geom2.reverse(geometry);
8087
8087
  }
8088
8088
  return geometry;
@@ -8597,16 +8597,16 @@ var require_calculatePlane = __commonJS({
8597
8597
  var calculatePlane = (slice) => {
8598
8598
  const edges = slice.edges;
8599
8599
  if (edges.length < 3) throw new Error("slices must have 3 or more edges to calculate a plane");
8600
- const midpoint = edges.reduce((point2, edge) => vec3.add(vec3.create(), point2, edge[0]), vec3.create());
8601
- vec3.scale(midpoint, midpoint, 1 / edges.length);
8600
+ const midpoint2 = edges.reduce((point2, edge) => vec3.add(vec3.create(), point2, edge[0]), vec3.create());
8601
+ vec3.scale(midpoint2, midpoint2, 1 / edges.length);
8602
8602
  let farthestEdge;
8603
- let distance2 = 0;
8603
+ let distance3 = 0;
8604
8604
  edges.forEach((edge) => {
8605
8605
  if (!vec3.equals(edge[0], edge[1])) {
8606
- const d = vec3.squaredDistance(midpoint, edge[0]);
8607
- if (d > distance2) {
8606
+ const d = vec3.squaredDistance(midpoint2, edge[0]);
8607
+ if (d > distance3) {
8608
8608
  farthestEdge = edge;
8609
- distance2 = d;
8609
+ distance3 = d;
8610
8610
  }
8611
8611
  }
8612
8612
  });
@@ -8969,13 +8969,13 @@ var require_linkedPolygon = __commonJS({
8969
8969
  const o3 = Math.sign(area(p2, q2, p1));
8970
8970
  const o4 = Math.sign(area(p2, q2, q1));
8971
8971
  if (o1 !== o2 && o3 !== o4) return true;
8972
- if (o1 === 0 && onSegment(p1, p2, q1)) return true;
8973
- if (o2 === 0 && onSegment(p1, q2, q1)) return true;
8974
- if (o3 === 0 && onSegment(p2, p1, q2)) return true;
8975
- if (o4 === 0 && onSegment(p2, q1, q2)) return true;
8972
+ if (o1 === 0 && onSegment2(p1, p2, q1)) return true;
8973
+ if (o2 === 0 && onSegment2(p1, q2, q1)) return true;
8974
+ if (o3 === 0 && onSegment2(p2, p1, q2)) return true;
8975
+ if (o4 === 0 && onSegment2(p2, q1, q2)) return true;
8976
8976
  return false;
8977
8977
  };
8978
- var onSegment = (p, q, r) => q.x <= Math.max(p.x, r.x) && q.x >= Math.min(p.x, r.x) && q.y <= Math.max(p.y, r.y) && q.y >= Math.min(p.y, r.y);
8978
+ var onSegment2 = (p, q, r) => q.x <= Math.max(p.x, r.x) && q.x >= Math.min(p.x, r.x) && q.y <= Math.max(p.y, r.y) && q.y >= Math.min(p.y, r.y);
8979
8979
  var signedArea = (data, start, end, dim) => {
8980
8980
  let sum = 0;
8981
8981
  for (let i = start, j = end - dim; i < end; i += dim) {
@@ -9454,9 +9454,9 @@ var require_repair = __commonJS({
9454
9454
  let bestReplacement;
9455
9455
  missingOut.forEach((key2) => {
9456
9456
  const v2 = vertexMap.get(key2);
9457
- const distance2 = vec3.distance(v1, v2);
9458
- if (distance2 < bestDistance) {
9459
- bestDistance = distance2;
9457
+ const distance3 = vec3.distance(v1, v2);
9458
+ if (distance3 < bestDistance) {
9459
+ bestDistance = distance3;
9460
9460
  bestReplacement = v2;
9461
9461
  }
9462
9462
  });
@@ -11802,7 +11802,7 @@ var require_offsetFromPoints = __commonJS({
11802
11802
  if (Math.abs(delta) < EPS) return points;
11803
11803
  let rotation2 = options.closed ? area(points) : 1;
11804
11804
  if (rotation2 === 0) rotation2 = 1;
11805
- const orientation = rotation2 > 0 && delta >= 0 || rotation2 < 0 && delta < 0;
11805
+ const orientation2 = rotation2 > 0 && delta >= 0 || rotation2 < 0 && delta < 0;
11806
11806
  delta = Math.abs(delta);
11807
11807
  let previousSegment = null;
11808
11808
  let newPoints = [];
@@ -11813,7 +11813,7 @@ var require_offsetFromPoints = __commonJS({
11813
11813
  const j = (i + 1) % n;
11814
11814
  const p0 = points[i];
11815
11815
  const p1 = points[j];
11816
- orientation ? vec2.subtract(of, p0, p1) : vec2.subtract(of, p1, p0);
11816
+ orientation2 ? vec2.subtract(of, p0, p1) : vec2.subtract(of, p1, p0);
11817
11817
  vec2.normal(of, of);
11818
11818
  vec2.normalize(of, of);
11819
11819
  vec2.scale(of, of, delta);
@@ -11877,11 +11877,11 @@ var require_offsetFromPoints = __commonJS({
11877
11877
  newCorners.forEach((corner) => {
11878
11878
  let rotation3 = vec2.angle(vec2.subtract(v0, corner.s1[0], corner.c));
11879
11879
  rotation3 -= vec2.angle(vec2.subtract(v0, corner.s0[1], corner.c));
11880
- if (orientation && rotation3 < 0) {
11880
+ if (orientation2 && rotation3 < 0) {
11881
11881
  rotation3 = rotation3 + Math.PI;
11882
11882
  if (rotation3 < 0) rotation3 = rotation3 + Math.PI;
11883
11883
  }
11884
- if (!orientation && rotation3 > 0) {
11884
+ if (!orientation2 && rotation3 > 0) {
11885
11885
  rotation3 = rotation3 - Math.PI;
11886
11886
  if (rotation3 > 0) rotation3 = rotation3 - Math.PI;
11887
11887
  }
@@ -12718,8 +12718,8 @@ var require_hullPoints2 = __commonJS({
12718
12718
  const points = [];
12719
12719
  uniquePoints.forEach((point2) => {
12720
12720
  const angle = fakeAtan2(point2[1] - min2[1], point2[0] - min2[0]);
12721
- const distSq = vec2.squaredDistance(point2, min2);
12722
- points.push({ point: point2, angle, distSq });
12721
+ const distSq2 = vec2.squaredDistance(point2, min2);
12722
+ points.push({ point: point2, angle, distSq: distSq2 });
12723
12723
  });
12724
12724
  points.sort((pt1, pt2) => pt1.angle !== pt2.angle ? pt1.angle - pt2.angle : pt1.distSq - pt2.distSq);
12725
12725
  const stack = [];
@@ -13361,11 +13361,11 @@ var require_triangulatePolygons = __commonJS({
13361
13361
  const nv = polygon3.vertices.length;
13362
13362
  if (nv > 3) {
13363
13363
  if (nv > 4) {
13364
- const midpoint = [0, 0, 0];
13365
- polygon3.vertices.forEach((vertice) => vec3.add(midpoint, midpoint, vertice));
13366
- vec3.snap(midpoint, vec3.divide(midpoint, midpoint, [nv, nv, nv]), epsilon);
13364
+ const midpoint2 = [0, 0, 0];
13365
+ polygon3.vertices.forEach((vertice) => vec3.add(midpoint2, midpoint2, vertice));
13366
+ vec3.snap(midpoint2, vec3.divide(midpoint2, midpoint2, [nv, nv, nv]), epsilon);
13367
13367
  for (let i = 0; i < nv; i++) {
13368
- const poly = poly3.create([midpoint, polygon3.vertices[i], polygon3.vertices[(i + 1) % nv]]);
13368
+ const poly = poly3.create([midpoint2, polygon3.vertices[i], polygon3.vertices[(i + 1) % nv]]);
13369
13369
  if (polygon3.color) poly.color = polygon3.color;
13370
13370
  triangles.push(poly);
13371
13371
  }
@@ -18225,12 +18225,12 @@ var bga_def = z510.object({
18225
18225
  });
18226
18226
  var bga = (raw_params) => {
18227
18227
  const parameters = bga_def.parse(raw_params);
18228
- let { num_pins, grid, p, w, h: h2, ball, pad: pad2, missing } = parameters;
18228
+ let { num_pins, grid: grid2, p, w, h: h2, ball, pad: pad2, missing } = parameters;
18229
18229
  ball ??= 0.75 / 1.27 * p;
18230
18230
  pad2 ??= ball * 0.8;
18231
18231
  const pads = [];
18232
18232
  const missing_pin_nums = (missing ?? []).filter((a) => typeof a === "number");
18233
- const num_pins_missing = grid.x * grid.y - num_pins;
18233
+ const num_pins_missing = grid2.x * grid2.y - num_pins;
18234
18234
  if (missing.length === 0 && num_pins_missing > 0) {
18235
18235
  if (Math.sqrt(num_pins_missing) % 1 === 0) {
18236
18236
  missing.push("center");
@@ -18240,11 +18240,11 @@ var bga = (raw_params) => {
18240
18240
  }
18241
18241
  if (missing?.includes("center")) {
18242
18242
  const square_size = Math.floor(Math.sqrt(num_pins_missing));
18243
- const inner_square_x = Math.floor((grid.x - square_size) / 2);
18244
- const inner_square_y = Math.floor((grid.y - square_size) / 2);
18243
+ const inner_square_x = Math.floor((grid2.x - square_size) / 2);
18244
+ const inner_square_y = Math.floor((grid2.y - square_size) / 2);
18245
18245
  for (let y = inner_square_y; y < inner_square_y + square_size; y++) {
18246
18246
  for (let x = inner_square_x; x < inner_square_x + square_size; x++) {
18247
- missing_pin_nums.push(y * grid.x + x + 1);
18247
+ missing_pin_nums.push(y * grid2.x + x + 1);
18248
18248
  }
18249
18249
  }
18250
18250
  }
@@ -18253,30 +18253,30 @@ var bga = (raw_params) => {
18253
18253
  }
18254
18254
  const missing_pin_nums_set = new Set(missing_pin_nums);
18255
18255
  let missing_pins_passed = 0;
18256
- for (let y = 0; y < grid.y; y++) {
18257
- for (let x = 0; x < grid.x; x++) {
18258
- const pad_x = (x - (grid.x - 1) / 2) * p;
18259
- const pad_y = (y - (grid.y - 1) / 2) * p;
18256
+ for (let y = 0; y < grid2.y; y++) {
18257
+ for (let x = 0; x < grid2.x; x++) {
18258
+ const pad_x = (x - (grid2.x - 1) / 2) * p;
18259
+ const pad_y = (y - (grid2.y - 1) / 2) * p;
18260
18260
  let pin_x = x;
18261
18261
  let pin_y = y;
18262
18262
  switch (parameters.origin) {
18263
18263
  case "bl":
18264
18264
  pin_x = x;
18265
- pin_y = grid.y - 1 - y;
18265
+ pin_y = grid2.y - 1 - y;
18266
18266
  break;
18267
18267
  case "br":
18268
- pin_x = grid.x - 1 - x;
18269
- pin_y = grid.y - 1 - y;
18268
+ pin_x = grid2.x - 1 - x;
18269
+ pin_y = grid2.y - 1 - y;
18270
18270
  break;
18271
18271
  case "tr":
18272
- pin_x = grid.x - 1 - x;
18272
+ pin_x = grid2.x - 1 - x;
18273
18273
  pin_y = y;
18274
18274
  break;
18275
18275
  case "tl":
18276
18276
  default:
18277
18277
  break;
18278
18278
  }
18279
- let pin_num = pin_y * grid.x + pin_x + 1;
18279
+ let pin_num = pin_y * grid2.x + pin_x + 1;
18280
18280
  if (missing_pin_nums_set.has(pin_num)) {
18281
18281
  missing_pins_passed++;
18282
18282
  continue;
@@ -18294,13 +18294,13 @@ var bga = (raw_params) => {
18294
18294
  }
18295
18295
  const silkscreenRefText = silkscreenRef(
18296
18296
  0,
18297
- grid.y * p / 2,
18297
+ grid2.y * p / 2,
18298
18298
  0.2
18299
18299
  );
18300
18300
  const pin1MarkerSize = p / 6;
18301
18301
  let markerRoute;
18302
- const edgeX = grid.x * p / 2;
18303
- const edgeY = grid.y * p / 2;
18302
+ const edgeX = grid2.x * p / 2;
18303
+ const edgeY = grid2.y * p / 2;
18304
18304
  switch (parameters.origin) {
18305
18305
  case "bl":
18306
18306
  markerRoute = [
@@ -18614,7 +18614,7 @@ var quad = (raw_params) => {
18614
18614
  const {
18615
18615
  x,
18616
18616
  y,
18617
- o: orientation
18617
+ o: orientation2
18618
18618
  } = getQuadCoords({
18619
18619
  pin_count: parameters.num_pins,
18620
18620
  pn: i + 1,
@@ -18626,7 +18626,7 @@ var quad = (raw_params) => {
18626
18626
  });
18627
18627
  let pw = parameters.pw;
18628
18628
  let pl = parameters.pl;
18629
- if (orientation === "vert") {
18629
+ if (orientation2 === "vert") {
18630
18630
  ;
18631
18631
  [pw, pl] = [pl, pw];
18632
18632
  }
@@ -25622,7 +25622,7 @@ var QFN = ({
25622
25622
  const {
25623
25623
  x,
25624
25624
  y,
25625
- o: orientation
25625
+ o: orientation2
25626
25626
  } = getQuadCoords2({
25627
25627
  pin_count: num_pins,
25628
25628
  pn: i + 1,
@@ -25634,7 +25634,7 @@ var QFN = ({
25634
25634
  });
25635
25635
  let pw = padWidth;
25636
25636
  let pl = padLength;
25637
- if (orientation === "vert") {
25637
+ if (orientation2 === "vert") {
25638
25638
  ;
25639
25639
  [pw, pl] = [pl, pw];
25640
25640
  }
@@ -29492,7 +29492,7 @@ import * as THREE15 from "three";
29492
29492
  // package.json
29493
29493
  var package_default = {
29494
29494
  name: "@tscircuit/3d-viewer",
29495
- version: "0.0.475",
29495
+ version: "0.0.477",
29496
29496
  main: "./dist/index.js",
29497
29497
  module: "./dist/index.js",
29498
29498
  type: "module",
@@ -29521,6 +29521,7 @@ var package_default = {
29521
29521
  dependencies: {
29522
29522
  "@jscad/regl-renderer": "^2.6.12",
29523
29523
  "@jscad/stl-serializer": "^2.1.20",
29524
+ "circuit-to-canvas": "^0.0.26",
29524
29525
  "react-hot-toast": "^2.6.0",
29525
29526
  three: "^0.165.0",
29526
29527
  "three-stdlib": "^2.36.0",
@@ -29652,12 +29653,12 @@ var CameraControllerProvider = ({ children, defaultTarget, initialCameraPosition
29652
29653
  );
29653
29654
  const baseDistance = useMemo8(() => {
29654
29655
  const [x, y, z138] = initialCameraPosition ?? [5, -5, 5];
29655
- const distance2 = Math.hypot(
29656
+ const distance3 = Math.hypot(
29656
29657
  x - defaultTarget.x,
29657
29658
  y - defaultTarget.y,
29658
29659
  z138 - defaultTarget.z
29659
29660
  );
29660
- return distance2 > 0 ? distance2 : 5;
29661
+ return distance3 > 0 ? distance3 : 5;
29661
29662
  }, [initialCameraPosition, defaultTarget]);
29662
29663
  const getPresetConfig = useCallback4(
29663
29664
  (preset) => {
@@ -29668,13 +29669,13 @@ var CameraControllerProvider = ({ children, defaultTarget, initialCameraPosition
29668
29669
  ];
29669
29670
  const camera = mainCameraRef.current;
29670
29671
  const controls = controlsRef.current;
29671
- let distance2 = baseDistance;
29672
+ let distance3 = baseDistance;
29672
29673
  if (camera && controls) {
29673
- distance2 = camera.position.distanceTo(controls.target);
29674
+ distance3 = camera.position.distanceTo(controls.target);
29674
29675
  }
29675
29676
  switch (preset) {
29676
29677
  case "Top Center Angled": {
29677
- const angledOffset = distance2 / Math.sqrt(2);
29678
+ const angledOffset = distance3 / Math.sqrt(2);
29678
29679
  return {
29679
29680
  position: [
29680
29681
  defaultTarget.x,
@@ -29690,7 +29691,7 @@ var CameraControllerProvider = ({ children, defaultTarget, initialCameraPosition
29690
29691
  position: [
29691
29692
  defaultTarget.x,
29692
29693
  defaultTarget.y,
29693
- defaultTarget.z + distance2
29694
+ defaultTarget.z + distance3
29694
29695
  ],
29695
29696
  target: targetVector,
29696
29697
  up: [0, 0, 1]
@@ -29698,9 +29699,9 @@ var CameraControllerProvider = ({ children, defaultTarget, initialCameraPosition
29698
29699
  case "Top Left Corner":
29699
29700
  return {
29700
29701
  position: [
29701
- defaultTarget.x - distance2 * 0.6,
29702
- defaultTarget.y - distance2 * 0.6,
29703
- defaultTarget.z + distance2 * 0.6
29702
+ defaultTarget.x - distance3 * 0.6,
29703
+ defaultTarget.y - distance3 * 0.6,
29704
+ defaultTarget.z + distance3 * 0.6
29704
29705
  ],
29705
29706
  target: targetVector,
29706
29707
  up: [0, 0, 1]
@@ -29708,9 +29709,9 @@ var CameraControllerProvider = ({ children, defaultTarget, initialCameraPosition
29708
29709
  case "Top Right Corner":
29709
29710
  return {
29710
29711
  position: [
29711
- defaultTarget.x + distance2 * 0.6,
29712
- defaultTarget.y - distance2 * 0.6,
29713
- defaultTarget.z + distance2 * 0.6
29712
+ defaultTarget.x + distance3 * 0.6,
29713
+ defaultTarget.y - distance3 * 0.6,
29714
+ defaultTarget.z + distance3 * 0.6
29714
29715
  ],
29715
29716
  target: targetVector,
29716
29717
  up: [0, 0, 1]
@@ -29718,7 +29719,7 @@ var CameraControllerProvider = ({ children, defaultTarget, initialCameraPosition
29718
29719
  case "Left Sideview":
29719
29720
  return {
29720
29721
  position: [
29721
- defaultTarget.x - distance2,
29722
+ defaultTarget.x - distance3,
29722
29723
  defaultTarget.y,
29723
29724
  defaultTarget.z
29724
29725
  ],
@@ -29728,7 +29729,7 @@ var CameraControllerProvider = ({ children, defaultTarget, initialCameraPosition
29728
29729
  case "Right Sideview":
29729
29730
  return {
29730
29731
  position: [
29731
- defaultTarget.x + distance2,
29732
+ defaultTarget.x + distance3,
29732
29733
  defaultTarget.y,
29733
29734
  defaultTarget.z
29734
29735
  ],
@@ -29739,7 +29740,7 @@ var CameraControllerProvider = ({ children, defaultTarget, initialCameraPosition
29739
29740
  return {
29740
29741
  position: [
29741
29742
  defaultTarget.x,
29742
- defaultTarget.y - distance2,
29743
+ defaultTarget.y - distance3,
29743
29744
  defaultTarget.z
29744
29745
  ],
29745
29746
  target: targetVector,
@@ -30321,13 +30322,13 @@ import { useEffect as useEffect15, useRef as useRef7 } from "react";
30321
30322
  import * as THREE14 from "three";
30322
30323
  import { Text as TroikaText } from "troika-three-text";
30323
30324
  import { jsx as jsx12 } from "react/jsx-runtime";
30324
- function computePointInFront(rotationVector, distance2) {
30325
+ function computePointInFront(rotationVector, distance3) {
30325
30326
  const quaternion = new THREE14.Quaternion().setFromEuler(
30326
30327
  new THREE14.Euler(rotationVector.x, rotationVector.y, rotationVector.z)
30327
30328
  );
30328
30329
  const forwardVector = new THREE14.Vector3(0, 0, 1);
30329
30330
  forwardVector.applyQuaternion(quaternion);
30330
- const result = forwardVector.multiplyScalar(distance2);
30331
+ const result = forwardVector.multiplyScalar(distance3);
30331
30332
  return result;
30332
30333
  }
30333
30334
  var OrientationCubeCanvas = () => {
@@ -32607,6 +32608,58 @@ import { su as su9 } from "@tscircuit/circuit-json-util";
32607
32608
  // src/utils/soldermask-texture.ts
32608
32609
  import * as THREE18 from "three";
32609
32610
  import { su as su5 } from "@tscircuit/circuit-json-util";
32611
+
32612
+ // node_modules/@tscircuit/math-utils/dist/chunk-5N7UJNVK.js
32613
+ var getBoundsFromPoints = (points) => {
32614
+ if (points.length === 0) {
32615
+ return null;
32616
+ }
32617
+ let minX = points[0].x;
32618
+ let minY = points[0].y;
32619
+ let maxX = points[0].x;
32620
+ let maxY = points[0].y;
32621
+ for (let i = 1; i < points.length; i++) {
32622
+ const point2 = points[i];
32623
+ if (point2.x < minX) minX = point2.x;
32624
+ if (point2.y < minY) minY = point2.y;
32625
+ if (point2.x > maxX) maxX = point2.x;
32626
+ if (point2.y > maxY) maxY = point2.y;
32627
+ }
32628
+ return { minX, minY, maxX, maxY };
32629
+ };
32630
+
32631
+ // src/utils/outline-bounds.ts
32632
+ function calculateOutlineBounds(boardData) {
32633
+ if (boardData.outline && boardData.outline.length >= 3) {
32634
+ const bounds2 = getBoundsFromPoints(boardData.outline);
32635
+ return {
32636
+ ...bounds2,
32637
+ width: bounds2.maxX - bounds2.minX,
32638
+ height: bounds2.maxY - bounds2.minY,
32639
+ centerX: (bounds2.minX + bounds2.maxX) / 2,
32640
+ centerY: (bounds2.minY + bounds2.maxY) / 2
32641
+ };
32642
+ }
32643
+ const boardWidth = boardData.width ?? 0;
32644
+ const boardHeight = boardData.height ?? 0;
32645
+ const boardCenterX = boardData.center?.x ?? 0;
32646
+ const boardCenterY = boardData.center?.y ?? 0;
32647
+ const bounds = {
32648
+ minX: boardCenterX - boardWidth / 2,
32649
+ maxX: boardCenterX + boardWidth / 2,
32650
+ minY: boardCenterY - boardHeight / 2,
32651
+ maxY: boardCenterY + boardHeight / 2
32652
+ };
32653
+ return {
32654
+ ...bounds,
32655
+ width: boardWidth,
32656
+ height: boardHeight,
32657
+ centerX: boardCenterX,
32658
+ centerY: boardCenterY
32659
+ };
32660
+ }
32661
+
32662
+ // src/utils/soldermask-texture.ts
32610
32663
  function createSoldermaskTextureForLayer({
32611
32664
  layer,
32612
32665
  circuitJson,
@@ -32614,9 +32667,14 @@ function createSoldermaskTextureForLayer({
32614
32667
  soldermaskColor,
32615
32668
  traceTextureResolution
32616
32669
  }) {
32670
+ const boardOutlineBounds = calculateOutlineBounds(boardData);
32617
32671
  const canvas = document.createElement("canvas");
32618
- const canvasWidth = Math.floor(boardData.width * traceTextureResolution);
32619
- const canvasHeight = Math.floor(boardData.height * traceTextureResolution);
32672
+ const canvasWidth = Math.floor(
32673
+ boardOutlineBounds.width * traceTextureResolution
32674
+ );
32675
+ const canvasHeight = Math.floor(
32676
+ boardOutlineBounds.height * traceTextureResolution
32677
+ );
32620
32678
  canvas.width = canvasWidth;
32621
32679
  canvas.height = canvasHeight;
32622
32680
  const ctx = canvas.getContext("2d");
@@ -32625,8 +32683,8 @@ function createSoldermaskTextureForLayer({
32625
32683
  ctx.translate(0, canvasHeight);
32626
32684
  ctx.scale(1, -1);
32627
32685
  }
32628
- const canvasXFromPcb = (pcbX) => (pcbX - boardData.center.x + boardData.width / 2) * traceTextureResolution;
32629
- const canvasYFromPcb = (pcbY) => (-(pcbY - boardData.center.y) + boardData.height / 2) * traceTextureResolution;
32686
+ const canvasXFromPcb = (pcbX) => (pcbX - boardOutlineBounds.minX) * traceTextureResolution;
32687
+ const canvasYFromPcb = (pcbY) => (boardOutlineBounds.maxY - pcbY) * traceTextureResolution;
32630
32688
  ctx.fillStyle = soldermaskColor;
32631
32689
  if (boardData.outline && boardData.outline.length >= 3) {
32632
32690
  ctx.beginPath();
@@ -33409,9 +33467,14 @@ function createSilkscreenTextureForLayer({
33409
33467
  if (textsOnLayer.length === 0 && pathsOnLayer.length === 0 && linesOnLayer.length === 0 && rectsOnLayer.length === 0 && circlesOnLayer.length === 0 && fabricationNoteRectsOnLayer.length === 0 && noteLinesOnLayer.length === 0) {
33410
33468
  return null;
33411
33469
  }
33470
+ const boardOutlineBounds = calculateOutlineBounds(boardData);
33412
33471
  const canvas = document.createElement("canvas");
33413
- const canvasWidth = Math.floor(boardData.width * traceTextureResolution);
33414
- const canvasHeight = Math.floor(boardData.height * traceTextureResolution);
33472
+ const canvasWidth = Math.floor(
33473
+ boardOutlineBounds.width * traceTextureResolution
33474
+ );
33475
+ const canvasHeight = Math.floor(
33476
+ boardOutlineBounds.height * traceTextureResolution
33477
+ );
33415
33478
  canvas.width = canvasWidth;
33416
33479
  canvas.height = canvasHeight;
33417
33480
  const ctx = canvas.getContext("2d");
@@ -33422,8 +33485,8 @@ function createSilkscreenTextureForLayer({
33422
33485
  }
33423
33486
  ctx.strokeStyle = silkscreenColor;
33424
33487
  ctx.fillStyle = silkscreenColor;
33425
- const canvasXFromPcb = (pcbX) => (pcbX - boardData.center.x + boardData.width / 2) * traceTextureResolution;
33426
- const canvasYFromPcb = (pcbY) => (-(pcbY - boardData.center.y) + boardData.height / 2) * traceTextureResolution;
33488
+ const canvasXFromPcb = (pcbX) => (pcbX - boardOutlineBounds.minX) * traceTextureResolution;
33489
+ const canvasYFromPcb = (pcbY) => (boardOutlineBounds.maxY - pcbY) * traceTextureResolution;
33427
33490
  linesOnLayer.forEach((lineEl) => {
33428
33491
  const startXmm = parseDimensionToMm(lineEl.x1) ?? 0;
33429
33492
  const startYmm = parseDimensionToMm(lineEl.y1) ?? 0;
@@ -33789,9 +33852,14 @@ function createTraceTextureForLayer({
33789
33852
  (t) => t.route.some((p) => isWireRoutePoint(p) && p.layer === layer)
33790
33853
  );
33791
33854
  if (tracesOnLayer.length === 0) return null;
33855
+ const boardOutlineBounds = calculateOutlineBounds(boardData);
33792
33856
  const canvas = document.createElement("canvas");
33793
- const canvasWidth = Math.floor(boardData.width * traceTextureResolution);
33794
- const canvasHeight = Math.floor(boardData.height * traceTextureResolution);
33857
+ const canvasWidth = Math.floor(
33858
+ boardOutlineBounds.width * traceTextureResolution
33859
+ );
33860
+ const canvasHeight = Math.floor(
33861
+ boardOutlineBounds.height * traceTextureResolution
33862
+ );
33795
33863
  canvas.width = canvasWidth;
33796
33864
  canvas.height = canvasHeight;
33797
33865
  const ctx = canvas.getContext("2d");
@@ -33817,8 +33885,8 @@ function createTraceTextureForLayer({
33817
33885
  const pcbY = point2.y;
33818
33886
  currentLineWidth = point2.width * traceTextureResolution;
33819
33887
  ctx.lineWidth = currentLineWidth;
33820
- const canvasX = (pcbX - boardData.center.x + boardData.width / 2) * traceTextureResolution;
33821
- const canvasY = (-(pcbY - boardData.center.y) + boardData.height / 2) * traceTextureResolution;
33888
+ const canvasX = (pcbX - boardOutlineBounds.minX) * traceTextureResolution;
33889
+ const canvasY = (boardOutlineBounds.maxY - pcbY) * traceTextureResolution;
33822
33890
  if (firstPoint) {
33823
33891
  ctx.moveTo(canvasX, canvasY);
33824
33892
  firstPoint = false;
@@ -33833,8 +33901,8 @@ function createTraceTextureForLayer({
33833
33901
  ctx.globalCompositeOperation = "destination-out";
33834
33902
  ctx.fillStyle = "black";
33835
33903
  allPcbVias.forEach((via) => {
33836
- const canvasX = (via.x - boardData.center.x + boardData.width / 2) * traceTextureResolution;
33837
- const canvasY = (-(via.y - boardData.center.y) + boardData.height / 2) * traceTextureResolution;
33904
+ const canvasX = (via.x - boardOutlineBounds.minX) * traceTextureResolution;
33905
+ const canvasY = (boardOutlineBounds.maxY - via.y) * traceTextureResolution;
33838
33906
  const canvasRadius = via.outer_diameter / 2 * traceTextureResolution;
33839
33907
  ctx.beginPath();
33840
33908
  ctx.arc(canvasX, canvasY, canvasRadius, 0, 2 * Math.PI, false);
@@ -33842,8 +33910,8 @@ function createTraceTextureForLayer({
33842
33910
  });
33843
33911
  allPcbPlatedHoles.forEach((ph) => {
33844
33912
  if (ph.layers.includes(layer) && ph.shape === "circle") {
33845
- const canvasX = (ph.x - boardData.center.x + boardData.width / 2) * traceTextureResolution;
33846
- const canvasY = (-(ph.y - boardData.center.y) + boardData.height / 2) * traceTextureResolution;
33913
+ const canvasX = (ph.x - boardOutlineBounds.minX) * traceTextureResolution;
33914
+ const canvasY = (boardOutlineBounds.maxY - ph.y) * traceTextureResolution;
33847
33915
  const canvasRadius = ph.outer_diameter / 2 * traceTextureResolution;
33848
33916
  ctx.beginPath();
33849
33917
  ctx.arc(canvasX, canvasY, canvasRadius, 0, 2 * Math.PI, false);
@@ -34038,9 +34106,14 @@ function createCopperTextTextureForLayer({
34038
34106
  if (textsOnLayer.length === 0) {
34039
34107
  return null;
34040
34108
  }
34109
+ const boardOutlineBounds = calculateOutlineBounds(boardData);
34041
34110
  const canvas = document.createElement("canvas");
34042
- const canvasWidth = Math.floor(boardData.width * traceTextureResolution);
34043
- const canvasHeight = Math.floor(boardData.height * traceTextureResolution);
34111
+ const canvasWidth = Math.floor(
34112
+ boardOutlineBounds.width * traceTextureResolution
34113
+ );
34114
+ const canvasHeight = Math.floor(
34115
+ boardOutlineBounds.height * traceTextureResolution
34116
+ );
34044
34117
  canvas.width = canvasWidth;
34045
34118
  canvas.height = canvasHeight;
34046
34119
  const ctx = canvas.getContext("2d");
@@ -34051,8 +34124,8 @@ function createCopperTextTextureForLayer({
34051
34124
  }
34052
34125
  ctx.strokeStyle = copperColor;
34053
34126
  ctx.fillStyle = copperColor;
34054
- const canvasXFromPcb = (pcbX) => (pcbX - boardData.center.x + boardData.width / 2) * traceTextureResolution;
34055
- const canvasYFromPcb = (pcbY) => (-(pcbY - boardData.center.y) + boardData.height / 2) * traceTextureResolution;
34127
+ const canvasXFromPcb = (pcbX) => (pcbX - boardOutlineBounds.minX) * traceTextureResolution;
34128
+ const canvasYFromPcb = (pcbY) => (boardOutlineBounds.maxY - pcbY) * traceTextureResolution;
34056
34129
  textsOnLayer.forEach((textS) => {
34057
34130
  const fontSize = typeof textS.font_size === "number" ? textS.font_size : 0.2;
34058
34131
  const textStrokeWidth = Math.max(0.02, fontSize * 0.08) * traceTextureResolution;
@@ -34285,11 +34358,12 @@ function JscadBoardTextures({
34285
34358
  useEffect22(() => {
34286
34359
  if (!rootObject || !boardData || !textures) return;
34287
34360
  const meshes = [];
34288
- const createTexturePlane = (texture, zOffset, isBottomLayer, name, usePolygonOffset = false, depthWrite = false) => {
34361
+ const createTexturePlane2 = (texture, zOffset, isBottomLayer, name, usePolygonOffset = false, depthWrite = false) => {
34289
34362
  if (!texture) return null;
34363
+ const boardOutlineBounds = calculateOutlineBounds(boardData);
34290
34364
  const planeGeom = new THREE23.PlaneGeometry(
34291
- boardData.width,
34292
- boardData.height
34365
+ boardOutlineBounds.width,
34366
+ boardOutlineBounds.height
34293
34367
  );
34294
34368
  const material = new THREE23.MeshBasicMaterial({
34295
34369
  map: texture,
@@ -34301,7 +34375,11 @@ function JscadBoardTextures({
34301
34375
  polygonOffsetUnits: usePolygonOffset ? -1 : 0
34302
34376
  });
34303
34377
  const mesh = new THREE23.Mesh(planeGeom, material);
34304
- mesh.position.set(boardData.center.x, boardData.center.y, zOffset);
34378
+ mesh.position.set(
34379
+ boardOutlineBounds.centerX,
34380
+ boardOutlineBounds.centerY,
34381
+ zOffset
34382
+ );
34305
34383
  if (isBottomLayer) {
34306
34384
  mesh.rotation.set(Math.PI, 0, 0);
34307
34385
  }
@@ -34310,7 +34388,7 @@ function JscadBoardTextures({
34310
34388
  };
34311
34389
  const SURFACE_OFFSET = 1e-3;
34312
34390
  if (visibility.topMask) {
34313
- const topSoldermaskMesh = createTexturePlane(
34391
+ const topSoldermaskMesh = createTexturePlane2(
34314
34392
  textures.topSoldermask,
34315
34393
  pcbThickness / 2 + SURFACE_OFFSET,
34316
34394
  false,
@@ -34323,7 +34401,7 @@ function JscadBoardTextures({
34323
34401
  }
34324
34402
  }
34325
34403
  if (visibility.bottomMask) {
34326
- const bottomSoldermaskMesh = createTexturePlane(
34404
+ const bottomSoldermaskMesh = createTexturePlane2(
34327
34405
  textures.bottomSoldermask,
34328
34406
  -pcbThickness / 2 - SURFACE_OFFSET,
34329
34407
  true,
@@ -34336,7 +34414,7 @@ function JscadBoardTextures({
34336
34414
  }
34337
34415
  }
34338
34416
  if (visibility.topCopper && visibility.topMask) {
34339
- const topTraceWithMaskMesh = createTexturePlane(
34417
+ const topTraceWithMaskMesh = createTexturePlane2(
34340
34418
  textures.topTraceWithMask,
34341
34419
  pcbThickness / 2 + BOARD_SURFACE_OFFSET.traces + 4e-3,
34342
34420
  false,
@@ -34348,7 +34426,7 @@ function JscadBoardTextures({
34348
34426
  }
34349
34427
  }
34350
34428
  if (visibility.bottomCopper && visibility.bottomMask) {
34351
- const bottomTraceWithMaskMesh = createTexturePlane(
34429
+ const bottomTraceWithMaskMesh = createTexturePlane2(
34352
34430
  textures.bottomTraceWithMask,
34353
34431
  -pcbThickness / 2 - BOARD_SURFACE_OFFSET.traces - 5e-3,
34354
34432
  true,
@@ -34360,7 +34438,7 @@ function JscadBoardTextures({
34360
34438
  }
34361
34439
  }
34362
34440
  if (visibility.topSilkscreen) {
34363
- const topSilkscreenMesh = createTexturePlane(
34441
+ const topSilkscreenMesh = createTexturePlane2(
34364
34442
  textures.topSilkscreen,
34365
34443
  pcbThickness / 2 + SURFACE_OFFSET + 2e-3,
34366
34444
  false,
@@ -34372,7 +34450,7 @@ function JscadBoardTextures({
34372
34450
  }
34373
34451
  }
34374
34452
  if (visibility.bottomSilkscreen) {
34375
- const bottomSilkscreenMesh = createTexturePlane(
34453
+ const bottomSilkscreenMesh = createTexturePlane2(
34376
34454
  textures.bottomSilkscreen,
34377
34455
  -pcbThickness / 2 - SURFACE_OFFSET - 2e-3,
34378
34456
  true,
@@ -34384,7 +34462,7 @@ function JscadBoardTextures({
34384
34462
  }
34385
34463
  }
34386
34464
  if (visibility.topCopper) {
34387
- const topCopperTextMesh = createTexturePlane(
34465
+ const topCopperTextMesh = createTexturePlane2(
34388
34466
  textures.topCopperText,
34389
34467
  pcbThickness / 2 + BOARD_SURFACE_OFFSET.copper,
34390
34468
  false,
@@ -34396,7 +34474,7 @@ function JscadBoardTextures({
34396
34474
  }
34397
34475
  }
34398
34476
  if (visibility.bottomCopper) {
34399
- const bottomCopperTextMesh = createTexturePlane(
34477
+ const bottomCopperTextMesh = createTexturePlane2(
34400
34478
  textures.bottomCopperText,
34401
34479
  -pcbThickness / 2 - BOARD_SURFACE_OFFSET.copper,
34402
34480
  true,
@@ -34408,7 +34486,7 @@ function JscadBoardTextures({
34408
34486
  }
34409
34487
  }
34410
34488
  if (visibility.boardBody) {
34411
- const topPanelOutlinesMesh = createTexturePlane(
34489
+ const topPanelOutlinesMesh = createTexturePlane2(
34412
34490
  textures.topPanelOutlines,
34413
34491
  pcbThickness / 2 + SURFACE_OFFSET + 3e-3,
34414
34492
  // Above silkscreen
@@ -34421,7 +34499,7 @@ function JscadBoardTextures({
34421
34499
  meshes.push(topPanelOutlinesMesh);
34422
34500
  rootObject.add(topPanelOutlinesMesh);
34423
34501
  }
34424
- const bottomPanelOutlinesMesh = createTexturePlane(
34502
+ const bottomPanelOutlinesMesh = createTexturePlane2(
34425
34503
  textures.bottomPanelOutlines,
34426
34504
  -pcbThickness / 2 - SURFACE_OFFSET - 3e-3,
34427
34505
  // Below bottom silkscreen
@@ -34673,7 +34751,7 @@ import { useEffect as useEffect24, useMemo as useMemo22, useState as useState15
34673
34751
  // src/hooks/useManifoldBoardBuilder.ts
34674
34752
  import { useState as useState14, useEffect as useEffect23, useMemo as useMemo21, useRef as useRef9 } from "react";
34675
34753
  import { su as su18 } from "@tscircuit/circuit-json-util";
34676
- import * as THREE29 from "three";
34754
+ import * as THREE30 from "three";
34677
34755
 
34678
34756
  // src/utils/manifold/create-manifold-board.ts
34679
34757
  var arePointsClockwise3 = (points) => {
@@ -34733,202 +34811,6 @@ function createManifoldBoard(Manifold, CrossSection, boardData, pcbThickness, ma
34733
34811
  return { boardOp, outlineCrossSection };
34734
34812
  }
34735
34813
 
34736
- // src/utils/manifold/process-copper-pours.ts
34737
- import * as THREE25 from "three";
34738
-
34739
- // src/utils/manifold-mesh-to-three-geometry.ts
34740
- import * as THREE24 from "three";
34741
- function manifoldMeshToThreeGeometry(manifoldMesh) {
34742
- const geometry = new THREE24.BufferGeometry();
34743
- geometry.setAttribute(
34744
- "position",
34745
- new THREE24.Float32BufferAttribute(manifoldMesh.vertProperties, 3)
34746
- );
34747
- geometry.setIndex(new THREE24.Uint32BufferAttribute(manifoldMesh.triVerts, 1));
34748
- if (manifoldMesh.runIndex && manifoldMesh.runIndex.length > 1 && manifoldMesh.runOriginalID) {
34749
- for (let i = 0; i < manifoldMesh.runIndex.length - 1; i++) {
34750
- const start = manifoldMesh.runIndex[i];
34751
- const count3 = manifoldMesh.runIndex[i + 1] - start;
34752
- geometry.addGroup(start, count3, 0);
34753
- }
34754
- } else {
34755
- geometry.addGroup(0, manifoldMesh.triVerts.length, 0);
34756
- }
34757
- return geometry;
34758
- }
34759
-
34760
- // src/utils/manifold/process-copper-pours.ts
34761
- var arePointsClockwise4 = (points) => {
34762
- let area = 0;
34763
- for (let i = 0; i < points.length; i++) {
34764
- const j = (i + 1) % points.length;
34765
- if (points[i] && points[j]) {
34766
- area += points[i][0] * points[j][1];
34767
- area -= points[j][0] * points[i][1];
34768
- }
34769
- }
34770
- const signedArea = area / 2;
34771
- return signedArea <= 0;
34772
- };
34773
- function segmentToPoints2(p1, p2, bulge, arcSegments) {
34774
- if (!bulge || Math.abs(bulge) < 1e-9) {
34775
- return [];
34776
- }
34777
- const theta = 4 * Math.atan(bulge);
34778
- const dx = p2[0] - p1[0];
34779
- const dy = p2[1] - p1[1];
34780
- const dist = Math.sqrt(dx * dx + dy * dy);
34781
- if (dist < 1e-9) return [];
34782
- const radius = Math.abs(dist / (2 * Math.sin(theta / 2)));
34783
- const m = Math.sqrt(Math.max(0, radius * radius - dist / 2 * (dist / 2)));
34784
- const midPoint = [(p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2];
34785
- const ux = dx / dist;
34786
- const uy = dy / dist;
34787
- const nx = -uy;
34788
- const ny = ux;
34789
- const centerX = midPoint[0] + nx * m * Math.sign(bulge);
34790
- const centerY = midPoint[1] + ny * m * Math.sign(bulge);
34791
- const startAngle = Math.atan2(p1[1] - centerY, p1[0] - centerX);
34792
- const points = [];
34793
- const numSteps = Math.max(
34794
- 2,
34795
- Math.ceil(arcSegments * Math.abs(theta) / (Math.PI * 2) * 4)
34796
- );
34797
- const angleStep = theta / numSteps;
34798
- for (let i = 1; i < numSteps; i++) {
34799
- const angle = startAngle + angleStep * i;
34800
- points.push([
34801
- centerX + radius * Math.cos(angle),
34802
- centerY + radius * Math.sin(angle)
34803
- ]);
34804
- }
34805
- return points;
34806
- }
34807
- function ringToPoints2(ring2, arcSegments) {
34808
- const allPoints = [];
34809
- const vertices = ring2.vertices;
34810
- for (let i = 0; i < vertices.length; i++) {
34811
- const p1 = vertices[i];
34812
- const p2 = vertices[(i + 1) % vertices.length];
34813
- allPoints.push([p1.x, p1.y]);
34814
- if (p1.bulge) {
34815
- const arcPoints = segmentToPoints2(
34816
- [p1.x, p1.y],
34817
- [p2.x, p2.y],
34818
- p1.bulge,
34819
- arcSegments
34820
- );
34821
- allPoints.push(...arcPoints);
34822
- }
34823
- }
34824
- return allPoints;
34825
- }
34826
- function processCopperPoursForManifold(Manifold, CrossSection, circuitJson, pcbThickness, manifoldInstancesForCleanup, boardMaterial, holeUnion, boardClipVolume) {
34827
- const copperPourGeoms = [];
34828
- const copperPours = circuitJson.filter(
34829
- (e) => e.type === "pcb_copper_pour"
34830
- );
34831
- for (const pour of copperPours) {
34832
- const pourThickness = DEFAULT_SMT_PAD_THICKNESS;
34833
- const layerSign = pour.layer === "bottom" ? -1 : 1;
34834
- const zPos = layerSign * (pcbThickness / 2 + pourThickness / 2 + MANIFOLD_Z_OFFSET);
34835
- let pourOp;
34836
- if (pour.shape === "rect") {
34837
- pourOp = Manifold.cube([pour.width, pour.height, pourThickness], true);
34838
- manifoldInstancesForCleanup.push(pourOp);
34839
- if (pour.rotation) {
34840
- const rotatedOp = pourOp.rotate([0, 0, pour.rotation]);
34841
- manifoldInstancesForCleanup.push(rotatedOp);
34842
- pourOp = rotatedOp;
34843
- }
34844
- pourOp = pourOp.translate([pour.center.x, pour.center.y, zPos]);
34845
- manifoldInstancesForCleanup.push(pourOp);
34846
- } else if (pour.shape === "polygon") {
34847
- if (pour.points.length < 3) continue;
34848
- let pointsVec2 = pour.points.map((p) => [
34849
- p.x,
34850
- p.y
34851
- ]);
34852
- if (arePointsClockwise4(pointsVec2)) {
34853
- pointsVec2 = pointsVec2.reverse();
34854
- }
34855
- const crossSection = CrossSection.ofPolygons([pointsVec2]);
34856
- manifoldInstancesForCleanup.push(crossSection);
34857
- pourOp = Manifold.extrude(
34858
- crossSection,
34859
- pourThickness,
34860
- 0,
34861
- // nDivisions
34862
- 0,
34863
- // twistDegrees
34864
- [1, 1],
34865
- // scaleTop
34866
- true
34867
- // center extrusion
34868
- ).translate([0, 0, zPos]);
34869
- manifoldInstancesForCleanup.push(pourOp);
34870
- } else if (pour.shape === "brep") {
34871
- const brepShape = pour.brep_shape;
34872
- if (!brepShape || !brepShape.outer_ring) continue;
34873
- let outerRingPoints = ringToPoints2(
34874
- brepShape.outer_ring,
34875
- SMOOTH_CIRCLE_SEGMENTS
34876
- );
34877
- if (arePointsClockwise4(outerRingPoints)) {
34878
- outerRingPoints = outerRingPoints.reverse();
34879
- }
34880
- const polygons = [outerRingPoints];
34881
- if (brepShape.inner_rings) {
34882
- const innerRingsPoints = brepShape.inner_rings.map((ring2) => {
34883
- let points = ringToPoints2(ring2, SMOOTH_CIRCLE_SEGMENTS);
34884
- if (!arePointsClockwise4(points)) {
34885
- points = points.reverse();
34886
- }
34887
- return points;
34888
- });
34889
- polygons.push(...innerRingsPoints);
34890
- }
34891
- const crossSection = CrossSection.ofPolygons(polygons);
34892
- manifoldInstancesForCleanup.push(crossSection);
34893
- pourOp = Manifold.extrude(
34894
- crossSection,
34895
- pourThickness,
34896
- 0,
34897
- // nDivisions
34898
- 0,
34899
- // twistDegrees
34900
- [1, 1],
34901
- // scaleTop
34902
- true
34903
- // center extrusion
34904
- ).translate([0, 0, zPos]);
34905
- manifoldInstancesForCleanup.push(pourOp);
34906
- }
34907
- if (pourOp) {
34908
- if (holeUnion) {
34909
- const withHoles = pourOp.subtract(holeUnion);
34910
- manifoldInstancesForCleanup.push(withHoles);
34911
- pourOp = withHoles;
34912
- }
34913
- if (boardClipVolume) {
34914
- const clipped = Manifold.intersection([pourOp, boardClipVolume]);
34915
- manifoldInstancesForCleanup.push(clipped);
34916
- pourOp = clipped;
34917
- }
34918
- const covered = pour.covered_with_solder_mask !== false;
34919
- const pourColorArr = covered ? tracesMaterialColors[boardMaterial] ?? colors.fr4TracesWithoutMaskTan : colors.copper;
34920
- const pourColor = new THREE25.Color(...pourColorArr);
34921
- const threeGeom = manifoldMeshToThreeGeometry(pourOp.getMesh());
34922
- copperPourGeoms.push({
34923
- key: `coppour-${pour.pcb_copper_pour_id}`,
34924
- geometry: threeGeom,
34925
- color: pourColor
34926
- });
34927
- }
34928
- }
34929
- return { copperPourGeoms };
34930
- }
34931
-
34932
34814
  // src/utils/manifold/process-cutouts.ts
34933
34815
  import { su as su13 } from "@tscircuit/circuit-json-util";
34934
34816
 
@@ -35008,7 +34890,7 @@ function createPadManifoldOp({
35008
34890
  }
35009
34891
 
35010
34892
  // src/utils/manifold/process-cutouts.ts
35011
- var arePointsClockwise5 = (points) => {
34893
+ var arePointsClockwise4 = (points) => {
35012
34894
  let area = 0;
35013
34895
  for (let i = 0; i < points.length; i++) {
35014
34896
  const j = (i + 1) % points.length;
@@ -35084,7 +34966,7 @@ function processCutoutsForManifold(Manifold, CrossSection, circuitJson, pcbThick
35084
34966
  p.x,
35085
34967
  p.y
35086
34968
  ]);
35087
- if (arePointsClockwise5(pointsVec2)) {
34969
+ if (arePointsClockwise4(pointsVec2)) {
35088
34970
  pointsVec2 = pointsVec2.reverse();
35089
34971
  }
35090
34972
  const crossSection = CrossSection.ofPolygons([pointsVec2]);
@@ -35219,8 +35101,31 @@ function processNonPlatedHolesForManifold(Manifold, circuitJson, pcbThickness, m
35219
35101
 
35220
35102
  // src/utils/manifold/process-plated-holes.ts
35221
35103
  import { su as su15 } from "@tscircuit/circuit-json-util";
35222
- import * as THREE26 from "three";
35223
- var arePointsClockwise6 = (points) => {
35104
+ import * as THREE25 from "three";
35105
+
35106
+ // src/utils/manifold-mesh-to-three-geometry.ts
35107
+ import * as THREE24 from "three";
35108
+ function manifoldMeshToThreeGeometry(manifoldMesh) {
35109
+ const geometry = new THREE24.BufferGeometry();
35110
+ geometry.setAttribute(
35111
+ "position",
35112
+ new THREE24.Float32BufferAttribute(manifoldMesh.vertProperties, 3)
35113
+ );
35114
+ geometry.setIndex(new THREE24.Uint32BufferAttribute(manifoldMesh.triVerts, 1));
35115
+ if (manifoldMesh.runIndex && manifoldMesh.runIndex.length > 1 && manifoldMesh.runOriginalID) {
35116
+ for (let i = 0; i < manifoldMesh.runIndex.length - 1; i++) {
35117
+ const start = manifoldMesh.runIndex[i];
35118
+ const count3 = manifoldMesh.runIndex[i + 1] - start;
35119
+ geometry.addGroup(start, count3, 0);
35120
+ }
35121
+ } else {
35122
+ geometry.addGroup(0, manifoldMesh.triVerts.length, 0);
35123
+ }
35124
+ return geometry;
35125
+ }
35126
+
35127
+ // src/utils/manifold/process-plated-holes.ts
35128
+ var arePointsClockwise5 = (points) => {
35224
35129
  let area = 0;
35225
35130
  for (let i = 0; i < points.length; i++) {
35226
35131
  const j = (i + 1) % points.length;
@@ -35240,7 +35145,7 @@ var createEllipsePoints = (width10, height10, segments) => {
35240
35145
  }
35241
35146
  return points;
35242
35147
  };
35243
- var COPPER_COLOR = new THREE26.Color(...colors.copper);
35148
+ var COPPER_COLOR = new THREE25.Color(...colors.copper);
35244
35149
  var PLATED_HOLE_LIP_HEIGHT = 0.05;
35245
35150
  function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbThickness, manifoldInstancesForCleanup, boardClipVolume) {
35246
35151
  const platedHoleBoardDrills = [];
@@ -35267,7 +35172,7 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
35267
35172
  point2.x,
35268
35173
  point2.y
35269
35174
  ]);
35270
- if (arePointsClockwise6(points)) {
35175
+ if (arePointsClockwise5(points)) {
35271
35176
  points = points.reverse();
35272
35177
  }
35273
35178
  const crossSection = CrossSection.ofPolygons([points]);
@@ -35312,7 +35217,7 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
35312
35217
  const height10 = Math.max(baseHeight + sizeDelta, M);
35313
35218
  if (holeShape === "oval") {
35314
35219
  let points = createEllipsePoints(width10, height10, SMOOTH_CIRCLE_SEGMENTS);
35315
- if (arePointsClockwise6(points)) {
35220
+ if (arePointsClockwise5(points)) {
35316
35221
  points = points.reverse();
35317
35222
  }
35318
35223
  const crossSection = CrossSection.ofPolygons([points]);
@@ -35627,7 +35532,7 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
35627
35532
  drillH,
35628
35533
  SMOOTH_CIRCLE_SEGMENTS
35629
35534
  );
35630
- if (arePointsClockwise6(boardDrillPoints)) {
35535
+ if (arePointsClockwise5(boardDrillPoints)) {
35631
35536
  boardDrillPoints = boardDrillPoints.reverse();
35632
35537
  }
35633
35538
  const boardDrillCrossSection = CrossSection.ofPolygons([boardDrillPoints]);
@@ -35655,7 +35560,7 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
35655
35560
  outerH,
35656
35561
  SMOOTH_CIRCLE_SEGMENTS
35657
35562
  );
35658
- if (arePointsClockwise6(outerPoints)) {
35563
+ if (arePointsClockwise5(outerPoints)) {
35659
35564
  outerPoints = outerPoints.reverse();
35660
35565
  }
35661
35566
  const outerCrossSection = CrossSection.ofPolygons([outerPoints]);
@@ -35674,7 +35579,7 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
35674
35579
  holeH,
35675
35580
  SMOOTH_CIRCLE_SEGMENTS
35676
35581
  );
35677
- if (arePointsClockwise6(innerPoints)) {
35582
+ if (arePointsClockwise5(innerPoints)) {
35678
35583
  innerPoints = innerPoints.reverse();
35679
35584
  }
35680
35585
  const innerCrossSection = CrossSection.ofPolygons([innerPoints]);
@@ -35814,8 +35719,8 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
35814
35719
 
35815
35720
  // src/utils/manifold/process-smt-pads.ts
35816
35721
  import { su as su16 } from "@tscircuit/circuit-json-util";
35817
- import * as THREE27 from "three";
35818
- var COPPER_COLOR2 = new THREE27.Color(...colors.copper);
35722
+ import * as THREE26 from "three";
35723
+ var COPPER_COLOR2 = new THREE26.Color(...colors.copper);
35819
35724
  function processSmtPadsForManifold(Manifold, circuitJson, pcbThickness, manifoldInstancesForCleanup, holeUnion, boardClipVolume) {
35820
35725
  const smtPadGeoms = [];
35821
35726
  const smtPads = su16(circuitJson).pcb_smtpad.list();
@@ -35854,7 +35759,7 @@ function processSmtPadsForManifold(Manifold, circuitJson, pcbThickness, manifold
35854
35759
 
35855
35760
  // src/utils/manifold/process-vias.ts
35856
35761
  import { su as su17 } from "@tscircuit/circuit-json-util";
35857
- import * as THREE28 from "three";
35762
+ import * as THREE27 from "three";
35858
35763
 
35859
35764
  // src/utils/via-geoms.ts
35860
35765
  function createViaCopper2({
@@ -35907,7 +35812,7 @@ function createViaCopper2({
35907
35812
  }
35908
35813
 
35909
35814
  // src/utils/manifold/process-vias.ts
35910
- var COPPER_COLOR3 = new THREE28.Color(...colors.copper);
35815
+ var COPPER_COLOR3 = new THREE27.Color(...colors.copper);
35911
35816
  function processViasForManifold(Manifold, circuitJson, pcbThickness, manifoldInstancesForCleanup, boardClipVolume) {
35912
35817
  const viaBoardDrills = [];
35913
35818
  const pcbVias = su17(circuitJson).pcb_via.list();
@@ -35958,6 +35863,397 @@ function processViasForManifold(Manifold, circuitJson, pcbThickness, manifoldIns
35958
35863
  return { viaBoardDrills, viaCopperGeoms };
35959
35864
  }
35960
35865
 
35866
+ // src/textures/create-copper-pour-texture-for-layer.ts
35867
+ import * as THREE28 from "three";
35868
+ import { CircuitToCanvasDrawer } from "circuit-to-canvas";
35869
+ function drawPolygon({
35870
+ ctx,
35871
+ points,
35872
+ canvasXFromPcb,
35873
+ canvasYFromPcb
35874
+ }) {
35875
+ if (points.length < 3) return;
35876
+ ctx.beginPath();
35877
+ points.forEach((point2, index2) => {
35878
+ const canvasX = canvasXFromPcb(point2[0]);
35879
+ const canvasY = canvasYFromPcb(point2[1]);
35880
+ if (index2 === 0) {
35881
+ ctx.moveTo(canvasX, canvasY);
35882
+ } else {
35883
+ ctx.lineTo(canvasX, canvasY);
35884
+ }
35885
+ });
35886
+ ctx.closePath();
35887
+ ctx.fill();
35888
+ }
35889
+ function drawBrepShape({
35890
+ ctx,
35891
+ pour,
35892
+ canvasXFromPcb,
35893
+ canvasYFromPcb
35894
+ }) {
35895
+ const brepShape = pour.brep_shape;
35896
+ if (!brepShape || !brepShape.outer_ring) return;
35897
+ const outerRingPoints = ringToPoints(brepShape.outer_ring, 32);
35898
+ if (outerRingPoints.length >= 3) {
35899
+ drawPolygon({
35900
+ ctx,
35901
+ points: outerRingPoints,
35902
+ canvasXFromPcb,
35903
+ canvasYFromPcb
35904
+ });
35905
+ }
35906
+ if (brepShape.inner_rings && brepShape.inner_rings.length > 0) {
35907
+ ctx.globalCompositeOperation = "destination-out";
35908
+ for (const innerRing of brepShape.inner_rings) {
35909
+ const innerRingPoints = ringToPoints(innerRing, 32);
35910
+ if (innerRingPoints.length >= 3) {
35911
+ drawPolygon({
35912
+ ctx,
35913
+ points: innerRingPoints,
35914
+ canvasXFromPcb,
35915
+ canvasYFromPcb
35916
+ });
35917
+ }
35918
+ }
35919
+ ctx.globalCompositeOperation = "source-over";
35920
+ }
35921
+ }
35922
+ function createCopperPourTextureForLayer({
35923
+ layer,
35924
+ circuitJson,
35925
+ boardData,
35926
+ traceTextureResolution = TRACE_TEXTURE_RESOLUTION
35927
+ }) {
35928
+ const copperPours = circuitJson.filter(
35929
+ (e) => e.type === "pcb_copper_pour"
35930
+ );
35931
+ const poursOnLayer = copperPours.filter((p) => p.layer === layer);
35932
+ if (poursOnLayer.length === 0) return null;
35933
+ const boardOutlineBounds = calculateOutlineBounds(boardData);
35934
+ const canvas = document.createElement("canvas");
35935
+ const canvasWidth = Math.floor(
35936
+ boardOutlineBounds.width * traceTextureResolution
35937
+ );
35938
+ const canvasHeight = Math.floor(
35939
+ boardOutlineBounds.height * traceTextureResolution
35940
+ );
35941
+ canvas.width = canvasWidth;
35942
+ canvas.height = canvasHeight;
35943
+ const ctx = canvas.getContext("2d");
35944
+ if (!ctx) return null;
35945
+ if (layer === "bottom") {
35946
+ ctx.translate(0, canvasHeight);
35947
+ ctx.scale(1, -1);
35948
+ }
35949
+ const canvasXFromPcb = (pcbX) => (pcbX - boardOutlineBounds.minX) * traceTextureResolution;
35950
+ const canvasYFromPcb = (pcbY) => (boardOutlineBounds.maxY - pcbY) * traceTextureResolution;
35951
+ const rectAndPolygonPours = poursOnLayer.filter(
35952
+ (pour) => pour.shape === "rect" || pour.shape === "polygon"
35953
+ );
35954
+ const brepPours = poursOnLayer.filter((pour) => pour.shape === "brep");
35955
+ if (rectAndPolygonPours.length > 0) {
35956
+ const drawer = new CircuitToCanvasDrawer(ctx);
35957
+ drawer.setCameraBounds({
35958
+ minX: boardOutlineBounds.minX,
35959
+ maxX: boardOutlineBounds.maxX,
35960
+ minY: boardOutlineBounds.minY,
35961
+ maxY: boardOutlineBounds.maxY
35962
+ });
35963
+ const coveredPours = rectAndPolygonPours.filter(
35964
+ (p) => p.covered_with_solder_mask !== false
35965
+ );
35966
+ const uncoveredPours = rectAndPolygonPours.filter(
35967
+ (p) => p.covered_with_solder_mask === false
35968
+ );
35969
+ const coveredColor = `rgb(${colors.fr4TracesWithMaskGreen.map((c) => c * 255).join(",")})`;
35970
+ const uncoveredColor = `rgb(${colors.copper.map((c) => c * 255).join(",")})`;
35971
+ if (coveredPours.length > 0) {
35972
+ drawer.configure({
35973
+ colorOverrides: {
35974
+ copper: {
35975
+ top: coveredColor,
35976
+ bottom: coveredColor,
35977
+ inner1: coveredColor,
35978
+ inner2: coveredColor,
35979
+ inner3: coveredColor,
35980
+ inner4: coveredColor,
35981
+ inner5: coveredColor,
35982
+ inner6: coveredColor
35983
+ }
35984
+ }
35985
+ });
35986
+ drawer.drawElements(coveredPours, { layers: [layer] });
35987
+ }
35988
+ if (uncoveredPours.length > 0) {
35989
+ drawer.configure({
35990
+ colorOverrides: {
35991
+ copper: {
35992
+ top: uncoveredColor,
35993
+ bottom: uncoveredColor,
35994
+ inner1: uncoveredColor,
35995
+ inner2: uncoveredColor,
35996
+ inner3: uncoveredColor,
35997
+ inner4: uncoveredColor,
35998
+ inner5: uncoveredColor,
35999
+ inner6: uncoveredColor
36000
+ }
36001
+ }
36002
+ });
36003
+ drawer.drawElements(uncoveredPours, { layers: [layer] });
36004
+ }
36005
+ }
36006
+ for (const pour of brepPours) {
36007
+ const covered = pour.covered_with_solder_mask !== false;
36008
+ const colorArr = covered ? colors.fr4TracesWithMaskGreen : colors.copper;
36009
+ const copperColor = `rgb(${colorArr[0] * 255}, ${colorArr[1] * 255}, ${colorArr[2] * 255})`;
36010
+ ctx.fillStyle = copperColor;
36011
+ drawBrepShape({ ctx, pour, canvasXFromPcb, canvasYFromPcb });
36012
+ }
36013
+ const texture = new THREE28.CanvasTexture(canvas);
36014
+ texture.generateMipmaps = true;
36015
+ texture.minFilter = THREE28.LinearMipmapLinearFilter;
36016
+ texture.magFilter = THREE28.LinearFilter;
36017
+ texture.anisotropy = 16;
36018
+ texture.needsUpdate = true;
36019
+ return texture;
36020
+ }
36021
+
36022
+ // src/textures/create-three-texture-meshes.ts
36023
+ import * as THREE29 from "three";
36024
+ function createTexturePlane(config, boardData) {
36025
+ const {
36026
+ texture,
36027
+ yOffset,
36028
+ isBottomLayer,
36029
+ textureType,
36030
+ usePolygonOffset = false,
36031
+ renderOrder = 0
36032
+ } = config;
36033
+ if (!texture) return null;
36034
+ const boardOutlineBounds = calculateOutlineBounds(boardData);
36035
+ const planeGeom = new THREE29.PlaneGeometry(
36036
+ boardOutlineBounds.width,
36037
+ boardOutlineBounds.height
36038
+ );
36039
+ const material = new THREE29.MeshBasicMaterial({
36040
+ map: texture,
36041
+ transparent: true,
36042
+ side: THREE29.DoubleSide,
36043
+ depthWrite: textureType === "panel-outlines",
36044
+ polygonOffset: usePolygonOffset,
36045
+ polygonOffsetFactor: usePolygonOffset ? -4 : 0,
36046
+ // Increased for better z-fighting prevention
36047
+ polygonOffsetUnits: usePolygonOffset ? -4 : 0
36048
+ });
36049
+ const mesh = new THREE29.Mesh(planeGeom, material);
36050
+ mesh.position.set(
36051
+ boardOutlineBounds.centerX,
36052
+ boardOutlineBounds.centerY,
36053
+ yOffset
36054
+ );
36055
+ if (isBottomLayer) {
36056
+ mesh.rotation.set(Math.PI, 0, 0);
36057
+ }
36058
+ mesh.name = `${isBottomLayer ? "bottom" : "top"}-${textureType}-texture-plane`;
36059
+ mesh.renderOrder = renderOrder;
36060
+ return mesh;
36061
+ }
36062
+ function createTextureMeshes(textures, boardData, pcbThickness) {
36063
+ const meshes = [];
36064
+ if (!textures || !boardData || pcbThickness === null) return meshes;
36065
+ const topTraceMesh = createTexturePlane(
36066
+ {
36067
+ texture: textures.topTrace,
36068
+ yOffset: pcbThickness / 2 + BOARD_SURFACE_OFFSET.traces,
36069
+ // Use consistent copper offset
36070
+ isBottomLayer: false,
36071
+ textureType: "trace",
36072
+ usePolygonOffset: false,
36073
+ renderOrder: 2
36074
+ // Render after soldermask
36075
+ },
36076
+ boardData
36077
+ );
36078
+ if (topTraceMesh) meshes.push(topTraceMesh);
36079
+ const topTraceWithMaskMesh = createTexturePlane(
36080
+ {
36081
+ texture: textures.topTraceWithMask,
36082
+ yOffset: pcbThickness / 2 + BOARD_SURFACE_OFFSET.traces,
36083
+ isBottomLayer: false,
36084
+ textureType: "trace-with-mask",
36085
+ usePolygonOffset: false,
36086
+ renderOrder: 2
36087
+ // Render after soldermask
36088
+ },
36089
+ boardData
36090
+ );
36091
+ if (topTraceWithMaskMesh) meshes.push(topTraceWithMaskMesh);
36092
+ const topSilkscreenMesh = createTexturePlane(
36093
+ {
36094
+ texture: textures.topSilkscreen,
36095
+ yOffset: pcbThickness / 2 + 3e-3,
36096
+ // Slightly above soldermask
36097
+ isBottomLayer: false,
36098
+ textureType: "silkscreen",
36099
+ usePolygonOffset: false,
36100
+ renderOrder: 3
36101
+ // Render after traces
36102
+ },
36103
+ boardData
36104
+ );
36105
+ if (topSilkscreenMesh) meshes.push(topSilkscreenMesh);
36106
+ const bottomTraceMesh = createTexturePlane(
36107
+ {
36108
+ texture: textures.bottomTrace,
36109
+ yOffset: -pcbThickness / 2 - BOARD_SURFACE_OFFSET.traces,
36110
+ // Use consistent copper offset
36111
+ isBottomLayer: true,
36112
+ textureType: "trace",
36113
+ usePolygonOffset: false,
36114
+ renderOrder: 2
36115
+ // Render after soldermask
36116
+ },
36117
+ boardData
36118
+ );
36119
+ if (bottomTraceMesh) meshes.push(bottomTraceMesh);
36120
+ const bottomTraceWithMaskMesh = createTexturePlane(
36121
+ {
36122
+ texture: textures.bottomTraceWithMask,
36123
+ yOffset: -pcbThickness / 2 - BOARD_SURFACE_OFFSET.traces,
36124
+ isBottomLayer: true,
36125
+ textureType: "trace-with-mask",
36126
+ usePolygonOffset: false,
36127
+ renderOrder: 2
36128
+ // Render after soldermask
36129
+ },
36130
+ boardData
36131
+ );
36132
+ if (bottomTraceWithMaskMesh) meshes.push(bottomTraceWithMaskMesh);
36133
+ const bottomSilkscreenMesh = createTexturePlane(
36134
+ {
36135
+ texture: textures.bottomSilkscreen,
36136
+ yOffset: -pcbThickness / 2 - 3e-3,
36137
+ isBottomLayer: true,
36138
+ textureType: "silkscreen",
36139
+ usePolygonOffset: false,
36140
+ renderOrder: 3
36141
+ // Render after traces
36142
+ },
36143
+ boardData
36144
+ );
36145
+ if (bottomSilkscreenMesh) meshes.push(bottomSilkscreenMesh);
36146
+ const topSoldermaskMesh = createTexturePlane(
36147
+ {
36148
+ texture: textures.topSoldermask,
36149
+ yOffset: pcbThickness / 2 + 1e-3,
36150
+ // Just above board surface
36151
+ isBottomLayer: false,
36152
+ textureType: "soldermask",
36153
+ usePolygonOffset: true,
36154
+ // Enable polygon offset
36155
+ renderOrder: 1
36156
+ // Render after board (renderOrder)
36157
+ },
36158
+ boardData
36159
+ );
36160
+ if (topSoldermaskMesh) meshes.push(topSoldermaskMesh);
36161
+ const bottomSoldermaskMesh = createTexturePlane(
36162
+ {
36163
+ texture: textures.bottomSoldermask,
36164
+ yOffset: -pcbThickness / 2 - 1e-3,
36165
+ // Just below board surface (bottom side)
36166
+ isBottomLayer: true,
36167
+ textureType: "soldermask",
36168
+ usePolygonOffset: true,
36169
+ // Enable polygon offset
36170
+ renderOrder: 1
36171
+ // Render after board (renderOrder)
36172
+ },
36173
+ boardData
36174
+ );
36175
+ if (bottomSoldermaskMesh) meshes.push(bottomSoldermaskMesh);
36176
+ const topCopperTextMesh = createTexturePlane(
36177
+ {
36178
+ texture: textures.topCopperText,
36179
+ yOffset: pcbThickness / 2 + BOARD_SURFACE_OFFSET.copper,
36180
+ isBottomLayer: false,
36181
+ textureType: "copper-text",
36182
+ usePolygonOffset: false,
36183
+ renderOrder: 2
36184
+ // Render after soldermask
36185
+ },
36186
+ boardData
36187
+ );
36188
+ if (topCopperTextMesh) meshes.push(topCopperTextMesh);
36189
+ const bottomCopperTextMesh = createTexturePlane(
36190
+ {
36191
+ texture: textures.bottomCopperText,
36192
+ yOffset: -pcbThickness / 2 - BOARD_SURFACE_OFFSET.copper,
36193
+ isBottomLayer: true,
36194
+ textureType: "copper-text",
36195
+ usePolygonOffset: false,
36196
+ renderOrder: 2
36197
+ // Render after soldermask
36198
+ },
36199
+ boardData
36200
+ );
36201
+ if (bottomCopperTextMesh) meshes.push(bottomCopperTextMesh);
36202
+ const topCopperMesh = createTexturePlane(
36203
+ {
36204
+ texture: textures.topCopper,
36205
+ yOffset: pcbThickness / 2 + BOARD_SURFACE_OFFSET.copper,
36206
+ isBottomLayer: false,
36207
+ textureType: "copper",
36208
+ usePolygonOffset: false,
36209
+ renderOrder: 2
36210
+ // Render after soldermask
36211
+ },
36212
+ boardData
36213
+ );
36214
+ if (topCopperMesh) meshes.push(topCopperMesh);
36215
+ const bottomCopperMesh = createTexturePlane(
36216
+ {
36217
+ texture: textures.bottomCopper,
36218
+ yOffset: -pcbThickness / 2 - BOARD_SURFACE_OFFSET.copper,
36219
+ isBottomLayer: true,
36220
+ textureType: "copper",
36221
+ usePolygonOffset: false,
36222
+ renderOrder: 2
36223
+ // Render after soldermask
36224
+ },
36225
+ boardData
36226
+ );
36227
+ if (bottomCopperMesh) meshes.push(bottomCopperMesh);
36228
+ const topPanelOutlinesMesh = createTexturePlane(
36229
+ {
36230
+ texture: textures.topPanelOutlines,
36231
+ yOffset: pcbThickness / 2 + 4e-3,
36232
+ // Above silkscreen
36233
+ isBottomLayer: false,
36234
+ textureType: "panel-outlines",
36235
+ usePolygonOffset: false,
36236
+ renderOrder: 4
36237
+ },
36238
+ boardData
36239
+ );
36240
+ if (topPanelOutlinesMesh) meshes.push(topPanelOutlinesMesh);
36241
+ const bottomPanelOutlinesMesh = createTexturePlane(
36242
+ {
36243
+ texture: textures.bottomPanelOutlines,
36244
+ yOffset: -pcbThickness / 2 - 4e-3,
36245
+ // Below bottom silkscreen
36246
+ isBottomLayer: true,
36247
+ textureType: "panel-outlines",
36248
+ usePolygonOffset: false,
36249
+ renderOrder: 4
36250
+ },
36251
+ boardData
36252
+ );
36253
+ if (bottomPanelOutlinesMesh) meshes.push(bottomPanelOutlinesMesh);
36254
+ return meshes;
36255
+ }
36256
+
35961
36257
  // src/hooks/useManifoldBoardBuilder.ts
35962
36258
  var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
35963
36259
  const [geoms, setGeoms] = useState14(null);
@@ -36027,7 +36323,7 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
36027
36323
  manifoldInstancesForCleanup.current = [];
36028
36324
  let boardManifold = null;
36029
36325
  const currentGeoms = {};
36030
- const currentTextures = {};
36326
+ const layerTextureMap = {};
36031
36327
  try {
36032
36328
  const currentPcbThickness = boardData.thickness || 1.6;
36033
36329
  setPcbThickness(currentPcbThickness);
@@ -36126,7 +36422,7 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
36126
36422
  {
36127
36423
  key: "plated-holes-union",
36128
36424
  geometry: cutPlatedGeom,
36129
- color: new THREE29.Color(
36425
+ color: new THREE30.Color(
36130
36426
  colors.copper[0],
36131
36427
  colors.copper[1],
36132
36428
  colors.copper[2]
@@ -36156,7 +36452,7 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
36156
36452
  const matColorArray = boardMaterialColors[boardData.material] ?? colors.fr4Tan;
36157
36453
  currentGeoms.board = {
36158
36454
  geometry: finalBoardGeom,
36159
- color: new THREE29.Color(
36455
+ color: new THREE30.Color(
36160
36456
  matColorArray[0],
36161
36457
  matColorArray[1],
36162
36458
  matColorArray[2]
@@ -36174,28 +36470,17 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
36174
36470
  boardClipVolume
36175
36471
  );
36176
36472
  currentGeoms.smtPads = smtPadGeoms;
36177
- const { copperPourGeoms } = processCopperPoursForManifold(
36178
- Manifold,
36179
- CrossSection,
36180
- circuitJson,
36181
- currentPcbThickness,
36182
- manifoldInstancesForCleanup.current,
36183
- boardData.material,
36184
- holeUnion,
36185
- boardClipVolume
36186
- );
36187
- currentGeoms.copperPours = copperPourGeoms;
36188
36473
  setGeoms(currentGeoms);
36189
36474
  const traceColorWithoutMaskArr = colors.fr4TracesWithoutMaskTan;
36190
36475
  const traceColorWithoutMask = `rgb(${Math.round(traceColorWithoutMaskArr[0] * 255)}, ${Math.round(traceColorWithoutMaskArr[1] * 255)}, ${Math.round(traceColorWithoutMaskArr[2] * 255)})`;
36191
- currentTextures.topTrace = createTraceTextureForLayer({
36476
+ layerTextureMap.topTrace = createTraceTextureForLayer({
36192
36477
  layer: "top",
36193
36478
  circuitJson,
36194
36479
  boardData,
36195
36480
  traceColor: traceColorWithoutMask,
36196
36481
  traceTextureResolution: TRACE_TEXTURE_RESOLUTION
36197
36482
  });
36198
- currentTextures.bottomTrace = createTraceTextureForLayer({
36483
+ layerTextureMap.bottomTrace = createTraceTextureForLayer({
36199
36484
  layer: "bottom",
36200
36485
  circuitJson,
36201
36486
  boardData,
@@ -36204,14 +36489,14 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
36204
36489
  });
36205
36490
  const traceColorWithMaskArr = colors.fr4TracesWithMaskGreen;
36206
36491
  const traceColorWithMask = `rgb(${Math.round(traceColorWithMaskArr[0] * 255)}, ${Math.round(traceColorWithMaskArr[1] * 255)}, ${Math.round(traceColorWithMaskArr[2] * 255)})`;
36207
- currentTextures.topTraceWithMask = createTraceTextureForLayer({
36492
+ layerTextureMap.topTraceWithMask = createTraceTextureForLayer({
36208
36493
  layer: "top",
36209
36494
  circuitJson,
36210
36495
  boardData,
36211
36496
  traceColor: traceColorWithMask,
36212
36497
  traceTextureResolution: TRACE_TEXTURE_RESOLUTION
36213
36498
  });
36214
- currentTextures.bottomTraceWithMask = createTraceTextureForLayer({
36499
+ layerTextureMap.bottomTraceWithMask = createTraceTextureForLayer({
36215
36500
  layer: "bottom",
36216
36501
  circuitJson,
36217
36502
  boardData,
@@ -36219,14 +36504,14 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
36219
36504
  traceTextureResolution: TRACE_TEXTURE_RESOLUTION
36220
36505
  });
36221
36506
  const silkscreenColor = "rgb(255,255,255)";
36222
- currentTextures.topSilkscreen = createSilkscreenTextureForLayer({
36507
+ layerTextureMap.topSilkscreen = createSilkscreenTextureForLayer({
36223
36508
  layer: "top",
36224
36509
  circuitJson,
36225
36510
  boardData,
36226
36511
  silkscreenColor,
36227
36512
  traceTextureResolution: TRACE_TEXTURE_RESOLUTION
36228
36513
  });
36229
- currentTextures.bottomSilkscreen = createSilkscreenTextureForLayer({
36514
+ layerTextureMap.bottomSilkscreen = createSilkscreenTextureForLayer({
36230
36515
  layer: "bottom",
36231
36516
  circuitJson,
36232
36517
  boardData,
@@ -36235,14 +36520,14 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
36235
36520
  });
36236
36521
  const soldermaskColorArr = soldermaskColors[boardData.material] ?? colors.fr4SolderMaskGreen;
36237
36522
  const soldermaskColor = `rgb(${Math.round(soldermaskColorArr[0] * 255)}, ${Math.round(soldermaskColorArr[1] * 255)}, ${Math.round(soldermaskColorArr[2] * 255)})`;
36238
- currentTextures.topSoldermask = createSoldermaskTextureForLayer({
36523
+ layerTextureMap.topSoldermask = createSoldermaskTextureForLayer({
36239
36524
  layer: "top",
36240
36525
  circuitJson,
36241
36526
  boardData,
36242
36527
  soldermaskColor,
36243
36528
  traceTextureResolution: TRACE_TEXTURE_RESOLUTION
36244
36529
  });
36245
- currentTextures.bottomSoldermask = createSoldermaskTextureForLayer({
36530
+ layerTextureMap.bottomSoldermask = createSoldermaskTextureForLayer({
36246
36531
  layer: "bottom",
36247
36532
  circuitJson,
36248
36533
  boardData,
@@ -36251,33 +36536,45 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
36251
36536
  });
36252
36537
  const copperColorArr = colors.copper;
36253
36538
  const copperColor = `rgb(${Math.round(copperColorArr[0] * 255)}, ${Math.round(copperColorArr[1] * 255)}, ${Math.round(copperColorArr[2] * 255)})`;
36254
- currentTextures.topCopperText = createCopperTextTextureForLayer({
36539
+ layerTextureMap.topCopperText = createCopperTextTextureForLayer({
36255
36540
  layer: "top",
36256
36541
  circuitJson,
36257
36542
  boardData,
36258
36543
  copperColor,
36259
36544
  traceTextureResolution: TRACE_TEXTURE_RESOLUTION
36260
36545
  });
36261
- currentTextures.bottomCopperText = createCopperTextTextureForLayer({
36546
+ layerTextureMap.bottomCopperText = createCopperTextTextureForLayer({
36262
36547
  layer: "bottom",
36263
36548
  circuitJson,
36264
36549
  boardData,
36265
36550
  copperColor,
36266
36551
  traceTextureResolution: TRACE_TEXTURE_RESOLUTION
36267
36552
  });
36268
- currentTextures.topPanelOutlines = createPanelOutlineTextureForLayer({
36553
+ layerTextureMap.topPanelOutlines = createPanelOutlineTextureForLayer({
36269
36554
  layer: "top",
36270
36555
  circuitJson,
36271
36556
  panelData: boardData,
36272
36557
  traceTextureResolution: TRACE_TEXTURE_RESOLUTION
36273
36558
  });
36274
- currentTextures.bottomPanelOutlines = createPanelOutlineTextureForLayer({
36559
+ layerTextureMap.bottomPanelOutlines = createPanelOutlineTextureForLayer({
36275
36560
  layer: "bottom",
36276
36561
  circuitJson,
36277
36562
  panelData: boardData,
36278
36563
  traceTextureResolution: TRACE_TEXTURE_RESOLUTION
36279
36564
  });
36280
- setTextures(currentTextures);
36565
+ layerTextureMap.topCopper = createCopperPourTextureForLayer({
36566
+ layer: "top",
36567
+ circuitJson,
36568
+ boardData,
36569
+ traceTextureResolution: TRACE_TEXTURE_RESOLUTION
36570
+ });
36571
+ layerTextureMap.bottomCopper = createCopperPourTextureForLayer({
36572
+ layer: "bottom",
36573
+ circuitJson,
36574
+ boardData,
36575
+ traceTextureResolution: TRACE_TEXTURE_RESOLUTION
36576
+ });
36577
+ setTextures(layerTextureMap);
36281
36578
  } catch (e) {
36282
36579
  console.error("Error processing geometry with Manifold in hook:", e);
36283
36580
  setError(
@@ -36305,11 +36602,11 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
36305
36602
  };
36306
36603
 
36307
36604
  // src/utils/manifold/create-three-geometry-meshes.ts
36308
- import * as THREE31 from "three";
36605
+ import * as THREE32 from "three";
36309
36606
 
36310
36607
  // src/utils/create-board-material.ts
36311
- import * as THREE30 from "three";
36312
- var DEFAULT_SIDE = THREE30.DoubleSide;
36608
+ import * as THREE31 from "three";
36609
+ var DEFAULT_SIDE = THREE31.DoubleSide;
36313
36610
  var createBoardMaterial = ({
36314
36611
  material,
36315
36612
  color,
@@ -36317,7 +36614,7 @@ var createBoardMaterial = ({
36317
36614
  isFaux = false
36318
36615
  }) => {
36319
36616
  if (material === "fr4") {
36320
- return new THREE30.MeshPhysicalMaterial({
36617
+ return new THREE31.MeshPhysicalMaterial({
36321
36618
  color,
36322
36619
  side,
36323
36620
  metalness: 0,
@@ -36331,7 +36628,7 @@ var createBoardMaterial = ({
36331
36628
  flatShading: true
36332
36629
  });
36333
36630
  }
36334
- return new THREE30.MeshStandardMaterial({
36631
+ return new THREE31.MeshStandardMaterial({
36335
36632
  color,
36336
36633
  side,
36337
36634
  flatShading: true,
@@ -36347,12 +36644,12 @@ function createGeometryMeshes(geoms) {
36347
36644
  const meshes = [];
36348
36645
  if (!geoms) return meshes;
36349
36646
  if (geoms.board && geoms.board.geometry) {
36350
- const mesh = new THREE31.Mesh(
36647
+ const mesh = new THREE32.Mesh(
36351
36648
  geoms.board.geometry,
36352
36649
  createBoardMaterial({
36353
36650
  material: geoms.board.material,
36354
36651
  color: geoms.board.color,
36355
- side: THREE31.DoubleSide,
36652
+ side: THREE32.DoubleSide,
36356
36653
  isFaux: geoms.board.isFaux
36357
36654
  })
36358
36655
  );
@@ -36362,11 +36659,11 @@ function createGeometryMeshes(geoms) {
36362
36659
  const createMeshesFromArray = (geomArray) => {
36363
36660
  if (geomArray) {
36364
36661
  geomArray.forEach((comp) => {
36365
- const mesh = new THREE31.Mesh(
36662
+ const mesh = new THREE32.Mesh(
36366
36663
  comp.geometry,
36367
- new THREE31.MeshStandardMaterial({
36664
+ new THREE32.MeshStandardMaterial({
36368
36665
  color: comp.color,
36369
- side: THREE31.DoubleSide,
36666
+ side: THREE32.DoubleSide,
36370
36667
  flatShading: true,
36371
36668
  // Consistent with board
36372
36669
  polygonOffset: true,
@@ -36382,164 +36679,6 @@ function createGeometryMeshes(geoms) {
36382
36679
  createMeshesFromArray(geoms.platedHoles);
36383
36680
  createMeshesFromArray(geoms.smtPads);
36384
36681
  createMeshesFromArray(geoms.vias);
36385
- createMeshesFromArray(geoms.copperPours);
36386
- return meshes;
36387
- }
36388
-
36389
- // src/utils/manifold/create-three-texture-meshes.ts
36390
- import * as THREE32 from "three";
36391
- function createTextureMeshes(textures, boardData, pcbThickness) {
36392
- const meshes = [];
36393
- if (!textures || !boardData || pcbThickness === null) return meshes;
36394
- const createTexturePlane = (texture, yOffset, isBottomLayer, keySuffix, usePolygonOffset = false, renderOrder = 0) => {
36395
- if (!texture) return null;
36396
- const planeGeom = new THREE32.PlaneGeometry(boardData.width, boardData.height);
36397
- const material = new THREE32.MeshBasicMaterial({
36398
- map: texture,
36399
- transparent: true,
36400
- side: THREE32.DoubleSide,
36401
- depthWrite: keySuffix === "panel-outlines",
36402
- polygonOffset: usePolygonOffset,
36403
- polygonOffsetFactor: usePolygonOffset ? -4 : 0,
36404
- // Increased for better z-fighting prevention
36405
- polygonOffsetUnits: usePolygonOffset ? -4 : 0
36406
- });
36407
- const mesh = new THREE32.Mesh(planeGeom, material);
36408
- mesh.position.set(boardData.center.x, boardData.center.y, yOffset);
36409
- if (isBottomLayer) {
36410
- mesh.rotation.set(Math.PI, 0, 0);
36411
- }
36412
- mesh.name = `${isBottomLayer ? "bottom" : "top"}-${keySuffix}-texture-plane`;
36413
- mesh.renderOrder = renderOrder;
36414
- return mesh;
36415
- };
36416
- const topTraceMesh = createTexturePlane(
36417
- textures.topTrace,
36418
- pcbThickness / 2 + BOARD_SURFACE_OFFSET.traces,
36419
- // Use consistent copper offset
36420
- false,
36421
- "trace",
36422
- false,
36423
- 2
36424
- // Render after soldermask
36425
- );
36426
- if (topTraceMesh) meshes.push(topTraceMesh);
36427
- const topTraceWithMaskMesh = createTexturePlane(
36428
- textures.topTraceWithMask,
36429
- pcbThickness / 2 + BOARD_SURFACE_OFFSET.traces,
36430
- false,
36431
- "trace-with-mask",
36432
- false,
36433
- 2
36434
- // Render after soldermask
36435
- );
36436
- if (topTraceWithMaskMesh) meshes.push(topTraceWithMaskMesh);
36437
- const topSilkscreenMesh = createTexturePlane(
36438
- textures.topSilkscreen,
36439
- pcbThickness / 2 + 3e-3,
36440
- // Slightly above soldermask
36441
- false,
36442
- "silkscreen",
36443
- false,
36444
- 3
36445
- // Render after traces
36446
- );
36447
- if (topSilkscreenMesh) meshes.push(topSilkscreenMesh);
36448
- const bottomTraceMesh = createTexturePlane(
36449
- textures.bottomTrace,
36450
- -pcbThickness / 2 - BOARD_SURFACE_OFFSET.traces,
36451
- // Use consistent copper offset
36452
- true,
36453
- "trace",
36454
- false,
36455
- 2
36456
- // Render after soldermask
36457
- );
36458
- if (bottomTraceMesh) meshes.push(bottomTraceMesh);
36459
- const bottomTraceWithMaskMesh = createTexturePlane(
36460
- textures.bottomTraceWithMask,
36461
- -pcbThickness / 2 - BOARD_SURFACE_OFFSET.traces,
36462
- true,
36463
- "trace-with-mask",
36464
- false,
36465
- 2
36466
- // Render after soldermask
36467
- );
36468
- if (bottomTraceWithMaskMesh) meshes.push(bottomTraceWithMaskMesh);
36469
- const bottomSilkscreenMesh = createTexturePlane(
36470
- textures.bottomSilkscreen,
36471
- -pcbThickness / 2 - 3e-3,
36472
- true,
36473
- "silkscreen",
36474
- false,
36475
- 3
36476
- // Render after traces
36477
- );
36478
- if (bottomSilkscreenMesh) meshes.push(bottomSilkscreenMesh);
36479
- const topSoldermaskMesh = createTexturePlane(
36480
- textures.topSoldermask,
36481
- pcbThickness / 2 + 1e-3,
36482
- // Just above board surface
36483
- false,
36484
- "soldermask",
36485
- true,
36486
- // Enable polygon offset
36487
- 1
36488
- // Render after board (renderOrder)
36489
- );
36490
- if (topSoldermaskMesh) meshes.push(topSoldermaskMesh);
36491
- const bottomSoldermaskMesh = createTexturePlane(
36492
- textures.bottomSoldermask,
36493
- -pcbThickness / 2 - 1e-3,
36494
- // Just below board surface (bottom side)
36495
- true,
36496
- "soldermask",
36497
- true,
36498
- // Enable polygon offset
36499
- 1
36500
- // Render after board (renderOrder)
36501
- );
36502
- if (bottomSoldermaskMesh) meshes.push(bottomSoldermaskMesh);
36503
- const topCopperTextMesh = createTexturePlane(
36504
- textures.topCopperText,
36505
- pcbThickness / 2 + BOARD_SURFACE_OFFSET.copper,
36506
- false,
36507
- "copper-text",
36508
- false,
36509
- 2
36510
- // Render after soldermask
36511
- );
36512
- if (topCopperTextMesh) meshes.push(topCopperTextMesh);
36513
- const bottomCopperTextMesh = createTexturePlane(
36514
- textures.bottomCopperText,
36515
- -pcbThickness / 2 - BOARD_SURFACE_OFFSET.copper,
36516
- true,
36517
- "copper-text",
36518
- false,
36519
- 2
36520
- // Render after soldermask
36521
- );
36522
- if (bottomCopperTextMesh) meshes.push(bottomCopperTextMesh);
36523
- const topPanelOutlinesMesh = createTexturePlane(
36524
- textures.topPanelOutlines,
36525
- pcbThickness / 2 + 4e-3,
36526
- // Above silkscreen
36527
- false,
36528
- "panel-outlines",
36529
- false,
36530
- 4
36531
- );
36532
- if (topPanelOutlinesMesh) meshes.push(topPanelOutlinesMesh);
36533
- const bottomPanelOutlinesMesh = createTexturePlane(
36534
- textures.bottomPanelOutlines,
36535
- -pcbThickness / 2 - 4e-3,
36536
- // Below bottom silkscreen
36537
- true,
36538
- "panel-outlines",
36539
- false,
36540
- 4
36541
- );
36542
- if (bottomPanelOutlinesMesh) meshes.push(bottomPanelOutlinesMesh);
36543
36682
  return meshes;
36544
36683
  }
36545
36684
 
@@ -36567,8 +36706,6 @@ var BoardMeshes = ({
36567
36706
  }
36568
36707
  } else if (mesh.name.includes("plated_hole") || mesh.name.includes("via")) {
36569
36708
  shouldShow = visibility.topCopper || visibility.bottomCopper;
36570
- } else if (mesh.name.includes("copper_pour")) {
36571
- shouldShow = visibility.topCopper || visibility.bottomCopper;
36572
36709
  }
36573
36710
  if (shouldShow) {
36574
36711
  rootObject.add(mesh);
@@ -36596,6 +36733,10 @@ var BoardMeshes = ({
36596
36733
  shouldShow = visibility.topCopper;
36597
36734
  } else if (mesh.name.includes("bottom-copper-text")) {
36598
36735
  shouldShow = visibility.bottomCopper;
36736
+ } else if (mesh.name.includes("top-copper")) {
36737
+ shouldShow = visibility.topCopper;
36738
+ } else if (mesh.name.includes("bottom-copper")) {
36739
+ shouldShow = visibility.bottomCopper;
36599
36740
  } else if (mesh.name.includes("panel-outlines")) {
36600
36741
  shouldShow = visibility.boardBody;
36601
36742
  }
@@ -38108,7 +38249,7 @@ var oppositeAlignmentMap = {
38108
38249
  start: "end",
38109
38250
  end: "start"
38110
38251
  };
38111
- function clamp(start, value, end) {
38252
+ function clamp2(start, value, end) {
38112
38253
  return max(start, min(value, end));
38113
38254
  }
38114
38255
  function evaluate(value, param) {
@@ -38461,7 +38602,7 @@ var arrow = (options) => ({
38461
38602
  const min$1 = minPadding;
38462
38603
  const max2 = clientSize - arrowDimensions[length2] - maxPadding;
38463
38604
  const center = clientSize / 2 - arrowDimensions[length2] / 2 + centerToReference;
38464
- const offset4 = clamp(min$1, center, max2);
38605
+ const offset4 = clamp2(min$1, center, max2);
38465
38606
  const shouldAddOffset = !middlewareData.arrow && getAlignment(placement) != null && center !== offset4 && rects.reference[length2] / 2 - (center < min$1 ? minPadding : maxPadding) - arrowDimensions[length2] / 2 < 0;
38466
38607
  const alignmentOffset = shouldAddOffset ? center < min$1 ? center - min$1 : center - max2 : 0;
38467
38608
  return {
@@ -38758,14 +38899,14 @@ var shift = function(options) {
38758
38899
  const maxSide = mainAxis === "y" ? "bottom" : "right";
38759
38900
  const min2 = mainAxisCoord + overflow[minSide];
38760
38901
  const max2 = mainAxisCoord - overflow[maxSide];
38761
- mainAxisCoord = clamp(min2, mainAxisCoord, max2);
38902
+ mainAxisCoord = clamp2(min2, mainAxisCoord, max2);
38762
38903
  }
38763
38904
  if (checkCrossAxis) {
38764
38905
  const minSide = crossAxis === "y" ? "top" : "left";
38765
38906
  const maxSide = crossAxis === "y" ? "bottom" : "right";
38766
38907
  const min2 = crossAxisCoord + overflow[minSide];
38767
38908
  const max2 = crossAxisCoord - overflow[maxSide];
38768
- crossAxisCoord = clamp(min2, crossAxisCoord, max2);
38909
+ crossAxisCoord = clamp2(min2, crossAxisCoord, max2);
38769
38910
  }
38770
38911
  const limitedCoords = limiter.fn({
38771
38912
  ...state,
@@ -40470,7 +40611,7 @@ RovingFocusGroup.displayName = GROUP_NAME;
40470
40611
  var RovingFocusGroupImpl = React34.forwardRef((props, forwardedRef) => {
40471
40612
  const {
40472
40613
  __scopeRovingFocusGroup,
40473
- orientation,
40614
+ orientation: orientation2,
40474
40615
  loop = false,
40475
40616
  dir,
40476
40617
  currentTabStopId: currentTabStopIdProp,
@@ -40505,7 +40646,7 @@ var RovingFocusGroupImpl = React34.forwardRef((props, forwardedRef) => {
40505
40646
  RovingFocusProvider,
40506
40647
  {
40507
40648
  scope: __scopeRovingFocusGroup,
40508
- orientation,
40649
+ orientation: orientation2,
40509
40650
  dir: direction,
40510
40651
  loop,
40511
40652
  currentTabStopId,
@@ -40526,7 +40667,7 @@ var RovingFocusGroupImpl = React34.forwardRef((props, forwardedRef) => {
40526
40667
  Primitive.div,
40527
40668
  {
40528
40669
  tabIndex: isTabbingBackOut || focusableItemsCount === 0 ? -1 : 0,
40529
- "data-orientation": orientation,
40670
+ "data-orientation": orientation2,
40530
40671
  ...groupProps,
40531
40672
  ref: composedRefs,
40532
40673
  style: { outline: "none", ...props.style },
@@ -40642,10 +40783,10 @@ function getDirectionAwareKey(key, dir) {
40642
40783
  if (dir !== "rtl") return key;
40643
40784
  return key === "ArrowLeft" ? "ArrowRight" : key === "ArrowRight" ? "ArrowLeft" : key;
40644
40785
  }
40645
- function getFocusIntent(event, orientation, dir) {
40786
+ function getFocusIntent(event, orientation2, dir) {
40646
40787
  const key = getDirectionAwareKey(event.key, dir);
40647
- if (orientation === "vertical" && ["ArrowLeft", "ArrowRight"].includes(key)) return void 0;
40648
- if (orientation === "horizontal" && ["ArrowUp", "ArrowDown"].includes(key)) return void 0;
40788
+ if (orientation2 === "vertical" && ["ArrowLeft", "ArrowRight"].includes(key)) return void 0;
40789
+ if (orientation2 === "horizontal" && ["ArrowUp", "ArrowDown"].includes(key)) return void 0;
40649
40790
  return MAP_KEY_TO_FOCUS_INTENT[key];
40650
40791
  }
40651
40792
  function focusFirst2(candidates, preventScroll = false) {