@tscircuit/3d-viewer 0.0.233 → 0.0.235
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +236 -42
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -13980,7 +13980,7 @@ var require_browser = __commonJS({
|
|
|
13980
13980
|
});
|
|
13981
13981
|
|
|
13982
13982
|
// src/CadViewer.tsx
|
|
13983
|
-
import { useState as
|
|
13983
|
+
import { useState as useState10, useRef as useRef8, useEffect as useEffect8 } from "react";
|
|
13984
13984
|
|
|
13985
13985
|
// src/hooks/use-convert-children-to-soup.ts
|
|
13986
13986
|
import { Circuit } from "@tscircuit/core";
|
|
@@ -16985,7 +16985,7 @@ import { Canvas, useFrame as useFrame2 } from "@react-three/fiber";
|
|
|
16985
16985
|
// package.json
|
|
16986
16986
|
var package_default = {
|
|
16987
16987
|
name: "@tscircuit/3d-viewer",
|
|
16988
|
-
version: "0.0.
|
|
16988
|
+
version: "0.0.234",
|
|
16989
16989
|
main: "./dist/index.js",
|
|
16990
16990
|
module: "./dist/index.js",
|
|
16991
16991
|
type: "module",
|
|
@@ -17313,7 +17313,7 @@ var colors = {
|
|
|
17313
17313
|
var MANIFOLD_Z_OFFSET = 1e-3;
|
|
17314
17314
|
var SMOOTH_CIRCLE_SEGMENTS = 32;
|
|
17315
17315
|
var DEFAULT_SMT_PAD_THICKNESS = 0.035;
|
|
17316
|
-
var TRACE_TEXTURE_RESOLUTION =
|
|
17316
|
+
var TRACE_TEXTURE_RESOLUTION = 50;
|
|
17317
17317
|
var boardMaterialColors = {
|
|
17318
17318
|
fr1: colors.fr1Copper,
|
|
17319
17319
|
fr4: colors.fr4Green
|
|
@@ -18980,12 +18980,12 @@ var CadViewerJscad = forwardRef2(
|
|
|
18980
18980
|
|
|
18981
18981
|
// src/CadViewerManifold.tsx
|
|
18982
18982
|
import { useEffect as useEffect6, useState as useState8, useMemo as useMemo7 } from "react";
|
|
18983
|
-
import { su as
|
|
18983
|
+
import { su as su13 } from "@tscircuit/soup-util";
|
|
18984
18984
|
import ManifoldModule from "manifold-3d";
|
|
18985
18985
|
|
|
18986
18986
|
// src/hooks/useManifoldBoardBuilder.ts
|
|
18987
18987
|
import { useState as useState7, useEffect as useEffect5, useMemo as useMemo6, useRef as useRef6 } from "react";
|
|
18988
|
-
import { su as
|
|
18988
|
+
import { su as su12 } from "@tscircuit/soup-util";
|
|
18989
18989
|
import * as THREE10 from "three";
|
|
18990
18990
|
|
|
18991
18991
|
// src/utils/manifold-mesh-to-three-geometry.ts
|
|
@@ -19537,6 +19537,105 @@ function createManifoldBoard(Manifold, CrossSection, boardData, pcbThickness, ma
|
|
|
19537
19537
|
return boardOp;
|
|
19538
19538
|
}
|
|
19539
19539
|
|
|
19540
|
+
// src/utils/manifold/process-cutouts.ts
|
|
19541
|
+
import { su as su11 } from "@tscircuit/soup-util";
|
|
19542
|
+
var arePointsClockwise3 = (points) => {
|
|
19543
|
+
let area = 0;
|
|
19544
|
+
for (let i = 0; i < points.length; i++) {
|
|
19545
|
+
const j = (i + 1) % points.length;
|
|
19546
|
+
if (points[i] && points[j]) {
|
|
19547
|
+
area += points[i][0] * points[j][1];
|
|
19548
|
+
area -= points[j][0] * points[i][1];
|
|
19549
|
+
}
|
|
19550
|
+
}
|
|
19551
|
+
const signedArea = area / 2;
|
|
19552
|
+
return signedArea <= 0;
|
|
19553
|
+
};
|
|
19554
|
+
function processCutoutsForManifold(Manifold, CrossSection, circuitJson, pcbThickness, manifoldInstancesForCleanup) {
|
|
19555
|
+
const cutoutOps = [];
|
|
19556
|
+
const pcbCutouts = su11(circuitJson).pcb_cutout.list();
|
|
19557
|
+
for (const cutout of pcbCutouts) {
|
|
19558
|
+
let cutoutOp;
|
|
19559
|
+
const cutoutHeight = pcbThickness * 1.5;
|
|
19560
|
+
switch (cutout.shape) {
|
|
19561
|
+
case "rect":
|
|
19562
|
+
cutoutOp = Manifold.cube(
|
|
19563
|
+
[cutout.width, cutout.height, cutoutHeight],
|
|
19564
|
+
true
|
|
19565
|
+
// centered
|
|
19566
|
+
);
|
|
19567
|
+
manifoldInstancesForCleanup.push(cutoutOp);
|
|
19568
|
+
if (cutout.rotation) {
|
|
19569
|
+
const rotationRadians = cutout.rotation * Math.PI / 180;
|
|
19570
|
+
const rotatedOp = cutoutOp.rotate([0, 0, cutout.rotation]);
|
|
19571
|
+
manifoldInstancesForCleanup.push(rotatedOp);
|
|
19572
|
+
cutoutOp = rotatedOp;
|
|
19573
|
+
}
|
|
19574
|
+
cutoutOp = cutoutOp.translate([
|
|
19575
|
+
cutout.center.x,
|
|
19576
|
+
cutout.center.y,
|
|
19577
|
+
0
|
|
19578
|
+
// Centered vertically by Manifold.cube, so Z is 0 for board plane
|
|
19579
|
+
]);
|
|
19580
|
+
manifoldInstancesForCleanup.push(cutoutOp);
|
|
19581
|
+
break;
|
|
19582
|
+
case "circle":
|
|
19583
|
+
cutoutOp = Manifold.cylinder(
|
|
19584
|
+
cutoutHeight,
|
|
19585
|
+
cutout.radius,
|
|
19586
|
+
-1,
|
|
19587
|
+
// default for radiusHigh
|
|
19588
|
+
SMOOTH_CIRCLE_SEGMENTS,
|
|
19589
|
+
true
|
|
19590
|
+
// centered
|
|
19591
|
+
);
|
|
19592
|
+
manifoldInstancesForCleanup.push(cutoutOp);
|
|
19593
|
+
cutoutOp = cutoutOp.translate([cutout.center.x, cutout.center.y, 0]);
|
|
19594
|
+
manifoldInstancesForCleanup.push(cutoutOp);
|
|
19595
|
+
break;
|
|
19596
|
+
case "polygon":
|
|
19597
|
+
if (cutout.points.length < 3) {
|
|
19598
|
+
console.warn(
|
|
19599
|
+
`PCB Cutout [${cutout.pcb_cutout_id}] polygon has fewer than 3 points, skipping.`
|
|
19600
|
+
);
|
|
19601
|
+
continue;
|
|
19602
|
+
}
|
|
19603
|
+
let pointsVec2 = cutout.points.map((p) => [
|
|
19604
|
+
p.x,
|
|
19605
|
+
p.y
|
|
19606
|
+
]);
|
|
19607
|
+
if (arePointsClockwise3(pointsVec2)) {
|
|
19608
|
+
pointsVec2 = pointsVec2.reverse();
|
|
19609
|
+
}
|
|
19610
|
+
const crossSection = CrossSection.ofPolygons([pointsVec2]);
|
|
19611
|
+
manifoldInstancesForCleanup.push(crossSection);
|
|
19612
|
+
cutoutOp = Manifold.extrude(
|
|
19613
|
+
crossSection,
|
|
19614
|
+
cutoutHeight,
|
|
19615
|
+
0,
|
|
19616
|
+
// nDivisions
|
|
19617
|
+
0,
|
|
19618
|
+
// twistDegrees
|
|
19619
|
+
[1, 1],
|
|
19620
|
+
// scaleTop
|
|
19621
|
+
true
|
|
19622
|
+
// center extrusion
|
|
19623
|
+
);
|
|
19624
|
+
manifoldInstancesForCleanup.push(cutoutOp);
|
|
19625
|
+
break;
|
|
19626
|
+
default:
|
|
19627
|
+
console.warn(
|
|
19628
|
+
`Unsupported cutout shape: ${cutout.shape} for cutout ${cutout.pcb_cutout_id}`
|
|
19629
|
+
);
|
|
19630
|
+
continue;
|
|
19631
|
+
}
|
|
19632
|
+
if (cutoutOp) {
|
|
19633
|
+
cutoutOps.push(cutoutOp);
|
|
19634
|
+
}
|
|
19635
|
+
}
|
|
19636
|
+
return { cutoutOps };
|
|
19637
|
+
}
|
|
19638
|
+
|
|
19540
19639
|
// src/hooks/useManifoldBoardBuilder.ts
|
|
19541
19640
|
var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
|
|
19542
19641
|
const [geoms, setGeoms] = useState7(null);
|
|
@@ -19547,7 +19646,7 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
|
|
|
19547
19646
|
const manifoldInstancesForCleanup = useRef6([]);
|
|
19548
19647
|
const boardData = useMemo6(() => {
|
|
19549
19648
|
if (!circuitJson) return null;
|
|
19550
|
-
const boards =
|
|
19649
|
+
const boards = su12(circuitJson).pcb_board.list();
|
|
19551
19650
|
if (boards.length === 0) {
|
|
19552
19651
|
return null;
|
|
19553
19652
|
}
|
|
@@ -19558,7 +19657,7 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
|
|
|
19558
19657
|
setGeoms(null);
|
|
19559
19658
|
setTextures(null);
|
|
19560
19659
|
setPcbThickness(null);
|
|
19561
|
-
if (circuitJson &&
|
|
19660
|
+
if (circuitJson && su12(circuitJson).pcb_board.list().length === 0) {
|
|
19562
19661
|
setError("No pcb_board found in circuitJson.");
|
|
19563
19662
|
}
|
|
19564
19663
|
setIsLoading(false);
|
|
@@ -19610,9 +19709,23 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
|
|
|
19610
19709
|
if (allBoardDrills.length > 0) {
|
|
19611
19710
|
const unionedDrills = Manifold.union(allBoardDrills);
|
|
19612
19711
|
manifoldInstancesForCleanup.current.push(unionedDrills);
|
|
19613
|
-
const
|
|
19614
|
-
manifoldInstancesForCleanup.current.push(
|
|
19615
|
-
currentBoardOp =
|
|
19712
|
+
const nextBoardAfterDrills = currentBoardOp.subtract(unionedDrills);
|
|
19713
|
+
manifoldInstancesForCleanup.current.push(nextBoardAfterDrills);
|
|
19714
|
+
currentBoardOp = nextBoardAfterDrills;
|
|
19715
|
+
}
|
|
19716
|
+
const { cutoutOps } = processCutoutsForManifold(
|
|
19717
|
+
Manifold,
|
|
19718
|
+
CrossSection,
|
|
19719
|
+
circuitJson,
|
|
19720
|
+
currentPcbThickness,
|
|
19721
|
+
manifoldInstancesForCleanup.current
|
|
19722
|
+
);
|
|
19723
|
+
if (cutoutOps.length > 0) {
|
|
19724
|
+
const unionedCutouts = Manifold.union(cutoutOps);
|
|
19725
|
+
manifoldInstancesForCleanup.current.push(unionedCutouts);
|
|
19726
|
+
const nextBoardAfterCutouts = currentBoardOp.subtract(unionedCutouts);
|
|
19727
|
+
manifoldInstancesForCleanup.current.push(nextBoardAfterCutouts);
|
|
19728
|
+
currentBoardOp = nextBoardAfterCutouts;
|
|
19616
19729
|
}
|
|
19617
19730
|
boardManifold = currentBoardOp;
|
|
19618
19731
|
if (boardManifold) {
|
|
@@ -19825,7 +19938,7 @@ var CadViewerManifold = ({
|
|
|
19825
19938
|
[textures, boardData, pcbThickness]
|
|
19826
19939
|
);
|
|
19827
19940
|
const cadComponents = useMemo7(
|
|
19828
|
-
() => circuitJson ?
|
|
19941
|
+
() => circuitJson ? su13(circuitJson).cad_component.list() : [],
|
|
19829
19942
|
[circuitJson]
|
|
19830
19943
|
);
|
|
19831
19944
|
const initialCameraPosition = useMemo7(() => {
|
|
@@ -19905,29 +20018,76 @@ var CadViewerManifold = ({
|
|
|
19905
20018
|
};
|
|
19906
20019
|
var CadViewerManifold_default = CadViewerManifold;
|
|
19907
20020
|
|
|
19908
|
-
// src/
|
|
19909
|
-
import {
|
|
19910
|
-
var
|
|
19911
|
-
const [engine, setEngine] = useState9("jscad");
|
|
20021
|
+
// src/hooks/useContextMenu.ts
|
|
20022
|
+
import { useState as useState9, useCallback as useCallback4, useRef as useRef7, useEffect as useEffect7 } from "react";
|
|
20023
|
+
var useContextMenu = ({ containerRef }) => {
|
|
19912
20024
|
const [menuVisible, setMenuVisible] = useState9(false);
|
|
19913
20025
|
const [menuPos, setMenuPos] = useState9({
|
|
19914
20026
|
x: 0,
|
|
19915
20027
|
y: 0
|
|
19916
20028
|
});
|
|
19917
|
-
const containerRef = useRef7(null);
|
|
19918
20029
|
const menuRef = useRef7(null);
|
|
19919
|
-
const
|
|
19920
|
-
|
|
19921
|
-
|
|
19922
|
-
|
|
20030
|
+
const interactionOriginPosRef = useRef7(null);
|
|
20031
|
+
const handleContextMenu = useCallback4(
|
|
20032
|
+
(e) => {
|
|
20033
|
+
e.preventDefault();
|
|
20034
|
+
const eventX = typeof e.clientX === "number" ? e.clientX : 0;
|
|
20035
|
+
const eventY = typeof e.clientY === "number" ? e.clientY : 0;
|
|
20036
|
+
if (!interactionOriginPosRef.current) {
|
|
20037
|
+
return;
|
|
20038
|
+
}
|
|
20039
|
+
const { x: originX, y: originY } = interactionOriginPosRef.current;
|
|
20040
|
+
const dx = Math.abs(eventX - originX);
|
|
20041
|
+
const dy = Math.abs(eventY - originY);
|
|
20042
|
+
const swipeThreshold = 10;
|
|
20043
|
+
if (dx > swipeThreshold || dy > swipeThreshold) {
|
|
20044
|
+
interactionOriginPosRef.current = null;
|
|
20045
|
+
return;
|
|
20046
|
+
}
|
|
20047
|
+
setMenuPos({ x: eventX, y: eventY });
|
|
20048
|
+
setMenuVisible(true);
|
|
20049
|
+
interactionOriginPosRef.current = null;
|
|
20050
|
+
},
|
|
20051
|
+
[setMenuPos, setMenuVisible]
|
|
20052
|
+
);
|
|
20053
|
+
const handleTouchStart = useCallback4((e) => {
|
|
20054
|
+
if (e.touches.length === 1) {
|
|
20055
|
+
const touch = e.touches[0];
|
|
20056
|
+
if (touch) {
|
|
20057
|
+
interactionOriginPosRef.current = { x: touch.clientX, y: touch.clientY };
|
|
20058
|
+
} else {
|
|
20059
|
+
interactionOriginPosRef.current = null;
|
|
20060
|
+
}
|
|
20061
|
+
} else {
|
|
20062
|
+
interactionOriginPosRef.current = null;
|
|
20063
|
+
}
|
|
20064
|
+
}, []);
|
|
20065
|
+
const handleTouchMove = useCallback4((e) => {
|
|
20066
|
+
if (!interactionOriginPosRef.current || e.touches.length !== 1) {
|
|
20067
|
+
return;
|
|
20068
|
+
}
|
|
20069
|
+
const touch = e.touches[0];
|
|
20070
|
+
if (touch) {
|
|
20071
|
+
const dx = Math.abs(touch.clientX - interactionOriginPosRef.current.x);
|
|
20072
|
+
const dy = Math.abs(touch.clientY - interactionOriginPosRef.current.y);
|
|
20073
|
+
const swipeThreshold = 10;
|
|
20074
|
+
if (dx > swipeThreshold || dy > swipeThreshold) {
|
|
20075
|
+
interactionOriginPosRef.current = null;
|
|
20076
|
+
}
|
|
20077
|
+
} else {
|
|
20078
|
+
interactionOriginPosRef.current = null;
|
|
20079
|
+
}
|
|
20080
|
+
}, []);
|
|
20081
|
+
const handleTouchEnd = useCallback4(() => {
|
|
20082
|
+
setTimeout(() => {
|
|
20083
|
+
if (interactionOriginPosRef.current) {
|
|
20084
|
+
interactionOriginPosRef.current = null;
|
|
20085
|
+
}
|
|
20086
|
+
}, 0);
|
|
19923
20087
|
}, []);
|
|
19924
|
-
const handleMenuClick = (newEngine) => {
|
|
19925
|
-
setEngine(newEngine);
|
|
19926
|
-
setMenuVisible(false);
|
|
19927
|
-
};
|
|
19928
20088
|
const handleClickAway = useCallback4((e) => {
|
|
19929
20089
|
const target = e.target;
|
|
19930
|
-
if (
|
|
20090
|
+
if (menuRef.current && !menuRef.current.contains(target)) {
|
|
19931
20091
|
setMenuVisible(false);
|
|
19932
20092
|
}
|
|
19933
20093
|
}, []);
|
|
@@ -19937,13 +20097,52 @@ var CadViewer = (props) => {
|
|
|
19937
20097
|
return () => document.removeEventListener("mousedown", handleClickAway);
|
|
19938
20098
|
}
|
|
19939
20099
|
}, [menuVisible, handleClickAway]);
|
|
19940
|
-
|
|
20100
|
+
const contextMenuEventHandlers = {
|
|
20101
|
+
onMouseDown: (e) => {
|
|
20102
|
+
if (e.button === 2) {
|
|
20103
|
+
interactionOriginPosRef.current = { x: e.clientX, y: e.clientY };
|
|
20104
|
+
} else {
|
|
20105
|
+
interactionOriginPosRef.current = null;
|
|
20106
|
+
}
|
|
20107
|
+
},
|
|
20108
|
+
onContextMenu: handleContextMenu,
|
|
20109
|
+
onTouchStart: handleTouchStart,
|
|
20110
|
+
onTouchMove: handleTouchMove,
|
|
20111
|
+
onTouchEnd: handleTouchEnd
|
|
20112
|
+
};
|
|
20113
|
+
return {
|
|
20114
|
+
menuVisible,
|
|
20115
|
+
menuPos,
|
|
20116
|
+
menuRef,
|
|
20117
|
+
contextMenuEventHandlers,
|
|
20118
|
+
setMenuVisible
|
|
20119
|
+
// Expose setMenuVisible for direct control if needed
|
|
20120
|
+
};
|
|
20121
|
+
};
|
|
20122
|
+
|
|
20123
|
+
// src/CadViewer.tsx
|
|
20124
|
+
import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
20125
|
+
var CadViewer = (props) => {
|
|
20126
|
+
const [engine, setEngine] = useState10("jscad");
|
|
20127
|
+
const containerRef = useRef8(null);
|
|
20128
|
+
const {
|
|
20129
|
+
menuVisible,
|
|
20130
|
+
menuPos,
|
|
20131
|
+
menuRef,
|
|
20132
|
+
contextMenuEventHandlers,
|
|
20133
|
+
setMenuVisible
|
|
20134
|
+
} = useContextMenu({ containerRef });
|
|
20135
|
+
const handleMenuClick = (newEngine) => {
|
|
20136
|
+
setEngine(newEngine);
|
|
20137
|
+
setMenuVisible(false);
|
|
20138
|
+
};
|
|
20139
|
+
useEffect8(() => {
|
|
19941
20140
|
const stored = window.localStorage.getItem("cadViewerEngine");
|
|
19942
20141
|
if (stored === "jscad" || stored === "manifold") {
|
|
19943
20142
|
setEngine(stored);
|
|
19944
20143
|
}
|
|
19945
20144
|
}, []);
|
|
19946
|
-
|
|
20145
|
+
useEffect8(() => {
|
|
19947
20146
|
window.localStorage.setItem("cadViewerEngine", engine);
|
|
19948
20147
|
}, [engine]);
|
|
19949
20148
|
const viewerKey = props.circuitJson ? JSON.stringify(props.circuitJson) : void 0;
|
|
@@ -19952,7 +20151,7 @@ var CadViewer = (props) => {
|
|
|
19952
20151
|
{
|
|
19953
20152
|
ref: containerRef,
|
|
19954
20153
|
style: { width: "100%", height: "100%", position: "relative" },
|
|
19955
|
-
|
|
20154
|
+
...contextMenuEventHandlers,
|
|
19956
20155
|
children: [
|
|
19957
20156
|
engine === "jscad" ? /* @__PURE__ */ jsx12(CadViewerJscad, { ...props }) : /* @__PURE__ */ jsx12(CadViewerManifold_default, { ...props }),
|
|
19958
20157
|
/* @__PURE__ */ jsxs9(
|
|
@@ -19970,11 +20169,6 @@ var CadViewer = (props) => {
|
|
|
19970
20169
|
opacity: 0.7,
|
|
19971
20170
|
userSelect: "none"
|
|
19972
20171
|
},
|
|
19973
|
-
onClick: () => {
|
|
19974
|
-
if ("ontouchstart" in window) {
|
|
19975
|
-
setEngine(engine === "jscad" ? "manifold" : "jscad");
|
|
19976
|
-
}
|
|
19977
|
-
},
|
|
19978
20172
|
children: [
|
|
19979
20173
|
"Engine: ",
|
|
19980
20174
|
/* @__PURE__ */ jsx12("b", { children: engine === "jscad" ? "JSCAD" : "Manifold" })
|
|
@@ -20047,7 +20241,7 @@ var CadViewer = (props) => {
|
|
|
20047
20241
|
|
|
20048
20242
|
// src/convert-circuit-json-to-3d-svg.ts
|
|
20049
20243
|
var import_debug = __toESM(require_browser(), 1);
|
|
20050
|
-
import { su as
|
|
20244
|
+
import { su as su14 } from "@tscircuit/soup-util";
|
|
20051
20245
|
import * as THREE16 from "three";
|
|
20052
20246
|
import { SVGRenderer } from "three/examples/jsm/renderers/SVGRenderer.js";
|
|
20053
20247
|
|
|
@@ -20262,7 +20456,7 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
|
|
|
20262
20456
|
const pointLight = new THREE16.PointLight(16777215, Math.PI / 4);
|
|
20263
20457
|
pointLight.position.set(-10, -10, 10);
|
|
20264
20458
|
scene.add(pointLight);
|
|
20265
|
-
const components =
|
|
20459
|
+
const components = su14(circuitJson).cad_component.list();
|
|
20266
20460
|
for (const component of components) {
|
|
20267
20461
|
await renderComponent(component, scene);
|
|
20268
20462
|
}
|
|
@@ -20308,7 +20502,7 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
|
|
|
20308
20502
|
}
|
|
20309
20503
|
|
|
20310
20504
|
// src/hooks/exporter/gltf.ts
|
|
20311
|
-
import { useEffect as
|
|
20505
|
+
import { useEffect as useEffect9, useState as useState11, useMemo as useMemo8, useCallback as useCallback6 } from "react";
|
|
20312
20506
|
function useSaveGltfAs(options = {}) {
|
|
20313
20507
|
const parse = useParser(options);
|
|
20314
20508
|
const link = useMemo8(() => document.createElement("a"), []);
|
|
@@ -20321,7 +20515,7 @@ function useSaveGltfAs(options = {}) {
|
|
|
20321
20515
|
link.dispatchEvent(new MouseEvent("click"));
|
|
20322
20516
|
URL.revokeObjectURL(url);
|
|
20323
20517
|
};
|
|
20324
|
-
|
|
20518
|
+
useEffect9(
|
|
20325
20519
|
() => () => {
|
|
20326
20520
|
link.remove();
|
|
20327
20521
|
instance = null;
|
|
@@ -20329,20 +20523,20 @@ function useSaveGltfAs(options = {}) {
|
|
|
20329
20523
|
[]
|
|
20330
20524
|
);
|
|
20331
20525
|
let instance;
|
|
20332
|
-
const ref =
|
|
20526
|
+
const ref = useCallback6((obj3D) => {
|
|
20333
20527
|
instance = obj3D;
|
|
20334
20528
|
}, []);
|
|
20335
20529
|
return [ref, saveAs];
|
|
20336
20530
|
}
|
|
20337
20531
|
function useExportGltfUrl(options = {}) {
|
|
20338
20532
|
const parse = useParser(options);
|
|
20339
|
-
const [url, setUrl] =
|
|
20340
|
-
const [error, setError] =
|
|
20341
|
-
const ref =
|
|
20533
|
+
const [url, setUrl] = useState11();
|
|
20534
|
+
const [error, setError] = useState11();
|
|
20535
|
+
const ref = useCallback6(
|
|
20342
20536
|
(instance) => parse(instance).then(setUrl).catch(setError),
|
|
20343
20537
|
[]
|
|
20344
20538
|
);
|
|
20345
|
-
|
|
20539
|
+
useEffect9(() => () => URL.revokeObjectURL(url), [url]);
|
|
20346
20540
|
return [ref, url, error];
|
|
20347
20541
|
}
|
|
20348
20542
|
function useParser(options = {}) {
|