@mindexec/cli 0.2.432 → 0.2.434

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.
@@ -1736,14 +1736,7 @@
1736
1736
  atlasContext.fillRect(0, 0, IMAGE_LOD_ATLAS_SIZE, IMAGE_LOD_ATLAS_SIZE);
1737
1737
  }
1738
1738
  this.imageAtlasTexture = new THREE.CanvasTexture(this.imageAtlasCanvas);
1739
- this.imageAtlasTexture.colorSpace = THREE.SRGBColorSpace;
1740
- this.imageAtlasTexture.minFilter = THREE.LinearFilter;
1741
- this.imageAtlasTexture.magFilter = THREE.LinearFilter;
1742
- this.imageAtlasTexture.wrapS = THREE.ClampToEdgeWrapping;
1743
- this.imageAtlasTexture.wrapT = THREE.ClampToEdgeWrapping;
1744
- this.imageAtlasTexture.flipY = false;
1745
- this.imageAtlasTexture.generateMipmaps = false;
1746
- this.imageAtlasTexture.needsUpdate = true;
1739
+ window.MindMapRenderPlan?.configureImageAtlasTexture?.(this.imageAtlasTexture, THREE);
1747
1740
  }
1748
1741
 
1749
1742
  const nodeVertexShader = `
@@ -1956,6 +1949,7 @@
1956
1949
  polygonOffsetUnits: -10.0
1957
1950
  });
1958
1951
 
1952
+ const imageAtlasOutputColorChunk = window.MindMapRenderPlan?.getImageAtlasOutputColorChunk?.(THREE) || '';
1959
1953
  const imageLodMaterial = new THREE.ShaderMaterial({
1960
1954
  uniforms: {
1961
1955
  uImageAtlas: { value: this.imageAtlasTexture },
@@ -2016,7 +2010,7 @@
2016
2010
  color = mix(color, borderColor, borderMask * (vSelected > 0.5 ? 0.92 : 0.36));
2017
2011
 
2018
2012
  gl_FragColor = vec4(color, 1.0);
2019
- #include <colorspace_fragment>
2013
+ ${imageAtlasOutputColorChunk}
2020
2014
  }
2021
2015
  `,
2022
2016
  transparent: false,
@@ -3420,7 +3414,7 @@
3420
3414
  }
3421
3415
 
3422
3416
  hasResidentDirtyWork(camera = this._module?.camera, module = this._module) {
3423
- return this.getResidentDirtyState(camera, module).dirty === true;
3417
+ return window.MindMapRenderPlan?.hasResidentDirtyWork?.(this, camera, module, getLodBandForCameraZ, buildLodSelectionKey, isAnimatedGifImageModel) === true;
3424
3418
  }
3425
3419
 
3426
3420
  willLodBandChange(camera) {
@@ -4018,17 +4012,10 @@
4018
4012
  }
4019
4013
 
4020
4014
  _clearFullResImageVisuals(nodeObjectsById) {
4021
- if (!this._fullResImageVisualIds || this._fullResImageVisualIds.size === 0) return;
4022
-
4023
- for (const nodeId of this._fullResImageVisualIds) {
4024
- const entry = nodeObjectsById?.get?.(nodeId) || null;
4025
- if (entry) this._hideImageLodFullVisual(entry);
4026
- }
4027
-
4028
- this._fullResImageVisualIds.clear();
4015
+ window.MindMapRenderPlan?.clearFullResImageVisuals?.(this, nodeObjectsById);
4029
4016
  }
4030
4017
 
4031
- _syncFullResImageVisuals(visibleIds, nodeObjectsById, module, lodBand) {
4018
+ _syncFullResImageVisuals(visibleIds, nodeObjectsById, module, lodBand, selectionKey = '') {
4032
4019
  if (this.isInLODMode !== false || !nodeObjectsById) {
4033
4020
  this._clearFullResImageVisuals(nodeObjectsById);
4034
4021
  return;
@@ -4058,7 +4045,10 @@
4058
4045
  if (!entry) continue;
4059
4046
 
4060
4047
  if (supportsCss3dNodeModel(entry?.model)) {
4061
- this._syncCssImageBodyBridge(entry, module);
4048
+ if (window.MindMapRenderPlan?.restoreParkedFullResCss?.(
4049
+ this, entry, module, nodeObjectsById, selectionKey, lodBand, nodeId) !== true) {
4050
+ this._syncCssImageBodyBridge(entry, module);
4051
+ }
4062
4052
  continue;
4063
4053
  }
4064
4054
 
@@ -4663,6 +4653,7 @@
4663
4653
  }
4664
4654
 
4665
4655
  entry.cssObject = cssObject;
4656
+ window.MindMapRenderPlan?.cachePreparedResidentCss?.(this, entry, module, module.nodeObjectsById);
4666
4657
  return true;
4667
4658
  }
4668
4659
 
@@ -4672,8 +4663,7 @@
4672
4663
  !Array.isArray(prioritizedVisible) ||
4673
4664
  !nodeObjectsById ||
4674
4665
  !module ||
4675
- this.isLoading ||
4676
- module.isZooming === true) {
4666
+ this.isLoading) {
4677
4667
  return;
4678
4668
  }
4679
4669
 
@@ -4684,12 +4674,12 @@
4684
4674
  if (!nodeId || this._css3dPrewarmQueuedIds.has(nodeId)) continue;
4685
4675
 
4686
4676
  const entry = nodeObjectsById.get(nodeId);
4687
- if (!entry || entry.cssObject || !supportsCss3dNodeModel(entry.model)) continue;
4677
+ if (!entry || (entry.cssObject && entry.isCssDirty !== true) || !supportsCss3dNodeModel(entry.model)) continue;
4688
4678
  if (allowPanTextPrewarm && !isTextLikeModel(entry.model)) continue;
4689
4679
  if (shouldShowAgentConsoleInLodBand(lodBand) && hasAgentConsoleOpenForEntry(entry)) continue;
4690
4680
 
4691
4681
  this._css3dPrewarmQueuedIds.add(nodeId);
4692
- this._css3dPrewarmQueue.push({ nodeId, module });
4682
+ this._css3dPrewarmQueue.push({ nodeId, module, nodeObjectsById, entry });
4693
4683
  }
4694
4684
 
4695
4685
  if (this._css3dPrewarmQueue.length > 0 && !this._css3dPrewarmProcessing) {
@@ -4715,6 +4705,7 @@
4715
4705
  const module = this._module || null;
4716
4706
  const allowPanTextPrewarm = module?.isPanning === true && module?.isZooming !== true;
4717
4707
  if ((module?.isPanning === true && !allowPanTextPrewarm) || module?.isZooming === true) {
4708
+ shouldContinue = this._css3dPrewarmQueue.length > 0;
4718
4709
  return;
4719
4710
  }
4720
4711
 
@@ -4740,11 +4731,17 @@
4740
4731
 
4741
4732
  this._css3dPrewarmQueuedIds.delete(nodeId);
4742
4733
  const itemModule = item.module || this._module;
4734
+ if (itemModule !== this._module || item.nodeObjectsById !== itemModule?.nodeObjectsById) continue;
4743
4735
  const entry = itemModule?.nodeObjectsById?.get(nodeId);
4744
- if (!entry || entry.cssObject || !supportsCss3dNodeModel(entry.model)) continue;
4736
+ if (!entry || entry !== item.entry || (entry.cssObject && entry.isCssDirty !== true) || !supportsCss3dNodeModel(entry.model)) continue;
4745
4737
  if (allowPanTextPrewarm && !isTextLikeModel(entry.model)) continue;
4746
4738
 
4747
- this._ensureHiddenCss3dObject(entry, itemModule);
4739
+ if (!entry.cssObject && !this._ensureHiddenCss3dObject(entry, itemModule)) continue;
4740
+ if (entry.isCssDirty === true && window.MindMapCss3DManager?.syncCss3dContent) {
4741
+ window.MindMapCss3DManager.syncCss3dContent(entry.model, entry.cssObject);
4742
+ entry.isCssDirty = false;
4743
+ }
4744
+ window.MindMapRenderPlan?.cachePreparedResidentCss?.(this, entry, itemModule, item.nodeObjectsById);
4748
4745
  count++;
4749
4746
  }
4750
4747
 
@@ -4806,6 +4803,11 @@
4806
4803
  return;
4807
4804
  }
4808
4805
  const cssParentScene = module?.cssScene || module?.scene;
4806
+ const shouldUseHighCss3dDetail = this._shouldUseHighCss3dDetail(entry, module);
4807
+ if (window.MindMapRenderPlan?.reuseStableVisibleCss?.(this, entry, module, nodeId, {
4808
+ isHighDetail: shouldUseHighCss3dDetail,
4809
+ allowResident: isLivePortalCssLodModel(model)
4810
+ }) === true) return;
4809
4811
 
4810
4812
  // Create if not exists
4811
4813
  if (!entry.cssObject) {
@@ -4846,7 +4848,6 @@
4846
4848
  }
4847
4849
  // ▲▲▲ [FIX] ▲▲▲
4848
4850
 
4849
- const shouldUseHighCss3dDetail = this._shouldUseHighCss3dDetail(entry, module);
4850
4851
  this._setCss3dLodClass(entry, shouldUseHighCss3dDetail);
4851
4852
 
4852
4853
  // ▼▼▼ [CRITICAL] Sync content BEFORE making CSS visible ▼▼▼
@@ -4897,15 +4898,6 @@
4897
4898
  }
4898
4899
  // ▲▲▲ [FIX] ▲▲▲
4899
4900
 
4900
- // CSS3D media nodes need one more sync after the DOM is actually visible.
4901
- // The video canvas proxy refuses to start on hidden CSS objects, so the
4902
- // pre-visibility sync above can otherwise leave the native <video> surface
4903
- // active in near mode and trigger browser compositor artifacts.
4904
- if (isMediaNode && window.MindMapCss3DManager?.syncCss3dMediaNodeFrame) {
4905
- window.MindMapCss3DManager.syncCss3dMediaNodeFrame(model, entry.cssObject, {
4906
- updateSpatialGrid: false
4907
- });
4908
- }
4909
4901
  if (getNodeContentType(model) === 'video' &&
4910
4902
  window.MindMapCss3DManager?.syncVideoNodeVisibilityPlayback) {
4911
4903
  window.MindMapCss3DManager.syncVideoNodeVisibilityPlayback(model, entry.cssObject, true);
@@ -4981,6 +4973,9 @@
4981
4973
  const shouldForceMediaGlFallback =
4982
4974
  (contentType === 'video' || contentType === 'embed') &&
4983
4975
  (options?.forceMediaGlFallback === true || !isCss3dRendererEnabled(this._module));
4976
+ const cssElement = entry?.cssObject?.element || null;
4977
+ let cssVisualChanged = entry?.currentType === 'CSS' || entry?.cssObject?.visible === true ||
4978
+ (!!entry?.cssObject?.parent && cssElement?.style?.display !== 'none');
4984
4979
  if (contentType === 'image' && entry?.model) {
4985
4980
  entry.model._showImageBodyInCssMode = false;
4986
4981
  this._resetFullResImageBridgeState(entry);
@@ -5023,11 +5018,11 @@
5023
5018
  }
5024
5019
  this._setGlowVisibility(entry, false);
5025
5020
  if (nodeId) {
5026
- this._nearCssVisibleIds.delete(nodeId);
5027
- this._lodImageCssFallbackNodeIds.delete(nodeId);
5028
- this._lodTemplateCssNodeIds.delete(nodeId);
5021
+ cssVisualChanged = this._nearCssVisibleIds.delete(nodeId) || cssVisualChanged;
5022
+ cssVisualChanged = this._lodImageCssFallbackNodeIds.delete(nodeId) || cssVisualChanged;
5023
+ cssVisualChanged = this._lodTemplateCssNodeIds.delete(nodeId) || cssVisualChanged;
5029
5024
  }
5030
- if (this._module) {
5025
+ if (this._module && cssVisualChanged) {
5031
5026
  this._module._css3dVisualChangedThisFrame = true;
5032
5027
  this._module._css3dVisualChangedSinceLastRender = true;
5033
5028
  }
@@ -5037,6 +5032,7 @@
5037
5032
  if (!entry || !isCssMediaFallbackModel(entry?.model)) {
5038
5033
  return false;
5039
5034
  }
5035
+ if (window.MindMapRenderPlan?.reuseActiveCssMediaFallback?.(this,entry,module)) return true;
5040
5036
 
5041
5037
  if (!entry.cssObject?.element && !this._ensureHiddenCss3dObject(entry, module)) {
5042
5038
  return false;
@@ -5153,6 +5149,12 @@
5153
5149
  const isNodeSelected = nodeId
5154
5150
  ? isNodeSelectedForLod(nodeId, multiSelectedIds, selectedNodeId)
5155
5151
  : false;
5152
+ const hasInteractiveOwner = module?.draggedNodeId === nodeId || this._getCurrentHoveredNodeId(module) === nodeId;
5153
+ if (contentType === 'image' && !isAnimatedGifImageModel(entry.model) &&
5154
+ this._hasActiveImageLodInstance(nodeId) && !isNodeSelected && !hasInteractiveOwner) {
5155
+ this._hideCssMediaLodFallback(entry, { forceMediaGlFallback: true });
5156
+ return false;
5157
+ }
5156
5158
  const shouldKeep = contentType === 'image'
5157
5159
  ? (entry.isVisibleInFrustum === true || isNodeSelected === true)
5158
5160
  : entry.isVisibleInFrustum === true;
@@ -5172,7 +5174,7 @@
5172
5174
 
5173
5175
  const allowImageCssFallbacks = this._shouldUseCssImageFallbackInResidentLod(module, lodBand);
5174
5176
 
5175
- for (const nodeId of Array.from(this._lodImageCssFallbackNodeIds)) {
5177
+ for (const nodeId of window.MindMapRenderPlan?.fallbackBatch?.(this, this._lodImageCssFallbackNodeIds) || []) {
5176
5178
  const entry = nodeObjectsById.get(nodeId) || null;
5177
5179
  if (!entry || !isCssMediaFallbackModel(entry.model)) {
5178
5180
  this._lodImageCssFallbackNodeIds.delete(nodeId);
@@ -5311,39 +5313,7 @@
5311
5313
  }
5312
5314
 
5313
5315
  hasPendingNearCssWarmup(module) {
5314
- if (this.isInLODMode !== false) {
5315
- return false;
5316
- }
5317
-
5318
- if (this._css3dProcessing || this._css3dQueuedMap.size > 0 || this._hasCss3dQueueItems()) {
5319
- return true;
5320
- }
5321
-
5322
- if (this._nearEntryBoostFrames > 0) {
5323
- return true;
5324
- }
5325
-
5326
- const moduleRef = module || this._module || null;
5327
- const visibleIds = this._getNearVisibleIds(moduleRef);
5328
- const nodeObjectsById = moduleRef?.nodeObjectsById || null;
5329
- if (!visibleIds || !nodeObjectsById || visibleIds.size === 0) {
5330
- return false;
5331
- }
5332
-
5333
- for (const nodeId of visibleIds) {
5334
- if (this._nearCssVisibleIds.has(nodeId)) {
5335
- continue;
5336
- }
5337
-
5338
- const entry = nodeObjectsById.get(nodeId);
5339
- if (!entry?.glObject || !supportsCss3dNodeModel(entry.model)) {
5340
- continue;
5341
- }
5342
-
5343
- return true;
5344
- }
5345
-
5346
- return false;
5316
+ return window.MindMapRenderPlan?.hasPendingNearCssWarmup?.(this, module, buildLodSelectionKey, isCss3dRendererEnabled, supportsCss3dNodeModel) === true;
5347
5317
  }
5348
5318
 
5349
5319
 
@@ -5364,7 +5334,6 @@
5364
5334
 
5365
5335
  if (uniform.value.getHex && uniform.value.getHex() === hex) return;
5366
5336
  uniform.value.setHex(hex);
5367
- mat.needsUpdate = true;
5368
5337
  }
5369
5338
 
5370
5339
  _setInstancedDefaultBorderColor(hex) {
@@ -5378,11 +5347,9 @@
5378
5347
 
5379
5348
  if (uniform && uniform.value) {
5380
5349
  uniform.value.setHex(hex);
5381
- mat.needsUpdate = true;
5382
5350
  }
5383
5351
  if (lineMaterial?.color) {
5384
5352
  lineMaterial.color.setHex(hex);
5385
- lineMaterial.needsUpdate = true;
5386
5353
  }
5387
5354
  }
5388
5355
 
@@ -5394,7 +5361,6 @@
5394
5361
  const nextValue = visible ? 1.0 : 0.0;
5395
5362
  if (uniform.value === nextValue) return;
5396
5363
  uniform.value = nextValue;
5397
- mat.needsUpdate = true;
5398
5364
  }
5399
5365
 
5400
5366
  _setInstancedFarInsetBorderVisibility(visible) {
@@ -5408,21 +5374,14 @@
5408
5374
  const nextValue = visible ? 1.0 : 0.0;
5409
5375
  const nextOpacity = visible ? LOD_NODE_BORDER_OPACITY_FAR : LOD_NODE_BORDER_OPACITY_MID;
5410
5376
  const nextLineOpacity = visible ? LOD_TEXT_LINE_OPACITY_FAR : LOD_TEXT_LINE_OPACITY_MID;
5411
- let changed = false;
5412
5377
  if (uniform && uniform.value !== nextValue) {
5413
5378
  uniform.value = nextValue;
5414
- changed = true;
5415
5379
  }
5416
5380
  if (opacityUniform && opacityUniform.value !== nextOpacity) {
5417
5381
  opacityUniform.value = nextOpacity;
5418
- changed = true;
5419
- }
5420
- if (changed) {
5421
- mat.needsUpdate = true;
5422
5382
  }
5423
5383
  if (lineOpacityUniform && lineOpacityUniform.value !== nextLineOpacity) {
5424
5384
  lineOpacityUniform.value = nextLineOpacity;
5425
- lineMaterial.needsUpdate = true;
5426
5385
  }
5427
5386
  }
5428
5387
 
@@ -5668,40 +5627,8 @@
5668
5627
  return { warmMax, queueMax, perIdle, budgetMs };
5669
5628
  }
5670
5629
 
5671
- _getAdaptiveNearEntryBoostFrames(visibleCount = 0, module = this._module) {
5672
- const avgFrameTime = Number(module?._avgFrameTime || 16);
5673
- const fps = Number(module?._currentFps || 60);
5674
- let frames = 12;
5675
-
5676
- if (visibleCount >= 72) {
5677
- frames = 16;
5678
- }
5679
- if (visibleCount >= 144) {
5680
- frames = 20;
5681
- }
5682
- if (visibleCount >= 240) {
5683
- frames = 24;
5684
- }
5685
-
5686
- if (avgFrameTime > 22 || fps < 42) {
5687
- frames = Math.max(10, frames - 4);
5688
- }
5689
-
5690
- return frames;
5691
- }
5692
-
5693
- _getAdaptiveNearCssActivationConfig(visibleCount = 0, module = this._module, isNearBoostFrame = false) {
5694
- const visibleBudget = Number.isFinite(Number(visibleCount))
5695
- ? Math.max(1, Math.ceil(Number(visibleCount)))
5696
- : Number.MAX_SAFE_INTEGER;
5697
-
5698
- // NEAR/NORMAL is the readable full-res CSS3D path. Splitting activation
5699
- // across frames makes some nodes move or reveal later than others, which
5700
- // is visually worse than a bounded one-tick activation cost.
5701
- return {
5702
- maxPerFrame: visibleBudget,
5703
- budgetMs: Number.MAX_SAFE_INTEGER
5704
- };
5630
+ _getAdaptiveNearCssActivationConfig(visibleCount = 0) {
5631
+ return { maxPerFrame: Math.max(1, Math.ceil(Number(visibleCount) || 1)), budgetMs: Number.MAX_SAFE_INTEGER };
5705
5632
  }
5706
5633
 
5707
5634
  updateLOD(camera, nodeObjectsById, module) {
@@ -5857,10 +5784,11 @@
5857
5784
  }
5858
5785
 
5859
5786
  if (modeChanged) {
5860
- const tModeStart = performance.now(); // ▼ [Timing]
5787
+ const transitionPlan = window.MindMapRenderPlan;
5788
+ transitionPlan?.beginResidentCssTransition?.(
5789
+ this, module, nodeObjectsById, previousLodBand, lodBand, lodSelectionKey);
5861
5790
  this.isInLODMode = shouldUseLOD;
5862
5791
  this._updateMeshVisibility(); // Use helper to respect loading state
5863
- console.log(`[LODRenderer] Mode switched to: ${shouldUseLOD ? 'LOD' : 'FULL-RES'} (Band=${lodBand}, Z=${cameraZ.toFixed(0)})`);
5864
5792
 
5865
5793
  if (this.isInLODMode) {
5866
5794
  this._lodVisualEpoch++;
@@ -5870,11 +5798,12 @@
5870
5798
  if (shouldUseLOD) {
5871
5799
  this._finishFullResHandoff('enter-lod');
5872
5800
  this._clearFullResImageVisuals(nodeObjectsById);
5801
+ if ((this.imageInstanceData?.nodeIds?.length || 0) > 0) {
5802
+ perfTime('lodImageInstances', () => this._applyImageInstanceData());
5803
+ }
5873
5804
  this._fullResMotionHiddenGlIds.clear();
5874
5805
  this._currentLodBand = lodBand;
5875
- if (lodBand === 'MID') {
5876
- this._markLineDetailsDirty();
5877
- }
5806
+ transitionPlan?.ensureResidentLineDetails?.(this, lodBand);
5878
5807
  if (this.instancedHaloMesh) this.instancedHaloMesh.visible = shouldShowInstancedHaloInLodBand(lodBand);
5879
5808
  this.instancedMesh.visible = true;
5880
5809
  if (this.isLoading) {
@@ -5895,6 +5824,7 @@
5895
5824
  cssIdsToHide.add(nodeId);
5896
5825
  }
5897
5826
  const currentNodeMap = this._module?.nodeObjectsById;
5827
+ const activeCssOwnerId = module?.draggedNodeId || this._getCurrentHoveredNodeId(module);
5898
5828
  for (const nodeId of this._activeFullResCssNodeIds) cssIdsToHide.add(nodeId);
5899
5829
  this._clearCss3dQueue();
5900
5830
  this._clearCss3dPrewarmQueue();
@@ -5909,7 +5839,6 @@
5909
5839
  this._primeWarmCss3dCache(prioritizedWarm, currentNodeMap, lodBand);
5910
5840
  this._queueCss3dPrewarm(prioritizedWarm, currentNodeMap, module, lodBand);
5911
5841
  if (currentNodeMap && cssIdsToHide.size > 0) {
5912
- const hideStart = performance.now();
5913
5842
  perfTime('lodCleanup', () => {
5914
5843
  for (const nodeId of cssIdsToHide) {
5915
5844
  const entry = currentNodeMap.get(nodeId);
@@ -5919,15 +5848,18 @@
5919
5848
  const isTextLike = isTextLikeModel(model);
5920
5849
  const shouldKeepConsoleProxy = false;
5921
5850
  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';
5851
+ transitionPlan?.parkFullResCss?.(
5852
+ this, entry, module, currentNodeMap, lodSelectionKey, 'text');
5927
5853
  if (entry.glObject) this._hideTextLodFullVisual(entry);
5928
5854
  this._setGlowVisibility(entry, false);
5929
5855
  continue;
5930
5856
  }
5857
+ const contentType = getNodeContentType(model);
5858
+ const isNodeSelected = isNodeSelectedForLod(nodeId, multiSelectedIds, selectedNodeId);
5859
+ if (!isLivePortalCss && contentType === 'image' &&
5860
+ transitionPlan?.parkReadyResidentImage?.(
5861
+ this, entry, module, currentNodeMap, lodSelectionKey, nodeId,
5862
+ isAnimatedGifImageModel(model), isNodeSelected, activeCssOwnerId === nodeId)) continue;
5931
5863
  const element = entry.cssObject?.element || null;
5932
5864
  if (!isLivePortalCss && isCssMediaFallbackModel(model) &&
5933
5865
  entry.cssObject?.visible === true && element && element.style.display !== 'none') {
@@ -5956,9 +5888,7 @@
5956
5888
  entry.currentType = 'GL';
5957
5889
  }
5958
5890
 
5959
- const contentType = getNodeContentType(model);
5960
5891
  const isImage = isImageLodProxyModel(model);
5961
- const isNodeSelected = isNodeSelectedForLod(nodeId, multiSelectedIds, selectedNodeId);
5962
5892
  if (!isLivePortalCss && isTextLike && entry.glObject) {
5963
5893
  this._hideTextLodFullVisual(entry);
5964
5894
  } else if (isImage) {
@@ -5979,7 +5909,6 @@
5979
5909
  module._css3dVisualChangedSinceLastRender = true;
5980
5910
  }
5981
5911
  });
5982
- console.log(`[LODRenderer] CSS3D hidden synchronously in ${(performance.now() - hideStart).toFixed(1)}ms (${cssIdsToHide.size} active)`);
5983
5912
  }
5984
5913
 
5985
5914
  if (module?.renderDebugFlags?.enableCss3dWillChange === true &&
@@ -6020,7 +5949,7 @@
6020
5949
  this._lastNearCssNoWorkKey = '';
6021
5950
  const nearVisibleIds = this._getNearVisibleIds(module);
6022
5951
  this._clearWarmCss3dCache(this._module?.nodeObjectsById, nearVisibleIds);
6023
- this._nearEntryBoostFrames = this._getAdaptiveNearEntryBoostFrames(nearVisibleIds?.size || 0, module);
5952
+ this._nearEntryBoostFrames = 0;
6024
5953
  this._lodCleanupPending = true;
6025
5954
 
6026
5955
  if (module?.renderDebugFlags?.enableCss3dWillChange === true &&
@@ -6095,7 +6024,7 @@
6095
6024
  }
6096
6025
 
6097
6026
  perfTime('fullResImages', () => {
6098
- this._syncFullResImageVisuals(visibleIds, nodeObjectsById, module, lodBand);
6027
+ this._syncFullResImageVisuals(visibleIds, nodeObjectsById, module, lodBand, lodSelectionKey);
6099
6028
  });
6100
6029
 
6101
6030
  const prioritizedVisible = this._getNearVisiblePriority(visibleIds, nodeObjectsById, camera);
@@ -6229,9 +6158,13 @@
6229
6158
  // visible CSS3D surface in-place so the expanded NORMAL
6230
6159
  // band cannot show a blank low-detail shell while a
6231
6160
  // deferred queue waits for motion/cooldown.
6232
- this._showNodeCss3d(entry, module);
6161
+ if (renderPlan?.restoreParkedFullResCss?.(
6162
+ this, entry, module, nodeObjectsById, lodSelectionKey, lodBand, nodeId) !== true) {
6163
+ this._showNodeCss3d(entry, module);
6164
+ }
6233
6165
  processedCount++;
6234
6166
  }
6167
+ renderPlan?.completeFullResTransition?.(this, allowedCssIds.size);
6235
6168
  });
6236
6169
 
6237
6170
  perfTime('fullResHandoff', () => {
@@ -6394,6 +6327,10 @@
6394
6327
  });
6395
6328
  }
6396
6329
 
6330
+ const committedResidentTextCount = window.MindMapRenderPlan?.syncCommittedResidentTextCount?.(
6331
+ this, hasResidentLodInstances, FORCE_RESIDENT_INSTANCES_IN_MID_FAR === true) ?? -1;
6332
+ if (committedResidentTextCount >= 0) totalTextLikeCount = committedResidentTextCount;
6333
+
6397
6334
  const nextVisibleSubsetMode = shouldUseLOD && this._shouldUseVisibleSubsetLod(totalTextLikeCount, lodBand);
6398
6335
  if (this._lodUsesVisibleSubset !== nextVisibleSubsetMode) {
6399
6336
  this._lodUsesVisibleSubset = nextVisibleSubsetMode;
@@ -6419,9 +6356,7 @@
6419
6356
  } else if (lodBand === 'MID') {
6420
6357
  this._setInstancedBaseColor(0xffffff);
6421
6358
  this._setInstancedDefaultBorderColor(0xd1d5db);
6422
- if (previousResidentBand === 'FAR') {
6423
- this._markLineDetailsDirty();
6424
- }
6359
+ if (previousResidentBand === 'FAR') window.MindMapRenderPlan?.ensureResidentLineDetails?.(this, lodBand);
6425
6360
  }
6426
6361
  }
6427
6362
  const shouldSyncTemplateCss3d =
@@ -6884,7 +6819,7 @@
6884
6819
  this._cachedImageNodeCount = imageNodeIds.length;
6885
6820
  }
6886
6821
 
6887
- _updateImageInstanceData(nodeObjectsById) {
6822
+ _updateImageInstanceData(nodeObjectsById, prepareOnly = false) {
6888
6823
  const imagePositions = [];
6889
6824
  const imageSizes = [];
6890
6825
  const imageSelections = [];
@@ -6911,13 +6846,13 @@
6911
6846
 
6912
6847
  if (contentType === 'image' &&
6913
6848
  this._shouldUseCssImageFallbackInResidentLod(this._module, this._currentLodBand)) {
6914
- this._hideImageLodFullVisual(entry);
6849
+ if (!prepareOnly) this._hideImageLodFullVisual(entry);
6915
6850
  return;
6916
6851
  }
6917
6852
 
6918
6853
  const obj = entry.glObject || entry.cssObject;
6919
6854
  if (!obj) {
6920
- this._hideImageLodFullVisual(entry);
6855
+ if (!prepareOnly) this._hideImageLodFullVisual(entry);
6921
6856
  return;
6922
6857
  }
6923
6858
 
@@ -6928,7 +6863,7 @@
6928
6863
  entry.isVisibleInFrustum === true ||
6929
6864
  isNodeSelected === true;
6930
6865
  if (!shouldKeepImageInstance) {
6931
- this._hideImageLodFullVisual(entry);
6866
+ if (!prepareOnly) this._hideImageLodFullVisual(entry);
6932
6867
  return;
6933
6868
  }
6934
6869
 
@@ -6943,7 +6878,7 @@
6943
6878
  if (!isRetryDeferred && isLoadPending) {
6944
6879
  imageBatchPendingIds.add(nodeId);
6945
6880
  }
6946
- if (contentType === 'image') {
6881
+ if (!prepareOnly && contentType === 'image') {
6947
6882
  this._syncImageLodTransitionVisual(
6948
6883
  entry,
6949
6884
  this._currentLodBand || 'MID',
@@ -6951,7 +6886,7 @@
6951
6886
  this._module,
6952
6887
  interactionState
6953
6888
  );
6954
- } else {
6889
+ } else if (!prepareOnly) {
6955
6890
  this._syncCssMediaLodFallback(entry, this._module);
6956
6891
  }
6957
6892
  return;
@@ -6967,10 +6902,10 @@
6967
6902
  imageUvRects.push(uvRect[0], uvRect[1], uvRect[2], uvRect[3]);
6968
6903
  imageNodeIds.push(nodeId);
6969
6904
  this._imageNodeIdToIndex.set(nodeId, imageNodeIds.length - 1);
6970
- if (contentType !== 'image') {
6905
+ if (!prepareOnly && contentType !== 'image') {
6971
6906
  this._hideCssMediaLodFallback(entry);
6972
6907
  }
6973
- this._hideImageLodFullVisual(entry);
6908
+ if (!prepareOnly) this._hideImageLodFullVisual(entry);
6974
6909
  });
6975
6910
 
6976
6911
  if (imageBatchPendingIds.size > 0) {
@@ -7135,35 +7070,7 @@
7135
7070
  }
7136
7071
 
7137
7072
  _hasAnimatedGifCssFallbackCandidates(module = this._module) {
7138
- const nodeObjectsById = module?.nodeObjectsById || this._module?.nodeObjectsById || null;
7139
- if (!nodeObjectsById) {
7140
- return false;
7141
- }
7142
-
7143
- const candidateIds = [];
7144
- const pushId = (value) => {
7145
- const id = String(value || '').trim();
7146
- if (id) candidateIds.push(id);
7147
- };
7148
-
7149
- module?._visibleIds?.forEach?.(pushId);
7150
- module?._prevVisibleIds?.forEach?.(pushId);
7151
- pushId(module?.selectedNodeIdJs);
7152
- module?.multiSelectedNodeIds?.forEach?.(pushId);
7153
- this._lodImageCssFallbackNodeIds?.forEach?.(pushId);
7154
-
7155
- const seenIds = new Set();
7156
- for (const nodeId of candidateIds) {
7157
- if (seenIds.has(nodeId)) continue;
7158
- seenIds.add(nodeId);
7159
-
7160
- const entry = nodeObjectsById.get(nodeId) || null;
7161
- if (isAnimatedGifImageModel(entry?.model)) {
7162
- return true;
7163
- }
7164
- }
7165
-
7166
- return false;
7073
+ return window.MindMapRenderPlan?.hasAnimatedGifCssFallbackCandidates?.(this, module, isAnimatedGifImageModel) === true;
7167
7074
  }
7168
7075
 
7169
7076
  _shouldPreserveCssMediaFallbackForInteraction(entry, module = this._module) {