@2112-lab/central-plant 0.3.35 → 0.3.37

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.
@@ -35,7 +35,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
35
35
  * Initialize the CentralPlant manager
36
36
  *
37
37
  * @constructor
38
- * @version 0.3.35
38
+ * @version 0.3.37
39
39
  * @updated 2025-10-22
40
40
  *
41
41
  * @description Creates a new CentralPlant instance and initializes internal managers and utilities.
@@ -224,12 +224,13 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
224
224
  behaviors: ((_this$importedSceneDa3 = this.importedSceneData.behaviors) === null || _this$importedSceneDa3 === void 0 ? void 0 : _this$importedSceneDa3.length) || 0,
225
225
  timestamp: new Date().toISOString()
226
226
  });
227
- console.log('[Behavior] Scene behaviors detail:', this.importedSceneData.behaviors);
227
+
228
+ // Scene behaviors loaded
228
229
 
229
230
  // Register behaviors with IoBehaviorManager
230
231
  ioBehavMgr = (_this$sceneViewer = this.sceneViewer) === null || _this$sceneViewer === void 0 || (_this$sceneViewer = _this$sceneViewer.managers) === null || _this$sceneViewer === void 0 ? void 0 : _this$sceneViewer.ioBehaviorManager;
231
232
  if (ioBehavMgr) {
232
- console.log('[Behavior] Calling setCrossComponentBehaviors with:', this.importedSceneData.behaviors || []);
233
+ // Setting cross-component behaviors
233
234
  ioBehavMgr.setCrossComponentBehaviors(this.importedSceneData.behaviors || []);
234
235
  } else {
235
236
  console.warn('[Behavior] ioBehaviorManager not available!');
@@ -728,7 +729,6 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
728
729
 
729
730
  // Enable drag functionality for the specific element
730
731
  this.sceneViewer.managers.componentDragManager.enableElementDrag(element, componentId);
731
- console.log("\u2705 enableDragDrop(): Enabled drag and drop for ".concat(componentId));
732
732
  return true;
733
733
  } catch (error) {
734
734
  console.error('❌ enableDragDrop(): Error enabling drag and drop:', error);
@@ -764,7 +764,6 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
764
764
  }
765
765
  try {
766
766
  this.sceneViewer.managers.componentDragManager.disableElementDrag(element);
767
- console.log('✅ disableDragDrop(): Disabled drag and drop for element');
768
767
  return true;
769
768
  } catch (error) {
770
769
  console.error('❌ disableDragDrop(): Error disabling drag and drop:', error);
@@ -798,7 +797,6 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
798
797
  if (this.sceneViewer.managers.componentDragManager) {
799
798
  this.sceneViewer.managers.componentDragManager.setEnabled(enabled);
800
799
  }
801
- console.log("\u2705 setDragDropEnabled(): Drag and drop ".concat(enabled ? 'enabled' : 'disabled'));
802
800
  return true;
803
801
  } catch (error) {
804
802
  console.error('❌ setDragDropEnabled(): Error setting drag and drop state:', error);
@@ -236,12 +236,10 @@ var CentralPlantInternals = /*#__PURE__*/function () {
236
236
  if (this.centralPlant.sceneViewer.$refs.container && this.centralPlant.sceneViewer.camera && this.centralPlant.sceneViewer.scene) {
237
237
  this.centralPlant.managers.tooltipsManager = new sceneTooltipsManager.SceneTooltipsManager(this.centralPlant.sceneViewer.$refs.container, this.centralPlant.sceneViewer.camera, this.centralPlant.sceneViewer.scene);
238
238
  this.centralPlant.sceneViewer.tooltipsManager = this.centralPlant.managers.tooltipsManager;
239
- console.log('🔍 Tooltip manager initialized:', this.centralPlant.managers.tooltipsManager);
240
239
 
241
240
  // Initialize the component tooltip manager (screen-space tooltip on selection)
242
241
  this.centralPlant.managers.componentTooltipManager = new componentTooltipManager.ComponentTooltipManager(this.centralPlant.sceneViewer);
243
242
  this.centralPlant.sceneViewer.componentTooltipManager = this.centralPlant.managers.componentTooltipManager;
244
- console.log('🔍 Component tooltip manager initialized');
245
243
  }
246
244
  }
247
245
 
@@ -1177,7 +1175,7 @@ var CentralPlantInternals = /*#__PURE__*/function () {
1177
1175
 
1178
1176
  // Register component-level behaviors (intra-component io-device linking)
1179
1177
  if (componentData.behaviors && componentData.behaviors.length > 0) {
1180
- console.log("[DragDrop] Registering ".concat(componentData.behaviors.length, " component-level behavior(s) for ").concat(componentId));
1178
+ // Registering ${componentData.behaviors.length} component-level behavior(s)
1181
1179
  ioBehavMgr.registerComponentBehaviors(componentId, componentData.behaviors);
1182
1180
  }
1183
1181
  }
@@ -121,6 +121,7 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
121
121
  entries.push({
122
122
  anim: anim,
123
123
  mesh: mesh,
124
+ deviceModelRoot: deviceModelRoot,
124
125
  origPos: mesh.position.clone(),
125
126
  origRot: mesh.rotation.clone(),
126
127
  origWorldPos: worldPos,
@@ -137,9 +138,7 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
137
138
  }
138
139
  if (entries.length) {
139
140
  this._entries.set(key, entries);
140
- console.log("[IoBehaviorManager] Loaded ".concat(entries.length, " animation(s) for attachment \"").concat(attachmentId, "\" (parent: ").concat(parentUuid, ") \u2014 stateVariables: ").concat(entries.map(function (e) {
141
- return e.anim.stateVariable;
142
- }).join(', ')));
141
+ // Loaded ${entries.length} animation(s) for attachment "${attachmentId}"
143
142
  } else {
144
143
  console.warn("[IoBehaviorManager] No mesh entries resolved for attachment \"".concat(attachmentId, "\" \u2014 behaviorConfig had ").concat(anims.length, " entries but none matched a mesh"));
145
144
  }
@@ -157,13 +156,8 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
157
156
  }, {
158
157
  key: "triggerState",
159
158
  value: function triggerState(attachmentId, dataPointId, value, parentUuid) {
160
- var _this$_crossComponent;
161
- console.log("[Behavior] triggerState called:", {
162
- attachmentId: attachmentId,
163
- dataPointId: dataPointId,
164
- value: value,
165
- parentUuid: parentUuid
166
- });
159
+ // triggerState: ${attachmentId}.${dataPointId} = ${value}
160
+
167
161
  if (parentUuid) {
168
162
  var key = this._key(parentUuid, attachmentId);
169
163
  var entries = this._entries.get(key);
@@ -218,12 +212,12 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
218
212
  // Evaluate component-level behaviors (intra-component io-device linking)
219
213
  if (parentUuid && this._componentBehaviors.has(parentUuid)) {
220
214
  var componentBehaviors = this._componentBehaviors.get(parentUuid);
221
- console.log("[Behavior] Checking component-level behaviors for ".concat(parentUuid, " (count: ").concat(componentBehaviors.length, ")"));
215
+ // Checking component-level behaviors (count: ${componentBehaviors.length})
222
216
  this.triggerCrossComponentBehaviors(componentBehaviors, parentUuid, attachmentId, dataPointId, value);
223
217
  }
224
218
 
225
219
  // Evaluate cross-component behaviors if any are registered
226
- console.log("[Behavior] Checking cross-component behaviors (count: ".concat(((_this$_crossComponent = this._crossComponentBehaviors) === null || _this$_crossComponent === void 0 ? void 0 : _this$_crossComponent.length) || 0, ")"));
220
+ // Checking cross-component behaviors (count: ${this._crossComponentBehaviors?.length || 0})
227
221
  if (this._crossComponentBehaviors && this._crossComponentBehaviors.length > 0) {
228
222
  this.triggerCrossComponentBehaviors(this._crossComponentBehaviors, parentUuid, attachmentId, dataPointId, value);
229
223
  }
@@ -242,7 +236,7 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
242
236
  this._crossComponentBehaviors = (behaviors || []).map(function (b) {
243
237
  return _this2._normalizeBehavior(b);
244
238
  });
245
- console.log("[Behavior] Loaded ".concat(this._crossComponentBehaviors.length, " cross-component behavior(s)"), this._crossComponentBehaviors);
239
+ // Loaded ${this._crossComponentBehaviors.length} cross-component behavior(s)
246
240
  }
247
241
 
248
242
  /**
@@ -261,7 +255,7 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
261
255
  return _this3._normalizeBehavior(b);
262
256
  });
263
257
  this._componentBehaviors.set(componentUuid, normalized);
264
- console.log("[Behavior] Registered ".concat(normalized.length, " component-level behavior(s) for component ").concat(componentUuid), normalized);
258
+ // Registered ${normalized.length} component-level behavior(s) for component ${componentUuid}
265
259
  }
266
260
 
267
261
  /**
@@ -372,7 +366,7 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
372
366
  key: "configure",
373
367
  value: function configure(stateAdapter) {
374
368
  this._stateAdapter = stateAdapter || null;
375
- console.log('[Behavior] State adapter configured:', !!this._stateAdapter);
369
+ // State adapter configured
376
370
  }
377
371
 
378
372
  /**
@@ -388,10 +382,10 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
388
382
  key: "triggerCrossComponentBehaviors",
389
383
  value: function triggerCrossComponentBehaviors(behaviors, triggerParentUuid, triggerAttachmentId, triggerStateId, value) {
390
384
  if (!behaviors || !Array.isArray(behaviors)) {
391
- console.log('[Behavior] No behaviors to evaluate');
392
385
  return;
393
386
  }
394
- console.log("[Behavior] Evaluating ".concat(behaviors.length, " behavior(s) for trigger: ").concat(triggerParentUuid, ".").concat(triggerAttachmentId, ".").concat(triggerStateId, " = ").concat(value));
387
+
388
+ // Evaluating ${behaviors.length} behavior(s)
395
389
  var _iterator5 = _rollupPluginBabelHelpers.createForOfIteratorHelper(behaviors),
396
390
  _step5;
397
391
  try {
@@ -426,7 +420,7 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
426
420
 
427
421
  // Verify that the input matches the triggering source
428
422
  if (inputComponent === triggerParentUuid && input.attachment === triggerAttachmentId && input.state === triggerStateId) {
429
- console.log("[Behavior] \u2713 Behavior \"".concat(behavior.id, "\" matched!"));
423
+ // Behavior "${behavior.id}" matched
430
424
 
431
425
  // Collect all outputs (single or multiple)
432
426
  var outputs = _outputs || (output ? [output] : []);
@@ -444,14 +438,13 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
444
438
 
445
439
  // Direct state mapping without conditions
446
440
  if (this._stateAdapter) {
447
- console.log("[Behavior] Dispatching state-to-state: ".concat(out.attachment, ".").concat(out.state, " = ").concat(value));
441
+ // Dispatching state-to-state: ${out.attachment}.${out.state} = ${value}
448
442
  this._stateAdapter.setState(out.attachment, out.state, value);
449
- console.log("[Behavior] \u2713 State-to-state triggered: ".concat(input.attachment, ".").concat(input.state, " (").concat(value, ") \u2192 ").concat(out.attachment, ".").concat(out.state));
450
443
 
451
444
  // Trigger animations on the output component
452
445
  // triggerState(attachmentId, dataPointId, value, parentUuid)
453
446
  if (outputComponent) {
454
- console.log("[Behavior] Triggering animations on output component: ".concat(outputComponent, ".").concat(out.attachment, ".").concat(out.state));
447
+ // Triggering animations on output component
455
448
  this.triggerState(out.attachment, out.state, value, outputComponent);
456
449
  } else {
457
450
  console.warn("[Behavior] Could not find component for attachment \"".concat(out.attachment, "\""));
@@ -462,7 +455,7 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
462
455
  }
463
456
  // LEGACY: Mesh-based pattern with conditions
464
457
  else if (conditions && out.child) {
465
- console.log('[Behavior] Using legacy mesh-based pattern with conditions');
458
+ // Using legacy mesh-based pattern with conditions
466
459
  // Evaluate conditions
467
460
  var _iterator7 = _rollupPluginBabelHelpers.createForOfIteratorHelper(conditions),
468
461
  _step7;
@@ -879,13 +872,9 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
879
872
  value: function _applyAnimation(entry, value) {
880
873
  var anim = entry.anim,
881
874
  mesh = entry.mesh,
882
- origPos = entry.origPos,
883
- origRot = entry.origRot,
884
- origWorldPos = entry.origWorldPos,
885
- origWorldQuat = entry.origWorldQuat,
886
- origWorldCenter = entry.origWorldCenter,
887
- deviceWorldQuat = entry.deviceWorldQuat,
888
- viewerMaxDim = entry.viewerMaxDim;
875
+ origPos = entry.origPos;
876
+ entry.origRot;
877
+ var viewerMaxDim = entry.viewerMaxDim;
889
878
  var mapping = this._resolveMapping(anim, value);
890
879
  if (!mapping) return;
891
880
  var types = anim.transformTypes || [];
@@ -897,7 +886,7 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
897
886
  if (type === 'translation') {
898
887
  this._applyTranslation(mesh, origPos, mapping.transform);
899
888
  } else if (type === 'rotation') {
900
- this._applyRotation(mesh, origPos, origRot, anim, mapping.rotationTransform, origWorldPos, origWorldQuat, origWorldCenter, deviceWorldQuat, viewerMaxDim);
889
+ this._applyRotation(entry, anim, mapping.rotationTransform, viewerMaxDim);
901
890
  } else if (type === 'color') {
902
891
  this._applyColor(mesh, mapping.colorTransform);
903
892
  }
@@ -1041,25 +1030,71 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
1041
1030
  mesh.position.set(origPos.x - ((_transform$x = transform.x) !== null && _transform$x !== void 0 ? _transform$x : 0), origPos.y - ((_transform$y = transform.y) !== null && _transform$y !== void 0 ? _transform$y : 0), origPos.z + ((_transform$z = transform.z) !== null && _transform$z !== void 0 ? _transform$z : 0));
1042
1031
  }
1043
1032
 
1033
+ /**
1034
+ * Recompute world-space rest-pose transforms for a behavior entry using the
1035
+ * current parent/device world matrix. origPos/origRot are local rest pose and
1036
+ * stay valid after parent moves; world anchors must be derived at apply time.
1037
+ *
1038
+ * @param {{ mesh, origPos, origRot, deviceModelRoot }} entry
1039
+ * @returns {{ origWorldPos: THREE.Vector3, origWorldQuat: THREE.Quaternion, origWorldCenter: THREE.Vector3, deviceWorldQuat: THREE.Quaternion }|null}
1040
+ */
1041
+ }, {
1042
+ key: "_getRestWorldTransforms",
1043
+ value: function _getRestWorldTransforms(entry) {
1044
+ var mesh = entry.mesh,
1045
+ origPos = entry.origPos,
1046
+ origRot = entry.origRot,
1047
+ deviceModelRoot = entry.deviceModelRoot;
1048
+ if (!mesh || !origPos || !origRot) return null;
1049
+ var savedPos = mesh.position.clone();
1050
+ var savedQuat = mesh.quaternion.clone();
1051
+ mesh.position.copy(origPos);
1052
+ mesh.rotation.copy(origRot);
1053
+ mesh.updateMatrixWorld(true);
1054
+ var origWorldPos = new THREE__namespace.Vector3();
1055
+ mesh.getWorldPosition(origWorldPos);
1056
+ var origWorldQuat = new THREE__namespace.Quaternion();
1057
+ mesh.getWorldQuaternion(origWorldQuat);
1058
+ var box = new THREE__namespace.Box3().setFromObject(mesh);
1059
+ var origWorldCenter = new THREE__namespace.Vector3();
1060
+ if (!box.isEmpty()) box.getCenter(origWorldCenter);else origWorldCenter.copy(origWorldPos);
1061
+ var deviceWorldQuat = new THREE__namespace.Quaternion();
1062
+ if (deviceModelRoot) {
1063
+ deviceModelRoot.getWorldQuaternion(deviceWorldQuat);
1064
+ }
1065
+ mesh.position.copy(savedPos);
1066
+ mesh.quaternion.copy(savedQuat);
1067
+ return {
1068
+ origWorldPos: origWorldPos,
1069
+ origWorldQuat: origWorldQuat,
1070
+ origWorldCenter: origWorldCenter,
1071
+ deviceWorldQuat: deviceWorldQuat
1072
+ };
1073
+ }
1074
+
1044
1075
  /**
1045
1076
  * Apply a rotation around an arbitrary pivot point using world-space quaternion
1046
1077
  * math matching the ReconstructionViewer's setMeshPreviewRotationAxis approach.
1047
1078
  * This ensures the runtime axis/pivot matches what the user configured in the
1048
1079
  * animation dialog, regardless of the device's parent transform in the scene.
1049
1080
  *
1050
- * @param {THREE.Object3D} mesh
1051
- * @param {THREE.Vector3} origPos - local position at load time (unused, kept for signature compat)
1052
- * @param {THREE.Euler} origRot - local rotation at load time (unused)
1081
+ * @param {{ mesh, origPos, origRot, deviceModelRoot }} entry
1053
1082
  * @param {Object} anim
1054
1083
  * @param {number} angleDeg - Degrees
1055
- * @param {THREE.Vector3} origWorldPos - world position at load time
1056
- * @param {THREE.Quaternion} origWorldQuat - world quaternion at load time
1057
- * @param {THREE.Vector3} origWorldCenter - world bounding-box center at load time
1084
+ * @param {number} viewerMaxDim
1058
1085
  */
1059
1086
  }, {
1060
1087
  key: "_applyRotation",
1061
- value: function _applyRotation(mesh, origPos, origRot, anim, angleDeg, origWorldPos, origWorldQuat, origWorldCenter, deviceWorldQuat, viewerMaxDim) {
1088
+ value: function _applyRotation(entry, anim, angleDeg, viewerMaxDim) {
1062
1089
  var _anim$rotAxis, _anim$rotAxisOffset;
1090
+ var mesh = entry.mesh,
1091
+ origPos = entry.origPos,
1092
+ origRot = entry.origRot;
1093
+ var restWorld = this._getRestWorldTransforms(entry);
1094
+ var origWorldPos = restWorld === null || restWorld === void 0 ? void 0 : restWorld.origWorldPos;
1095
+ var origWorldQuat = restWorld === null || restWorld === void 0 ? void 0 : restWorld.origWorldQuat;
1096
+ var origWorldCenter = restWorld === null || restWorld === void 0 ? void 0 : restWorld.origWorldCenter;
1097
+ var deviceWorldQuat = restWorld === null || restWorld === void 0 ? void 0 : restWorld.deviceWorldQuat;
1063
1098
  var angle = THREE__namespace.MathUtils.degToRad(typeof angleDeg === 'number' ? angleDeg : 0);
1064
1099
  var axis = ((_anim$rotAxis = anim.rotAxis) !== null && _anim$rotAxis !== void 0 ? _anim$rotAxis : 'x').toLowerCase();
1065
1100
  var off = (_anim$rotAxisOffset = anim.rotAxisOffset) !== null && _anim$rotAxisOffset !== void 0 ? _anim$rotAxisOffset : {
@@ -770,7 +770,6 @@ function _findInAllCachePartitions() {
770
770
  _context16.n = 7;
771
771
  break;
772
772
  }
773
- console.log("\u2705 [findInAllCachePartitions] Found in ".concat(cacheName, " (exact match): ").concat(cacheKey.substring(0, 80), "..."));
774
773
  return _context16.a(2, response);
775
774
  case 7:
776
775
  if (!(encodedCacheKey !== cacheKey)) {
@@ -785,7 +784,6 @@ function _findInAllCachePartitions() {
785
784
  _context16.n = 9;
786
785
  break;
787
786
  }
788
- console.log("\u2705 [findInAllCachePartitions] Found in ".concat(cacheName, " (encoded match): ").concat(encodedCacheKey.substring(0, 80), "..."));
789
787
  return _context16.a(2, response);
790
788
  case 9:
791
789
  _context16.n = 4;
@@ -820,8 +818,6 @@ function _getCachedS3Object() {
820
818
  cachedResponse,
821
819
  cachedTime,
822
820
  age,
823
- _allKeys,
824
- matchingKeys,
825
821
  _args19 = arguments;
826
822
  return _rollupPluginBabelHelpers.regenerator().w(function (_context19) {
827
823
  while (1) switch (_context19.n) {
@@ -829,50 +825,26 @@ function _getCachedS3Object() {
829
825
  storageOptions = _args19.length > 1 && _args19[1] !== undefined ? _args19[1] : {};
830
826
  expiryMs = _args19.length > 2 && _args19[2] !== undefined ? _args19[2] : null;
831
827
  cacheKey = "https://s3.cache/".concat(s3Key);
832
- expiry = expiryMs || CacheManager.cacheManager.getExpiryForPath(s3Key);
833
- console.log("\uD83D\uDD0D [S3Cache] Checking for cached S3 object:", {
834
- s3Key: s3Key,
835
- cacheKey: cacheKey
836
- });
837
-
838
- // First, check ALL app cache partitions for a hit (handles auth race condition)
828
+ expiry = expiryMs || CacheManager.cacheManager.getExpiryForPath(s3Key); // First, check ALL app cache partitions for a hit (handles auth race condition)
839
829
  _context19.n = 1;
840
830
  return findInAllCachePartitions(cacheKey);
841
831
  case 1:
842
832
  cachedResponse = _context19.v;
843
833
  if (!cachedResponse) {
844
- _context19.n = 4;
834
+ _context19.n = 3;
845
835
  break;
846
836
  }
847
837
  cachedTime = cachedResponse.headers.get('x-cached-time');
848
838
  age = Date.now() - parseInt(cachedTime || '0');
849
- console.log("\u2705 [S3Cache] Found in cache partition, age: ".concat(Math.round(age / 1000), "s, expiry: ").concat(Math.round(expiry / 1000), "s"));
850
839
  if (!(age < expiry)) {
851
840
  _context19.n = 3;
852
841
  break;
853
842
  }
854
- console.log("\u2705 [S3Cache] Returning cached blob for: ".concat(s3Key));
855
843
  _context19.n = 2;
856
844
  return cachedResponse.blob();
857
845
  case 2:
858
846
  return _context19.a(2, _context19.v);
859
847
  case 3:
860
- console.log("\u23F0 [S3Cache] Cache entry expired, will re-fetch");
861
- _context19.n = 6;
862
- break;
863
- case 4:
864
- console.log("\u274C [S3Cache] Not found in any cache partition");
865
- _context19.n = 5;
866
- return getAllCacheKeys();
867
- case 5:
868
- _allKeys = _context19.v;
869
- matchingKeys = _rollupPluginBabelHelpers.toConsumableArray(_allKeys).filter(function (k) {
870
- return k.includes('24dd6a7a') || k.includes('.glb');
871
- });
872
- if (matchingKeys.length > 0) {
873
- console.log("\uD83D\uDD0D [S3Cache] Available GLB cache keys:", matchingKeys.slice(0, 5));
874
- }
875
- case 6:
876
848
  return _context19.a(2, CacheManager.cacheManager.execute({
877
849
  cacheKey: cacheKey,
878
850
  sourceKey: s3Key,
@@ -1031,7 +1003,6 @@ function _preloadS3Objects() {
1031
1003
  };
1032
1004
  }()));
1033
1005
  case 1:
1034
- console.log("\u2705 Preload complete: ".concat(results.success, " success, ").concat(results.failed, " failed"));
1035
1006
  return _context22.a(2, results);
1036
1007
  }
1037
1008
  }, _callee22);
@@ -1209,7 +1180,6 @@ function _preloadLocalFiles() {
1209
1180
  return _rollupPluginBabelHelpers.regenerator().w(function (_context29) {
1210
1181
  while (1) switch (_context29.n) {
1211
1182
  case 0:
1212
- console.log("preloadLocalFiles started");
1213
1183
  results = {
1214
1184
  success: 0,
1215
1185
  failed: 0,
@@ -1248,7 +1218,6 @@ function _preloadLocalFiles() {
1248
1218
  };
1249
1219
  }()));
1250
1220
  case 1:
1251
- console.log("preloadLocalFiles finished");
1252
1221
  if (results.failed > 0) {
1253
1222
  console.warn("\u26A0\uFE0F preloadLocalFiles Cache priming finished with errors: ".concat(results.failed, " failed"), results.errors);
1254
1223
  }
@@ -473,7 +473,6 @@ var S3MetadataCacheService = /*#__PURE__*/function () {
473
473
  // Update memory cache
474
474
  this._memoryCache = metadata;
475
475
  this._memoryCacheTime = Date.now();
476
- console.log("\uD83D\uDCBE S3MetadataCacheService: Set ".concat(components.length, " components"));
477
476
  return _context9.a(2, true);
478
477
  case 4:
479
478
  _context9.p = 4;
@@ -344,7 +344,7 @@ var ComponentDataManager = /*#__PURE__*/function (_BaseDisposable) {
344
344
  value: (function () {
345
345
  var _extendComponentDictionary = _rollupPluginBabelHelpers.asyncToGenerator(/*#__PURE__*/_rollupPluginBabelHelpers.regenerator().m(function _callee3(additionalComponents) {
346
346
  var _this3 = this;
347
- var _this$sceneViewer, newComponents, skippedCount, addedCount, modelPreloader, _t;
347
+ var _this$sceneViewer, newComponents, modelPreloader, _t;
348
348
  return _rollupPluginBabelHelpers.regenerator().w(function (_context3) {
349
349
  while (1) switch (_context3.n) {
350
350
  case 0:
@@ -368,7 +368,6 @@ var ComponentDataManager = /*#__PURE__*/function (_BaseDisposable) {
368
368
  _context3.p = 3;
369
369
  // Filter out components that already exist in the dictionary (deduplication)
370
370
  newComponents = {};
371
- skippedCount = 0;
372
371
  Object.entries(additionalComponents).forEach(function (_ref3) {
373
372
  var _ref4 = _rollupPluginBabelHelpers.slicedToArray(_ref3, 2),
374
373
  key = _ref4[0],
@@ -376,13 +375,12 @@ var ComponentDataManager = /*#__PURE__*/function (_BaseDisposable) {
376
375
  if (!_this3.componentDictionary[key]) {
377
376
  newComponents[key] = component;
378
377
  } else {
379
- skippedCount++;
380
378
  console.log("\u26A0\uFE0F Skipping duplicate component: ".concat(key, " (").concat(component.name || 'unnamed', ")"));
381
379
  }
382
380
  });
383
381
 
384
382
  // Merge only new components into dictionary
385
- addedCount = Object.keys(newComponents).length;
383
+ Object.keys(newComponents).length;
386
384
  Object.assign(this.componentDictionary, newComponents);
387
385
 
388
386
  // Update ModelPreloader's dictionary reference
@@ -390,12 +388,10 @@ var ComponentDataManager = /*#__PURE__*/function (_BaseDisposable) {
390
388
  modelPreloader = (_this$sceneViewer = this.sceneViewer) === null || _this$sceneViewer === void 0 || (_this$sceneViewer = _this$sceneViewer.centralPlant) === null || _this$sceneViewer === void 0 || (_this$sceneViewer = _this$sceneViewer.utilities) === null || _this$sceneViewer === void 0 ? void 0 : _this$sceneViewer.modelPreloader;
391
389
  if (modelPreloader) {
392
390
  modelPreloader.componentDictionary = this.componentDictionary;
393
- console.log("\uD83D\uDD04 Updated ModelPreloader's dictionary reference (".concat(Object.keys(this.componentDictionary).length, " total components)"));
394
391
  }
395
392
 
396
393
  // Clear cache to force refresh
397
394
  this.clearCache();
398
- console.log("\u2705 extendComponentDictionary(): Added ".concat(addedCount, " new components (").concat(skippedCount, " duplicates skipped)"));
399
395
  return _context3.a(2, true);
400
396
  case 4:
401
397
  _context3.p = 4;
@@ -29,7 +29,7 @@ var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
29
29
  // ---------------------------------------------------------------------------
30
30
  // Inline styles (injected once into the document head)
31
31
  // ---------------------------------------------------------------------------
32
- var TOOLTIP_STYLES = "\n.cp-tooltip {\n position: absolute;\n pointer-events: auto;\n z-index: 10000;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 13px;\n line-height: 1.4;\n user-select: none;\n min-width: 200px;\n max-width: 280px;\n transform: translate(-50%, -100%);\n margin-top: -12px;\n transition: opacity 0.15s ease;\n}\n\n.cp-tooltip__card {\n background: rgba(28, 32, 40, 0.95);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 10px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.45);\n overflow: hidden;\n}\n\n/* \u2500\u2500 Header \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.cp-tooltip__header {\n padding: 10px 14px;\n font-weight: 600;\n font-size: 14px;\n color: #e8ecf1;\n background: rgba(255, 255, 255, 0.04);\n border-bottom: 1px solid rgba(255, 255, 255, 0.08);\n letter-spacing: 0.2px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* \u2500\u2500 I/O Devices section \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.cp-tooltip__io-section {\n position: relative;\n}\n\n.cp-tooltip__io-trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 14px;\n color: #a4adba;\n cursor: pointer;\n transition: background 0.12s ease, color 0.12s ease;\n}\n\n.cp-tooltip__io-trigger:hover {\n background: rgba(255, 255, 255, 0.06);\n color: #e8ecf1;\n}\n\n.cp-tooltip__io-trigger-label {\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 0.6px;\n font-weight: 500;\n}\n\n.cp-tooltip__io-arrow {\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.cp-tooltip__io-section.expanded .cp-tooltip__io-arrow {\n transform: rotate(90deg);\n}\n\n/* \u2500\u2500 Device list \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.cp-tooltip__device-list {\n max-height: 0;\n overflow: hidden;\n transition: max-height 0.25s ease;\n}\n\n.cp-tooltip__io-section.expanded .cp-tooltip__device-list {\n max-height: 300px;\n}\n\n.cp-tooltip__device-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 14px 6px 20px;\n color: #c1c8d1;\n font-size: 12px;\n border-top: 1px solid rgba(255, 255, 255, 0.04);\n transition: background 0.1s ease;\n}\n\n.cp-tooltip__device-item:hover {\n background: rgba(255, 255, 255, 0.04);\n}\n\n.cp-tooltip__device-dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: #4fc3f7;\n flex-shrink: 0;\n}\n\n.cp-tooltip__device-name {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* \u2500\u2500 Empty state \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.cp-tooltip__no-devices {\n padding: 8px 14px;\n color: #6b7280;\n font-size: 12px;\n font-style: italic;\n}\n\n/* \u2500\u2500 Caret arrow pointing down \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.cp-tooltip__caret {\n width: 0;\n height: 0;\n border-left: 7px solid transparent;\n border-right: 7px solid transparent;\n border-top: 7px solid rgba(28, 32, 40, 0.95);\n margin: 0 auto;\n position: relative;\n top: -1px;\n}\n\n/* \u2500\u2500 Data point rows \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.cp-tooltip__dp-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n padding: 4px 12px 4px 30px;\n font-size: 11.5px;\n border-top: 1px solid rgba(255, 255, 255, 0.025);\n min-height: 24px;\n}\n\n.cp-tooltip__dp-name {\n flex: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n color: #7c8d9e;\n}\n\n/* Read-only state badge */\n.cp-tooltip__dp-badge {\n font-size: 10.5px;\n font-weight: 600;\n padding: 1px 7px;\n border-radius: 8px;\n flex-shrink: 0;\n background: rgba(255, 255, 255, 0.07);\n color: #9aabb8;\n min-width: 30px;\n text-align: center;\n letter-spacing: 0.2px;\n}\n\n.cp-tooltip__dp-badge.active {\n background: rgba(76, 175, 80, 0.28);\n color: #a5d6a7;\n}\n\n/* Binary toggle button */\n.cp-tooltip__dp-toggle {\n font-size: 10.5px;\n font-weight: 600;\n padding: 2px 9px;\n border-radius: 8px;\n flex-shrink: 0;\n border: 1px solid rgba(255, 255, 255, 0.14);\n background: rgba(255, 255, 255, 0.06);\n color: #c1c8d1;\n cursor: pointer;\n min-width: 40px;\n text-align: center;\n transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;\n}\n\n.cp-tooltip__dp-toggle:hover {\n background: rgba(255, 255, 255, 0.12);\n border-color: rgba(255, 255, 255, 0.25);\n}\n\n.cp-tooltip__dp-toggle.on {\n background: rgba(76, 175, 80, 0.28);\n border-color: rgba(76, 175, 80, 0.55);\n color: #a5d6a7;\n}\n\n/* Number / float input */\n.cp-tooltip__dp-input {\n width: 62px;\n background: rgba(255, 255, 255, 0.06);\n border: 1px solid rgba(255, 255, 255, 0.14);\n border-radius: 4px;\n color: #e8ecf1;\n font-size: 11px;\n padding: 2px 5px;\n text-align: right;\n outline: none;\n flex-shrink: 0;\n}\n\n.cp-tooltip__dp-input:focus {\n border-color: rgba(79, 195, 247, 0.55);\n}\n\n/* Enum select */\n.cp-tooltip__dp-select {\n background: rgba(255, 255, 255, 0.06);\n border: 1px solid rgba(255, 255, 255, 0.14);\n border-radius: 4px;\n color: #e8ecf1;\n font-size: 11px;\n padding: 2px 4px;\n outline: none;\n flex-shrink: 0;\n max-width: 96px;\n cursor: pointer;\n}\n\n.cp-tooltip__dp-select:focus {\n border-color: rgba(79, 195, 247, 0.55);\n}\n\n/* Unit suffix */\n.cp-tooltip__dp-unit {\n font-size: 10px;\n color: #505c68;\n flex-shrink: 0;\n margin-left: -4px;\n}\n";
32
+ var TOOLTIP_STYLES = "\n.cp-tooltip {\n position: absolute;\n pointer-events: auto;\n z-index: 10000;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 13px;\n line-height: 1.4;\n user-select: none;\n min-width: 200px;\n max-width: 280px;\n transform: translate(-50%, -100%);\n margin-top: -12px;\n transition: opacity 0.15s ease;\n color-scheme: light;\n}\n\n.cp-tooltip__card {\n background: rgba(255, 255, 255, 0.97);\n border: 1px solid rgba(0, 0, 0, 0.1);\n border-radius: 10px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);\n overflow: hidden;\n}\n\n/* \u2500\u2500 Header \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.cp-tooltip__header {\n padding: 10px 14px;\n font-weight: 600;\n font-size: 14px;\n color: #2c3e50;\n background: rgba(0, 0, 0, 0.02);\n border-bottom: 1px solid rgba(0, 0, 0, 0.08);\n letter-spacing: 0.2px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* \u2500\u2500 I/O Devices section \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.cp-tooltip__io-section {\n position: relative;\n}\n\n.cp-tooltip__io-trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 14px;\n color: #666666;\n cursor: pointer;\n transition: background 0.12s ease, color 0.12s ease;\n}\n\n.cp-tooltip__io-trigger:hover {\n background: rgba(0, 0, 0, 0.04);\n color: #333333;\n}\n\n.cp-tooltip__io-trigger-label {\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 0.6px;\n font-weight: 500;\n}\n\n.cp-tooltip__io-arrow {\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.cp-tooltip__io-section.expanded .cp-tooltip__io-arrow {\n transform: rotate(90deg);\n}\n\n/* \u2500\u2500 Device list \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.cp-tooltip__device-list {\n max-height: 0;\n overflow: hidden;\n transition: max-height 0.25s ease;\n}\n\n.cp-tooltip__io-section.expanded .cp-tooltip__device-list {\n max-height: 300px;\n}\n\n.cp-tooltip__device-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 14px 6px 20px;\n color: #555555;\n font-size: 12px;\n border-top: 1px solid rgba(0, 0, 0, 0.06);\n transition: background 0.1s ease;\n}\n\n.cp-tooltip__device-item:hover {\n background: rgba(0, 0, 0, 0.03);\n}\n\n.cp-tooltip__device-dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: #1976d2;\n flex-shrink: 0;\n}\n\n.cp-tooltip__device-name {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* \u2500\u2500 Empty state \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.cp-tooltip__no-devices {\n padding: 8px 14px;\n color: #888888;\n font-size: 12px;\n font-style: italic;\n}\n\n/* \u2500\u2500 Caret arrow pointing down \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.cp-tooltip__caret {\n width: 0;\n height: 0;\n border-left: 7px solid transparent;\n border-right: 7px solid transparent;\n border-top: 7px solid rgba(255, 255, 255, 0.97);\n margin: 0 auto;\n position: relative;\n top: -1px;\n filter: drop-shadow(0 1px 0 rgba(0, 0, 0, 0.1));\n}\n\n/* \u2500\u2500 Data point rows \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.cp-tooltip__dp-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n padding: 4px 12px 4px 30px;\n font-size: 11.5px;\n border-top: 1px solid rgba(0, 0, 0, 0.05);\n min-height: 24px;\n}\n\n.cp-tooltip__dp-name {\n flex: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n color: #666666;\n}\n\n/* Read-only state badge */\n.cp-tooltip__dp-badge {\n font-size: 10.5px;\n font-weight: 600;\n padding: 1px 7px;\n border-radius: 8px;\n flex-shrink: 0;\n background: #f0f2f5;\n color: #666666;\n min-width: 30px;\n text-align: center;\n letter-spacing: 0.2px;\n}\n\n.cp-tooltip__dp-badge.active {\n background: rgba(76, 175, 80, 0.15);\n color: #2e7d32;\n}\n\n/* Binary toggle button */\n.cp-tooltip__dp-toggle {\n font-size: 10.5px;\n font-weight: 600;\n padding: 2px 9px;\n border-radius: 8px;\n flex-shrink: 0;\n border: 1px solid #dddddd;\n background: #f8f9fa;\n color: #555555;\n cursor: pointer;\n min-width: 40px;\n text-align: center;\n transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;\n}\n\n.cp-tooltip__dp-toggle:hover {\n background: #eeeeee;\n border-color: #cccccc;\n}\n\n.cp-tooltip__dp-toggle.on {\n background: rgba(76, 175, 80, 0.15);\n border-color: rgba(76, 175, 80, 0.45);\n color: #2e7d32;\n}\n\n/* Number / float input */\n.cp-tooltip__dp-input {\n width: 62px;\n background: #f8f9fa;\n border: 1px solid #dddddd;\n border-radius: 4px;\n color: #333333;\n font-size: 11px;\n padding: 2px 5px;\n text-align: right;\n outline: none;\n flex-shrink: 0;\n}\n\n.cp-tooltip__dp-input:focus {\n border-color: #1976d2;\n}\n\n/* Enum select */\n.cp-tooltip__dp-select {\n background: #f8f9fa;\n border: 1px solid #dddddd;\n border-radius: 4px;\n color: #333333;\n font-size: 11px;\n padding: 2px 4px;\n outline: none;\n flex-shrink: 0;\n max-width: 96px;\n cursor: pointer;\n}\n\n.cp-tooltip__dp-select:focus {\n border-color: #1976d2;\n}\n\n/* Unit suffix */\n.cp-tooltip__dp-unit {\n font-size: 10px;\n color: #888888;\n flex-shrink: 0;\n margin-left: -4px;\n}\n";
33
33
  var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
34
34
  /**
35
35
  * @param {Object} sceneViewer - The sceneViewer instance
@@ -77,7 +77,8 @@ var SceneExportManager = /*#__PURE__*/function () {
77
77
  }, {
78
78
  key: "exportSceneData",
79
79
  value: function exportSceneData() {
80
- var _this = this;
80
+ var _this = this,
81
+ _this$sceneViewer$cur2;
81
82
  console.log('📤 Starting scene export...');
82
83
  if (!this.sceneViewer.scene) {
83
84
  console.warn('⚠️ No scene available for export');
@@ -289,6 +290,12 @@ var SceneExportManager = /*#__PURE__*/function () {
289
290
  children: sceneChildren
290
291
  }
291
292
  };
293
+
294
+ // Preserve cross-component behaviors authored in the Behavior window
295
+ var sceneBehaviors = (_this$sceneViewer$cur2 = this.sceneViewer.currentSceneData) === null || _this$sceneViewer$cur2 === void 0 ? void 0 : _this$sceneViewer$cur2.behaviors;
296
+ if (sceneBehaviors && sceneBehaviors.length > 0) {
297
+ exportData.behaviors = sceneBehaviors;
298
+ }
292
299
  console.log('✅ Scene export completed:', exportData);
293
300
  console.log("\uD83D\uDCCA Exported ".concat(sceneChildren.length, " components and ").concat(exportData.connections.length, " connections"));
294
301
  return exportData;
@@ -354,7 +361,7 @@ var SceneExportManager = /*#__PURE__*/function () {
354
361
  }, {
355
362
  key: "getExportMetadata",
356
363
  value: function getExportMetadata() {
357
- var _this$sceneViewer$cur2;
364
+ var _this$sceneViewer$cur3;
358
365
  if (!this.sceneViewer.scene) {
359
366
  return null;
360
367
  }
@@ -365,7 +372,7 @@ var SceneExportManager = /*#__PURE__*/function () {
365
372
  return {
366
373
  totalObjects: objectCount,
367
374
  hasCurrentSceneData: !!this.sceneViewer.currentSceneData,
368
- connectionsCount: ((_this$sceneViewer$cur2 = this.sceneViewer.currentSceneData) === null || _this$sceneViewer$cur2 === void 0 || (_this$sceneViewer$cur2 = _this$sceneViewer$cur2.connections) === null || _this$sceneViewer$cur2 === void 0 ? void 0 : _this$sceneViewer$cur2.length) || 0,
375
+ connectionsCount: ((_this$sceneViewer$cur3 = this.sceneViewer.currentSceneData) === null || _this$sceneViewer$cur3 === void 0 || (_this$sceneViewer$cur3 = _this$sceneViewer$cur3.connections) === null || _this$sceneViewer$cur3 === void 0 ? void 0 : _this$sceneViewer$cur3.length) || 0,
369
376
  exportTimestamp: new Date().toISOString()
370
377
  };
371
378
  }
@@ -897,7 +897,6 @@ var SceneOperationsManager = /*#__PURE__*/function () {
897
897
 
898
898
  // Check if dictionary has connector children and component doesn't already have them
899
899
  if (dictEntry !== null && dictEntry !== void 0 && dictEntry.children && Array.isArray(dictEntry.children) && dictEntry.children.length > 0) {
900
- // Only inject if the component doesn't already have children
901
900
  if (!child.children || child.children.length === 0) {
902
901
  // Get component rotation (in degrees from JSON)
903
902
  var rotation = child.rotation || {
@@ -927,7 +926,6 @@ var SceneOperationsManager = /*#__PURE__*/function () {
927
926
  connectorsInjected++;
928
927
  return clonedConnector;
929
928
  });
930
- console.log("\uD83D\uDD0C Injected ".concat(child.children.length, " connectors for ").concat(child.uuid, " (").concat(libraryId, ") with rotation [").concat(rotation.x, "\xB0, ").concat(rotation.y, "\xB0, ").concat(rotation.z, "\xB0]"));
931
929
  componentsProcessed++;
932
930
  }
933
931
  }
@@ -204,17 +204,14 @@ var ModelPreloader = /*#__PURE__*/function () {
204
204
  _context3.n = 1;
205
205
  break;
206
206
  }
207
- console.log("\uD83C\uDFAF Model ".concat(modelKey, " already cached, skipping"));
208
207
  return _context3.a(2, this.modelCache.get(modelKey));
209
208
  case 1:
210
209
  if (!this.loadingPromises.has(modelKey)) {
211
210
  _context3.n = 2;
212
211
  break;
213
212
  }
214
- console.log("\u23F3 Model ".concat(modelKey, " already loading, waiting for completion"));
215
213
  return _context3.a(2, this.loadingPromises.get(modelKey));
216
214
  case 2:
217
- console.log("\uD83D\uDD04 Starting preload of GLB model: ".concat(modelKey));
218
215
  loadPromise = new Promise(/*#__PURE__*/function () {
219
216
  var _ref = _rollupPluginBabelHelpers.asyncToGenerator(/*#__PURE__*/_rollupPluginBabelHelpers.regenerator().m(function _callee2(resolve, reject) {
220
217
  var modelPath, _t;
@@ -230,7 +227,6 @@ var ModelPreloader = /*#__PURE__*/function () {
230
227
  return _this2.urlResolver(modelKey);
231
228
  case 2:
232
229
  modelPath = _context2.v;
233
- console.log("\uD83D\uDD17 Resolved URL for ".concat(modelKey, ":"), modelPath.substring(0, 100) + '...');
234
230
  _context2.n = 4;
235
231
  break;
236
232
  case 3:
@@ -244,11 +240,9 @@ var ModelPreloader = /*#__PURE__*/function () {
244
240
  break;
245
241
  case 5:
246
242
  modelPath = "".concat(_this2.modelsBasePath).concat(modelKey);
247
- console.log("\uD83D\uDCC2 Loading from: ".concat(modelPath));
248
243
  case 6:
249
244
  // Load GLB model
250
245
  _this2.gltfLoader.load(modelPath, function (gltf) {
251
- console.log("\u2705 Successfully preloaded GLB model: ".concat(modelKey));
252
246
  // Cache the scene for future use
253
247
  _this2.modelCache.set(modelKey, gltf.scene);
254
248
 
@@ -267,13 +261,6 @@ var ModelPreloader = /*#__PURE__*/function () {
267
261
  resolve(gltf.scene);
268
262
  }, function (progress) {
269
263
  // Optional: track loading progress
270
- if (progress.lengthComputable) {
271
- var percentage = progress.loaded / progress.total * 100;
272
- if (percentage % 25 === 0) {
273
- // Log every 25%
274
- console.log("\uD83D\uDCCA Loading GLB ".concat(modelKey, ": ").concat(percentage.toFixed(0), "%"));
275
- }
276
- }
277
264
  }, function (error) {
278
265
  console.error("\u274C Failed to preload GLB model ".concat(modelKey, ":"), error);
279
266
  // Remove from loading promises
@@ -311,13 +298,10 @@ var ModelPreloader = /*#__PURE__*/function () {
311
298
  value: function getCachedModel(modelKey) {
312
299
  var useIndexedGeometry = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
313
300
  if (this.modelCache.has(modelKey)) {
314
- console.log("\uD83C\uDFAF Returning cached model: ".concat(modelKey));
315
301
  var cachedData = this.modelCache.get(modelKey);
316
302
 
317
303
  // Handle OBJ models with processed geometry
318
304
  if (cachedData && cachedData.isObjModel && useIndexedGeometry && cachedData.processedGeometry) {
319
- console.log("\uD83D\uDD27 Using indexed BufferGeometry for OBJ: ".concat(modelKey));
320
-
321
305
  // Create a mesh from the processed indexed geometry
322
306
  var mesh = new THREE__namespace.Mesh(cachedData.processedGeometry.clone(), cachedData.materials.clone());
323
307
 
@@ -553,7 +537,7 @@ var ModelPreloader = /*#__PURE__*/function () {
553
537
  }
554
538
 
555
539
  // Model not cached, need to load it
556
- console.log("\uD83D\uDD04 Loading model for library ID ".concat(libraryId, ": ").concat(modelKey));
540
+ // Loading model for library ID
557
541
  this.preloadSingleModel(modelKey).then(function (model) {
558
542
  if (model) {
559
543
  var _clonedModel = model.clone();