@mindexec/cli 0.2.436 → 0.2.437

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (18) hide show
  1. package/package.json +1 -1
  2. package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js +28 -16
  3. package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +2 -2
  4. package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-renderer.js +153 -233
  5. package/wwwroot/_content/MindExecution.Shared/js/mind-map-logic-workers.js +26 -5
  6. package/wwwroot/_content/MindExecution.Shared/js/mind-map-normal-boundary-optimizer.js +624 -0
  7. package/wwwroot/_content/MindExecution.Shared/js/mind-map-render-plan.js +40 -23
  8. package/wwwroot/_content/MindExecution.Shared/js/mind-map-visibility-worker.js +10 -5
  9. package/wwwroot/_content/MindExecution.Shared/js/renderers/CSS3DRenderer.js +10 -1
  10. package/wwwroot/_framework/{MindExecution.Plugins.Concept.7uhld08zkc.dll → MindExecution.Plugins.Concept.vbnlpkxcoo.dll} +0 -0
  11. package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.y1sj1ifw0z.dll → MindExecution.Plugins.PlanMaster.k3xu6iqktj.dll} +0 -0
  12. package/wwwroot/_framework/{MindExecution.Plugins.YouTube.ij0uk05x1o.dll → MindExecution.Plugins.YouTube.dqlboez3y6.dll} +0 -0
  13. package/wwwroot/_framework/{MindExecution.Shared.1h72etbxec.dll → MindExecution.Shared.6xss0iwsn1.dll} +0 -0
  14. package/wwwroot/_framework/{MindExecution.Web.18xe2efznc.dll → MindExecution.Web.22pax8j6l6.dll} +0 -0
  15. package/wwwroot/_framework/blazor.boot.json +11 -11
  16. package/wwwroot/index.html +3 -2
  17. package/wwwroot/service-worker-assets.js +24 -20
  18. package/wwwroot/service-worker.js +1 -1
@@ -51,7 +51,7 @@
51
51
  // ▲▲▲ [Usage] ▲▲▲
52
52
 
53
53
  // Procedural line rendering settings
54
- const LOD_RENDERER_BUILD_ID = '20260628-pan-wheel-resident-defer-v840';
54
+ const LOD_RENDERER_BUILD_ID = '20260713-normal-boundary-delta-v844';
55
55
  const DirtyKind = Object.freeze({
56
56
  ResidentFullRebuild: 'resident-full-rebuild',
57
57
  ResidentPatch: 'resident-patch',
@@ -896,6 +896,12 @@
896
896
  this._css3dPrewarmMax = 128;
897
897
  this._css3dPrewarmPerIdle = 4;
898
898
  this._css3dPrewarmBudgetMs = 6;
899
+ this._fullResCssFringePrewarmState = null;
900
+ this._fullResCssFringePrewarmCount = 0;
901
+ this._fullResCssFringePrewarmCandidateCount = 0;
902
+ this._fullResCssFringeLayoutWarmCount = 0;
903
+ this._fullResCssFringePreparedIds = new Set();
904
+ this._disposed = false;
899
905
  // ▲▲▲ [Perf] ▲▲▲
900
906
 
901
907
  // ▼▼▼ [State] Loading flag ▼▼▼
@@ -940,7 +946,15 @@
940
946
  this._currentLodBand = null; // 'NEAR' | 'NORMAL' | 'MID' | 'FAR'
941
947
  this._nearCssVisibleIds = new Set();
942
948
  this._activeFullResCssNodeIds = new Set();
949
+ this._lastFullResCssAllowVisibilityVersion = -1;
950
+ this._lastFullResCssAllowSelectionKey = '';
951
+ this._lastFullResCssAllowNodeMap = null;
952
+ this._fullResCssPendingReadyIds = new Set();
953
+ this._lastFullResReadinessVisibilityVersion = -1;
954
+ this._lastFullResReadinessSelectionKey = '';
955
+ this._lastFullResReadinessNodeMap = null;
943
956
  this._nearPriorityBuffer = [];
957
+ this._nearPriorityRecordById = new Map();
944
958
  this._nearEntryBoostFrames = 0;
945
959
  this._warmCss3dNodeIds = new Set();
946
960
  this._warmCss3dMax = 128;
@@ -991,6 +1005,10 @@
991
1005
  this._postLoadVisualSyncPending = false;
992
1006
  this._postLoadVisualSyncReason = '';
993
1007
  this._fullResImageVisualIds = new Set();
1008
+ this._lastFullResImageSyncVisibilityVersion = -1;
1009
+ this._lastFullResImageSyncSelectionKey = '';
1010
+ this._lastFullResImageSyncLodBand = '';
1011
+ this._lastFullResImageSyncNodeMap = null;
994
1012
  this._fullResMotionHiddenGlIds = new Set();
995
1013
  this._lastImageFallbackRevealKey = '';
996
1014
  this._fullResCssImageBridgeSettleMs = 48;
@@ -2996,6 +3014,13 @@
2996
3014
  this._lastLodScanSelectionKey = '';
2997
3015
  this._lastLodScanVisibilityVersion = -1;
2998
3016
  this._lastNearCssNoWorkKey = '';
3017
+ this._lastFullResCssAllowVisibilityVersion = -1;
3018
+ this._lastFullResCssAllowSelectionKey = '';
3019
+ this._lastFullResCssAllowNodeMap = null;
3020
+ this._lastFullResReadinessVisibilityVersion = -1;
3021
+ this._lastFullResReadinessSelectionKey = '';
3022
+ this._lastFullResReadinessNodeMap = null;
3023
+ this._fullResCssPendingReadyIds.clear();
2999
3024
  this._pendingLodVisibilityVersion = -1;
3000
3025
  this._lastImageFallbackRevealKey = '';
3001
3026
  if (resetCursor) {
@@ -4013,6 +4038,10 @@
4013
4038
 
4014
4039
  _clearFullResImageVisuals(nodeObjectsById) {
4015
4040
  window.MindMapRenderPlan?.clearFullResImageVisuals?.(this, nodeObjectsById);
4041
+ this._lastFullResImageSyncVisibilityVersion = -1;
4042
+ this._lastFullResImageSyncSelectionKey = '';
4043
+ this._lastFullResImageSyncLodBand = '';
4044
+ this._lastFullResImageSyncNodeMap = null;
4016
4045
  }
4017
4046
 
4018
4047
  _syncFullResImageVisuals(visibleIds, nodeObjectsById, module, lodBand, selectionKey = '') {
@@ -4021,26 +4050,56 @@
4021
4050
  return;
4022
4051
  }
4023
4052
 
4024
- const nextVisibleImageIds = new Set();
4025
4053
  const multiSelectedIds = module?.multiSelectedNodeIds || new Set();
4026
4054
  const selectedNodeId = module?.selectedNodeIdJs || null;
4027
4055
  const interactionState = {
4028
4056
  hoveredNodeId: this._getCurrentHoveredNodeId(module),
4029
4057
  draggedNodeId: module?.draggedNodeId || null
4030
4058
  };
4031
- if (visibleIds?.size > 0) {
4059
+ const visibilityVersion = Number(module?._visibilityVersion || 0);
4060
+ const normalizedSelectionKey = String(selectionKey || '');
4061
+ const canApplyVisibilityDelta =
4062
+ this._lastFullResImageSyncNodeMap === nodeObjectsById &&
4063
+ this._lastFullResImageSyncSelectionKey === normalizedSelectionKey &&
4064
+ this._lastFullResImageSyncLodBand === lodBand &&
4065
+ visibilityVersion === this._lastFullResImageSyncVisibilityVersion + 1 &&
4066
+ module?._lastVisibilityDiffComplete === true &&
4067
+ Number(module?._lastVisibilityDiffVersion ?? -1) === visibilityVersion;
4068
+ const nextVisibleImageIds = canApplyVisibilityDelta
4069
+ ? new Set(this._fullResImageVisualIds)
4070
+ : new Set();
4071
+ const imageIdsToSync = new Set();
4072
+
4073
+ if (canApplyVisibilityDelta) {
4074
+ for (const nodeIdValue of module._lastVisibilityExitedIds || []) {
4075
+ nextVisibleImageIds.delete(String(nodeIdValue || '').trim());
4076
+ }
4077
+ for (const nodeIdValue of module._lastVisibilityEnteredIds || []) {
4078
+ const nodeId = String(nodeIdValue || '').trim();
4079
+ if (this._addFullResImageVisualIfEligible(nextVisibleImageIds, nodeObjectsById, nodeId)) {
4080
+ imageIdsToSync.add(nodeId);
4081
+ }
4082
+ }
4083
+ } else if (visibleIds?.size > 0) {
4032
4084
  for (const nodeId of visibleIds) {
4033
- this._addFullResImageVisualIfEligible(nextVisibleImageIds, nodeObjectsById, nodeId);
4085
+ if (this._addFullResImageVisualIfEligible(nextVisibleImageIds, nodeObjectsById, nodeId)) {
4086
+ imageIdsToSync.add(nodeId);
4087
+ }
4034
4088
  }
4035
4089
  }
4036
4090
 
4037
- this._addFullResImageVisualIfEligible(nextVisibleImageIds, nodeObjectsById, selectedNodeId);
4038
- if (multiSelectedIds?.forEach) {
4039
- multiSelectedIds.forEach(id => this._addFullResImageVisualIfEligible(nextVisibleImageIds, nodeObjectsById, id));
4040
- }
4041
- this._addFullResImageVisualIfEligible(nextVisibleImageIds, nodeObjectsById, module?.draggedNodeId || null);
4091
+ const addStickyImage = (nodeId) => {
4092
+ if (this._addFullResImageVisualIfEligible(nextVisibleImageIds, nodeObjectsById, nodeId)) {
4093
+ imageIdsToSync.add(String(nodeId || '').trim());
4094
+ } else if (nextVisibleImageIds.has(String(nodeId || '').trim())) {
4095
+ imageIdsToSync.add(String(nodeId || '').trim());
4096
+ }
4097
+ };
4098
+ addStickyImage(selectedNodeId);
4099
+ multiSelectedIds?.forEach?.(addStickyImage);
4100
+ addStickyImage(module?.draggedNodeId || null);
4042
4101
 
4043
- for (const nodeId of nextVisibleImageIds) {
4102
+ for (const nodeId of imageIdsToSync) {
4044
4103
  const entry = nodeObjectsById.get(nodeId);
4045
4104
  if (!entry) continue;
4046
4105
 
@@ -4069,6 +4128,10 @@
4069
4128
  }
4070
4129
 
4071
4130
  this._fullResImageVisualIds = nextVisibleImageIds;
4131
+ this._lastFullResImageSyncVisibilityVersion = visibilityVersion;
4132
+ this._lastFullResImageSyncSelectionKey = normalizedSelectionKey;
4133
+ this._lastFullResImageSyncLodBand = String(lodBand || '');
4134
+ this._lastFullResImageSyncNodeMap = nodeObjectsById;
4072
4135
  this._syncInstancedImageMeshVisibility();
4073
4136
  }
4074
4137
  // ▲▲▲ [New] ▲▲▲
@@ -4216,73 +4279,6 @@
4216
4279
  return currentVisibleIds.has(nodeId);
4217
4280
  }
4218
4281
 
4219
- _buildFullResCssAllowSet(prioritizedVisible, nodeObjectsById, module = this._module, lodBand = this._currentLodBand) {
4220
- const allowedIds = new Set();
4221
-
4222
- const stickyIds = [
4223
- module?.selectedNodeIdJs || null,
4224
- module?.draggedNodeId || null,
4225
- module?._textOverlayV2State?.editing?.nodeId || null,
4226
- module?._editingOverlayState?.nodeId || null,
4227
- module?._textOverlayV2State?.selectionNodeId || null
4228
- ];
4229
- for (const stickyId of stickyIds) {
4230
- const nodeId = String(stickyId || '').trim();
4231
- if (!nodeId) continue;
4232
- const entry = nodeObjectsById?.get?.(nodeId) || null;
4233
- if (entry && supportsCss3dNodeModel(entry.model)) {
4234
- allowedIds.add(nodeId);
4235
- }
4236
- }
4237
-
4238
- const multiSelectedIds = module?.multiSelectedNodeIds || null;
4239
- if (multiSelectedIds?.forEach) {
4240
- multiSelectedIds.forEach((nodeId) => {
4241
- const entry = nodeObjectsById?.get?.(nodeId) || null;
4242
- if (entry && supportsCss3dNodeModel(entry.model)) {
4243
- allowedIds.add(nodeId);
4244
- }
4245
- });
4246
- }
4247
-
4248
- if (!Array.isArray(prioritizedVisible) || prioritizedVisible.length === 0) {
4249
- return allowedIds;
4250
- }
4251
-
4252
- // Full-res NEAR/NORMAL is the readable CSS3D path. Do not drop visible
4253
- // text nodes during pan/zoom/cooldown; otherwise the expanded NORMAL band
4254
- // shows empty cards until the throttled activation queue catches up.
4255
- for (let i = 0; i < prioritizedVisible.length; i++) {
4256
- const nodeId = prioritizedVisible[i]?.nodeId;
4257
- if (!nodeId || allowedIds.has(nodeId)) continue;
4258
- const entry = nodeObjectsById?.get?.(nodeId) || null;
4259
- if (!entry || !supportsCss3dNodeModel(entry.model)) continue;
4260
- allowedIds.add(nodeId);
4261
- }
4262
-
4263
- return allowedIds;
4264
- }
4265
-
4266
- _hasFullResCssReadinessDrift(prioritizedVisible, nodeObjectsById, allowedCssIds) {
4267
- if (!Array.isArray(prioritizedVisible) || prioritizedVisible.length === 0) {
4268
- return false;
4269
- }
4270
-
4271
- for (let i = 0; i < prioritizedVisible.length; i++) {
4272
- const nodeId = prioritizedVisible[i]?.nodeId;
4273
- if (!nodeId || allowedCssIds?.has?.(nodeId) !== true) continue;
4274
-
4275
- const entry = nodeObjectsById?.get?.(nodeId) || null;
4276
- if (!entry || !supportsCss3dNodeModel(entry.model)) continue;
4277
-
4278
- if (this._isFullResCssReady(entry) !== true) {
4279
- return true;
4280
- }
4281
- }
4282
-
4283
- return false;
4284
- }
4285
-
4286
4282
  _reprioritizeNearCss3dQueue(prioritizedVisible, nodeObjectsById, module) {
4287
4283
  this._compactCss3dQueue(true);
4288
4284
  if (this.isInLODMode === true || !this._hasCss3dQueueItems()) {
@@ -4408,155 +4404,6 @@
4408
4404
  }
4409
4405
  }
4410
4406
 
4411
- _restoreCss3dTextSourceForHighDetail(entry) {
4412
- const root = entry?.cssObject?.element || null;
4413
- if (!root) return;
4414
- if (!isTextLikeModel(entry?.model)) return;
4415
-
4416
- const nodeId = String(entry?.model?.id || entry?.model?.Id || entry?.glObject?.userData?.nodeId || '').trim();
4417
- const module = this._module || null;
4418
- const overlayV2 = window.MindMapTextOverlayV2 || null;
4419
- const overlayActive = !!nodeId && (
4420
- overlayV2?.hasSelection?.(module, nodeId) === true ||
4421
- overlayV2?.hasEditing?.(module, nodeId) === true
4422
- );
4423
-
4424
- if (overlayActive) {
4425
- return;
4426
- }
4427
-
4428
- overlayV2?.resumeSource?.(entry);
4429
-
4430
- const clearSuspendedTarget = (target) => {
4431
- if (!target) return;
4432
- target.classList?.remove?.('mind-map-v2-source-suspended');
4433
- target.classList?.remove?.('mind-map-text-overlay-source-suspended');
4434
- target.removeAttribute?.('data-text-overlay-source-suspended');
4435
- if (target.style) {
4436
- target.style.opacity = '';
4437
- target.style.pointerEvents = '';
4438
- target.style.userSelect = '';
4439
- target.style.webkitUserSelect = '';
4440
- target.style.caretColor = '';
4441
- target.style.contentVisibility = '';
4442
- target.style.containIntrinsicSize = '';
4443
- target.style.contain = '';
4444
- }
4445
- };
4446
-
4447
- clearSuspendedTarget(root);
4448
- root.querySelectorAll?.('[data-text-overlay-source-suspended], .mind-map-text-overlay-source-suspended, .mind-map-v2-source-suspended')?.forEach?.(clearSuspendedTarget);
4449
- }
4450
-
4451
- _getCss3dDetailTargets(entry) {
4452
- const root = entry?.cssObject?.element || null;
4453
- if (!root) return [];
4454
-
4455
- const targets = [root];
4456
- const inner = root.querySelector?.('.node-container') || null;
4457
- if (inner && inner !== root) {
4458
- targets.push(inner);
4459
- }
4460
-
4461
- return targets.filter(target => !!target?.classList);
4462
- }
4463
-
4464
- _isCss3dLowDetail(entry) {
4465
- return this._getCss3dDetailTargets(entry)
4466
- .some(target => target.classList.contains('lod-low'));
4467
- }
4468
-
4469
- _isFullResCssReady(entry) {
4470
- const cssObject = entry?.cssObject || null;
4471
- const element = cssObject?.element || null;
4472
- if (!cssObject || !element || cssObject.visible !== true || entry?.currentType !== 'CSS') {
4473
- return false;
4474
- }
4475
-
4476
- if (element.style?.display === 'none' ||
4477
- element.style?.visibility === 'hidden' ||
4478
- element.style?.opacity === '0') {
4479
- return false;
4480
- }
4481
-
4482
- return this._isCss3dLowDetail(entry) !== true;
4483
- }
4484
-
4485
- _setNodeDetailLevel(entry, level) {
4486
- if (!entry?.cssObject?.element) return;
4487
-
4488
- const targets = this._getCss3dDetailTargets(entry);
4489
- if (targets.length === 0) return;
4490
-
4491
- if (level === 'HIGH') {
4492
- for (const target of targets) {
4493
- target.classList.remove('lod-low');
4494
- target.classList.add('lod-high');
4495
- }
4496
- this._restoreCss3dTextSourceForHighDetail(entry);
4497
- } else {
4498
- for (const target of targets) {
4499
- target.classList.remove('lod-high');
4500
- target.classList.add('lod-low');
4501
- }
4502
- }
4503
- }
4504
-
4505
- _setCss3dLodClass(entry, isHigh) {
4506
- this._setNodeDetailLevel(entry, isHigh ? 'HIGH' : 'LOW');
4507
- if (getNodeContentType(entry?.model) === 'video' &&
4508
- window.MindMapCss3DManager?.syncCss3dVideoLodMediaSource) {
4509
- window.MindMapCss3DManager.syncCss3dVideoLodMediaSource(entry.model, entry.cssObject, isHigh === true);
4510
- }
4511
- }
4512
-
4513
- _restoreVisibleCss3dHighDetailForNear(nodeObjectsById, module, lodBand) {
4514
- // Full-res: NEAR / NORMAL. MID/FAR use resident instances.
4515
- if ((lodBand !== 'NEAR' && lodBand !== 'NORMAL') || !nodeObjectsById) {
4516
- return 0;
4517
- }
4518
-
4519
- let restoredCount = 0;
4520
- for (const entry of nodeObjectsById.values()) {
4521
- const cssElement = entry?.cssObject?.element || null;
4522
- const nodeId = String(entry?.model?.id || entry?.model?.Id || entry?.glObject?.userData?.nodeId || '').trim();
4523
- const isRecordedVisible = !!nodeId && this._nearCssVisibleIds.has(nodeId);
4524
- if (!cssElement ||
4525
- (entry.cssObject?.visible !== true && !isRecordedVisible) ||
4526
- (cssElement.style.display === 'none' && !isRecordedVisible) ||
4527
- this._isCss3dLowDetail(entry) !== true) {
4528
- continue;
4529
- }
4530
-
4531
- this._setCss3dLodClass(entry, true);
4532
- restoredCount++;
4533
- }
4534
-
4535
- if (restoredCount > 0 && module) {
4536
- module._css3dVisualChangedThisFrame = true;
4537
- module._css3dVisualChangedSinceLastRender = true;
4538
- }
4539
-
4540
- return restoredCount;
4541
- }
4542
-
4543
- _shouldUseHighCss3dDetail(entry, module) {
4544
- const cameraZ = Number(module?.camera?.position?.z || 0);
4545
- const cameraBand = getLodBandForCameraZ(cameraZ);
4546
- if (cameraBand === 'NEAR' || cameraBand === 'NORMAL') {
4547
- return true;
4548
- }
4549
-
4550
- const lodBand = this._currentLodBand || cameraBand;
4551
- const nodeId = String(entry?.model?.id || entry?.model?.Id || entry?.glObject?.userData?.nodeId || '').trim();
4552
- const selectedNodeId = String(module?.selectedNodeIdJs || module?.selectedNodeId || '').trim();
4553
- if (nodeId && selectedNodeId && nodeId === selectedNodeId) {
4554
- return true;
4555
- }
4556
-
4557
- return false;
4558
- }
4559
-
4560
4407
  _shouldKeepMountedEmbedResident(entry) {
4561
4408
  return getNodeContentType(entry?.model) === 'embed' &&
4562
4409
  window.MindMapCss3DManager?.hasMountedEmbedIframe?.(entry.cssObject) === true;
@@ -4564,6 +4411,7 @@
4564
4411
 
4565
4412
  _detachCss3dObject(entry) {
4566
4413
  if (!entry?.cssObject) return;
4414
+ this._clearFullResCssFringePrepared(entry);
4567
4415
  if (getNodeContentType(entry?.model) === 'video' &&
4568
4416
  window.MindMapCss3DManager?.syncVideoNodeVisibilityPlayback) {
4569
4417
  window.MindMapCss3DManager.syncVideoNodeVisibilityPlayback(entry.model, entry.cssObject, false);
@@ -4655,6 +4503,7 @@
4655
4503
  }
4656
4504
 
4657
4505
  entry.cssObject = cssObject;
4506
+ entry._css3dDetailTargetCache = null;
4658
4507
  window.MindMapRenderPlan?.cachePreparedResidentCss?.(this, entry, module, module.nodeObjectsById);
4659
4508
  return true;
4660
4509
  }
@@ -4810,11 +4659,16 @@
4810
4659
  isHighDetail: shouldUseHighCss3dDetail,
4811
4660
  allowResident: isLivePortalCssLodModel(model)
4812
4661
  }) === true) return;
4662
+ if (this._promoteFullResCssFringePrepared(entry) !== true) {
4663
+ this._clearFullResCssFringePrepared(entry);
4664
+ if (entry.cssObject?.userData) delete entry.cssObject.userData._fullResFringeCreated;
4665
+ }
4813
4666
 
4814
4667
  // Create if not exists
4815
4668
  if (!entry.cssObject) {
4816
4669
  entry.cssObject = window.MindMapCss3DManager.createCss3dObject(module, model);
4817
4670
  if (entry.cssObject) {
4671
+ entry._css3dDetailTargetCache = null;
4818
4672
  const glPos = entry.glObject?.position;
4819
4673
  if (glPos) entry.cssObject.position.copy(glPos);
4820
4674
  cssParentScene?.add(entry.cssObject);
@@ -4862,6 +4716,7 @@
4862
4716
  !cssMediaEl.getAttribute('src') &&
4863
4717
  isLowDetailVideoProxy !== true;
4864
4718
  if ((entry.isCssDirty || needsInitialMediaSync) && window.MindMapCss3DManager?.syncCss3dContent) {
4719
+ entry._css3dDetailTargetCache = null;
4865
4720
  window.MindMapCss3DManager.syncCss3dContent(model, entry.cssObject);
4866
4721
  entry.isCssDirty = false; // sync 완료 후 clean
4867
4722
  }
@@ -5435,7 +5290,12 @@
5435
5290
  const obj = entry.glObject || entry.cssObject;
5436
5291
  if (!obj) continue;
5437
5292
 
5438
- buffer.push({ nodeId });
5293
+ let record = this._nearPriorityRecordById.get(nodeId);
5294
+ if (!record) {
5295
+ record = { nodeId };
5296
+ this._nearPriorityRecordById.set(nodeId, record);
5297
+ }
5298
+ buffer.push(record);
5439
5299
  }
5440
5300
 
5441
5301
  if (buffer.length === visibleIds.size) {
@@ -5463,7 +5323,16 @@
5463
5323
  const hasCssPenalty = entry.cssObject ? 0 : 1; // existing CSS first within the same content tier
5464
5324
  const mediaPriority = isImageLodProxyModel(entry.model) ? 0 : 1;
5465
5325
 
5466
- buffer.push({ nodeId, textPriority, hasCssPenalty, mediaPriority, distSq });
5326
+ let record = this._nearPriorityRecordById.get(nodeId);
5327
+ if (!record) {
5328
+ record = { nodeId };
5329
+ this._nearPriorityRecordById.set(nodeId, record);
5330
+ }
5331
+ record.textPriority = textPriority;
5332
+ record.hasCssPenalty = hasCssPenalty;
5333
+ record.mediaPriority = mediaPriority;
5334
+ record.distSq = distSq;
5335
+ buffer.push(record);
5467
5336
  }
5468
5337
 
5469
5338
  buffer.sort((a, b) => {
@@ -5786,6 +5655,9 @@
5786
5655
  }
5787
5656
 
5788
5657
  if (modeChanged) {
5658
+ if (shouldUseLOD) {
5659
+ this._cancelFullResCssFringePrewarm(nodeObjectsById, true);
5660
+ }
5789
5661
  const transitionPlan = window.MindMapRenderPlan;
5790
5662
  transitionPlan?.beginResidentCssTransition?.(
5791
5663
  this, module, nodeObjectsById, previousLodBand, lodBand, lodSelectionKey);
@@ -5805,6 +5677,9 @@
5805
5677
  }
5806
5678
  this._fullResMotionHiddenGlIds.clear();
5807
5679
  this._currentLodBand = lodBand;
5680
+ this._lastFullResCssAllowVisibilityVersion = -1;
5681
+ this._lastFullResReadinessVisibilityVersion = -1;
5682
+ this._fullResCssPendingReadyIds.clear();
5808
5683
  transitionPlan?.ensureResidentLineDetails?.(this, lodBand);
5809
5684
  if (this.instancedHaloMesh) this.instancedHaloMesh.visible = shouldShowInstancedHaloInLodBand(lodBand);
5810
5685
  this.instancedMesh.visible = true;
@@ -6030,8 +5905,10 @@
6030
5905
  });
6031
5906
 
6032
5907
  const prioritizedVisible = this._getNearVisiblePriority(visibleIds, nodeObjectsById, camera);
6033
- const allowedCssIds = this._buildFullResCssAllowSet(prioritizedVisible, nodeObjectsById, module, lodBand);
6034
- const cssReadinessDrift = this._hasFullResCssReadinessDrift(prioritizedVisible, nodeObjectsById, allowedCssIds);
5908
+ const allowedCssIds = this._buildFullResCssAllowSet(
5909
+ prioritizedVisible, nodeObjectsById, module, lodBand, lodSelectionKey);
5910
+ const cssReadinessDrift = this._hasFullResCssReadinessDrift(
5911
+ prioritizedVisible, nodeObjectsById, allowedCssIds, module, lodSelectionKey);
6035
5912
  this._activeFullResCssNodeIds = allowedCssIds;
6036
5913
 
6037
5914
  if (bandChangedWithoutModeSwitch) {
@@ -6052,6 +5929,7 @@
6052
5929
  }
6053
5930
  for (const nodeId of staleIds) {
6054
5931
  this._css3dQueuedMap.delete(nodeId);
5932
+ this._fullResCssPendingReadyIds.delete(nodeId);
6055
5933
  const entry = nodeObjectsById.get(nodeId);
6056
5934
  if (entry) {
6057
5935
  this._hideNodeCss3d(entry);
@@ -6066,6 +5944,7 @@
6066
5944
  this._applyFullResCssMotionOptimization(nodeObjectsById, module, lodBand);
6067
5945
  });
6068
5946
 
5947
+ const nearCssNoWorkKey = renderPlan?.buildFullResKey(lodBand, visibilityVersion, lodSelectionKey, nodeObjectsById.size, visibleIds.size, this._nearCssVisibleIds.size, allowedCssIds.size, css3dEnabled, module, this);
6069
5948
  if (module?._fullResMotionFrozen === true) {
6070
5949
  if (this._fullResHandoffActive === true) {
6071
5950
  this._fullResHandoffUntil = Math.max(
@@ -6077,11 +5956,11 @@
6077
5956
  if (this._hasCss3dQueueItems()) {
6078
5957
  this._requestCss3dQueueProcess(module, true);
6079
5958
  }
6080
- this._lastNearCssNoWorkKey = '';
5959
+ renderPlan?.recordStableFullRes?.(
5960
+ this, module, nearCssNoWorkKey, bandChangedWithoutModeSwitch, cssReadinessDrift);
6081
5961
  return;
6082
5962
  }
6083
5963
 
6084
- const nearCssNoWorkKey = renderPlan?.buildFullResKey(lodBand, visibilityVersion, lodSelectionKey, nodeObjectsById.size, visibleIds.size, this._nearCssVisibleIds.size, allowedCssIds.size, css3dEnabled, module, this);
6085
5964
  if (renderPlan?.commitStableFullRes(this, module, nearCssNoWorkKey, bandChangedWithoutModeSwitch, cssReadinessDrift)) return;
6086
5965
 
6087
5966
  let hasNearCssWork =
@@ -6164,6 +6043,9 @@
6164
6043
  this, entry, module, nodeObjectsById, lodSelectionKey, lodBand, nodeId) !== true) {
6165
6044
  this._showNodeCss3d(entry, module);
6166
6045
  }
6046
+ if (this._isFullResCssReady(entry)) {
6047
+ this._fullResCssPendingReadyIds.delete(nodeId);
6048
+ }
6167
6049
  processedCount++;
6168
6050
  }
6169
6051
  renderPlan?.completeFullResTransition?.(this, allowedCssIds.size);
@@ -9505,12 +9387,25 @@
9505
9387
  this.lineDataCache.clear();
9506
9388
  this.lineDataArray.fill(0);
9507
9389
  this._nearCssVisibleIds.clear();
9390
+ this._activeFullResCssNodeIds.clear();
9391
+ this._fullResCssPendingReadyIds.clear();
9392
+ this._lastFullResCssAllowVisibilityVersion = -1;
9393
+ this._lastFullResCssAllowSelectionKey = '';
9394
+ this._lastFullResCssAllowNodeMap = null;
9395
+ this._lastFullResReadinessVisibilityVersion = -1;
9396
+ this._lastFullResReadinessSelectionKey = '';
9397
+ this._lastFullResReadinessNodeMap = null;
9508
9398
  this._lodConsoleProxyNodeIds.clear();
9509
9399
  this._lodImageCssFallbackNodeIds.clear();
9510
9400
  this._lodTemplateCssNodeIds.clear();
9511
9401
  this._clearCss3dQueue();
9512
9402
  this._clearCss3dPrewarmQueue();
9513
9403
  this._css3dProcessing = false;
9404
+ if (this._fullResCssFringePrewarmState?.retryTimer) {
9405
+ clearTimeout(this._fullResCssFringePrewarmState.retryTimer);
9406
+ }
9407
+ this._fullResCssFringePrewarmState = null;
9408
+ this._fullResCssFringePrewarmCandidateCount = 0;
9514
9409
  this._visibilityKeys = [];
9515
9410
  this._visibilityKeysDirty = true;
9516
9411
  this._visibilityCursor = 0;
@@ -9538,8 +9433,13 @@
9538
9433
  this._lastBlockedResidentRebuildReason = '';
9539
9434
  this._lastBlockedResidentRebuildAt = 0;
9540
9435
  this._nearPriorityBuffer = [];
9436
+ this._nearPriorityRecordById.clear();
9541
9437
  this._nearEntryBoostFrames = 0;
9542
9438
  this._fullResImageVisualIds?.clear?.();
9439
+ this._lastFullResImageSyncVisibilityVersion = -1;
9440
+ this._lastFullResImageSyncSelectionKey = '';
9441
+ this._lastFullResImageSyncLodBand = '';
9442
+ this._lastFullResImageSyncNodeMap = null;
9543
9443
  this._pendingSelectionRefreshIds.clear();
9544
9444
  if (this._idleRebuildTimer) {
9545
9445
  clearTimeout(this._idleRebuildTimer);
@@ -9621,6 +9521,7 @@
9621
9521
  if (!entry) return;
9622
9522
 
9623
9523
  if (entry.cssObject) {
9524
+ this._clearFullResCssFringePrepared(entry);
9624
9525
  entry.cssObject.visible = false;
9625
9526
  if (entry.cssObject.parent) {
9626
9527
  entry.cssObject.parent.remove(entry.cssObject);
@@ -9648,6 +9549,7 @@
9648
9549
  this._setGlowVisibility(entry, false);
9649
9550
  });
9650
9551
  }
9552
+ this._fullResCssFringePreparedIds.clear();
9651
9553
 
9652
9554
  if (this.instancedHaloMesh) this.instancedHaloMesh.visible = false;
9653
9555
  if (this.instancedMesh) this.instancedMesh.visible = false;
@@ -9706,10 +9608,14 @@
9706
9608
  this._css3dPrewarmQueuedIds?.delete?.(nodeId);
9707
9609
  this._warmCss3dNodeIds?.delete?.(nodeId);
9708
9610
  this._nearCssVisibleIds?.delete?.(nodeId);
9611
+ this._activeFullResCssNodeIds?.delete?.(nodeId);
9612
+ this._fullResCssPendingReadyIds?.delete?.(nodeId);
9709
9613
  this._fullResImageVisualIds?.delete?.(nodeId);
9614
+ this._nearPriorityRecordById?.delete?.(nodeId);
9710
9615
  this._lodConsoleProxyNodeIds?.delete?.(nodeId);
9711
9616
  this._lodImageCssFallbackNodeIds?.delete?.(nodeId);
9712
9617
  this._lodTemplateCssNodeIds?.delete?.(nodeId);
9618
+ this._fullResCssFringePreparedIds?.delete?.(nodeId);
9713
9619
  removedAny = true;
9714
9620
  }
9715
9621
 
@@ -10238,6 +10144,8 @@
10238
10144
  }
10239
10145
 
10240
10146
  dispose() {
10147
+ this._disposed = true;
10148
+ this._cancelFullResCssFringePrewarm(this._module?.nodeObjectsById, true);
10241
10149
  this.textureArrays.forEach(arr => arr.texture.dispose());
10242
10150
  if (this.instancedHaloMesh) {
10243
10151
  this.instancedHaloMesh.material.dispose();
@@ -10310,7 +10218,19 @@
10310
10218
  // Export
10311
10219
  // ═══════════════════════════════════════════════════════════════════════════
10312
10220
 
10313
- window.LODRenderer = LODRenderer;
10221
+ const normalBoundaryOptimizer = window.MindMapNormalBoundaryOptimizer;
10222
+ if (!normalBoundaryOptimizer?.install?.(LODRenderer.prototype, {
10223
+ supportsCss3dNodeModel,
10224
+ isTextLikeModel,
10225
+ isLivePortalCssLodModel,
10226
+ hasAgentConsoleOpenForEntry,
10227
+ getNodeContentType,
10228
+ getLodBandForCameraZ
10229
+ })) {
10230
+ throw new Error('[LODRenderer] Normal boundary optimizer module is unavailable.');
10231
+ }
10232
+
10233
+ window.LODRenderer = LODRenderer;
10314
10234
 
10315
10235
  // Export constants for external use
10316
10236
  window.LODRenderer.THUMBNAIL_SIZE = THUMBNAIL_SIZE;