@vizij/render 0.0.7 → 0.1.1
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.d.mts +56 -6
- package/dist/index.d.ts +56 -6
- package/dist/index.js +564 -108
- package/dist/index.mjs +545 -117
- package/package.json +10 -10
package/dist/index.mjs
CHANGED
|
@@ -1,19 +1,10 @@
|
|
|
1
1
|
// src/vizij.tsx
|
|
2
|
-
import {
|
|
3
|
-
Suspense,
|
|
4
|
-
memo as memo6,
|
|
5
|
-
useContext as useContext3,
|
|
6
|
-
useEffect as useEffect6
|
|
7
|
-
} from "react";
|
|
2
|
+
import { Suspense, memo as memo6, useContext as useContext3, useEffect as useEffect7 } from "react";
|
|
8
3
|
import { ErrorBoundary } from "react-error-boundary";
|
|
9
|
-
import {
|
|
10
|
-
Object3D as Object3D4,
|
|
11
|
-
SRGBColorSpace,
|
|
12
|
-
NoToneMapping
|
|
13
|
-
} from "three";
|
|
4
|
+
import { Object3D as Object3D4, SRGBColorSpace, NoToneMapping } from "three";
|
|
14
5
|
import { Canvas, useThree } from "@react-three/fiber";
|
|
15
6
|
import { Line as Line3, OrthographicCamera, Text } from "@react-three/drei";
|
|
16
|
-
import { useShallow as
|
|
7
|
+
import { useShallow as useShallow7 } from "zustand/react/shallow";
|
|
17
8
|
|
|
18
9
|
// src/renderables/renderable.tsx
|
|
19
10
|
import { memo as memo5, useMemo as useMemo5 } from "react";
|
|
@@ -35,13 +26,7 @@ function useVizijStore(selector) {
|
|
|
35
26
|
}
|
|
36
27
|
|
|
37
28
|
// src/renderables/group.tsx
|
|
38
|
-
import {
|
|
39
|
-
memo,
|
|
40
|
-
useCallback,
|
|
41
|
-
useEffect as useEffect2,
|
|
42
|
-
useRef,
|
|
43
|
-
useMemo
|
|
44
|
-
} from "react";
|
|
29
|
+
import { memo, useCallback, useEffect as useEffect2, useRef, useMemo } from "react";
|
|
45
30
|
import * as THREE from "three";
|
|
46
31
|
import { useShallow } from "zustand/react/shallow";
|
|
47
32
|
import {
|
|
@@ -138,7 +123,7 @@ function InnerRenderedGroup({
|
|
|
138
123
|
namespace,
|
|
139
124
|
chain
|
|
140
125
|
}) {
|
|
141
|
-
const ref = useRef();
|
|
126
|
+
const ref = useRef(null);
|
|
142
127
|
const group = useVizijStore(useShallow((state) => state.world[id]));
|
|
143
128
|
const refIsNull = !group.refs[namespace]?.current;
|
|
144
129
|
const animatables = useVizijStore(useShallow((state) => state.animatables));
|
|
@@ -249,13 +234,7 @@ function InnerRenderedGroup({
|
|
|
249
234
|
var RenderedGroup = memo(InnerRenderedGroup);
|
|
250
235
|
|
|
251
236
|
// src/renderables/ellipse.tsx
|
|
252
|
-
import {
|
|
253
|
-
memo as memo2,
|
|
254
|
-
useCallback as useCallback2,
|
|
255
|
-
useEffect as useEffect3,
|
|
256
|
-
useRef as useRef2,
|
|
257
|
-
useMemo as useMemo2
|
|
258
|
-
} from "react";
|
|
237
|
+
import { memo as memo2, useCallback as useCallback2, useEffect as useEffect3, useRef as useRef2, useMemo as useMemo2 } from "react";
|
|
259
238
|
import { useShallow as useShallow2 } from "zustand/react/shallow";
|
|
260
239
|
import {
|
|
261
240
|
instanceOfRawNumber as instanceOfRawNumber2,
|
|
@@ -272,9 +251,11 @@ function InnerRenderedEllipse({
|
|
|
272
251
|
namespace,
|
|
273
252
|
chain
|
|
274
253
|
}) {
|
|
275
|
-
const ellipseRef = useRef2();
|
|
276
|
-
const materialRef = useRef2(
|
|
277
|
-
|
|
254
|
+
const ellipseRef = useRef2(null);
|
|
255
|
+
const materialRef = useRef2(
|
|
256
|
+
null
|
|
257
|
+
);
|
|
258
|
+
const lineRef = useRef2(null);
|
|
278
259
|
const strokeOffsetRef = useRef2(0);
|
|
279
260
|
const strokeWidthRef = useRef2(0);
|
|
280
261
|
const onElementClick = useVizijStore(
|
|
@@ -547,13 +528,7 @@ var showLine = (ellipse) => {
|
|
|
547
528
|
};
|
|
548
529
|
|
|
549
530
|
// src/renderables/rectangle.tsx
|
|
550
|
-
import {
|
|
551
|
-
memo as memo3,
|
|
552
|
-
useCallback as useCallback3,
|
|
553
|
-
useEffect as useEffect4,
|
|
554
|
-
useRef as useRef3,
|
|
555
|
-
useMemo as useMemo3
|
|
556
|
-
} from "react";
|
|
531
|
+
import { memo as memo3, useCallback as useCallback3, useEffect as useEffect4, useRef as useRef3, useMemo as useMemo3 } from "react";
|
|
557
532
|
import { useShallow as useShallow3 } from "zustand/react/shallow";
|
|
558
533
|
import {
|
|
559
534
|
instanceOfRawNumber as instanceOfRawNumber3,
|
|
@@ -570,9 +545,11 @@ function InnerRenderedRectangle({
|
|
|
570
545
|
namespace,
|
|
571
546
|
chain
|
|
572
547
|
}) {
|
|
573
|
-
const rectangleRef = useRef3();
|
|
574
|
-
const materialRef = useRef3(
|
|
575
|
-
|
|
548
|
+
const rectangleRef = useRef3(null);
|
|
549
|
+
const materialRef = useRef3(
|
|
550
|
+
null
|
|
551
|
+
);
|
|
552
|
+
const lineRef = useRef3(null);
|
|
576
553
|
const strokeOffsetRef = useRef3(0);
|
|
577
554
|
const strokeWidthRef = useRef3(0);
|
|
578
555
|
const onElementClick = useVizijStore(
|
|
@@ -846,13 +823,7 @@ var showLine2 = (rectangle) => {
|
|
|
846
823
|
};
|
|
847
824
|
|
|
848
825
|
// src/renderables/shape.tsx
|
|
849
|
-
import {
|
|
850
|
-
memo as memo4,
|
|
851
|
-
useCallback as useCallback4,
|
|
852
|
-
useRef as useRef4,
|
|
853
|
-
useMemo as useMemo4,
|
|
854
|
-
useEffect as useEffect5
|
|
855
|
-
} from "react";
|
|
826
|
+
import { memo as memo4, useCallback as useCallback4, useRef as useRef4, useMemo as useMemo4, useEffect as useEffect5 } from "react";
|
|
856
827
|
import * as THREE2 from "three";
|
|
857
828
|
import { useShallow as useShallow4 } from "zustand/react/shallow";
|
|
858
829
|
import {
|
|
@@ -869,8 +840,8 @@ function InnerRenderedShape({
|
|
|
869
840
|
namespace,
|
|
870
841
|
chain
|
|
871
842
|
}) {
|
|
872
|
-
const refGroup = useRef4();
|
|
873
|
-
const ref = useRef4();
|
|
843
|
+
const refGroup = useRef4(null);
|
|
844
|
+
const ref = useRef4(null);
|
|
874
845
|
const shape = useVizijStore(useShallow4((state) => state.world[id]));
|
|
875
846
|
const refs = useVizijStore(
|
|
876
847
|
useShallow4((state) => state.world[id].refs)
|
|
@@ -911,7 +882,7 @@ function InnerRenderedShape({
|
|
|
911
882
|
}),
|
|
912
883
|
[shape, animatableValues, selectionData]
|
|
913
884
|
);
|
|
914
|
-
const material = useRef4();
|
|
885
|
+
const material = useRef4(null);
|
|
915
886
|
const morphTargetSettings = useMemo4(() => {
|
|
916
887
|
if (shape.morphTargets) {
|
|
917
888
|
const dictionary = shape.morphTargets.reduce(
|
|
@@ -1432,6 +1403,35 @@ function createAnimatable(value) {
|
|
|
1432
1403
|
}
|
|
1433
1404
|
createAnimatable({ type: "euler", name: "Rotation" });
|
|
1434
1405
|
|
|
1406
|
+
// src/functions/exportable-bodies.ts
|
|
1407
|
+
function asGroupEntries(world) {
|
|
1408
|
+
return Object.values(world).filter((entry) => entry.type === "group");
|
|
1409
|
+
}
|
|
1410
|
+
function selectExportableGroupEntries(world, filterIds) {
|
|
1411
|
+
const groupEntries = asGroupEntries(world);
|
|
1412
|
+
const filterSet = Array.isArray(filterIds) && filterIds.length > 0 ? new Set(filterIds) : null;
|
|
1413
|
+
if (filterSet) {
|
|
1414
|
+
return groupEntries.filter((entry) => filterSet.has(entry.id));
|
|
1415
|
+
}
|
|
1416
|
+
const rootBoundsGroups = groupEntries.filter(
|
|
1417
|
+
(entry) => Boolean(entry.rootBounds)
|
|
1418
|
+
);
|
|
1419
|
+
if (rootBoundsGroups.length > 0) {
|
|
1420
|
+
return rootBoundsGroups;
|
|
1421
|
+
}
|
|
1422
|
+
const explicitRootGroups = groupEntries.filter(
|
|
1423
|
+
(entry) => entry.root === true
|
|
1424
|
+
);
|
|
1425
|
+
if (explicitRootGroups.length > 0) {
|
|
1426
|
+
return explicitRootGroups;
|
|
1427
|
+
}
|
|
1428
|
+
const topLevelGroups = groupEntries.filter((entry) => !entry.parent);
|
|
1429
|
+
if (topLevelGroups.length > 0) {
|
|
1430
|
+
return topLevelGroups;
|
|
1431
|
+
}
|
|
1432
|
+
return groupEntries;
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
1435
|
// src/store.ts
|
|
1436
1436
|
THREE3.Object3D.DEFAULT_UP.set(0, 0, 1);
|
|
1437
1437
|
enableMapSet();
|
|
@@ -1507,23 +1507,17 @@ var VizijSlice = (set, get) => ({
|
|
|
1507
1507
|
},
|
|
1508
1508
|
getExportableBodies: (filterIds) => {
|
|
1509
1509
|
const worldData = get().world;
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
const
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
const firstNs = Object.keys(entry.refs)[0];
|
|
1522
|
-
const refGroup = entry.refs[firstNs].current;
|
|
1523
|
-
return refGroup;
|
|
1524
|
-
});
|
|
1525
|
-
return bodies;
|
|
1526
|
-
}
|
|
1510
|
+
const candidateGroups = selectExportableGroupEntries(
|
|
1511
|
+
worldData,
|
|
1512
|
+
filterIds
|
|
1513
|
+
);
|
|
1514
|
+
return candidateGroups.flatMap((entry) => {
|
|
1515
|
+
const refs = Object.values(
|
|
1516
|
+
entry.refs ?? {}
|
|
1517
|
+
);
|
|
1518
|
+
const resolved = refs.find((ref) => ref?.current)?.current ?? null;
|
|
1519
|
+
return resolved ? [resolved] : [];
|
|
1520
|
+
});
|
|
1527
1521
|
},
|
|
1528
1522
|
setGeometry: (id, geometry) => {
|
|
1529
1523
|
set(
|
|
@@ -1557,6 +1551,19 @@ var VizijSlice = (set, get) => ({
|
|
|
1557
1551
|
})
|
|
1558
1552
|
);
|
|
1559
1553
|
},
|
|
1554
|
+
setValues: (writes = []) => {
|
|
1555
|
+
if (writes.length === 0) {
|
|
1556
|
+
return;
|
|
1557
|
+
}
|
|
1558
|
+
set(
|
|
1559
|
+
produce((state) => {
|
|
1560
|
+
writes.forEach(({ id, namespace, value }) => {
|
|
1561
|
+
const lookupId = getLookup2(namespace, id);
|
|
1562
|
+
state.values.set(lookupId, value);
|
|
1563
|
+
});
|
|
1564
|
+
})
|
|
1565
|
+
);
|
|
1566
|
+
},
|
|
1560
1567
|
setWorldElementName: (id, value) => {
|
|
1561
1568
|
set(
|
|
1562
1569
|
produce((state) => {
|
|
@@ -1751,8 +1758,117 @@ var createVizijStore = (initial) => create()(
|
|
|
1751
1758
|
}))
|
|
1752
1759
|
);
|
|
1753
1760
|
|
|
1761
|
+
// src/effects/selection-glow-effect.tsx
|
|
1762
|
+
import { Fragment as Fragment4, useEffect as useEffect6, useMemo as useMemo6, useRef as useRef5 } from "react";
|
|
1763
|
+
import { useFrame } from "@react-three/fiber";
|
|
1764
|
+
import { useShallow as useShallow6 } from "zustand/react/shallow";
|
|
1765
|
+
import {
|
|
1766
|
+
AdditiveBlending,
|
|
1767
|
+
Color,
|
|
1768
|
+
EdgesGeometry,
|
|
1769
|
+
LineBasicMaterial,
|
|
1770
|
+
Matrix4,
|
|
1771
|
+
Quaternion,
|
|
1772
|
+
Vector3
|
|
1773
|
+
} from "three";
|
|
1774
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
1775
|
+
function SelectionGlowEffect({
|
|
1776
|
+
enabled = false,
|
|
1777
|
+
color = "#ff1010ff",
|
|
1778
|
+
opacity = 0.9,
|
|
1779
|
+
thresholdAngle = 2
|
|
1780
|
+
}) {
|
|
1781
|
+
const selections = useVizijStore(
|
|
1782
|
+
useShallow6(
|
|
1783
|
+
(state) => enabled ? state.elementSelection ?? [] : []
|
|
1784
|
+
)
|
|
1785
|
+
);
|
|
1786
|
+
if (!enabled || selections.length === 0) {
|
|
1787
|
+
return null;
|
|
1788
|
+
}
|
|
1789
|
+
return /* @__PURE__ */ jsx6(Fragment4, { children: selections.map((selection) => /* @__PURE__ */ jsx6(
|
|
1790
|
+
SelectionOutline,
|
|
1791
|
+
{
|
|
1792
|
+
selection,
|
|
1793
|
+
color: selection.color ?? color,
|
|
1794
|
+
opacity,
|
|
1795
|
+
thresholdAngle
|
|
1796
|
+
},
|
|
1797
|
+
`${selection.namespace}:${selection.id}`
|
|
1798
|
+
)) });
|
|
1799
|
+
}
|
|
1800
|
+
function SelectionOutline({
|
|
1801
|
+
selection,
|
|
1802
|
+
color,
|
|
1803
|
+
opacity,
|
|
1804
|
+
thresholdAngle
|
|
1805
|
+
}) {
|
|
1806
|
+
const target = useVizijStore(
|
|
1807
|
+
useShallow6((state) => {
|
|
1808
|
+
const entry = state.world[selection.id];
|
|
1809
|
+
const ref = entry?.refs?.[selection.namespace];
|
|
1810
|
+
const geometry = entry?.geometry ?? null;
|
|
1811
|
+
return { ref, geometry };
|
|
1812
|
+
})
|
|
1813
|
+
);
|
|
1814
|
+
const sourceRef = target.ref;
|
|
1815
|
+
const edgesGeometry = useMemo6(() => {
|
|
1816
|
+
if (!target.geometry) return null;
|
|
1817
|
+
const edges = new EdgesGeometry(target.geometry, thresholdAngle);
|
|
1818
|
+
return edges;
|
|
1819
|
+
}, [target.geometry, thresholdAngle]);
|
|
1820
|
+
useEffect6(() => () => edgesGeometry?.dispose(), [edgesGeometry]);
|
|
1821
|
+
const material = useMemo6(() => {
|
|
1822
|
+
const mat = new LineBasicMaterial({
|
|
1823
|
+
color: new Color(color),
|
|
1824
|
+
transparent: true,
|
|
1825
|
+
opacity,
|
|
1826
|
+
blending: AdditiveBlending,
|
|
1827
|
+
depthTest: false,
|
|
1828
|
+
depthWrite: false,
|
|
1829
|
+
toneMapped: false
|
|
1830
|
+
});
|
|
1831
|
+
return mat;
|
|
1832
|
+
}, [color, opacity]);
|
|
1833
|
+
useEffect6(() => () => material.dispose(), [material]);
|
|
1834
|
+
const lineRef = useRef5(null);
|
|
1835
|
+
useFrame(() => {
|
|
1836
|
+
const source = sourceRef?.current;
|
|
1837
|
+
const line = lineRef.current;
|
|
1838
|
+
if (!source || !line) return;
|
|
1839
|
+
copyWorldTransform(source, line);
|
|
1840
|
+
line.visible = source.visible;
|
|
1841
|
+
});
|
|
1842
|
+
if (!sourceRef || !edgesGeometry) {
|
|
1843
|
+
return null;
|
|
1844
|
+
}
|
|
1845
|
+
return /* @__PURE__ */ jsx6(
|
|
1846
|
+
"lineSegments",
|
|
1847
|
+
{
|
|
1848
|
+
ref: lineRef,
|
|
1849
|
+
geometry: edgesGeometry,
|
|
1850
|
+
material,
|
|
1851
|
+
frustumCulled: false,
|
|
1852
|
+
renderOrder: 1e3
|
|
1853
|
+
}
|
|
1854
|
+
);
|
|
1855
|
+
}
|
|
1856
|
+
var tempMatrix = new Matrix4();
|
|
1857
|
+
var tempPosition = new Vector3();
|
|
1858
|
+
var tempQuaternion = new Quaternion();
|
|
1859
|
+
var tempScale = new Vector3();
|
|
1860
|
+
function copyWorldTransform(source, target) {
|
|
1861
|
+
source.updateWorldMatrix(true, false);
|
|
1862
|
+
tempMatrix.copy(source.matrixWorld);
|
|
1863
|
+
tempMatrix.decompose(tempPosition, tempQuaternion, tempScale);
|
|
1864
|
+
target.position.copy(tempPosition);
|
|
1865
|
+
target.quaternion.copy(tempQuaternion);
|
|
1866
|
+
target.scale.copy(tempScale);
|
|
1867
|
+
target.updateMatrix();
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1754
1870
|
// src/vizij.tsx
|
|
1755
|
-
import { Fragment as
|
|
1871
|
+
import { Fragment as Fragment5, jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1756
1872
|
Object3D4.DEFAULT_UP.set(0, 0, 1);
|
|
1757
1873
|
function Vizij({
|
|
1758
1874
|
style,
|
|
@@ -1760,11 +1876,12 @@ function Vizij({
|
|
|
1760
1876
|
rootId,
|
|
1761
1877
|
namespace = "default",
|
|
1762
1878
|
showSafeArea = false,
|
|
1879
|
+
showSelectionGlow = false,
|
|
1763
1880
|
onPointerMissed
|
|
1764
1881
|
}) {
|
|
1765
1882
|
const ctx = useContext3(VizijContext);
|
|
1766
1883
|
if (ctx) {
|
|
1767
|
-
return /* @__PURE__ */
|
|
1884
|
+
return /* @__PURE__ */ jsx7(
|
|
1768
1885
|
Canvas,
|
|
1769
1886
|
{
|
|
1770
1887
|
shadows: false,
|
|
@@ -1776,18 +1893,19 @@ function Vizij({
|
|
|
1776
1893
|
toneMapping: NoToneMapping,
|
|
1777
1894
|
antialias: true
|
|
1778
1895
|
},
|
|
1779
|
-
children: /* @__PURE__ */
|
|
1896
|
+
children: /* @__PURE__ */ jsx7(
|
|
1780
1897
|
MemoizedInnerVizij,
|
|
1781
1898
|
{
|
|
1782
1899
|
rootId,
|
|
1783
1900
|
namespace,
|
|
1784
|
-
showSafeArea
|
|
1901
|
+
showSafeArea,
|
|
1902
|
+
showSelectionGlow
|
|
1785
1903
|
}
|
|
1786
1904
|
)
|
|
1787
1905
|
}
|
|
1788
1906
|
);
|
|
1789
1907
|
} else {
|
|
1790
|
-
return /* @__PURE__ */
|
|
1908
|
+
return /* @__PURE__ */ jsx7(VizijContext.Provider, { value: useDefaultVizijStore, children: /* @__PURE__ */ jsx7(
|
|
1791
1909
|
Canvas,
|
|
1792
1910
|
{
|
|
1793
1911
|
style,
|
|
@@ -1798,12 +1916,13 @@ function Vizij({
|
|
|
1798
1916
|
toneMapping: NoToneMapping,
|
|
1799
1917
|
antialias: true
|
|
1800
1918
|
},
|
|
1801
|
-
children: /* @__PURE__ */
|
|
1919
|
+
children: /* @__PURE__ */ jsx7(
|
|
1802
1920
|
MemoizedInnerVizij,
|
|
1803
1921
|
{
|
|
1804
1922
|
rootId,
|
|
1805
1923
|
namespace,
|
|
1806
|
-
showSafeArea
|
|
1924
|
+
showSafeArea,
|
|
1925
|
+
showSelectionGlow
|
|
1807
1926
|
}
|
|
1808
1927
|
)
|
|
1809
1928
|
}
|
|
@@ -1814,15 +1933,16 @@ function InnerVizij({
|
|
|
1814
1933
|
rootId,
|
|
1815
1934
|
namespace = "default",
|
|
1816
1935
|
container,
|
|
1817
|
-
showSafeArea
|
|
1936
|
+
showSafeArea,
|
|
1937
|
+
showSelectionGlow
|
|
1818
1938
|
}) {
|
|
1819
1939
|
const sceneParentSizing = container ? {
|
|
1820
1940
|
width: container.width * container.resolution,
|
|
1821
1941
|
height: container.height * container.resolution
|
|
1822
1942
|
} : void 0;
|
|
1823
|
-
return /* @__PURE__ */ jsxs4(
|
|
1824
|
-
/* @__PURE__ */
|
|
1825
|
-
/* @__PURE__ */
|
|
1943
|
+
return /* @__PURE__ */ jsxs4(Fragment5, { children: [
|
|
1944
|
+
/* @__PURE__ */ jsx7("ambientLight", { intensity: Math.PI / 2 }),
|
|
1945
|
+
/* @__PURE__ */ jsx7(
|
|
1826
1946
|
OrthographicCamera,
|
|
1827
1947
|
{
|
|
1828
1948
|
makeDefault: true,
|
|
@@ -1831,7 +1951,7 @@ function InnerVizij({
|
|
|
1831
1951
|
far: 101
|
|
1832
1952
|
}
|
|
1833
1953
|
),
|
|
1834
|
-
/* @__PURE__ */
|
|
1954
|
+
/* @__PURE__ */ jsx7(Suspense, { fallback: null, children: /* @__PURE__ */ jsx7(
|
|
1835
1955
|
World,
|
|
1836
1956
|
{
|
|
1837
1957
|
rootId,
|
|
@@ -1839,7 +1959,8 @@ function InnerVizij({
|
|
|
1839
1959
|
parentSizing: sceneParentSizing
|
|
1840
1960
|
}
|
|
1841
1961
|
) }),
|
|
1842
|
-
|
|
1962
|
+
showSelectionGlow && /* @__PURE__ */ jsx7(SelectionGlowEffect, { enabled: true }),
|
|
1963
|
+
showSafeArea && /* @__PURE__ */ jsx7(SafeAreaRenderer, { rootId })
|
|
1843
1964
|
] });
|
|
1844
1965
|
}
|
|
1845
1966
|
var MemoizedInnerVizij = memo6(InnerVizij);
|
|
@@ -1849,7 +1970,7 @@ function InnerWorld({
|
|
|
1849
1970
|
parentSizing
|
|
1850
1971
|
}) {
|
|
1851
1972
|
const [present, rootBounds] = useVizijStore(
|
|
1852
|
-
|
|
1973
|
+
useShallow7((state) => {
|
|
1853
1974
|
const group = state.world[rootId];
|
|
1854
1975
|
const bounds = group?.rootBounds ?? defaultRootBounds;
|
|
1855
1976
|
return [group !== void 0, bounds];
|
|
@@ -1859,7 +1980,7 @@ function InnerWorld({
|
|
|
1859
1980
|
camera: state.camera,
|
|
1860
1981
|
size: state.size
|
|
1861
1982
|
}));
|
|
1862
|
-
|
|
1983
|
+
useEffect7(() => {
|
|
1863
1984
|
const width = rootBounds.size.x;
|
|
1864
1985
|
const height = rootBounds.size.y;
|
|
1865
1986
|
if (camera && parentSizing === void 0 && camera.isOrthographicCamera) {
|
|
@@ -1888,8 +2009,8 @@ function InnerWorld({
|
|
|
1888
2009
|
}
|
|
1889
2010
|
}, [rootBounds, camera, parentSizing, size]);
|
|
1890
2011
|
return /* @__PURE__ */ jsxs4(ErrorBoundary, { fallback: null, children: [
|
|
1891
|
-
present && /* @__PURE__ */
|
|
1892
|
-
!present && /* @__PURE__ */
|
|
2012
|
+
present && /* @__PURE__ */ jsx7(Renderable, { id: rootId, namespace, chain: [] }),
|
|
2013
|
+
!present && /* @__PURE__ */ jsx7(
|
|
1893
2014
|
Text,
|
|
1894
2015
|
{
|
|
1895
2016
|
position: [0, 0, 0],
|
|
@@ -1912,7 +2033,7 @@ function SafeAreaRenderer({ rootId }) {
|
|
|
1912
2033
|
const right = rootBounds.center.x + rootBounds.size.x / 2;
|
|
1913
2034
|
const top = rootBounds.center.y + rootBounds.size.y / 2;
|
|
1914
2035
|
const bottom = rootBounds.center.y - rootBounds.size.y / 2;
|
|
1915
|
-
return /* @__PURE__ */
|
|
2036
|
+
return /* @__PURE__ */ jsx7(
|
|
1916
2037
|
Line3,
|
|
1917
2038
|
{
|
|
1918
2039
|
points: [
|
|
@@ -1943,11 +2064,11 @@ var ShapeMaterial = /* @__PURE__ */ ((ShapeMaterial2) => {
|
|
|
1943
2064
|
})(ShapeMaterial || {});
|
|
1944
2065
|
|
|
1945
2066
|
// src/hooks/use-vizij-store-subscription.ts
|
|
1946
|
-
import { useContext as useContext4, useEffect as
|
|
2067
|
+
import { useContext as useContext4, useEffect as useEffect8 } from "react";
|
|
1947
2068
|
function useVizijStoreSubscription(selector, listener) {
|
|
1948
2069
|
const store = useContext4(VizijContext);
|
|
1949
2070
|
if (!store) throw new Error("Missing VizijProvider in the tree");
|
|
1950
|
-
|
|
2071
|
+
useEffect8(() => {
|
|
1951
2072
|
const initialValue = selector(store.getState());
|
|
1952
2073
|
listener(initialValue);
|
|
1953
2074
|
return store.subscribe(selector, listener);
|
|
@@ -2013,9 +2134,7 @@ function namespaceArrayToRefs(namespaces) {
|
|
|
2013
2134
|
}
|
|
2014
2135
|
|
|
2015
2136
|
// src/functions/gltf-loading/import-mesh.ts
|
|
2016
|
-
import {
|
|
2017
|
-
Object3D as Object3D5
|
|
2018
|
-
} from "three";
|
|
2137
|
+
import { Object3D as Object3D5 } from "three";
|
|
2019
2138
|
|
|
2020
2139
|
// src/functions/gltf-loading/import-geometry.ts
|
|
2021
2140
|
function sanitizeMorphKey(name, fallbackIndex, used) {
|
|
@@ -2055,7 +2174,7 @@ function importGeometry(geometry, mesh) {
|
|
|
2055
2174
|
type: "number",
|
|
2056
2175
|
default: mesh.morphTargetInfluences?.[index] ?? 0,
|
|
2057
2176
|
constraints: {
|
|
2058
|
-
min:
|
|
2177
|
+
min: -1,
|
|
2059
2178
|
max: 1
|
|
2060
2179
|
},
|
|
2061
2180
|
pub: {
|
|
@@ -2185,6 +2304,15 @@ function importMesh(mesh, namespaces, colorLookup) {
|
|
|
2185
2304
|
world = { ...world, ...newWorldItems };
|
|
2186
2305
|
animatables = { ...animatables, ...newAnimatables };
|
|
2187
2306
|
children.push(childId);
|
|
2307
|
+
} else if (shouldImportAsGroupChild(child)) {
|
|
2308
|
+
const [newWorldItems, newAnimatables, childId, newMeshColors] = importGroup(child, namespaces, {
|
|
2309
|
+
...colorLookup,
|
|
2310
|
+
...newColorLookup
|
|
2311
|
+
});
|
|
2312
|
+
newColorLookup = { ...newColorLookup, ...newMeshColors };
|
|
2313
|
+
world = { ...world, ...newWorldItems };
|
|
2314
|
+
animatables = { ...animatables, ...newAnimatables };
|
|
2315
|
+
children.push(childId);
|
|
2188
2316
|
}
|
|
2189
2317
|
});
|
|
2190
2318
|
const newShape = {
|
|
@@ -2228,6 +2356,24 @@ function getShapeMaterial(mesh, useEmissive) {
|
|
|
2228
2356
|
return "standard" /* Standard */;
|
|
2229
2357
|
}
|
|
2230
2358
|
}
|
|
2359
|
+
function shouldImportAsGroupChild(child) {
|
|
2360
|
+
if (!child.isObject3D) {
|
|
2361
|
+
return false;
|
|
2362
|
+
}
|
|
2363
|
+
if (child.isMesh) {
|
|
2364
|
+
return false;
|
|
2365
|
+
}
|
|
2366
|
+
if (child.isCamera) {
|
|
2367
|
+
return false;
|
|
2368
|
+
}
|
|
2369
|
+
if (child.isLight) {
|
|
2370
|
+
return false;
|
|
2371
|
+
}
|
|
2372
|
+
if (child.isBone) {
|
|
2373
|
+
return false;
|
|
2374
|
+
}
|
|
2375
|
+
return true;
|
|
2376
|
+
}
|
|
2231
2377
|
|
|
2232
2378
|
// src/functions/gltf-loading/import-group.ts
|
|
2233
2379
|
Object3D6.DEFAULT_UP.set(0, 0, 1);
|
|
@@ -2287,7 +2433,7 @@ function importGroup(group, namespaces, colorLookup, rootBounds) {
|
|
|
2287
2433
|
world = { ...world, ...newWorldItems };
|
|
2288
2434
|
animatables = { ...animatables, ...newAnimatables };
|
|
2289
2435
|
children.push(childId);
|
|
2290
|
-
} else if (child
|
|
2436
|
+
} else if (shouldImportAsGroupChild2(child)) {
|
|
2291
2437
|
const [newWorldItems, newAnimatables, childId, newMeshColors] = importGroup(child, namespaces, {
|
|
2292
2438
|
...colorLookup,
|
|
2293
2439
|
...newColorLookup
|
|
@@ -2316,6 +2462,24 @@ function importGroup(group, namespaces, colorLookup, rootBounds) {
|
|
|
2316
2462
|
world = { ...world, [newGroup.id]: newGroup };
|
|
2317
2463
|
return [world, animatables, newGroup.id, newColorLookup];
|
|
2318
2464
|
}
|
|
2465
|
+
function shouldImportAsGroupChild2(child) {
|
|
2466
|
+
if (!child.isObject3D) {
|
|
2467
|
+
return false;
|
|
2468
|
+
}
|
|
2469
|
+
if (child.isMesh) {
|
|
2470
|
+
return false;
|
|
2471
|
+
}
|
|
2472
|
+
if (child.isCamera) {
|
|
2473
|
+
return false;
|
|
2474
|
+
}
|
|
2475
|
+
if (child.isLight) {
|
|
2476
|
+
return false;
|
|
2477
|
+
}
|
|
2478
|
+
if (child.isBone) {
|
|
2479
|
+
return false;
|
|
2480
|
+
}
|
|
2481
|
+
return true;
|
|
2482
|
+
}
|
|
2319
2483
|
|
|
2320
2484
|
// src/functions/gltf-loading/import-scene.ts
|
|
2321
2485
|
Object3D7.DEFAULT_UP.set(0, 0, 1);
|
|
@@ -2589,9 +2753,10 @@ function deriveRootBounds(group) {
|
|
|
2589
2753
|
}
|
|
2590
2754
|
|
|
2591
2755
|
// src/functions/vizij-bundle.ts
|
|
2756
|
+
import { cloneDeepSafe } from "@vizij/utils";
|
|
2592
2757
|
var BUNDLE_KEYS = ["VIZIJ_bundle"];
|
|
2593
2758
|
function cloneBundle(value) {
|
|
2594
|
-
return
|
|
2759
|
+
return cloneDeepSafe(value);
|
|
2595
2760
|
}
|
|
2596
2761
|
function readExtensionValue(extensionContainer) {
|
|
2597
2762
|
for (const key of BUNDLE_KEYS) {
|
|
@@ -2625,6 +2790,13 @@ function searchParserJsonForBundle(parserJson) {
|
|
|
2625
2790
|
if (!parserJson || typeof parserJson !== "object") {
|
|
2626
2791
|
return null;
|
|
2627
2792
|
}
|
|
2793
|
+
const rootExtensions = parserJson && typeof parserJson === "object" ? parserJson.extensions : null;
|
|
2794
|
+
if (rootExtensions && typeof rootExtensions === "object") {
|
|
2795
|
+
const match = readExtensionValue(rootExtensions);
|
|
2796
|
+
if (match) {
|
|
2797
|
+
return cloneBundle(match.value);
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2628
2800
|
const nodes = Array.isArray(parserJson.nodes) ? parserJson.nodes : [];
|
|
2629
2801
|
for (const node of nodes) {
|
|
2630
2802
|
const extensions = node && typeof node === "object" ? node.extensions : null;
|
|
@@ -2689,6 +2861,7 @@ function applyVizijBundle(object, bundle) {
|
|
|
2689
2861
|
}
|
|
2690
2862
|
|
|
2691
2863
|
// src/functions/gltf-loading/extract-animations.ts
|
|
2864
|
+
import { cloneDeepSafe as cloneDeepSafe2 } from "@vizij/utils";
|
|
2692
2865
|
var CHANNEL_PATH_TO_TRACK_PROPERTY = {
|
|
2693
2866
|
translation: "position",
|
|
2694
2867
|
rotation: "quaternion",
|
|
@@ -2704,7 +2877,7 @@ function clonePlainObject(value) {
|
|
|
2704
2877
|
if (!value) {
|
|
2705
2878
|
return void 0;
|
|
2706
2879
|
}
|
|
2707
|
-
return
|
|
2880
|
+
return cloneDeepSafe2(value);
|
|
2708
2881
|
}
|
|
2709
2882
|
function inferValueSize(valueType) {
|
|
2710
2883
|
switch (valueType) {
|
|
@@ -3059,23 +3232,94 @@ function extractVizijAnimations(parserJson, clips) {
|
|
|
3059
3232
|
|
|
3060
3233
|
// src/functions/load-gltf.ts
|
|
3061
3234
|
THREE5.Object3D.DEFAULT_UP.set(0, 0, 1);
|
|
3235
|
+
var GLB_MAGIC = 1179937895;
|
|
3236
|
+
var GLB_VERSION = 2;
|
|
3237
|
+
var GLB_HEADER_BYTES = 12;
|
|
3238
|
+
var GLB_CHUNK_HEADER_BYTES = 8;
|
|
3239
|
+
var GLB_JSON_CHUNK_TYPE = 1313821514;
|
|
3062
3240
|
var EmptyModelError = class extends Error {
|
|
3063
3241
|
constructor(message) {
|
|
3064
3242
|
super(message);
|
|
3065
3243
|
this.name = "EmptyModelError";
|
|
3066
3244
|
}
|
|
3067
3245
|
};
|
|
3246
|
+
function parseGlbJsonChunk(buffer) {
|
|
3247
|
+
if (buffer.byteLength < GLB_HEADER_BYTES + GLB_CHUNK_HEADER_BYTES) {
|
|
3248
|
+
return void 0;
|
|
3249
|
+
}
|
|
3250
|
+
const view = new DataView(buffer);
|
|
3251
|
+
const magic = view.getUint32(0, true);
|
|
3252
|
+
const version = view.getUint32(4, true);
|
|
3253
|
+
if (magic !== GLB_MAGIC || version !== GLB_VERSION) {
|
|
3254
|
+
return void 0;
|
|
3255
|
+
}
|
|
3256
|
+
const chunkLength = view.getUint32(GLB_HEADER_BYTES, true);
|
|
3257
|
+
const chunkType = view.getUint32(GLB_HEADER_BYTES + 4, true);
|
|
3258
|
+
if (chunkType !== GLB_JSON_CHUNK_TYPE) {
|
|
3259
|
+
return void 0;
|
|
3260
|
+
}
|
|
3261
|
+
const chunkStart = GLB_HEADER_BYTES + GLB_CHUNK_HEADER_BYTES;
|
|
3262
|
+
const chunkEnd = chunkStart + chunkLength;
|
|
3263
|
+
if (chunkEnd > buffer.byteLength) {
|
|
3264
|
+
return void 0;
|
|
3265
|
+
}
|
|
3266
|
+
try {
|
|
3267
|
+
const chunkBytes = new Uint8Array(buffer, chunkStart, chunkLength);
|
|
3268
|
+
const jsonText = new TextDecoder().decode(chunkBytes);
|
|
3269
|
+
return JSON.parse(jsonText);
|
|
3270
|
+
} catch {
|
|
3271
|
+
return void 0;
|
|
3272
|
+
}
|
|
3273
|
+
}
|
|
3274
|
+
async function resolveParserJson(parserJson, fallback) {
|
|
3275
|
+
if (parserJson && typeof parserJson === "object") {
|
|
3276
|
+
return parserJson;
|
|
3277
|
+
}
|
|
3278
|
+
if (fallback.arrayBuffer) {
|
|
3279
|
+
const fromArrayBuffer = parseGlbJsonChunk(fallback.arrayBuffer);
|
|
3280
|
+
if (fromArrayBuffer && typeof fromArrayBuffer === "object") {
|
|
3281
|
+
return fromArrayBuffer;
|
|
3282
|
+
}
|
|
3283
|
+
}
|
|
3284
|
+
if (fallback.blob) {
|
|
3285
|
+
try {
|
|
3286
|
+
const blobBuffer = typeof fallback.blob.arrayBuffer === "function" ? await fallback.blob.arrayBuffer() : await new Response(fallback.blob).arrayBuffer();
|
|
3287
|
+
const fromBlob = parseGlbJsonChunk(blobBuffer);
|
|
3288
|
+
if (fromBlob && typeof fromBlob === "object") {
|
|
3289
|
+
return fromBlob;
|
|
3290
|
+
}
|
|
3291
|
+
} catch {
|
|
3292
|
+
}
|
|
3293
|
+
}
|
|
3294
|
+
if (fallback.url && typeof fetch === "function") {
|
|
3295
|
+
try {
|
|
3296
|
+
const response = await fetch(fallback.url);
|
|
3297
|
+
if (response.ok) {
|
|
3298
|
+
const binary = await response.arrayBuffer();
|
|
3299
|
+
const fromUrl = parseGlbJsonChunk(binary);
|
|
3300
|
+
if (fromUrl && typeof fromUrl === "object") {
|
|
3301
|
+
return fromUrl;
|
|
3302
|
+
}
|
|
3303
|
+
}
|
|
3304
|
+
} catch {
|
|
3305
|
+
}
|
|
3306
|
+
}
|
|
3307
|
+
return parserJson;
|
|
3308
|
+
}
|
|
3068
3309
|
async function loadGLTF(url, namespaces, aggressiveImport = false, rootBounds) {
|
|
3069
3310
|
const modelLoader = new GLTFLoader();
|
|
3070
3311
|
modelLoader.setDRACOLoader(new DRACOLoader());
|
|
3071
3312
|
const modelData = await modelLoader.loadAsync(url);
|
|
3313
|
+
const parserJson = await resolveParserJson(modelData?.parser?.json, {
|
|
3314
|
+
url
|
|
3315
|
+
});
|
|
3072
3316
|
const actualizedNamespaces = namespaces.length > 0 ? namespaces : ["default"];
|
|
3073
3317
|
const asset = parseScene(
|
|
3074
3318
|
modelData.scene,
|
|
3075
3319
|
actualizedNamespaces,
|
|
3076
3320
|
aggressiveImport,
|
|
3077
3321
|
rootBounds,
|
|
3078
|
-
|
|
3322
|
+
parserJson,
|
|
3079
3323
|
modelData.animations
|
|
3080
3324
|
);
|
|
3081
3325
|
return [asset.world, asset.animatables, asset.animations];
|
|
@@ -3089,7 +3333,8 @@ async function loadGLTFFromBlob(blob, namespaces, aggressiveImport = false, root
|
|
|
3089
3333
|
objectUrl,
|
|
3090
3334
|
actualizedNamespaces,
|
|
3091
3335
|
aggressiveImport,
|
|
3092
|
-
rootBounds
|
|
3336
|
+
rootBounds,
|
|
3337
|
+
{ blob }
|
|
3093
3338
|
);
|
|
3094
3339
|
return [asset.world, asset.animatables, asset.animations];
|
|
3095
3340
|
} finally {
|
|
@@ -3103,14 +3348,18 @@ async function loadGLTFFromBlob(blob, namespaces, aggressiveImport = false, root
|
|
|
3103
3348
|
loader.parse(
|
|
3104
3349
|
arrayBuffer,
|
|
3105
3350
|
"",
|
|
3106
|
-
(gltf) => {
|
|
3351
|
+
async (gltf) => {
|
|
3107
3352
|
try {
|
|
3353
|
+
const parserJson = await resolveParserJson(
|
|
3354
|
+
gltf?.parser?.json,
|
|
3355
|
+
{ arrayBuffer }
|
|
3356
|
+
);
|
|
3108
3357
|
const asset = parseScene(
|
|
3109
3358
|
gltf.scene,
|
|
3110
3359
|
actualizedNamespaces,
|
|
3111
3360
|
aggressiveImport,
|
|
3112
3361
|
rootBounds,
|
|
3113
|
-
|
|
3362
|
+
parserJson,
|
|
3114
3363
|
gltf.animations
|
|
3115
3364
|
);
|
|
3116
3365
|
resolve([asset.world, asset.animatables, asset.animations]);
|
|
@@ -3137,19 +3386,23 @@ function parseScene(scene, namespaces, aggressiveImport, rootBounds, parserJson,
|
|
|
3137
3386
|
);
|
|
3138
3387
|
const bundle = extractVizijBundle(scene, parserJson);
|
|
3139
3388
|
const animations = extractVizijAnimations(parserJson, clips);
|
|
3140
|
-
return { world, animatables, bundle, animations };
|
|
3389
|
+
return { world, animatables, bundle, animations, scene };
|
|
3141
3390
|
}
|
|
3142
|
-
async function loadGLTFWithBundle(url, namespaces, aggressiveImport = false, rootBounds) {
|
|
3391
|
+
async function loadGLTFWithBundle(url, namespaces, aggressiveImport = false, rootBounds, parserJsonFallback) {
|
|
3143
3392
|
const modelLoader = new GLTFLoader();
|
|
3144
3393
|
modelLoader.setDRACOLoader(new DRACOLoader());
|
|
3145
3394
|
const modelData = await modelLoader.loadAsync(url);
|
|
3395
|
+
const parserJson = await resolveParserJson(modelData?.parser?.json, {
|
|
3396
|
+
url,
|
|
3397
|
+
...parserJsonFallback
|
|
3398
|
+
});
|
|
3146
3399
|
const actualizedNamespaces = namespaces.length > 0 ? namespaces : ["default"];
|
|
3147
3400
|
return parseScene(
|
|
3148
3401
|
modelData.scene,
|
|
3149
3402
|
actualizedNamespaces,
|
|
3150
3403
|
aggressiveImport,
|
|
3151
3404
|
rootBounds,
|
|
3152
|
-
|
|
3405
|
+
parserJson,
|
|
3153
3406
|
modelData.animations
|
|
3154
3407
|
);
|
|
3155
3408
|
}
|
|
@@ -3162,7 +3415,8 @@ async function loadGLTFFromBlobWithBundle(blob, namespaces, aggressiveImport = f
|
|
|
3162
3415
|
objectUrl,
|
|
3163
3416
|
actualizedNamespaces,
|
|
3164
3417
|
aggressiveImport,
|
|
3165
|
-
rootBounds
|
|
3418
|
+
rootBounds,
|
|
3419
|
+
{ blob }
|
|
3166
3420
|
);
|
|
3167
3421
|
} finally {
|
|
3168
3422
|
URL.revokeObjectURL(objectUrl);
|
|
@@ -3175,14 +3429,18 @@ async function loadGLTFFromBlobWithBundle(blob, namespaces, aggressiveImport = f
|
|
|
3175
3429
|
loader.parse(
|
|
3176
3430
|
arrayBuffer,
|
|
3177
3431
|
"",
|
|
3178
|
-
(gltf) => {
|
|
3432
|
+
async (gltf) => {
|
|
3179
3433
|
try {
|
|
3434
|
+
const parserJson = await resolveParserJson(
|
|
3435
|
+
gltf?.parser?.json,
|
|
3436
|
+
{ arrayBuffer }
|
|
3437
|
+
);
|
|
3180
3438
|
const asset = parseScene(
|
|
3181
3439
|
gltf.scene,
|
|
3182
3440
|
actualizedNamespaces,
|
|
3183
3441
|
aggressiveImport,
|
|
3184
3442
|
rootBounds,
|
|
3185
|
-
|
|
3443
|
+
parserJson,
|
|
3186
3444
|
gltf.animations
|
|
3187
3445
|
);
|
|
3188
3446
|
resolve(asset);
|
|
@@ -3234,6 +3492,160 @@ var loadGltfFromBlob = (blob, namespaces) => {
|
|
|
3234
3492
|
import { GLTFExporter } from "three-stdlib";
|
|
3235
3493
|
import * as THREE6 from "three";
|
|
3236
3494
|
THREE6.Object3D.DEFAULT_UP.set(0, 0, 1);
|
|
3495
|
+
function normalizeExportError(error) {
|
|
3496
|
+
if (error instanceof Error) {
|
|
3497
|
+
return error;
|
|
3498
|
+
}
|
|
3499
|
+
if (typeof error === "string") {
|
|
3500
|
+
return new Error(error);
|
|
3501
|
+
}
|
|
3502
|
+
return new Error("Failed to export scene.");
|
|
3503
|
+
}
|
|
3504
|
+
function triggerBlobDownload(blob, filename) {
|
|
3505
|
+
const url = URL.createObjectURL(blob);
|
|
3506
|
+
const link = document.createElement("a");
|
|
3507
|
+
link.href = url;
|
|
3508
|
+
link.download = filename;
|
|
3509
|
+
link.style.display = "none";
|
|
3510
|
+
document.body.appendChild(link);
|
|
3511
|
+
link.click();
|
|
3512
|
+
document.body.removeChild(link);
|
|
3513
|
+
setTimeout(() => URL.revokeObjectURL(url), 0);
|
|
3514
|
+
}
|
|
3515
|
+
var GLB_MAGIC2 = 1179937895;
|
|
3516
|
+
var GLB_VERSION2 = 2;
|
|
3517
|
+
var GLB_JSON_CHUNK_TYPE2 = 1313821514;
|
|
3518
|
+
var GLB_HEADER_BYTES2 = 12;
|
|
3519
|
+
var GLB_CHUNK_HEADER_BYTES2 = 8;
|
|
3520
|
+
var GLB_JSON_PADDING_BYTE = 32;
|
|
3521
|
+
function isNearlyEqual(a, b, epsilon = 1e-6) {
|
|
3522
|
+
return Math.abs(a - b) <= epsilon;
|
|
3523
|
+
}
|
|
3524
|
+
function isIdentityTransformNode(node) {
|
|
3525
|
+
const translation = node.translation;
|
|
3526
|
+
if (Array.isArray(translation) && (translation.length !== 3 || !isNearlyEqual(Number(translation[0]), 0) || !isNearlyEqual(Number(translation[1]), 0) || !isNearlyEqual(Number(translation[2]), 0))) {
|
|
3527
|
+
return false;
|
|
3528
|
+
}
|
|
3529
|
+
const rotation = node.rotation;
|
|
3530
|
+
if (Array.isArray(rotation) && (rotation.length !== 4 || !isNearlyEqual(Number(rotation[0]), 0) || !isNearlyEqual(Number(rotation[1]), 0) || !isNearlyEqual(Number(rotation[2]), 0) || !isNearlyEqual(Number(rotation[3]), 1))) {
|
|
3531
|
+
return false;
|
|
3532
|
+
}
|
|
3533
|
+
const scale = node.scale;
|
|
3534
|
+
if (Array.isArray(scale) && (scale.length !== 3 || !isNearlyEqual(Number(scale[0]), 1) || !isNearlyEqual(Number(scale[1]), 1) || !isNearlyEqual(Number(scale[2]), 1))) {
|
|
3535
|
+
return false;
|
|
3536
|
+
}
|
|
3537
|
+
return true;
|
|
3538
|
+
}
|
|
3539
|
+
function isPassThroughWrapperNode(node) {
|
|
3540
|
+
if (!node || typeof node !== "object") {
|
|
3541
|
+
return false;
|
|
3542
|
+
}
|
|
3543
|
+
if (!Array.isArray(node.children) || node.children.length === 0) {
|
|
3544
|
+
return false;
|
|
3545
|
+
}
|
|
3546
|
+
const hasOnlyNumericChildren = node.children.every(
|
|
3547
|
+
(index) => Number.isInteger(index)
|
|
3548
|
+
);
|
|
3549
|
+
if (!hasOnlyNumericChildren) {
|
|
3550
|
+
return false;
|
|
3551
|
+
}
|
|
3552
|
+
if (node.mesh !== void 0 || node.camera !== void 0 || node.skin !== void 0) {
|
|
3553
|
+
return false;
|
|
3554
|
+
}
|
|
3555
|
+
if (node.extensions && typeof node.extensions === "object" && Object.keys(node.extensions).length > 0) {
|
|
3556
|
+
return false;
|
|
3557
|
+
}
|
|
3558
|
+
return isIdentityTransformNode(node);
|
|
3559
|
+
}
|
|
3560
|
+
function normalizeExportedSceneJson(json, fallbackSceneName) {
|
|
3561
|
+
if (!json || typeof json !== "object") {
|
|
3562
|
+
return false;
|
|
3563
|
+
}
|
|
3564
|
+
if (!Array.isArray(json.scenes) || !Array.isArray(json.nodes)) {
|
|
3565
|
+
return false;
|
|
3566
|
+
}
|
|
3567
|
+
const sceneIndexRaw = json.scene;
|
|
3568
|
+
const sceneIndex = typeof sceneIndexRaw === "number" && Number.isInteger(sceneIndexRaw) ? sceneIndexRaw : 0;
|
|
3569
|
+
const sceneDef = json.scenes[sceneIndex];
|
|
3570
|
+
if (!sceneDef || typeof sceneDef !== "object") {
|
|
3571
|
+
return false;
|
|
3572
|
+
}
|
|
3573
|
+
let changed = false;
|
|
3574
|
+
let wrapperNodeName;
|
|
3575
|
+
if (Array.isArray(sceneDef.nodes) && sceneDef.nodes.length === 1) {
|
|
3576
|
+
const wrapperIndex = sceneDef.nodes[0];
|
|
3577
|
+
if (Number.isInteger(wrapperIndex)) {
|
|
3578
|
+
const wrapperNode = json.nodes[wrapperIndex];
|
|
3579
|
+
if (isPassThroughWrapperNode(wrapperNode)) {
|
|
3580
|
+
sceneDef.nodes = [...wrapperNode.children];
|
|
3581
|
+
wrapperNodeName = typeof wrapperNode.name === "string" ? wrapperNode.name : void 0;
|
|
3582
|
+
changed = true;
|
|
3583
|
+
}
|
|
3584
|
+
}
|
|
3585
|
+
}
|
|
3586
|
+
const currentSceneName = typeof sceneDef.name === "string" ? sceneDef.name.trim() : "";
|
|
3587
|
+
if (currentSceneName === "AuxScene") {
|
|
3588
|
+
const nextSceneName = (wrapperNodeName?.trim() || fallbackSceneName?.trim() || "Scene").trim();
|
|
3589
|
+
if (nextSceneName.length > 0 && nextSceneName !== currentSceneName) {
|
|
3590
|
+
sceneDef.name = nextSceneName;
|
|
3591
|
+
changed = true;
|
|
3592
|
+
}
|
|
3593
|
+
}
|
|
3594
|
+
return changed;
|
|
3595
|
+
}
|
|
3596
|
+
function sanitizeExportedGlb(buffer, fallbackSceneName) {
|
|
3597
|
+
if (buffer.byteLength < GLB_HEADER_BYTES2 + GLB_CHUNK_HEADER_BYTES2) {
|
|
3598
|
+
return buffer;
|
|
3599
|
+
}
|
|
3600
|
+
const originalBytes = new Uint8Array(buffer);
|
|
3601
|
+
const view = new DataView(buffer);
|
|
3602
|
+
const magic = view.getUint32(0, true);
|
|
3603
|
+
const version = view.getUint32(4, true);
|
|
3604
|
+
if (magic !== GLB_MAGIC2 || version !== GLB_VERSION2) {
|
|
3605
|
+
return buffer;
|
|
3606
|
+
}
|
|
3607
|
+
const jsonChunkLength = view.getUint32(GLB_HEADER_BYTES2, true);
|
|
3608
|
+
const jsonChunkType = view.getUint32(GLB_HEADER_BYTES2 + 4, true);
|
|
3609
|
+
if (jsonChunkType !== GLB_JSON_CHUNK_TYPE2) {
|
|
3610
|
+
return buffer;
|
|
3611
|
+
}
|
|
3612
|
+
const jsonChunkStart = GLB_HEADER_BYTES2 + GLB_CHUNK_HEADER_BYTES2;
|
|
3613
|
+
const jsonChunkEnd = jsonChunkStart + jsonChunkLength;
|
|
3614
|
+
if (jsonChunkEnd > originalBytes.length) {
|
|
3615
|
+
return buffer;
|
|
3616
|
+
}
|
|
3617
|
+
let jsonPayload;
|
|
3618
|
+
try {
|
|
3619
|
+
const jsonText = new TextDecoder().decode(
|
|
3620
|
+
originalBytes.slice(jsonChunkStart, jsonChunkEnd)
|
|
3621
|
+
);
|
|
3622
|
+
jsonPayload = JSON.parse(jsonText);
|
|
3623
|
+
} catch {
|
|
3624
|
+
return buffer;
|
|
3625
|
+
}
|
|
3626
|
+
const changed = normalizeExportedSceneJson(jsonPayload, fallbackSceneName);
|
|
3627
|
+
if (!changed) {
|
|
3628
|
+
return buffer;
|
|
3629
|
+
}
|
|
3630
|
+
const encodedJson = new TextEncoder().encode(JSON.stringify(jsonPayload));
|
|
3631
|
+
const paddedJsonLength = encodedJson.length + 3 & ~3;
|
|
3632
|
+
const paddedJson = new Uint8Array(paddedJsonLength);
|
|
3633
|
+
paddedJson.fill(GLB_JSON_PADDING_BYTE);
|
|
3634
|
+
paddedJson.set(encodedJson);
|
|
3635
|
+
const remainingChunks = originalBytes.slice(jsonChunkEnd);
|
|
3636
|
+
const totalLength = GLB_HEADER_BYTES2 + GLB_CHUNK_HEADER_BYTES2 + paddedJsonLength + remainingChunks.length;
|
|
3637
|
+
const sanitized = new ArrayBuffer(totalLength);
|
|
3638
|
+
const sanitizedBytes = new Uint8Array(sanitized);
|
|
3639
|
+
const sanitizedView = new DataView(sanitized);
|
|
3640
|
+
sanitizedView.setUint32(0, GLB_MAGIC2, true);
|
|
3641
|
+
sanitizedView.setUint32(4, GLB_VERSION2, true);
|
|
3642
|
+
sanitizedView.setUint32(8, totalLength, true);
|
|
3643
|
+
sanitizedView.setUint32(GLB_HEADER_BYTES2, paddedJsonLength, true);
|
|
3644
|
+
sanitizedView.setUint32(GLB_HEADER_BYTES2 + 4, GLB_JSON_CHUNK_TYPE2, true);
|
|
3645
|
+
sanitizedBytes.set(paddedJson, jsonChunkStart);
|
|
3646
|
+
sanitizedBytes.set(remainingChunks, jsonChunkStart + paddedJsonLength);
|
|
3647
|
+
return sanitized;
|
|
3648
|
+
}
|
|
3237
3649
|
function exportScene(data, fileNameOrOptions = "scene.glb") {
|
|
3238
3650
|
const options = typeof fileNameOrOptions === "string" ? { fileName: fileNameOrOptions } : fileNameOrOptions ?? {};
|
|
3239
3651
|
const fileName = options.fileName ?? "scene.glb";
|
|
@@ -3248,7 +3660,15 @@ function exportScene(data, fileNameOrOptions = "scene.glb") {
|
|
|
3248
3660
|
}
|
|
3249
3661
|
}
|
|
3250
3662
|
}));
|
|
3251
|
-
const
|
|
3663
|
+
const sourceRoot = data;
|
|
3664
|
+
const exportRoot = sourceRoot instanceof THREE6.Scene ? sourceRoot : sourceRoot.clone(true);
|
|
3665
|
+
const exportTarget = exportRoot instanceof THREE6.Scene ? exportRoot : (() => {
|
|
3666
|
+
const scene = new THREE6.Scene();
|
|
3667
|
+
scene.name = data.name?.trim() || "Scene";
|
|
3668
|
+
scene.add(exportRoot);
|
|
3669
|
+
return scene;
|
|
3670
|
+
})();
|
|
3671
|
+
const detachBundle = shouldAttachBundle && options.bundle ? applyVizijBundle(exportRoot, options.bundle) : () => {
|
|
3252
3672
|
};
|
|
3253
3673
|
const binary = options.binary ?? true;
|
|
3254
3674
|
const exporterOptions = {
|
|
@@ -3262,33 +3682,40 @@ function exportScene(data, fileNameOrOptions = "scene.glb") {
|
|
|
3262
3682
|
}
|
|
3263
3683
|
try {
|
|
3264
3684
|
exporter.parse(
|
|
3265
|
-
|
|
3685
|
+
exportTarget,
|
|
3266
3686
|
(gltf) => {
|
|
3267
3687
|
detachBundle();
|
|
3268
3688
|
if (!(gltf instanceof ArrayBuffer)) {
|
|
3269
|
-
|
|
3689
|
+
const error = new Error("Failed to export scene.");
|
|
3690
|
+
options.onError?.(error);
|
|
3691
|
+
return;
|
|
3270
3692
|
}
|
|
3271
|
-
const
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
type: "application/octet-stream"
|
|
3275
|
-
})
|
|
3693
|
+
const sanitizedGltf = sanitizeExportedGlb(
|
|
3694
|
+
gltf,
|
|
3695
|
+
data.name?.trim() || void 0
|
|
3276
3696
|
);
|
|
3277
3697
|
const trimmed = fileName.trim();
|
|
3278
3698
|
const safeFileName = trimmed.length > 0 ? trimmed : "scene.glb";
|
|
3279
3699
|
const downloadName = safeFileName.toLowerCase().endsWith(".glb") ? safeFileName : `${safeFileName}.glb`;
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3700
|
+
triggerBlobDownload(
|
|
3701
|
+
new Blob([sanitizedGltf], {
|
|
3702
|
+
type: "application/octet-stream"
|
|
3703
|
+
}),
|
|
3704
|
+
downloadName
|
|
3705
|
+
);
|
|
3706
|
+
options.onComplete?.();
|
|
3283
3707
|
},
|
|
3284
|
-
() => {
|
|
3708
|
+
(error) => {
|
|
3285
3709
|
detachBundle();
|
|
3710
|
+
options.onError?.(normalizeExportError(error));
|
|
3286
3711
|
},
|
|
3287
3712
|
exporterOptions
|
|
3288
3713
|
);
|
|
3289
3714
|
} catch (error) {
|
|
3290
3715
|
detachBundle();
|
|
3291
|
-
|
|
3716
|
+
const normalizedError = normalizeExportError(error);
|
|
3717
|
+
options.onError?.(normalizedError);
|
|
3718
|
+
throw normalizedError;
|
|
3292
3719
|
}
|
|
3293
3720
|
}
|
|
3294
3721
|
export {
|
|
@@ -3307,6 +3734,7 @@ export {
|
|
|
3307
3734
|
loadGLTFFromBlobWithBundle,
|
|
3308
3735
|
loadGLTFWithBundle,
|
|
3309
3736
|
loadGltfFromBlob,
|
|
3737
|
+
parseGlbJsonChunk,
|
|
3310
3738
|
useDefaultVizijStore,
|
|
3311
3739
|
useFeatures,
|
|
3312
3740
|
useVizijStore,
|