@2112-lab/central-plant 0.3.10 → 0.3.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.
@@ -35717,6 +35717,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
35717
35717
  }, {
35718
35718
  key: "setupZoomAndPanHandlers",
35719
35719
  value: function setupZoomAndPanHandlers(viewport) {
35720
+ var _this5 = this;
35720
35721
  if (!viewport.stage) return;
35721
35722
 
35722
35723
  // Mouse wheel zoom
@@ -35742,6 +35743,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
35742
35743
  y: pointer.y - mousePointTo.y * clampedScale
35743
35744
  };
35744
35745
  viewport.stage.position(newPos);
35746
+ _this5.drawGrid(viewport);
35745
35747
  viewport.stage.batchDraw();
35746
35748
  });
35747
35749
 
@@ -35761,6 +35763,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
35761
35763
  viewport.stage.x(viewport.stage.x() + dx);
35762
35764
  viewport.stage.y(viewport.stage.y() + dy);
35763
35765
  viewport.lastPanPoint = pos;
35766
+ _this5.drawGrid(viewport);
35764
35767
  viewport.stage.batchDraw();
35765
35768
  });
35766
35769
  viewport.stage.on('mouseup', function () {
@@ -35785,33 +35788,40 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
35785
35788
  var width = viewport.stage.width();
35786
35789
  var height = viewport.stage.height();
35787
35790
  var gridSize = viewport.PIXELS_PER_UNIT;
35788
-
35789
- // Center of the viewport represents world origin (0,0,0)
35790
- var centerX = width / 2;
35791
- var centerY = height / 2;
35791
+ var stageX = viewport.stage.x();
35792
+ var stageY = viewport.stage.y();
35793
+ var scale = viewport.stage.scaleX();
35794
+
35795
+ // World origin sits at (width/2, height/2) in stage-local coordinates
35796
+ var originX = width / 2;
35797
+ var originY = height / 2;
35798
+
35799
+ // Compute the visible area in stage-local coordinates, with 1-cell padding
35800
+ var visLeft = -stageX / scale - gridSize;
35801
+ var visTop = -stageY / scale - gridSize;
35802
+ var visRight = (width - stageX) / scale + gridSize;
35803
+ var visBottom = (height - stageY) / scale + gridSize;
35792
35804
  var gridGroup = new this.Konva.Group();
35793
-
35794
- // Draw vertical lines centered at origin
35795
- var startX = centerX % gridSize - gridSize;
35796
35805
  var gridColor = '#dddddd';
35797
- for (var x = startX; x < width; x += gridSize) {
35798
- var distFromCenter = Math.abs(x - centerX);
35799
- var isOriginLine = distFromCenter < 1;
35806
+
35807
+ // Draw vertical lines start at the first grid column left of the visible area
35808
+ var firstX = Math.floor((visLeft - originX) / gridSize) * gridSize + originX;
35809
+ for (var x = firstX; x <= visRight; x += gridSize) {
35810
+ var isOriginLine = Math.abs(x - originX) < 0.5;
35800
35811
  gridGroup.add(new this.Konva.Line({
35801
- points: [x, 0, x, height],
35812
+ points: [x, visTop, x, visBottom],
35802
35813
  stroke: gridColor,
35803
35814
  strokeWidth: isOriginLine ? 2 : 1,
35804
35815
  listening: false
35805
35816
  }));
35806
35817
  }
35807
35818
 
35808
- // Draw horizontal lines centered at origin
35809
- var startY = centerY % gridSize - gridSize;
35810
- for (var y = startY; y < height; y += gridSize) {
35811
- var _distFromCenter = Math.abs(y - centerY);
35812
- var _isOriginLine = _distFromCenter < 1;
35819
+ // Draw horizontal lines start at the first grid row above the visible area
35820
+ var firstY = Math.floor((visTop - originY) / gridSize) * gridSize + originY;
35821
+ for (var y = firstY; y <= visBottom; y += gridSize) {
35822
+ var _isOriginLine = Math.abs(y - originY) < 0.5;
35813
35823
  gridGroup.add(new this.Konva.Line({
35814
- points: [0, y, width, y],
35824
+ points: [visLeft, y, visRight, y],
35815
35825
  stroke: gridColor,
35816
35826
  strokeWidth: _isOriginLine ? 2 : 1,
35817
35827
  listening: false
@@ -35821,14 +35831,14 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
35821
35831
  // Draw center crosshair at world origin
35822
35832
  var crosshairSize = gridSize;
35823
35833
  gridGroup.add(new this.Konva.Line({
35824
- points: [centerX, centerY - crosshairSize, centerX, centerY + crosshairSize],
35834
+ points: [originX, originY - crosshairSize, originX, originY + crosshairSize],
35825
35835
  stroke: '#333',
35826
35836
  strokeWidth: 1,
35827
35837
  listening: false,
35828
35838
  dash: [5, 5]
35829
35839
  }));
35830
35840
  gridGroup.add(new this.Konva.Line({
35831
- points: [centerX - crosshairSize, centerY, centerX + crosshairSize, centerY],
35841
+ points: [originX - crosshairSize, originY, originX + crosshairSize, originY],
35832
35842
  stroke: '#333',
35833
35843
  strokeWidth: 1,
35834
35844
  listening: false,
@@ -35845,7 +35855,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
35845
35855
  }, {
35846
35856
  key: "renderComponents",
35847
35857
  value: function renderComponents(viewport) {
35848
- var _this5 = this;
35858
+ var _this6 = this;
35849
35859
  if (!viewport.componentLayer || !viewport.stage || !this.sceneViewer) return;
35850
35860
  viewport.componentLayer.destroyChildren();
35851
35861
 
@@ -35868,7 +35878,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
35868
35878
  var scale = viewport.PIXELS_PER_UNIT;
35869
35879
  components.forEach(function (component) {
35870
35880
  try {
35871
- _this5.renderComponent(viewport, component, centerX, centerY, scale);
35881
+ _this6.renderComponent(viewport, component, centerX, centerY, scale);
35872
35882
  } catch (err) {
35873
35883
  console.warn('⚠️ Error rendering component in 2D:', component.name, err);
35874
35884
  }
@@ -35928,18 +35938,19 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
35928
35938
  draggable: false
35929
35939
  });
35930
35940
 
35931
- // Add label
35941
+ // Add label (hidden by default; shown on hover)
35932
35942
  var label = new this.Konva.Text({
35933
35943
  x: -rectWidth / 2,
35934
35944
  y: -rectHeight / 2 - 20,
35935
35945
  text: component.name || 'Component',
35936
35946
  fontSize: 12,
35937
35947
  fill: '#333',
35938
- listening: false
35948
+ listening: false,
35949
+ visible: false
35939
35950
  });
35940
35951
 
35941
35952
  // Add mouse event handlers
35942
- this.addComponentInteractions(viewport, rect, componentGroup, component, worldWidth, worldDepth, worldHeight, bboxCenter);
35953
+ this.addComponentInteractions(viewport, rect, componentGroup, component, worldWidth, worldDepth, worldHeight, bboxCenter, label);
35943
35954
  componentGroup.add(rect);
35944
35955
  componentGroup.add(label);
35945
35956
  viewport.componentLayer.add(componentGroup);
@@ -36106,8 +36117,8 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
36106
36117
  */
36107
36118
  }, {
36108
36119
  key: "addComponentInteractions",
36109
- value: function addComponentInteractions(viewport, rect, componentGroup, component, worldWidth, worldDepth, worldHeight, bboxCenter) {
36110
- var _this6 = this;
36120
+ value: function addComponentInteractions(viewport, rect, componentGroup, component, worldWidth, worldDepth, worldHeight, bboxCenter, label) {
36121
+ var _this7 = this;
36111
36122
  if (!this.Konva) return;
36112
36123
  var colors = this.generateComponentColor(component.id);
36113
36124
 
@@ -36118,6 +36129,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
36118
36129
  rect.stroke('#007bff');
36119
36130
  rect.strokeWidth(3);
36120
36131
  viewport.stage.container().style.cursor = 'grab';
36132
+ if (label) label.visible(true);
36121
36133
  viewport.componentLayer.batchDraw();
36122
36134
  }
36123
36135
  });
@@ -36127,6 +36139,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
36127
36139
  rect.stroke(colors.stroke);
36128
36140
  rect.strokeWidth(2);
36129
36141
  viewport.stage.container().style.cursor = 'default';
36142
+ if (label) label.visible(false);
36130
36143
  viewport.componentLayer.batchDraw();
36131
36144
  }
36132
36145
  });
@@ -36134,12 +36147,12 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
36134
36147
  // CLICK EVENT
36135
36148
  rect.on('click', function () {
36136
36149
  if (!viewport.isDragging) {
36137
- var _this6$sceneViewer;
36150
+ var _this7$sceneViewer;
36138
36151
  console.log("\uD83C\uDFAF Component clicked: ".concat(component.name));
36139
36152
 
36140
36153
  // Use centralPlant API to select component
36141
- if ((_this6$sceneViewer = _this6.sceneViewer) !== null && _this6$sceneViewer !== void 0 && _this6$sceneViewer.centralPlant && component.uuid) {
36142
- _this6.sceneViewer.centralPlant.selectComponent(component.uuid);
36154
+ if ((_this7$sceneViewer = _this7.sceneViewer) !== null && _this7$sceneViewer !== void 0 && _this7$sceneViewer.centralPlant && component.uuid) {
36155
+ _this7.sceneViewer.centralPlant.selectComponent(component.uuid);
36143
36156
  }
36144
36157
  }
36145
36158
  });
@@ -36169,7 +36182,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
36169
36182
  var worldOriginY = stageHeight / 2;
36170
36183
 
36171
36184
  // Snap to grid
36172
- var snappedPos = _this6.snapScreenToGrid(viewport, currentPos.x, currentPos.y, scale, worldOriginX, worldOriginY);
36185
+ var snappedPos = _this7.snapScreenToGrid(viewport, currentPos.x, currentPos.y, scale, worldOriginX, worldOriginY);
36173
36186
  componentGroup.position(snappedPos);
36174
36187
  viewport.componentLayer.batchDraw();
36175
36188
  });
@@ -36177,7 +36190,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
36177
36190
  // DRAG END
36178
36191
  componentGroup.on('dragend', function () {
36179
36192
  setTimeout(function () {
36180
- var _this6$sceneViewer2;
36193
+ var _this7$sceneViewer2;
36181
36194
  viewport.isDragging = false;
36182
36195
  var finalPos = componentGroup.position();
36183
36196
  var stageWidth = viewport.stage.width();
@@ -36187,38 +36200,50 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
36187
36200
  var worldOriginY = stageHeight / 2;
36188
36201
 
36189
36202
  // Convert screen to world coordinates
36190
- var worldCoords = _this6.screenToWorldCoords(viewport, finalPos.x, finalPos.y, scale, worldOriginX, worldOriginY);
36203
+ var worldCoords = _this7.screenToWorldCoords(viewport, finalPos.x, finalPos.y, scale, worldOriginX, worldOriginY);
36191
36204
 
36192
36205
  // Calculate new position: delta from old bbox center to new bbox center
36193
36206
  var currentPos = component.position;
36194
- var newPosition = _this6.worldCoordsToObjectPosition(viewport, worldCoords, currentPos, bboxCenter);
36207
+ var newPosition = _this7.worldCoordsToObjectPosition(viewport, worldCoords, currentPos, bboxCenter);
36195
36208
 
36196
36209
  // Apply translation via centralPlant API
36197
36210
  var deltaX = newPosition.x - currentPos.x;
36198
36211
  var deltaY = newPosition.y - currentPos.y;
36199
36212
  var deltaZ = newPosition.z - currentPos.z;
36200
- if ((_this6$sceneViewer2 = _this6.sceneViewer) !== null && _this6$sceneViewer2 !== void 0 && _this6$sceneViewer2.centralPlant && component.uuid) {
36213
+ if ((_this7$sceneViewer2 = _this7.sceneViewer) !== null && _this7$sceneViewer2 !== void 0 && _this7$sceneViewer2.centralPlant && component.uuid) {
36201
36214
  var success = true;
36202
- if (Math.abs(deltaX) > 0.01) {
36203
- success = success && _this6.sceneViewer.centralPlant.translate(component.uuid, 'x', deltaX);
36204
- }
36205
- if (Math.abs(deltaY) > 0.01) {
36206
- success = success && _this6.sceneViewer.centralPlant.translate(component.uuid, 'y', deltaY);
36207
- }
36208
- if (Math.abs(deltaZ) > 0.01) {
36209
- success = success && _this6.sceneViewer.centralPlant.translate(component.uuid, 'z', deltaZ);
36215
+
36216
+ // Suppress per-axis path updates so the pathfinder only runs once,
36217
+ // after ALL axes have been translated, with the final combined position.
36218
+ // Running updatePaths() after each individual axis (the default
36219
+ // translateComponent behaviour) produces intermediate wrong results on
36220
+ // the first drag because no cached fingerprint exists yet to skip them.
36221
+ var wasAutoUpdate = _this7.sceneViewer.shouldUpdatePaths;
36222
+ _this7.sceneViewer.shouldUpdatePaths = false;
36223
+ try {
36224
+ if (Math.abs(deltaX) > 0.01) {
36225
+ success = success && _this7.sceneViewer.centralPlant.translate(component.uuid, 'x', deltaX);
36226
+ }
36227
+ if (Math.abs(deltaY) > 0.01) {
36228
+ success = success && _this7.sceneViewer.centralPlant.translate(component.uuid, 'y', deltaY);
36229
+ }
36230
+ if (Math.abs(deltaZ) > 0.01) {
36231
+ success = success && _this7.sceneViewer.centralPlant.translate(component.uuid, 'z', deltaZ);
36232
+ }
36233
+ } finally {
36234
+ _this7.sceneViewer.shouldUpdatePaths = wasAutoUpdate;
36210
36235
  }
36211
- if (!success && _this6.dragStartPosition) {
36236
+ if (!success && _this7.dragStartPosition) {
36212
36237
  console.warn('⚠️ Failed to translate component, reverting position');
36213
- componentGroup.position(_this6.dragStartPosition);
36238
+ componentGroup.position(_this7.dragStartPosition);
36214
36239
  } else {
36215
36240
  console.log("\u2705 Component ".concat(component.name, " translated successfully in 2D viewport"));
36216
36241
 
36217
- // Auto-update paths if enabled
36218
- if (_this6.sceneViewer && _this6.sceneViewer.shouldUpdatePaths) {
36242
+ // Single path update with the final combined position
36243
+ if (wasAutoUpdate && _this7.sceneViewer) {
36219
36244
  console.log('🔄 Auto-updating paths after 2D viewport translation...');
36220
36245
  try {
36221
- _this6.sceneViewer.updatePaths();
36246
+ _this7.sceneViewer.updatePaths();
36222
36247
  console.log('✅ Paths auto-updated successfully from 2D viewport');
36223
36248
  } catch (error) {
36224
36249
  console.error('❌ Error auto-updating paths from 2D viewport:', error);
@@ -36471,28 +36496,28 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
36471
36496
  }, {
36472
36497
  key: "refresh",
36473
36498
  value: function refresh() {
36474
- var _this7 = this;
36499
+ var _this8 = this;
36475
36500
  var key = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
36476
36501
  if (this._refreshPending) return;
36477
36502
  this._refreshPending = true;
36478
36503
  requestAnimationFrame(function () {
36479
- _this7._refreshPending = false;
36504
+ _this8._refreshPending = false;
36480
36505
  // Clear per-cycle caches so each component is measured/traversed once per paint
36481
- _this7._bboxCache.clear();
36482
- _this7._componentListCache = null;
36506
+ _this8._bboxCache.clear();
36507
+ _this8._componentListCache = null;
36483
36508
  if (key) {
36484
- var viewport = _this7.viewports.get(key);
36509
+ var viewport = _this8.viewports.get(key);
36485
36510
  if (viewport && viewport.isReady) {
36486
- _this7.renderComponents(viewport);
36511
+ _this8.renderComponents(viewport);
36487
36512
  }
36488
36513
  } else {
36489
- var _iterator = _createForOfIteratorHelper(_this7.viewports.values()),
36514
+ var _iterator = _createForOfIteratorHelper(_this8.viewports.values()),
36490
36515
  _step;
36491
36516
  try {
36492
36517
  for (_iterator.s(); !(_step = _iterator.n()).done;) {
36493
36518
  var _viewport = _step.value;
36494
36519
  if (_viewport.isReady) {
36495
- _this7.renderComponents(_viewport);
36520
+ _this8.renderComponents(_viewport);
36496
36521
  }
36497
36522
  }
36498
36523
  } catch (err) {
@@ -37934,7 +37959,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
37934
37959
  * Initialize the CentralPlant manager
37935
37960
  *
37936
37961
  * @constructor
37937
- * @version 0.3.10
37962
+ * @version 0.3.12
37938
37963
  * @updated 2025-10-22
37939
37964
  *
37940
37965
  * @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.3.10
38
+ * @version 0.3.12
39
39
  * @updated 2025-10-22
40
40
  *
41
41
  * @description Creates a new CentralPlant instance and initializes internal managers and utilities.
@@ -400,6 +400,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
400
400
  }, {
401
401
  key: "setupZoomAndPanHandlers",
402
402
  value: function setupZoomAndPanHandlers(viewport) {
403
+ var _this5 = this;
403
404
  if (!viewport.stage) return;
404
405
 
405
406
  // Mouse wheel zoom
@@ -425,6 +426,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
425
426
  y: pointer.y - mousePointTo.y * clampedScale
426
427
  };
427
428
  viewport.stage.position(newPos);
429
+ _this5.drawGrid(viewport);
428
430
  viewport.stage.batchDraw();
429
431
  });
430
432
 
@@ -444,6 +446,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
444
446
  viewport.stage.x(viewport.stage.x() + dx);
445
447
  viewport.stage.y(viewport.stage.y() + dy);
446
448
  viewport.lastPanPoint = pos;
449
+ _this5.drawGrid(viewport);
447
450
  viewport.stage.batchDraw();
448
451
  });
449
452
  viewport.stage.on('mouseup', function () {
@@ -468,33 +471,40 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
468
471
  var width = viewport.stage.width();
469
472
  var height = viewport.stage.height();
470
473
  var gridSize = viewport.PIXELS_PER_UNIT;
471
-
472
- // Center of the viewport represents world origin (0,0,0)
473
- var centerX = width / 2;
474
- var centerY = height / 2;
474
+ var stageX = viewport.stage.x();
475
+ var stageY = viewport.stage.y();
476
+ var scale = viewport.stage.scaleX();
477
+
478
+ // World origin sits at (width/2, height/2) in stage-local coordinates
479
+ var originX = width / 2;
480
+ var originY = height / 2;
481
+
482
+ // Compute the visible area in stage-local coordinates, with 1-cell padding
483
+ var visLeft = -stageX / scale - gridSize;
484
+ var visTop = -stageY / scale - gridSize;
485
+ var visRight = (width - stageX) / scale + gridSize;
486
+ var visBottom = (height - stageY) / scale + gridSize;
475
487
  var gridGroup = new this.Konva.Group();
476
-
477
- // Draw vertical lines centered at origin
478
- var startX = centerX % gridSize - gridSize;
479
488
  var gridColor = '#dddddd';
480
- for (var x = startX; x < width; x += gridSize) {
481
- var distFromCenter = Math.abs(x - centerX);
482
- var isOriginLine = distFromCenter < 1;
489
+
490
+ // Draw vertical lines start at the first grid column left of the visible area
491
+ var firstX = Math.floor((visLeft - originX) / gridSize) * gridSize + originX;
492
+ for (var x = firstX; x <= visRight; x += gridSize) {
493
+ var isOriginLine = Math.abs(x - originX) < 0.5;
483
494
  gridGroup.add(new this.Konva.Line({
484
- points: [x, 0, x, height],
495
+ points: [x, visTop, x, visBottom],
485
496
  stroke: gridColor,
486
497
  strokeWidth: isOriginLine ? 2 : 1,
487
498
  listening: false
488
499
  }));
489
500
  }
490
501
 
491
- // Draw horizontal lines centered at origin
492
- var startY = centerY % gridSize - gridSize;
493
- for (var y = startY; y < height; y += gridSize) {
494
- var _distFromCenter = Math.abs(y - centerY);
495
- var _isOriginLine = _distFromCenter < 1;
502
+ // Draw horizontal lines start at the first grid row above the visible area
503
+ var firstY = Math.floor((visTop - originY) / gridSize) * gridSize + originY;
504
+ for (var y = firstY; y <= visBottom; y += gridSize) {
505
+ var _isOriginLine = Math.abs(y - originY) < 0.5;
496
506
  gridGroup.add(new this.Konva.Line({
497
- points: [0, y, width, y],
507
+ points: [visLeft, y, visRight, y],
498
508
  stroke: gridColor,
499
509
  strokeWidth: _isOriginLine ? 2 : 1,
500
510
  listening: false
@@ -504,14 +514,14 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
504
514
  // Draw center crosshair at world origin
505
515
  var crosshairSize = gridSize;
506
516
  gridGroup.add(new this.Konva.Line({
507
- points: [centerX, centerY - crosshairSize, centerX, centerY + crosshairSize],
517
+ points: [originX, originY - crosshairSize, originX, originY + crosshairSize],
508
518
  stroke: '#333',
509
519
  strokeWidth: 1,
510
520
  listening: false,
511
521
  dash: [5, 5]
512
522
  }));
513
523
  gridGroup.add(new this.Konva.Line({
514
- points: [centerX - crosshairSize, centerY, centerX + crosshairSize, centerY],
524
+ points: [originX - crosshairSize, originY, originX + crosshairSize, originY],
515
525
  stroke: '#333',
516
526
  strokeWidth: 1,
517
527
  listening: false,
@@ -528,7 +538,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
528
538
  }, {
529
539
  key: "renderComponents",
530
540
  value: function renderComponents(viewport) {
531
- var _this5 = this;
541
+ var _this6 = this;
532
542
  if (!viewport.componentLayer || !viewport.stage || !this.sceneViewer) return;
533
543
  viewport.componentLayer.destroyChildren();
534
544
 
@@ -551,7 +561,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
551
561
  var scale = viewport.PIXELS_PER_UNIT;
552
562
  components.forEach(function (component) {
553
563
  try {
554
- _this5.renderComponent(viewport, component, centerX, centerY, scale);
564
+ _this6.renderComponent(viewport, component, centerX, centerY, scale);
555
565
  } catch (err) {
556
566
  console.warn('⚠️ Error rendering component in 2D:', component.name, err);
557
567
  }
@@ -611,18 +621,19 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
611
621
  draggable: false
612
622
  });
613
623
 
614
- // Add label
624
+ // Add label (hidden by default; shown on hover)
615
625
  var label = new this.Konva.Text({
616
626
  x: -rectWidth / 2,
617
627
  y: -rectHeight / 2 - 20,
618
628
  text: component.name || 'Component',
619
629
  fontSize: 12,
620
630
  fill: '#333',
621
- listening: false
631
+ listening: false,
632
+ visible: false
622
633
  });
623
634
 
624
635
  // Add mouse event handlers
625
- this.addComponentInteractions(viewport, rect, componentGroup, component, worldWidth, worldDepth, worldHeight, bboxCenter);
636
+ this.addComponentInteractions(viewport, rect, componentGroup, component, worldWidth, worldDepth, worldHeight, bboxCenter, label);
626
637
  componentGroup.add(rect);
627
638
  componentGroup.add(label);
628
639
  viewport.componentLayer.add(componentGroup);
@@ -789,8 +800,8 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
789
800
  */
790
801
  }, {
791
802
  key: "addComponentInteractions",
792
- value: function addComponentInteractions(viewport, rect, componentGroup, component, worldWidth, worldDepth, worldHeight, bboxCenter) {
793
- var _this6 = this;
803
+ value: function addComponentInteractions(viewport, rect, componentGroup, component, worldWidth, worldDepth, worldHeight, bboxCenter, label) {
804
+ var _this7 = this;
794
805
  if (!this.Konva) return;
795
806
  var colors = this.generateComponentColor(component.id);
796
807
 
@@ -801,6 +812,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
801
812
  rect.stroke('#007bff');
802
813
  rect.strokeWidth(3);
803
814
  viewport.stage.container().style.cursor = 'grab';
815
+ if (label) label.visible(true);
804
816
  viewport.componentLayer.batchDraw();
805
817
  }
806
818
  });
@@ -810,6 +822,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
810
822
  rect.stroke(colors.stroke);
811
823
  rect.strokeWidth(2);
812
824
  viewport.stage.container().style.cursor = 'default';
825
+ if (label) label.visible(false);
813
826
  viewport.componentLayer.batchDraw();
814
827
  }
815
828
  });
@@ -817,12 +830,12 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
817
830
  // CLICK EVENT
818
831
  rect.on('click', function () {
819
832
  if (!viewport.isDragging) {
820
- var _this6$sceneViewer;
833
+ var _this7$sceneViewer;
821
834
  console.log("\uD83C\uDFAF Component clicked: ".concat(component.name));
822
835
 
823
836
  // Use centralPlant API to select component
824
- if ((_this6$sceneViewer = _this6.sceneViewer) !== null && _this6$sceneViewer !== void 0 && _this6$sceneViewer.centralPlant && component.uuid) {
825
- _this6.sceneViewer.centralPlant.selectComponent(component.uuid);
837
+ if ((_this7$sceneViewer = _this7.sceneViewer) !== null && _this7$sceneViewer !== void 0 && _this7$sceneViewer.centralPlant && component.uuid) {
838
+ _this7.sceneViewer.centralPlant.selectComponent(component.uuid);
826
839
  }
827
840
  }
828
841
  });
@@ -852,7 +865,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
852
865
  var worldOriginY = stageHeight / 2;
853
866
 
854
867
  // Snap to grid
855
- var snappedPos = _this6.snapScreenToGrid(viewport, currentPos.x, currentPos.y, scale, worldOriginX, worldOriginY);
868
+ var snappedPos = _this7.snapScreenToGrid(viewport, currentPos.x, currentPos.y, scale, worldOriginX, worldOriginY);
856
869
  componentGroup.position(snappedPos);
857
870
  viewport.componentLayer.batchDraw();
858
871
  });
@@ -860,7 +873,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
860
873
  // DRAG END
861
874
  componentGroup.on('dragend', function () {
862
875
  setTimeout(function () {
863
- var _this6$sceneViewer2;
876
+ var _this7$sceneViewer2;
864
877
  viewport.isDragging = false;
865
878
  var finalPos = componentGroup.position();
866
879
  var stageWidth = viewport.stage.width();
@@ -870,38 +883,50 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
870
883
  var worldOriginY = stageHeight / 2;
871
884
 
872
885
  // Convert screen to world coordinates
873
- var worldCoords = _this6.screenToWorldCoords(viewport, finalPos.x, finalPos.y, scale, worldOriginX, worldOriginY);
886
+ var worldCoords = _this7.screenToWorldCoords(viewport, finalPos.x, finalPos.y, scale, worldOriginX, worldOriginY);
874
887
 
875
888
  // Calculate new position: delta from old bbox center to new bbox center
876
889
  var currentPos = component.position;
877
- var newPosition = _this6.worldCoordsToObjectPosition(viewport, worldCoords, currentPos, bboxCenter);
890
+ var newPosition = _this7.worldCoordsToObjectPosition(viewport, worldCoords, currentPos, bboxCenter);
878
891
 
879
892
  // Apply translation via centralPlant API
880
893
  var deltaX = newPosition.x - currentPos.x;
881
894
  var deltaY = newPosition.y - currentPos.y;
882
895
  var deltaZ = newPosition.z - currentPos.z;
883
- if ((_this6$sceneViewer2 = _this6.sceneViewer) !== null && _this6$sceneViewer2 !== void 0 && _this6$sceneViewer2.centralPlant && component.uuid) {
896
+ if ((_this7$sceneViewer2 = _this7.sceneViewer) !== null && _this7$sceneViewer2 !== void 0 && _this7$sceneViewer2.centralPlant && component.uuid) {
884
897
  var success = true;
885
- if (Math.abs(deltaX) > 0.01) {
886
- success = success && _this6.sceneViewer.centralPlant.translate(component.uuid, 'x', deltaX);
887
- }
888
- if (Math.abs(deltaY) > 0.01) {
889
- success = success && _this6.sceneViewer.centralPlant.translate(component.uuid, 'y', deltaY);
890
- }
891
- if (Math.abs(deltaZ) > 0.01) {
892
- success = success && _this6.sceneViewer.centralPlant.translate(component.uuid, 'z', deltaZ);
898
+
899
+ // Suppress per-axis path updates so the pathfinder only runs once,
900
+ // after ALL axes have been translated, with the final combined position.
901
+ // Running updatePaths() after each individual axis (the default
902
+ // translateComponent behaviour) produces intermediate wrong results on
903
+ // the first drag because no cached fingerprint exists yet to skip them.
904
+ var wasAutoUpdate = _this7.sceneViewer.shouldUpdatePaths;
905
+ _this7.sceneViewer.shouldUpdatePaths = false;
906
+ try {
907
+ if (Math.abs(deltaX) > 0.01) {
908
+ success = success && _this7.sceneViewer.centralPlant.translate(component.uuid, 'x', deltaX);
909
+ }
910
+ if (Math.abs(deltaY) > 0.01) {
911
+ success = success && _this7.sceneViewer.centralPlant.translate(component.uuid, 'y', deltaY);
912
+ }
913
+ if (Math.abs(deltaZ) > 0.01) {
914
+ success = success && _this7.sceneViewer.centralPlant.translate(component.uuid, 'z', deltaZ);
915
+ }
916
+ } finally {
917
+ _this7.sceneViewer.shouldUpdatePaths = wasAutoUpdate;
893
918
  }
894
- if (!success && _this6.dragStartPosition) {
919
+ if (!success && _this7.dragStartPosition) {
895
920
  console.warn('⚠️ Failed to translate component, reverting position');
896
- componentGroup.position(_this6.dragStartPosition);
921
+ componentGroup.position(_this7.dragStartPosition);
897
922
  } else {
898
923
  console.log("\u2705 Component ".concat(component.name, " translated successfully in 2D viewport"));
899
924
 
900
- // Auto-update paths if enabled
901
- if (_this6.sceneViewer && _this6.sceneViewer.shouldUpdatePaths) {
925
+ // Single path update with the final combined position
926
+ if (wasAutoUpdate && _this7.sceneViewer) {
902
927
  console.log('🔄 Auto-updating paths after 2D viewport translation...');
903
928
  try {
904
- _this6.sceneViewer.updatePaths();
929
+ _this7.sceneViewer.updatePaths();
905
930
  console.log('✅ Paths auto-updated successfully from 2D viewport');
906
931
  } catch (error) {
907
932
  console.error('❌ Error auto-updating paths from 2D viewport:', error);
@@ -1154,28 +1179,28 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
1154
1179
  }, {
1155
1180
  key: "refresh",
1156
1181
  value: function refresh() {
1157
- var _this7 = this;
1182
+ var _this8 = this;
1158
1183
  var key = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
1159
1184
  if (this._refreshPending) return;
1160
1185
  this._refreshPending = true;
1161
1186
  requestAnimationFrame(function () {
1162
- _this7._refreshPending = false;
1187
+ _this8._refreshPending = false;
1163
1188
  // Clear per-cycle caches so each component is measured/traversed once per paint
1164
- _this7._bboxCache.clear();
1165
- _this7._componentListCache = null;
1189
+ _this8._bboxCache.clear();
1190
+ _this8._componentListCache = null;
1166
1191
  if (key) {
1167
- var viewport = _this7.viewports.get(key);
1192
+ var viewport = _this8.viewports.get(key);
1168
1193
  if (viewport && viewport.isReady) {
1169
- _this7.renderComponents(viewport);
1194
+ _this8.renderComponents(viewport);
1170
1195
  }
1171
1196
  } else {
1172
- var _iterator = _rollupPluginBabelHelpers.createForOfIteratorHelper(_this7.viewports.values()),
1197
+ var _iterator = _rollupPluginBabelHelpers.createForOfIteratorHelper(_this8.viewports.values()),
1173
1198
  _step;
1174
1199
  try {
1175
1200
  for (_iterator.s(); !(_step = _iterator.n()).done;) {
1176
1201
  var _viewport = _step.value;
1177
1202
  if (_viewport.isReady) {
1178
- _this7.renderComponents(_viewport);
1203
+ _this8.renderComponents(_viewport);
1179
1204
  }
1180
1205
  }
1181
1206
  } catch (err) {
@@ -31,7 +31,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
31
31
  * Initialize the CentralPlant manager
32
32
  *
33
33
  * @constructor
34
- * @version 0.3.10
34
+ * @version 0.3.12
35
35
  * @updated 2025-10-22
36
36
  *
37
37
  * @description Creates a new CentralPlant instance and initializes internal managers and utilities.
@@ -376,6 +376,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
376
376
  }, {
377
377
  key: "setupZoomAndPanHandlers",
378
378
  value: function setupZoomAndPanHandlers(viewport) {
379
+ var _this5 = this;
379
380
  if (!viewport.stage) return;
380
381
 
381
382
  // Mouse wheel zoom
@@ -401,6 +402,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
401
402
  y: pointer.y - mousePointTo.y * clampedScale
402
403
  };
403
404
  viewport.stage.position(newPos);
405
+ _this5.drawGrid(viewport);
404
406
  viewport.stage.batchDraw();
405
407
  });
406
408
 
@@ -420,6 +422,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
420
422
  viewport.stage.x(viewport.stage.x() + dx);
421
423
  viewport.stage.y(viewport.stage.y() + dy);
422
424
  viewport.lastPanPoint = pos;
425
+ _this5.drawGrid(viewport);
423
426
  viewport.stage.batchDraw();
424
427
  });
425
428
  viewport.stage.on('mouseup', function () {
@@ -444,33 +447,40 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
444
447
  var width = viewport.stage.width();
445
448
  var height = viewport.stage.height();
446
449
  var gridSize = viewport.PIXELS_PER_UNIT;
447
-
448
- // Center of the viewport represents world origin (0,0,0)
449
- var centerX = width / 2;
450
- var centerY = height / 2;
450
+ var stageX = viewport.stage.x();
451
+ var stageY = viewport.stage.y();
452
+ var scale = viewport.stage.scaleX();
453
+
454
+ // World origin sits at (width/2, height/2) in stage-local coordinates
455
+ var originX = width / 2;
456
+ var originY = height / 2;
457
+
458
+ // Compute the visible area in stage-local coordinates, with 1-cell padding
459
+ var visLeft = -stageX / scale - gridSize;
460
+ var visTop = -stageY / scale - gridSize;
461
+ var visRight = (width - stageX) / scale + gridSize;
462
+ var visBottom = (height - stageY) / scale + gridSize;
451
463
  var gridGroup = new this.Konva.Group();
452
-
453
- // Draw vertical lines centered at origin
454
- var startX = centerX % gridSize - gridSize;
455
464
  var gridColor = '#dddddd';
456
- for (var x = startX; x < width; x += gridSize) {
457
- var distFromCenter = Math.abs(x - centerX);
458
- var isOriginLine = distFromCenter < 1;
465
+
466
+ // Draw vertical lines start at the first grid column left of the visible area
467
+ var firstX = Math.floor((visLeft - originX) / gridSize) * gridSize + originX;
468
+ for (var x = firstX; x <= visRight; x += gridSize) {
469
+ var isOriginLine = Math.abs(x - originX) < 0.5;
459
470
  gridGroup.add(new this.Konva.Line({
460
- points: [x, 0, x, height],
471
+ points: [x, visTop, x, visBottom],
461
472
  stroke: gridColor,
462
473
  strokeWidth: isOriginLine ? 2 : 1,
463
474
  listening: false
464
475
  }));
465
476
  }
466
477
 
467
- // Draw horizontal lines centered at origin
468
- var startY = centerY % gridSize - gridSize;
469
- for (var y = startY; y < height; y += gridSize) {
470
- var _distFromCenter = Math.abs(y - centerY);
471
- var _isOriginLine = _distFromCenter < 1;
478
+ // Draw horizontal lines start at the first grid row above the visible area
479
+ var firstY = Math.floor((visTop - originY) / gridSize) * gridSize + originY;
480
+ for (var y = firstY; y <= visBottom; y += gridSize) {
481
+ var _isOriginLine = Math.abs(y - originY) < 0.5;
472
482
  gridGroup.add(new this.Konva.Line({
473
- points: [0, y, width, y],
483
+ points: [visLeft, y, visRight, y],
474
484
  stroke: gridColor,
475
485
  strokeWidth: _isOriginLine ? 2 : 1,
476
486
  listening: false
@@ -480,14 +490,14 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
480
490
  // Draw center crosshair at world origin
481
491
  var crosshairSize = gridSize;
482
492
  gridGroup.add(new this.Konva.Line({
483
- points: [centerX, centerY - crosshairSize, centerX, centerY + crosshairSize],
493
+ points: [originX, originY - crosshairSize, originX, originY + crosshairSize],
484
494
  stroke: '#333',
485
495
  strokeWidth: 1,
486
496
  listening: false,
487
497
  dash: [5, 5]
488
498
  }));
489
499
  gridGroup.add(new this.Konva.Line({
490
- points: [centerX - crosshairSize, centerY, centerX + crosshairSize, centerY],
500
+ points: [originX - crosshairSize, originY, originX + crosshairSize, originY],
491
501
  stroke: '#333',
492
502
  strokeWidth: 1,
493
503
  listening: false,
@@ -504,7 +514,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
504
514
  }, {
505
515
  key: "renderComponents",
506
516
  value: function renderComponents(viewport) {
507
- var _this5 = this;
517
+ var _this6 = this;
508
518
  if (!viewport.componentLayer || !viewport.stage || !this.sceneViewer) return;
509
519
  viewport.componentLayer.destroyChildren();
510
520
 
@@ -527,7 +537,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
527
537
  var scale = viewport.PIXELS_PER_UNIT;
528
538
  components.forEach(function (component) {
529
539
  try {
530
- _this5.renderComponent(viewport, component, centerX, centerY, scale);
540
+ _this6.renderComponent(viewport, component, centerX, centerY, scale);
531
541
  } catch (err) {
532
542
  console.warn('⚠️ Error rendering component in 2D:', component.name, err);
533
543
  }
@@ -587,18 +597,19 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
587
597
  draggable: false
588
598
  });
589
599
 
590
- // Add label
600
+ // Add label (hidden by default; shown on hover)
591
601
  var label = new this.Konva.Text({
592
602
  x: -rectWidth / 2,
593
603
  y: -rectHeight / 2 - 20,
594
604
  text: component.name || 'Component',
595
605
  fontSize: 12,
596
606
  fill: '#333',
597
- listening: false
607
+ listening: false,
608
+ visible: false
598
609
  });
599
610
 
600
611
  // Add mouse event handlers
601
- this.addComponentInteractions(viewport, rect, componentGroup, component, worldWidth, worldDepth, worldHeight, bboxCenter);
612
+ this.addComponentInteractions(viewport, rect, componentGroup, component, worldWidth, worldDepth, worldHeight, bboxCenter, label);
602
613
  componentGroup.add(rect);
603
614
  componentGroup.add(label);
604
615
  viewport.componentLayer.add(componentGroup);
@@ -765,8 +776,8 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
765
776
  */
766
777
  }, {
767
778
  key: "addComponentInteractions",
768
- value: function addComponentInteractions(viewport, rect, componentGroup, component, worldWidth, worldDepth, worldHeight, bboxCenter) {
769
- var _this6 = this;
779
+ value: function addComponentInteractions(viewport, rect, componentGroup, component, worldWidth, worldDepth, worldHeight, bboxCenter, label) {
780
+ var _this7 = this;
770
781
  if (!this.Konva) return;
771
782
  var colors = this.generateComponentColor(component.id);
772
783
 
@@ -777,6 +788,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
777
788
  rect.stroke('#007bff');
778
789
  rect.strokeWidth(3);
779
790
  viewport.stage.container().style.cursor = 'grab';
791
+ if (label) label.visible(true);
780
792
  viewport.componentLayer.batchDraw();
781
793
  }
782
794
  });
@@ -786,6 +798,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
786
798
  rect.stroke(colors.stroke);
787
799
  rect.strokeWidth(2);
788
800
  viewport.stage.container().style.cursor = 'default';
801
+ if (label) label.visible(false);
789
802
  viewport.componentLayer.batchDraw();
790
803
  }
791
804
  });
@@ -793,12 +806,12 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
793
806
  // CLICK EVENT
794
807
  rect.on('click', function () {
795
808
  if (!viewport.isDragging) {
796
- var _this6$sceneViewer;
809
+ var _this7$sceneViewer;
797
810
  console.log("\uD83C\uDFAF Component clicked: ".concat(component.name));
798
811
 
799
812
  // Use centralPlant API to select component
800
- if ((_this6$sceneViewer = _this6.sceneViewer) !== null && _this6$sceneViewer !== void 0 && _this6$sceneViewer.centralPlant && component.uuid) {
801
- _this6.sceneViewer.centralPlant.selectComponent(component.uuid);
813
+ if ((_this7$sceneViewer = _this7.sceneViewer) !== null && _this7$sceneViewer !== void 0 && _this7$sceneViewer.centralPlant && component.uuid) {
814
+ _this7.sceneViewer.centralPlant.selectComponent(component.uuid);
802
815
  }
803
816
  }
804
817
  });
@@ -828,7 +841,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
828
841
  var worldOriginY = stageHeight / 2;
829
842
 
830
843
  // Snap to grid
831
- var snappedPos = _this6.snapScreenToGrid(viewport, currentPos.x, currentPos.y, scale, worldOriginX, worldOriginY);
844
+ var snappedPos = _this7.snapScreenToGrid(viewport, currentPos.x, currentPos.y, scale, worldOriginX, worldOriginY);
832
845
  componentGroup.position(snappedPos);
833
846
  viewport.componentLayer.batchDraw();
834
847
  });
@@ -836,7 +849,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
836
849
  // DRAG END
837
850
  componentGroup.on('dragend', function () {
838
851
  setTimeout(function () {
839
- var _this6$sceneViewer2;
852
+ var _this7$sceneViewer2;
840
853
  viewport.isDragging = false;
841
854
  var finalPos = componentGroup.position();
842
855
  var stageWidth = viewport.stage.width();
@@ -846,38 +859,50 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
846
859
  var worldOriginY = stageHeight / 2;
847
860
 
848
861
  // Convert screen to world coordinates
849
- var worldCoords = _this6.screenToWorldCoords(viewport, finalPos.x, finalPos.y, scale, worldOriginX, worldOriginY);
862
+ var worldCoords = _this7.screenToWorldCoords(viewport, finalPos.x, finalPos.y, scale, worldOriginX, worldOriginY);
850
863
 
851
864
  // Calculate new position: delta from old bbox center to new bbox center
852
865
  var currentPos = component.position;
853
- var newPosition = _this6.worldCoordsToObjectPosition(viewport, worldCoords, currentPos, bboxCenter);
866
+ var newPosition = _this7.worldCoordsToObjectPosition(viewport, worldCoords, currentPos, bboxCenter);
854
867
 
855
868
  // Apply translation via centralPlant API
856
869
  var deltaX = newPosition.x - currentPos.x;
857
870
  var deltaY = newPosition.y - currentPos.y;
858
871
  var deltaZ = newPosition.z - currentPos.z;
859
- if ((_this6$sceneViewer2 = _this6.sceneViewer) !== null && _this6$sceneViewer2 !== void 0 && _this6$sceneViewer2.centralPlant && component.uuid) {
872
+ if ((_this7$sceneViewer2 = _this7.sceneViewer) !== null && _this7$sceneViewer2 !== void 0 && _this7$sceneViewer2.centralPlant && component.uuid) {
860
873
  var success = true;
861
- if (Math.abs(deltaX) > 0.01) {
862
- success = success && _this6.sceneViewer.centralPlant.translate(component.uuid, 'x', deltaX);
863
- }
864
- if (Math.abs(deltaY) > 0.01) {
865
- success = success && _this6.sceneViewer.centralPlant.translate(component.uuid, 'y', deltaY);
866
- }
867
- if (Math.abs(deltaZ) > 0.01) {
868
- success = success && _this6.sceneViewer.centralPlant.translate(component.uuid, 'z', deltaZ);
874
+
875
+ // Suppress per-axis path updates so the pathfinder only runs once,
876
+ // after ALL axes have been translated, with the final combined position.
877
+ // Running updatePaths() after each individual axis (the default
878
+ // translateComponent behaviour) produces intermediate wrong results on
879
+ // the first drag because no cached fingerprint exists yet to skip them.
880
+ var wasAutoUpdate = _this7.sceneViewer.shouldUpdatePaths;
881
+ _this7.sceneViewer.shouldUpdatePaths = false;
882
+ try {
883
+ if (Math.abs(deltaX) > 0.01) {
884
+ success = success && _this7.sceneViewer.centralPlant.translate(component.uuid, 'x', deltaX);
885
+ }
886
+ if (Math.abs(deltaY) > 0.01) {
887
+ success = success && _this7.sceneViewer.centralPlant.translate(component.uuid, 'y', deltaY);
888
+ }
889
+ if (Math.abs(deltaZ) > 0.01) {
890
+ success = success && _this7.sceneViewer.centralPlant.translate(component.uuid, 'z', deltaZ);
891
+ }
892
+ } finally {
893
+ _this7.sceneViewer.shouldUpdatePaths = wasAutoUpdate;
869
894
  }
870
- if (!success && _this6.dragStartPosition) {
895
+ if (!success && _this7.dragStartPosition) {
871
896
  console.warn('⚠️ Failed to translate component, reverting position');
872
- componentGroup.position(_this6.dragStartPosition);
897
+ componentGroup.position(_this7.dragStartPosition);
873
898
  } else {
874
899
  console.log("\u2705 Component ".concat(component.name, " translated successfully in 2D viewport"));
875
900
 
876
- // Auto-update paths if enabled
877
- if (_this6.sceneViewer && _this6.sceneViewer.shouldUpdatePaths) {
901
+ // Single path update with the final combined position
902
+ if (wasAutoUpdate && _this7.sceneViewer) {
878
903
  console.log('🔄 Auto-updating paths after 2D viewport translation...');
879
904
  try {
880
- _this6.sceneViewer.updatePaths();
905
+ _this7.sceneViewer.updatePaths();
881
906
  console.log('✅ Paths auto-updated successfully from 2D viewport');
882
907
  } catch (error) {
883
908
  console.error('❌ Error auto-updating paths from 2D viewport:', error);
@@ -1130,28 +1155,28 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
1130
1155
  }, {
1131
1156
  key: "refresh",
1132
1157
  value: function refresh() {
1133
- var _this7 = this;
1158
+ var _this8 = this;
1134
1159
  var key = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
1135
1160
  if (this._refreshPending) return;
1136
1161
  this._refreshPending = true;
1137
1162
  requestAnimationFrame(function () {
1138
- _this7._refreshPending = false;
1163
+ _this8._refreshPending = false;
1139
1164
  // Clear per-cycle caches so each component is measured/traversed once per paint
1140
- _this7._bboxCache.clear();
1141
- _this7._componentListCache = null;
1165
+ _this8._bboxCache.clear();
1166
+ _this8._componentListCache = null;
1142
1167
  if (key) {
1143
- var viewport = _this7.viewports.get(key);
1168
+ var viewport = _this8.viewports.get(key);
1144
1169
  if (viewport && viewport.isReady) {
1145
- _this7.renderComponents(viewport);
1170
+ _this8.renderComponents(viewport);
1146
1171
  }
1147
1172
  } else {
1148
- var _iterator = _createForOfIteratorHelper(_this7.viewports.values()),
1173
+ var _iterator = _createForOfIteratorHelper(_this8.viewports.values()),
1149
1174
  _step;
1150
1175
  try {
1151
1176
  for (_iterator.s(); !(_step = _iterator.n()).done;) {
1152
1177
  var _viewport = _step.value;
1153
1178
  if (_viewport.isReady) {
1154
- _this7.renderComponents(_viewport);
1179
+ _this8.renderComponents(_viewport);
1155
1180
  }
1156
1181
  }
1157
1182
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@2112-lab/central-plant",
3
- "version": "0.3.10",
3
+ "version": "0.3.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",