@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/dist/index.js CHANGED
@@ -37,10 +37,14 @@ __export(index_exports, {
37
37
  Vizij: () => Vizij,
38
38
  VizijContext: () => VizijContext,
39
39
  VizijSlice: () => VizijSlice,
40
+ applyVizijBundle: () => applyVizijBundle,
40
41
  createVizijStore: () => createVizijStore,
41
42
  exportScene: () => exportScene,
43
+ extractVizijBundle: () => extractVizijBundle,
42
44
  loadGLTF: () => loadGLTF,
43
45
  loadGLTFFromBlob: () => loadGLTFFromBlob,
46
+ loadGLTFFromBlobWithBundle: () => loadGLTFFromBlobWithBundle,
47
+ loadGLTFWithBundle: () => loadGLTFWithBundle,
44
48
  loadGltfFromBlob: () => loadGltfFromBlob,
45
49
  useDefaultVizijStore: () => useDefaultVizijStore,
46
50
  useFeatures: () => useFeatures,
@@ -428,6 +432,11 @@ function InnerRenderedGroup({
428
432
  setReference(group.id, namespace, ref);
429
433
  }
430
434
  }, [group.id, namespace, ref, setReference, refIsNull]);
435
+ (0, import_react5.useEffect)(() => {
436
+ if (ref.current) {
437
+ ref.current.name = group.name;
438
+ }
439
+ }, [group.name]);
431
440
  const handlePointerOver = (0, import_react5.useCallback)(
432
441
  (event) => {
433
442
  if (event.eventObject !== event.object) {
@@ -579,6 +588,9 @@ function InnerRenderedEllipse({
579
588
  if ((0, import_utils4.instanceOfRawRGB)(color)) {
580
589
  materialRef.current.color.setRGB(color.r, color.g, color.b);
581
590
  materialRef.current.needsUpdate = true;
591
+ } else if ((0, import_utils4.instanceOfRawVector3)(color)) {
592
+ materialRef.current.color.setRGB(color.x, color.y, color.z);
593
+ materialRef.current.needsUpdate = true;
582
594
  } else if ((0, import_utils4.instanceOfRawHSL)(color)) {
583
595
  materialRef.current.color.setHSL(color.h, color.s, color.l);
584
596
  materialRef.current.needsUpdate = true;
@@ -631,6 +643,13 @@ function InnerRenderedEllipse({
631
643
  strokeColor.b
632
644
  );
633
645
  lineRef.current.material.needsUpdate = true;
646
+ } else if ((0, import_utils4.instanceOfRawVector3)(strokeColor)) {
647
+ lineRef.current.material.color.setRGB(
648
+ strokeColor.x,
649
+ strokeColor.y,
650
+ strokeColor.z
651
+ );
652
+ lineRef.current.material.needsUpdate = true;
634
653
  } else if ((0, import_utils4.instanceOfRawHSL)(strokeColor)) {
635
654
  lineRef.current.material.color.setHSL(
636
655
  strokeColor.h,
@@ -854,6 +873,9 @@ function InnerRenderedRectangle({
854
873
  if ((0, import_utils5.instanceOfRawRGB)(color)) {
855
874
  materialRef.current.color.setRGB(color.r, color.g, color.b);
856
875
  materialRef.current.needsUpdate = true;
876
+ } else if ((0, import_utils5.instanceOfRawVector3)(color)) {
877
+ materialRef.current.color.setRGB(color.x, color.y, color.z);
878
+ materialRef.current.needsUpdate = true;
857
879
  } else if ((0, import_utils5.instanceOfRawHSL)(color)) {
858
880
  materialRef.current.color.setHSL(color.h, color.s, color.l);
859
881
  materialRef.current.needsUpdate = true;
@@ -906,6 +928,13 @@ function InnerRenderedRectangle({
906
928
  strokeColor.b
907
929
  );
908
930
  lineRef.current.material.needsUpdate = true;
931
+ } else if ((0, import_utils5.instanceOfRawVector3)(strokeColor)) {
932
+ lineRef.current.material.color.setRGB(
933
+ strokeColor.x,
934
+ strokeColor.y,
935
+ strokeColor.z
936
+ );
937
+ lineRef.current.material.needsUpdate = true;
909
938
  } else if ((0, import_utils5.instanceOfRawHSL)(strokeColor)) {
910
939
  lineRef.current.material.color.setHSL(
911
940
  strokeColor.h,
@@ -1049,7 +1078,17 @@ function InnerRenderedShape({
1049
1078
  });
1050
1079
  return av;
1051
1080
  }, [shape.features, animatables]);
1052
- const geometry = (0, import_react8.useMemo)(() => shape.geometry.clone(), [shape.geometry]);
1081
+ const materialName = (0, import_react8.useMemo)(
1082
+ () => deriveMaterialName(shape, animatableValues),
1083
+ [shape, animatableValues]
1084
+ );
1085
+ const geometry = (0, import_react8.useMemo)(() => {
1086
+ const cloned = shape.geometry.clone();
1087
+ if (shape.name) {
1088
+ cloned.name = shape.name;
1089
+ }
1090
+ return cloned;
1091
+ }, [shape.geometry, shape.name]);
1053
1092
  const selectionData = (0, import_react8.useMemo)(
1054
1093
  () => ({ id, namespace, type: "shape" }),
1055
1094
  [id, namespace]
@@ -1139,9 +1178,14 @@ function InnerRenderedShape({
1139
1178
  color.g,
1140
1179
  color.b
1141
1180
  );
1142
- if ((material.current || void 0)?.color) {
1143
- material.current.needsUpdate = true;
1144
- }
1181
+ material.current.needsUpdate = true;
1182
+ } else if ((material.current || void 0)?.color && (0, import_utils6.instanceOfRawVector3)(color)) {
1183
+ material.current.color.setRGB(
1184
+ color.x,
1185
+ color.y,
1186
+ color.z
1187
+ );
1188
+ material.current.needsUpdate = true;
1145
1189
  } else if (material.current && (0, import_utils6.instanceOfRawHSL)(color)) {
1146
1190
  material.current.color.setHSL(
1147
1191
  color.h,
@@ -1164,6 +1208,21 @@ function InnerRenderedShape({
1164
1208
  (0, import_react8.useEffect)(() => {
1165
1209
  if (ref.current && refIsNull) setReference(shape.id, namespace, ref);
1166
1210
  }, [shape.id, namespace, ref, setReference, refIsNull]);
1211
+ (0, import_react8.useEffect)(() => {
1212
+ if (ref.current) {
1213
+ ref.current.name = shape.name;
1214
+ }
1215
+ }, [shape.name]);
1216
+ (0, import_react8.useEffect)(() => {
1217
+ if (!material.current) {
1218
+ return;
1219
+ }
1220
+ if (materialName) {
1221
+ material.current.name = materialName;
1222
+ } else if (shape.name) {
1223
+ material.current.name = shape.name;
1224
+ }
1225
+ }, [materialName, shape.name]);
1167
1226
  const handlePointerOver = (0, import_react8.useCallback)(
1168
1227
  (event) => {
1169
1228
  event.stopPropagation();
@@ -1250,6 +1309,51 @@ function InnerRenderedShape({
1250
1309
  );
1251
1310
  }
1252
1311
  var RenderedShape = (0, import_react8.memo)(InnerRenderedShape);
1312
+ var MATERIAL_FEATURE_KEYS = [
1313
+ "color",
1314
+ "opacity",
1315
+ "roughness",
1316
+ "metalness",
1317
+ "shininess"
1318
+ ];
1319
+ var MATERIAL_NAME_SUFFIXES = [
1320
+ " color",
1321
+ " colours",
1322
+ " colour",
1323
+ " opacity",
1324
+ " roughness",
1325
+ " metalness",
1326
+ " shininess"
1327
+ ];
1328
+ function deriveMaterialName(shape, values) {
1329
+ for (const key of MATERIAL_FEATURE_KEYS) {
1330
+ const feature = shape.features[key];
1331
+ if (feature && feature.animated) {
1332
+ const animatable = values[feature.value];
1333
+ const candidate = extractMaterialName(animatable?.name);
1334
+ if (candidate) {
1335
+ return candidate;
1336
+ }
1337
+ }
1338
+ }
1339
+ return void 0;
1340
+ }
1341
+ function extractMaterialName(name) {
1342
+ if (!name) {
1343
+ return void 0;
1344
+ }
1345
+ const trimmed = name.trim();
1346
+ if (!trimmed) {
1347
+ return void 0;
1348
+ }
1349
+ const lowered = trimmed.toLowerCase();
1350
+ for (const suffix of MATERIAL_NAME_SUFFIXES) {
1351
+ if (lowered.endsWith(suffix)) {
1352
+ return trimmed.slice(0, trimmed.length - suffix.length).trim();
1353
+ }
1354
+ }
1355
+ return trimmed;
1356
+ }
1253
1357
 
1254
1358
  // src/renderables/renderable.tsx
1255
1359
  var import_jsx_runtime6 = require("react/jsx-runtime");
@@ -2421,9 +2525,12 @@ function traverseThree(group, namespaces, aggressiveImport = false, rootBounds)
2421
2525
  });
2422
2526
  const useRobotData = !aggressiveImport || hasRobotData;
2423
2527
  if (useRobotData) {
2424
- group.traverse((child) => {
2528
+ const stack = [group];
2529
+ while (stack.length > 0) {
2530
+ const child = stack.pop();
2425
2531
  if (child.userData?.gltfExtensions?.RobotData) {
2426
2532
  const data = child.userData.gltfExtensions.RobotData;
2533
+ applyStoredRenderableNames(child, data);
2427
2534
  let loadedData;
2428
2535
  let mappedFeatures;
2429
2536
  let animatableValues;
@@ -2489,7 +2596,10 @@ function traverseThree(group, namespaces, aggressiveImport = false, rootBounds)
2489
2596
  throw new Error(`Unhandled type`);
2490
2597
  }
2491
2598
  }
2492
- });
2599
+ if (child.children) {
2600
+ stack.push(...child.children);
2601
+ }
2602
+ }
2493
2603
  } else {
2494
2604
  const derivedRootBounds = rootBounds ?? deriveRootBounds(group);
2495
2605
  if (!derivedRootBounds) {
@@ -2505,6 +2615,94 @@ function traverseThree(group, namespaces, aggressiveImport = false, rootBounds)
2505
2615
  }
2506
2616
  return [worldData, animatableData];
2507
2617
  }
2618
+ var MATERIAL_NAME_FEATURE_KEYS = [
2619
+ "color",
2620
+ "opacity",
2621
+ "roughness",
2622
+ "metalness",
2623
+ "shininess"
2624
+ ];
2625
+ var MATERIAL_NAME_SUFFIXES2 = [
2626
+ " color",
2627
+ " colours",
2628
+ " colour",
2629
+ " opacity",
2630
+ " roughness",
2631
+ " metalness",
2632
+ " shininess"
2633
+ ];
2634
+ function applyStoredRenderableNames(object, data) {
2635
+ if (typeof data.name === "string" && data.name.length > 0) {
2636
+ object.name = data.name;
2637
+ }
2638
+ if (object.isGroup) {
2639
+ const group = object;
2640
+ if (typeof data.name === "string" && data.name.length > 0) {
2641
+ group.name = data.name;
2642
+ }
2643
+ }
2644
+ if (object.isMesh) {
2645
+ const mesh = object;
2646
+ if (typeof data.name === "string" && data.name.length > 0) {
2647
+ mesh.name = data.name;
2648
+ if (mesh.geometry) {
2649
+ mesh.geometry.name = data.name;
2650
+ }
2651
+ }
2652
+ const inferredName = inferMaterialNameFromStoredRenderable(data);
2653
+ if (inferredName) {
2654
+ assignMaterialName(mesh.material, inferredName);
2655
+ }
2656
+ }
2657
+ }
2658
+ function assignMaterialName(material, name) {
2659
+ if (!material) {
2660
+ return;
2661
+ }
2662
+ if (Array.isArray(material)) {
2663
+ material.forEach((mat) => {
2664
+ mat.name = name;
2665
+ });
2666
+ } else {
2667
+ material.name = name;
2668
+ }
2669
+ }
2670
+ function inferMaterialNameFromStoredRenderable(data) {
2671
+ if (data.type !== "shape") {
2672
+ return void 0;
2673
+ }
2674
+ const features = data.features;
2675
+ for (const key of MATERIAL_NAME_FEATURE_KEYS) {
2676
+ const candidate = extractMaterialNameFromFeature(features[key]);
2677
+ if (candidate) {
2678
+ return candidate;
2679
+ }
2680
+ }
2681
+ return void 0;
2682
+ }
2683
+ function extractMaterialNameFromFeature(feature) {
2684
+ if (!isStoredAnimatedFeature(feature)) {
2685
+ return void 0;
2686
+ }
2687
+ const animatableName = feature.value.name;
2688
+ if (!animatableName) {
2689
+ return void 0;
2690
+ }
2691
+ return stripMaterialSuffixes(animatableName);
2692
+ }
2693
+ function stripMaterialSuffixes(name) {
2694
+ const trimmed = name.trim();
2695
+ const lowered = trimmed.toLowerCase();
2696
+ for (const suffix of MATERIAL_NAME_SUFFIXES2) {
2697
+ if (lowered.endsWith(suffix)) {
2698
+ return trimmed.slice(0, trimmed.length - suffix.length).trim();
2699
+ }
2700
+ }
2701
+ return trimmed;
2702
+ }
2703
+ function isStoredAnimatedFeature(feature) {
2704
+ return Boolean(feature) && typeof feature === "object" && feature.animated === true && "value" in feature;
2705
+ }
2508
2706
  function isGroupFeatures(value) {
2509
2707
  if (!value || typeof value !== "object") {
2510
2708
  throw new Error("Expected object");
@@ -2569,6 +2767,106 @@ function deriveRootBounds(group) {
2569
2767
  };
2570
2768
  }
2571
2769
 
2770
+ // src/functions/vizij-bundle.ts
2771
+ var BUNDLE_KEYS = ["VIZIJ_bundle"];
2772
+ function cloneBundle(value) {
2773
+ return JSON.parse(JSON.stringify(value));
2774
+ }
2775
+ function readExtensionValue(extensionContainer) {
2776
+ for (const key of BUNDLE_KEYS) {
2777
+ if (extensionContainer && Object.prototype.hasOwnProperty.call(extensionContainer, key)) {
2778
+ const value = extensionContainer[key];
2779
+ if (value && typeof value === "object") {
2780
+ return { key, value };
2781
+ }
2782
+ }
2783
+ }
2784
+ return null;
2785
+ }
2786
+ function searchObjectForBundle(object) {
2787
+ const stack = [object];
2788
+ while (stack.length > 0) {
2789
+ const current = stack.pop();
2790
+ const extensions = current?.userData?.gltfExtensions ?? current?.userData?.extensions ?? null;
2791
+ if (extensions && typeof extensions === "object") {
2792
+ const match = readExtensionValue(extensions);
2793
+ if (match) {
2794
+ return cloneBundle(match.value);
2795
+ }
2796
+ }
2797
+ if (current.children && current.children.length > 0) {
2798
+ stack.push(...current.children);
2799
+ }
2800
+ }
2801
+ return null;
2802
+ }
2803
+ function searchParserJsonForBundle(parserJson) {
2804
+ if (!parserJson || typeof parserJson !== "object") {
2805
+ return null;
2806
+ }
2807
+ const nodes = Array.isArray(parserJson.nodes) ? parserJson.nodes : [];
2808
+ for (const node of nodes) {
2809
+ const extensions = node && typeof node === "object" ? node.extensions : null;
2810
+ if (extensions && typeof extensions === "object") {
2811
+ const match = readExtensionValue(extensions);
2812
+ if (match) {
2813
+ return cloneBundle(match.value);
2814
+ }
2815
+ }
2816
+ }
2817
+ const scenes = Array.isArray(parserJson.scenes) ? parserJson.scenes : [];
2818
+ for (const scene of scenes) {
2819
+ const extensions = scene && typeof scene === "object" ? scene.extensions : null;
2820
+ if (extensions && typeof extensions === "object") {
2821
+ const match = readExtensionValue(extensions);
2822
+ if (match) {
2823
+ return cloneBundle(match.value);
2824
+ }
2825
+ }
2826
+ }
2827
+ return null;
2828
+ }
2829
+ function extractVizijBundle(object, parserJson) {
2830
+ const fromObject = searchObjectForBundle(object);
2831
+ if (fromObject) {
2832
+ return fromObject;
2833
+ }
2834
+ const fromParser = searchParserJsonForBundle(parserJson);
2835
+ if (fromParser) {
2836
+ return fromParser;
2837
+ }
2838
+ return null;
2839
+ }
2840
+ function applyVizijBundle(object, bundle) {
2841
+ const userData = object.userData && typeof object.userData === "object" ? object.userData : {};
2842
+ const originalExtensions = userData.gltfExtensions;
2843
+ let applied = false;
2844
+ if (bundle) {
2845
+ userData.gltfExtensions = {
2846
+ ...originalExtensions ?? {},
2847
+ VIZIJ_bundle: bundle
2848
+ };
2849
+ object.userData = userData;
2850
+ applied = true;
2851
+ }
2852
+ return () => {
2853
+ if (!applied) {
2854
+ return;
2855
+ }
2856
+ if (originalExtensions) {
2857
+ userData.gltfExtensions = originalExtensions;
2858
+ } else {
2859
+ if (userData.gltfExtensions) {
2860
+ delete userData.gltfExtensions;
2861
+ }
2862
+ if (Object.keys(userData).length === 0) {
2863
+ delete object.userData;
2864
+ }
2865
+ }
2866
+ applied = false;
2867
+ };
2868
+ }
2869
+
2572
2870
  // src/functions/load-gltf.ts
2573
2871
  THREE5.Object3D.DEFAULT_UP.set(0, 0, 1);
2574
2872
  var EmptyModelError = class extends Error {
@@ -2582,24 +2880,27 @@ async function loadGLTF(url, namespaces, aggressiveImport = false, rootBounds) {
2582
2880
  modelLoader.setDRACOLoader(new import_three_stdlib.DRACOLoader());
2583
2881
  const modelData = await modelLoader.loadAsync(url);
2584
2882
  const actualizedNamespaces = namespaces.length > 0 ? namespaces : ["default"];
2585
- return traverseThree(
2883
+ const asset = parseScene(
2586
2884
  modelData.scene,
2587
2885
  actualizedNamespaces,
2588
2886
  aggressiveImport,
2589
- rootBounds
2887
+ rootBounds,
2888
+ modelData?.parser?.json
2590
2889
  );
2890
+ return [asset.world, asset.animatables];
2591
2891
  }
2592
2892
  async function loadGLTFFromBlob(blob, namespaces, aggressiveImport = false, rootBounds) {
2593
2893
  const actualizedNamespaces = namespaces.length > 0 ? namespaces : ["default"];
2594
2894
  if (typeof URL !== "undefined" && typeof URL.createObjectURL === "function") {
2595
2895
  const objectUrl = URL.createObjectURL(blob);
2596
2896
  try {
2597
- return await loadGLTF(
2897
+ const asset = await loadGLTFWithBundle(
2598
2898
  objectUrl,
2599
2899
  actualizedNamespaces,
2600
2900
  aggressiveImport,
2601
2901
  rootBounds
2602
2902
  );
2903
+ return [asset.world, asset.animatables];
2603
2904
  } finally {
2604
2905
  URL.revokeObjectURL(objectUrl);
2605
2906
  }
@@ -2613,14 +2914,83 @@ async function loadGLTFFromBlob(blob, namespaces, aggressiveImport = false, root
2613
2914
  "",
2614
2915
  (gltf) => {
2615
2916
  try {
2616
- resolve(
2617
- traverseThree(
2618
- gltf.scene,
2619
- actualizedNamespaces,
2620
- aggressiveImport,
2621
- rootBounds
2622
- )
2917
+ const asset = parseScene(
2918
+ gltf.scene,
2919
+ actualizedNamespaces,
2920
+ aggressiveImport,
2921
+ rootBounds,
2922
+ gltf?.parser?.json
2623
2923
  );
2924
+ resolve([asset.world, asset.animatables]);
2925
+ } catch (error) {
2926
+ if (error instanceof Error) {
2927
+ reject(error);
2928
+ } else {
2929
+ reject(new Error(String(error)));
2930
+ }
2931
+ }
2932
+ },
2933
+ (error) => {
2934
+ reject(new Error(`Error loading GLTF: ${error.message}`));
2935
+ }
2936
+ );
2937
+ });
2938
+ }
2939
+ function parseScene(scene, namespaces, aggressiveImport, rootBounds, parserJson) {
2940
+ const [world, animatables] = traverseThree(
2941
+ scene,
2942
+ namespaces,
2943
+ aggressiveImport,
2944
+ rootBounds
2945
+ );
2946
+ const bundle = extractVizijBundle(scene, parserJson);
2947
+ return { world, animatables, bundle };
2948
+ }
2949
+ async function loadGLTFWithBundle(url, namespaces, aggressiveImport = false, rootBounds) {
2950
+ const modelLoader = new import_three_stdlib.GLTFLoader();
2951
+ modelLoader.setDRACOLoader(new import_three_stdlib.DRACOLoader());
2952
+ const modelData = await modelLoader.loadAsync(url);
2953
+ const actualizedNamespaces = namespaces.length > 0 ? namespaces : ["default"];
2954
+ return parseScene(
2955
+ modelData.scene,
2956
+ actualizedNamespaces,
2957
+ aggressiveImport,
2958
+ rootBounds,
2959
+ modelData?.parser?.json
2960
+ );
2961
+ }
2962
+ async function loadGLTFFromBlobWithBundle(blob, namespaces, aggressiveImport = false, rootBounds) {
2963
+ const actualizedNamespaces = namespaces.length > 0 ? namespaces : ["default"];
2964
+ if (typeof URL !== "undefined" && typeof URL.createObjectURL === "function") {
2965
+ const objectUrl = URL.createObjectURL(blob);
2966
+ try {
2967
+ return await loadGLTFWithBundle(
2968
+ objectUrl,
2969
+ actualizedNamespaces,
2970
+ aggressiveImport,
2971
+ rootBounds
2972
+ );
2973
+ } finally {
2974
+ URL.revokeObjectURL(objectUrl);
2975
+ }
2976
+ }
2977
+ const arrayBuffer = typeof blob.arrayBuffer === "function" ? await blob.arrayBuffer() : await new Response(blob).arrayBuffer();
2978
+ return new Promise((resolve, reject) => {
2979
+ const loader = new import_three_stdlib.GLTFLoader();
2980
+ loader.setDRACOLoader(new import_three_stdlib.DRACOLoader());
2981
+ loader.parse(
2982
+ arrayBuffer,
2983
+ "",
2984
+ (gltf) => {
2985
+ try {
2986
+ const asset = parseScene(
2987
+ gltf.scene,
2988
+ actualizedNamespaces,
2989
+ aggressiveImport,
2990
+ rootBounds,
2991
+ gltf?.parser?.json
2992
+ );
2993
+ resolve(asset);
2624
2994
  } catch (error) {
2625
2995
  if (error instanceof Error) {
2626
2996
  reject(error);
@@ -2669,36 +3039,62 @@ var loadGltfFromBlob = (blob, namespaces) => {
2669
3039
  var import_three_stdlib3 = require("three-stdlib");
2670
3040
  var THREE6 = __toESM(require("three"));
2671
3041
  THREE6.Object3D.DEFAULT_UP.set(0, 0, 1);
2672
- function exportScene(data, fileName = "scene.glb") {
3042
+ function exportScene(data, fileNameOrOptions = "scene.glb") {
3043
+ const options = typeof fileNameOrOptions === "string" ? { fileName: fileNameOrOptions } : fileNameOrOptions ?? {};
3044
+ const fileName = options.fileName ?? "scene.glb";
3045
+ const animationClips = Array.isArray(options.animations) ? options.animations.filter(Boolean) : [];
3046
+ const shouldAttachBundle = Boolean(options.bundle);
2673
3047
  const exporter = new import_three_stdlib3.GLTFExporter();
2674
- exporter.parse(
2675
- data,
2676
- (gltf) => {
2677
- if (!(gltf instanceof ArrayBuffer)) {
2678
- throw new Error("Failed to export scene!");
2679
- }
2680
- const link = document.createElement("a");
2681
- link.href = URL.createObjectURL(
2682
- new Blob([gltf], {
2683
- type: "application/octet-stream"
2684
- })
2685
- );
2686
- const trimmed = fileName.trim();
2687
- const safeFileName = trimmed.length > 0 ? trimmed : "scene.glb";
2688
- const downloadName = safeFileName.toLowerCase().endsWith(".glb") ? safeFileName : `${safeFileName}.glb`;
2689
- link.download = downloadName;
2690
- link.click();
2691
- URL.revokeObjectURL(link.href);
2692
- },
2693
- () => {
2694
- },
2695
- {
2696
- trs: true,
2697
- onlyVisible: false,
2698
- binary: true,
2699
- includeCustomExtensions: true
3048
+ exporter.register(() => ({
3049
+ writeMesh(mesh, meshDef) {
3050
+ const meshName = mesh.name?.trim() || mesh.geometry?.name?.trim() || void 0;
3051
+ if (meshName) {
3052
+ meshDef.name = meshName;
3053
+ }
2700
3054
  }
2701
- );
3055
+ }));
3056
+ const detachBundle = shouldAttachBundle && options.bundle ? applyVizijBundle(data, options.bundle) : () => {
3057
+ };
3058
+ const binary = options.binary ?? true;
3059
+ const exporterOptions = {
3060
+ trs: true,
3061
+ onlyVisible: false,
3062
+ binary,
3063
+ includeCustomExtensions: true
3064
+ };
3065
+ if (animationClips.length > 0) {
3066
+ exporterOptions.animations = animationClips;
3067
+ }
3068
+ try {
3069
+ exporter.parse(
3070
+ data,
3071
+ (gltf) => {
3072
+ detachBundle();
3073
+ if (!(gltf instanceof ArrayBuffer)) {
3074
+ throw new Error("Failed to export scene!");
3075
+ }
3076
+ const link = document.createElement("a");
3077
+ link.href = URL.createObjectURL(
3078
+ new Blob([gltf], {
3079
+ type: "application/octet-stream"
3080
+ })
3081
+ );
3082
+ const trimmed = fileName.trim();
3083
+ const safeFileName = trimmed.length > 0 ? trimmed : "scene.glb";
3084
+ const downloadName = safeFileName.toLowerCase().endsWith(".glb") ? safeFileName : `${safeFileName}.glb`;
3085
+ link.download = downloadName;
3086
+ link.click();
3087
+ URL.revokeObjectURL(link.href);
3088
+ },
3089
+ () => {
3090
+ detachBundle();
3091
+ },
3092
+ exporterOptions
3093
+ );
3094
+ } catch (error) {
3095
+ detachBundle();
3096
+ throw error;
3097
+ }
2702
3098
  }
2703
3099
  // Annotate the CommonJS export names for ESM import in node:
2704
3100
  0 && (module.exports = {
@@ -2709,10 +3105,14 @@ function exportScene(data, fileName = "scene.glb") {
2709
3105
  Vizij,
2710
3106
  VizijContext,
2711
3107
  VizijSlice,
3108
+ applyVizijBundle,
2712
3109
  createVizijStore,
2713
3110
  exportScene,
3111
+ extractVizijBundle,
2714
3112
  loadGLTF,
2715
3113
  loadGLTFFromBlob,
3114
+ loadGLTFFromBlobWithBundle,
3115
+ loadGLTFWithBundle,
2716
3116
  loadGltfFromBlob,
2717
3117
  useDefaultVizijStore,
2718
3118
  useFeatures,