@vizij/render 0.1.1 → 1.0.0

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
@@ -30,22 +30,33 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.tsx
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ DEFAULT_TONE_MAPPING_MODE: () => DEFAULT_TONE_MAPPING_MODE,
33
34
  EmptyModelError: () => EmptyModelError,
34
35
  InnerVizij: () => InnerVizij,
35
36
  ShapeMaterial: () => ShapeMaterial,
37
+ TONE_MAPPING_LABELS: () => TONE_MAPPING_LABELS,
38
+ TONE_MAPPING_MODES: () => TONE_MAPPING_MODES,
36
39
  Vizij: () => Vizij,
37
40
  VizijContext: () => VizijContext,
38
41
  VizijSlice: () => VizijSlice,
39
42
  applyVizijBundle: () => applyVizijBundle,
43
+ buildSceneGraph: () => buildSceneGraph,
40
44
  createVizijStore: () => createVizijStore,
45
+ deriveMorphFeatureKeys: () => deriveMorphFeatureKeys,
46
+ deriveRootBounds: () => deriveRootBounds,
41
47
  exportScene: () => exportScene,
42
48
  extractVizijBundle: () => extractVizijBundle,
49
+ isToneMappingMode: () => isToneMappingMode,
43
50
  loadGLTF: () => loadGLTF,
44
51
  loadGLTFFromBlob: () => loadGLTFFromBlob,
45
52
  loadGLTFFromBlobWithBundle: () => loadGLTFFromBlobWithBundle,
46
53
  loadGLTFWithBundle: () => loadGLTFWithBundle,
47
- loadGltfFromBlob: () => loadGltfFromBlob,
54
+ normalizeToneMappingMode: () => normalizeToneMappingMode,
48
55
  parseGlbJsonChunk: () => parseGlbJsonChunk,
56
+ patchGlbJson: () => patchGlbJson,
57
+ patchVizijBundleMetadata: () => patchVizijBundleMetadata,
58
+ resolveToneMapping: () => resolveToneMapping,
59
+ sanitizeMorphKey: () => sanitizeMorphKey,
49
60
  useDefaultVizijStore: () => useDefaultVizijStore,
50
61
  useFeatures: () => useFeatures,
51
62
  useVizijStore: () => useVizijStore,
@@ -56,9 +67,9 @@ __export(index_exports, {
56
67
  module.exports = __toCommonJS(index_exports);
57
68
 
58
69
  // src/vizij.tsx
59
- var import_react11 = require("react");
70
+ var import_react10 = require("react");
60
71
  var import_react_error_boundary = require("react-error-boundary");
61
- var import_three2 = require("three");
72
+ var import_three3 = require("three");
62
73
  var import_fiber2 = require("@react-three/fiber");
63
74
  var import_drei3 = require("@react-three/drei");
64
75
  var import_shallow8 = require("zustand/react/shallow");
@@ -136,35 +147,33 @@ function useFeatures(namespace, features, callbacks, debugInfo) {
136
147
  }, [features, callbacks, store, debugInfo, namespace]);
137
148
  }
138
149
 
139
- // src/functions/create-stored-data.ts
140
- var import_lodash2 = require("lodash");
141
-
142
150
  // src/functions/create-stored-features.ts
143
- var import_lodash = require("lodash");
144
151
  function createStoredFeatures(objectFeatures, animatableValues) {
145
- return (0, import_lodash.mapValues)(objectFeatures, (feat) => {
146
- if (feat.animated) {
147
- const storedFeat = {
148
- animated: true,
149
- value: animatableValues[feat.value],
150
- ...feat.label ? { label: feat.label } : {}
151
- };
152
- return storedFeat;
153
- } else {
152
+ const stored = Object.entries(objectFeatures).map(
153
+ ([key, feat]) => {
154
+ if (feat.animated) {
155
+ const storedFeat = {
156
+ animated: true,
157
+ value: animatableValues[feat.value],
158
+ ...feat.label ? { label: feat.label } : {}
159
+ };
160
+ return [key, storedFeat];
161
+ }
154
162
  const staticFeature = feat;
155
- return staticFeature.label ? { ...staticFeature } : staticFeature;
163
+ return [key, staticFeature.label ? { ...staticFeature } : staticFeature];
156
164
  }
157
- });
165
+ );
166
+ return Object.fromEntries(stored);
158
167
  }
159
168
 
160
169
  // src/functions/create-stored-data.ts
161
170
  function createStoredRenderable(data, animatableValues) {
162
- const d = (0, import_lodash2.omit)(data, "refs", "geometry");
171
+ const { geometry: _geometry, ...stored } = data;
163
172
  const storedFeatures = createStoredFeatures(
164
173
  data.features,
165
174
  animatableValues
166
175
  );
167
- return { ...d, features: storedFeatures };
176
+ return { ...stored, features: storedFeatures };
168
177
  }
169
178
 
170
179
  // src/renderables/group.tsx
@@ -177,7 +186,9 @@ function InnerRenderedGroup({
177
186
  }) {
178
187
  const ref = (0, import_react4.useRef)(null);
179
188
  const group = useVizijStore((0, import_shallow2.useShallow)((state) => state.world[id]));
180
- const refIsNull = !group.refs[namespace]?.current;
189
+ const refIsNull = useVizijStore(
190
+ (state) => !state.refs[id]?.[namespace]?.current
191
+ );
181
192
  const animatables = useVizijStore((0, import_shallow2.useShallow)((state) => state.animatables));
182
193
  const setHoveredElement = useVizijStore(
183
194
  (0, import_shallow2.useShallow)((state) => state.setHoveredElement)
@@ -312,7 +323,9 @@ function InnerRenderedEllipse({
312
323
  const ellipse = useVizijStore(
313
324
  (0, import_shallow3.useShallow)((state) => state.world[id])
314
325
  );
315
- const refIsNull = !ellipse.refs[namespace]?.current;
326
+ const refIsNull = useVizijStore(
327
+ (state) => !state.refs[id]?.[namespace]?.current
328
+ );
316
329
  const animatables = useVizijStore((0, import_shallow3.useShallow)((state) => state.animatables));
317
330
  const animatableValues = (0, import_react5.useMemo)(() => {
318
331
  const av = {};
@@ -599,7 +612,9 @@ function InnerRenderedRectangle({
599
612
  const rectangle = useVizijStore(
600
613
  (0, import_shallow4.useShallow)((state) => state.world[id])
601
614
  );
602
- const refIsNull = !rectangle.refs[namespace]?.current;
615
+ const refIsNull = useVizijStore(
616
+ (state) => !state.refs[id]?.[namespace]?.current
617
+ );
603
618
  const animatables = useVizijStore((0, import_shallow4.useShallow)((state) => state.animatables));
604
619
  const animatableValues = (0, import_react6.useMemo)(() => {
605
620
  const av = {};
@@ -865,6 +880,61 @@ var import_react7 = require("react");
865
880
  var THREE2 = __toESM(require("three"));
866
881
  var import_shallow5 = require("zustand/react/shallow");
867
882
  var import_utils5 = require("@vizij/utils");
883
+
884
+ // src/functions/material-name.ts
885
+ var MATERIAL_FEATURE_KEYS = [
886
+ "color",
887
+ "opacity",
888
+ "roughness",
889
+ "metalness",
890
+ "shininess",
891
+ "emissive",
892
+ "emissiveIntensity",
893
+ "specular"
894
+ ];
895
+ var MATERIAL_NAME_SUFFIXES = [
896
+ " color",
897
+ " colours",
898
+ " colour",
899
+ " opacity",
900
+ " roughness",
901
+ " metalness",
902
+ " shininess",
903
+ " emissive intensity",
904
+ " emissive",
905
+ " specular"
906
+ ];
907
+ function deriveMaterialName(shape, values) {
908
+ for (const key of MATERIAL_FEATURE_KEYS) {
909
+ const feature = shape.features[key];
910
+ if (feature && feature.animated) {
911
+ const animatable = values[feature.value];
912
+ const candidate = extractMaterialName(animatable?.name);
913
+ if (candidate) {
914
+ return candidate;
915
+ }
916
+ }
917
+ }
918
+ return void 0;
919
+ }
920
+ function extractMaterialName(name) {
921
+ if (!name) {
922
+ return void 0;
923
+ }
924
+ const trimmed = name.trim();
925
+ if (!trimmed) {
926
+ return void 0;
927
+ }
928
+ const lowered = trimmed.toLowerCase();
929
+ for (const suffix of MATERIAL_NAME_SUFFIXES) {
930
+ if (lowered.endsWith(suffix)) {
931
+ return trimmed.slice(0, trimmed.length - suffix.length).trim();
932
+ }
933
+ }
934
+ return trimmed;
935
+ }
936
+
937
+ // src/renderables/shape.tsx
868
938
  var import_jsx_runtime4 = require("react/jsx-runtime");
869
939
  THREE2.Object3D.DEFAULT_UP.set(0, 0, 1);
870
940
  function InnerRenderedShape({
@@ -875,10 +945,9 @@ function InnerRenderedShape({
875
945
  const refGroup = (0, import_react7.useRef)(null);
876
946
  const ref = (0, import_react7.useRef)(null);
877
947
  const shape = useVizijStore((0, import_shallow5.useShallow)((state) => state.world[id]));
878
- const refs = useVizijStore(
879
- (0, import_shallow5.useShallow)((state) => state.world[id].refs)
948
+ const refIsNull = useVizijStore(
949
+ (state) => !state.refs[id]?.[namespace]?.current
880
950
  );
881
- const refIsNull = !refs[namespace]?.current;
882
951
  const animatables = useVizijStore((0, import_shallow5.useShallow)((state) => state.animatables));
883
952
  const animatableValues = (0, import_react7.useMemo)(() => {
884
953
  const av = {};
@@ -1006,6 +1075,48 @@ function InnerRenderedShape({
1006
1075
  );
1007
1076
  }
1008
1077
  },
1078
+ roughness: (value) => {
1079
+ const standard = material.current;
1080
+ if (standard?.roughness !== void 0 && (0, import_utils5.instanceOfRawNumber)(value)) {
1081
+ standard.roughness = value;
1082
+ standard.needsUpdate = true;
1083
+ }
1084
+ },
1085
+ metalness: (value) => {
1086
+ const standard = material.current;
1087
+ if (standard?.metalness !== void 0 && (0, import_utils5.instanceOfRawNumber)(value)) {
1088
+ standard.metalness = value;
1089
+ standard.needsUpdate = true;
1090
+ }
1091
+ },
1092
+ shininess: (value) => {
1093
+ const phong = material.current;
1094
+ if (phong?.shininess !== void 0 && (0, import_utils5.instanceOfRawNumber)(value)) {
1095
+ phong.shininess = value;
1096
+ phong.needsUpdate = true;
1097
+ }
1098
+ },
1099
+ emissive: (value) => {
1100
+ const standard = material.current;
1101
+ if (standard?.emissive && (0, import_utils5.instanceOfRawRGB)(value)) {
1102
+ standard.emissive.setRGB(value.r, value.g, value.b);
1103
+ standard.needsUpdate = true;
1104
+ }
1105
+ },
1106
+ emissiveIntensity: (value) => {
1107
+ const standard = material.current;
1108
+ if (standard?.emissiveIntensity !== void 0 && (0, import_utils5.instanceOfRawNumber)(value)) {
1109
+ standard.emissiveIntensity = value;
1110
+ standard.needsUpdate = true;
1111
+ }
1112
+ },
1113
+ specular: (value) => {
1114
+ const phong = material.current;
1115
+ if (phong?.specular && (0, import_utils5.instanceOfRawRGB)(value)) {
1116
+ phong.specular.setRGB(value.r, value.g, value.b);
1117
+ phong.needsUpdate = true;
1118
+ }
1119
+ },
1009
1120
  ...morphTargetSettings[2]
1010
1121
  },
1011
1122
  shape
@@ -1121,51 +1232,6 @@ function InnerRenderedShape({
1121
1232
  );
1122
1233
  }
1123
1234
  var RenderedShape = (0, import_react7.memo)(InnerRenderedShape);
1124
- var MATERIAL_FEATURE_KEYS = [
1125
- "color",
1126
- "opacity",
1127
- "roughness",
1128
- "metalness",
1129
- "shininess"
1130
- ];
1131
- var MATERIAL_NAME_SUFFIXES = [
1132
- " color",
1133
- " colours",
1134
- " colour",
1135
- " opacity",
1136
- " roughness",
1137
- " metalness",
1138
- " shininess"
1139
- ];
1140
- function deriveMaterialName(shape, values) {
1141
- for (const key of MATERIAL_FEATURE_KEYS) {
1142
- const feature = shape.features[key];
1143
- if (feature && feature.animated) {
1144
- const animatable = values[feature.value];
1145
- const candidate = extractMaterialName(animatable?.name);
1146
- if (candidate) {
1147
- return candidate;
1148
- }
1149
- }
1150
- }
1151
- return void 0;
1152
- }
1153
- function extractMaterialName(name) {
1154
- if (!name) {
1155
- return void 0;
1156
- }
1157
- const trimmed = name.trim();
1158
- if (!trimmed) {
1159
- return void 0;
1160
- }
1161
- const lowered = trimmed.toLowerCase();
1162
- for (const suffix of MATERIAL_NAME_SUFFIXES) {
1163
- if (lowered.endsWith(suffix)) {
1164
- return trimmed.slice(0, trimmed.length - suffix.length).trim();
1165
- }
1166
- }
1167
- return trimmed;
1168
- }
1169
1235
 
1170
1236
  // src/renderables/renderable.tsx
1171
1237
  var import_jsx_runtime5 = require("react/jsx-runtime");
@@ -1175,65 +1241,35 @@ function InnerRenderable({
1175
1241
  chain
1176
1242
  }) {
1177
1243
  const type = useVizijStore((0, import_shallow6.useShallow)((state) => state.world[id].type));
1178
- const refs = useVizijStore((0, import_shallow6.useShallow)((state) => state.world[id].refs));
1179
- const resolvedNamespaces = (0, import_react8.useMemo)(() => {
1180
- let namespaces = [namespace];
1181
- if (namespace in refs) {
1182
- namespaces = [namespace];
1183
- } else {
1184
- namespaces = Object.keys(refs);
1185
- }
1186
- return namespaces;
1187
- }, [namespace, refs]);
1188
- if (resolvedNamespaces.length === 0) {
1189
- return null;
1244
+ const key = `${namespace}.${id}`;
1245
+ switch (type) {
1246
+ case "group":
1247
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RenderedGroup, { id, namespace, chain }, key);
1248
+ case "ellipse":
1249
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1250
+ RenderedEllipse,
1251
+ {
1252
+ id,
1253
+ namespace,
1254
+ chain
1255
+ },
1256
+ key
1257
+ );
1258
+ case "rectangle":
1259
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1260
+ RenderedRectangle,
1261
+ {
1262
+ id,
1263
+ namespace,
1264
+ chain
1265
+ },
1266
+ key
1267
+ );
1268
+ case "shape":
1269
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RenderedShape, { id, namespace, chain }, key);
1270
+ default:
1271
+ return null;
1190
1272
  }
1191
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children: resolvedNamespaces.map((ns) => {
1192
- switch (type) {
1193
- case "group":
1194
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1195
- RenderedGroup,
1196
- {
1197
- id,
1198
- namespace: ns,
1199
- chain
1200
- },
1201
- `${ns}.${id}`
1202
- );
1203
- case "ellipse":
1204
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1205
- RenderedEllipse,
1206
- {
1207
- id,
1208
- namespace: ns,
1209
- chain
1210
- },
1211
- `${ns}.${id}`
1212
- );
1213
- case "rectangle":
1214
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1215
- RenderedRectangle,
1216
- {
1217
- id,
1218
- namespace: ns,
1219
- chain
1220
- },
1221
- `${ns}.${id}`
1222
- );
1223
- case "shape":
1224
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1225
- RenderedShape,
1226
- {
1227
- id,
1228
- namespace: ns,
1229
- chain
1230
- },
1231
- `${ns}.${id}`
1232
- );
1233
- default:
1234
- return null;
1235
- }
1236
- }) });
1237
1273
  }
1238
1274
  var Renderable = (0, import_react8.memo)(InnerRenderable);
1239
1275
 
@@ -1242,23 +1278,19 @@ var import_zustand2 = require("zustand");
1242
1278
  var import_middleware = require("zustand/middleware");
1243
1279
  var import_immer = require("immer");
1244
1280
  var THREE3 = __toESM(require("three"));
1245
- var import_utils6 = require("@vizij/utils");
1246
-
1247
- // src/actions/create-new-element.ts
1248
- var import_react9 = require("react");
1249
- var import_lodash3 = require("lodash");
1281
+ var import_utils8 = require("@vizij/utils");
1250
1282
 
1251
1283
  // src/functions/create-world-element.ts
1284
+ var import_utils6 = require("@vizij/utils");
1252
1285
  function createDefaultGroup(partialBody) {
1253
1286
  const translation = partialBody.features?.translation || { animated: false, value: { x: 0, y: 0 } };
1254
1287
  const rotation = partialBody.features?.rotation || { animated: false, value: { x: 0, y: 0, z: 0 } };
1255
1288
  const scale = partialBody.features?.scale || { animated: false, value: { x: 1, y: 1, z: 1 } };
1256
1289
  return {
1257
- id: partialBody.id || crypto.randomUUID(),
1290
+ id: partialBody.id || (0, import_utils6.createBrowserSafeId)(),
1258
1291
  name: partialBody.name || "new-body",
1259
1292
  type: partialBody.type || "group",
1260
1293
  tags: partialBody.tags || [],
1261
- refs: partialBody.refs || {},
1262
1294
  features: { translation, rotation, scale },
1263
1295
  root: partialBody.root ?? false,
1264
1296
  children: partialBody.children || []
@@ -1275,11 +1307,9 @@ function createNewElement(state, type, root = false) {
1275
1307
  });
1276
1308
  if (Object.entries(state.world).length === 0) {
1277
1309
  const name = `New-Root`;
1278
- const refs = { default: (0, import_react9.createRef)() };
1279
1310
  const newElement = createDefaultGroup({
1280
1311
  name,
1281
- root: true,
1282
- refs
1312
+ root: true
1283
1313
  });
1284
1314
  state.world[newElement.id] = newElement;
1285
1315
  state.elementSelection = [buildSelection(newElement.id)];
@@ -1291,11 +1321,7 @@ function createNewElement(state, type, root = false) {
1291
1321
  return;
1292
1322
  }
1293
1323
  const name = `New-Body`;
1294
- const refs = (0, import_lodash3.mapValues)(
1295
- worldRootEntry.refs,
1296
- () => (0, import_react9.createRef)()
1297
- );
1298
- const newChild = createDefaultGroup({ name, root, refs });
1324
+ const newChild = createDefaultGroup({ name, root });
1299
1325
  worldRootEntry.children.push(newChild.id);
1300
1326
  state.world[newChild.id] = newChild;
1301
1327
  state.elementSelection = [buildSelection(newChild.id)];
@@ -1315,7 +1341,32 @@ function removeFromTree(state, nodesToRemove) {
1315
1341
  });
1316
1342
  }
1317
1343
 
1344
+ // src/memoryInvestigation.ts
1345
+ function getGlobalMemoryInvestigation() {
1346
+ return globalThis;
1347
+ }
1348
+ function updateRenderState(updater) {
1349
+ const globalObj = getGlobalMemoryInvestigation();
1350
+ if (!globalObj.__VIZIJ_MEMORY_INVESTIGATION__?.enabled) {
1351
+ return;
1352
+ }
1353
+ if (!globalObj.__vizijMemoryDebugState) {
1354
+ globalObj.__vizijMemoryDebugState = {};
1355
+ }
1356
+ if (!globalObj.__vizijMemoryDebugState.render) {
1357
+ globalObj.__vizijMemoryDebugState.render = {};
1358
+ }
1359
+ updater(globalObj.__vizijMemoryDebugState.render);
1360
+ }
1361
+ function recordRenderCounter(key, delta = 1) {
1362
+ updateRenderState((renderState) => {
1363
+ const current = typeof renderState[key] === "number" ? Number(renderState[key]) : 0;
1364
+ renderState[key] = current + delta;
1365
+ });
1366
+ }
1367
+
1318
1368
  // src/functions/create-animatable.ts
1369
+ var import_utils7 = require("@vizij/utils");
1319
1370
  function createAnimatable(value) {
1320
1371
  if (!value.type) {
1321
1372
  return null;
@@ -1325,7 +1376,7 @@ function createAnimatable(value) {
1325
1376
  }
1326
1377
  if (value.type === "euler") {
1327
1378
  const newAnimatable = {
1328
- id: value.id ?? crypto.randomUUID(),
1379
+ id: value.id ?? (0, import_utils7.createBrowserSafeId)(),
1329
1380
  name: `${value.name} Rotation`,
1330
1381
  type: value.type,
1331
1382
  default: value.default ?? { x: 0, y: 0, z: 0 },
@@ -1342,7 +1393,7 @@ function createAnimatable(value) {
1342
1393
  return newAnimatable;
1343
1394
  } else if (value.type === "vector3") {
1344
1395
  const newAnimatable = {
1345
- id: value.id ?? crypto.randomUUID(),
1396
+ id: value.id ?? (0, import_utils7.createBrowserSafeId)(),
1346
1397
  name: `${value.name} Vector3`,
1347
1398
  type: value.type,
1348
1399
  default: value.default ?? { x: 0, y: 0, z: 0 },
@@ -1359,7 +1410,7 @@ function createAnimatable(value) {
1359
1410
  return newAnimatable;
1360
1411
  } else if (value.type === "string") {
1361
1412
  const newAnimatable = {
1362
- id: value.id ?? crypto.randomUUID(),
1413
+ id: value.id ?? (0, import_utils7.createBrowserSafeId)(),
1363
1414
  name: value.name,
1364
1415
  type: value.type,
1365
1416
  default: value.default ?? "Hello World",
@@ -1372,7 +1423,7 @@ function createAnimatable(value) {
1372
1423
  return newAnimatable;
1373
1424
  } else if (value.type === "number") {
1374
1425
  const newAnimatable = {
1375
- id: value.id ?? crypto.randomUUID(),
1426
+ id: value.id ?? (0, import_utils7.createBrowserSafeId)(),
1376
1427
  name: value.name,
1377
1428
  type: value.type,
1378
1429
  default: value.default ?? 0,
@@ -1385,7 +1436,7 @@ function createAnimatable(value) {
1385
1436
  return newAnimatable;
1386
1437
  } else if (value.type === "boolean") {
1387
1438
  const newAnimatable = {
1388
- id: value.id ?? crypto.randomUUID(),
1439
+ id: value.id ?? (0, import_utils7.createBrowserSafeId)(),
1389
1440
  name: value.name,
1390
1441
  type: value.type,
1391
1442
  default: value.default ?? false,
@@ -1398,7 +1449,7 @@ function createAnimatable(value) {
1398
1449
  return newAnimatable;
1399
1450
  } else if (value.type === "rgb") {
1400
1451
  const newAnimatable = {
1401
- id: value.id ?? crypto.randomUUID(),
1452
+ id: value.id ?? (0, import_utils7.createBrowserSafeId)(),
1402
1453
  name: value.name,
1403
1454
  type: value.type,
1404
1455
  default: value.default ?? { r: 0, g: 0, b: 0 },
@@ -1415,7 +1466,7 @@ function createAnimatable(value) {
1415
1466
  return newAnimatable;
1416
1467
  } else if (value.type === "hsl") {
1417
1468
  const newAnimatable = {
1418
- id: value.id ?? crypto.randomUUID(),
1469
+ id: value.id ?? (0, import_utils7.createBrowserSafeId)(),
1419
1470
  name: value.name,
1420
1471
  type: value.type,
1421
1472
  default: value.default ?? { h: 0, s: 0, l: 0 },
@@ -1470,6 +1521,7 @@ THREE3.Object3D.DEFAULT_UP.set(0, 0, 1);
1470
1521
  var VizijSlice = (set, get) => ({
1471
1522
  // worldRef: createRef<THREE.Group>(),
1472
1523
  world: {},
1524
+ refs: {},
1473
1525
  animatables: {},
1474
1526
  values: /* @__PURE__ */ new Map(),
1475
1527
  renderHit: false,
@@ -1543,12 +1595,10 @@ var VizijSlice = (set, get) => ({
1543
1595
  worldData,
1544
1596
  filterIds
1545
1597
  );
1598
+ const refs = get().refs;
1546
1599
  return candidateGroups.flatMap((entry) => {
1547
- const refs = Object.values(
1548
- entry.refs ?? {}
1549
- );
1550
- const resolved = refs.find((ref) => ref?.current)?.current ?? null;
1551
- return resolved ? [resolved] : [];
1600
+ const mounted = Object.values(refs[entry.id] ?? {}).map((ref) => ref.current).find((object) => Boolean(object));
1601
+ return mounted ? [mounted] : [];
1552
1602
  });
1553
1603
  },
1554
1604
  setGeometry: (id, geometry) => {
@@ -1561,7 +1611,7 @@ var VizijSlice = (set, get) => ({
1561
1611
  setValue: (id, namespace, value) => {
1562
1612
  set(
1563
1613
  (0, import_immer.produce)((state) => {
1564
- const lookupId = (0, import_utils6.getLookup)(namespace, id);
1614
+ const lookupId = (0, import_utils8.getLookup)(namespace, id);
1565
1615
  if (typeof value === "function") {
1566
1616
  const current = state.values.get(lookupId);
1567
1617
  if (current !== void 0) {
@@ -1590,7 +1640,7 @@ var VizijSlice = (set, get) => ({
1590
1640
  set(
1591
1641
  (0, import_immer.produce)((state) => {
1592
1642
  writes.forEach(({ id, namespace, value }) => {
1593
- const lookupId = (0, import_utils6.getLookup)(namespace, id);
1643
+ const lookupId = (0, import_utils8.getLookup)(namespace, id);
1594
1644
  state.values.set(lookupId, value);
1595
1645
  });
1596
1646
  })
@@ -1721,8 +1771,8 @@ var VizijSlice = (set, get) => ({
1721
1771
  setSlot: (parentId, parentNamespace, childId, childNamespace) => {
1722
1772
  set(
1723
1773
  (0, import_immer.produce)((state) => {
1724
- const parentLookupId = (0, import_utils6.getLookup)(parentNamespace, parentId);
1725
- const childLookupId = (0, import_utils6.getLookup)(childNamespace, childId);
1774
+ const parentLookupId = (0, import_utils8.getLookup)(parentNamespace, parentId);
1775
+ const childLookupId = (0, import_utils8.getLookup)(childNamespace, childId);
1726
1776
  state.slotConfig[parentLookupId] = childLookupId;
1727
1777
  })
1728
1778
  );
@@ -1741,12 +1791,13 @@ var VizijSlice = (set, get) => ({
1741
1791
  clearSlot: (parentId, parentNamespace) => {
1742
1792
  set(
1743
1793
  (0, import_immer.produce)((state) => {
1744
- const parentLookupId = (0, import_utils6.getLookup)(parentNamespace, parentId);
1794
+ const parentLookupId = (0, import_utils8.getLookup)(parentNamespace, parentId);
1745
1795
  delete state.slotConfig[parentLookupId];
1746
1796
  })
1747
1797
  );
1748
1798
  },
1749
1799
  setVizij: (scene, animatables) => {
1800
+ recordRenderCounter("rootReplacementCount");
1750
1801
  set({
1751
1802
  world: scene,
1752
1803
  animatables
@@ -1754,6 +1805,7 @@ var VizijSlice = (set, get) => ({
1754
1805
  },
1755
1806
  addWorldElements(world, animatables, replace) {
1756
1807
  if (replace) {
1808
+ recordRenderCounter("rootReplacementCount");
1757
1809
  set({ world, animatables });
1758
1810
  } else {
1759
1811
  set((state) => ({
@@ -1768,14 +1820,12 @@ var VizijSlice = (set, get) => ({
1768
1820
  }));
1769
1821
  },
1770
1822
  setReference: (id, namespace, ref) => {
1771
- set(
1772
- (0, import_immer.produce)((state) => {
1773
- state.world[id].refs[namespace].current = ref.current;
1774
- if (ref.current?.children && state.world[id].refs[namespace].current) {
1775
- state.world[id].refs[namespace].current.children = ref.current.children;
1776
- }
1777
- })
1778
- );
1823
+ set((state) => ({
1824
+ refs: {
1825
+ ...state.refs,
1826
+ [id]: { ...state.refs[id], [namespace]: ref }
1827
+ }
1828
+ }));
1779
1829
  }
1780
1830
  });
1781
1831
  var useDefaultVizijStore = (0, import_zustand2.create)()(
@@ -1790,15 +1840,59 @@ var createVizijStore = (initial) => (0, import_zustand2.create)()(
1790
1840
  }))
1791
1841
  );
1792
1842
 
1843
+ // src/types/shape.ts
1844
+ var ShapeMaterial = /* @__PURE__ */ ((ShapeMaterial2) => {
1845
+ ShapeMaterial2["Standard"] = "standard";
1846
+ ShapeMaterial2["Phong"] = "phong";
1847
+ ShapeMaterial2["Basic"] = "basic";
1848
+ ShapeMaterial2["Lambert"] = "lambert";
1849
+ ShapeMaterial2["Normal"] = "normal";
1850
+ return ShapeMaterial2;
1851
+ })(ShapeMaterial || {});
1852
+
1853
+ // src/types/tone-mapping.ts
1854
+ var import_three = require("three");
1855
+ var TONE_MAPPING_MODES = [
1856
+ "none",
1857
+ "agx",
1858
+ "aces",
1859
+ "neutral"
1860
+ ];
1861
+ var TONE_MAPPING_LABELS = {
1862
+ none: "None (web match)",
1863
+ agx: "AgX (Blender)",
1864
+ aces: "ACES Filmic",
1865
+ neutral: "Neutral"
1866
+ };
1867
+ var DEFAULT_TONE_MAPPING_MODE = "none";
1868
+ var TONE_MAPPING_CONSTANTS = {
1869
+ none: import_three.NoToneMapping,
1870
+ agx: import_three.AgXToneMapping,
1871
+ aces: import_three.ACESFilmicToneMapping,
1872
+ neutral: import_three.NeutralToneMapping
1873
+ };
1874
+ function isToneMappingMode(value) {
1875
+ return typeof value === "string" && Object.prototype.hasOwnProperty.call(TONE_MAPPING_CONSTANTS, value);
1876
+ }
1877
+ function resolveToneMapping(mode) {
1878
+ if (isToneMappingMode(mode)) {
1879
+ return TONE_MAPPING_CONSTANTS[mode];
1880
+ }
1881
+ return TONE_MAPPING_CONSTANTS[DEFAULT_TONE_MAPPING_MODE];
1882
+ }
1883
+ function normalizeToneMappingMode(value) {
1884
+ return isToneMappingMode(value) ? value : DEFAULT_TONE_MAPPING_MODE;
1885
+ }
1886
+
1793
1887
  // src/effects/selection-glow-effect.tsx
1794
- var import_react10 = require("react");
1888
+ var import_react9 = require("react");
1795
1889
  var import_fiber = require("@react-three/fiber");
1796
1890
  var import_shallow7 = require("zustand/react/shallow");
1797
- var import_three = require("three");
1891
+ var import_three2 = require("three");
1798
1892
  var import_jsx_runtime6 = require("react/jsx-runtime");
1799
1893
  function SelectionGlowEffect({
1800
1894
  enabled = false,
1801
- color = "#ff1010ff",
1895
+ color = "#ff1010",
1802
1896
  opacity = 0.9,
1803
1897
  thresholdAngle = 2
1804
1898
  }) {
@@ -1810,7 +1904,7 @@ function SelectionGlowEffect({
1810
1904
  if (!enabled || selections.length === 0) {
1811
1905
  return null;
1812
1906
  }
1813
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react10.Fragment, { children: selections.map((selection) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1907
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react9.Fragment, { children: selections.map((selection) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1814
1908
  SelectionOutline,
1815
1909
  {
1816
1910
  selection,
@@ -1830,32 +1924,32 @@ function SelectionOutline({
1830
1924
  const target = useVizijStore(
1831
1925
  (0, import_shallow7.useShallow)((state) => {
1832
1926
  const entry = state.world[selection.id];
1833
- const ref = entry?.refs?.[selection.namespace];
1927
+ const ref = state.refs[selection.id]?.[selection.namespace];
1834
1928
  const geometry = entry?.geometry ?? null;
1835
1929
  return { ref, geometry };
1836
1930
  })
1837
1931
  );
1838
1932
  const sourceRef = target.ref;
1839
- const edgesGeometry = (0, import_react10.useMemo)(() => {
1933
+ const edgesGeometry = (0, import_react9.useMemo)(() => {
1840
1934
  if (!target.geometry) return null;
1841
- const edges = new import_three.EdgesGeometry(target.geometry, thresholdAngle);
1935
+ const edges = new import_three2.EdgesGeometry(target.geometry, thresholdAngle);
1842
1936
  return edges;
1843
1937
  }, [target.geometry, thresholdAngle]);
1844
- (0, import_react10.useEffect)(() => () => edgesGeometry?.dispose(), [edgesGeometry]);
1845
- const material = (0, import_react10.useMemo)(() => {
1846
- const mat = new import_three.LineBasicMaterial({
1847
- color: new import_three.Color(color),
1938
+ (0, import_react9.useEffect)(() => () => edgesGeometry?.dispose(), [edgesGeometry]);
1939
+ const material = (0, import_react9.useMemo)(() => {
1940
+ const mat = new import_three2.LineBasicMaterial({
1941
+ color: new import_three2.Color(color),
1848
1942
  transparent: true,
1849
1943
  opacity,
1850
- blending: import_three.AdditiveBlending,
1944
+ blending: import_three2.AdditiveBlending,
1851
1945
  depthTest: false,
1852
1946
  depthWrite: false,
1853
1947
  toneMapped: false
1854
1948
  });
1855
1949
  return mat;
1856
1950
  }, [color, opacity]);
1857
- (0, import_react10.useEffect)(() => () => material.dispose(), [material]);
1858
- const lineRef = (0, import_react10.useRef)(null);
1951
+ (0, import_react9.useEffect)(() => () => material.dispose(), [material]);
1952
+ const lineRef = (0, import_react9.useRef)(null);
1859
1953
  (0, import_fiber.useFrame)(() => {
1860
1954
  const source = sourceRef?.current;
1861
1955
  const line = lineRef.current;
@@ -1877,10 +1971,10 @@ function SelectionOutline({
1877
1971
  }
1878
1972
  );
1879
1973
  }
1880
- var tempMatrix = new import_three.Matrix4();
1881
- var tempPosition = new import_three.Vector3();
1882
- var tempQuaternion = new import_three.Quaternion();
1883
- var tempScale = new import_three.Vector3();
1974
+ var tempMatrix = new import_three2.Matrix4();
1975
+ var tempPosition = new import_three2.Vector3();
1976
+ var tempQuaternion = new import_three2.Quaternion();
1977
+ var tempScale = new import_three2.Vector3();
1884
1978
  function copyWorldTransform(source, target) {
1885
1979
  source.updateWorldMatrix(true, false);
1886
1980
  tempMatrix.copy(source.matrixWorld);
@@ -1893,7 +1987,7 @@ function copyWorldTransform(source, target) {
1893
1987
 
1894
1988
  // src/vizij.tsx
1895
1989
  var import_jsx_runtime7 = require("react/jsx-runtime");
1896
- import_three2.Object3D.DEFAULT_UP.set(0, 0, 1);
1990
+ import_three3.Object3D.DEFAULT_UP.set(0, 0, 1);
1897
1991
  function Vizij({
1898
1992
  style,
1899
1993
  className,
@@ -1901,9 +1995,17 @@ function Vizij({
1901
1995
  namespace = "default",
1902
1996
  showSafeArea = false,
1903
1997
  showSelectionGlow = false,
1998
+ toneMapping = "none",
1904
1999
  onPointerMissed
1905
2000
  }) {
1906
- const ctx = (0, import_react11.useContext)(VizijContext);
2001
+ const ctx = (0, import_react10.useContext)(VizijContext);
2002
+ (0, import_react10.useEffect)(() => {
2003
+ recordRenderCounter("canvasMountCount");
2004
+ recordRenderCounter("mountedCanvasCount");
2005
+ return () => {
2006
+ recordRenderCounter("mountedCanvasCount", -1);
2007
+ };
2008
+ }, []);
1907
2009
  if (ctx) {
1908
2010
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1909
2011
  import_fiber2.Canvas,
@@ -1913,8 +2015,7 @@ function Vizij({
1913
2015
  className,
1914
2016
  onPointerMissed,
1915
2017
  gl: {
1916
- outputColorSpace: import_three2.SRGBColorSpace,
1917
- toneMapping: import_three2.NoToneMapping,
2018
+ outputColorSpace: import_three3.SRGBColorSpace,
1918
2019
  antialias: true
1919
2020
  },
1920
2021
  children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
@@ -1923,7 +2024,8 @@ function Vizij({
1923
2024
  rootId,
1924
2025
  namespace,
1925
2026
  showSafeArea,
1926
- showSelectionGlow
2027
+ showSelectionGlow,
2028
+ toneMapping
1927
2029
  }
1928
2030
  )
1929
2031
  }
@@ -1936,8 +2038,7 @@ function Vizij({
1936
2038
  className,
1937
2039
  onPointerMissed,
1938
2040
  gl: {
1939
- outputColorSpace: import_three2.SRGBColorSpace,
1940
- toneMapping: import_three2.NoToneMapping,
2041
+ outputColorSpace: import_three3.SRGBColorSpace,
1941
2042
  antialias: true
1942
2043
  },
1943
2044
  children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
@@ -1946,7 +2047,8 @@ function Vizij({
1946
2047
  rootId,
1947
2048
  namespace,
1948
2049
  showSafeArea,
1949
- showSelectionGlow
2050
+ showSelectionGlow,
2051
+ toneMapping
1950
2052
  }
1951
2053
  )
1952
2054
  }
@@ -1958,7 +2060,8 @@ function InnerVizij({
1958
2060
  namespace = "default",
1959
2061
  container,
1960
2062
  showSafeArea,
1961
- showSelectionGlow
2063
+ showSelectionGlow,
2064
+ toneMapping = "none"
1962
2065
  }) {
1963
2066
  const sceneParentSizing = container ? {
1964
2067
  width: container.width * container.resolution,
@@ -1966,16 +2069,17 @@ function InnerVizij({
1966
2069
  } : void 0;
1967
2070
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1968
2071
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ambientLight", { intensity: Math.PI / 2 }),
2072
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ToneMappingController, { mode: toneMapping }),
1969
2073
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1970
2074
  import_drei3.OrthographicCamera,
1971
2075
  {
1972
2076
  makeDefault: true,
1973
2077
  position: [0, 0, 100],
1974
2078
  near: 0.1,
1975
- far: 101
2079
+ far: 1e3
1976
2080
  }
1977
2081
  ),
1978
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react11.Suspense, { fallback: null, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2082
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react10.Suspense, { fallback: null, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1979
2083
  World,
1980
2084
  {
1981
2085
  rootId,
@@ -1987,7 +2091,32 @@ function InnerVizij({
1987
2091
  showSafeArea && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SafeAreaRenderer, { rootId })
1988
2092
  ] });
1989
2093
  }
1990
- var MemoizedInnerVizij = (0, import_react11.memo)(InnerVizij);
2094
+ var MemoizedInnerVizij = (0, import_react10.memo)(InnerVizij);
2095
+ function ToneMappingController({ mode }) {
2096
+ const gl = (0, import_fiber2.useThree)((state) => state.gl);
2097
+ const scene = (0, import_fiber2.useThree)((state) => state.scene);
2098
+ (0, import_react10.useEffect)(() => {
2099
+ const resolved = resolveToneMapping(mode);
2100
+ if (gl.toneMapping === resolved) {
2101
+ return;
2102
+ }
2103
+ gl.toneMapping = resolved;
2104
+ scene.traverse((object) => {
2105
+ const material = object.material;
2106
+ if (!material) {
2107
+ return;
2108
+ }
2109
+ if (Array.isArray(material)) {
2110
+ material.forEach((mat) => {
2111
+ mat.needsUpdate = true;
2112
+ });
2113
+ } else {
2114
+ material.needsUpdate = true;
2115
+ }
2116
+ });
2117
+ }, [gl, scene, mode]);
2118
+ return null;
2119
+ }
1991
2120
  function InnerWorld({
1992
2121
  rootId,
1993
2122
  namespace = "default",
@@ -2004,7 +2133,7 @@ function InnerWorld({
2004
2133
  camera: state.camera,
2005
2134
  size: state.size
2006
2135
  }));
2007
- (0, import_react11.useEffect)(() => {
2136
+ (0, import_react10.useEffect)(() => {
2008
2137
  const width = rootBounds.size.x;
2009
2138
  const height = rootBounds.size.y;
2010
2139
  if (camera && parentSizing === void 0 && camera.isOrthographicCamera) {
@@ -2047,7 +2176,7 @@ function InnerWorld({
2047
2176
  )
2048
2177
  ] });
2049
2178
  }
2050
- var World = (0, import_react11.memo)(InnerWorld);
2179
+ var World = (0, import_react10.memo)(InnerWorld);
2051
2180
  function SafeAreaRenderer({ rootId }) {
2052
2181
  const rootBounds = useVizijStore((state) => {
2053
2182
  const group = state.world[rootId];
@@ -2077,22 +2206,12 @@ var defaultRootBounds = {
2077
2206
  size: { x: 5, y: 4 }
2078
2207
  };
2079
2208
 
2080
- // src/types/shape.ts
2081
- var ShapeMaterial = /* @__PURE__ */ ((ShapeMaterial2) => {
2082
- ShapeMaterial2["Standard"] = "standard";
2083
- ShapeMaterial2["Phong"] = "phong";
2084
- ShapeMaterial2["Basic"] = "basic";
2085
- ShapeMaterial2["Lambert"] = "lambert";
2086
- ShapeMaterial2["Normal"] = "normal";
2087
- return ShapeMaterial2;
2088
- })(ShapeMaterial || {});
2089
-
2090
2209
  // src/hooks/use-vizij-store-subscription.ts
2091
- var import_react12 = require("react");
2210
+ var import_react11 = require("react");
2092
2211
  function useVizijStoreSubscription(selector, listener) {
2093
- const store = (0, import_react12.useContext)(VizijContext);
2212
+ const store = (0, import_react11.useContext)(VizijContext);
2094
2213
  if (!store) throw new Error("Missing VizijProvider in the tree");
2095
- (0, import_react12.useEffect)(() => {
2214
+ (0, import_react11.useEffect)(() => {
2096
2215
  const initialValue = selector(store.getState());
2097
2216
  listener(initialValue);
2098
2217
  return store.subscribe(selector, listener);
@@ -2100,17 +2219,17 @@ function useVizijStoreSubscription(selector, listener) {
2100
2219
  }
2101
2220
 
2102
2221
  // src/hooks/use-vizij-store-setter.ts
2103
- var import_react13 = require("react");
2222
+ var import_react12 = require("react");
2104
2223
  function useVizijStoreSetter() {
2105
- const store = (0, import_react13.useContext)(VizijContext);
2224
+ const store = (0, import_react12.useContext)(VizijContext);
2106
2225
  if (!store) throw new Error("Missing VizijProvider in the tree");
2107
2226
  return store.setState;
2108
2227
  }
2109
2228
 
2110
2229
  // src/hooks/use-vizij-store-getter.ts
2111
- var import_react14 = require("react");
2230
+ var import_react13 = require("react");
2112
2231
  function useVizijStoreGetter() {
2113
- const store = (0, import_react14.useContext)(VizijContext);
2232
+ const store = (0, import_react13.useContext)(VizijContext);
2114
2233
  if (!store) throw new Error("Missing VizijProvider in the tree");
2115
2234
  return store.getState;
2116
2235
  }
@@ -2120,7 +2239,6 @@ var THREE5 = __toESM(require("three"));
2120
2239
  var import_three_stdlib = require("three-stdlib");
2121
2240
 
2122
2241
  // src/functions/gltf-loading/traverse-three.ts
2123
- var import_react16 = require("react");
2124
2242
  var THREE4 = __toESM(require("three"));
2125
2243
 
2126
2244
  // src/functions/gltf-loading/map-features.ts
@@ -2146,25 +2264,27 @@ function mapFeatures(features) {
2146
2264
  }
2147
2265
 
2148
2266
  // src/functions/gltf-loading/import-scene.ts
2149
- var import_three5 = require("three");
2267
+ var import_three6 = require("three");
2150
2268
 
2151
2269
  // src/functions/gltf-loading/import-group.ts
2152
- var import_three4 = require("three");
2153
-
2154
- // src/functions/util.ts
2155
- var import_react15 = require("react");
2156
- function namespaceArrayToRefs(namespaces) {
2157
- return namespaces.reduce((acc, ns) => ({ ...acc, [ns]: (0, import_react15.createRef)() }), {});
2158
- }
2270
+ var import_three5 = require("three");
2271
+ var import_utils11 = require("@vizij/utils");
2159
2272
 
2160
2273
  // src/functions/gltf-loading/import-mesh.ts
2161
- var import_three3 = require("three");
2274
+ var import_three4 = require("three");
2275
+ var import_utils10 = require("@vizij/utils");
2162
2276
 
2163
2277
  // src/functions/gltf-loading/import-geometry.ts
2164
- function sanitizeMorphKey(name, fallbackIndex, used) {
2278
+ var import_utils9 = require("@vizij/utils");
2279
+
2280
+ // src/functions/gltf-loading/morph-keys.ts
2281
+ function slugifyMorphName(name, fallbackIndex) {
2165
2282
  const baseName = name && name.trim().length > 0 ? name.trim() : `morph_${fallbackIndex + 1}`;
2166
2283
  const slug = baseName.toLowerCase().replace(/[^a-z0-9]+/gi, "_").replace(/^_+|_+$/g, "");
2167
- const safeBase = slug.length > 0 ? slug : `morph_${fallbackIndex + 1}`;
2284
+ return slug.length > 0 ? slug : `morph_${fallbackIndex + 1}`;
2285
+ }
2286
+ function sanitizeMorphKey(name, fallbackIndex, used) {
2287
+ const safeBase = slugifyMorphName(name, fallbackIndex);
2168
2288
  let candidate = safeBase;
2169
2289
  let counter = 1;
2170
2290
  while (used.has(candidate)) {
@@ -2173,6 +2293,12 @@ function sanitizeMorphKey(name, fallbackIndex, used) {
2173
2293
  used.add(candidate);
2174
2294
  return candidate;
2175
2295
  }
2296
+ function deriveMorphFeatureKeys(names) {
2297
+ const used = /* @__PURE__ */ new Set();
2298
+ return names.map((name, index) => sanitizeMorphKey(name, index, used));
2299
+ }
2300
+
2301
+ // src/functions/gltf-loading/import-geometry.ts
2176
2302
  function importGeometry(geometry, mesh) {
2177
2303
  const features = {};
2178
2304
  const animatableValues = {};
@@ -2184,7 +2310,7 @@ function importGeometry(geometry, mesh) {
2184
2310
  const usedKeys = /* @__PURE__ */ new Set();
2185
2311
  Object.entries(mesh.morphTargetDictionary ?? {}).forEach(
2186
2312
  ([name, index]) => {
2187
- const morphId = crypto.randomUUID();
2313
+ const morphId = (0, import_utils9.createBrowserSafeId)();
2188
2314
  const featureKey = sanitizeMorphKey(name, index, usedKeys);
2189
2315
  morphIds.push(featureKey);
2190
2316
  features[featureKey] = {
@@ -2214,13 +2340,13 @@ function importGeometry(geometry, mesh) {
2214
2340
  }
2215
2341
 
2216
2342
  // src/functions/gltf-loading/import-mesh.ts
2217
- import_three3.Object3D.DEFAULT_UP.set(0, 0, 1);
2218
- function importMesh(mesh, namespaces, colorLookup) {
2343
+ import_three4.Object3D.DEFAULT_UP.set(0, 0, 1);
2344
+ function importMesh(mesh, colorLookup) {
2219
2345
  let world = {};
2220
2346
  let animatables = {};
2221
2347
  let newColorLookup = {};
2222
2348
  const translationAnimatable = {
2223
- id: crypto.randomUUID(),
2349
+ id: (0, import_utils10.createBrowserSafeId)(),
2224
2350
  name: `${mesh.name ?? "Mesh"} translation`,
2225
2351
  type: "vector3",
2226
2352
  default: { x: mesh.position.x, y: mesh.position.y, z: mesh.position.z },
@@ -2236,7 +2362,7 @@ function importMesh(mesh, namespaces, colorLookup) {
2236
2362
  [translationAnimatable.id]: translationAnimatable
2237
2363
  };
2238
2364
  const rotationAnimatable = {
2239
- id: crypto.randomUUID(),
2365
+ id: (0, import_utils10.createBrowserSafeId)(),
2240
2366
  name: `${mesh.name ?? "Mesh"} rotation`,
2241
2367
  type: "euler",
2242
2368
  default: { x: mesh.rotation.x, y: mesh.rotation.y, z: mesh.rotation.z },
@@ -2249,7 +2375,7 @@ function importMesh(mesh, namespaces, colorLookup) {
2249
2375
  };
2250
2376
  animatables = { ...animatables, [rotationAnimatable.id]: rotationAnimatable };
2251
2377
  const scaleAnimatable = {
2252
- id: crypto.randomUUID(),
2378
+ id: (0, import_utils10.createBrowserSafeId)(),
2253
2379
  name: `${mesh.name ?? "Mesh"} scale`,
2254
2380
  type: "vector3",
2255
2381
  default: { x: mesh.scale.x, y: mesh.scale.y, z: mesh.scale.z },
@@ -2260,56 +2386,120 @@ function importMesh(mesh, namespaces, colorLookup) {
2260
2386
  }
2261
2387
  };
2262
2388
  animatables = { ...animatables, [scaleAnimatable.id]: scaleAnimatable };
2263
- const color = mesh.material.color;
2264
- let useEmissive = false;
2265
- if (color.r === 0 && color.g === 0 && color.b === 0 && mesh.material.emissive) {
2266
- color.copy(mesh.material.emissive);
2267
- useEmissive = true;
2268
- }
2269
- const colorName = mesh.material.name;
2270
- const colorAnimatable = {
2271
- id: crypto.randomUUID(),
2272
- name: mesh.material.name ?? `${mesh.name ?? "Mesh"} color`,
2273
- type: "rgb",
2274
- default: { r: color.r, g: color.g, b: color.b },
2275
- constraints: {
2276
- min: [0, 0, 0],
2277
- max: [1, 1, 1]
2278
- },
2389
+ const material = mesh.material;
2390
+ const color = material.color;
2391
+ const colorName = material.name;
2392
+ const label = (suffix) => colorName ? `${colorName} ${suffix}` : `${mesh.name ?? "Mesh"} ${suffix}`;
2393
+ const makeNumberAnimatable = (suffix, value, constraints) => ({
2394
+ id: (0, import_utils10.createBrowserSafeId)(),
2395
+ name: label(suffix),
2396
+ type: "number",
2397
+ default: value,
2398
+ constraints,
2279
2399
  pub: {
2280
2400
  public: true,
2281
- output: mesh.material.name ? `${mesh.material.name} color` : `${mesh.name ?? "Mesh"} color`
2401
+ output: label(suffix)
2282
2402
  }
2283
- };
2284
- const opacityAnimatable = {
2285
- id: crypto.randomUUID(),
2286
- name: mesh.material.name ? `${mesh.material.name} opacity` : `${mesh.name ?? "Mesh"} opacity`,
2287
- type: "number",
2288
- default: mesh.material.opacity,
2403
+ });
2404
+ const makeColorAnimatable = (suffix, value) => ({
2405
+ id: (0, import_utils10.createBrowserSafeId)(),
2406
+ name: label(suffix),
2407
+ type: "rgb",
2408
+ default: { r: value.r, g: value.g, b: value.b },
2289
2409
  constraints: {
2290
- min: 0,
2291
- max: 1
2410
+ min: [0, 0, 0],
2411
+ max: [1, 1, 1]
2292
2412
  },
2293
2413
  pub: {
2294
2414
  public: true,
2295
- output: mesh.material.name ? `${mesh.material.name} opacity` : `${mesh.name ?? "Mesh"} opacity`
2415
+ output: label(suffix)
2296
2416
  }
2417
+ });
2418
+ const colorAnimatable = {
2419
+ ...makeColorAnimatable("color", color),
2420
+ name: material.name ?? `${mesh.name ?? "Mesh"} color`
2297
2421
  };
2298
- let colorId = colorAnimatable.id;
2299
- let opacityId = opacityAnimatable.id;
2422
+ const opacityAnimatable = makeNumberAnimatable("opacity", material.opacity, {
2423
+ min: 0,
2424
+ max: 1
2425
+ });
2426
+ const materialAnimatables = [
2427
+ colorAnimatable,
2428
+ opacityAnimatable
2429
+ ];
2430
+ let roughnessAnimatable;
2431
+ let metalnessAnimatable;
2432
+ let emissiveAnimatable;
2433
+ let emissiveIntensityAnimatable;
2434
+ let shininessAnimatable;
2435
+ let specularAnimatable;
2436
+ if (material.isMeshStandardMaterial) {
2437
+ roughnessAnimatable = makeNumberAnimatable(
2438
+ "roughness",
2439
+ material.roughness,
2440
+ {
2441
+ min: 0,
2442
+ max: 1
2443
+ }
2444
+ );
2445
+ metalnessAnimatable = makeNumberAnimatable(
2446
+ "metalness",
2447
+ material.metalness,
2448
+ {
2449
+ min: 0,
2450
+ max: 1
2451
+ }
2452
+ );
2453
+ emissiveAnimatable = makeColorAnimatable("emissive", material.emissive);
2454
+ emissiveIntensityAnimatable = makeNumberAnimatable(
2455
+ "emissive intensity",
2456
+ material.emissiveIntensity,
2457
+ { min: 0 }
2458
+ );
2459
+ materialAnimatables.push(
2460
+ roughnessAnimatable,
2461
+ metalnessAnimatable,
2462
+ emissiveAnimatable,
2463
+ emissiveIntensityAnimatable
2464
+ );
2465
+ } else if (mesh.material.isMeshPhongMaterial) {
2466
+ const phong = mesh.material;
2467
+ shininessAnimatable = makeNumberAnimatable("shininess", phong.shininess, {
2468
+ min: 0
2469
+ });
2470
+ emissiveAnimatable = makeColorAnimatable("emissive", phong.emissive);
2471
+ emissiveIntensityAnimatable = makeNumberAnimatable(
2472
+ "emissive intensity",
2473
+ phong.emissiveIntensity,
2474
+ { min: 0 }
2475
+ );
2476
+ specularAnimatable = makeColorAnimatable("specular", phong.specular);
2477
+ materialAnimatables.push(
2478
+ shininessAnimatable,
2479
+ emissiveAnimatable,
2480
+ emissiveIntensityAnimatable,
2481
+ specularAnimatable
2482
+ );
2483
+ }
2484
+ let materialIds;
2300
2485
  if (colorName && colorLookup[colorName]) {
2301
- colorId = colorLookup[colorName][0];
2302
- opacityId = colorLookup[colorName][1];
2303
- useEmissive = colorLookup[colorName][2];
2486
+ materialIds = colorLookup[colorName];
2304
2487
  } else {
2305
- animatables = { ...animatables, [colorAnimatable.id]: colorAnimatable };
2306
- animatables = { ...animatables, [opacityAnimatable.id]: opacityAnimatable };
2488
+ materialIds = {
2489
+ color: colorAnimatable.id,
2490
+ opacity: opacityAnimatable.id,
2491
+ roughness: roughnessAnimatable?.id,
2492
+ metalness: metalnessAnimatable?.id,
2493
+ emissive: emissiveAnimatable?.id,
2494
+ emissiveIntensity: emissiveIntensityAnimatable?.id,
2495
+ shininess: shininessAnimatable?.id,
2496
+ specular: specularAnimatable?.id
2497
+ };
2498
+ materialAnimatables.forEach((animatable) => {
2499
+ animatables = { ...animatables, [animatable.id]: animatable };
2500
+ });
2307
2501
  if (colorName) {
2308
- newColorLookup[colorName] = [
2309
- colorAnimatable.id,
2310
- opacityAnimatable.id,
2311
- useEmissive
2312
- ];
2502
+ newColorLookup[colorName] = materialIds;
2313
2503
  }
2314
2504
  }
2315
2505
  const [geometryFeatures, geometryAnimatables, morphTargets] = importGeometry(
@@ -2320,7 +2510,7 @@ function importMesh(mesh, namespaces, colorLookup) {
2320
2510
  const children = [];
2321
2511
  mesh.children.forEach((child) => {
2322
2512
  if (child.isMesh) {
2323
- const [newWorldItems, newAnimatables, childId, newMeshColors] = importMesh(child, namespaces, {
2513
+ const [newWorldItems, newAnimatables, childId, newMeshColors] = importMesh(child, {
2324
2514
  ...colorLookup,
2325
2515
  ...newColorLookup
2326
2516
  });
@@ -2329,7 +2519,7 @@ function importMesh(mesh, namespaces, colorLookup) {
2329
2519
  animatables = { ...animatables, ...newAnimatables };
2330
2520
  children.push(childId);
2331
2521
  } else if (shouldImportAsGroupChild(child)) {
2332
- const [newWorldItems, newAnimatables, childId, newMeshColors] = importGroup(child, namespaces, {
2522
+ const [newWorldItems, newAnimatables, childId, newMeshColors] = importGroup(child, {
2333
2523
  ...colorLookup,
2334
2524
  ...newColorLookup
2335
2525
  });
@@ -2343,7 +2533,7 @@ function importMesh(mesh, namespaces, colorLookup) {
2343
2533
  id: mesh.uuid,
2344
2534
  name: mesh.name,
2345
2535
  geometry: mesh.geometry,
2346
- material: getShapeMaterial(mesh, useEmissive),
2536
+ material: getShapeMaterial(mesh),
2347
2537
  type: "shape",
2348
2538
  tags: [],
2349
2539
  morphTargets,
@@ -2351,21 +2541,28 @@ function importMesh(mesh, namespaces, colorLookup) {
2351
2541
  translation: { animated: true, value: translationAnimatable.id },
2352
2542
  rotation: { animated: true, value: rotationAnimatable.id },
2353
2543
  scale: { animated: true, value: scaleAnimatable.id },
2354
- color: { animated: true, value: colorId },
2355
- opacity: { animated: true, value: opacityId },
2544
+ color: { animated: true, value: materialIds.color },
2545
+ opacity: { animated: true, value: materialIds.opacity },
2546
+ ...materialIds.roughness ? { roughness: { animated: true, value: materialIds.roughness } } : {},
2547
+ ...materialIds.metalness ? { metalness: { animated: true, value: materialIds.metalness } } : {},
2548
+ ...materialIds.emissive ? { emissive: { animated: true, value: materialIds.emissive } } : {},
2549
+ ...materialIds.emissiveIntensity ? {
2550
+ emissiveIntensity: {
2551
+ animated: true,
2552
+ value: materialIds.emissiveIntensity
2553
+ }
2554
+ } : {},
2555
+ ...materialIds.shininess ? { shininess: { animated: true, value: materialIds.shininess } } : {},
2556
+ ...materialIds.specular ? { specular: { animated: true, value: materialIds.specular } } : {},
2356
2557
  ...geometryFeatures
2357
2558
  },
2358
- children: children.length > 0 ? children : void 0,
2359
- refs: namespaceArrayToRefs(namespaces)
2559
+ children: children.length > 0 ? children : void 0
2360
2560
  };
2361
2561
  world = { ...world, [newShape.id]: newShape };
2362
2562
  return [world, animatables, newShape.id, newColorLookup];
2363
2563
  }
2364
- function getShapeMaterial(mesh, useEmissive) {
2564
+ function getShapeMaterial(mesh) {
2365
2565
  const material = mesh.material;
2366
- if (useEmissive) {
2367
- return "basic" /* Basic */;
2368
- }
2369
2566
  if (material.isMeshStandardMaterial) {
2370
2567
  return "standard" /* Standard */;
2371
2568
  } else if (material.isMeshPhongMaterial) {
@@ -2400,14 +2597,14 @@ function shouldImportAsGroupChild(child) {
2400
2597
  }
2401
2598
 
2402
2599
  // src/functions/gltf-loading/import-group.ts
2403
- import_three4.Object3D.DEFAULT_UP.set(0, 0, 1);
2404
- function importGroup(group, namespaces, colorLookup, rootBounds) {
2600
+ import_three5.Object3D.DEFAULT_UP.set(0, 0, 1);
2601
+ function importGroup(group, colorLookup, rootBounds) {
2405
2602
  let world = {};
2406
2603
  let animatables = {};
2407
2604
  let newColorLookup = {};
2408
2605
  const children = [];
2409
2606
  const translationAnimatable = {
2410
- id: crypto.randomUUID(),
2607
+ id: (0, import_utils11.createBrowserSafeId)(),
2411
2608
  name: `${group.name ?? "Group"} translation`,
2412
2609
  type: "vector3",
2413
2610
  default: { x: group.position.x, y: group.position.y, z: group.position.z },
@@ -2423,7 +2620,7 @@ function importGroup(group, namespaces, colorLookup, rootBounds) {
2423
2620
  [translationAnimatable.id]: translationAnimatable
2424
2621
  };
2425
2622
  const rotationAnimatable = {
2426
- id: crypto.randomUUID(),
2623
+ id: (0, import_utils11.createBrowserSafeId)(),
2427
2624
  name: `${group.name ?? "Group"} rotation`,
2428
2625
  type: "euler",
2429
2626
  default: { x: group.rotation.x, y: group.rotation.y, z: group.rotation.z },
@@ -2436,7 +2633,7 @@ function importGroup(group, namespaces, colorLookup, rootBounds) {
2436
2633
  };
2437
2634
  animatables = { ...animatables, [rotationAnimatable.id]: rotationAnimatable };
2438
2635
  const scaleAnimatable = {
2439
- id: crypto.randomUUID(),
2636
+ id: (0, import_utils11.createBrowserSafeId)(),
2440
2637
  name: `${group.name ?? "Group"} scale`,
2441
2638
  type: "vector3",
2442
2639
  default: { x: group.scale.x, y: group.scale.y, z: group.scale.z },
@@ -2449,7 +2646,7 @@ function importGroup(group, namespaces, colorLookup, rootBounds) {
2449
2646
  animatables = { ...animatables, [scaleAnimatable.id]: scaleAnimatable };
2450
2647
  group.children.forEach((child) => {
2451
2648
  if (child.isMesh) {
2452
- const [newWorldItems, newAnimatables, childId, newMeshColors] = importMesh(child, namespaces, {
2649
+ const [newWorldItems, newAnimatables, childId, newMeshColors] = importMesh(child, {
2453
2650
  ...colorLookup,
2454
2651
  ...newColorLookup
2455
2652
  });
@@ -2458,7 +2655,7 @@ function importGroup(group, namespaces, colorLookup, rootBounds) {
2458
2655
  animatables = { ...animatables, ...newAnimatables };
2459
2656
  children.push(childId);
2460
2657
  } else if (shouldImportAsGroupChild2(child)) {
2461
- const [newWorldItems, newAnimatables, childId, newMeshColors] = importGroup(child, namespaces, {
2658
+ const [newWorldItems, newAnimatables, childId, newMeshColors] = importGroup(child, {
2462
2659
  ...colorLookup,
2463
2660
  ...newColorLookup
2464
2661
  });
@@ -2480,8 +2677,7 @@ function importGroup(group, namespaces, colorLookup, rootBounds) {
2480
2677
  },
2481
2678
  root: Boolean(rootBounds),
2482
2679
  rootBounds,
2483
- children,
2484
- refs: namespaceArrayToRefs(namespaces)
2680
+ children
2485
2681
  };
2486
2682
  world = { ...world, [newGroup.id]: newGroup };
2487
2683
  return [world, animatables, newGroup.id, newColorLookup];
@@ -2506,13 +2702,12 @@ function shouldImportAsGroupChild2(child) {
2506
2702
  }
2507
2703
 
2508
2704
  // src/functions/gltf-loading/import-scene.ts
2509
- import_three5.Object3D.DEFAULT_UP.set(0, 0, 1);
2510
- function importScene(scene, namespaces, rootBounds) {
2705
+ import_three6.Object3D.DEFAULT_UP.set(0, 0, 1);
2706
+ function importScene(scene, rootBounds) {
2511
2707
  let world = {};
2512
2708
  let animatables = {};
2513
2709
  const [newWorldItems, newAnimatables] = importGroup(
2514
2710
  scene,
2515
- namespaces,
2516
2711
  {},
2517
2712
  rootBounds
2518
2713
  );
@@ -2523,7 +2718,7 @@ function importScene(scene, namespaces, rootBounds) {
2523
2718
 
2524
2719
  // src/functions/gltf-loading/traverse-three.ts
2525
2720
  THREE4.Object3D.DEFAULT_UP.set(0, 0, 1);
2526
- function traverseThree(group, namespaces, aggressiveImport = false, rootBounds) {
2721
+ function traverseThree(group, aggressiveImport = false, rootBounds) {
2527
2722
  const worldData = {};
2528
2723
  const animatableData = {};
2529
2724
  let hasRobotData = false;
@@ -2546,11 +2741,7 @@ function traverseThree(group, namespaces, aggressiveImport = false, rootBounds)
2546
2741
  switch (data.type) {
2547
2742
  case "group":
2548
2743
  loadedData = {
2549
- ...data,
2550
- refs: namespaces.reduce(
2551
- (acc, ns) => ({ ...acc, [ns]: (0, import_react16.createRef)() }),
2552
- {}
2553
- )
2744
+ ...data
2554
2745
  };
2555
2746
  [mappedFeatures, animatableValues] = mapFeatures(data.features);
2556
2747
  isGroupFeatures(mappedFeatures);
@@ -2561,11 +2752,7 @@ function traverseThree(group, namespaces, aggressiveImport = false, rootBounds)
2561
2752
  case "shape":
2562
2753
  loadedData = {
2563
2754
  ...data,
2564
- geometry: child.geometry,
2565
- refs: namespaces.reduce(
2566
- (acc, ns) => ({ ...acc, [ns]: (0, import_react16.createRef)() }),
2567
- {}
2568
- )
2755
+ geometry: child.geometry
2569
2756
  };
2570
2757
  [mappedFeatures, animatableValues] = mapFeatures(data.features);
2571
2758
  isShapeFeatures(mappedFeatures);
@@ -2575,11 +2762,7 @@ function traverseThree(group, namespaces, aggressiveImport = false, rootBounds)
2575
2762
  break;
2576
2763
  case "ellipse":
2577
2764
  loadedData = {
2578
- ...data,
2579
- refs: namespaces.reduce(
2580
- (acc, ns) => ({ ...acc, [ns]: (0, import_react16.createRef)() }),
2581
- {}
2582
- )
2765
+ ...data
2583
2766
  };
2584
2767
  [mappedFeatures, animatableValues] = mapFeatures(data.features);
2585
2768
  isEllipseFeatures(mappedFeatures);
@@ -2589,11 +2772,7 @@ function traverseThree(group, namespaces, aggressiveImport = false, rootBounds)
2589
2772
  break;
2590
2773
  case "rectangle":
2591
2774
  loadedData = {
2592
- ...data,
2593
- refs: namespaces.reduce(
2594
- (acc, ns) => ({ ...acc, [ns]: (0, import_react16.createRef)() }),
2595
- {}
2596
- )
2775
+ ...data
2597
2776
  };
2598
2777
  [mappedFeatures, animatableValues] = mapFeatures(data.features);
2599
2778
  isRectangleFeatures(mappedFeatures);
@@ -2616,7 +2795,6 @@ function traverseThree(group, namespaces, aggressiveImport = false, rootBounds)
2616
2795
  }
2617
2796
  const [newWorldData, newAnimatableData] = importScene(
2618
2797
  group,
2619
- namespaces,
2620
2798
  derivedRootBounds
2621
2799
  );
2622
2800
  Object.assign(worldData, newWorldData);
@@ -2629,7 +2807,10 @@ var MATERIAL_NAME_FEATURE_KEYS = [
2629
2807
  "opacity",
2630
2808
  "roughness",
2631
2809
  "metalness",
2632
- "shininess"
2810
+ "shininess",
2811
+ "emissive",
2812
+ "emissiveIntensity",
2813
+ "specular"
2633
2814
  ];
2634
2815
  var MATERIAL_NAME_SUFFIXES2 = [
2635
2816
  " color",
@@ -2638,7 +2819,10 @@ var MATERIAL_NAME_SUFFIXES2 = [
2638
2819
  " opacity",
2639
2820
  " roughness",
2640
2821
  " metalness",
2641
- " shininess"
2822
+ " shininess",
2823
+ " emissive intensity",
2824
+ " emissive",
2825
+ " specular"
2642
2826
  ];
2643
2827
  function applyStoredRenderableNames(object, data) {
2644
2828
  if (typeof data.name === "string" && data.name.length > 0) {
@@ -2777,10 +2961,10 @@ function deriveRootBounds(group) {
2777
2961
  }
2778
2962
 
2779
2963
  // src/functions/vizij-bundle.ts
2780
- var import_utils7 = require("@vizij/utils");
2964
+ var import_utils12 = require("@vizij/utils");
2781
2965
  var BUNDLE_KEYS = ["VIZIJ_bundle"];
2782
2966
  function cloneBundle(value) {
2783
- return (0, import_utils7.cloneDeepSafe)(value);
2967
+ return (0, import_utils12.cloneDeepSafe)(value);
2784
2968
  }
2785
2969
  function readExtensionValue(extensionContainer) {
2786
2970
  for (const key of BUNDLE_KEYS) {
@@ -2858,12 +3042,29 @@ function applyVizijBundle(object, bundle) {
2858
3042
  const userData = object.userData && typeof object.userData === "object" ? object.userData : {};
2859
3043
  const originalExtensions = userData.gltfExtensions;
2860
3044
  let applied = false;
3045
+ const staleCarriers = [];
2861
3046
  if (bundle) {
2862
3047
  userData.gltfExtensions = {
2863
3048
  ...originalExtensions ?? {},
2864
3049
  VIZIJ_bundle: bundle
2865
3050
  };
2866
3051
  object.userData = userData;
3052
+ object.traverse((node) => {
3053
+ if (node === object) {
3054
+ return;
3055
+ }
3056
+ const extensions = node.userData?.gltfExtensions;
3057
+ if (!extensions || !(BUNDLE_KEYS[0] in extensions)) {
3058
+ return;
3059
+ }
3060
+ staleCarriers.push({ node, extensions });
3061
+ const { [BUNDLE_KEYS[0]]: _stale, ...rest } = extensions;
3062
+ if (Object.keys(rest).length > 0) {
3063
+ node.userData.gltfExtensions = rest;
3064
+ } else {
3065
+ delete node.userData.gltfExtensions;
3066
+ }
3067
+ });
2867
3068
  applied = true;
2868
3069
  }
2869
3070
  return () => {
@@ -2880,12 +3081,16 @@ function applyVizijBundle(object, bundle) {
2880
3081
  delete object.userData;
2881
3082
  }
2882
3083
  }
3084
+ for (const { node, extensions } of staleCarriers) {
3085
+ node.userData.gltfExtensions = extensions;
3086
+ }
3087
+ staleCarriers.length = 0;
2883
3088
  applied = false;
2884
3089
  };
2885
3090
  }
2886
3091
 
2887
3092
  // src/functions/gltf-loading/extract-animations.ts
2888
- var import_utils8 = require("@vizij/utils");
3093
+ var import_utils13 = require("@vizij/utils");
2889
3094
  var CHANNEL_PATH_TO_TRACK_PROPERTY = {
2890
3095
  translation: "position",
2891
3096
  rotation: "quaternion",
@@ -2901,7 +3106,7 @@ function clonePlainObject(value) {
2901
3106
  if (!value) {
2902
3107
  return void 0;
2903
3108
  }
2904
- return (0, import_utils8.cloneDeepSafe)(value);
3109
+ return (0, import_utils13.cloneDeepSafe)(value);
2905
3110
  }
2906
3111
  function inferValueSize(valueType) {
2907
3112
  switch (valueType) {
@@ -3305,16 +3510,6 @@ async function resolveParserJson(parserJson, fallback) {
3305
3510
  return fromArrayBuffer;
3306
3511
  }
3307
3512
  }
3308
- if (fallback.blob) {
3309
- try {
3310
- const blobBuffer = typeof fallback.blob.arrayBuffer === "function" ? await fallback.blob.arrayBuffer() : await new Response(fallback.blob).arrayBuffer();
3311
- const fromBlob = parseGlbJsonChunk(blobBuffer);
3312
- if (fromBlob && typeof fromBlob === "object") {
3313
- return fromBlob;
3314
- }
3315
- } catch {
3316
- }
3317
- }
3318
3513
  if (fallback.url && typeof fetch === "function") {
3319
3514
  try {
3320
3515
  const response = await fetch(fallback.url);
@@ -3330,81 +3525,21 @@ async function resolveParserJson(parserJson, fallback) {
3330
3525
  }
3331
3526
  return parserJson;
3332
3527
  }
3333
- async function loadGLTF(url, namespaces, aggressiveImport = false, rootBounds) {
3334
- const modelLoader = new import_three_stdlib.GLTFLoader();
3335
- modelLoader.setDRACOLoader(new import_three_stdlib.DRACOLoader());
3336
- const modelData = await modelLoader.loadAsync(url);
3337
- const parserJson = await resolveParserJson(modelData?.parser?.json, {
3338
- url
3339
- });
3340
- const actualizedNamespaces = namespaces.length > 0 ? namespaces : ["default"];
3341
- const asset = parseScene(
3342
- modelData.scene,
3343
- actualizedNamespaces,
3528
+ async function loadGLTF(url, aggressiveImport = false, rootBounds) {
3529
+ const asset = await loadGLTFWithBundle(url, aggressiveImport, rootBounds);
3530
+ return [asset.world, asset.animatables, asset.animations];
3531
+ }
3532
+ async function loadGLTFFromBlob(blob, aggressiveImport = false, rootBounds) {
3533
+ const asset = await loadGLTFFromBlobWithBundle(
3534
+ blob,
3344
3535
  aggressiveImport,
3345
- rootBounds,
3346
- parserJson,
3347
- modelData.animations
3536
+ rootBounds
3348
3537
  );
3349
3538
  return [asset.world, asset.animatables, asset.animations];
3350
3539
  }
3351
- async function loadGLTFFromBlob(blob, namespaces, aggressiveImport = false, rootBounds) {
3352
- const actualizedNamespaces = namespaces.length > 0 ? namespaces : ["default"];
3353
- if (typeof URL !== "undefined" && typeof URL.createObjectURL === "function") {
3354
- const objectUrl = URL.createObjectURL(blob);
3355
- try {
3356
- const asset = await loadGLTFWithBundle(
3357
- objectUrl,
3358
- actualizedNamespaces,
3359
- aggressiveImport,
3360
- rootBounds,
3361
- { blob }
3362
- );
3363
- return [asset.world, asset.animatables, asset.animations];
3364
- } finally {
3365
- URL.revokeObjectURL(objectUrl);
3366
- }
3367
- }
3368
- const arrayBuffer = typeof blob.arrayBuffer === "function" ? await blob.arrayBuffer() : await new Response(blob).arrayBuffer();
3369
- return new Promise((resolve, reject) => {
3370
- const loader = new import_three_stdlib.GLTFLoader();
3371
- loader.setDRACOLoader(new import_three_stdlib.DRACOLoader());
3372
- loader.parse(
3373
- arrayBuffer,
3374
- "",
3375
- async (gltf) => {
3376
- try {
3377
- const parserJson = await resolveParserJson(
3378
- gltf?.parser?.json,
3379
- { arrayBuffer }
3380
- );
3381
- const asset = parseScene(
3382
- gltf.scene,
3383
- actualizedNamespaces,
3384
- aggressiveImport,
3385
- rootBounds,
3386
- parserJson,
3387
- gltf.animations
3388
- );
3389
- resolve([asset.world, asset.animatables, asset.animations]);
3390
- } catch (error) {
3391
- if (error instanceof Error) {
3392
- reject(error);
3393
- } else {
3394
- reject(new Error(String(error)));
3395
- }
3396
- }
3397
- },
3398
- (error) => {
3399
- reject(new Error(`Error loading GLTF: ${error.message}`));
3400
- }
3401
- );
3402
- });
3403
- }
3404
- function parseScene(scene, namespaces, aggressiveImport, rootBounds, parserJson, clips) {
3540
+ function parseScene(scene, aggressiveImport, rootBounds, parserJson, clips) {
3405
3541
  const [world, animatables] = traverseThree(
3406
3542
  scene,
3407
- namespaces,
3408
3543
  aggressiveImport,
3409
3544
  rootBounds
3410
3545
  );
@@ -3412,108 +3547,52 @@ function parseScene(scene, namespaces, aggressiveImport, rootBounds, parserJson,
3412
3547
  const animations = extractVizijAnimations(parserJson, clips);
3413
3548
  return { world, animatables, bundle, animations, scene };
3414
3549
  }
3415
- async function loadGLTFWithBundle(url, namespaces, aggressiveImport = false, rootBounds, parserJsonFallback) {
3550
+ function createTrackedGLTFLoader() {
3551
+ recordRenderCounter("gltfLoadCount");
3552
+ recordRenderCounter("dracoLoaderCreationCount");
3416
3553
  const modelLoader = new import_three_stdlib.GLTFLoader();
3417
3554
  modelLoader.setDRACOLoader(new import_three_stdlib.DRACOLoader());
3555
+ return modelLoader;
3556
+ }
3557
+ async function loadGLTFWithBundle(url, aggressiveImport = false, rootBounds, parserJsonFallback) {
3558
+ recordRenderCounter("gltfUrlLoadCount");
3559
+ const modelLoader = createTrackedGLTFLoader();
3418
3560
  const modelData = await modelLoader.loadAsync(url);
3419
3561
  const parserJson = await resolveParserJson(modelData?.parser?.json, {
3420
3562
  url,
3421
3563
  ...parserJsonFallback
3422
3564
  });
3423
- const actualizedNamespaces = namespaces.length > 0 ? namespaces : ["default"];
3424
3565
  return parseScene(
3425
3566
  modelData.scene,
3426
- actualizedNamespaces,
3427
3567
  aggressiveImport,
3428
3568
  rootBounds,
3429
3569
  parserJson,
3430
3570
  modelData.animations
3431
3571
  );
3432
3572
  }
3433
- async function loadGLTFFromBlobWithBundle(blob, namespaces, aggressiveImport = false, rootBounds) {
3434
- const actualizedNamespaces = namespaces.length > 0 ? namespaces : ["default"];
3435
- if (typeof URL !== "undefined" && typeof URL.createObjectURL === "function") {
3436
- const objectUrl = URL.createObjectURL(blob);
3437
- try {
3438
- return await loadGLTFWithBundle(
3439
- objectUrl,
3440
- actualizedNamespaces,
3441
- aggressiveImport,
3442
- rootBounds,
3443
- { blob }
3444
- );
3445
- } finally {
3446
- URL.revokeObjectURL(objectUrl);
3447
- }
3448
- }
3449
- const arrayBuffer = typeof blob.arrayBuffer === "function" ? await blob.arrayBuffer() : await new Response(blob).arrayBuffer();
3450
- return new Promise((resolve, reject) => {
3451
- const loader = new import_three_stdlib.GLTFLoader();
3452
- loader.setDRACOLoader(new import_three_stdlib.DRACOLoader());
3453
- loader.parse(
3454
- arrayBuffer,
3455
- "",
3456
- async (gltf) => {
3457
- try {
3458
- const parserJson = await resolveParserJson(
3459
- gltf?.parser?.json,
3460
- { arrayBuffer }
3461
- );
3462
- const asset = parseScene(
3463
- gltf.scene,
3464
- actualizedNamespaces,
3465
- aggressiveImport,
3466
- rootBounds,
3467
- parserJson,
3468
- gltf.animations
3469
- );
3470
- resolve(asset);
3471
- } catch (error) {
3472
- if (error instanceof Error) {
3473
- reject(error);
3474
- } else {
3475
- reject(new Error(String(error)));
3476
- }
3477
- }
3478
- },
3479
- (error) => {
3480
- reject(new Error(`Error loading GLTF: ${error.message}`));
3481
- }
3482
- );
3573
+ async function loadGLTFFromBlobWithBundle(blob, aggressiveImport = false, rootBounds) {
3574
+ recordRenderCounter("gltfBlobLoadCount");
3575
+ const arrayBuffer = await blob.arrayBuffer();
3576
+ const loader = createTrackedGLTFLoader();
3577
+ const gltf = await new Promise((resolve, reject) => {
3578
+ loader.parse(arrayBuffer, "", resolve, (error) => {
3579
+ reject(new Error(`Error loading GLTF: ${error.message}`));
3580
+ });
3483
3581
  });
3484
- }
3485
-
3486
- // src/functions/load-gltf-blob.ts
3487
- var import_three_stdlib2 = require("three-stdlib");
3488
- var loadGltfFromBlob = (blob, namespaces) => {
3489
- return new Promise((resolve, reject) => {
3490
- const loader = new import_three_stdlib2.GLTFLoader();
3491
- loader.setDRACOLoader(new import_three_stdlib2.DRACOLoader());
3492
- const reader = new FileReader();
3493
- reader.onload = () => {
3494
- const arrayBuffer = reader.result;
3495
- loader.parse(
3496
- arrayBuffer,
3497
- "",
3498
- // Base path for resolving external resources
3499
- (gltf) => {
3500
- const actualizedNamespaces = namespaces.length > 0 ? namespaces : ["default"];
3501
- resolve(traverseThree(gltf.scene, actualizedNamespaces));
3502
- },
3503
- (error) => {
3504
- reject(new Error(`Error loading GLTF: ${error.message}`));
3505
- }
3506
- );
3507
- };
3508
- reader.onerror = () => {
3509
- reject(new Error("Failed to read Blob as ArrayBuffer."));
3510
- };
3511
- reader.readAsArrayBuffer(blob);
3582
+ const parserJson = await resolveParserJson(gltf?.parser?.json, {
3583
+ arrayBuffer
3512
3584
  });
3513
- };
3585
+ return parseScene(
3586
+ gltf.scene,
3587
+ aggressiveImport,
3588
+ rootBounds,
3589
+ parserJson,
3590
+ gltf.animations
3591
+ );
3592
+ }
3514
3593
 
3515
3594
  // src/functions/export.ts
3516
- var import_three_stdlib3 = require("three-stdlib");
3595
+ var import_three_stdlib2 = require("three-stdlib");
3517
3596
  var THREE6 = __toESM(require("three"));
3518
3597
  THREE6.Object3D.DEFAULT_UP.set(0, 0, 1);
3519
3598
  function normalizeExportError(error) {
@@ -3525,17 +3604,6 @@ function normalizeExportError(error) {
3525
3604
  }
3526
3605
  return new Error("Failed to export scene.");
3527
3606
  }
3528
- function triggerBlobDownload(blob, filename) {
3529
- const url = URL.createObjectURL(blob);
3530
- const link = document.createElement("a");
3531
- link.href = url;
3532
- link.download = filename;
3533
- link.style.display = "none";
3534
- document.body.appendChild(link);
3535
- link.click();
3536
- document.body.removeChild(link);
3537
- setTimeout(() => URL.revokeObjectURL(url), 0);
3538
- }
3539
3607
  var GLB_MAGIC2 = 1179937895;
3540
3608
  var GLB_VERSION2 = 2;
3541
3609
  var GLB_JSON_CHUNK_TYPE2 = 1313821514;
@@ -3617,7 +3685,7 @@ function normalizeExportedSceneJson(json, fallbackSceneName) {
3617
3685
  }
3618
3686
  return changed;
3619
3687
  }
3620
- function sanitizeExportedGlb(buffer, fallbackSceneName) {
3688
+ function patchGlbJson(buffer, mutate) {
3621
3689
  if (buffer.byteLength < GLB_HEADER_BYTES2 + GLB_CHUNK_HEADER_BYTES2) {
3622
3690
  return buffer;
3623
3691
  }
@@ -3647,8 +3715,7 @@ function sanitizeExportedGlb(buffer, fallbackSceneName) {
3647
3715
  } catch {
3648
3716
  return buffer;
3649
3717
  }
3650
- const changed = normalizeExportedSceneJson(jsonPayload, fallbackSceneName);
3651
- if (!changed) {
3718
+ if (!mutate(jsonPayload)) {
3652
3719
  return buffer;
3653
3720
  }
3654
3721
  const encodedJson = new TextEncoder().encode(JSON.stringify(jsonPayload));
@@ -3670,12 +3737,42 @@ function sanitizeExportedGlb(buffer, fallbackSceneName) {
3670
3737
  sanitizedBytes.set(remainingChunks, jsonChunkStart + paddedJsonLength);
3671
3738
  return sanitized;
3672
3739
  }
3673
- function exportScene(data, fileNameOrOptions = "scene.glb") {
3674
- const options = typeof fileNameOrOptions === "string" ? { fileName: fileNameOrOptions } : fileNameOrOptions ?? {};
3675
- const fileName = options.fileName ?? "scene.glb";
3676
- const animationClips = Array.isArray(options.animations) ? options.animations.filter(Boolean) : [];
3677
- const shouldAttachBundle = Boolean(options.bundle);
3678
- const exporter = new import_three_stdlib3.GLTFExporter();
3740
+ function sanitizeExportedGlb(buffer, fallbackSceneName) {
3741
+ return patchGlbJson(
3742
+ buffer,
3743
+ (json) => normalizeExportedSceneJson(json, fallbackSceneName)
3744
+ );
3745
+ }
3746
+ function patchVizijBundleMetadata(glb, metadata) {
3747
+ return patchGlbJson(glb, (json) => {
3748
+ const carriers = [];
3749
+ const rootExtensions = json.extensions;
3750
+ if (rootExtensions && typeof rootExtensions === "object") {
3751
+ carriers.push(rootExtensions);
3752
+ }
3753
+ const nodes = Array.isArray(json.nodes) ? json.nodes : [];
3754
+ for (const node of nodes) {
3755
+ const extensions = node?.extensions;
3756
+ if (extensions && typeof extensions === "object") {
3757
+ carriers.push(extensions);
3758
+ }
3759
+ }
3760
+ let patched = false;
3761
+ for (const extensions of carriers) {
3762
+ const bundle = extensions.VIZIJ_bundle;
3763
+ if (!bundle || typeof bundle !== "object") {
3764
+ continue;
3765
+ }
3766
+ const record = bundle;
3767
+ const existing = record.metadata && typeof record.metadata === "object" ? record.metadata : {};
3768
+ record.metadata = { ...existing, ...metadata };
3769
+ patched = true;
3770
+ }
3771
+ return patched;
3772
+ });
3773
+ }
3774
+ async function exportScene(root, options = {}) {
3775
+ const exporter = new import_three_stdlib2.GLTFExporter();
3679
3776
  exporter.register(() => ({
3680
3777
  writeMesh(mesh, meshDef) {
3681
3778
  const meshName = mesh.name?.trim() || mesh.geometry?.name?.trim() || void 0;
@@ -3684,82 +3781,324 @@ function exportScene(data, fileNameOrOptions = "scene.glb") {
3684
3781
  }
3685
3782
  }
3686
3783
  }));
3687
- const sourceRoot = data;
3688
- const exportRoot = sourceRoot instanceof THREE6.Scene ? sourceRoot : sourceRoot.clone(true);
3784
+ const exportRoot = root instanceof THREE6.Scene ? root : root.clone(true);
3689
3785
  const exportTarget = exportRoot instanceof THREE6.Scene ? exportRoot : (() => {
3690
3786
  const scene = new THREE6.Scene();
3691
- scene.name = data.name?.trim() || "Scene";
3787
+ scene.name = root.name?.trim() || "Scene";
3692
3788
  scene.add(exportRoot);
3693
3789
  return scene;
3694
3790
  })();
3695
- const detachBundle = shouldAttachBundle && options.bundle ? applyVizijBundle(exportRoot, options.bundle) : () => {
3791
+ const detachBundle = options.bundle ? applyVizijBundle(exportRoot, options.bundle) : () => {
3696
3792
  };
3697
- const binary = options.binary ?? true;
3698
- const exporterOptions = {
3699
- trs: true,
3700
- onlyVisible: false,
3701
- binary,
3702
- includeCustomExtensions: true
3703
- };
3704
- if (animationClips.length > 0) {
3705
- exporterOptions.animations = animationClips;
3706
- }
3793
+ const animations = (options.animations ?? []).filter(Boolean);
3794
+ let gltf;
3707
3795
  try {
3708
- exporter.parse(
3709
- exportTarget,
3710
- (gltf) => {
3711
- detachBundle();
3712
- if (!(gltf instanceof ArrayBuffer)) {
3713
- const error = new Error("Failed to export scene.");
3714
- options.onError?.(error);
3715
- return;
3716
- }
3717
- const sanitizedGltf = sanitizeExportedGlb(
3718
- gltf,
3719
- data.name?.trim() || void 0
3720
- );
3721
- const trimmed = fileName.trim();
3722
- const safeFileName = trimmed.length > 0 ? trimmed : "scene.glb";
3723
- const downloadName = safeFileName.toLowerCase().endsWith(".glb") ? safeFileName : `${safeFileName}.glb`;
3724
- triggerBlobDownload(
3725
- new Blob([sanitizedGltf], {
3726
- type: "application/octet-stream"
3727
- }),
3728
- downloadName
3729
- );
3730
- options.onComplete?.();
3731
- },
3732
- (error) => {
3733
- detachBundle();
3734
- options.onError?.(normalizeExportError(error));
3735
- },
3736
- exporterOptions
3737
- );
3796
+ gltf = await exporter.parseAsync(exportTarget, {
3797
+ trs: true,
3798
+ onlyVisible: false,
3799
+ binary: true,
3800
+ includeCustomExtensions: true,
3801
+ ...animations.length > 0 ? { animations } : {}
3802
+ });
3738
3803
  } catch (error) {
3804
+ throw normalizeExportError(error);
3805
+ } finally {
3739
3806
  detachBundle();
3740
- const normalizedError = normalizeExportError(error);
3741
- options.onError?.(normalizedError);
3742
- throw normalizedError;
3807
+ }
3808
+ if (!(gltf instanceof ArrayBuffer)) {
3809
+ throw new Error("Failed to export scene.");
3810
+ }
3811
+ return sanitizeExportedGlb(gltf, root.name?.trim() || void 0);
3812
+ }
3813
+
3814
+ // src/functions/build-scene-graph.ts
3815
+ var THREE7 = __toESM(require("three"));
3816
+ var import_utils14 = require("@vizij/utils");
3817
+ THREE7.Object3D.DEFAULT_UP.set(0, 0, 1);
3818
+ function buildSceneGraph(world, animatables, rootId) {
3819
+ const entry = world[rootId];
3820
+ if (!entry) {
3821
+ throw new Error(`The world has no element "${rootId}".`);
3822
+ }
3823
+ const used = {};
3824
+ for (const feature of Object.values(entry.features)) {
3825
+ if (feature.animated) {
3826
+ used[feature.value] = animatableOf(animatables, feature.value);
3827
+ }
3828
+ }
3829
+ const robotData = createStoredRenderable(entry, used);
3830
+ switch (entry.type) {
3831
+ case "group": {
3832
+ const object = new THREE7.Group();
3833
+ object.name = entry.name;
3834
+ object.userData = { gltfExtensions: { RobotData: robotData } };
3835
+ applyFeatures(entry.features, animatables, groupTransform(object));
3836
+ for (const child of entry.children) {
3837
+ object.add(buildSceneGraph(world, animatables, child));
3838
+ }
3839
+ return object;
3840
+ }
3841
+ case "shape": {
3842
+ const geometry = entry.geometry.clone();
3843
+ if (entry.name) {
3844
+ geometry.name = entry.name;
3845
+ }
3846
+ const material = createMaterial(entry.material);
3847
+ material.name = deriveMaterialName(entry, used) ?? entry.name ?? "";
3848
+ const object = new THREE7.Mesh(geometry, material);
3849
+ object.name = entry.name;
3850
+ object.userData = { gltfExtensions: { RobotData: robotData } };
3851
+ applyFeatures(entry.features, animatables, {
3852
+ ...shapeTransform(object),
3853
+ ...materialFactors(material),
3854
+ ...morphWeights(object, entry)
3855
+ });
3856
+ for (const child of entry.children ?? []) {
3857
+ object.add(buildSceneGraph(world, animatables, child));
3858
+ }
3859
+ return object;
3860
+ }
3861
+ default:
3862
+ throw new Error(
3863
+ `Element "${rootId}" is a ${entry.type}, which has no exported form.`
3864
+ );
3865
+ }
3866
+ }
3867
+ function animatableOf(animatables, id) {
3868
+ const animatable = animatables[id];
3869
+ if (!animatable) {
3870
+ throw new Error(`No animatable "${id}".`);
3871
+ }
3872
+ return animatable;
3873
+ }
3874
+ function applyFeatures(features, animatables, handlers) {
3875
+ for (const [key, handler] of Object.entries(handlers)) {
3876
+ const feature = features[key];
3877
+ if (!feature) {
3878
+ continue;
3879
+ }
3880
+ const value = feature.animated ? authoredDefault(animatableOf(animatables, feature.value)) : feature.value;
3881
+ if (value !== void 0) {
3882
+ handler(value);
3883
+ }
3884
+ }
3885
+ }
3886
+ function groupTransform(object) {
3887
+ return {
3888
+ translation: (value) => {
3889
+ if ((0, import_utils14.instanceOfRawVector3)(value)) {
3890
+ object.position.set(value.x, value.y, value.z);
3891
+ } else if ((0, import_utils14.instanceOfRawVector2)(value)) {
3892
+ object.position.set(value.x, value.y, object.position.z);
3893
+ }
3894
+ },
3895
+ rotation: (value) => {
3896
+ if ((0, import_utils14.instanceOfRawEuler)(value)) {
3897
+ object.rotation.set(value.x, value.y, value.z, "ZYX");
3898
+ } else if ((0, import_utils14.instanceOfRawNumber)(value)) {
3899
+ object.rotation.set(0, 0, 0);
3900
+ object.rotateZ(value);
3901
+ }
3902
+ },
3903
+ scale: (value) => {
3904
+ if ((0, import_utils14.instanceOfRawVector3)(value)) {
3905
+ if (value.x === null || value.y === null || value.z === null) {
3906
+ object.scale.set(0.1, 0.1, 0.1);
3907
+ } else {
3908
+ object.scale.set(value.x, value.y, value.z);
3909
+ }
3910
+ } else if ((0, import_utils14.instanceOfRawNumber)(value)) {
3911
+ object.scale.set(value, value, value);
3912
+ } else {
3913
+ object.scale.set(1, 1, 1);
3914
+ }
3915
+ }
3916
+ };
3917
+ }
3918
+ function shapeTransform(object) {
3919
+ return {
3920
+ translation: (value) => {
3921
+ if ((0, import_utils14.instanceOfRawVector3)(value)) {
3922
+ object.position.set(value.x, value.y, value.z);
3923
+ }
3924
+ },
3925
+ rotation: (value) => {
3926
+ if ((0, import_utils14.instanceOfRawEuler)(value)) {
3927
+ object.rotation.set(value.x, value.y, value.z, "ZYX");
3928
+ }
3929
+ },
3930
+ scale: (value) => {
3931
+ if ((0, import_utils14.instanceOfRawVector3)(value)) {
3932
+ object.scale.set(value.x, value.y, value.z);
3933
+ } else if ((0, import_utils14.instanceOfRawNumber)(value)) {
3934
+ object.scale.set(value, value, value);
3935
+ } else {
3936
+ object.scale.set(1, 1, 1);
3937
+ }
3938
+ }
3939
+ };
3940
+ }
3941
+ function materialFactors(material) {
3942
+ const standard = material;
3943
+ const phong = material;
3944
+ return {
3945
+ opacity: (value) => {
3946
+ if ((0, import_utils14.instanceOfRawNumber)(value)) {
3947
+ material.opacity = value;
3948
+ material.transparent = value < 1;
3949
+ }
3950
+ },
3951
+ color: (value) => {
3952
+ if (!standard.color) {
3953
+ return;
3954
+ }
3955
+ if ((0, import_utils14.instanceOfRawRGB)(value)) {
3956
+ standard.color.setRGB(value.r, value.g, value.b);
3957
+ } else if ((0, import_utils14.instanceOfRawVector3)(value)) {
3958
+ standard.color.setRGB(value.x, value.y, value.z);
3959
+ } else if ((0, import_utils14.instanceOfRawHSL)(value)) {
3960
+ standard.color.setHSL(value.h, value.s, value.l);
3961
+ }
3962
+ },
3963
+ roughness: (value) => {
3964
+ if (standard.roughness !== void 0 && (0, import_utils14.instanceOfRawNumber)(value)) {
3965
+ standard.roughness = value;
3966
+ }
3967
+ },
3968
+ metalness: (value) => {
3969
+ if (standard.metalness !== void 0 && (0, import_utils14.instanceOfRawNumber)(value)) {
3970
+ standard.metalness = value;
3971
+ }
3972
+ },
3973
+ shininess: (value) => {
3974
+ if (phong.shininess !== void 0 && (0, import_utils14.instanceOfRawNumber)(value)) {
3975
+ phong.shininess = value;
3976
+ }
3977
+ },
3978
+ emissive: (value) => {
3979
+ if (standard.emissive && (0, import_utils14.instanceOfRawRGB)(value)) {
3980
+ standard.emissive.setRGB(value.r, value.g, value.b);
3981
+ }
3982
+ },
3983
+ emissiveIntensity: (value) => {
3984
+ if (standard.emissiveIntensity !== void 0 && (0, import_utils14.instanceOfRawNumber)(value)) {
3985
+ standard.emissiveIntensity = value;
3986
+ }
3987
+ },
3988
+ specular: (value) => {
3989
+ if (phong.specular && (0, import_utils14.instanceOfRawRGB)(value)) {
3990
+ phong.specular.setRGB(value.r, value.g, value.b);
3991
+ }
3992
+ }
3993
+ };
3994
+ }
3995
+ function morphWeights(object, shape) {
3996
+ const targets = shape.morphTargets ?? [];
3997
+ if (targets.length === 0) {
3998
+ return {};
3999
+ }
4000
+ const influences = targets.map(() => 0);
4001
+ object.morphTargetDictionary = Object.fromEntries(
4002
+ targets.map((target, index) => [target, index])
4003
+ );
4004
+ object.morphTargetInfluences = influences;
4005
+ return Object.fromEntries(
4006
+ targets.map((target, index) => [
4007
+ target,
4008
+ (value) => {
4009
+ if ((0, import_utils14.instanceOfRawNumber)(value)) {
4010
+ influences[index] = value;
4011
+ }
4012
+ }
4013
+ ])
4014
+ );
4015
+ }
4016
+ function createMaterial(kind) {
4017
+ const parameters = { side: THREE7.DoubleSide };
4018
+ switch (kind) {
4019
+ case "basic" /* Basic */:
4020
+ return new THREE7.MeshBasicMaterial(parameters);
4021
+ case "lambert" /* Lambert */:
4022
+ return new THREE7.MeshLambertMaterial(parameters);
4023
+ case "phong" /* Phong */:
4024
+ return new THREE7.MeshPhongMaterial(parameters);
4025
+ case "normal" /* Normal */:
4026
+ return new THREE7.MeshNormalMaterial(parameters);
4027
+ case "standard" /* Standard */:
4028
+ return new THREE7.MeshStandardMaterial(parameters);
4029
+ }
4030
+ }
4031
+ var SCALAR_KEYS = ["f32", "f64", "i64", "i32", "u64", "u32", "float"];
4032
+ function scalarOf(value) {
4033
+ if (typeof value === "number") {
4034
+ return value;
4035
+ }
4036
+ if (value && typeof value === "object") {
4037
+ for (const key of SCALAR_KEYS) {
4038
+ const scalar = value[key];
4039
+ if (typeof scalar === "number") {
4040
+ return scalar;
4041
+ }
4042
+ }
4043
+ }
4044
+ return void 0;
4045
+ }
4046
+ function authoredDefault(animatable) {
4047
+ const value = animatable.default;
4048
+ const scalar = scalarOf(value);
4049
+ if (scalar !== void 0) {
4050
+ return scalar;
4051
+ }
4052
+ const fields = value?.struct?.fields;
4053
+ if (!Array.isArray(fields)) {
4054
+ return value;
4055
+ }
4056
+ const n = fields.map(
4057
+ (field) => scalarOf(field?.value) ?? 0
4058
+ );
4059
+ switch (animatable.type) {
4060
+ case "vector3":
4061
+ case "euler":
4062
+ return { x: n[0], y: n[1], z: n[2] };
4063
+ case "vector2":
4064
+ return { x: n[0], y: n[1] };
4065
+ case "rgb":
4066
+ return { r: n[0], g: n[1], b: n[2] };
4067
+ case "hsl":
4068
+ return { h: n[0], s: n[1], l: n[2] };
4069
+ default:
4070
+ return void 0;
3743
4071
  }
3744
4072
  }
3745
4073
  // Annotate the CommonJS export names for ESM import in node:
3746
4074
  0 && (module.exports = {
4075
+ DEFAULT_TONE_MAPPING_MODE,
3747
4076
  EmptyModelError,
3748
4077
  InnerVizij,
3749
4078
  ShapeMaterial,
4079
+ TONE_MAPPING_LABELS,
4080
+ TONE_MAPPING_MODES,
3750
4081
  Vizij,
3751
4082
  VizijContext,
3752
4083
  VizijSlice,
3753
4084
  applyVizijBundle,
4085
+ buildSceneGraph,
3754
4086
  createVizijStore,
4087
+ deriveMorphFeatureKeys,
4088
+ deriveRootBounds,
3755
4089
  exportScene,
3756
4090
  extractVizijBundle,
4091
+ isToneMappingMode,
3757
4092
  loadGLTF,
3758
4093
  loadGLTFFromBlob,
3759
4094
  loadGLTFFromBlobWithBundle,
3760
4095
  loadGLTFWithBundle,
3761
- loadGltfFromBlob,
4096
+ normalizeToneMappingMode,
3762
4097
  parseGlbJsonChunk,
4098
+ patchGlbJson,
4099
+ patchVizijBundleMetadata,
4100
+ resolveToneMapping,
4101
+ sanitizeMorphKey,
3763
4102
  useDefaultVizijStore,
3764
4103
  useFeatures,
3765
4104
  useVizijStore,