@mindexec/cli 0.2.430 → 0.2.432

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.
@@ -924,10 +924,10 @@
924
924
  // Create initial texture array
925
925
  this._createTextureArray();
926
926
 
927
- // Line data cache & texture (for actual text-based lines)
928
- this.maxInstances = 10000;
929
- this.lineDataCache = new Map(); // nodeId -> { signature, lineCount, lineLengths }
930
- this.lineDataArray = new Uint8Array(this.maxInstances * MAX_LINE_SAMPLES);
927
+ this.maxInstances = 10000;
928
+ this.lineDataCache = new Map();
929
+ this.lineTextureRows = window.MindMapRenderPlan?.initialLineTextureRows?.(this.maxInstances) || this.maxInstances;
930
+ this.lineDataArray = new Uint8Array(this.lineTextureRows * MAX_LINE_SAMPLES);
931
931
  this.lineDataTexture = null;
932
932
  this.lineDataDirty = true;
933
933
  this._lastInstanceCount = 0;
@@ -1211,7 +1211,7 @@
1211
1211
  return this.imageAtlasFreeSlots.pop();
1212
1212
  }
1213
1213
 
1214
- if (this.imageAtlasNextSlot >= IMAGE_LOD_ATLAS_MAX_SLOTS) {
1214
+ if (this.imageAtlasNextSlot >= (this.imageAtlasMaxSlots || IMAGE_LOD_ATLAS_MAX_SLOTS)) {
1215
1215
  return -1;
1216
1216
  }
1217
1217
 
@@ -1219,9 +1219,10 @@
1219
1219
  }
1220
1220
 
1221
1221
  _getImageAtlasUvRect(slotIndex) {
1222
- const col = slotIndex % IMAGE_LOD_ATLAS_COLUMNS;
1223
- const row = Math.floor(slotIndex / IMAGE_LOD_ATLAS_COLUMNS);
1224
- const invAtlas = 1 / IMAGE_LOD_ATLAS_SIZE;
1222
+ const columns = this.imageAtlasColumns || IMAGE_LOD_ATLAS_COLUMNS;
1223
+ const col = slotIndex % columns;
1224
+ const row = Math.floor(slotIndex / columns);
1225
+ const invAtlas = 1 / (this.imageAtlasSize || IMAGE_LOD_ATLAS_SIZE);
1225
1226
  const inset = 1.0;
1226
1227
  return [
1227
1228
  (col * IMAGE_LOD_THUMBNAIL_SIZE + inset) * invAtlas,
@@ -1232,7 +1233,7 @@
1232
1233
  }
1233
1234
 
1234
1235
  _getImagePlaceholderUvRect() {
1235
- const invAtlas = 1 / IMAGE_LOD_ATLAS_SIZE;
1236
+ const invAtlas = 1 / (this.imageAtlasSize || IMAGE_LOD_ATLAS_SIZE);
1236
1237
  return [invAtlas, invAtlas, invAtlas, invAtlas];
1237
1238
  }
1238
1239
 
@@ -1583,8 +1584,9 @@
1583
1584
  return false;
1584
1585
  }
1585
1586
 
1586
- const col = slot.slotIndex % IMAGE_LOD_ATLAS_COLUMNS;
1587
- const row = Math.floor(slot.slotIndex / IMAGE_LOD_ATLAS_COLUMNS);
1587
+ const columns = this.imageAtlasColumns || IMAGE_LOD_ATLAS_COLUMNS;
1588
+ const col = slot.slotIndex % columns;
1589
+ const row = Math.floor(slot.slotIndex / columns);
1588
1590
  const x = col * IMAGE_LOD_THUMBNAIL_SIZE;
1589
1591
  const y = row * IMAGE_LOD_THUMBNAIL_SIZE;
1590
1592
  const size = IMAGE_LOD_THUMBNAIL_SIZE;
@@ -1712,8 +1714,8 @@
1712
1714
  if (!this.lineDataTexture) {
1713
1715
  this.lineDataTexture = new THREE.DataTexture(
1714
1716
  this.lineDataArray,
1715
- MAX_LINE_SAMPLES,
1716
- this.maxInstances,
1717
+ MAX_LINE_SAMPLES,
1718
+ this.lineTextureRows,
1717
1719
  THREE.RedFormat,
1718
1720
  THREE.UnsignedByteType
1719
1721
  );
@@ -2154,7 +2156,7 @@
2154
2156
  const lineMaterial = new THREE.ShaderMaterial({
2155
2157
  uniforms: {
2156
2158
  uLineDataTex: { value: this.lineDataTexture },
2157
- uLineDataSize: { value: new THREE.Vector2(MAX_LINE_SAMPLES, this.maxInstances) },
2159
+ uLineDataSize: { value: new THREE.Vector2(MAX_LINE_SAMPLES, this.lineTextureRows) },
2158
2160
  uLineHeightPx: { value: LINE_HEIGHT_PX },
2159
2161
  uLinePaddingPx: { value: LINE_PADDING_PX },
2160
2162
  uLineHalfThicknessPx: { value: LOD_TEXT_LINE_HALF_THICKNESS_SCREEN_PX },
@@ -2727,43 +2729,6 @@
2727
2729
  this._startFullResHandoff(previousBand || this._fullResHandoffPreviousBand || 'MID', 'pending-css', this._fullResPanHandoffMaxMs);
2728
2730
  }
2729
2731
 
2730
- _collectResidentModeCss3dCleanupIds(nodeObjectsById) {
2731
- const ids = new Set();
2732
- if (!nodeObjectsById?.forEach) {
2733
- return ids;
2734
- }
2735
-
2736
- nodeObjectsById.forEach((entry, key) => {
2737
- if (!entry?.cssObject || isLivePortalCssLodModel(entry?.model)) {
2738
- return;
2739
- }
2740
-
2741
- const element = entry.cssObject.element || null;
2742
- const isAttached = !!entry.cssObject.parent;
2743
- const isDisplayed = !!element &&
2744
- element.style.display !== 'none' &&
2745
- element.style.visibility !== 'hidden' &&
2746
- element.style.opacity !== '0';
2747
- const isVisible = entry.cssObject.visible === true || isAttached || isDisplayed;
2748
- if (!isVisible) {
2749
- return;
2750
- }
2751
-
2752
- const nodeId = String(
2753
- entry.model?.id ||
2754
- entry.model?.Id ||
2755
- entry.glObject?.userData?.nodeId ||
2756
- entry.cssObject?.userData?.nodeId ||
2757
- key ||
2758
- ''
2759
- ).trim();
2760
- if (nodeId) {
2761
- ids.add(nodeId);
2762
- }
2763
- });
2764
-
2765
- return ids;
2766
- }
2767
2732
  // ▲▲▲ [New] ▲▲▲
2768
2733
 
2769
2734
  // ═══════════════════════════════════════════════════════════════════════
@@ -3756,7 +3721,7 @@
3756
3721
  }
3757
3722
  }
3758
3723
 
3759
- for (const nodeId of Array.from(this._lodImageCssFallbackNodeIds)) {
3724
+ for (const nodeId of window.MindMapRenderPlan?.fallbackBatch?.(this,this._lodImageCssFallbackNodeIds)||Array.from(this._lodImageCssFallbackNodeIds)) {
3760
3725
  if (nextFallbackIds.has(nodeId)) {
3761
3726
  continue;
3762
3727
  }
@@ -3779,7 +3744,7 @@
3779
3744
  }
3780
3745
 
3781
3746
  let hiddenCount = 0;
3782
- for (const nodeId of Array.from(this._lodImageCssFallbackNodeIds)) {
3747
+ for (const nodeId of window.MindMapRenderPlan?.fallbackBatch?.(this,this._lodImageCssFallbackNodeIds)||Array.from(this._lodImageCssFallbackNodeIds)) {
3783
3748
  const entry = nodeObjectsById?.get?.(nodeId) || null;
3784
3749
  if (entry) {
3785
3750
  this._hideCssMediaLodFallback(entry);
@@ -4554,6 +4519,7 @@
4554
4519
  }
4555
4520
 
4556
4521
  _restoreVisibleCss3dHighDetailForNear(nodeObjectsById, module, lodBand) {
4522
+ // Full-res: NEAR / NORMAL. MID/FAR use resident instances.
4557
4523
  if ((lodBand !== 'NEAR' && lodBand !== 'NORMAL') || !nodeObjectsById) {
4558
4524
  return 0;
4559
4525
  }
@@ -5826,8 +5792,8 @@
5826
5792
  if (this.instancedImageMesh) this.instancedImageMesh.visible = false;
5827
5793
  return;
5828
5794
  }
5795
+ window.MindMapRenderPlan?.scheduleResidentLinePrewarm?.(this, module, nodeObjectsById);
5829
5796
 
5830
- // Explicit bands: NEAR(DOM overlay + CSS3D), MID(resident nodes+lines), FAR(nodes only)
5831
5797
  const shouldUseLOD = lodBand === 'MID' || lodBand === 'FAR';
5832
5798
  perfMode = shouldUseLOD ? 'lod' : 'fullres';
5833
5799
  const isLodPanFrame = shouldUseLOD &&
@@ -5890,8 +5856,6 @@
5890
5856
  this._markCss3dSyncNeeded(true);
5891
5857
  }
5892
5858
 
5893
- // State changed? Only toggle visibility on state change
5894
- // Also force transition when mode is unknown (after reset/re-activation).
5895
5859
  if (modeChanged) {
5896
5860
  const tModeStart = performance.now(); // ▼ [Timing]
5897
5861
  this.isInLODMode = shouldUseLOD;
@@ -5904,7 +5868,6 @@
5904
5868
  }
5905
5869
 
5906
5870
  if (shouldUseLOD) {
5907
- // LOD: instanced nodes are visible, halo is enabled in MID/FAR.
5908
5871
  this._finishFullResHandoff('enter-lod');
5909
5872
  this._clearFullResImageVisuals(nodeObjectsById);
5910
5873
  this._fullResMotionHiddenGlIds.clear();
@@ -5923,7 +5886,6 @@
5923
5886
  this._syncInstancedImageMeshVisibility();
5924
5887
  }
5925
5888
 
5926
- // Keep the resident MID/FAR instance buffers; only real node mutations mark them dirty.
5927
5889
  const cssIdsToHide = new Set(this._nearCssVisibleIds);
5928
5890
  for (let i = this._css3dQueueCursor || 0; i < this._css3dQueue.length; i++) {
5929
5891
  const item = this._css3dQueue[i];
@@ -5933,17 +5895,13 @@
5933
5895
  cssIdsToHide.add(nodeId);
5934
5896
  }
5935
5897
  const currentNodeMap = this._module?.nodeObjectsById;
5936
- for (const nodeId of this._collectResidentModeCss3dCleanupIds(currentNodeMap)) {
5937
- cssIdsToHide.add(nodeId);
5938
- }
5898
+ for (const nodeId of this._activeFullResCssNodeIds) cssIdsToHide.add(nodeId);
5939
5899
  this._clearCss3dQueue();
5940
5900
  this._clearCss3dPrewarmQueue();
5941
5901
  this._css3dProcessing = false;
5942
5902
  this._nearCssVisibleIds.clear();
5943
5903
  this._lastNearCssNoWorkKey = '';
5944
5904
 
5945
- // Hide only CSS3D nodes that were actually on-screen; the LOD cleanup queue
5946
- // catches any stale off-screen DOM without blocking the wheel transition.
5947
5905
  const visibleIds = this._getNearVisibleIds(module);
5948
5906
  const prioritizedWarm = currentNodeMap && visibleIds
5949
5907
  ? this._getNearVisiblePriority(visibleIds, currentNodeMap, camera)
@@ -5958,7 +5916,26 @@
5958
5916
  if (!entry) continue;
5959
5917
  const model = entry.model;
5960
5918
  const isLivePortalCss = isLivePortalCssLodModel(model);
5919
+ const isTextLike = isTextLikeModel(model);
5961
5920
  const shouldKeepConsoleProxy = false;
5921
+ if (!isLivePortalCss && isTextLike) {
5922
+ if (entry.cssObject) {
5923
+ entry.cssObject.visible = false;
5924
+ entry.cssObject.element?.style?.setProperty?.('display', 'none', 'important');
5925
+ }
5926
+ entry.currentType = 'GL';
5927
+ if (entry.glObject) this._hideTextLodFullVisual(entry);
5928
+ this._setGlowVisibility(entry, false);
5929
+ continue;
5930
+ }
5931
+ const element = entry.cssObject?.element || null;
5932
+ if (!isLivePortalCss && isCssMediaFallbackModel(model) &&
5933
+ entry.cssObject?.visible === true && element && element.style.display !== 'none') {
5934
+ this._lodImageCssFallbackNodeIds.add(nodeId);
5935
+ entry.currentType = 'GL';
5936
+ if (entry.glObject) this._hideGlBodyOnly(entry);
5937
+ continue;
5938
+ }
5962
5939
  if (entry.cssObject?.element) {
5963
5940
  this._hideAgentConsoleLodProxy(entry);
5964
5941
  }
@@ -5979,8 +5956,6 @@
5979
5956
  entry.currentType = 'GL';
5980
5957
  }
5981
5958
 
5982
- // Text-like nodes: hide GL body (InstancedMesh renders them)
5983
- const isTextLike = isTextLikeModel(model);
5984
5959
  const contentType = getNodeContentType(model);
5985
5960
  const isImage = isImageLodProxyModel(model);
5986
5961
  const isNodeSelected = isNodeSelectedForLod(nodeId, multiSelectedIds, selectedNodeId);
@@ -5988,7 +5963,6 @@
5988
5963
  this._hideTextLodFullVisual(entry);
5989
5964
  } else if (isImage) {
5990
5965
  if (shouldKeepCssMediaFallback) {
5991
- // Visible media stays on the CSS fallback path until its resident proxy is ready.
5992
5966
  } else {
5993
5967
  if (contentType === 'image' && !isCss3dRendererEnabled(module)) {
5994
5968
  this._syncImageLodTransitionVisual(entry, lodBand, isNodeSelected, module);
@@ -6000,6 +5974,10 @@
6000
5974
 
6001
5975
  this._setGlowVisibility(entry, false);
6002
5976
  }
5977
+ if (module) {
5978
+ module._css3dVisualChangedThisFrame = true;
5979
+ module._css3dVisualChangedSinceLastRender = true;
5980
+ }
6003
5981
  });
6004
5982
  console.log(`[LODRenderer] CSS3D hidden synchronously in ${(performance.now() - hideStart).toFixed(1)}ms (${cssIdsToHide.size} active)`);
6005
5983
  }
@@ -6016,8 +5994,6 @@
6016
5994
 
6017
5995
  } else {
6018
5996
  perfTime('fullResSetup', () => {
6019
- // Full-res: NEAR / NORMAL. MID/FAR use resident instances.
6020
- const tNearStart = performance.now();
6021
5997
  if (this.instancedHaloMesh) this.instancedHaloMesh.visible = false;
6022
5998
  if (this.instancedConsoleMesh) this.instancedConsoleMesh.visible = false;
6023
5999
  this._startFullResHandoff(previousLodBand, 'enter-full-res', this._fullResHandoffMaxMs);
@@ -6051,8 +6027,6 @@
6051
6027
  window.MindMapCss3DManager?.setWillChange) {
6052
6028
  window.MindMapCss3DManager.setWillChange(true, module);
6053
6029
  }
6054
- const tModeEnd = performance.now();
6055
- console.log(`[LODRenderer] ⏱️ Full-res band=${lodBand}: setup ${(tModeEnd - tNearStart).toFixed(1)}ms (visible-only CSS3D activation)`);
6056
6030
  // ▲▲▲ [FIX] ▲▲▲
6057
6031
  });
6058
6032
  }
@@ -6091,8 +6065,12 @@
6091
6065
  // ▼▼▼ [Fix] Keep CSS3D visibility synced while panning in near mode ▼▼▼
6092
6066
  if (!this.isInLODMode) {
6093
6067
  this._currentLodBand = lodBand;
6094
- this._restoreVisibleCss3dHighDetailForNear(nodeObjectsById, module, lodBand);
6095
6068
  const visibleIds = this._getNearVisibleIds(module);
6069
+ const renderPlan = window.MindMapRenderPlan;
6070
+ const css3dEnabled = isCss3dRendererEnabled(module);
6071
+ const stableFullResKey = renderPlan?.buildFullResKey(lodBand, visibilityVersion, lodSelectionKey, nodeObjectsById.size, visibleIds?.size || 0, this._nearCssVisibleIds.size, this._activeFullResCssNodeIds.size, css3dEnabled, module, this);
6072
+ if (visibleIds?.size > 0 && renderPlan?.shouldSkipStableFullRes(this, module, stableFullResKey, bandChangedWithoutModeSwitch)) return;
6073
+ this._restoreVisibleCss3dHighDetailForNear(nodeObjectsById, module, lodBand);
6096
6074
  if (!visibleIds || visibleIds.size === 0) {
6097
6075
  perfTime('fullResHandoff', () => {
6098
6076
  this._activeFullResCssNodeIds.clear();
@@ -6172,17 +6150,8 @@
6172
6150
  return;
6173
6151
  }
6174
6152
 
6175
- const nearCssNoWorkKey = `${lodBand}|${visibilityVersion}|${nodeObjectsById.size}|${this._nearCssVisibleIds.size}|${allowedCssIds.size}`;
6176
- if (this._lastNearCssNoWorkKey === nearCssNoWorkKey &&
6177
- !this._hasCss3dQueueItems() &&
6178
- this._css3dQueuedMap.size === 0 &&
6179
- this._css3dProcessing !== true &&
6180
- this._nearEntryBoostFrames <= 0 &&
6181
- this._fullResHandoffActive !== true &&
6182
- cssReadinessDrift !== true &&
6183
- !bandChangedWithoutModeSwitch) {
6184
- return;
6185
- }
6153
+ const nearCssNoWorkKey = renderPlan?.buildFullResKey(lodBand, visibilityVersion, lodSelectionKey, nodeObjectsById.size, visibleIds.size, this._nearCssVisibleIds.size, allowedCssIds.size, css3dEnabled, module, this);
6154
+ if (renderPlan?.commitStableFullRes(this, module, nearCssNoWorkKey, bandChangedWithoutModeSwitch, cssReadinessDrift)) return;
6186
6155
 
6187
6156
  let hasNearCssWork =
6188
6157
  this._hasCss3dQueueItems() ||
@@ -6590,7 +6559,7 @@
6590
6559
  }
6591
6560
  this._updateInstanceData(nodeObjectsById);
6592
6561
  this._applyInstanceData();
6593
- this._lineDetailsPatchPending = false;
6562
+ this._lineDetailsPatchPending = this._residentLineFallbackUsed === true;
6594
6563
  if (fullBuildReason !== 'line-details') {
6595
6564
  this._noteResidentFullBuild(fullBuildReason, lodBand);
6596
6565
  }
@@ -6660,8 +6629,9 @@
6660
6629
  }
6661
6630
  }
6662
6631
 
6663
- _updateInstanceData(nodeObjectsById) {
6664
- const positions = [];
6632
+ _updateInstanceData(nodeObjectsById) {
6633
+ this._residentLineFallbackUsed = false;
6634
+ const positions = [];
6665
6635
  const sizes = [];
6666
6636
  const selections = [];
6667
6637
  const seeds = [];
@@ -6872,8 +6842,10 @@
6872
6842
  }
6873
6843
  }
6874
6844
  } else {
6875
- // Build actual line length data from text
6876
- const lineData = this._getLineDataForNode(model, entry.lodSeed, w, h, entry);
6845
+ const lineData = window.MindMapRenderPlan?.resolveResidentLineData?.(
6846
+ this, entry, w, h, this._residentBuilt === true,
6847
+ MAX_LINE_SAMPLES, LINE_HEIGHT_PX, LINE_PADDING_PX
6848
+ ) || this._getLineDataForNode(model, entry.lodSeed, w, h, entry);
6877
6849
  lineCounts.push(lineData.lineCount);
6878
6850
  lineHeights.push(lineData.lineHeightPx || LINE_HEIGHT_PX);
6879
6851
  linePaddings.push(lineData.paddingX || LINE_PADDING_PX, lineData.paddingY || LINE_PADDING_PX);
@@ -7589,6 +7561,7 @@
7589
7561
  }
7590
7562
 
7591
7563
  const nodeIds = Array.isArray(this.instanceData?.nodeIds) ? this.instanceData.nodeIds : [];
7564
+ if (window.MindMapRenderPlan?.areResidentLinesPrepared?.(this, nodeObjectsById, nodeIds) === false) return false;
7592
7565
  const lineCounts = this.instanceData?.lineCounts || [];
7593
7566
  const lineLengths = this.instanceData?.lineLengths || [];
7594
7567
  const lineHeights = this.instanceData?.lineHeights || [];
@@ -7614,7 +7587,8 @@
7614
7587
  const model = entry.model;
7615
7588
  const w = model.width || 400;
7616
7589
  const h = model.height || 200;
7617
- const lineData = this._getLineDataForNode(model, entry.lodSeed, w, h, entry);
7590
+ const lineData = window.MindMapRenderPlan?.getPreparedLineData?.(this, entry, w, h) ||
7591
+ this._getLineDataForNode(model, entry.lodSeed, w, h, entry);
7618
7592
  const base = i * MAX_LINE_SAMPLES;
7619
7593
 
7620
7594
  lineCounts[i] = lineData.lineCount || 0;
@@ -8410,18 +8384,16 @@
8410
8384
  const consoleCount = consolePositions.length / 3;
8411
8385
  const imageCount = imagePositions.length / 3;
8412
8386
 
8413
- // Resize buffers if needed (simple resize strategy: if full, create bigger)
8414
- // For now assuming 10000 is enough, or it will just slice (visual glitch but no crash)
8415
- const max = positionAttr.count;
8387
+ const max = positionAttr.count;
8416
8388
  if (count > max) {
8417
8389
  console.warn('[LODRenderer] Buffer overflow, need to resize (omitted for safety)');
8418
8390
  }
8419
8391
 
8420
8392
  const safeCount = Math.min(count, max);
8393
+ window.MindMapRenderPlan?.ensureLineTextureCapacity?.(this, safeCount, MAX_LINE_SAMPLES);
8421
8394
  let lineRowsRewritten = false;
8422
8395
  const suspendLineDetailsForPan = this._isPanLineDetailSuspended();
8423
8396
 
8424
- // Update attribute data
8425
8397
  for (let i = 0; i < safeCount; i++) {
8426
8398
  positionAttr.setXYZ(i, positions[i * 3], positions[i * 3 + 1], positions[i * 3 + 2]);
8427
8399
  sizeAttr.setXY(i, sizes[i * 2], sizes[i * 2 + 1]);