@tscircuit/pcb-viewer 1.11.412 → 1.11.413
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -6
- package/dist/index.d.ts +1 -1
- package/dist/index.js +236 -226
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -98,27 +98,30 @@ continuously. The main thread handles React, interaction, and view messages.
|
|
|
98
98
|
There is no bitmap zoom-settle delay or pool of raster workers.
|
|
99
99
|
|
|
100
100
|
Pass `renderer="canvas"` to explicitly use the existing Canvas renderer. WebGPU
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
101
|
+
stays selected when WebGPU/OffscreenCanvas is unavailable, initialization fails,
|
|
102
|
+
the GPU device is lost, or the scene includes unsupported geometry (such as
|
|
103
|
+
dimension annotations or interpolated trace routes). These failures display an
|
|
104
|
+
error in the viewer and release the worker; they never start the Canvas renderer.
|
|
105
|
+
If the installed WebGPU renderer does not support X-Ray, the viewer displays a
|
|
106
|
+
notice and keeps the GPU view visible. The initial GPU geometry compile
|
|
104
107
|
still takes time on large boards, but runs in the worker. Curves use fixed
|
|
105
108
|
triangle tessellation and can show facets at extreme zoom.
|
|
106
109
|
|
|
107
110
|
Right-click the board and choose **Rendering Engine → Canvas** or
|
|
108
111
|
**WebGPU (experimental)** to switch without resetting pan, zoom, or layer visibility.
|
|
109
112
|
The `renderer` prop sets the initial selection; changing that prop updates the selection.
|
|
110
|
-
|
|
113
|
+
Switching to Canvas always requires an explicit engine selection.
|
|
111
114
|
|
|
112
115
|
Run `bun run test:webgpu` after `bunx playwright install chromium` to test the built
|
|
113
116
|
viewer bundle, AM3352 wheel zoom, resize, StrictMode cleanup, context-menu switching,
|
|
114
|
-
and
|
|
117
|
+
and failure handling. The Cosmos `WebGpuAm3352` fixture also switches between backends.
|
|
115
118
|
|
|
116
119
|
The WebGPU integration is still experimental. The complete imported Canvas suite
|
|
117
120
|
currently exposes substantial non-text parity gaps, including soldermask, trace
|
|
118
121
|
clipping, and keepouts. See the renderer's
|
|
119
122
|
[full parity report](https://github.com/tscircuit/circuit-json-webgpu/blob/main/tests/parity/latest-report.json).
|
|
120
123
|
The integration PR remains draft until these are resolved; existing diagnostics
|
|
121
|
-
|
|
124
|
+
do not yet detect every visual mismatch.
|
|
122
125
|
|
|
123
126
|
The WebGPU renderer is installed as a bundled devDependency from
|
|
124
127
|
`https://jscdn.tscircuit.com/@tscircuit/circuit-json-webgpu/0.0.3.tgz`.
|
package/dist/index.d.ts
CHANGED
|
@@ -82,7 +82,7 @@ type Props = {
|
|
|
82
82
|
circuitJson?: AnyCircuitElement[];
|
|
83
83
|
height?: number;
|
|
84
84
|
/** Initial engine; users can switch via the context menu. Prop changes reset it.
|
|
85
|
-
* WebGPU runs in a worker and
|
|
85
|
+
* WebGPU runs in a worker and reports failures without changing engines. */
|
|
86
86
|
renderer?: "webgpu" | "canvas";
|
|
87
87
|
allowEditing?: boolean;
|
|
88
88
|
editEvents?: ManualEditEvent[];
|
package/dist/index.js
CHANGED
|
@@ -11633,8 +11633,229 @@ var createWebGpuWorker = async () => {
|
|
|
11633
11633
|
};
|
|
11634
11634
|
|
|
11635
11635
|
// src/components/WebGpuElementsRenderer.tsx
|
|
11636
|
-
import { useEffect as
|
|
11637
|
-
import { SuperGrid
|
|
11636
|
+
import { useEffect as useEffect5, useMemo as useMemo3, useRef as useRef3, useState as useState4 } from "react";
|
|
11637
|
+
import { SuperGrid, toMMSI } from "react-supergrid";
|
|
11638
|
+
import { Fragment, jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
11639
|
+
function WebGpuElementsRenderer(props) {
|
|
11640
|
+
const { elements, primitives, transform, width = 500, height = 500 } = props;
|
|
11641
|
+
const holder = useRef3(null);
|
|
11642
|
+
const workerRef = useRef3(void 0);
|
|
11643
|
+
const ready = useRef3(false);
|
|
11644
|
+
const [supportsXRayNet, setSupportsXRayNet] = useState4(null);
|
|
11645
|
+
const [failure, setFailure] = useState4();
|
|
11646
|
+
const selectedLayer = useGlobalStore((s) => s.selected_layer);
|
|
11647
|
+
const hiddenLayerOpacity = useGlobalStore((s) => s.hidden_layer_opacity);
|
|
11648
|
+
const showCopperPours = useGlobalStore((s) => s.is_showing_copper_pours);
|
|
11649
|
+
const showSolderMask = useGlobalStore((s) => s.is_showing_solder_mask);
|
|
11650
|
+
const showSilkscreen = useGlobalStore((s) => s.is_showing_silkscreen);
|
|
11651
|
+
const showFabricationNotes = useGlobalStore(
|
|
11652
|
+
(s) => s.is_showing_fabrication_notes
|
|
11653
|
+
);
|
|
11654
|
+
const showPcbNotes = useGlobalStore((s) => s.is_showing_pcb_notes);
|
|
11655
|
+
const showCourtyards = useGlobalStore((s) => s.is_showing_courtyards);
|
|
11656
|
+
const highlightedElementIds = useMemo3(
|
|
11657
|
+
() => [
|
|
11658
|
+
...new Set(
|
|
11659
|
+
primitives.flatMap((p) => {
|
|
11660
|
+
if (!p.is_mouse_over && !p.is_in_highlighted_net) return [];
|
|
11661
|
+
const element = p._element;
|
|
11662
|
+
const id = element?.[`${element.type}_id`];
|
|
11663
|
+
return id ? [id] : [];
|
|
11664
|
+
})
|
|
11665
|
+
)
|
|
11666
|
+
],
|
|
11667
|
+
[primitives]
|
|
11668
|
+
);
|
|
11669
|
+
const xRayElementIds = useMemo3(
|
|
11670
|
+
() => (props.xRayElements ?? []).map(
|
|
11671
|
+
(element) => element[`${element.type}_id`]
|
|
11672
|
+
),
|
|
11673
|
+
[props.xRayElements]
|
|
11674
|
+
);
|
|
11675
|
+
const options = useMemo3(
|
|
11676
|
+
() => ({
|
|
11677
|
+
selectedLayer,
|
|
11678
|
+
hiddenLayerOpacity,
|
|
11679
|
+
showCopperPours,
|
|
11680
|
+
showSolderMask,
|
|
11681
|
+
showSilkscreen,
|
|
11682
|
+
showFabricationNotes,
|
|
11683
|
+
showPcbNotes,
|
|
11684
|
+
showCourtyards,
|
|
11685
|
+
highlightedElementIds,
|
|
11686
|
+
xRayElementIds
|
|
11687
|
+
}),
|
|
11688
|
+
[
|
|
11689
|
+
selectedLayer,
|
|
11690
|
+
hiddenLayerOpacity,
|
|
11691
|
+
showCopperPours,
|
|
11692
|
+
showSolderMask,
|
|
11693
|
+
showSilkscreen,
|
|
11694
|
+
showFabricationNotes,
|
|
11695
|
+
showPcbNotes,
|
|
11696
|
+
showCourtyards,
|
|
11697
|
+
highlightedElementIds,
|
|
11698
|
+
xRayElementIds
|
|
11699
|
+
]
|
|
11700
|
+
);
|
|
11701
|
+
const sceneRef = useRef3(elements);
|
|
11702
|
+
const viewRef = useRef3(void 0);
|
|
11703
|
+
sceneRef.current = elements;
|
|
11704
|
+
if (transform) {
|
|
11705
|
+
const ratio = typeof window === "undefined" ? 1 : window.devicePixelRatio || 1;
|
|
11706
|
+
viewRef.current = {
|
|
11707
|
+
type: "view",
|
|
11708
|
+
width: Math.max(1, Math.round(width * ratio)),
|
|
11709
|
+
height: Math.max(1, Math.round(height * ratio)),
|
|
11710
|
+
transform: {
|
|
11711
|
+
a: transform.a * ratio,
|
|
11712
|
+
b: transform.b * ratio,
|
|
11713
|
+
c: transform.c * ratio,
|
|
11714
|
+
d: transform.d * ratio,
|
|
11715
|
+
e: transform.e * ratio,
|
|
11716
|
+
f: transform.f * ratio
|
|
11717
|
+
},
|
|
11718
|
+
options
|
|
11719
|
+
};
|
|
11720
|
+
}
|
|
11721
|
+
useEffect5(() => {
|
|
11722
|
+
let disposed = false, failed = false, worker;
|
|
11723
|
+
const canvas = document.createElement("canvas");
|
|
11724
|
+
canvas.className = "pcb-webgpu-canvas";
|
|
11725
|
+
canvas.style.cssText = "position:absolute;inset:0;width:100%;height:100%;pointer-events:none";
|
|
11726
|
+
holder.current?.append(canvas);
|
|
11727
|
+
const fail = (message) => {
|
|
11728
|
+
if (disposed || failed) return;
|
|
11729
|
+
failed = true;
|
|
11730
|
+
clearTimeout(timeout);
|
|
11731
|
+
canvas.remove();
|
|
11732
|
+
ready.current = false;
|
|
11733
|
+
worker?.terminate();
|
|
11734
|
+
worker = void 0;
|
|
11735
|
+
workerRef.current = void 0;
|
|
11736
|
+
if (holder.current) holder.current.dataset.xRayNetActive = "false";
|
|
11737
|
+
setFailure(message);
|
|
11738
|
+
};
|
|
11739
|
+
const timeout = setTimeout(
|
|
11740
|
+
() => fail("WebGPU worker startup timed out"),
|
|
11741
|
+
15e3
|
|
11742
|
+
);
|
|
11743
|
+
void (async () => {
|
|
11744
|
+
try {
|
|
11745
|
+
if (!navigator.gpu || typeof Worker === "undefined" || !canvas.transferControlToOffscreen)
|
|
11746
|
+
throw new Error("WebGPU workers are unavailable");
|
|
11747
|
+
worker = await createWebGpuWorker();
|
|
11748
|
+
if (disposed || failed) {
|
|
11749
|
+
worker.terminate();
|
|
11750
|
+
return;
|
|
11751
|
+
}
|
|
11752
|
+
workerRef.current = worker;
|
|
11753
|
+
worker.onmessage = ({ data }) => {
|
|
11754
|
+
if (disposed || failed) return;
|
|
11755
|
+
if (data.type === "rendered") {
|
|
11756
|
+
if (holder.current)
|
|
11757
|
+
holder.current.dataset.xRayNetActive = String(data.xRayActive);
|
|
11758
|
+
} else if (data.type === "error") {
|
|
11759
|
+
fail(data.message);
|
|
11760
|
+
} else if (data.type === "ready") {
|
|
11761
|
+
clearTimeout(timeout);
|
|
11762
|
+
setSupportsXRayNet(data.supportsXRayNet);
|
|
11763
|
+
ready.current = true;
|
|
11764
|
+
worker.postMessage({
|
|
11765
|
+
type: "scene",
|
|
11766
|
+
elements: sceneRef.current
|
|
11767
|
+
});
|
|
11768
|
+
if (viewRef.current) worker.postMessage(viewRef.current);
|
|
11769
|
+
}
|
|
11770
|
+
};
|
|
11771
|
+
worker.onerror = (event) => {
|
|
11772
|
+
event.preventDefault();
|
|
11773
|
+
fail(event.message || "WebGPU worker failed");
|
|
11774
|
+
};
|
|
11775
|
+
worker.addEventListener("messageerror", () => {
|
|
11776
|
+
fail("WebGPU worker communication failed");
|
|
11777
|
+
});
|
|
11778
|
+
const offscreen = canvas.transferControlToOffscreen();
|
|
11779
|
+
worker.postMessage(
|
|
11780
|
+
{ type: "init", canvas: offscreen },
|
|
11781
|
+
[offscreen]
|
|
11782
|
+
);
|
|
11783
|
+
} catch (error) {
|
|
11784
|
+
fail(String(error));
|
|
11785
|
+
}
|
|
11786
|
+
})();
|
|
11787
|
+
return () => {
|
|
11788
|
+
disposed = true;
|
|
11789
|
+
clearTimeout(timeout);
|
|
11790
|
+
ready.current = false;
|
|
11791
|
+
workerRef.current = void 0;
|
|
11792
|
+
worker?.terminate();
|
|
11793
|
+
canvas.remove();
|
|
11794
|
+
};
|
|
11795
|
+
}, []);
|
|
11796
|
+
useEffect5(() => {
|
|
11797
|
+
if (ready.current)
|
|
11798
|
+
workerRef.current?.postMessage({
|
|
11799
|
+
type: "scene",
|
|
11800
|
+
elements
|
|
11801
|
+
});
|
|
11802
|
+
}, [elements]);
|
|
11803
|
+
useEffect5(() => {
|
|
11804
|
+
if (ready.current && viewRef.current)
|
|
11805
|
+
workerRef.current?.postMessage(viewRef.current);
|
|
11806
|
+
}, [transform, width, height, options]);
|
|
11807
|
+
const xRayUnavailable = Boolean(
|
|
11808
|
+
props.xRayElements && supportsXRayNet === false
|
|
11809
|
+
);
|
|
11810
|
+
return /* @__PURE__ */ jsx3(
|
|
11811
|
+
"div",
|
|
11812
|
+
{
|
|
11813
|
+
ref: holder,
|
|
11814
|
+
"data-pcb-renderer": "webgpu",
|
|
11815
|
+
"data-webgpu-error": failure,
|
|
11816
|
+
style: {
|
|
11817
|
+
width,
|
|
11818
|
+
height,
|
|
11819
|
+
background: "black",
|
|
11820
|
+
position: "relative",
|
|
11821
|
+
overflow: "hidden"
|
|
11822
|
+
},
|
|
11823
|
+
children: failure ? /* @__PURE__ */ jsxs(
|
|
11824
|
+
"div",
|
|
11825
|
+
{
|
|
11826
|
+
role: "alert",
|
|
11827
|
+
style: { padding: 16, color: "white", position: "relative" },
|
|
11828
|
+
children: [
|
|
11829
|
+
/* @__PURE__ */ jsx3("strong", { children: "WebGPU rendering failed" }),
|
|
11830
|
+
/* @__PURE__ */ jsx3("div", { children: failure })
|
|
11831
|
+
]
|
|
11832
|
+
}
|
|
11833
|
+
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
11834
|
+
/* @__PURE__ */ jsx3(
|
|
11835
|
+
SuperGrid,
|
|
11836
|
+
{
|
|
11837
|
+
textColor: "rgba(0,255,0,0.8)",
|
|
11838
|
+
majorColor: "rgba(0,255,0,0.4)",
|
|
11839
|
+
minorColor: "rgba(0,255,0,0.2)",
|
|
11840
|
+
screenSpaceCellSize: 200,
|
|
11841
|
+
width,
|
|
11842
|
+
height,
|
|
11843
|
+
transform,
|
|
11844
|
+
stringifyCoord: (x, y, z) => `${toMMSI(x, z)}, ${toMMSI(y, z)}`
|
|
11845
|
+
}
|
|
11846
|
+
),
|
|
11847
|
+
xRayUnavailable && /* @__PURE__ */ jsx3(
|
|
11848
|
+
"div",
|
|
11849
|
+
{
|
|
11850
|
+
role: "status",
|
|
11851
|
+
style: { padding: 16, color: "white", position: "relative" },
|
|
11852
|
+
children: "X-Ray is unavailable in this WebGPU renderer."
|
|
11853
|
+
}
|
|
11854
|
+
)
|
|
11855
|
+
] })
|
|
11856
|
+
}
|
|
11857
|
+
);
|
|
11858
|
+
}
|
|
11638
11859
|
|
|
11639
11860
|
// src/components/CanvasPrimitiveRenderer.tsx
|
|
11640
11861
|
import { CircuitToCanvasDrawer as CircuitToCanvasDrawer17 } from "circuit-to-canvas";
|
|
@@ -13577,9 +13798,9 @@ var getPrimitivesForDrawer = ({
|
|
|
13577
13798
|
).filter((primitive) => primitive._element?.type !== "pcb_via").filter((primitive) => primitive._element?.type !== "pcb_trace").filter((primitive) => primitive._element?.type !== "pcb_copper_text");
|
|
13578
13799
|
|
|
13579
13800
|
// src/components/CanvasPrimitiveRenderer.tsx
|
|
13580
|
-
import { useEffect as
|
|
13581
|
-
import { SuperGrid, toMMSI } from "react-supergrid";
|
|
13582
|
-
import { jsx as
|
|
13801
|
+
import { useEffect as useEffect6, useRef as useRef4 } from "react";
|
|
13802
|
+
import { SuperGrid as SuperGrid2, toMMSI as toMMSI2 } from "react-supergrid";
|
|
13803
|
+
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
13583
13804
|
var CanvasPrimitiveRenderer = ({
|
|
13584
13805
|
primitives,
|
|
13585
13806
|
elements,
|
|
@@ -13589,8 +13810,8 @@ var CanvasPrimitiveRenderer = ({
|
|
|
13589
13810
|
width = 500,
|
|
13590
13811
|
height = 500
|
|
13591
13812
|
}) => {
|
|
13592
|
-
const xRayCanvasRef =
|
|
13593
|
-
const canvasRefs =
|
|
13813
|
+
const xRayCanvasRef = useRef4(null);
|
|
13814
|
+
const canvasRefs = useRef4({});
|
|
13594
13815
|
const hiddenLayerOpacity = useGlobalStore((s) => s.hidden_layer_opacity);
|
|
13595
13816
|
const selectedLayer = useGlobalStore((s) => s.selected_layer);
|
|
13596
13817
|
const isShowingCopperPours = useGlobalStore((s) => s.is_showing_copper_pours);
|
|
@@ -13601,7 +13822,7 @@ var CanvasPrimitiveRenderer = ({
|
|
|
13601
13822
|
const isShowingPcbNotes = useGlobalStore((s) => s.is_showing_pcb_notes);
|
|
13602
13823
|
const isShowingCourtyards = useGlobalStore((s) => s.is_showing_courtyards);
|
|
13603
13824
|
const isShowingSilkscreen = useGlobalStore((s) => s.is_showing_silkscreen);
|
|
13604
|
-
|
|
13825
|
+
useEffect6(() => {
|
|
13605
13826
|
if (!canvasRefs.current) return;
|
|
13606
13827
|
if (Object.keys(canvasRefs.current).length === 0) return;
|
|
13607
13828
|
const availableCanvasRefs = Object.fromEntries(
|
|
@@ -13898,7 +14119,7 @@ var CanvasPrimitiveRenderer = ({
|
|
|
13898
14119
|
isShowingCourtyards,
|
|
13899
14120
|
isShowingSilkscreen
|
|
13900
14121
|
]);
|
|
13901
|
-
return /* @__PURE__ */
|
|
14122
|
+
return /* @__PURE__ */ jsxs2(
|
|
13902
14123
|
"div",
|
|
13903
14124
|
{
|
|
13904
14125
|
style: {
|
|
@@ -13908,8 +14129,8 @@ var CanvasPrimitiveRenderer = ({
|
|
|
13908
14129
|
position: "relative"
|
|
13909
14130
|
},
|
|
13910
14131
|
children: [
|
|
13911
|
-
/* @__PURE__ */
|
|
13912
|
-
|
|
14132
|
+
/* @__PURE__ */ jsx4(
|
|
14133
|
+
SuperGrid2,
|
|
13913
14134
|
{
|
|
13914
14135
|
textColor: "rgba(0,255,0,0.8)",
|
|
13915
14136
|
majorColor: "rgba(0,255,0,0.4)",
|
|
@@ -13918,10 +14139,10 @@ var CanvasPrimitiveRenderer = ({
|
|
|
13918
14139
|
width,
|
|
13919
14140
|
height,
|
|
13920
14141
|
transform,
|
|
13921
|
-
stringifyCoord: (x, y, z) => `${
|
|
14142
|
+
stringifyCoord: (x, y, z) => `${toMMSI2(x, z)}, ${toMMSI2(y, z)}`
|
|
13922
14143
|
}
|
|
13923
14144
|
),
|
|
13924
|
-
xRayElements && /* @__PURE__ */
|
|
14145
|
+
xRayElements && /* @__PURE__ */ jsx4(
|
|
13925
14146
|
"canvas",
|
|
13926
14147
|
{
|
|
13927
14148
|
ref: xRayCanvasRef,
|
|
@@ -13941,7 +14162,7 @@ var CanvasPrimitiveRenderer = ({
|
|
|
13941
14162
|
if (!isShowingSolderMask && layer.includes("soldermask")) return false;
|
|
13942
14163
|
if (!isShowingSilkscreen && layer.includes("silkscreen")) return false;
|
|
13943
14164
|
return true;
|
|
13944
|
-
}).map((l) => l.replace(/-/g, "")).map((layer, i) => /* @__PURE__ */
|
|
14165
|
+
}).map((l) => l.replace(/-/g, "")).map((layer, i) => /* @__PURE__ */ jsx4(
|
|
13945
14166
|
"canvas",
|
|
13946
14167
|
{
|
|
13947
14168
|
className: `pcb-layer-${layer}`,
|
|
@@ -13970,217 +14191,6 @@ var CanvasPrimitiveRenderer = ({
|
|
|
13970
14191
|
);
|
|
13971
14192
|
};
|
|
13972
14193
|
|
|
13973
|
-
// src/components/WebGpuElementsRenderer.tsx
|
|
13974
|
-
import { Fragment, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
13975
|
-
function WebGpuElementsRenderer(props) {
|
|
13976
|
-
const { elements, primitives, transform, width = 500, height = 500 } = props;
|
|
13977
|
-
const holder = useRef4(null);
|
|
13978
|
-
const workerRef = useRef4(void 0);
|
|
13979
|
-
const ready = useRef4(false);
|
|
13980
|
-
const [supportsXRayNet, setSupportsXRayNet] = useState4(false);
|
|
13981
|
-
const [failure, setFailure] = useState4();
|
|
13982
|
-
const selectedLayer = useGlobalStore((s) => s.selected_layer);
|
|
13983
|
-
const hiddenLayerOpacity = useGlobalStore((s) => s.hidden_layer_opacity);
|
|
13984
|
-
const showCopperPours = useGlobalStore((s) => s.is_showing_copper_pours);
|
|
13985
|
-
const showSolderMask = useGlobalStore((s) => s.is_showing_solder_mask);
|
|
13986
|
-
const showSilkscreen = useGlobalStore((s) => s.is_showing_silkscreen);
|
|
13987
|
-
const showFabricationNotes = useGlobalStore(
|
|
13988
|
-
(s) => s.is_showing_fabrication_notes
|
|
13989
|
-
);
|
|
13990
|
-
const showPcbNotes = useGlobalStore((s) => s.is_showing_pcb_notes);
|
|
13991
|
-
const showCourtyards = useGlobalStore((s) => s.is_showing_courtyards);
|
|
13992
|
-
const highlightedElementIds = useMemo3(
|
|
13993
|
-
() => [
|
|
13994
|
-
...new Set(
|
|
13995
|
-
primitives.flatMap((p) => {
|
|
13996
|
-
if (!p.is_mouse_over && !p.is_in_highlighted_net) return [];
|
|
13997
|
-
const element = p._element;
|
|
13998
|
-
const id = element?.[`${element.type}_id`];
|
|
13999
|
-
return id ? [id] : [];
|
|
14000
|
-
})
|
|
14001
|
-
)
|
|
14002
|
-
],
|
|
14003
|
-
[primitives]
|
|
14004
|
-
);
|
|
14005
|
-
const xRayElementIds = useMemo3(
|
|
14006
|
-
() => (props.xRayElements ?? []).map(
|
|
14007
|
-
(element) => element[`${element.type}_id`]
|
|
14008
|
-
),
|
|
14009
|
-
[props.xRayElements]
|
|
14010
|
-
);
|
|
14011
|
-
const options = useMemo3(
|
|
14012
|
-
() => ({
|
|
14013
|
-
selectedLayer,
|
|
14014
|
-
hiddenLayerOpacity,
|
|
14015
|
-
showCopperPours,
|
|
14016
|
-
showSolderMask,
|
|
14017
|
-
showSilkscreen,
|
|
14018
|
-
showFabricationNotes,
|
|
14019
|
-
showPcbNotes,
|
|
14020
|
-
showCourtyards,
|
|
14021
|
-
highlightedElementIds,
|
|
14022
|
-
xRayElementIds
|
|
14023
|
-
}),
|
|
14024
|
-
[
|
|
14025
|
-
selectedLayer,
|
|
14026
|
-
hiddenLayerOpacity,
|
|
14027
|
-
showCopperPours,
|
|
14028
|
-
showSolderMask,
|
|
14029
|
-
showSilkscreen,
|
|
14030
|
-
showFabricationNotes,
|
|
14031
|
-
showPcbNotes,
|
|
14032
|
-
showCourtyards,
|
|
14033
|
-
highlightedElementIds,
|
|
14034
|
-
xRayElementIds
|
|
14035
|
-
]
|
|
14036
|
-
);
|
|
14037
|
-
const sceneRef = useRef4(elements);
|
|
14038
|
-
const viewRef = useRef4(void 0);
|
|
14039
|
-
sceneRef.current = elements;
|
|
14040
|
-
if (transform) {
|
|
14041
|
-
const ratio = typeof window === "undefined" ? 1 : window.devicePixelRatio || 1;
|
|
14042
|
-
viewRef.current = {
|
|
14043
|
-
type: "view",
|
|
14044
|
-
width: Math.max(1, Math.round(width * ratio)),
|
|
14045
|
-
height: Math.max(1, Math.round(height * ratio)),
|
|
14046
|
-
transform: {
|
|
14047
|
-
a: transform.a * ratio,
|
|
14048
|
-
b: transform.b * ratio,
|
|
14049
|
-
c: transform.c * ratio,
|
|
14050
|
-
d: transform.d * ratio,
|
|
14051
|
-
e: transform.e * ratio,
|
|
14052
|
-
f: transform.f * ratio
|
|
14053
|
-
},
|
|
14054
|
-
options
|
|
14055
|
-
};
|
|
14056
|
-
}
|
|
14057
|
-
useEffect6(() => {
|
|
14058
|
-
let disposed = false, failed = false, worker;
|
|
14059
|
-
const canvas = document.createElement("canvas");
|
|
14060
|
-
canvas.className = "pcb-webgpu-canvas";
|
|
14061
|
-
canvas.style.cssText = "position:absolute;inset:0;width:100%;height:100%;pointer-events:none";
|
|
14062
|
-
holder.current?.append(canvas);
|
|
14063
|
-
const fallback = (message) => {
|
|
14064
|
-
if (disposed || failed) return;
|
|
14065
|
-
failed = true;
|
|
14066
|
-
canvas.remove();
|
|
14067
|
-
ready.current = false;
|
|
14068
|
-
worker?.terminate();
|
|
14069
|
-
workerRef.current = void 0;
|
|
14070
|
-
setFailure(message);
|
|
14071
|
-
};
|
|
14072
|
-
const timeout = setTimeout(
|
|
14073
|
-
() => fallback("WebGPU worker startup timed out"),
|
|
14074
|
-
15e3
|
|
14075
|
-
);
|
|
14076
|
-
void (async () => {
|
|
14077
|
-
try {
|
|
14078
|
-
if (!navigator.gpu || typeof Worker === "undefined" || !canvas.transferControlToOffscreen)
|
|
14079
|
-
throw new Error("WebGPU workers are unavailable");
|
|
14080
|
-
worker = await createWebGpuWorker();
|
|
14081
|
-
if (disposed || failed) {
|
|
14082
|
-
worker.terminate();
|
|
14083
|
-
return;
|
|
14084
|
-
}
|
|
14085
|
-
workerRef.current = worker;
|
|
14086
|
-
worker.onmessage = ({ data }) => {
|
|
14087
|
-
if (disposed || failed) return;
|
|
14088
|
-
if (data.type === "rendered") {
|
|
14089
|
-
if (holder.current)
|
|
14090
|
-
holder.current.dataset.xRayNetActive = String(data.xRayActive);
|
|
14091
|
-
} else if (data.type === "error") {
|
|
14092
|
-
clearTimeout(timeout);
|
|
14093
|
-
fallback(data.message);
|
|
14094
|
-
} else if (data.type === "ready") {
|
|
14095
|
-
clearTimeout(timeout);
|
|
14096
|
-
setSupportsXRayNet(data.supportsXRayNet);
|
|
14097
|
-
ready.current = true;
|
|
14098
|
-
worker.postMessage({
|
|
14099
|
-
type: "scene",
|
|
14100
|
-
elements: sceneRef.current
|
|
14101
|
-
});
|
|
14102
|
-
if (viewRef.current) worker.postMessage(viewRef.current);
|
|
14103
|
-
}
|
|
14104
|
-
};
|
|
14105
|
-
worker.onerror = (event) => {
|
|
14106
|
-
event.preventDefault();
|
|
14107
|
-
clearTimeout(timeout);
|
|
14108
|
-
fallback(event.message || "WebGPU worker failed");
|
|
14109
|
-
};
|
|
14110
|
-
worker.onmessageerror = () => {
|
|
14111
|
-
clearTimeout(timeout);
|
|
14112
|
-
fallback("WebGPU worker communication failed");
|
|
14113
|
-
};
|
|
14114
|
-
const offscreen = canvas.transferControlToOffscreen();
|
|
14115
|
-
worker.postMessage(
|
|
14116
|
-
{ type: "init", canvas: offscreen },
|
|
14117
|
-
[offscreen]
|
|
14118
|
-
);
|
|
14119
|
-
} catch (error) {
|
|
14120
|
-
clearTimeout(timeout);
|
|
14121
|
-
fallback(String(error));
|
|
14122
|
-
}
|
|
14123
|
-
})();
|
|
14124
|
-
return () => {
|
|
14125
|
-
disposed = true;
|
|
14126
|
-
clearTimeout(timeout);
|
|
14127
|
-
ready.current = false;
|
|
14128
|
-
workerRef.current = void 0;
|
|
14129
|
-
worker?.terminate();
|
|
14130
|
-
canvas.remove();
|
|
14131
|
-
};
|
|
14132
|
-
}, []);
|
|
14133
|
-
useEffect6(() => {
|
|
14134
|
-
if (ready.current)
|
|
14135
|
-
workerRef.current?.postMessage({
|
|
14136
|
-
type: "scene",
|
|
14137
|
-
elements
|
|
14138
|
-
});
|
|
14139
|
-
}, [elements]);
|
|
14140
|
-
useEffect6(() => {
|
|
14141
|
-
if (ready.current && viewRef.current)
|
|
14142
|
-
workerRef.current?.postMessage(viewRef.current);
|
|
14143
|
-
}, [transform, width, height, options]);
|
|
14144
|
-
const fallbackElements = useMemo3(
|
|
14145
|
-
() => showCopperPours ? elements : elements.filter((e) => e.type !== "pcb_copper_pour"),
|
|
14146
|
-
[elements, showCopperPours]
|
|
14147
|
-
);
|
|
14148
|
-
if (failure)
|
|
14149
|
-
return /* @__PURE__ */ jsx4("div", { "data-pcb-renderer": "canvas", "data-webgpu-fallback": failure, children: /* @__PURE__ */ jsx4(CanvasPrimitiveRenderer, { ...props, elements: fallbackElements }) });
|
|
14150
|
-
const useXRayFallback = Boolean(props.xRayElements && !supportsXRayNet);
|
|
14151
|
-
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
14152
|
-
useXRayFallback && /* @__PURE__ */ jsx4("div", { "data-x-ray-fallback": "unsupported-webgpu-version", children: /* @__PURE__ */ jsx4(CanvasPrimitiveRenderer, { ...props, elements: fallbackElements }) }),
|
|
14153
|
-
/* @__PURE__ */ jsx4(
|
|
14154
|
-
"div",
|
|
14155
|
-
{
|
|
14156
|
-
ref: holder,
|
|
14157
|
-
"data-pcb-renderer": "webgpu",
|
|
14158
|
-
style: {
|
|
14159
|
-
width,
|
|
14160
|
-
height,
|
|
14161
|
-
background: "black",
|
|
14162
|
-
position: "relative",
|
|
14163
|
-
overflow: "hidden",
|
|
14164
|
-
display: useXRayFallback ? "none" : void 0
|
|
14165
|
-
},
|
|
14166
|
-
children: /* @__PURE__ */ jsx4(
|
|
14167
|
-
SuperGrid2,
|
|
14168
|
-
{
|
|
14169
|
-
textColor: "rgba(0,255,0,0.8)",
|
|
14170
|
-
majorColor: "rgba(0,255,0,0.4)",
|
|
14171
|
-
minorColor: "rgba(0,255,0,0.2)",
|
|
14172
|
-
screenSpaceCellSize: 200,
|
|
14173
|
-
width,
|
|
14174
|
-
height,
|
|
14175
|
-
transform,
|
|
14176
|
-
stringifyCoord: (x, y, z) => `${toMMSI2(x, z)}, ${toMMSI2(y, z)}`
|
|
14177
|
-
}
|
|
14178
|
-
)
|
|
14179
|
-
}
|
|
14180
|
-
)
|
|
14181
|
-
] });
|
|
14182
|
-
}
|
|
14183
|
-
|
|
14184
14194
|
// node_modules/graphics-debug/dist/chunk-OHVOYMJ4.js
|
|
14185
14195
|
import {
|
|
14186
14196
|
glyphAdvanceRatio,
|
|
@@ -18359,7 +18369,7 @@ import { css as css3 } from "@emotion/css";
|
|
|
18359
18369
|
// package.json
|
|
18360
18370
|
var package_default = {
|
|
18361
18371
|
name: "@tscircuit/pcb-viewer",
|
|
18362
|
-
version: "1.11.
|
|
18372
|
+
version: "1.11.412",
|
|
18363
18373
|
main: "dist/index.js",
|
|
18364
18374
|
type: "module",
|
|
18365
18375
|
repository: {
|