@tscircuit/3d-viewer 0.0.639 → 0.0.641
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 +4 -1
- package/dist/index.js +70 -33
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -121,6 +121,7 @@ const svgString = await convert3dCircuitToSvg(circuitJson, options)
|
|
|
121
121
|
```
|
|
122
122
|
|
|
123
123
|
The `convert3dCircuitToSvg` function accepts the following options:
|
|
124
|
+
|
|
124
125
|
- `width`: Width of the output SVG (default: 800)
|
|
125
126
|
- `height`: Height of the output SVG (default: 600)
|
|
126
127
|
- `backgroundColor`: Background color in hex format (default: "#ffffff")
|
|
@@ -137,6 +138,7 @@ The `convert3dCircuitToSvg` function accepts the following options:
|
|
|
137
138
|
Main component for rendering the 3D PCB viewer.
|
|
138
139
|
|
|
139
140
|
Props:
|
|
141
|
+
|
|
140
142
|
- `circuit-json`: (optional) An array of AnyCircuitElement objects representing the PCB layout.
|
|
141
143
|
- `children`: (optional) React children elements describing the PCB layout (alternative to using `circuit-json`).
|
|
142
144
|
- `resolveStaticAsset`: (optional) Function that receives each component model URL (`obj`, `wrl`, `stl`, `gltf`, `glb`, `step`) and returns the resolved URL to load.
|
|
@@ -146,12 +148,14 @@ Props:
|
|
|
146
148
|
Defines the PCB board dimensions.
|
|
147
149
|
|
|
148
150
|
Props:
|
|
151
|
+
|
|
149
152
|
- `width`: Width of the board (e.g., "20mm").
|
|
150
153
|
- `height`: Height of the board (e.g., "20mm").
|
|
151
154
|
|
|
152
155
|
### Component Elements
|
|
153
156
|
|
|
154
157
|
Various component elements can be used as children of the `<board>` element:
|
|
158
|
+
|
|
155
159
|
- `<resistor>`
|
|
156
160
|
- `<capacitor>`
|
|
157
161
|
- `<chip>`
|
|
@@ -306,7 +310,6 @@ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) f
|
|
|
306
310
|
|
|
307
311
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
308
312
|
|
|
309
|
-
|
|
310
313
|
### Section views
|
|
311
314
|
|
|
312
315
|
Right-click the viewer and choose **Advanced → Section View…**.
|
package/dist/index.js
CHANGED
|
@@ -19303,6 +19303,17 @@ var useObjectVisibility = (circuitKey) => {
|
|
|
19303
19303
|
};
|
|
19304
19304
|
};
|
|
19305
19305
|
|
|
19306
|
+
// src/utils/find-model-object.ts
|
|
19307
|
+
var findModelObject = (root, objectId) => {
|
|
19308
|
+
let model;
|
|
19309
|
+
root.traverse((object) => {
|
|
19310
|
+
const { cad_component_id, cad_cable_id } = object.userData;
|
|
19311
|
+
if (!model && (cad_component_id ?? cad_cable_id) === objectId)
|
|
19312
|
+
model = object;
|
|
19313
|
+
});
|
|
19314
|
+
return model;
|
|
19315
|
+
};
|
|
19316
|
+
|
|
19306
19317
|
// src/utils/configure-runtime-font.ts
|
|
19307
19318
|
import { configureTextBuilder } from "troika-three-text";
|
|
19308
19319
|
|
|
@@ -22333,7 +22344,7 @@ import * as THREE31 from "three";
|
|
|
22333
22344
|
// package.json
|
|
22334
22345
|
var package_default = {
|
|
22335
22346
|
name: "@tscircuit/3d-viewer",
|
|
22336
|
-
version: "0.0.
|
|
22347
|
+
version: "0.0.640",
|
|
22337
22348
|
repository: {
|
|
22338
22349
|
type: "git",
|
|
22339
22350
|
url: "https://github.com/tscircuit/3d-viewer"
|
|
@@ -22849,6 +22860,7 @@ var Canvas = forwardRef(
|
|
|
22849
22860
|
mountRef.current.removeChild(renderer.domElement);
|
|
22850
22861
|
}
|
|
22851
22862
|
renderer.dispose();
|
|
22863
|
+
renderer.forceContextLoss();
|
|
22852
22864
|
scene.remove(rootObject.current);
|
|
22853
22865
|
if (window.__TSCIRCUIT_THREE_OBJECT === rootObject.current) {
|
|
22854
22866
|
window.__TSCIRCUIT_THREE_OBJECT = void 0;
|
|
@@ -39249,6 +39261,7 @@ var ContextMenu = ({
|
|
|
39249
39261
|
onSectionView,
|
|
39250
39262
|
onExplosionView,
|
|
39251
39263
|
explosionAvailable = false,
|
|
39264
|
+
downloadModelName,
|
|
39252
39265
|
onDownloadGltf,
|
|
39253
39266
|
onOpenKeyboardShortcuts
|
|
39254
39267
|
}) => {
|
|
@@ -39559,7 +39572,7 @@ var ContextMenu = ({
|
|
|
39559
39572
|
}
|
|
39560
39573
|
),
|
|
39561
39574
|
/* @__PURE__ */ jsx40(DropdownMenuSeparator, { style: separatorStyles2 }),
|
|
39562
|
-
/* @__PURE__ */
|
|
39575
|
+
/* @__PURE__ */ jsxs10(
|
|
39563
39576
|
DropdownMenuItem,
|
|
39564
39577
|
{
|
|
39565
39578
|
style: {
|
|
@@ -39571,7 +39584,10 @@ var ContextMenu = ({
|
|
|
39571
39584
|
onMouseEnter: () => setHoveredItem("download"),
|
|
39572
39585
|
onMouseLeave: () => setHoveredItem(null),
|
|
39573
39586
|
onTouchStart: () => setHoveredItem("download"),
|
|
39574
|
-
children:
|
|
39587
|
+
children: [
|
|
39588
|
+
/* @__PURE__ */ jsx40("span", { style: { flex: 1, display: "flex", alignItems: "center" }, children: "Download GLTF" }),
|
|
39589
|
+
downloadModelName && /* @__PURE__ */ jsx40("span", { style: { opacity: 0.55, fontSize: 13 }, children: downloadModelName })
|
|
39590
|
+
]
|
|
39575
39591
|
}
|
|
39576
39592
|
),
|
|
39577
39593
|
/* @__PURE__ */ jsx40(DropdownMenuSeparator, { style: separatorStyles2 }),
|
|
@@ -40400,34 +40416,51 @@ function createSectionExport(root, spec) {
|
|
|
40400
40416
|
// src/hooks/useGlobalDownloadGltf.ts
|
|
40401
40417
|
import { useCallback as useCallback24 } from "react";
|
|
40402
40418
|
import { GLTFExporter as GLTFExporter2 } from "three/examples/jsm/exporters/GLTFExporter.js";
|
|
40419
|
+
|
|
40420
|
+
// src/utils/clone-model-for-export.ts
|
|
40421
|
+
var cloneModelForExport = (root, objectId) => {
|
|
40422
|
+
const source = findModelObject(root, objectId);
|
|
40423
|
+
if (!source) return;
|
|
40424
|
+
source.updateWorldMatrix(true, true);
|
|
40425
|
+
const output = source.clone(true);
|
|
40426
|
+
source.matrixWorld.decompose(output.position, output.quaternion, output.scale);
|
|
40427
|
+
return output;
|
|
40428
|
+
};
|
|
40429
|
+
|
|
40430
|
+
// src/hooks/useGlobalDownloadGltf.ts
|
|
40403
40431
|
var useGlobalDownloadGltf = () => {
|
|
40404
|
-
return useCallback24(
|
|
40405
|
-
|
|
40406
|
-
|
|
40407
|
-
|
|
40408
|
-
|
|
40409
|
-
|
|
40410
|
-
|
|
40411
|
-
sectionExport
|
|
40412
|
-
(
|
|
40413
|
-
|
|
40414
|
-
|
|
40415
|
-
|
|
40416
|
-
|
|
40417
|
-
|
|
40418
|
-
|
|
40419
|
-
|
|
40420
|
-
|
|
40421
|
-
|
|
40422
|
-
|
|
40423
|
-
|
|
40424
|
-
|
|
40425
|
-
|
|
40426
|
-
|
|
40427
|
-
|
|
40428
|
-
|
|
40429
|
-
|
|
40430
|
-
|
|
40432
|
+
return useCallback24(
|
|
40433
|
+
(model, root = window.__TSCIRCUIT_THREE_OBJECT) => {
|
|
40434
|
+
if (!root) return;
|
|
40435
|
+
const target = model ? cloneModelForExport(root, model.objectId) : root;
|
|
40436
|
+
if (!target) return;
|
|
40437
|
+
if (model) target.name = model.name;
|
|
40438
|
+
const section = root.userData.sectionView;
|
|
40439
|
+
const sectionExport = section ? createSectionExport(target, section) : void 0;
|
|
40440
|
+
const exporter = new GLTFExporter2();
|
|
40441
|
+
exporter.parse(
|
|
40442
|
+
sectionExport?.root ?? target,
|
|
40443
|
+
(gltf) => {
|
|
40444
|
+
sectionExport?.dispose();
|
|
40445
|
+
const blob = new Blob(
|
|
40446
|
+
[gltf instanceof ArrayBuffer ? gltf : JSON.stringify(gltf)],
|
|
40447
|
+
{ type: "model/gltf+json" }
|
|
40448
|
+
);
|
|
40449
|
+
const url = URL.createObjectURL(blob);
|
|
40450
|
+
const link = document.createElement("a");
|
|
40451
|
+
link.href = url;
|
|
40452
|
+
link.download = model ? `${model.name}.gltf` : "scene.gltf";
|
|
40453
|
+
link.click();
|
|
40454
|
+
URL.revokeObjectURL(url);
|
|
40455
|
+
},
|
|
40456
|
+
(err) => {
|
|
40457
|
+
sectionExport?.dispose();
|
|
40458
|
+
console.error("Failed to export GLTF", err);
|
|
40459
|
+
}
|
|
40460
|
+
);
|
|
40461
|
+
},
|
|
40462
|
+
[]
|
|
40463
|
+
);
|
|
40431
40464
|
};
|
|
40432
40465
|
|
|
40433
40466
|
// src/CadViewer.tsx
|
|
@@ -40493,10 +40526,13 @@ var CadViewerInner = (props) => {
|
|
|
40493
40526
|
const sceneRef = useContext13(SchematicNavigationContext);
|
|
40494
40527
|
const [selectedComponent, setSelectedComponent] = useState46();
|
|
40495
40528
|
const [selectedObject, setSelectedObject] = useState46();
|
|
40529
|
+
const [selectedModel, setSelectedModel] = useState46();
|
|
40496
40530
|
const handleMenuOpen = useCallback25(
|
|
40497
40531
|
(position) => {
|
|
40498
|
-
|
|
40499
|
-
|
|
40532
|
+
const picked = pickSceneObject(sceneRef.current, position, circuitJson);
|
|
40533
|
+
setSelectedObject(picked);
|
|
40534
|
+
setSelectedModel(
|
|
40535
|
+
picked && sceneRef.current && findModelObject(sceneRef.current.rootObject, picked.objectId) ? picked : void 0
|
|
40500
40536
|
);
|
|
40501
40537
|
setSelectedComponent(
|
|
40502
40538
|
props.onViewSchematicComponent ? pickSchematicComponent(sceneRef.current, position, circuitJson) : void 0
|
|
@@ -40775,8 +40811,9 @@ var CadViewerInner = (props) => {
|
|
|
40775
40811
|
setCameraPreset("Custom");
|
|
40776
40812
|
closeMenu();
|
|
40777
40813
|
},
|
|
40814
|
+
downloadModelName: selectedModel?.name,
|
|
40778
40815
|
onDownloadGltf: () => {
|
|
40779
|
-
downloadGltf();
|
|
40816
|
+
downloadGltf(selectedModel, sceneRef.current?.rootObject);
|
|
40780
40817
|
closeMenu();
|
|
40781
40818
|
},
|
|
40782
40819
|
onOpenKeyboardShortcuts: () => {
|