@2112-lab/central-plant 0.3.38 → 0.3.41

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.
Files changed (29) hide show
  1. package/dist/bundle/index.js +1096 -562
  2. package/dist/cjs/src/core/centralPlant.js +115 -68
  3. package/dist/cjs/src/core/centralPlantInternals.js +20 -36
  4. package/dist/cjs/src/index.js +23 -0
  5. package/dist/cjs/src/managers/behaviors/IoBehaviorManager.js +175 -234
  6. package/dist/cjs/src/managers/components/componentDataManager.js +63 -11
  7. package/dist/cjs/src/managers/scene/componentTooltipManager.js +95 -65
  8. package/dist/cjs/src/managers/scene/modelManager.js +93 -145
  9. package/dist/cjs/src/managers/scene/sceneOperationsManager.js +8 -3
  10. package/dist/cjs/src/utils/animationTransformUtils.js +82 -0
  11. package/dist/cjs/src/utils/behaviorDispatch.js +62 -0
  12. package/dist/cjs/src/utils/behaviorRegistration.js +76 -0
  13. package/dist/cjs/src/utils/behaviorSceneUtils.js +155 -0
  14. package/dist/cjs/src/utils/behaviorSchema.js +209 -0
  15. package/dist/esm/src/core/centralPlant.js +115 -68
  16. package/dist/esm/src/core/centralPlantInternals.js +21 -37
  17. package/dist/esm/src/index.js +5 -0
  18. package/dist/esm/src/managers/behaviors/IoBehaviorManager.js +176 -235
  19. package/dist/esm/src/managers/components/componentDataManager.js +63 -11
  20. package/dist/esm/src/managers/scene/componentTooltipManager.js +95 -65
  21. package/dist/esm/src/managers/scene/modelManager.js +94 -146
  22. package/dist/esm/src/managers/scene/sceneOperationsManager.js +8 -3
  23. package/dist/esm/src/utils/animationTransformUtils.js +56 -0
  24. package/dist/esm/src/utils/behaviorDispatch.js +56 -0
  25. package/dist/esm/src/utils/behaviorRegistration.js +71 -0
  26. package/dist/esm/src/utils/behaviorSceneUtils.js +147 -0
  27. package/dist/esm/src/utils/behaviorSchema.js +201 -0
  28. package/dist/index.d.ts +186 -1
  29. package/package.json +1 -1
@@ -4,6 +4,8 @@ import { BaseDisposable } from './baseDisposable.js';
4
4
  import { DisposalUtilities } from '../utils/DisposalUtilities.js';
5
5
  import { CentralPlantInternals } from './centralPlantInternals.js';
6
6
  import '../rendering/modelPreloader.js';
7
+ import { scanSceneIoEndpoints, applyCrossComponentBehaviors, loadCrossComponentBehaviors, reregisterSceneBehaviors } from '../utils/behaviorSceneUtils.js';
8
+ import { getScopedAttachmentKey } from '../utils/behaviorDispatch.js';
7
9
 
8
10
  // ─────────────────────────────────────────────────────────────────────────────
9
11
  // Flow-direction compatibility helper (module-level, no class dependency)
@@ -31,7 +33,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
31
33
  * Initialize the CentralPlant manager
32
34
  *
33
35
  * @constructor
34
- * @version 0.3.38
36
+ * @version 0.3.41
35
37
  * @updated 2025-10-22
36
38
  *
37
39
  * @description Creates a new CentralPlant instance and initializes internal managers and utilities.
@@ -205,8 +207,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
205
207
  key: "setImportedSceneData",
206
208
  value: (function () {
207
209
  var _setImportedSceneData = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2(sceneData) {
208
- var _this$importedSceneDa, _this$importedSceneDa2, _this$importedSceneDa3, _this$sceneViewer;
209
- var ioBehavMgr;
210
+ var _this$importedSceneDa, _this$importedSceneDa2, _this$importedSceneDa3;
210
211
  return _regenerator().w(function (_context2) {
211
212
  while (1) switch (_context2.n) {
212
213
  case 0:
@@ -223,14 +224,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
223
224
 
224
225
  // Scene behaviors loaded
225
226
 
226
- // Register behaviors with IoBehaviorManager
227
- 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;
228
- if (ioBehavMgr) {
229
- // Setting cross-component behaviors
230
- ioBehavMgr.setCrossComponentBehaviors(this.importedSceneData.behaviors || []);
231
- } else {
232
- console.warn('[Behavior] ioBehaviorManager not available!');
233
- }
227
+ // Cross-component behaviors are registered by sceneOperationsManager.loadSceneData()
234
228
 
235
229
  // Reset component counter based on imported components to avoid ID conflicts
236
230
  this.internals.resetComponentCounter();
@@ -411,8 +405,8 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
411
405
  }, {
412
406
  key: "selectObject",
413
407
  value: function selectObject(objectOrId) {
414
- var _this$sceneViewer2, _object;
415
- if (!((_this$sceneViewer2 = this.sceneViewer) !== null && _this$sceneViewer2 !== void 0 && _this$sceneViewer2.transformManager)) {
408
+ var _this$sceneViewer, _object;
409
+ if (!((_this$sceneViewer = this.sceneViewer) !== null && _this$sceneViewer !== void 0 && _this$sceneViewer.transformManager)) {
416
410
  console.warn('⚠️ Transform manager not initialized');
417
411
  return false;
418
412
  }
@@ -458,8 +452,8 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
458
452
  }, {
459
453
  key: "toggleObject",
460
454
  value: function toggleObject(objectOrId) {
461
- var _this$sceneViewer3, _object2;
462
- if (!((_this$sceneViewer3 = this.sceneViewer) !== null && _this$sceneViewer3 !== void 0 && _this$sceneViewer3.transformManager)) {
455
+ var _this$sceneViewer2, _object2;
456
+ if (!((_this$sceneViewer2 = this.sceneViewer) !== null && _this$sceneViewer2 !== void 0 && _this$sceneViewer2.transformManager)) {
463
457
  console.warn('⚠️ Transform manager not initialized');
464
458
  return false;
465
459
  }
@@ -495,8 +489,8 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
495
489
  }, {
496
490
  key: "deselectObject",
497
491
  value: function deselectObject() {
498
- var _this$sceneViewer4;
499
- if (!((_this$sceneViewer4 = this.sceneViewer) !== null && _this$sceneViewer4 !== void 0 && _this$sceneViewer4.transformManager)) {
492
+ var _this$sceneViewer3;
493
+ if (!((_this$sceneViewer3 = this.sceneViewer) !== null && _this$sceneViewer3 !== void 0 && _this$sceneViewer3.transformManager)) {
500
494
  console.warn('⚠️ Transform manager not initialized');
501
495
  return false;
502
496
  }
@@ -1076,68 +1070,70 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
1076
1070
  }
1077
1071
 
1078
1072
  /**
1079
- * Set the state of an I/O device instance in the Three.js scene.
1080
- *
1081
- * This is the primary public API for driving IO device state changes from
1082
- * external code (real-time data feeds, AI agents, automated tests, etc.).
1083
- * It performs three coordinated actions in order:
1084
- * 1. Persists the new value through the state adapter (Vuex in sandbox,
1085
- * or any custom adapter injected via componentTooltipManager.configure())
1086
- * so that the host application's store stays consistent.
1087
- * 2. Evaluates all behaviors whose input matches this (attachmentId, stateId)
1088
- * pair and applies the resulting property changes to Three.js meshes.
1089
- * 3. Emits an 'io-device-state-changed' event on the sceneViewer so that
1090
- * host applications without a Vuex store (e.g. cp3d-viewer) can react.
1091
- *
1092
- * @param {string} attachmentId - The attachment ID of the IO device (matches
1093
- * the `attachmentId` stored in the Three.js object's userData)
1094
- * @param {string} stateId - The data-point / state ID on the device (e.g. 'power', 'level')
1095
- * @param {*} value - The new state value (boolean, number, string, etc.)
1096
- * @param {string} [parentUuid] - UUID of the parent component instance.
1097
- * Required when multiple instances of the same smart component share the
1098
- * same attachmentId — prevents cross-instance state bleed.
1099
- * @returns {boolean} True if the behavior system was reached; false if unavailable.
1100
- * @example
1101
- * // Toggle a push-button on a specific pump instance
1102
- * centralPlant.setIoDeviceState('pump-push-button-01', 'power', true, pumpUuid)
1103
- *
1104
- * // Drive an analog level sensor (no parentUuid needed when only one instance)
1105
- * centralPlant.setIoDeviceState('chiller-level-sensor-01', 'level', 0.75)
1073
+ * Internal single path for I/O state changes: persist, animate, link, emit.
1074
+ * @private
1106
1075
  */
1107
1076
  }, {
1108
- key: "setIoDeviceState",
1109
- value: function setIoDeviceState(attachmentId, stateId, value, parentUuid) {
1110
- var _this$sceneViewer5, _this$sceneViewer6, _this$sceneViewer7;
1111
- // 1. Persist via state adapter if one has been configured
1112
- var stateAdapter = (_this$sceneViewer5 = this.sceneViewer) === null || _this$sceneViewer5 === void 0 || (_this$sceneViewer5 = _this$sceneViewer5.managers) === null || _this$sceneViewer5 === void 0 || (_this$sceneViewer5 = _this$sceneViewer5.componentTooltipManager) === null || _this$sceneViewer5 === void 0 ? void 0 : _this$sceneViewer5._stateAdapter;
1077
+ key: "_dispatchIoState",
1078
+ value: function _dispatchIoState(attachmentId, stateId, value, parentUuid) {
1079
+ var _this$managers, _this$sceneViewer4, _this$sceneViewer5, _this$managers2, _this$sceneViewer6, _this$sceneViewer7, _this$sceneViewer8;
1080
+ var tooltipMgr = ((_this$managers = this.managers) === null || _this$managers === void 0 ? void 0 : _this$managers.componentTooltipManager) || ((_this$sceneViewer4 = this.sceneViewer) === null || _this$sceneViewer4 === void 0 ? void 0 : _this$sceneViewer4.componentTooltipManager) || ((_this$sceneViewer5 = this.sceneViewer) === null || _this$sceneViewer5 === void 0 || (_this$sceneViewer5 = _this$sceneViewer5.managers) === null || _this$sceneViewer5 === void 0 ? void 0 : _this$sceneViewer5.componentTooltipManager);
1081
+ var stateAdapter = tooltipMgr === null || tooltipMgr === void 0 ? void 0 : tooltipMgr._stateAdapter;
1113
1082
  if (stateAdapter !== null && stateAdapter !== void 0 && stateAdapter.setState) {
1114
- var scopedKey = parentUuid ? "".concat(parentUuid, "::").concat(attachmentId) : attachmentId;
1083
+ var scopedKey = getScopedAttachmentKey(attachmentId, parentUuid);
1115
1084
  try {
1116
1085
  stateAdapter.setState(scopedKey, stateId, value);
1117
1086
  } catch (err) {
1118
- console.warn('⚠️ setIoDeviceState(): stateAdapter.setState() threw:', err);
1087
+ console.warn('⚠️ _dispatchIoState(): stateAdapter.setState() threw:', err);
1119
1088
  }
1120
1089
  }
1121
-
1122
- // 2. Apply io-behavior changes
1123
- var ioBehavMgr = (_this$sceneViewer6 = this.sceneViewer) === null || _this$sceneViewer6 === void 0 || (_this$sceneViewer6 = _this$sceneViewer6.managers) === null || _this$sceneViewer6 === void 0 ? void 0 : _this$sceneViewer6.ioBehaviorManager;
1090
+ var ioBehavMgr = ((_this$managers2 = this.managers) === null || _this$managers2 === void 0 ? void 0 : _this$managers2.ioBehaviorManager) || ((_this$sceneViewer6 = this.sceneViewer) === null || _this$sceneViewer6 === void 0 || (_this$sceneViewer6 = _this$sceneViewer6.managers) === null || _this$sceneViewer6 === void 0 ? void 0 : _this$sceneViewer6.ioBehaviorManager) || ((_this$sceneViewer7 = this.sceneViewer) === null || _this$sceneViewer7 === void 0 ? void 0 : _this$sceneViewer7.ioBehaviorManager);
1124
1091
  if (ioBehavMgr) {
1125
- var _this$importedSceneDa4;
1126
1092
  ioBehavMgr.triggerState(attachmentId, stateId, value, parentUuid);
1127
-
1128
- // Evaluate cross-component behaviors if they exist in the imported scene
1129
- if ((_this$importedSceneDa4 = this.importedSceneData) !== null && _this$importedSceneDa4 !== void 0 && _this$importedSceneDa4.behaviors) {
1130
- ioBehavMgr.triggerCrossComponentBehaviors(this.importedSceneData.behaviors, parentUuid, attachmentId, stateId, value);
1131
- }
1132
1093
  }
1133
-
1134
- // 3. Emit event for host apps that don't use the state adapter (e.g. cp3d-viewer)
1135
- (_this$sceneViewer7 = this.sceneViewer) === null || _this$sceneViewer7 === void 0 || _this$sceneViewer7.emit('io-device-state-changed', {
1094
+ (_this$sceneViewer8 = this.sceneViewer) === null || _this$sceneViewer8 === void 0 || _this$sceneViewer8.emit('io-device-state-changed', {
1136
1095
  attachmentId: attachmentId,
1137
1096
  stateId: stateId,
1138
1097
  value: value,
1139
1098
  parentUuid: parentUuid || null
1140
1099
  });
1100
+ }
1101
+
1102
+ /**
1103
+ * Configure the state adapter on both tooltip and behavior managers.
1104
+ * @param {{ getState: Function, setState: Function }} stateAdapter
1105
+ */
1106
+ }, {
1107
+ key: "configureStateAdapter",
1108
+ value: function configureStateAdapter(stateAdapter) {
1109
+ var _this$managers3, _this$sceneViewer9, _this$managers4, _this$sceneViewer1, _this$sceneViewer10;
1110
+ var tooltipMgr = ((_this$managers3 = this.managers) === null || _this$managers3 === void 0 ? void 0 : _this$managers3.componentTooltipManager) || ((_this$sceneViewer9 = this.sceneViewer) === null || _this$sceneViewer9 === void 0 ? void 0 : _this$sceneViewer9.componentTooltipManager);
1111
+ if (tooltipMgr !== null && tooltipMgr !== void 0 && tooltipMgr.configure) {
1112
+ var _this$sceneViewer0;
1113
+ tooltipMgr.configure(stateAdapter);
1114
+ if ((_this$sceneViewer0 = this.sceneViewer) !== null && _this$sceneViewer0 !== void 0 && _this$sceneViewer0.managers) {
1115
+ this.sceneViewer.managers.componentTooltipManager = tooltipMgr;
1116
+ }
1117
+ }
1118
+ var ioBehavMgr = ((_this$managers4 = this.managers) === null || _this$managers4 === void 0 ? void 0 : _this$managers4.ioBehaviorManager) || ((_this$sceneViewer1 = this.sceneViewer) === null || _this$sceneViewer1 === void 0 || (_this$sceneViewer1 = _this$sceneViewer1.managers) === null || _this$sceneViewer1 === void 0 ? void 0 : _this$sceneViewer1.ioBehaviorManager) || ((_this$sceneViewer10 = this.sceneViewer) === null || _this$sceneViewer10 === void 0 ? void 0 : _this$sceneViewer10.ioBehaviorManager);
1119
+ if (ioBehavMgr !== null && ioBehavMgr !== void 0 && ioBehavMgr.configure) {
1120
+ ioBehavMgr.configure(stateAdapter);
1121
+ }
1122
+ }
1123
+
1124
+ /**
1125
+ * Set the state of an I/O device instance in the Three.js scene.
1126
+ *
1127
+ * @param {string} attachmentId - IO device attachment ID
1128
+ * @param {string} stateId - Data-point / state ID (e.g. 'power', 'level')
1129
+ * @param {*} value - New state value
1130
+ * @param {string} [parentUuid] - Parent component instance UUID
1131
+ * @returns {boolean}
1132
+ */
1133
+ }, {
1134
+ key: "setIoDeviceState",
1135
+ value: function setIoDeviceState(attachmentId, stateId, value, parentUuid) {
1136
+ this._dispatchIoState(attachmentId, stateId, value, parentUuid);
1141
1137
  return true;
1142
1138
  }
1143
1139
 
@@ -1154,8 +1150,8 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
1154
1150
  }, {
1155
1151
  key: "getSceneAttachments",
1156
1152
  value: function getSceneAttachments() {
1157
- var _this$sceneViewer8;
1158
- var scene = (_this$sceneViewer8 = this.sceneViewer) === null || _this$sceneViewer8 === void 0 ? void 0 : _this$sceneViewer8.scene;
1153
+ var _this$sceneViewer11;
1154
+ var scene = (_this$sceneViewer11 = this.sceneViewer) === null || _this$sceneViewer11 === void 0 ? void 0 : _this$sceneViewer11.scene;
1159
1155
  if (!scene) return [];
1160
1156
  var results = [];
1161
1157
  scene.traverse(function (obj) {
@@ -1863,6 +1859,58 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
1863
1859
  }
1864
1860
  return extendComponentDictionary;
1865
1861
  }()
1862
+ /**
1863
+ * Merge mesh animation configs into the component dictionary.
1864
+ * @param {Object<string, { behaviorConfig?: Array, meshNameMap?: Object }>} configsByAssetId
1865
+ * @returns {number} Count of dictionary entries updated
1866
+ */
1867
+ )
1868
+ }, {
1869
+ key: "mergeBehaviorConfigsIntoDictionary",
1870
+ value: function mergeBehaviorConfigsIntoDictionary(configsByAssetId) {
1871
+ if (!this.managers.componentDataManager) {
1872
+ console.warn('⚠️ mergeBehaviorConfigsIntoDictionary(): Component data manager not available');
1873
+ return 0;
1874
+ }
1875
+ return this.managers.componentDataManager.mergeBehaviorConfigsIntoDictionary(configsByAssetId);
1876
+ }
1877
+
1878
+ /**
1879
+ * Scan live scene for I/O device endpoints (for behavior authoring UIs).
1880
+ */
1881
+ }, {
1882
+ key: "scanSceneIoEndpoints",
1883
+ value: function scanSceneIoEndpoints$1() {
1884
+ return scanSceneIoEndpoints(this);
1885
+ }
1886
+
1887
+ /**
1888
+ * Apply cross-component behaviors to scene data and the runtime manager.
1889
+ */
1890
+ }, {
1891
+ key: "setSceneBehaviors",
1892
+ value: function setSceneBehaviors(behaviors) {
1893
+ applyCrossComponentBehaviors(this, behaviors);
1894
+ }
1895
+
1896
+ /**
1897
+ * Read cross-component behaviors from the current scene data mirrors.
1898
+ */
1899
+ }, {
1900
+ key: "getSceneBehaviors",
1901
+ value: function getSceneBehaviors() {
1902
+ return loadCrossComponentBehaviors(this);
1903
+ }
1904
+
1905
+ /**
1906
+ * Re-register all intra- and cross-component behaviors on placed instances.
1907
+ */
1908
+ }, {
1909
+ key: "reregisterSceneBehaviors",
1910
+ value: function reregisterSceneBehaviors$1() {
1911
+ reregisterSceneBehaviors(this);
1912
+ }
1913
+
1866
1914
  /**
1867
1915
  * Remove S3 components from component dictionary
1868
1916
  * @returns {Promise<boolean>} True if components were removed successfully, false otherwise
@@ -1875,7 +1923,6 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
1875
1923
  * console.log('S3 components removed');
1876
1924
  * }
1877
1925
  */
1878
- )
1879
1926
  }, {
1880
1927
  key: "removeS3Components",
1881
1928
  value: (function () {
@@ -2782,9 +2829,9 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
2782
2829
  }, {
2783
2830
  key: "clearScene",
2784
2831
  value: function clearScene() {
2785
- var _this$sceneViewer9;
2832
+ var _this$sceneViewer12;
2786
2833
  this.importedSceneData = null;
2787
- var ioBehavMgr = (_this$sceneViewer9 = this.sceneViewer) === null || _this$sceneViewer9 === void 0 || (_this$sceneViewer9 = _this$sceneViewer9.managers) === null || _this$sceneViewer9 === void 0 ? void 0 : _this$sceneViewer9.ioBehaviorManager;
2834
+ var ioBehavMgr = (_this$sceneViewer12 = this.sceneViewer) === null || _this$sceneViewer12 === void 0 || (_this$sceneViewer12 = _this$sceneViewer12.managers) === null || _this$sceneViewer12 === void 0 ? void 0 : _this$sceneViewer12.ioBehaviorManager;
2788
2835
  if (ioBehavMgr) {
2789
2836
  ioBehavMgr.setCrossComponentBehaviors([]);
2790
2837
  }
@@ -1,5 +1,6 @@
1
- import { createClass as _createClass, objectSpread2 as _objectSpread2, createForOfIteratorHelper as _createForOfIteratorHelper, typeof as _typeof, slicedToArray as _slicedToArray, toConsumableArray as _toConsumableArray, classCallCheck as _classCallCheck, asyncToGenerator as _asyncToGenerator, regenerator as _regenerator } from '../../_virtual/_rollupPluginBabelHelpers.js';
1
+ import { createClass as _createClass, objectSpread2 as _objectSpread2, createForOfIteratorHelper as _createForOfIteratorHelper, typeof as _typeof, toConsumableArray as _toConsumableArray, classCallCheck as _classCallCheck, asyncToGenerator as _asyncToGenerator, regenerator as _regenerator } from '../../_virtual/_rollupPluginBabelHelpers.js';
2
2
  import * as THREE from 'three';
3
+ import { registerBehaviorsForComponent } from '../utils/behaviorRegistration.js';
3
4
  import { CentralPlantValidator } from './centralPlantValidator.js';
4
5
  import { createTransformControls } from '../managers/controls/transformControlsManager.js';
5
6
  import { ThreeJSResourceManager } from '../managers/system/threeJSResourceManager.js';
@@ -216,6 +217,7 @@ var CentralPlantInternals = /*#__PURE__*/function () {
216
217
  // Initialize the component tooltip manager (screen-space tooltip on selection)
217
218
  this.centralPlant.managers.componentTooltipManager = new ComponentTooltipManager(this.centralPlant.sceneViewer);
218
219
  this.centralPlant.sceneViewer.componentTooltipManager = this.centralPlant.managers.componentTooltipManager;
220
+ this.centralPlant.sceneViewer.managers.componentTooltipManager = this.centralPlant.managers.componentTooltipManager;
219
221
  }
220
222
  }
221
223
 
@@ -1124,37 +1126,14 @@ var CentralPlantInternals = /*#__PURE__*/function () {
1124
1126
  // Add attached IO device models for smart components
1125
1127
  if (componentData.isSmart && componentData.attachedDevices) {
1126
1128
  var _this$centralPlant$sc8;
1127
- attachIODevicesToComponent(componentModel, componentData, modelPreloader, componentId);
1128
-
1129
- // Register behavior configs so IoBehaviorManager can respond to state changes
1130
1129
  var ioBehavMgr = (_this$centralPlant$sc8 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc8 === void 0 || (_this$centralPlant$sc8 = _this$centralPlant$sc8.managers) === null || _this$centralPlant$sc8 === void 0 ? void 0 : _this$centralPlant$sc8.ioBehaviorManager;
1131
- if (ioBehavMgr) {
1132
- var _loop = function _loop() {
1133
- var _modelPreloader$compo;
1134
- var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
1135
- attachmentId = _Object$entries$_i[0],
1136
- attachment = _Object$entries$_i[1];
1137
- var deviceData = (_modelPreloader$compo = modelPreloader.componentDictionary) === null || _modelPreloader$compo === void 0 ? void 0 : _modelPreloader$compo[attachment.deviceId];
1138
- if (!(deviceData !== null && deviceData !== void 0 && deviceData.behaviorConfig)) return 1; // continue
1139
- var deviceRoot = null;
1140
- componentModel.traverse(function (obj) {
1141
- var _obj$userData2;
1142
- if (!deviceRoot && ((_obj$userData2 = obj.userData) === null || _obj$userData2 === void 0 ? void 0 : _obj$userData2.attachmentId) === attachmentId) deviceRoot = obj;
1143
- });
1144
- if (deviceRoot) {
1145
- ioBehavMgr.loadBehaviors(attachmentId, deviceData.behaviorConfig, deviceRoot, componentId);
1146
- }
1147
- };
1148
- for (var _i = 0, _Object$entries = Object.entries(componentData.attachedDevices); _i < _Object$entries.length; _i++) {
1149
- if (_loop()) continue;
1130
+ attachIODevicesToComponent(componentModel, componentData, modelPreloader, componentId).then(function () {
1131
+ if (ioBehavMgr) {
1132
+ registerBehaviorsForComponent(ioBehavMgr, componentId, componentData, componentModel, modelPreloader.componentDictionary);
1150
1133
  }
1151
-
1152
- // Register component-level behaviors (intra-component io-device linking)
1153
- if (componentData.behaviors && componentData.behaviors.length > 0) {
1154
- // Registering ${componentData.behaviors.length} component-level behavior(s)
1155
- ioBehavMgr.registerComponentBehaviors(componentId, componentData.behaviors);
1156
- }
1157
- }
1134
+ }).catch(function (err) {
1135
+ console.error("\u274C Error attaching IO devices for ".concat(libraryId, ":"), err);
1136
+ });
1158
1137
  }
1159
1138
 
1160
1139
  // Notify the component manager about the new component
@@ -1284,8 +1263,8 @@ var CentralPlantInternals = /*#__PURE__*/function () {
1284
1263
  // the component (e.g., dynamically added but not yet synced to sceneData)
1285
1264
  if (connectorIds.size === 0 && threeScene) {
1286
1265
  threeScene.traverse(function (obj) {
1287
- var _obj$userData3, _obj$userData4;
1288
- if ((obj.uuid === resolvedUuid || ((_obj$userData3 = obj.userData) === null || _obj$userData3 === void 0 ? void 0 : _obj$userData3.originalUuid) === resolvedUuid) && ((_obj$userData4 = obj.userData) === null || _obj$userData4 === void 0 ? void 0 : _obj$userData4.objectType) === 'component') {
1266
+ var _obj$userData2, _obj$userData3;
1267
+ if ((obj.uuid === resolvedUuid || ((_obj$userData2 = obj.userData) === null || _obj$userData2 === void 0 ? void 0 : _obj$userData2.originalUuid) === resolvedUuid) && ((_obj$userData3 = obj.userData) === null || _obj$userData3 === void 0 ? void 0 : _obj$userData3.objectType) === 'component') {
1289
1268
  obj.children.forEach(function (child) {
1290
1269
  var _child$userData3;
1291
1270
  if (((_child$userData3 = child.userData) === null || _child$userData3 === void 0 ? void 0 : _child$userData3.objectType) === 'connector') {
@@ -1329,18 +1308,23 @@ var CentralPlantInternals = /*#__PURE__*/function () {
1329
1308
  // Step 5: Remove the component from the Three.js scene
1330
1309
  var success = componentManager.removeComponentFromScene(componentId);
1331
1310
  if (success) {
1311
+ var _this$centralPlant$sc10;
1312
+ var ioBehavMgr = (_this$centralPlant$sc10 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc10 === void 0 || (_this$centralPlant$sc10 = _this$centralPlant$sc10.managers) === null || _this$centralPlant$sc10 === void 0 ? void 0 : _this$centralPlant$sc10.ioBehaviorManager;
1313
+ if (ioBehavMgr !== null && ioBehavMgr !== void 0 && ioBehavMgr.unloadForComponent) {
1314
+ ioBehavMgr.unloadForComponent(resolvedUuid);
1315
+ }
1332
1316
  // Step 6: Directly remove SEGMENT-* and Gateway objects from Three.js whose
1333
1317
  // pathFrom/pathTo references one of this component's connectors.
1334
1318
  // This is surgical cleanup that works regardless of shouldUpdatePaths.
1335
1319
  if (connectorIds.size > 0 && threeScene) {
1336
1320
  var objectsToRemove = [];
1337
1321
  threeScene.traverse(function (obj) {
1338
- var _obj$uuid, _obj$userData5, _obj$uuid2, _obj$userData6;
1339
- var isComputedSegment = ((_obj$uuid = obj.uuid) === null || _obj$uuid === void 0 ? void 0 : _obj$uuid.startsWith('SEGMENT-')) && ((_obj$userData5 = obj.userData) === null || _obj$userData5 === void 0 ? void 0 : _obj$userData5.isDeclared) !== true;
1340
- var isComputedGateway = ((_obj$uuid2 = obj.uuid) === null || _obj$uuid2 === void 0 ? void 0 : _obj$uuid2.includes('Gateway')) && ((_obj$userData6 = obj.userData) === null || _obj$userData6 === void 0 ? void 0 : _obj$userData6.isDeclared) !== true;
1322
+ var _obj$uuid, _obj$userData4, _obj$uuid2, _obj$userData5;
1323
+ var isComputedSegment = ((_obj$uuid = obj.uuid) === null || _obj$uuid === void 0 ? void 0 : _obj$uuid.startsWith('SEGMENT-')) && ((_obj$userData4 = obj.userData) === null || _obj$userData4 === void 0 ? void 0 : _obj$userData4.isDeclared) !== true;
1324
+ var isComputedGateway = ((_obj$uuid2 = obj.uuid) === null || _obj$uuid2 === void 0 ? void 0 : _obj$uuid2.includes('Gateway')) && ((_obj$userData5 = obj.userData) === null || _obj$userData5 === void 0 ? void 0 : _obj$userData5.isDeclared) !== true;
1341
1325
  if (isComputedSegment || isComputedGateway) {
1342
- var _obj$userData7, _obj$userData8;
1343
- if (connectorIds.has((_obj$userData7 = obj.userData) === null || _obj$userData7 === void 0 ? void 0 : _obj$userData7.pathFrom) || connectorIds.has((_obj$userData8 = obj.userData) === null || _obj$userData8 === void 0 ? void 0 : _obj$userData8.pathTo)) {
1326
+ var _obj$userData6, _obj$userData7;
1327
+ if (connectorIds.has((_obj$userData6 = obj.userData) === null || _obj$userData6 === void 0 ? void 0 : _obj$userData6.pathFrom) || connectorIds.has((_obj$userData7 = obj.userData) === null || _obj$userData7 === void 0 ? void 0 : _obj$userData7.pathTo)) {
1344
1328
  objectsToRemove.push(obj);
1345
1329
  }
1346
1330
  }
@@ -10,6 +10,11 @@ export { SceneTooltipsManager } from './managers/scene/sceneTooltipsManager.js';
10
10
  export { ComponentTooltipManager } from './managers/scene/componentTooltipManager.js';
11
11
  export { SceneHierarchyManager } from './managers/scene/sceneHierarchyManager.js';
12
12
  export { IoBehaviorManager } from './managers/behaviors/IoBehaviorManager.js';
13
+ export { buildCrossBehavior, buildIntraBehavior, normalizeBehavior, parseCrossBehavior, parseIntraBehavior } from './utils/behaviorSchema.js';
14
+ export { registerBehaviorsForComponent, reloadBehaviorsForDeviceAsset } from './utils/behaviorRegistration.js';
15
+ export { getIoBehaviorManager, getScopedAttachmentKey, resolveDataPoints } from './utils/behaviorDispatch.js';
16
+ export { applyCrossComponentBehaviors, loadCrossComponentBehaviors, refreshSceneIntraBehaviors, reregisterSceneBehaviors, scanSceneIoEndpoints } from './utils/behaviorSceneUtils.js';
17
+ export { applyModelRootTranslation, applyModelRootTranslationFromWorldBase, modelOffsetToWorldDelta } from './utils/animationTransformUtils.js';
13
18
  export { ComponentManager } from './managers/components/componentManager.js';
14
19
  export { AnimationManager } from './managers/scene/animationManager.js';
15
20
  export { PathfindingManager } from './managers/pathfinding/pathfindingManager.js';