@tscircuit/3d-viewer 0.0.519 → 0.0.521

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +223 -556
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -9928,7 +9928,7 @@ var require_vectorText = __commonJS({
9928
9928
  }
9929
9929
  return line;
9930
9930
  };
9931
- var vectorText3 = (options, text) => {
9931
+ var vectorText2 = (options, text) => {
9932
9932
  const {
9933
9933
  xOffset,
9934
9934
  yOffset,
@@ -9985,7 +9985,7 @@ var require_vectorText = __commonJS({
9985
9985
  }
9986
9986
  return output;
9987
9987
  };
9988
- module.exports = vectorText3;
9988
+ module.exports = vectorText2;
9989
9989
  }
9990
9990
  });
9991
9991
 
@@ -14248,7 +14248,7 @@ import { useState as useState36, useCallback as useCallback21, useRef as useRef2
14248
14248
  import * as THREE36 from "three";
14249
14249
 
14250
14250
  // src/CadViewerJscad.tsx
14251
- import { su as su12 } from "@tscircuit/circuit-json-util";
14251
+ import { su as su11 } from "@tscircuit/circuit-json-util";
14252
14252
  import { forwardRef as forwardRef3, useMemo as useMemo20 } from "react";
14253
14253
 
14254
14254
  // src/AnyCadComponent.tsx
@@ -28483,7 +28483,7 @@ import * as THREE16 from "three";
28483
28483
  // package.json
28484
28484
  var package_default = {
28485
28485
  name: "@tscircuit/3d-viewer",
28486
- version: "0.0.518",
28486
+ version: "0.0.520",
28487
28487
  main: "./dist/index.js",
28488
28488
  module: "./dist/index.js",
28489
28489
  type: "module",
@@ -28513,7 +28513,7 @@ var package_default = {
28513
28513
  "@jscad/regl-renderer": "^2.6.12",
28514
28514
  "@jscad/stl-serializer": "^2.1.20",
28515
28515
  "circuit-json": "^0.0.372",
28516
- "circuit-to-canvas": "^0.0.80",
28516
+ "circuit-to-canvas": "^0.0.81",
28517
28517
  "react-hot-toast": "^2.6.0",
28518
28518
  three: "^0.165.0",
28519
28519
  "three-stdlib": "^2.36.0",
@@ -31448,7 +31448,7 @@ var ThreeErrorBoundary = class extends React11.Component {
31448
31448
  };
31449
31449
 
31450
31450
  // src/three-components/JscadBoardTextures.tsx
31451
- import { su as su9 } from "@tscircuit/circuit-json-util";
31451
+ import { su as su8 } from "@tscircuit/circuit-json-util";
31452
31452
  import { useEffect as useEffect23, useMemo as useMemo19 } from "react";
31453
31453
 
31454
31454
  // src/textures/create-combined-board-textures.ts
@@ -32166,467 +32166,9 @@ function createPanelOutlineTextureForLayer({
32166
32166
  return texture;
32167
32167
  }
32168
32168
 
32169
- // src/utils/silkscreen-texture.ts
32170
- var import_text2 = __toESM(require_text(), 1);
32169
+ // src/utils/trace-texture.ts
32171
32170
  import * as THREE22 from "three";
32172
32171
  import { su as su7 } from "@tscircuit/circuit-json-util";
32173
-
32174
- // src/utils/units.ts
32175
- var MM_PER_INCH = 25.4;
32176
- var MM_PER_MIL = MM_PER_INCH / 1e3;
32177
- var dimensionRegex = /^\s*(-?\d*(?:\.\d+)?)(?:\s*(mm|mil|inch|in|"))?\s*$/i;
32178
- function normalizeUnit(unit) {
32179
- if (!unit) return void 0;
32180
- const normalized = unit.trim().toLowerCase();
32181
- if (normalized === '"') return "in";
32182
- if (normalized === "inch") return "in";
32183
- return normalized;
32184
- }
32185
- function parseDimensionToMm(value) {
32186
- if (value === null || value === void 0) return void 0;
32187
- if (typeof value === "number") {
32188
- return Number.isFinite(value) ? value : void 0;
32189
- }
32190
- if (typeof value !== "string") return void 0;
32191
- const trimmed = value.trim();
32192
- if (trimmed.length === 0) return void 0;
32193
- const match = trimmed.match(dimensionRegex);
32194
- if (!match) {
32195
- const numeric = Number.parseFloat(trimmed);
32196
- return Number.isFinite(numeric) ? numeric : void 0;
32197
- }
32198
- const [, magnitudeRaw, unitRaw] = match;
32199
- const magnitude = Number.parseFloat(magnitudeRaw || "0");
32200
- if (!Number.isFinite(magnitude)) return void 0;
32201
- const unit = normalizeUnit(unitRaw);
32202
- switch (unit) {
32203
- case "mil":
32204
- return magnitude * MM_PER_MIL;
32205
- case "in":
32206
- return magnitude * MM_PER_INCH;
32207
- case "mm":
32208
- case void 0:
32209
- return magnitude;
32210
- default:
32211
- return magnitude;
32212
- }
32213
- }
32214
- function coerceDimensionToMm(value, fallback) {
32215
- const parsed = parseDimensionToMm(value);
32216
- return parsed === void 0 ? fallback : parsed;
32217
- }
32218
-
32219
- // src/utils/silkscreen-texture.ts
32220
- function parseFabricationNoteColor(colorString) {
32221
- let hex = colorString;
32222
- if (hex.startsWith("#")) {
32223
- hex = hex.slice(1);
32224
- }
32225
- if (hex.length === 6) {
32226
- const r = parseInt(hex.slice(0, 2), 16);
32227
- const g = parseInt(hex.slice(2, 4), 16);
32228
- const b = parseInt(hex.slice(4, 6), 16);
32229
- return `rgb(${r}, ${g}, ${b})`;
32230
- }
32231
- if (colorString.startsWith("rgb")) {
32232
- return colorString;
32233
- }
32234
- return "rgb(255, 243, 204)";
32235
- }
32236
- function createSilkscreenTextureForLayer({
32237
- layer,
32238
- circuitJson,
32239
- boardData,
32240
- silkscreenColor = "rgb(255,255,255)",
32241
- traceTextureResolution
32242
- }) {
32243
- const pcbSilkscreenTexts = su7(circuitJson).pcb_silkscreen_text.list();
32244
- const pcbSilkscreenPaths = su7(circuitJson).pcb_silkscreen_path.list();
32245
- const pcbSilkscreenLines = su7(circuitJson).pcb_silkscreen_line.list();
32246
- const pcbSilkscreenRects = su7(circuitJson).pcb_silkscreen_rect.list();
32247
- const pcbSilkscreenCircles = su7(circuitJson).pcb_silkscreen_circle.list();
32248
- const pcbFabricationNoteRects = su7(circuitJson).pcb_fabrication_note_rect.list();
32249
- const pcbNoteLines = su7(circuitJson).pcb_note_line.list();
32250
- const textsOnLayer = pcbSilkscreenTexts.filter((t) => t.layer === layer);
32251
- const pathsOnLayer = pcbSilkscreenPaths.filter((p) => p.layer === layer);
32252
- const linesOnLayer = pcbSilkscreenLines.filter((l) => l.layer === layer);
32253
- const rectsOnLayer = pcbSilkscreenRects.filter((r) => r.layer === layer);
32254
- const circlesOnLayer = pcbSilkscreenCircles.filter((c) => c.layer === layer);
32255
- const fabricationNoteRectsOnLayer = pcbFabricationNoteRects.filter(
32256
- (r) => r.layer === layer
32257
- );
32258
- const noteLinesOnLayer = pcbNoteLines.filter(
32259
- (l) => l.layer === layer
32260
- );
32261
- if (textsOnLayer.length === 0 && pathsOnLayer.length === 0 && linesOnLayer.length === 0 && rectsOnLayer.length === 0 && circlesOnLayer.length === 0 && fabricationNoteRectsOnLayer.length === 0 && noteLinesOnLayer.length === 0) {
32262
- return null;
32263
- }
32264
- const boardOutlineBounds = calculateOutlineBounds(boardData);
32265
- const canvas = document.createElement("canvas");
32266
- const canvasWidth = Math.floor(
32267
- boardOutlineBounds.width * traceTextureResolution
32268
- );
32269
- const canvasHeight = Math.floor(
32270
- boardOutlineBounds.height * traceTextureResolution
32271
- );
32272
- canvas.width = canvasWidth;
32273
- canvas.height = canvasHeight;
32274
- const ctx = canvas.getContext("2d");
32275
- if (!ctx) return null;
32276
- if (layer === "bottom") {
32277
- ctx.translate(0, canvasHeight);
32278
- ctx.scale(1, -1);
32279
- }
32280
- ctx.strokeStyle = silkscreenColor;
32281
- ctx.fillStyle = silkscreenColor;
32282
- const canvasXFromPcb = (pcbX) => (pcbX - boardOutlineBounds.minX) * traceTextureResolution;
32283
- const canvasYFromPcb = (pcbY) => (boardOutlineBounds.maxY - pcbY) * traceTextureResolution;
32284
- linesOnLayer.forEach((lineEl) => {
32285
- const startXmm = parseDimensionToMm(lineEl.x1) ?? 0;
32286
- const startYmm = parseDimensionToMm(lineEl.y1) ?? 0;
32287
- const endXmm = parseDimensionToMm(lineEl.x2) ?? 0;
32288
- const endYmm = parseDimensionToMm(lineEl.y2) ?? 0;
32289
- if (startXmm === endXmm && startYmm === endYmm) return;
32290
- ctx.beginPath();
32291
- ctx.lineWidth = coerceDimensionToMm(lineEl.stroke_width, 0.1) * traceTextureResolution;
32292
- ctx.lineCap = "round";
32293
- ctx.moveTo(canvasXFromPcb(startXmm), canvasYFromPcb(startYmm));
32294
- ctx.lineTo(canvasXFromPcb(endXmm), canvasYFromPcb(endYmm));
32295
- ctx.stroke();
32296
- });
32297
- noteLinesOnLayer.forEach((lineEl) => {
32298
- const startXmm = parseDimensionToMm(lineEl.x1) ?? 0;
32299
- const startYmm = parseDimensionToMm(lineEl.y1) ?? 0;
32300
- const endXmm = parseDimensionToMm(lineEl.x2) ?? 0;
32301
- const endYmm = parseDimensionToMm(lineEl.y2) ?? 0;
32302
- if (startXmm === endXmm && startYmm === endYmm) return;
32303
- ctx.save();
32304
- let strokeColor = silkscreenColor;
32305
- if (lineEl.color) {
32306
- strokeColor = parseFabricationNoteColor(lineEl.color);
32307
- } else {
32308
- strokeColor = "rgb(255, 243, 204)";
32309
- }
32310
- ctx.strokeStyle = strokeColor;
32311
- ctx.beginPath();
32312
- ctx.lineWidth = coerceDimensionToMm(lineEl.stroke_width, 0.1) * traceTextureResolution;
32313
- ctx.lineCap = "round";
32314
- const isDashed = lineEl.is_dashed ?? false;
32315
- if (isDashed) {
32316
- const dashLength = Math.max(ctx.lineWidth * 2, 1);
32317
- ctx.setLineDash([dashLength, dashLength]);
32318
- }
32319
- ctx.moveTo(canvasXFromPcb(startXmm), canvasYFromPcb(startYmm));
32320
- ctx.lineTo(canvasXFromPcb(endXmm), canvasYFromPcb(endYmm));
32321
- ctx.stroke();
32322
- if (isDashed) {
32323
- ctx.setLineDash([]);
32324
- }
32325
- ctx.restore();
32326
- });
32327
- pathsOnLayer.forEach((path) => {
32328
- if (path.route.length < 2) return;
32329
- ctx.beginPath();
32330
- ctx.lineWidth = coerceDimensionToMm(path.stroke_width, 0.1) * traceTextureResolution;
32331
- ctx.lineCap = "round";
32332
- ctx.lineJoin = "round";
32333
- path.route.forEach((point, index2) => {
32334
- const canvasX = canvasXFromPcb(parseDimensionToMm(point.x) ?? 0);
32335
- const canvasY = canvasYFromPcb(parseDimensionToMm(point.y) ?? 0);
32336
- if (index2 === 0) ctx.moveTo(canvasX, canvasY);
32337
- else ctx.lineTo(canvasX, canvasY);
32338
- });
32339
- ctx.stroke();
32340
- });
32341
- circlesOnLayer.forEach((circleEl) => {
32342
- const radius = coerceDimensionToMm(circleEl.radius, 0);
32343
- if (radius <= 0) return;
32344
- const strokeWidth = coerceDimensionToMm(circleEl.stroke_width, 0.12);
32345
- const hasStroke = strokeWidth > 0;
32346
- const centerXmm = parseDimensionToMm(circleEl.center?.x) ?? 0;
32347
- const centerYmm = parseDimensionToMm(circleEl.center?.y) ?? 0;
32348
- const canvasCenterX = canvasXFromPcb(centerXmm);
32349
- const canvasCenterY = canvasYFromPcb(centerYmm);
32350
- const radiusPx = radius * traceTextureResolution;
32351
- ctx.save();
32352
- ctx.translate(canvasCenterX, canvasCenterY);
32353
- if (hasStroke) {
32354
- const outerRadiusPx = radiusPx + strokeWidth / 2 * traceTextureResolution;
32355
- const innerRadiusPx = Math.max(
32356
- 0,
32357
- radiusPx - strokeWidth / 2 * traceTextureResolution
32358
- );
32359
- if (innerRadiusPx > 0) {
32360
- ctx.beginPath();
32361
- ctx.arc(0, 0, outerRadiusPx, 0, 2 * Math.PI);
32362
- ctx.arc(0, 0, innerRadiusPx, 0, 2 * Math.PI, true);
32363
- ctx.fill("evenodd");
32364
- } else {
32365
- ctx.beginPath();
32366
- ctx.arc(0, 0, outerRadiusPx, 0, 2 * Math.PI);
32367
- ctx.fill();
32368
- }
32369
- } else {
32370
- ctx.beginPath();
32371
- ctx.arc(0, 0, radiusPx, 0, 2 * Math.PI);
32372
- ctx.fill();
32373
- }
32374
- ctx.restore();
32375
- });
32376
- rectsOnLayer.forEach((rect) => {
32377
- const width10 = coerceDimensionToMm(rect.width, 0);
32378
- const height10 = coerceDimensionToMm(rect.height, 0);
32379
- if (width10 <= 0 || height10 <= 0) return;
32380
- const centerXmm = parseDimensionToMm(rect.center?.x) ?? 0;
32381
- const centerYmm = parseDimensionToMm(rect.center?.y) ?? 0;
32382
- const canvasCenterX = canvasXFromPcb(centerXmm);
32383
- const canvasCenterY = canvasYFromPcb(centerYmm);
32384
- const rawRadius = extractRectBorderRadius(rect);
32385
- const borderRadiusInput = typeof rawRadius === "string" ? parseDimensionToMm(rawRadius) : rawRadius;
32386
- const borderRadiusMm = clampRectBorderRadius(
32387
- width10,
32388
- height10,
32389
- borderRadiusInput
32390
- );
32391
- ctx.save();
32392
- ctx.translate(canvasCenterX, canvasCenterY);
32393
- const halfWidthPx = width10 / 2 * traceTextureResolution;
32394
- const halfHeightPx = height10 / 2 * traceTextureResolution;
32395
- const borderRadiusPx = Math.min(
32396
- borderRadiusMm * traceTextureResolution,
32397
- halfWidthPx,
32398
- halfHeightPx
32399
- );
32400
- const hasStroke = rect.stroke_width ?? false;
32401
- const isFilled = rect.is_filled ?? true;
32402
- const isDashed = rect.is_stroke_dashed ?? false;
32403
- const strokeWidthPx = hasStroke ? coerceDimensionToMm(rect.stroke_width, 0.1) * traceTextureResolution : 0;
32404
- const drawRoundedRectPath = (x, y, rectWidth, rectHeight, radius) => {
32405
- ctx.beginPath();
32406
- if (radius <= 0) {
32407
- ctx.rect(x, y, rectWidth, rectHeight);
32408
- } else {
32409
- const r = radius;
32410
- const right = x + rectWidth;
32411
- const bottom = y + rectHeight;
32412
- ctx.moveTo(x + r, y);
32413
- ctx.lineTo(right - r, y);
32414
- ctx.quadraticCurveTo(right, y, right, y + r);
32415
- ctx.lineTo(right, bottom - r);
32416
- ctx.quadraticCurveTo(right, bottom, right - r, bottom);
32417
- ctx.lineTo(x + r, bottom);
32418
- ctx.quadraticCurveTo(x, bottom, x, bottom - r);
32419
- ctx.lineTo(x, y + r);
32420
- ctx.quadraticCurveTo(x, y, x + r, y);
32421
- ctx.closePath();
32422
- }
32423
- };
32424
- drawRoundedRectPath(
32425
- -halfWidthPx,
32426
- -halfHeightPx,
32427
- halfWidthPx * 2,
32428
- halfHeightPx * 2,
32429
- borderRadiusPx
32430
- );
32431
- if (isFilled) {
32432
- ctx.fill();
32433
- }
32434
- if (hasStroke && strokeWidthPx > 0) {
32435
- ctx.lineWidth = strokeWidthPx;
32436
- if (isDashed) {
32437
- const dashLength = Math.max(strokeWidthPx * 2, 1);
32438
- ctx.setLineDash([dashLength, dashLength]);
32439
- }
32440
- ctx.stroke();
32441
- if (isDashed) {
32442
- ctx.setLineDash([]);
32443
- }
32444
- }
32445
- ctx.restore();
32446
- });
32447
- fabricationNoteRectsOnLayer.forEach((rect) => {
32448
- const width10 = coerceDimensionToMm(rect.width, 0);
32449
- const height10 = coerceDimensionToMm(rect.height, 0);
32450
- if (width10 <= 0 || height10 <= 0) return;
32451
- const centerXmm = parseDimensionToMm(rect.center?.x) ?? 0;
32452
- const centerYmm = parseDimensionToMm(rect.center?.y) ?? 0;
32453
- const canvasCenterX = canvasXFromPcb(centerXmm);
32454
- const canvasCenterY = canvasYFromPcb(centerYmm);
32455
- const rawRadius = extractRectBorderRadius(rect);
32456
- const borderRadiusInput = typeof rawRadius === "string" ? parseDimensionToMm(rawRadius) : rawRadius;
32457
- const borderRadiusMm = clampRectBorderRadius(
32458
- width10,
32459
- height10,
32460
- borderRadiusInput
32461
- );
32462
- ctx.save();
32463
- ctx.translate(canvasCenterX, canvasCenterY);
32464
- const halfWidthPx = width10 / 2 * traceTextureResolution;
32465
- const halfHeightPx = height10 / 2 * traceTextureResolution;
32466
- const borderRadiusPx = Math.min(
32467
- borderRadiusMm * traceTextureResolution,
32468
- halfWidthPx,
32469
- halfHeightPx
32470
- );
32471
- const hasStroke = rect.has_stroke ?? false;
32472
- const isFilled = rect.is_filled ?? true;
32473
- const isDashed = rect.is_stroke_dashed ?? false;
32474
- const strokeWidthPx = hasStroke ? coerceDimensionToMm(rect.stroke_width, 0.1) * traceTextureResolution : 0;
32475
- let fillColor = silkscreenColor;
32476
- let strokeColor = silkscreenColor;
32477
- if (rect.color) {
32478
- const parsedColor = parseFabricationNoteColor(rect.color);
32479
- fillColor = parsedColor;
32480
- strokeColor = parsedColor;
32481
- } else {
32482
- fillColor = "rgb(255, 243, 204)";
32483
- strokeColor = "rgb(255, 243, 204)";
32484
- }
32485
- const drawRoundedRectPath = (x, y, rectWidth, rectHeight, radius) => {
32486
- ctx.beginPath();
32487
- if (radius <= 0) {
32488
- ctx.rect(x, y, rectWidth, rectHeight);
32489
- } else {
32490
- const r = radius;
32491
- const right = x + rectWidth;
32492
- const bottom = y + rectHeight;
32493
- ctx.moveTo(x + r, y);
32494
- ctx.lineTo(right - r, y);
32495
- ctx.quadraticCurveTo(right, y, right, y + r);
32496
- ctx.lineTo(right, bottom - r);
32497
- ctx.quadraticCurveTo(right, bottom, right - r, bottom);
32498
- ctx.lineTo(x + r, bottom);
32499
- ctx.quadraticCurveTo(x, bottom, x, bottom - r);
32500
- ctx.lineTo(x, y + r);
32501
- ctx.quadraticCurveTo(x, y, x + r, y);
32502
- ctx.closePath();
32503
- }
32504
- };
32505
- drawRoundedRectPath(
32506
- -halfWidthPx,
32507
- -halfHeightPx,
32508
- halfWidthPx * 2,
32509
- halfHeightPx * 2,
32510
- borderRadiusPx
32511
- );
32512
- if (isFilled) {
32513
- ctx.fillStyle = fillColor;
32514
- ctx.fill();
32515
- }
32516
- if (hasStroke && strokeWidthPx > 0) {
32517
- ctx.strokeStyle = strokeColor;
32518
- ctx.lineWidth = strokeWidthPx;
32519
- if (isDashed) {
32520
- const dashLength = Math.max(strokeWidthPx * 2, 1);
32521
- ctx.setLineDash([dashLength, dashLength]);
32522
- }
32523
- ctx.stroke();
32524
- if (isDashed) {
32525
- ctx.setLineDash([]);
32526
- }
32527
- }
32528
- ctx.restore();
32529
- });
32530
- textsOnLayer.forEach((textS) => {
32531
- const fontSize = textS.font_size || 0.25;
32532
- const textStrokeWidth = Math.min(Math.max(0.01, fontSize * 0.1), fontSize * 0.05) * traceTextureResolution;
32533
- ctx.lineWidth = textStrokeWidth;
32534
- ctx.lineCap = "butt";
32535
- ctx.lineJoin = "miter";
32536
- const rawTextOutlines = (0, import_text2.vectorText)({
32537
- height: fontSize * 0.45,
32538
- input: textS.text
32539
- });
32540
- const processedTextOutlines = [];
32541
- rawTextOutlines.forEach((outline) => {
32542
- if (outline.length === 29) {
32543
- processedTextOutlines.push(
32544
- outline.slice(0, 15)
32545
- );
32546
- processedTextOutlines.push(
32547
- outline.slice(14, 29)
32548
- );
32549
- } else if (outline.length === 17) {
32550
- processedTextOutlines.push(
32551
- outline.slice(0, 10)
32552
- );
32553
- processedTextOutlines.push(
32554
- outline.slice(9, 17)
32555
- );
32556
- } else {
32557
- processedTextOutlines.push(outline);
32558
- }
32559
- });
32560
- const points = processedTextOutlines.flat();
32561
- const textBounds = {
32562
- minX: points.length > 0 ? Math.min(...points.map((p) => p[0])) : 0,
32563
- maxX: points.length > 0 ? Math.max(...points.map((p) => p[0])) : 0,
32564
- minY: points.length > 0 ? Math.min(...points.map((p) => p[1])) : 0,
32565
- maxY: points.length > 0 ? Math.max(...points.map((p) => p[1])) : 0
32566
- };
32567
- const textCenterX = (textBounds.minX + textBounds.maxX) / 2;
32568
- const textCenterY = (textBounds.minY + textBounds.maxY) / 2;
32569
- let xOff = -textCenterX;
32570
- let yOff = -textCenterY;
32571
- const alignment = textS.anchor_alignment || "center";
32572
- if (alignment.includes("left")) {
32573
- xOff = -textBounds.minX;
32574
- } else if (alignment.includes("right")) {
32575
- xOff = -textBounds.maxX;
32576
- }
32577
- if (alignment.includes("top")) {
32578
- yOff = -textBounds.maxY;
32579
- } else if (alignment.includes("bottom")) {
32580
- yOff = -textBounds.minY;
32581
- }
32582
- const transformMatrices = [];
32583
- let rotationDeg = textS.ccw_rotation ?? 0;
32584
- if (textS.layer === "bottom") {
32585
- transformMatrices.push(
32586
- translate6(textCenterX, textCenterY),
32587
- { a: -1, b: 0, c: 0, d: 1, e: 0, f: 0 },
32588
- translate6(-textCenterX, -textCenterY)
32589
- );
32590
- rotationDeg = -rotationDeg;
32591
- }
32592
- if (rotationDeg) {
32593
- const rad = rotationDeg * Math.PI / 180;
32594
- transformMatrices.push(
32595
- translate6(textCenterX, textCenterY),
32596
- rotate2(rad),
32597
- translate6(-textCenterX, -textCenterY)
32598
- );
32599
- }
32600
- const finalTransformMatrix = transformMatrices.length > 0 ? compose(...transformMatrices) : void 0;
32601
- processedTextOutlines.forEach((segment) => {
32602
- ctx.beginPath();
32603
- segment.forEach((p, index2) => {
32604
- let transformedP = { x: p[0], y: p[1] };
32605
- if (finalTransformMatrix) {
32606
- transformedP = applyToPoint(finalTransformMatrix, transformedP);
32607
- }
32608
- const pcbX = transformedP.x + xOff + textS.anchor_position.x;
32609
- const pcbY = transformedP.y + yOff + textS.anchor_position.y;
32610
- const canvasX = canvasXFromPcb(pcbX);
32611
- const canvasY = canvasYFromPcb(pcbY);
32612
- if (index2 === 0) ctx.moveTo(canvasX, canvasY);
32613
- else ctx.lineTo(canvasX, canvasY);
32614
- });
32615
- ctx.stroke();
32616
- });
32617
- });
32618
- const texture = new THREE22.CanvasTexture(canvas);
32619
- texture.generateMipmaps = true;
32620
- texture.minFilter = THREE22.LinearMipmapLinearFilter;
32621
- texture.magFilter = THREE22.LinearFilter;
32622
- texture.anisotropy = 16;
32623
- texture.needsUpdate = true;
32624
- return texture;
32625
- }
32626
-
32627
- // src/utils/trace-texture.ts
32628
- import * as THREE23 from "three";
32629
- import { su as su8 } from "@tscircuit/circuit-json-util";
32630
32172
  function isWireRoutePoint(point) {
32631
32173
  return point && point.route_type === "wire" && typeof point.layer === "string" && typeof point.width === "number";
32632
32174
  }
@@ -32637,9 +32179,9 @@ function createTraceTextureForLayer({
32637
32179
  traceColor,
32638
32180
  traceTextureResolution
32639
32181
  }) {
32640
- const pcbTraces = su8(circuitJson).pcb_trace.list();
32641
- const allPcbVias = su8(circuitJson).pcb_via.list();
32642
- const allPcbPlatedHoles = su8(
32182
+ const pcbTraces = su7(circuitJson).pcb_trace.list();
32183
+ const allPcbVias = su7(circuitJson).pcb_via.list();
32184
+ const allPcbPlatedHoles = su7(
32643
32185
  circuitJson
32644
32186
  ).pcb_plated_hole.list();
32645
32187
  const tracesOnLayer = pcbTraces.filter(
@@ -32738,17 +32280,17 @@ function createTraceTextureForLayer({
32738
32280
  }
32739
32281
  });
32740
32282
  ctx.globalCompositeOperation = "source-over";
32741
- const texture = new THREE23.CanvasTexture(canvas);
32283
+ const texture = new THREE22.CanvasTexture(canvas);
32742
32284
  texture.generateMipmaps = true;
32743
- texture.minFilter = THREE23.LinearMipmapLinearFilter;
32744
- texture.magFilter = THREE23.LinearFilter;
32285
+ texture.minFilter = THREE22.LinearMipmapLinearFilter;
32286
+ texture.magFilter = THREE22.LinearFilter;
32745
32287
  texture.anisotropy = 16;
32746
32288
  texture.needsUpdate = true;
32747
32289
  return texture;
32748
32290
  }
32749
32291
 
32750
32292
  // src/textures/create-copper-pour-texture-for-layer.ts
32751
- import * as THREE24 from "three";
32293
+ import * as THREE23 from "three";
32752
32294
  import { CircuitToCanvasDrawer } from "circuit-to-canvas";
32753
32295
 
32754
32296
  // src/geoms/brep-converter.ts
@@ -32954,6 +32496,167 @@ function createCopperPourTextureForLayer({
32954
32496
  ctx.fillStyle = copperColor;
32955
32497
  drawBrepShape({ ctx, pour, canvasXFromPcb, canvasYFromPcb });
32956
32498
  }
32499
+ const texture = new THREE23.CanvasTexture(canvas);
32500
+ texture.generateMipmaps = true;
32501
+ texture.minFilter = THREE23.LinearMipmapLinearFilter;
32502
+ texture.magFilter = THREE23.LinearFilter;
32503
+ texture.anisotropy = 16;
32504
+ texture.needsUpdate = true;
32505
+ return texture;
32506
+ }
32507
+
32508
+ // src/textures/create-silkscreen-texture-for-layer.ts
32509
+ import * as THREE24 from "three";
32510
+
32511
+ // src/textures/soldermask/soldermask-bounds.ts
32512
+ var boundsFromPanel = (panel) => ({
32513
+ minX: panel.center.x - panel.width / 2,
32514
+ maxX: panel.center.x + panel.width / 2,
32515
+ minY: panel.center.y - panel.height / 2,
32516
+ maxY: panel.center.y + panel.height / 2,
32517
+ width: panel.width,
32518
+ height: panel.height,
32519
+ centerX: panel.center.x,
32520
+ centerY: panel.center.y
32521
+ });
32522
+ var mergeBounds = (a, b) => {
32523
+ const minX = Math.min(a.minX, b.minX);
32524
+ const maxX = Math.max(a.maxX, b.maxX);
32525
+ const minY = Math.min(a.minY, b.minY);
32526
+ const maxY = Math.max(a.maxY, b.maxY);
32527
+ return {
32528
+ minX,
32529
+ maxX,
32530
+ minY,
32531
+ maxY,
32532
+ width: maxX - minX,
32533
+ height: maxY - minY,
32534
+ centerX: (minX + maxX) / 2,
32535
+ centerY: (minY + maxY) / 2
32536
+ };
32537
+ };
32538
+ var getSoldermaskRenderBounds = (circuitJson, boardData) => {
32539
+ const panels = circuitJson.filter(
32540
+ (e) => e.type === "pcb_panel"
32541
+ );
32542
+ const boards = circuitJson.filter(
32543
+ (e) => e.type === "pcb_board"
32544
+ );
32545
+ const activePanel = panels.find((panel) => panel.pcb_panel_id === boardData.pcb_board_id) ?? panels[0];
32546
+ if (activePanel && activePanel.width > 0 && activePanel.height > 0) {
32547
+ return boundsFromPanel(activePanel);
32548
+ }
32549
+ const boardsForBounds = boards.length > 1 ? boards : [boardData];
32550
+ return boardsForBounds.map((board) => calculateOutlineBounds(board)).reduce((acc, bounds) => mergeBounds(acc, bounds));
32551
+ };
32552
+
32553
+ // src/textures/silkscreen/silkscreen-drawing.ts
32554
+ import { CircuitToCanvasDrawer as CircuitToCanvasDrawer2 } from "circuit-to-canvas";
32555
+ var FABRICATION_NOTE_COLOR = "rgb(255,243,204)";
32556
+ var TRANSPARENT = "rgba(0,0,0,0)";
32557
+ var setDrawerBounds = (drawer, bounds) => {
32558
+ drawer.setCameraBounds({
32559
+ minX: bounds.minX,
32560
+ maxX: bounds.maxX,
32561
+ minY: bounds.minY,
32562
+ maxY: bounds.maxY
32563
+ });
32564
+ };
32565
+ var drawSilkscreenLayer = ({
32566
+ ctx,
32567
+ layer,
32568
+ bounds,
32569
+ elements,
32570
+ silkscreenColor
32571
+ }) => {
32572
+ const renderLayer = layer === "top" ? "top_silkscreen" : "bottom_silkscreen";
32573
+ const drawer = new CircuitToCanvasDrawer2(ctx);
32574
+ drawer.configure({
32575
+ colorOverrides: {
32576
+ copper: {
32577
+ top: TRANSPARENT,
32578
+ bottom: TRANSPARENT,
32579
+ inner1: TRANSPARENT,
32580
+ inner2: TRANSPARENT,
32581
+ inner3: TRANSPARENT,
32582
+ inner4: TRANSPARENT,
32583
+ inner5: TRANSPARENT,
32584
+ inner6: TRANSPARENT
32585
+ },
32586
+ copperPour: {
32587
+ top: TRANSPARENT,
32588
+ bottom: TRANSPARENT
32589
+ },
32590
+ drill: TRANSPARENT,
32591
+ boardOutline: TRANSPARENT,
32592
+ substrate: TRANSPARENT,
32593
+ keepout: TRANSPARENT,
32594
+ courtyard: {
32595
+ top: TRANSPARENT,
32596
+ bottom: TRANSPARENT
32597
+ },
32598
+ soldermask: {
32599
+ top: TRANSPARENT,
32600
+ bottom: TRANSPARENT
32601
+ },
32602
+ soldermaskWithCopperUnderneath: {
32603
+ top: TRANSPARENT,
32604
+ bottom: TRANSPARENT
32605
+ },
32606
+ soldermaskOverCopper: {
32607
+ top: TRANSPARENT,
32608
+ bottom: TRANSPARENT
32609
+ },
32610
+ silkscreen: {
32611
+ top: silkscreenColor,
32612
+ bottom: silkscreenColor
32613
+ },
32614
+ fabricationNote: FABRICATION_NOTE_COLOR
32615
+ }
32616
+ });
32617
+ setDrawerBounds(drawer, bounds);
32618
+ drawer.drawElements(elements, {
32619
+ layers: [renderLayer]
32620
+ });
32621
+ };
32622
+
32623
+ // src/textures/create-silkscreen-texture-for-layer.ts
32624
+ var isSilkscreenElement = (element, layer) => {
32625
+ if (!("layer" in element) || element.layer !== layer) return false;
32626
+ const elementType = element.type;
32627
+ return elementType.startsWith("pcb_silkscreen_") || elementType === "pcb_fabrication_note_rect" || elementType === "pcb_note_line";
32628
+ };
32629
+ function createSilkscreenTextureForLayer({
32630
+ layer,
32631
+ circuitJson,
32632
+ boardData,
32633
+ traceTextureResolution = TRACE_TEXTURE_RESOLUTION,
32634
+ silkscreenColor = "rgb(255,255,255)"
32635
+ }) {
32636
+ const elements = circuitJson.filter(
32637
+ (element) => isSilkscreenElement(element, layer)
32638
+ );
32639
+ if (elements.length === 0) return null;
32640
+ const bounds = getSoldermaskRenderBounds(circuitJson, boardData);
32641
+ const canvasWidth = Math.floor(bounds.width * traceTextureResolution);
32642
+ const canvasHeight = Math.floor(bounds.height * traceTextureResolution);
32643
+ if (canvasWidth <= 0 || canvasHeight <= 0) return null;
32644
+ const canvas = document.createElement("canvas");
32645
+ canvas.width = canvasWidth;
32646
+ canvas.height = canvasHeight;
32647
+ const ctx = canvas.getContext("2d");
32648
+ if (!ctx) return null;
32649
+ if (layer === "bottom") {
32650
+ ctx.translate(0, canvasHeight);
32651
+ ctx.scale(1, -1);
32652
+ }
32653
+ drawSilkscreenLayer({
32654
+ ctx,
32655
+ layer,
32656
+ bounds,
32657
+ elements,
32658
+ silkscreenColor
32659
+ });
32957
32660
  const texture = new THREE24.CanvasTexture(canvas);
32958
32661
  texture.generateMipmaps = true;
32959
32662
  texture.minFilter = THREE24.LinearMipmapLinearFilter;
@@ -32967,7 +32670,7 @@ function createCopperPourTextureForLayer({
32967
32670
  import * as THREE25 from "three";
32968
32671
 
32969
32672
  // src/textures/soldermask/soldermask-drawing.ts
32970
- import { CircuitToCanvasDrawer as CircuitToCanvasDrawer2 } from "circuit-to-canvas";
32673
+ import { CircuitToCanvasDrawer as CircuitToCanvasDrawer3 } from "circuit-to-canvas";
32971
32674
  var toRgb = (colorArr) => {
32972
32675
  const [r = 0, g = 0, b = 0] = colorArr;
32973
32676
  return `rgb(${Math.round(r * 255)}, ${Math.round(g * 255)}, ${Math.round(
@@ -32986,7 +32689,7 @@ var getSoldermaskPalette = (material) => {
32986
32689
  transparent: "rgba(0,0,0,0)"
32987
32690
  };
32988
32691
  };
32989
- var setDrawerBounds = (drawer, bounds) => {
32692
+ var setDrawerBounds2 = (drawer, bounds) => {
32990
32693
  drawer.setCameraBounds({
32991
32694
  minX: bounds.minX,
32992
32695
  maxX: bounds.maxX,
@@ -33003,7 +32706,7 @@ var drawSoldermaskLayer = ({
33003
32706
  }) => {
33004
32707
  const palette = getSoldermaskPalette(boardMaterial);
33005
32708
  const copperRenderLayer = layer === "top" ? "top_copper" : "bottom_copper";
33006
- const drawer = new CircuitToCanvasDrawer2(ctx);
32709
+ const drawer = new CircuitToCanvasDrawer3(ctx);
33007
32710
  drawer.configure({
33008
32711
  colorOverrides: {
33009
32712
  copper: {
@@ -33034,7 +32737,7 @@ var drawSoldermaskLayer = ({
33034
32737
  }
33035
32738
  }
33036
32739
  });
33037
- setDrawerBounds(drawer, bounds);
32740
+ setDrawerBounds2(drawer, bounds);
33038
32741
  drawer.drawElements(elements, {
33039
32742
  layers: [copperRenderLayer],
33040
32743
  drawSoldermask: true,
@@ -33047,7 +32750,7 @@ var drawSoldermaskLayer = ({
33047
32750
  if (uncoveredPours.length > 0) {
33048
32751
  ctx.save();
33049
32752
  ctx.globalCompositeOperation = "destination-out";
33050
- const cutoutDrawer = new CircuitToCanvasDrawer2(ctx);
32753
+ const cutoutDrawer = new CircuitToCanvasDrawer3(ctx);
33051
32754
  cutoutDrawer.configure({
33052
32755
  colorOverrides: {
33053
32756
  copper: {
@@ -33062,54 +32765,12 @@ var drawSoldermaskLayer = ({
33062
32765
  }
33063
32766
  }
33064
32767
  });
33065
- setDrawerBounds(cutoutDrawer, bounds);
32768
+ setDrawerBounds2(cutoutDrawer, bounds);
33066
32769
  cutoutDrawer.drawElements(uncoveredPours, { layers: [copperRenderLayer] });
33067
32770
  ctx.restore();
33068
32771
  }
33069
32772
  };
33070
32773
 
33071
- // src/textures/soldermask/soldermask-bounds.ts
33072
- var boundsFromPanel = (panel) => ({
33073
- minX: panel.center.x - panel.width / 2,
33074
- maxX: panel.center.x + panel.width / 2,
33075
- minY: panel.center.y - panel.height / 2,
33076
- maxY: panel.center.y + panel.height / 2,
33077
- width: panel.width,
33078
- height: panel.height,
33079
- centerX: panel.center.x,
33080
- centerY: panel.center.y
33081
- });
33082
- var mergeBounds = (a, b) => {
33083
- const minX = Math.min(a.minX, b.minX);
33084
- const maxX = Math.max(a.maxX, b.maxX);
33085
- const minY = Math.min(a.minY, b.minY);
33086
- const maxY = Math.max(a.maxY, b.maxY);
33087
- return {
33088
- minX,
33089
- maxX,
33090
- minY,
33091
- maxY,
33092
- width: maxX - minX,
33093
- height: maxY - minY,
33094
- centerX: (minX + maxX) / 2,
33095
- centerY: (minY + maxY) / 2
33096
- };
33097
- };
33098
- var getSoldermaskRenderBounds = (circuitJson, boardData) => {
33099
- const panels = circuitJson.filter(
33100
- (e) => e.type === "pcb_panel"
33101
- );
33102
- const boards = circuitJson.filter(
33103
- (e) => e.type === "pcb_board"
33104
- );
33105
- const activePanel = panels.find((panel) => panel.pcb_panel_id === boardData.pcb_board_id) ?? panels[0];
33106
- if (activePanel && activePanel.width > 0 && activePanel.height > 0) {
33107
- return boundsFromPanel(activePanel);
33108
- }
33109
- const boardsForBounds = boards.length > 1 ? boards : [boardData];
33110
- return boardsForBounds.map((board) => calculateOutlineBounds(board)).reduce((acc, bounds) => mergeBounds(acc, bounds));
33111
- };
33112
-
33113
32774
  // src/textures/create-soldermask-texture-for-layer.ts
33114
32775
  function createSoldermaskTextureForLayer({
33115
32776
  layer,
@@ -33385,7 +33046,7 @@ function JscadBoardTextures({
33385
33046
  const panels = circuitJson.filter(
33386
33047
  (e) => e.type === "pcb_panel"
33387
33048
  );
33388
- const boards = su9(circuitJson).pcb_board.list();
33049
+ const boards = su8(circuitJson).pcb_board.list();
33389
33050
  if (panels.length > 0) {
33390
33051
  const panel = panels[0];
33391
33052
  const firstBoardInPanel = boards.find(
@@ -33522,16 +33183,16 @@ function JscadBoardTextures({
33522
33183
  }
33523
33184
 
33524
33185
  // src/utils/preprocess-circuit-json.ts
33525
- import { su as su11 } from "@tscircuit/circuit-json-util";
33186
+ import { su as su10 } from "@tscircuit/circuit-json-util";
33526
33187
 
33527
33188
  // src/utils/create-faux-board.ts
33528
- import { su as su10, getBoundsOfPcbElements } from "@tscircuit/circuit-json-util";
33189
+ import { su as su9, getBoundsOfPcbElements } from "@tscircuit/circuit-json-util";
33529
33190
  function createFauxBoard(circuitJson) {
33530
- const cadComponents = su10(circuitJson).cad_component.list();
33531
- const pads = su10(circuitJson).pcb_smtpad.list();
33532
- const holes = su10(circuitJson).pcb_hole.list();
33533
- const platedHoles = su10(circuitJson).pcb_plated_hole.list();
33534
- const vias = su10(circuitJson).pcb_via.list();
33191
+ const cadComponents = su9(circuitJson).cad_component.list();
33192
+ const pads = su9(circuitJson).pcb_smtpad.list();
33193
+ const holes = su9(circuitJson).pcb_hole.list();
33194
+ const platedHoles = su9(circuitJson).pcb_plated_hole.list();
33195
+ const vias = su9(circuitJson).pcb_via.list();
33535
33196
  if (cadComponents.length === 0 && pads.length === 0 && holes.length === 0 && platedHoles.length === 0 && vias.length === 0) {
33536
33197
  return null;
33537
33198
  }
@@ -33580,7 +33241,7 @@ function createFauxBoard(circuitJson) {
33580
33241
 
33581
33242
  // src/utils/preprocess-circuit-json.ts
33582
33243
  function addFauxBoardIfNeeded(circuitJson) {
33583
- const boards = su11(circuitJson).pcb_board.list();
33244
+ const boards = su10(circuitJson).pcb_board.list();
33584
33245
  if (boards.length > 0) {
33585
33246
  return circuitJson;
33586
33247
  }
@@ -33631,7 +33292,7 @@ var CadViewerJscad = forwardRef3(
33631
33292
  const initialCameraPosition = useMemo20(() => {
33632
33293
  if (!internalCircuitJson) return [5, -5, 5];
33633
33294
  try {
33634
- const board = su12(internalCircuitJson).pcb_board.list()[0];
33295
+ const board = su11(internalCircuitJson).pcb_board.list()[0];
33635
33296
  if (!board) return [5, -5, 5];
33636
33297
  const { width: width10, height: height10 } = board;
33637
33298
  if (!width10 && !height10) {
@@ -33657,7 +33318,7 @@ var CadViewerJscad = forwardRef3(
33657
33318
  const isFauxBoard = useMemo20(() => {
33658
33319
  if (!internalCircuitJson) return false;
33659
33320
  try {
33660
- const board = su12(internalCircuitJson).pcb_board.list()[0];
33321
+ const board = su11(internalCircuitJson).pcb_board.list()[0];
33661
33322
  return !!board && board.pcb_board_id === "faux-board";
33662
33323
  } catch (e) {
33663
33324
  return false;
@@ -33666,7 +33327,7 @@ var CadViewerJscad = forwardRef3(
33666
33327
  const boardDimensions = useMemo20(() => {
33667
33328
  if (!internalCircuitJson) return void 0;
33668
33329
  try {
33669
- const board = su12(internalCircuitJson).pcb_board.list()[0];
33330
+ const board = su11(internalCircuitJson).pcb_board.list()[0];
33670
33331
  if (!board) return void 0;
33671
33332
  return { width: board.width ?? 0, height: board.height ?? 0 };
33672
33333
  } catch (e) {
@@ -33677,7 +33338,7 @@ var CadViewerJscad = forwardRef3(
33677
33338
  const boardCenter = useMemo20(() => {
33678
33339
  if (!internalCircuitJson) return void 0;
33679
33340
  try {
33680
- const board = su12(internalCircuitJson).pcb_board.list()[0];
33341
+ const board = su11(internalCircuitJson).pcb_board.list()[0];
33681
33342
  if (!board || !board.center) return void 0;
33682
33343
  return { x: board.center.x, y: board.center.y };
33683
33344
  } catch (e) {
@@ -33687,7 +33348,7 @@ var CadViewerJscad = forwardRef3(
33687
33348
  }, [internalCircuitJson]);
33688
33349
  const pcbThickness = usePcbThickness(internalCircuitJson);
33689
33350
  const { stls: boardStls, loading } = useStlsFromGeom(boardGeom);
33690
- const cad_components = su12(internalCircuitJson).cad_component.list();
33351
+ const cad_components = su11(internalCircuitJson).cad_component.list();
33691
33352
  return /* @__PURE__ */ jsxs5(
33692
33353
  CadViewerContainer,
33693
33354
  {
@@ -33741,12 +33402,12 @@ var CadViewerJscad = forwardRef3(
33741
33402
  );
33742
33403
 
33743
33404
  // src/CadViewerManifold.tsx
33744
- import { su as su18 } from "@tscircuit/circuit-json-util";
33405
+ import { su as su17 } from "@tscircuit/circuit-json-util";
33745
33406
  import { useEffect as useEffect25, useMemo as useMemo22, useState as useState16 } from "react";
33746
33407
  import * as THREE35 from "three";
33747
33408
 
33748
33409
  // src/hooks/useManifoldBoardBuilder.ts
33749
- import { su as su17 } from "@tscircuit/circuit-json-util";
33410
+ import { su as su16 } from "@tscircuit/circuit-json-util";
33750
33411
  import { useEffect as useEffect24, useMemo as useMemo21, useRef as useRef9, useState as useState15 } from "react";
33751
33412
  import * as THREE32 from "three";
33752
33413
 
@@ -33809,7 +33470,7 @@ function createManifoldBoard(Manifold, CrossSection, boardData, pcbThickness, ma
33809
33470
  }
33810
33471
 
33811
33472
  // src/utils/manifold/process-cutouts.ts
33812
- import { su as su13 } from "@tscircuit/circuit-json-util";
33473
+ import { su as su12 } from "@tscircuit/circuit-json-util";
33813
33474
 
33814
33475
  // src/utils/pad-geoms.ts
33815
33476
  var RECT_PAD_SEGMENTS2 = 64;
@@ -33868,7 +33529,7 @@ var arePointsClockwise3 = (points) => {
33868
33529
  };
33869
33530
  function processCutoutsForManifold(Manifold, CrossSection, circuitJson, pcbThickness, manifoldInstancesForCleanup) {
33870
33531
  const cutoutOps = [];
33871
- const pcbCutouts = su13(circuitJson).pcb_cutout.list();
33532
+ const pcbCutouts = su12(circuitJson).pcb_cutout.list();
33872
33533
  for (const cutout of pcbCutouts) {
33873
33534
  let cutoutOp;
33874
33535
  const cutoutHeight = pcbThickness * 1.5;
@@ -33963,7 +33624,7 @@ function processCutoutsForManifold(Manifold, CrossSection, circuitJson, pcbThick
33963
33624
  }
33964
33625
 
33965
33626
  // src/utils/manifold/process-non-plated-holes.ts
33966
- import { su as su14 } from "@tscircuit/circuit-json-util";
33627
+ import { su as su13 } from "@tscircuit/circuit-json-util";
33967
33628
 
33968
33629
  // src/utils/hole-geoms.ts
33969
33630
  function createCircleHoleDrill({
@@ -34006,7 +33667,7 @@ function createPlatedHoleDrill({
34006
33667
  // src/utils/manifold/process-non-plated-holes.ts
34007
33668
  function processNonPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbThickness, manifoldInstancesForCleanup) {
34008
33669
  const nonPlatedHoleBoardDrills = [];
34009
- const pcbHoles = su14(circuitJson).pcb_hole.list();
33670
+ const pcbHoles = su13(circuitJson).pcb_hole.list();
34010
33671
  const createPillOp = (width10, height10, depth) => {
34011
33672
  const pillOp = createRoundedRectPrism({
34012
33673
  Manifold,
@@ -34089,7 +33750,7 @@ function processNonPlatedHolesForManifold(Manifold, CrossSection, circuitJson, p
34089
33750
  }
34090
33751
 
34091
33752
  // src/utils/manifold/process-plated-holes.ts
34092
- import { su as su15 } from "@tscircuit/circuit-json-util";
33753
+ import { su as su14 } from "@tscircuit/circuit-json-util";
34093
33754
  import * as THREE30 from "three";
34094
33755
 
34095
33756
  // src/utils/manifold-mesh-to-three-geometry.ts
@@ -34141,7 +33802,7 @@ var PLATED_HOLE_SURFACE_CLEARANCE = 5e-4;
34141
33802
  var PLATED_HOLE_FILL_CLEARANCE = 4e-3;
34142
33803
  function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbThickness, manifoldInstancesForCleanup, boardClipVolume) {
34143
33804
  const platedHoleBoardDrills = [];
34144
- const pcbPlatedHoles = su15(circuitJson).pcb_plated_hole.list();
33805
+ const pcbPlatedHoles = su14(circuitJson).pcb_plated_hole.list();
34145
33806
  const platedHoleCopperGeoms = [];
34146
33807
  const platedHoleCopperOpsForSubtract = [];
34147
33808
  const createPillOp = (width10, height10, depth) => {
@@ -34875,7 +34536,7 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
34875
34536
  }
34876
34537
 
34877
34538
  // src/utils/manifold/process-vias.ts
34878
- import { su as su16 } from "@tscircuit/circuit-json-util";
34539
+ import { su as su15 } from "@tscircuit/circuit-json-util";
34879
34540
  import * as THREE31 from "three";
34880
34541
 
34881
34542
  // src/utils/via-geoms.ts
@@ -34932,7 +34593,7 @@ function createViaCopper2({
34932
34593
  var COPPER_COLOR2 = new THREE31.Color(...colors.copper);
34933
34594
  function processViasForManifold(Manifold, circuitJson, pcbThickness, manifoldInstancesForCleanup, boardClipVolume) {
34934
34595
  const viaBoardDrills = [];
34935
- const pcbVias = su16(circuitJson).pcb_via.list();
34596
+ const pcbVias = su15(circuitJson).pcb_via.list();
34936
34597
  const viaCopperGeoms = [];
34937
34598
  pcbVias.forEach((via, index2) => {
34938
34599
  if (typeof via.hole_diameter === "number") {
@@ -34991,7 +34652,7 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson, visibility) => {
34991
34652
  const panels = circuitJson.filter(
34992
34653
  (e) => e.type === "pcb_panel"
34993
34654
  );
34994
- const boards = su17(circuitJson).pcb_board.list();
34655
+ const boards = su16(circuitJson).pcb_board.list();
34995
34656
  if (panels.length > 0) {
34996
34657
  const panel = panels[0];
34997
34658
  const firstBoardInPanel = boards.find(
@@ -35012,7 +34673,7 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson, visibility) => {
35012
34673
  return boardsNotInPanel.length > 0 ? boardsNotInPanel[0] : null;
35013
34674
  }, [circuitJson]);
35014
34675
  const isFauxBoard = useMemo21(() => {
35015
- const boards = su17(circuitJson).pcb_board.list();
34676
+ const boards = su16(circuitJson).pcb_board.list();
35016
34677
  return boards.length > 0 && boards[0].pcb_board_id === "faux-board";
35017
34678
  }, [circuitJson]);
35018
34679
  const traceTextureResolution = useMemo21(() => {
@@ -35314,7 +34975,7 @@ var BoardMeshes = ({
35314
34975
  }) => {
35315
34976
  const { rootObject } = useThree();
35316
34977
  const { visibility } = useLayerVisibility();
35317
- const disposeTextureMesh = (mesh) => {
34978
+ const disposeMesh = (mesh) => {
35318
34979
  mesh.geometry.dispose();
35319
34980
  const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
35320
34981
  for (const material of materials) {
@@ -35356,23 +35017,29 @@ var BoardMeshes = ({
35356
35017
  rootObject.add(mesh);
35357
35018
  }
35358
35019
  });
35359
- textureMeshes.forEach((mesh) => {
35360
- rootObject.add(mesh);
35361
- });
35362
35020
  return () => {
35363
35021
  geometryMeshes.forEach((mesh) => {
35364
35022
  if (mesh.parent === rootObject) {
35365
35023
  rootObject.remove(mesh);
35366
35024
  }
35025
+ disposeMesh(mesh);
35367
35026
  });
35027
+ };
35028
+ }, [rootObject, geometryMeshes, visibility]);
35029
+ useEffect25(() => {
35030
+ if (!rootObject) return;
35031
+ textureMeshes.forEach((mesh) => {
35032
+ rootObject.add(mesh);
35033
+ });
35034
+ return () => {
35368
35035
  textureMeshes.forEach((mesh) => {
35369
35036
  if (mesh.parent === rootObject) {
35370
35037
  rootObject.remove(mesh);
35371
35038
  }
35372
- disposeTextureMesh(mesh);
35039
+ disposeMesh(mesh);
35373
35040
  });
35374
35041
  };
35375
- }, [rootObject, geometryMeshes, textureMeshes, visibility]);
35042
+ }, [rootObject, textureMeshes]);
35376
35043
  return null;
35377
35044
  };
35378
35045
  var MANIFOLD_CDN_BASE_URL = "https://cdn.jsdelivr.net/npm/manifold-3d@3.2.1";
@@ -35470,7 +35137,7 @@ try {
35470
35137
  [textures, boardData, pcbThickness, isFauxBoard]
35471
35138
  );
35472
35139
  const cadComponents = useMemo22(
35473
- () => su18(circuitJson).cad_component.list(),
35140
+ () => su17(circuitJson).cad_component.list(),
35474
35141
  [circuitJson]
35475
35142
  );
35476
35143
  const boardDimensions = useMemo22(() => {
@@ -42484,7 +42151,7 @@ var CadViewer = (props) => {
42484
42151
 
42485
42152
  // src/convert-circuit-json-to-3d-svg.ts
42486
42153
  var import_debug = __toESM(require_browser(), 1);
42487
- import { su as su19 } from "@tscircuit/circuit-json-util";
42154
+ import { su as su18 } from "@tscircuit/circuit-json-util";
42488
42155
  import * as THREE40 from "three";
42489
42156
  import { SVGRenderer } from "three/examples/jsm/renderers/SVGRenderer.js";
42490
42157
 
@@ -42713,11 +42380,11 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
42713
42380
  const pointLight = new THREE40.PointLight(16777215, Math.PI / 4);
42714
42381
  pointLight.position.set(-10, -10, 10);
42715
42382
  scene.add(pointLight);
42716
- const components = su19(circuitJson).cad_component.list();
42383
+ const components = su18(circuitJson).cad_component.list();
42717
42384
  for (const component of components) {
42718
42385
  await renderComponent(component, scene);
42719
42386
  }
42720
- const boardData = su19(circuitJson).pcb_board.list()[0];
42387
+ const boardData = su18(circuitJson).pcb_board.list()[0];
42721
42388
  const boardGeom = createBoardGeomFromCircuitJson(circuitJson);
42722
42389
  if (boardGeom) {
42723
42390
  const solderMaskColor = colors.fr4SolderMaskGreen;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/3d-viewer",
3
- "version": "0.0.519",
3
+ "version": "0.0.521",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.js",
6
6
  "type": "module",
@@ -30,7 +30,7 @@
30
30
  "@jscad/regl-renderer": "^2.6.12",
31
31
  "@jscad/stl-serializer": "^2.1.20",
32
32
  "circuit-json": "^0.0.372",
33
- "circuit-to-canvas": "^0.0.80",
33
+ "circuit-to-canvas": "^0.0.81",
34
34
  "react-hot-toast": "^2.6.0",
35
35
  "three": "^0.165.0",
36
36
  "three-stdlib": "^2.36.0",