@2112-lab/central-plant 0.2.10 → 0.2.12

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.
@@ -28164,6 +28164,103 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
28164
28164
  return this.pathDataStore.get(pathId);
28165
28165
  }
28166
28166
 
28167
+ /**
28168
+ * Propagate flowAttributes from the original connection list to any gateway-split
28169
+ * rendered sub-paths in pathDataStore, then apply all flow visualizations.
28170
+ * Called after every pathfinding execution (initial load and transform updates).
28171
+ *
28172
+ * @param {Array} connections - Original connections array (may include flowAttributes)
28173
+ * @param {object} pathfindingResult - Result returned by _executePathfinding
28174
+ * @private
28175
+ */
28176
+ }, {
28177
+ key: "_propagateFlowAttributesAndApplyVisualizations",
28178
+ value: function _propagateFlowAttributesAndApplyVisualizations(connections, pathfindingResult) {
28179
+ var _this5 = this,
28180
+ _this$sceneViewer;
28181
+ if (!Array.isArray(connections) || !pathfindingResult) return;
28182
+
28183
+ // Pass 1: use the explicit gateway connection mappings to build a precise
28184
+ // original-pathId → Set<renderedPathId> map.
28185
+ var originalToSubPaths = new Map();
28186
+ if (pathfindingResult.gateways) {
28187
+ pathfindingResult.gateways.forEach(function (gateway) {
28188
+ var _ref = gateway.connections || {},
28189
+ removed = _ref.removed,
28190
+ added = _ref.added;
28191
+ if (!(removed !== null && removed !== void 0 && removed.length) || !(added !== null && added !== void 0 && added.length)) return;
28192
+ removed.forEach(function (removedConn) {
28193
+ var origId = "".concat(removedConn.from, "-->").concat(removedConn.to);
28194
+ if (!originalToSubPaths.has(origId)) originalToSubPaths.set(origId, new Set());
28195
+ added.forEach(function (addedConn) {
28196
+ originalToSubPaths.get(origId).add("".concat(addedConn.from, "-->").concat(addedConn.to));
28197
+ });
28198
+ });
28199
+ });
28200
+ }
28201
+ connections.forEach(function (conn) {
28202
+ if (!conn.flowAttributes) return;
28203
+ var origId = "".concat(conn.from, "-->").concat(conn.to);
28204
+ var subPathIds = new Set(originalToSubPaths.get(origId) || []);
28205
+ subPathIds.add(origId);
28206
+ subPathIds.forEach(function (subPathId) {
28207
+ var pd = _this5.pathDataStore.get(subPathId);
28208
+ if (pd && Object.keys(pd.flowAttributes).length === 0) {
28209
+ Object.entries(conn.flowAttributes).forEach(function (_ref2) {
28210
+ var _ref3 = _slicedToArray(_ref2, 2),
28211
+ key = _ref3[0],
28212
+ value = _ref3[1];
28213
+ return pd.setFlowAttribute(key, value);
28214
+ });
28215
+ }
28216
+ });
28217
+ });
28218
+
28219
+ // Pass 2: endpoint fallback for Gateway→Gateway intermediate segments and
28220
+ // for paths whose connections were restructured by manualizeSegment/manualizeGateway.
28221
+ // After manualization, currentSceneData.connections no longer contains the original
28222
+ // A→B entry with flowAttributes (it's been split into new sub-connections), so we
28223
+ // seed the endpoint maps from both the connections array AND from existing pathDataStore
28224
+ // entries that already carry flowAttributes — those persist across re-executions.
28225
+ var fromEndpointAttrs = new Map();
28226
+ var toEndpointAttrs = new Map();
28227
+
28228
+ // Seed from persisted pathDataStore entries first (covers post-manualization re-runs)
28229
+ this.pathDataStore.forEach(function (pd, pathId) {
28230
+ if (Object.keys(pd.flowAttributes).length === 0) return;
28231
+ var sepIdx = pathId.indexOf('-->');
28232
+ if (sepIdx === -1) return;
28233
+ var from = pathId.slice(0, sepIdx);
28234
+ var to = pathId.slice(sepIdx + 3);
28235
+ if (!fromEndpointAttrs.has(from)) fromEndpointAttrs.set(from, pd.flowAttributes);
28236
+ if (!toEndpointAttrs.has(to)) toEndpointAttrs.set(to, pd.flowAttributes);
28237
+ });
28238
+
28239
+ // Also seed from connections array (covers initial load before pathDataStore has any attrs)
28240
+ connections.forEach(function (conn) {
28241
+ if (!conn.flowAttributes) return;
28242
+ if (!fromEndpointAttrs.has(conn.from)) fromEndpointAttrs.set(conn.from, conn.flowAttributes);
28243
+ if (!toEndpointAttrs.has(conn.to)) toEndpointAttrs.set(conn.to, conn.flowAttributes);
28244
+ });
28245
+ this.pathDataStore.forEach(function (pd, pathId) {
28246
+ if (Object.keys(pd.flowAttributes).length > 0) return;
28247
+ var sepIdx = pathId.indexOf('-->');
28248
+ if (sepIdx === -1) return;
28249
+ var from = pathId.slice(0, sepIdx);
28250
+ var to = pathId.slice(sepIdx + 3);
28251
+ var attrs = fromEndpointAttrs.get(from) || toEndpointAttrs.get(to);
28252
+ if (attrs) Object.entries(attrs).forEach(function (_ref4) {
28253
+ var _ref5 = _slicedToArray(_ref4, 2),
28254
+ key = _ref5[0],
28255
+ value = _ref5[1];
28256
+ return pd.setFlowAttribute(key, value);
28257
+ });
28258
+ });
28259
+
28260
+ // Apply visualizations
28261
+ (_this$sceneViewer = this.sceneViewer) === null || _this$sceneViewer === void 0 || (_this$sceneViewer = _this$sceneViewer.managers) === null || _this$sceneViewer === void 0 || (_this$sceneViewer = _this$sceneViewer.pathFlowManager) === null || _this$sceneViewer === void 0 || _this$sceneViewer.applyAllVisualizations();
28262
+ }
28263
+
28167
28264
  /**
28168
28265
  * Initialize pathfinder and create paths
28169
28266
  */
@@ -28171,9 +28268,8 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
28171
28268
  key: "initializePathfinder",
28172
28269
  value: (function () {
28173
28270
  var _initializePathfinder = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2(data, crosscubeTextureSet) {
28174
- var _this5 = this,
28175
- _this$sceneViewer;
28176
- var pathfindingResult, originalToSubPaths, fromEndpointAttrs, flowMgr;
28271
+ var _this6 = this;
28272
+ var pathfindingResult;
28177
28273
  return _regenerator().w(function (_context2) {
28178
28274
  while (1) switch (_context2.n) {
28179
28275
  case 0:
@@ -28186,11 +28282,11 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
28186
28282
  data.connections.forEach(function (conn) {
28187
28283
  if (conn.flowAttributes && _typeof(conn.flowAttributes) === 'object') {
28188
28284
  var pathId = "".concat(conn.from, "-->").concat(conn.to);
28189
- var pd = _this5._getOrCreatePathData(pathId, conn.from, conn.to);
28190
- Object.entries(conn.flowAttributes).forEach(function (_ref) {
28191
- var _ref2 = _slicedToArray(_ref, 2),
28192
- key = _ref2[0],
28193
- value = _ref2[1];
28285
+ var pd = _this6._getOrCreatePathData(pathId, conn.from, conn.to);
28286
+ Object.entries(conn.flowAttributes).forEach(function (_ref6) {
28287
+ var _ref7 = _slicedToArray(_ref6, 2),
28288
+ key = _ref7[0],
28289
+ value = _ref7[1];
28194
28290
  pd.setFlowAttribute(key, value);
28195
28291
  });
28196
28292
  console.log("\uD83C\uDF0A Loaded flowAttributes for path \"".concat(pathId, "\":"), conn.flowAttributes);
@@ -28206,82 +28302,7 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
28206
28302
  });
28207
28303
  case 1:
28208
28304
  pathfindingResult = _context2.v;
28209
- // ── Propagate flowAttributes to gateway-split rendered paths ──────────
28210
- // The pathfinder may split a connection A→B through gateway waypoints,
28211
- // producing sub-paths like A→G and G→B with different pathIds.
28212
- // We need to copy the original connection's flowAttributes onto every
28213
- // rendered sub-path entry in pathDataStore so the visualisation can
28214
- // find them by their rendered pathId.
28215
- if (Array.isArray(data.connections) && pathfindingResult) {
28216
- // Pass 1: use the explicit gateway connection mappings to get a precise
28217
- // original→sub-path map.
28218
- originalToSubPaths = new Map(); // origPathId → Set<renderedPathId>
28219
- if (pathfindingResult.gateways) {
28220
- pathfindingResult.gateways.forEach(function (gateway) {
28221
- var _ref3 = gateway.connections || {},
28222
- removed = _ref3.removed,
28223
- added = _ref3.added;
28224
- if (!(removed !== null && removed !== void 0 && removed.length) || !(added !== null && added !== void 0 && added.length)) return;
28225
- removed.forEach(function (removedConn) {
28226
- var origId = "".concat(removedConn.from, "-->").concat(removedConn.to);
28227
- if (!originalToSubPaths.has(origId)) originalToSubPaths.set(origId, new Set());
28228
- added.forEach(function (addedConn) {
28229
- originalToSubPaths.get(origId).add("".concat(addedConn.from, "-->").concat(addedConn.to));
28230
- });
28231
- });
28232
- });
28233
- }
28234
- data.connections.forEach(function (conn) {
28235
- if (!conn.flowAttributes) return;
28236
- var origId = "".concat(conn.from, "-->").concat(conn.to);
28237
- var subPathIds = new Set(originalToSubPaths.get(origId) || []);
28238
- subPathIds.add(origId); // include the direct path if it wasn't rewired
28239
-
28240
- subPathIds.forEach(function (subPathId) {
28241
- var pd = _this5.pathDataStore.get(subPathId);
28242
- if (pd && Object.keys(pd.flowAttributes).length === 0) {
28243
- Object.entries(conn.flowAttributes).forEach(function (_ref4) {
28244
- var _ref5 = _slicedToArray(_ref4, 2),
28245
- key = _ref5[0],
28246
- value = _ref5[1];
28247
- pd.setFlowAttribute(key, value);
28248
- });
28249
- console.log("\uD83C\uDF0A Propagated flowAttributes to sub-path \"".concat(subPathId, "\" from \"").concat(origId, "\""));
28250
- }
28251
- });
28252
- });
28253
-
28254
- // Pass 2: endpoint fallback for any rendered path still missing attributes
28255
- // (covers Gateway→Gateway intermediate segments not captured by gateway.connections.added)
28256
- fromEndpointAttrs = new Map(); // connectorId → flowAttributes
28257
- data.connections.forEach(function (conn) {
28258
- if (conn.flowAttributes && !fromEndpointAttrs.has(conn.from)) {
28259
- fromEndpointAttrs.set(conn.from, conn.flowAttributes);
28260
- }
28261
- });
28262
- this.pathDataStore.forEach(function (pd, pathId) {
28263
- if (Object.keys(pd.flowAttributes).length > 0) return;
28264
- var sepIdx = pathId.indexOf('-->');
28265
- if (sepIdx === -1) return;
28266
- var from = pathId.slice(0, sepIdx);
28267
- var attrs = fromEndpointAttrs.get(from);
28268
- if (attrs) {
28269
- Object.entries(attrs).forEach(function (_ref6) {
28270
- var _ref7 = _slicedToArray(_ref6, 2),
28271
- key = _ref7[0],
28272
- value = _ref7[1];
28273
- return pd.setFlowAttribute(key, value);
28274
- });
28275
- console.log("\uD83C\uDF0A Endpoint-matched flowAttributes for path \"".concat(pathId, "\""));
28276
- }
28277
- });
28278
- }
28279
-
28280
- // ── Apply flow visualizations now that paths are rendered ──────────────
28281
- flowMgr = (_this$sceneViewer = this.sceneViewer) === null || _this$sceneViewer === void 0 || (_this$sceneViewer = _this$sceneViewer.managers) === null || _this$sceneViewer === void 0 ? void 0 : _this$sceneViewer.pathFlowManager;
28282
- if (flowMgr) {
28283
- flowMgr.applyAllVisualizations();
28284
- }
28305
+ this._propagateFlowAttributesAndApplyVisualizations(data.connections, pathfindingResult);
28285
28306
 
28286
28307
  // Update connections with rewired connections
28287
28308
  if (pathfindingResult.rewiredConnections) {
@@ -28407,6 +28428,9 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
28407
28428
  });
28408
28429
  case 2:
28409
28430
  result = _context3.v;
28431
+ // Re-apply flow attribute colors (new materials are created on each execution)
28432
+ this._propagateFlowAttributesAndApplyVisualizations(currentSceneData.connections, result);
28433
+
28410
28434
  // Cache fingerprint + result for next comparison
28411
28435
  this._lastPathfindingFingerprint = fingerprint;
28412
28436
  this._lastPathfindingResult = result;
@@ -32255,7 +32279,7 @@ var SceneOperationsManager = /*#__PURE__*/function () {
32255
32279
  if (typeof window !== 'undefined') {
32256
32280
  isDev = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1';
32257
32281
  }
32258
- if (isDev && segment.material) {
32282
+ if (isDev && process.env.DISABLE_MANUALIZED_SEGMENT_COLORING !== 'true' && segment.material) {
32259
32283
  segment.material.color.setHex(0x0000ff); // Blue
32260
32284
  console.log('🎨 Set manual segment material color to blue (dev mode)');
32261
32285
  }
@@ -32286,7 +32310,7 @@ var SceneOperationsManager = /*#__PURE__*/function () {
32286
32310
  console.log('🔌 Created connectors:', connectors);
32287
32311
 
32288
32312
  // In dev mode, enlarge connectors by 1.5x and turn them red
32289
- if (isDev) {
32313
+ if (isDev && process.env.DISABLE_MANUALIZED_SEGMENT_COLORING !== 'true') {
32290
32314
  connectors.forEach(function (connector) {
32291
32315
  if (connector) {
32292
32316
  connector.scale.set(1.25, 1.25, 1.25);
@@ -37816,7 +37840,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
37816
37840
  * Initialize the CentralPlant manager
37817
37841
  *
37818
37842
  * @constructor
37819
- * @version 0.2.10
37843
+ * @version 0.2.12
37820
37844
  * @updated 2025-10-22
37821
37845
  *
37822
37846
  * @description Creates a new CentralPlant instance and initializes internal managers and utilities.
@@ -35,7 +35,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
35
35
  * Initialize the CentralPlant manager
36
36
  *
37
37
  * @constructor
38
- * @version 0.2.10
38
+ * @version 0.2.12
39
39
  * @updated 2025-10-22
40
40
  *
41
41
  * @description Creates a new CentralPlant instance and initializes internal managers and utilities.
@@ -541,6 +541,103 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
541
541
  return this.pathDataStore.get(pathId);
542
542
  }
543
543
 
544
+ /**
545
+ * Propagate flowAttributes from the original connection list to any gateway-split
546
+ * rendered sub-paths in pathDataStore, then apply all flow visualizations.
547
+ * Called after every pathfinding execution (initial load and transform updates).
548
+ *
549
+ * @param {Array} connections - Original connections array (may include flowAttributes)
550
+ * @param {object} pathfindingResult - Result returned by _executePathfinding
551
+ * @private
552
+ */
553
+ }, {
554
+ key: "_propagateFlowAttributesAndApplyVisualizations",
555
+ value: function _propagateFlowAttributesAndApplyVisualizations(connections, pathfindingResult) {
556
+ var _this5 = this,
557
+ _this$sceneViewer;
558
+ if (!Array.isArray(connections) || !pathfindingResult) return;
559
+
560
+ // Pass 1: use the explicit gateway connection mappings to build a precise
561
+ // original-pathId → Set<renderedPathId> map.
562
+ var originalToSubPaths = new Map();
563
+ if (pathfindingResult.gateways) {
564
+ pathfindingResult.gateways.forEach(function (gateway) {
565
+ var _ref = gateway.connections || {},
566
+ removed = _ref.removed,
567
+ added = _ref.added;
568
+ if (!(removed !== null && removed !== void 0 && removed.length) || !(added !== null && added !== void 0 && added.length)) return;
569
+ removed.forEach(function (removedConn) {
570
+ var origId = "".concat(removedConn.from, "-->").concat(removedConn.to);
571
+ if (!originalToSubPaths.has(origId)) originalToSubPaths.set(origId, new Set());
572
+ added.forEach(function (addedConn) {
573
+ originalToSubPaths.get(origId).add("".concat(addedConn.from, "-->").concat(addedConn.to));
574
+ });
575
+ });
576
+ });
577
+ }
578
+ connections.forEach(function (conn) {
579
+ if (!conn.flowAttributes) return;
580
+ var origId = "".concat(conn.from, "-->").concat(conn.to);
581
+ var subPathIds = new Set(originalToSubPaths.get(origId) || []);
582
+ subPathIds.add(origId);
583
+ subPathIds.forEach(function (subPathId) {
584
+ var pd = _this5.pathDataStore.get(subPathId);
585
+ if (pd && Object.keys(pd.flowAttributes).length === 0) {
586
+ Object.entries(conn.flowAttributes).forEach(function (_ref2) {
587
+ var _ref3 = _rollupPluginBabelHelpers.slicedToArray(_ref2, 2),
588
+ key = _ref3[0],
589
+ value = _ref3[1];
590
+ return pd.setFlowAttribute(key, value);
591
+ });
592
+ }
593
+ });
594
+ });
595
+
596
+ // Pass 2: endpoint fallback for Gateway→Gateway intermediate segments and
597
+ // for paths whose connections were restructured by manualizeSegment/manualizeGateway.
598
+ // After manualization, currentSceneData.connections no longer contains the original
599
+ // A→B entry with flowAttributes (it's been split into new sub-connections), so we
600
+ // seed the endpoint maps from both the connections array AND from existing pathDataStore
601
+ // entries that already carry flowAttributes — those persist across re-executions.
602
+ var fromEndpointAttrs = new Map();
603
+ var toEndpointAttrs = new Map();
604
+
605
+ // Seed from persisted pathDataStore entries first (covers post-manualization re-runs)
606
+ this.pathDataStore.forEach(function (pd, pathId) {
607
+ if (Object.keys(pd.flowAttributes).length === 0) return;
608
+ var sepIdx = pathId.indexOf('-->');
609
+ if (sepIdx === -1) return;
610
+ var from = pathId.slice(0, sepIdx);
611
+ var to = pathId.slice(sepIdx + 3);
612
+ if (!fromEndpointAttrs.has(from)) fromEndpointAttrs.set(from, pd.flowAttributes);
613
+ if (!toEndpointAttrs.has(to)) toEndpointAttrs.set(to, pd.flowAttributes);
614
+ });
615
+
616
+ // Also seed from connections array (covers initial load before pathDataStore has any attrs)
617
+ connections.forEach(function (conn) {
618
+ if (!conn.flowAttributes) return;
619
+ if (!fromEndpointAttrs.has(conn.from)) fromEndpointAttrs.set(conn.from, conn.flowAttributes);
620
+ if (!toEndpointAttrs.has(conn.to)) toEndpointAttrs.set(conn.to, conn.flowAttributes);
621
+ });
622
+ this.pathDataStore.forEach(function (pd, pathId) {
623
+ if (Object.keys(pd.flowAttributes).length > 0) return;
624
+ var sepIdx = pathId.indexOf('-->');
625
+ if (sepIdx === -1) return;
626
+ var from = pathId.slice(0, sepIdx);
627
+ var to = pathId.slice(sepIdx + 3);
628
+ var attrs = fromEndpointAttrs.get(from) || toEndpointAttrs.get(to);
629
+ if (attrs) Object.entries(attrs).forEach(function (_ref4) {
630
+ var _ref5 = _rollupPluginBabelHelpers.slicedToArray(_ref4, 2),
631
+ key = _ref5[0],
632
+ value = _ref5[1];
633
+ return pd.setFlowAttribute(key, value);
634
+ });
635
+ });
636
+
637
+ // Apply visualizations
638
+ (_this$sceneViewer = this.sceneViewer) === null || _this$sceneViewer === void 0 || (_this$sceneViewer = _this$sceneViewer.managers) === null || _this$sceneViewer === void 0 || (_this$sceneViewer = _this$sceneViewer.pathFlowManager) === null || _this$sceneViewer === void 0 || _this$sceneViewer.applyAllVisualizations();
639
+ }
640
+
544
641
  /**
545
642
  * Initialize pathfinder and create paths
546
643
  */
@@ -548,9 +645,8 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
548
645
  key: "initializePathfinder",
549
646
  value: (function () {
550
647
  var _initializePathfinder = _rollupPluginBabelHelpers.asyncToGenerator(/*#__PURE__*/_rollupPluginBabelHelpers.regenerator().m(function _callee2(data, crosscubeTextureSet) {
551
- var _this5 = this,
552
- _this$sceneViewer;
553
- var pathfindingResult, originalToSubPaths, fromEndpointAttrs, flowMgr;
648
+ var _this6 = this;
649
+ var pathfindingResult;
554
650
  return _rollupPluginBabelHelpers.regenerator().w(function (_context2) {
555
651
  while (1) switch (_context2.n) {
556
652
  case 0:
@@ -563,11 +659,11 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
563
659
  data.connections.forEach(function (conn) {
564
660
  if (conn.flowAttributes && _rollupPluginBabelHelpers["typeof"](conn.flowAttributes) === 'object') {
565
661
  var pathId = "".concat(conn.from, "-->").concat(conn.to);
566
- var pd = _this5._getOrCreatePathData(pathId, conn.from, conn.to);
567
- Object.entries(conn.flowAttributes).forEach(function (_ref) {
568
- var _ref2 = _rollupPluginBabelHelpers.slicedToArray(_ref, 2),
569
- key = _ref2[0],
570
- value = _ref2[1];
662
+ var pd = _this6._getOrCreatePathData(pathId, conn.from, conn.to);
663
+ Object.entries(conn.flowAttributes).forEach(function (_ref6) {
664
+ var _ref7 = _rollupPluginBabelHelpers.slicedToArray(_ref6, 2),
665
+ key = _ref7[0],
666
+ value = _ref7[1];
571
667
  pd.setFlowAttribute(key, value);
572
668
  });
573
669
  console.log("\uD83C\uDF0A Loaded flowAttributes for path \"".concat(pathId, "\":"), conn.flowAttributes);
@@ -583,82 +679,7 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
583
679
  });
584
680
  case 1:
585
681
  pathfindingResult = _context2.v;
586
- // ── Propagate flowAttributes to gateway-split rendered paths ──────────
587
- // The pathfinder may split a connection A→B through gateway waypoints,
588
- // producing sub-paths like A→G and G→B with different pathIds.
589
- // We need to copy the original connection's flowAttributes onto every
590
- // rendered sub-path entry in pathDataStore so the visualisation can
591
- // find them by their rendered pathId.
592
- if (Array.isArray(data.connections) && pathfindingResult) {
593
- // Pass 1: use the explicit gateway connection mappings to get a precise
594
- // original→sub-path map.
595
- originalToSubPaths = new Map(); // origPathId → Set<renderedPathId>
596
- if (pathfindingResult.gateways) {
597
- pathfindingResult.gateways.forEach(function (gateway) {
598
- var _ref3 = gateway.connections || {},
599
- removed = _ref3.removed,
600
- added = _ref3.added;
601
- if (!(removed !== null && removed !== void 0 && removed.length) || !(added !== null && added !== void 0 && added.length)) return;
602
- removed.forEach(function (removedConn) {
603
- var origId = "".concat(removedConn.from, "-->").concat(removedConn.to);
604
- if (!originalToSubPaths.has(origId)) originalToSubPaths.set(origId, new Set());
605
- added.forEach(function (addedConn) {
606
- originalToSubPaths.get(origId).add("".concat(addedConn.from, "-->").concat(addedConn.to));
607
- });
608
- });
609
- });
610
- }
611
- data.connections.forEach(function (conn) {
612
- if (!conn.flowAttributes) return;
613
- var origId = "".concat(conn.from, "-->").concat(conn.to);
614
- var subPathIds = new Set(originalToSubPaths.get(origId) || []);
615
- subPathIds.add(origId); // include the direct path if it wasn't rewired
616
-
617
- subPathIds.forEach(function (subPathId) {
618
- var pd = _this5.pathDataStore.get(subPathId);
619
- if (pd && Object.keys(pd.flowAttributes).length === 0) {
620
- Object.entries(conn.flowAttributes).forEach(function (_ref4) {
621
- var _ref5 = _rollupPluginBabelHelpers.slicedToArray(_ref4, 2),
622
- key = _ref5[0],
623
- value = _ref5[1];
624
- pd.setFlowAttribute(key, value);
625
- });
626
- console.log("\uD83C\uDF0A Propagated flowAttributes to sub-path \"".concat(subPathId, "\" from \"").concat(origId, "\""));
627
- }
628
- });
629
- });
630
-
631
- // Pass 2: endpoint fallback for any rendered path still missing attributes
632
- // (covers Gateway→Gateway intermediate segments not captured by gateway.connections.added)
633
- fromEndpointAttrs = new Map(); // connectorId → flowAttributes
634
- data.connections.forEach(function (conn) {
635
- if (conn.flowAttributes && !fromEndpointAttrs.has(conn.from)) {
636
- fromEndpointAttrs.set(conn.from, conn.flowAttributes);
637
- }
638
- });
639
- this.pathDataStore.forEach(function (pd, pathId) {
640
- if (Object.keys(pd.flowAttributes).length > 0) return;
641
- var sepIdx = pathId.indexOf('-->');
642
- if (sepIdx === -1) return;
643
- var from = pathId.slice(0, sepIdx);
644
- var attrs = fromEndpointAttrs.get(from);
645
- if (attrs) {
646
- Object.entries(attrs).forEach(function (_ref6) {
647
- var _ref7 = _rollupPluginBabelHelpers.slicedToArray(_ref6, 2),
648
- key = _ref7[0],
649
- value = _ref7[1];
650
- return pd.setFlowAttribute(key, value);
651
- });
652
- console.log("\uD83C\uDF0A Endpoint-matched flowAttributes for path \"".concat(pathId, "\""));
653
- }
654
- });
655
- }
656
-
657
- // ── Apply flow visualizations now that paths are rendered ──────────────
658
- flowMgr = (_this$sceneViewer = this.sceneViewer) === null || _this$sceneViewer === void 0 || (_this$sceneViewer = _this$sceneViewer.managers) === null || _this$sceneViewer === void 0 ? void 0 : _this$sceneViewer.pathFlowManager;
659
- if (flowMgr) {
660
- flowMgr.applyAllVisualizations();
661
- }
682
+ this._propagateFlowAttributesAndApplyVisualizations(data.connections, pathfindingResult);
662
683
 
663
684
  // Update connections with rewired connections
664
685
  if (pathfindingResult.rewiredConnections) {
@@ -784,6 +805,9 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
784
805
  });
785
806
  case 2:
786
807
  result = _context3.v;
808
+ // Re-apply flow attribute colors (new materials are created on each execution)
809
+ this._propagateFlowAttributesAndApplyVisualizations(currentSceneData.connections, result);
810
+
787
811
  // Cache fingerprint + result for next comparison
788
812
  this._lastPathfindingFingerprint = fingerprint;
789
813
  this._lastPathfindingResult = result;
@@ -1771,7 +1771,7 @@ var SceneOperationsManager = /*#__PURE__*/function () {
1771
1771
  if (typeof window !== 'undefined') {
1772
1772
  isDev = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1';
1773
1773
  }
1774
- if (isDev && segment.material) {
1774
+ if (isDev && process.env.DISABLE_MANUALIZED_SEGMENT_COLORING !== 'true' && segment.material) {
1775
1775
  segment.material.color.setHex(0x0000ff); // Blue
1776
1776
  console.log('🎨 Set manual segment material color to blue (dev mode)');
1777
1777
  }
@@ -1802,7 +1802,7 @@ var SceneOperationsManager = /*#__PURE__*/function () {
1802
1802
  console.log('🔌 Created connectors:', connectors);
1803
1803
 
1804
1804
  // In dev mode, enlarge connectors by 1.5x and turn them red
1805
- if (isDev) {
1805
+ if (isDev && process.env.DISABLE_MANUALIZED_SEGMENT_COLORING !== 'true') {
1806
1806
  connectors.forEach(function (connector) {
1807
1807
  if (connector) {
1808
1808
  connector.scale.set(1.25, 1.25, 1.25);
@@ -31,7 +31,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
31
31
  * Initialize the CentralPlant manager
32
32
  *
33
33
  * @constructor
34
- * @version 0.2.10
34
+ * @version 0.2.12
35
35
  * @updated 2025-10-22
36
36
  *
37
37
  * @description Creates a new CentralPlant instance and initializes internal managers and utilities.
@@ -1,4 +1,4 @@
1
- import { inherits as _inherits, createClass as _createClass, createForOfIteratorHelper as _createForOfIteratorHelper, objectSpread2 as _objectSpread2, superPropGet as _superPropGet, classCallCheck as _classCallCheck, callSuper as _callSuper, toConsumableArray as _toConsumableArray, asyncToGenerator as _asyncToGenerator, regenerator as _regenerator, slicedToArray as _slicedToArray, typeof as _typeof } from '../../../_virtual/_rollupPluginBabelHelpers.js';
1
+ import { inherits as _inherits, createClass as _createClass, createForOfIteratorHelper as _createForOfIteratorHelper, objectSpread2 as _objectSpread2, slicedToArray as _slicedToArray, superPropGet as _superPropGet, classCallCheck as _classCallCheck, callSuper as _callSuper, toConsumableArray as _toConsumableArray, asyncToGenerator as _asyncToGenerator, regenerator as _regenerator, typeof as _typeof } from '../../../_virtual/_rollupPluginBabelHelpers.js';
2
2
  import * as THREE from 'three';
3
3
  import { Pathfinder } from '@2112-lab/pathfinder';
4
4
  import { BaseDisposable } from '../../core/baseDisposable.js';
@@ -517,6 +517,103 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
517
517
  return this.pathDataStore.get(pathId);
518
518
  }
519
519
 
520
+ /**
521
+ * Propagate flowAttributes from the original connection list to any gateway-split
522
+ * rendered sub-paths in pathDataStore, then apply all flow visualizations.
523
+ * Called after every pathfinding execution (initial load and transform updates).
524
+ *
525
+ * @param {Array} connections - Original connections array (may include flowAttributes)
526
+ * @param {object} pathfindingResult - Result returned by _executePathfinding
527
+ * @private
528
+ */
529
+ }, {
530
+ key: "_propagateFlowAttributesAndApplyVisualizations",
531
+ value: function _propagateFlowAttributesAndApplyVisualizations(connections, pathfindingResult) {
532
+ var _this5 = this,
533
+ _this$sceneViewer;
534
+ if (!Array.isArray(connections) || !pathfindingResult) return;
535
+
536
+ // Pass 1: use the explicit gateway connection mappings to build a precise
537
+ // original-pathId → Set<renderedPathId> map.
538
+ var originalToSubPaths = new Map();
539
+ if (pathfindingResult.gateways) {
540
+ pathfindingResult.gateways.forEach(function (gateway) {
541
+ var _ref = gateway.connections || {},
542
+ removed = _ref.removed,
543
+ added = _ref.added;
544
+ if (!(removed !== null && removed !== void 0 && removed.length) || !(added !== null && added !== void 0 && added.length)) return;
545
+ removed.forEach(function (removedConn) {
546
+ var origId = "".concat(removedConn.from, "-->").concat(removedConn.to);
547
+ if (!originalToSubPaths.has(origId)) originalToSubPaths.set(origId, new Set());
548
+ added.forEach(function (addedConn) {
549
+ originalToSubPaths.get(origId).add("".concat(addedConn.from, "-->").concat(addedConn.to));
550
+ });
551
+ });
552
+ });
553
+ }
554
+ connections.forEach(function (conn) {
555
+ if (!conn.flowAttributes) return;
556
+ var origId = "".concat(conn.from, "-->").concat(conn.to);
557
+ var subPathIds = new Set(originalToSubPaths.get(origId) || []);
558
+ subPathIds.add(origId);
559
+ subPathIds.forEach(function (subPathId) {
560
+ var pd = _this5.pathDataStore.get(subPathId);
561
+ if (pd && Object.keys(pd.flowAttributes).length === 0) {
562
+ Object.entries(conn.flowAttributes).forEach(function (_ref2) {
563
+ var _ref3 = _slicedToArray(_ref2, 2),
564
+ key = _ref3[0],
565
+ value = _ref3[1];
566
+ return pd.setFlowAttribute(key, value);
567
+ });
568
+ }
569
+ });
570
+ });
571
+
572
+ // Pass 2: endpoint fallback for Gateway→Gateway intermediate segments and
573
+ // for paths whose connections were restructured by manualizeSegment/manualizeGateway.
574
+ // After manualization, currentSceneData.connections no longer contains the original
575
+ // A→B entry with flowAttributes (it's been split into new sub-connections), so we
576
+ // seed the endpoint maps from both the connections array AND from existing pathDataStore
577
+ // entries that already carry flowAttributes — those persist across re-executions.
578
+ var fromEndpointAttrs = new Map();
579
+ var toEndpointAttrs = new Map();
580
+
581
+ // Seed from persisted pathDataStore entries first (covers post-manualization re-runs)
582
+ this.pathDataStore.forEach(function (pd, pathId) {
583
+ if (Object.keys(pd.flowAttributes).length === 0) return;
584
+ var sepIdx = pathId.indexOf('-->');
585
+ if (sepIdx === -1) return;
586
+ var from = pathId.slice(0, sepIdx);
587
+ var to = pathId.slice(sepIdx + 3);
588
+ if (!fromEndpointAttrs.has(from)) fromEndpointAttrs.set(from, pd.flowAttributes);
589
+ if (!toEndpointAttrs.has(to)) toEndpointAttrs.set(to, pd.flowAttributes);
590
+ });
591
+
592
+ // Also seed from connections array (covers initial load before pathDataStore has any attrs)
593
+ connections.forEach(function (conn) {
594
+ if (!conn.flowAttributes) return;
595
+ if (!fromEndpointAttrs.has(conn.from)) fromEndpointAttrs.set(conn.from, conn.flowAttributes);
596
+ if (!toEndpointAttrs.has(conn.to)) toEndpointAttrs.set(conn.to, conn.flowAttributes);
597
+ });
598
+ this.pathDataStore.forEach(function (pd, pathId) {
599
+ if (Object.keys(pd.flowAttributes).length > 0) return;
600
+ var sepIdx = pathId.indexOf('-->');
601
+ if (sepIdx === -1) return;
602
+ var from = pathId.slice(0, sepIdx);
603
+ var to = pathId.slice(sepIdx + 3);
604
+ var attrs = fromEndpointAttrs.get(from) || toEndpointAttrs.get(to);
605
+ if (attrs) Object.entries(attrs).forEach(function (_ref4) {
606
+ var _ref5 = _slicedToArray(_ref4, 2),
607
+ key = _ref5[0],
608
+ value = _ref5[1];
609
+ return pd.setFlowAttribute(key, value);
610
+ });
611
+ });
612
+
613
+ // Apply visualizations
614
+ (_this$sceneViewer = this.sceneViewer) === null || _this$sceneViewer === void 0 || (_this$sceneViewer = _this$sceneViewer.managers) === null || _this$sceneViewer === void 0 || (_this$sceneViewer = _this$sceneViewer.pathFlowManager) === null || _this$sceneViewer === void 0 || _this$sceneViewer.applyAllVisualizations();
615
+ }
616
+
520
617
  /**
521
618
  * Initialize pathfinder and create paths
522
619
  */
@@ -524,9 +621,8 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
524
621
  key: "initializePathfinder",
525
622
  value: (function () {
526
623
  var _initializePathfinder = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2(data, crosscubeTextureSet) {
527
- var _this5 = this,
528
- _this$sceneViewer;
529
- var pathfindingResult, originalToSubPaths, fromEndpointAttrs, flowMgr;
624
+ var _this6 = this;
625
+ var pathfindingResult;
530
626
  return _regenerator().w(function (_context2) {
531
627
  while (1) switch (_context2.n) {
532
628
  case 0:
@@ -539,11 +635,11 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
539
635
  data.connections.forEach(function (conn) {
540
636
  if (conn.flowAttributes && _typeof(conn.flowAttributes) === 'object') {
541
637
  var pathId = "".concat(conn.from, "-->").concat(conn.to);
542
- var pd = _this5._getOrCreatePathData(pathId, conn.from, conn.to);
543
- Object.entries(conn.flowAttributes).forEach(function (_ref) {
544
- var _ref2 = _slicedToArray(_ref, 2),
545
- key = _ref2[0],
546
- value = _ref2[1];
638
+ var pd = _this6._getOrCreatePathData(pathId, conn.from, conn.to);
639
+ Object.entries(conn.flowAttributes).forEach(function (_ref6) {
640
+ var _ref7 = _slicedToArray(_ref6, 2),
641
+ key = _ref7[0],
642
+ value = _ref7[1];
547
643
  pd.setFlowAttribute(key, value);
548
644
  });
549
645
  console.log("\uD83C\uDF0A Loaded flowAttributes for path \"".concat(pathId, "\":"), conn.flowAttributes);
@@ -559,82 +655,7 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
559
655
  });
560
656
  case 1:
561
657
  pathfindingResult = _context2.v;
562
- // ── Propagate flowAttributes to gateway-split rendered paths ──────────
563
- // The pathfinder may split a connection A→B through gateway waypoints,
564
- // producing sub-paths like A→G and G→B with different pathIds.
565
- // We need to copy the original connection's flowAttributes onto every
566
- // rendered sub-path entry in pathDataStore so the visualisation can
567
- // find them by their rendered pathId.
568
- if (Array.isArray(data.connections) && pathfindingResult) {
569
- // Pass 1: use the explicit gateway connection mappings to get a precise
570
- // original→sub-path map.
571
- originalToSubPaths = new Map(); // origPathId → Set<renderedPathId>
572
- if (pathfindingResult.gateways) {
573
- pathfindingResult.gateways.forEach(function (gateway) {
574
- var _ref3 = gateway.connections || {},
575
- removed = _ref3.removed,
576
- added = _ref3.added;
577
- if (!(removed !== null && removed !== void 0 && removed.length) || !(added !== null && added !== void 0 && added.length)) return;
578
- removed.forEach(function (removedConn) {
579
- var origId = "".concat(removedConn.from, "-->").concat(removedConn.to);
580
- if (!originalToSubPaths.has(origId)) originalToSubPaths.set(origId, new Set());
581
- added.forEach(function (addedConn) {
582
- originalToSubPaths.get(origId).add("".concat(addedConn.from, "-->").concat(addedConn.to));
583
- });
584
- });
585
- });
586
- }
587
- data.connections.forEach(function (conn) {
588
- if (!conn.flowAttributes) return;
589
- var origId = "".concat(conn.from, "-->").concat(conn.to);
590
- var subPathIds = new Set(originalToSubPaths.get(origId) || []);
591
- subPathIds.add(origId); // include the direct path if it wasn't rewired
592
-
593
- subPathIds.forEach(function (subPathId) {
594
- var pd = _this5.pathDataStore.get(subPathId);
595
- if (pd && Object.keys(pd.flowAttributes).length === 0) {
596
- Object.entries(conn.flowAttributes).forEach(function (_ref4) {
597
- var _ref5 = _slicedToArray(_ref4, 2),
598
- key = _ref5[0],
599
- value = _ref5[1];
600
- pd.setFlowAttribute(key, value);
601
- });
602
- console.log("\uD83C\uDF0A Propagated flowAttributes to sub-path \"".concat(subPathId, "\" from \"").concat(origId, "\""));
603
- }
604
- });
605
- });
606
-
607
- // Pass 2: endpoint fallback for any rendered path still missing attributes
608
- // (covers Gateway→Gateway intermediate segments not captured by gateway.connections.added)
609
- fromEndpointAttrs = new Map(); // connectorId → flowAttributes
610
- data.connections.forEach(function (conn) {
611
- if (conn.flowAttributes && !fromEndpointAttrs.has(conn.from)) {
612
- fromEndpointAttrs.set(conn.from, conn.flowAttributes);
613
- }
614
- });
615
- this.pathDataStore.forEach(function (pd, pathId) {
616
- if (Object.keys(pd.flowAttributes).length > 0) return;
617
- var sepIdx = pathId.indexOf('-->');
618
- if (sepIdx === -1) return;
619
- var from = pathId.slice(0, sepIdx);
620
- var attrs = fromEndpointAttrs.get(from);
621
- if (attrs) {
622
- Object.entries(attrs).forEach(function (_ref6) {
623
- var _ref7 = _slicedToArray(_ref6, 2),
624
- key = _ref7[0],
625
- value = _ref7[1];
626
- return pd.setFlowAttribute(key, value);
627
- });
628
- console.log("\uD83C\uDF0A Endpoint-matched flowAttributes for path \"".concat(pathId, "\""));
629
- }
630
- });
631
- }
632
-
633
- // ── Apply flow visualizations now that paths are rendered ──────────────
634
- flowMgr = (_this$sceneViewer = this.sceneViewer) === null || _this$sceneViewer === void 0 || (_this$sceneViewer = _this$sceneViewer.managers) === null || _this$sceneViewer === void 0 ? void 0 : _this$sceneViewer.pathFlowManager;
635
- if (flowMgr) {
636
- flowMgr.applyAllVisualizations();
637
- }
658
+ this._propagateFlowAttributesAndApplyVisualizations(data.connections, pathfindingResult);
638
659
 
639
660
  // Update connections with rewired connections
640
661
  if (pathfindingResult.rewiredConnections) {
@@ -760,6 +781,9 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
760
781
  });
761
782
  case 2:
762
783
  result = _context3.v;
784
+ // Re-apply flow attribute colors (new materials are created on each execution)
785
+ this._propagateFlowAttributesAndApplyVisualizations(currentSceneData.connections, result);
786
+
763
787
  // Cache fingerprint + result for next comparison
764
788
  this._lastPathfindingFingerprint = fingerprint;
765
789
  this._lastPathfindingResult = result;
@@ -1747,7 +1747,7 @@ var SceneOperationsManager = /*#__PURE__*/function () {
1747
1747
  if (typeof window !== 'undefined') {
1748
1748
  isDev = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1';
1749
1749
  }
1750
- if (isDev && segment.material) {
1750
+ if (isDev && process.env.DISABLE_MANUALIZED_SEGMENT_COLORING !== 'true' && segment.material) {
1751
1751
  segment.material.color.setHex(0x0000ff); // Blue
1752
1752
  console.log('🎨 Set manual segment material color to blue (dev mode)');
1753
1753
  }
@@ -1778,7 +1778,7 @@ var SceneOperationsManager = /*#__PURE__*/function () {
1778
1778
  console.log('🔌 Created connectors:', connectors);
1779
1779
 
1780
1780
  // In dev mode, enlarge connectors by 1.5x and turn them red
1781
- if (isDev) {
1781
+ if (isDev && process.env.DISABLE_MANUALIZED_SEGMENT_COLORING !== 'true') {
1782
1782
  connectors.forEach(function (connector) {
1783
1783
  if (connector) {
1784
1784
  connector.scale.set(1.25, 1.25, 1.25);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@2112-lab/central-plant",
3
- "version": "0.2.10",
3
+ "version": "0.2.12",
4
4
  "description": "Utility modules for the Central Plant Application",
5
5
  "main": "dist/bundle/index.js",
6
6
  "module": "dist/esm/src/index.js",