@vizij/render 0.0.1 → 0.0.3
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 +12 -0
- package/dist/index.d.mts +113 -3
- package/dist/index.d.ts +113 -3
- package/dist/index.js +444 -44
- package/dist/index.mjs +440 -44
- package/package.json +3 -4
package/dist/index.mjs
CHANGED
|
@@ -393,6 +393,11 @@ function InnerRenderedGroup({
|
|
|
393
393
|
setReference(group.id, namespace, ref);
|
|
394
394
|
}
|
|
395
395
|
}, [group.id, namespace, ref, setReference, refIsNull]);
|
|
396
|
+
useEffect2(() => {
|
|
397
|
+
if (ref.current) {
|
|
398
|
+
ref.current.name = group.name;
|
|
399
|
+
}
|
|
400
|
+
}, [group.name]);
|
|
396
401
|
const handlePointerOver = useCallback(
|
|
397
402
|
(event) => {
|
|
398
403
|
if (event.eventObject !== event.object) {
|
|
@@ -557,6 +562,9 @@ function InnerRenderedEllipse({
|
|
|
557
562
|
if (instanceOfRawRGB(color)) {
|
|
558
563
|
materialRef.current.color.setRGB(color.r, color.g, color.b);
|
|
559
564
|
materialRef.current.needsUpdate = true;
|
|
565
|
+
} else if (instanceOfRawVector32(color)) {
|
|
566
|
+
materialRef.current.color.setRGB(color.x, color.y, color.z);
|
|
567
|
+
materialRef.current.needsUpdate = true;
|
|
560
568
|
} else if (instanceOfRawHSL(color)) {
|
|
561
569
|
materialRef.current.color.setHSL(color.h, color.s, color.l);
|
|
562
570
|
materialRef.current.needsUpdate = true;
|
|
@@ -609,6 +617,13 @@ function InnerRenderedEllipse({
|
|
|
609
617
|
strokeColor.b
|
|
610
618
|
);
|
|
611
619
|
lineRef.current.material.needsUpdate = true;
|
|
620
|
+
} else if (instanceOfRawVector32(strokeColor)) {
|
|
621
|
+
lineRef.current.material.color.setRGB(
|
|
622
|
+
strokeColor.x,
|
|
623
|
+
strokeColor.y,
|
|
624
|
+
strokeColor.z
|
|
625
|
+
);
|
|
626
|
+
lineRef.current.material.needsUpdate = true;
|
|
612
627
|
} else if (instanceOfRawHSL(strokeColor)) {
|
|
613
628
|
lineRef.current.material.color.setHSL(
|
|
614
629
|
strokeColor.h,
|
|
@@ -845,6 +860,9 @@ function InnerRenderedRectangle({
|
|
|
845
860
|
if (instanceOfRawRGB2(color)) {
|
|
846
861
|
materialRef.current.color.setRGB(color.r, color.g, color.b);
|
|
847
862
|
materialRef.current.needsUpdate = true;
|
|
863
|
+
} else if (instanceOfRawVector33(color)) {
|
|
864
|
+
materialRef.current.color.setRGB(color.x, color.y, color.z);
|
|
865
|
+
materialRef.current.needsUpdate = true;
|
|
848
866
|
} else if (instanceOfRawHSL2(color)) {
|
|
849
867
|
materialRef.current.color.setHSL(color.h, color.s, color.l);
|
|
850
868
|
materialRef.current.needsUpdate = true;
|
|
@@ -897,6 +915,13 @@ function InnerRenderedRectangle({
|
|
|
897
915
|
strokeColor.b
|
|
898
916
|
);
|
|
899
917
|
lineRef.current.material.needsUpdate = true;
|
|
918
|
+
} else if (instanceOfRawVector33(strokeColor)) {
|
|
919
|
+
lineRef.current.material.color.setRGB(
|
|
920
|
+
strokeColor.x,
|
|
921
|
+
strokeColor.y,
|
|
922
|
+
strokeColor.z
|
|
923
|
+
);
|
|
924
|
+
lineRef.current.material.needsUpdate = true;
|
|
900
925
|
} else if (instanceOfRawHSL2(strokeColor)) {
|
|
901
926
|
lineRef.current.material.color.setHSL(
|
|
902
927
|
strokeColor.h,
|
|
@@ -1052,7 +1077,17 @@ function InnerRenderedShape({
|
|
|
1052
1077
|
});
|
|
1053
1078
|
return av;
|
|
1054
1079
|
}, [shape.features, animatables]);
|
|
1055
|
-
const
|
|
1080
|
+
const materialName = useMemo4(
|
|
1081
|
+
() => deriveMaterialName(shape, animatableValues),
|
|
1082
|
+
[shape, animatableValues]
|
|
1083
|
+
);
|
|
1084
|
+
const geometry = useMemo4(() => {
|
|
1085
|
+
const cloned = shape.geometry.clone();
|
|
1086
|
+
if (shape.name) {
|
|
1087
|
+
cloned.name = shape.name;
|
|
1088
|
+
}
|
|
1089
|
+
return cloned;
|
|
1090
|
+
}, [shape.geometry, shape.name]);
|
|
1056
1091
|
const selectionData = useMemo4(
|
|
1057
1092
|
() => ({ id, namespace, type: "shape" }),
|
|
1058
1093
|
[id, namespace]
|
|
@@ -1142,9 +1177,14 @@ function InnerRenderedShape({
|
|
|
1142
1177
|
color.g,
|
|
1143
1178
|
color.b
|
|
1144
1179
|
);
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1180
|
+
material.current.needsUpdate = true;
|
|
1181
|
+
} else if ((material.current || void 0)?.color && instanceOfRawVector34(color)) {
|
|
1182
|
+
material.current.color.setRGB(
|
|
1183
|
+
color.x,
|
|
1184
|
+
color.y,
|
|
1185
|
+
color.z
|
|
1186
|
+
);
|
|
1187
|
+
material.current.needsUpdate = true;
|
|
1148
1188
|
} else if (material.current && instanceOfRawHSL3(color)) {
|
|
1149
1189
|
material.current.color.setHSL(
|
|
1150
1190
|
color.h,
|
|
@@ -1167,6 +1207,21 @@ function InnerRenderedShape({
|
|
|
1167
1207
|
useEffect5(() => {
|
|
1168
1208
|
if (ref.current && refIsNull) setReference(shape.id, namespace, ref);
|
|
1169
1209
|
}, [shape.id, namespace, ref, setReference, refIsNull]);
|
|
1210
|
+
useEffect5(() => {
|
|
1211
|
+
if (ref.current) {
|
|
1212
|
+
ref.current.name = shape.name;
|
|
1213
|
+
}
|
|
1214
|
+
}, [shape.name]);
|
|
1215
|
+
useEffect5(() => {
|
|
1216
|
+
if (!material.current) {
|
|
1217
|
+
return;
|
|
1218
|
+
}
|
|
1219
|
+
if (materialName) {
|
|
1220
|
+
material.current.name = materialName;
|
|
1221
|
+
} else if (shape.name) {
|
|
1222
|
+
material.current.name = shape.name;
|
|
1223
|
+
}
|
|
1224
|
+
}, [materialName, shape.name]);
|
|
1170
1225
|
const handlePointerOver = useCallback4(
|
|
1171
1226
|
(event) => {
|
|
1172
1227
|
event.stopPropagation();
|
|
@@ -1253,6 +1308,51 @@ function InnerRenderedShape({
|
|
|
1253
1308
|
);
|
|
1254
1309
|
}
|
|
1255
1310
|
var RenderedShape = memo5(InnerRenderedShape);
|
|
1311
|
+
var MATERIAL_FEATURE_KEYS = [
|
|
1312
|
+
"color",
|
|
1313
|
+
"opacity",
|
|
1314
|
+
"roughness",
|
|
1315
|
+
"metalness",
|
|
1316
|
+
"shininess"
|
|
1317
|
+
];
|
|
1318
|
+
var MATERIAL_NAME_SUFFIXES = [
|
|
1319
|
+
" color",
|
|
1320
|
+
" colours",
|
|
1321
|
+
" colour",
|
|
1322
|
+
" opacity",
|
|
1323
|
+
" roughness",
|
|
1324
|
+
" metalness",
|
|
1325
|
+
" shininess"
|
|
1326
|
+
];
|
|
1327
|
+
function deriveMaterialName(shape, values) {
|
|
1328
|
+
for (const key of MATERIAL_FEATURE_KEYS) {
|
|
1329
|
+
const feature = shape.features[key];
|
|
1330
|
+
if (feature && feature.animated) {
|
|
1331
|
+
const animatable = values[feature.value];
|
|
1332
|
+
const candidate = extractMaterialName(animatable?.name);
|
|
1333
|
+
if (candidate) {
|
|
1334
|
+
return candidate;
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
return void 0;
|
|
1339
|
+
}
|
|
1340
|
+
function extractMaterialName(name) {
|
|
1341
|
+
if (!name) {
|
|
1342
|
+
return void 0;
|
|
1343
|
+
}
|
|
1344
|
+
const trimmed = name.trim();
|
|
1345
|
+
if (!trimmed) {
|
|
1346
|
+
return void 0;
|
|
1347
|
+
}
|
|
1348
|
+
const lowered = trimmed.toLowerCase();
|
|
1349
|
+
for (const suffix of MATERIAL_NAME_SUFFIXES) {
|
|
1350
|
+
if (lowered.endsWith(suffix)) {
|
|
1351
|
+
return trimmed.slice(0, trimmed.length - suffix.length).trim();
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
return trimmed;
|
|
1355
|
+
}
|
|
1256
1356
|
|
|
1257
1357
|
// src/renderables/renderable.tsx
|
|
1258
1358
|
import { Fragment as Fragment3, jsx as jsx6 } from "react/jsx-runtime";
|
|
@@ -2426,9 +2526,12 @@ function traverseThree(group, namespaces, aggressiveImport = false, rootBounds)
|
|
|
2426
2526
|
});
|
|
2427
2527
|
const useRobotData = !aggressiveImport || hasRobotData;
|
|
2428
2528
|
if (useRobotData) {
|
|
2429
|
-
|
|
2529
|
+
const stack = [group];
|
|
2530
|
+
while (stack.length > 0) {
|
|
2531
|
+
const child = stack.pop();
|
|
2430
2532
|
if (child.userData?.gltfExtensions?.RobotData) {
|
|
2431
2533
|
const data = child.userData.gltfExtensions.RobotData;
|
|
2534
|
+
applyStoredRenderableNames(child, data);
|
|
2432
2535
|
let loadedData;
|
|
2433
2536
|
let mappedFeatures;
|
|
2434
2537
|
let animatableValues;
|
|
@@ -2494,7 +2597,10 @@ function traverseThree(group, namespaces, aggressiveImport = false, rootBounds)
|
|
|
2494
2597
|
throw new Error(`Unhandled type`);
|
|
2495
2598
|
}
|
|
2496
2599
|
}
|
|
2497
|
-
|
|
2600
|
+
if (child.children) {
|
|
2601
|
+
stack.push(...child.children);
|
|
2602
|
+
}
|
|
2603
|
+
}
|
|
2498
2604
|
} else {
|
|
2499
2605
|
const derivedRootBounds = rootBounds ?? deriveRootBounds(group);
|
|
2500
2606
|
if (!derivedRootBounds) {
|
|
@@ -2510,6 +2616,94 @@ function traverseThree(group, namespaces, aggressiveImport = false, rootBounds)
|
|
|
2510
2616
|
}
|
|
2511
2617
|
return [worldData, animatableData];
|
|
2512
2618
|
}
|
|
2619
|
+
var MATERIAL_NAME_FEATURE_KEYS = [
|
|
2620
|
+
"color",
|
|
2621
|
+
"opacity",
|
|
2622
|
+
"roughness",
|
|
2623
|
+
"metalness",
|
|
2624
|
+
"shininess"
|
|
2625
|
+
];
|
|
2626
|
+
var MATERIAL_NAME_SUFFIXES2 = [
|
|
2627
|
+
" color",
|
|
2628
|
+
" colours",
|
|
2629
|
+
" colour",
|
|
2630
|
+
" opacity",
|
|
2631
|
+
" roughness",
|
|
2632
|
+
" metalness",
|
|
2633
|
+
" shininess"
|
|
2634
|
+
];
|
|
2635
|
+
function applyStoredRenderableNames(object, data) {
|
|
2636
|
+
if (typeof data.name === "string" && data.name.length > 0) {
|
|
2637
|
+
object.name = data.name;
|
|
2638
|
+
}
|
|
2639
|
+
if (object.isGroup) {
|
|
2640
|
+
const group = object;
|
|
2641
|
+
if (typeof data.name === "string" && data.name.length > 0) {
|
|
2642
|
+
group.name = data.name;
|
|
2643
|
+
}
|
|
2644
|
+
}
|
|
2645
|
+
if (object.isMesh) {
|
|
2646
|
+
const mesh = object;
|
|
2647
|
+
if (typeof data.name === "string" && data.name.length > 0) {
|
|
2648
|
+
mesh.name = data.name;
|
|
2649
|
+
if (mesh.geometry) {
|
|
2650
|
+
mesh.geometry.name = data.name;
|
|
2651
|
+
}
|
|
2652
|
+
}
|
|
2653
|
+
const inferredName = inferMaterialNameFromStoredRenderable(data);
|
|
2654
|
+
if (inferredName) {
|
|
2655
|
+
assignMaterialName(mesh.material, inferredName);
|
|
2656
|
+
}
|
|
2657
|
+
}
|
|
2658
|
+
}
|
|
2659
|
+
function assignMaterialName(material, name) {
|
|
2660
|
+
if (!material) {
|
|
2661
|
+
return;
|
|
2662
|
+
}
|
|
2663
|
+
if (Array.isArray(material)) {
|
|
2664
|
+
material.forEach((mat) => {
|
|
2665
|
+
mat.name = name;
|
|
2666
|
+
});
|
|
2667
|
+
} else {
|
|
2668
|
+
material.name = name;
|
|
2669
|
+
}
|
|
2670
|
+
}
|
|
2671
|
+
function inferMaterialNameFromStoredRenderable(data) {
|
|
2672
|
+
if (data.type !== "shape") {
|
|
2673
|
+
return void 0;
|
|
2674
|
+
}
|
|
2675
|
+
const features = data.features;
|
|
2676
|
+
for (const key of MATERIAL_NAME_FEATURE_KEYS) {
|
|
2677
|
+
const candidate = extractMaterialNameFromFeature(features[key]);
|
|
2678
|
+
if (candidate) {
|
|
2679
|
+
return candidate;
|
|
2680
|
+
}
|
|
2681
|
+
}
|
|
2682
|
+
return void 0;
|
|
2683
|
+
}
|
|
2684
|
+
function extractMaterialNameFromFeature(feature) {
|
|
2685
|
+
if (!isStoredAnimatedFeature(feature)) {
|
|
2686
|
+
return void 0;
|
|
2687
|
+
}
|
|
2688
|
+
const animatableName = feature.value.name;
|
|
2689
|
+
if (!animatableName) {
|
|
2690
|
+
return void 0;
|
|
2691
|
+
}
|
|
2692
|
+
return stripMaterialSuffixes(animatableName);
|
|
2693
|
+
}
|
|
2694
|
+
function stripMaterialSuffixes(name) {
|
|
2695
|
+
const trimmed = name.trim();
|
|
2696
|
+
const lowered = trimmed.toLowerCase();
|
|
2697
|
+
for (const suffix of MATERIAL_NAME_SUFFIXES2) {
|
|
2698
|
+
if (lowered.endsWith(suffix)) {
|
|
2699
|
+
return trimmed.slice(0, trimmed.length - suffix.length).trim();
|
|
2700
|
+
}
|
|
2701
|
+
}
|
|
2702
|
+
return trimmed;
|
|
2703
|
+
}
|
|
2704
|
+
function isStoredAnimatedFeature(feature) {
|
|
2705
|
+
return Boolean(feature) && typeof feature === "object" && feature.animated === true && "value" in feature;
|
|
2706
|
+
}
|
|
2513
2707
|
function isGroupFeatures(value) {
|
|
2514
2708
|
if (!value || typeof value !== "object") {
|
|
2515
2709
|
throw new Error("Expected object");
|
|
@@ -2574,6 +2768,106 @@ function deriveRootBounds(group) {
|
|
|
2574
2768
|
};
|
|
2575
2769
|
}
|
|
2576
2770
|
|
|
2771
|
+
// src/functions/vizij-bundle.ts
|
|
2772
|
+
var BUNDLE_KEYS = ["VIZIJ_bundle"];
|
|
2773
|
+
function cloneBundle(value) {
|
|
2774
|
+
return JSON.parse(JSON.stringify(value));
|
|
2775
|
+
}
|
|
2776
|
+
function readExtensionValue(extensionContainer) {
|
|
2777
|
+
for (const key of BUNDLE_KEYS) {
|
|
2778
|
+
if (extensionContainer && Object.prototype.hasOwnProperty.call(extensionContainer, key)) {
|
|
2779
|
+
const value = extensionContainer[key];
|
|
2780
|
+
if (value && typeof value === "object") {
|
|
2781
|
+
return { key, value };
|
|
2782
|
+
}
|
|
2783
|
+
}
|
|
2784
|
+
}
|
|
2785
|
+
return null;
|
|
2786
|
+
}
|
|
2787
|
+
function searchObjectForBundle(object) {
|
|
2788
|
+
const stack = [object];
|
|
2789
|
+
while (stack.length > 0) {
|
|
2790
|
+
const current = stack.pop();
|
|
2791
|
+
const extensions = current?.userData?.gltfExtensions ?? current?.userData?.extensions ?? null;
|
|
2792
|
+
if (extensions && typeof extensions === "object") {
|
|
2793
|
+
const match = readExtensionValue(extensions);
|
|
2794
|
+
if (match) {
|
|
2795
|
+
return cloneBundle(match.value);
|
|
2796
|
+
}
|
|
2797
|
+
}
|
|
2798
|
+
if (current.children && current.children.length > 0) {
|
|
2799
|
+
stack.push(...current.children);
|
|
2800
|
+
}
|
|
2801
|
+
}
|
|
2802
|
+
return null;
|
|
2803
|
+
}
|
|
2804
|
+
function searchParserJsonForBundle(parserJson) {
|
|
2805
|
+
if (!parserJson || typeof parserJson !== "object") {
|
|
2806
|
+
return null;
|
|
2807
|
+
}
|
|
2808
|
+
const nodes = Array.isArray(parserJson.nodes) ? parserJson.nodes : [];
|
|
2809
|
+
for (const node of nodes) {
|
|
2810
|
+
const extensions = node && typeof node === "object" ? node.extensions : null;
|
|
2811
|
+
if (extensions && typeof extensions === "object") {
|
|
2812
|
+
const match = readExtensionValue(extensions);
|
|
2813
|
+
if (match) {
|
|
2814
|
+
return cloneBundle(match.value);
|
|
2815
|
+
}
|
|
2816
|
+
}
|
|
2817
|
+
}
|
|
2818
|
+
const scenes = Array.isArray(parserJson.scenes) ? parserJson.scenes : [];
|
|
2819
|
+
for (const scene of scenes) {
|
|
2820
|
+
const extensions = scene && typeof scene === "object" ? scene.extensions : null;
|
|
2821
|
+
if (extensions && typeof extensions === "object") {
|
|
2822
|
+
const match = readExtensionValue(extensions);
|
|
2823
|
+
if (match) {
|
|
2824
|
+
return cloneBundle(match.value);
|
|
2825
|
+
}
|
|
2826
|
+
}
|
|
2827
|
+
}
|
|
2828
|
+
return null;
|
|
2829
|
+
}
|
|
2830
|
+
function extractVizijBundle(object, parserJson) {
|
|
2831
|
+
const fromObject = searchObjectForBundle(object);
|
|
2832
|
+
if (fromObject) {
|
|
2833
|
+
return fromObject;
|
|
2834
|
+
}
|
|
2835
|
+
const fromParser = searchParserJsonForBundle(parserJson);
|
|
2836
|
+
if (fromParser) {
|
|
2837
|
+
return fromParser;
|
|
2838
|
+
}
|
|
2839
|
+
return null;
|
|
2840
|
+
}
|
|
2841
|
+
function applyVizijBundle(object, bundle) {
|
|
2842
|
+
const userData = object.userData && typeof object.userData === "object" ? object.userData : {};
|
|
2843
|
+
const originalExtensions = userData.gltfExtensions;
|
|
2844
|
+
let applied = false;
|
|
2845
|
+
if (bundle) {
|
|
2846
|
+
userData.gltfExtensions = {
|
|
2847
|
+
...originalExtensions ?? {},
|
|
2848
|
+
VIZIJ_bundle: bundle
|
|
2849
|
+
};
|
|
2850
|
+
object.userData = userData;
|
|
2851
|
+
applied = true;
|
|
2852
|
+
}
|
|
2853
|
+
return () => {
|
|
2854
|
+
if (!applied) {
|
|
2855
|
+
return;
|
|
2856
|
+
}
|
|
2857
|
+
if (originalExtensions) {
|
|
2858
|
+
userData.gltfExtensions = originalExtensions;
|
|
2859
|
+
} else {
|
|
2860
|
+
if (userData.gltfExtensions) {
|
|
2861
|
+
delete userData.gltfExtensions;
|
|
2862
|
+
}
|
|
2863
|
+
if (Object.keys(userData).length === 0) {
|
|
2864
|
+
delete object.userData;
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2867
|
+
applied = false;
|
|
2868
|
+
};
|
|
2869
|
+
}
|
|
2870
|
+
|
|
2577
2871
|
// src/functions/load-gltf.ts
|
|
2578
2872
|
THREE5.Object3D.DEFAULT_UP.set(0, 0, 1);
|
|
2579
2873
|
var EmptyModelError = class extends Error {
|
|
@@ -2587,24 +2881,27 @@ async function loadGLTF(url, namespaces, aggressiveImport = false, rootBounds) {
|
|
|
2587
2881
|
modelLoader.setDRACOLoader(new DRACOLoader());
|
|
2588
2882
|
const modelData = await modelLoader.loadAsync(url);
|
|
2589
2883
|
const actualizedNamespaces = namespaces.length > 0 ? namespaces : ["default"];
|
|
2590
|
-
|
|
2884
|
+
const asset = parseScene(
|
|
2591
2885
|
modelData.scene,
|
|
2592
2886
|
actualizedNamespaces,
|
|
2593
2887
|
aggressiveImport,
|
|
2594
|
-
rootBounds
|
|
2888
|
+
rootBounds,
|
|
2889
|
+
modelData?.parser?.json
|
|
2595
2890
|
);
|
|
2891
|
+
return [asset.world, asset.animatables];
|
|
2596
2892
|
}
|
|
2597
2893
|
async function loadGLTFFromBlob(blob, namespaces, aggressiveImport = false, rootBounds) {
|
|
2598
2894
|
const actualizedNamespaces = namespaces.length > 0 ? namespaces : ["default"];
|
|
2599
2895
|
if (typeof URL !== "undefined" && typeof URL.createObjectURL === "function") {
|
|
2600
2896
|
const objectUrl = URL.createObjectURL(blob);
|
|
2601
2897
|
try {
|
|
2602
|
-
|
|
2898
|
+
const asset = await loadGLTFWithBundle(
|
|
2603
2899
|
objectUrl,
|
|
2604
2900
|
actualizedNamespaces,
|
|
2605
2901
|
aggressiveImport,
|
|
2606
2902
|
rootBounds
|
|
2607
2903
|
);
|
|
2904
|
+
return [asset.world, asset.animatables];
|
|
2608
2905
|
} finally {
|
|
2609
2906
|
URL.revokeObjectURL(objectUrl);
|
|
2610
2907
|
}
|
|
@@ -2618,14 +2915,83 @@ async function loadGLTFFromBlob(blob, namespaces, aggressiveImport = false, root
|
|
|
2618
2915
|
"",
|
|
2619
2916
|
(gltf) => {
|
|
2620
2917
|
try {
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
)
|
|
2918
|
+
const asset = parseScene(
|
|
2919
|
+
gltf.scene,
|
|
2920
|
+
actualizedNamespaces,
|
|
2921
|
+
aggressiveImport,
|
|
2922
|
+
rootBounds,
|
|
2923
|
+
gltf?.parser?.json
|
|
2628
2924
|
);
|
|
2925
|
+
resolve([asset.world, asset.animatables]);
|
|
2926
|
+
} catch (error) {
|
|
2927
|
+
if (error instanceof Error) {
|
|
2928
|
+
reject(error);
|
|
2929
|
+
} else {
|
|
2930
|
+
reject(new Error(String(error)));
|
|
2931
|
+
}
|
|
2932
|
+
}
|
|
2933
|
+
},
|
|
2934
|
+
(error) => {
|
|
2935
|
+
reject(new Error(`Error loading GLTF: ${error.message}`));
|
|
2936
|
+
}
|
|
2937
|
+
);
|
|
2938
|
+
});
|
|
2939
|
+
}
|
|
2940
|
+
function parseScene(scene, namespaces, aggressiveImport, rootBounds, parserJson) {
|
|
2941
|
+
const [world, animatables] = traverseThree(
|
|
2942
|
+
scene,
|
|
2943
|
+
namespaces,
|
|
2944
|
+
aggressiveImport,
|
|
2945
|
+
rootBounds
|
|
2946
|
+
);
|
|
2947
|
+
const bundle = extractVizijBundle(scene, parserJson);
|
|
2948
|
+
return { world, animatables, bundle };
|
|
2949
|
+
}
|
|
2950
|
+
async function loadGLTFWithBundle(url, namespaces, aggressiveImport = false, rootBounds) {
|
|
2951
|
+
const modelLoader = new GLTFLoader();
|
|
2952
|
+
modelLoader.setDRACOLoader(new DRACOLoader());
|
|
2953
|
+
const modelData = await modelLoader.loadAsync(url);
|
|
2954
|
+
const actualizedNamespaces = namespaces.length > 0 ? namespaces : ["default"];
|
|
2955
|
+
return parseScene(
|
|
2956
|
+
modelData.scene,
|
|
2957
|
+
actualizedNamespaces,
|
|
2958
|
+
aggressiveImport,
|
|
2959
|
+
rootBounds,
|
|
2960
|
+
modelData?.parser?.json
|
|
2961
|
+
);
|
|
2962
|
+
}
|
|
2963
|
+
async function loadGLTFFromBlobWithBundle(blob, namespaces, aggressiveImport = false, rootBounds) {
|
|
2964
|
+
const actualizedNamespaces = namespaces.length > 0 ? namespaces : ["default"];
|
|
2965
|
+
if (typeof URL !== "undefined" && typeof URL.createObjectURL === "function") {
|
|
2966
|
+
const objectUrl = URL.createObjectURL(blob);
|
|
2967
|
+
try {
|
|
2968
|
+
return await loadGLTFWithBundle(
|
|
2969
|
+
objectUrl,
|
|
2970
|
+
actualizedNamespaces,
|
|
2971
|
+
aggressiveImport,
|
|
2972
|
+
rootBounds
|
|
2973
|
+
);
|
|
2974
|
+
} finally {
|
|
2975
|
+
URL.revokeObjectURL(objectUrl);
|
|
2976
|
+
}
|
|
2977
|
+
}
|
|
2978
|
+
const arrayBuffer = typeof blob.arrayBuffer === "function" ? await blob.arrayBuffer() : await new Response(blob).arrayBuffer();
|
|
2979
|
+
return new Promise((resolve, reject) => {
|
|
2980
|
+
const loader = new GLTFLoader();
|
|
2981
|
+
loader.setDRACOLoader(new DRACOLoader());
|
|
2982
|
+
loader.parse(
|
|
2983
|
+
arrayBuffer,
|
|
2984
|
+
"",
|
|
2985
|
+
(gltf) => {
|
|
2986
|
+
try {
|
|
2987
|
+
const asset = parseScene(
|
|
2988
|
+
gltf.scene,
|
|
2989
|
+
actualizedNamespaces,
|
|
2990
|
+
aggressiveImport,
|
|
2991
|
+
rootBounds,
|
|
2992
|
+
gltf?.parser?.json
|
|
2993
|
+
);
|
|
2994
|
+
resolve(asset);
|
|
2629
2995
|
} catch (error) {
|
|
2630
2996
|
if (error instanceof Error) {
|
|
2631
2997
|
reject(error);
|
|
@@ -2674,36 +3040,62 @@ var loadGltfFromBlob = (blob, namespaces) => {
|
|
|
2674
3040
|
import { GLTFExporter } from "three-stdlib";
|
|
2675
3041
|
import * as THREE6 from "three";
|
|
2676
3042
|
THREE6.Object3D.DEFAULT_UP.set(0, 0, 1);
|
|
2677
|
-
function exportScene(data,
|
|
3043
|
+
function exportScene(data, fileNameOrOptions = "scene.glb") {
|
|
3044
|
+
const options = typeof fileNameOrOptions === "string" ? { fileName: fileNameOrOptions } : fileNameOrOptions ?? {};
|
|
3045
|
+
const fileName = options.fileName ?? "scene.glb";
|
|
3046
|
+
const animationClips = Array.isArray(options.animations) ? options.animations.filter(Boolean) : [];
|
|
3047
|
+
const shouldAttachBundle = Boolean(options.bundle);
|
|
2678
3048
|
const exporter = new GLTFExporter();
|
|
2679
|
-
exporter.
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
if (
|
|
2683
|
-
|
|
2684
|
-
}
|
|
2685
|
-
const link = document.createElement("a");
|
|
2686
|
-
link.href = URL.createObjectURL(
|
|
2687
|
-
new Blob([gltf], {
|
|
2688
|
-
type: "application/octet-stream"
|
|
2689
|
-
})
|
|
2690
|
-
);
|
|
2691
|
-
const trimmed = fileName.trim();
|
|
2692
|
-
const safeFileName = trimmed.length > 0 ? trimmed : "scene.glb";
|
|
2693
|
-
const downloadName = safeFileName.toLowerCase().endsWith(".glb") ? safeFileName : `${safeFileName}.glb`;
|
|
2694
|
-
link.download = downloadName;
|
|
2695
|
-
link.click();
|
|
2696
|
-
URL.revokeObjectURL(link.href);
|
|
2697
|
-
},
|
|
2698
|
-
() => {
|
|
2699
|
-
},
|
|
2700
|
-
{
|
|
2701
|
-
trs: true,
|
|
2702
|
-
onlyVisible: false,
|
|
2703
|
-
binary: true,
|
|
2704
|
-
includeCustomExtensions: true
|
|
3049
|
+
exporter.register(() => ({
|
|
3050
|
+
writeMesh(mesh, meshDef) {
|
|
3051
|
+
const meshName = mesh.name?.trim() || mesh.geometry?.name?.trim() || void 0;
|
|
3052
|
+
if (meshName) {
|
|
3053
|
+
meshDef.name = meshName;
|
|
3054
|
+
}
|
|
2705
3055
|
}
|
|
2706
|
-
);
|
|
3056
|
+
}));
|
|
3057
|
+
const detachBundle = shouldAttachBundle && options.bundle ? applyVizijBundle(data, options.bundle) : () => {
|
|
3058
|
+
};
|
|
3059
|
+
const binary = options.binary ?? true;
|
|
3060
|
+
const exporterOptions = {
|
|
3061
|
+
trs: true,
|
|
3062
|
+
onlyVisible: false,
|
|
3063
|
+
binary,
|
|
3064
|
+
includeCustomExtensions: true
|
|
3065
|
+
};
|
|
3066
|
+
if (animationClips.length > 0) {
|
|
3067
|
+
exporterOptions.animations = animationClips;
|
|
3068
|
+
}
|
|
3069
|
+
try {
|
|
3070
|
+
exporter.parse(
|
|
3071
|
+
data,
|
|
3072
|
+
(gltf) => {
|
|
3073
|
+
detachBundle();
|
|
3074
|
+
if (!(gltf instanceof ArrayBuffer)) {
|
|
3075
|
+
throw new Error("Failed to export scene!");
|
|
3076
|
+
}
|
|
3077
|
+
const link = document.createElement("a");
|
|
3078
|
+
link.href = URL.createObjectURL(
|
|
3079
|
+
new Blob([gltf], {
|
|
3080
|
+
type: "application/octet-stream"
|
|
3081
|
+
})
|
|
3082
|
+
);
|
|
3083
|
+
const trimmed = fileName.trim();
|
|
3084
|
+
const safeFileName = trimmed.length > 0 ? trimmed : "scene.glb";
|
|
3085
|
+
const downloadName = safeFileName.toLowerCase().endsWith(".glb") ? safeFileName : `${safeFileName}.glb`;
|
|
3086
|
+
link.download = downloadName;
|
|
3087
|
+
link.click();
|
|
3088
|
+
URL.revokeObjectURL(link.href);
|
|
3089
|
+
},
|
|
3090
|
+
() => {
|
|
3091
|
+
detachBundle();
|
|
3092
|
+
},
|
|
3093
|
+
exporterOptions
|
|
3094
|
+
);
|
|
3095
|
+
} catch (error) {
|
|
3096
|
+
detachBundle();
|
|
3097
|
+
throw error;
|
|
3098
|
+
}
|
|
2707
3099
|
}
|
|
2708
3100
|
export {
|
|
2709
3101
|
Controller,
|
|
@@ -2713,10 +3105,14 @@ export {
|
|
|
2713
3105
|
Vizij,
|
|
2714
3106
|
VizijContext,
|
|
2715
3107
|
VizijSlice,
|
|
3108
|
+
applyVizijBundle,
|
|
2716
3109
|
createVizijStore,
|
|
2717
3110
|
exportScene,
|
|
3111
|
+
extractVizijBundle,
|
|
2718
3112
|
loadGLTF,
|
|
2719
3113
|
loadGLTFFromBlob,
|
|
3114
|
+
loadGLTFFromBlobWithBundle,
|
|
3115
|
+
loadGLTFWithBundle,
|
|
2720
3116
|
loadGltfFromBlob,
|
|
2721
3117
|
useDefaultVizijStore,
|
|
2722
3118
|
useFeatures,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vizij/render",
|
|
3
3
|
"description": "Higher-level visualization and interaction components for robot and ai faces.",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.3",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"lint:fix": "pnpm --filter \"$npm_package_name\" exec eslint --ext .js,.jsx,.ts,.tsx --fix -- .",
|
|
32
32
|
"prettier:check": "prettier --check .",
|
|
33
33
|
"prettier:write": "prettier --write .",
|
|
34
|
-
"test": "
|
|
34
|
+
"test": "node --loader ./tests/node-ts-loader.mjs --test tests/*.node-test.mjs",
|
|
35
35
|
"clean": "rm -rf dist .turbo coverage tsconfig.tsbuildinfo",
|
|
36
36
|
"reset": "rm -rf node_modules",
|
|
37
37
|
"reset:hard": "pnpm run reset && rm -f pnpm-lock.yaml package-lock.json yarn.lock",
|
|
@@ -72,8 +72,7 @@
|
|
|
72
72
|
"zustand": "^5.0.2",
|
|
73
73
|
"tsup": "^8.0.1",
|
|
74
74
|
"typescript": "^5.5.0",
|
|
75
|
-
"prettier": "^3.4.2"
|
|
76
|
-
"vitest": "^3.2.4"
|
|
75
|
+
"prettier": "^3.4.2"
|
|
77
76
|
},
|
|
78
77
|
"size-limit": [
|
|
79
78
|
{
|