@mindexec/cli 0.2.478 → 0.2.479

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 (146) hide show
  1. package/README.md +323 -323
  2. package/codex-model-catalog.js +202 -202
  3. package/codex-runtime.js +1608 -1608
  4. package/desktop-workspace-state.cjs +120 -120
  5. package/electron/main.cjs +517 -517
  6. package/electron/preload.cjs +17 -17
  7. package/electron/recurring-update-owner-smoke.mjs +55 -55
  8. package/electron/recurring-update-owner.cjs +97 -97
  9. package/electron/source-smoke.mjs +108 -108
  10. package/electron/update-feed-resolver.cjs +79 -79
  11. package/electron/update-feed.json +10 -10
  12. package/electron/update-manager-smoke.mjs +146 -146
  13. package/electron/update-manager.cjs +297 -297
  14. package/electron/windows-package-smoke.mjs +156 -156
  15. package/launch-bridge.cjs +236 -236
  16. package/lzo1x.js +110 -110
  17. package/mode4-atlas-worker.js +440 -440
  18. package/mode4-atlas.js +130 -130
  19. package/package.json +1 -1
  20. package/port-guard.cjs +285 -285
  21. package/remote-fast/osx-arm64/MacScreenCaptureKitH264.swift +339 -339
  22. package/remote-fast/osx-arm64/MacSystemAudioCapture.swift +214 -214
  23. package/remote-fast/osx-arm64/UnixRawCaptureHelper.mjs +80 -80
  24. package/remote-fast/osx-arm64/livedesk-raw-capture-resampler.mjs +73 -73
  25. package/remote-fast/osx-arm64/mindexec-remote-fast.dll +0 -0
  26. package/remote-fast/osx-x64/MacScreenCaptureKitH264.swift +339 -339
  27. package/remote-fast/osx-x64/MacSystemAudioCapture.swift +214 -214
  28. package/remote-fast/osx-x64/UnixRawCaptureHelper.mjs +80 -80
  29. package/remote-fast/osx-x64/livedesk-raw-capture-resampler.mjs +73 -73
  30. package/remote-fast/osx-x64/mindexec-remote-fast.dll +0 -0
  31. package/remote-fast/win-x64/mindexec-remote-fast.dll +0 -0
  32. package/remote-hub.js +3698 -3698
  33. package/scripts/auth-session-smoke.mjs +262 -262
  34. package/scripts/board-render-ownership-smoke.mjs +85 -85
  35. package/scripts/codex-model-catalog-smoke.mjs +150 -150
  36. package/scripts/codex-runtime-home-smoke.mjs +58 -58
  37. package/scripts/codex-sdk-image-live-smoke.mjs +43 -43
  38. package/scripts/codex-sdk-image-runtime-smoke.mjs +122 -122
  39. package/scripts/codex-sdk-runtime-smoke.mjs +89 -89
  40. package/scripts/desktop-update-publisher-smoke.mjs +89 -89
  41. package/scripts/desktop-update-worker-smoke.mjs +72 -72
  42. package/scripts/desktop-workspace-state-smoke.mjs +81 -81
  43. package/scripts/drive-installed-update-smoke.mjs +67 -67
  44. package/scripts/npm-fresh-install-smoke.mjs +216 -216
  45. package/scripts/publish-mindexec-desktop-updates.mjs +224 -224
  46. package/scripts/remote-agent-managed-smoke.mjs +318 -318
  47. package/scripts/remote-agent-package-smoke.mjs +64 -64
  48. package/scripts/remote-agent-ws-smoke.mjs +269 -269
  49. package/scripts/remote-fast-live-rate-smoke.mjs +343 -343
  50. package/scripts/remote-fast-mdm-browser-smoke.mjs +453 -453
  51. package/scripts/remote-fleet-render-smoke.mjs +1350 -1350
  52. package/scripts/remote-frame-ws-smoke.mjs +234 -234
  53. package/scripts/remote-http-smoke.mjs +592 -592
  54. package/scripts/remote-hub-identity-smoke.mjs +146 -146
  55. package/scripts/remote-hub-scale-smoke.mjs +124 -124
  56. package/scripts/remote-hub-smoke.mjs +699 -699
  57. package/scripts/remote-input-ws-smoke.mjs +263 -263
  58. package/scripts/remote-registry-follower-smoke.mjs +815 -815
  59. package/scripts/setup-tree-sitter-grammars.mjs +59 -59
  60. package/server.js +7510 -7510
  61. package/start-bridge.bat +32 -32
  62. package/start-bridge.sh +81 -81
  63. package/tree-sitter-grammars/README.md +18 -0
  64. package/tree-sitter-grammars/tree-sitter-c_sharp.wasm +0 -0
  65. package/tree-sitter-grammars/tree-sitter-go.wasm +0 -0
  66. package/tree-sitter-grammars/tree-sitter-java.wasm +0 -0
  67. package/tree-sitter-grammars/tree-sitter-javascript.wasm +0 -0
  68. package/tree-sitter-grammars/tree-sitter-python.wasm +0 -0
  69. package/tree-sitter-grammars/tree-sitter-rust.wasm +0 -0
  70. package/tree-sitter-grammars/tree-sitter-tsx.wasm +0 -0
  71. package/tree-sitter-grammars/tree-sitter-typescript.wasm +0 -0
  72. package/wwwroot/_content/MindExecution.Plugins.Admin/css/admin-dashboard.css +546 -546
  73. package/wwwroot/_content/MindExecution.Plugins.Directory/background.png +0 -0
  74. package/wwwroot/_content/MindExecution.Plugins.YouTube/css/youtube-search.css +251 -251
  75. package/wwwroot/_content/MindExecution.Shared/css/mind-map-overrides.css +3789 -3789
  76. package/wwwroot/_content/MindExecution.Shared/fonts/NotoSansKR-Bold.ttf +0 -0
  77. package/wwwroot/_content/MindExecution.Shared/fonts/NotoSansKR-Regular.ttf +0 -0
  78. package/wwwroot/_content/MindExecution.Shared/js/agent-visualization.js +27 -27
  79. package/wwwroot/_content/MindExecution.Shared/js/background-themes.js +1449 -1449
  80. package/wwwroot/_content/MindExecution.Shared/js/code-master.js +8316 -8316
  81. package/wwwroot/_content/MindExecution.Shared/js/file-system-helper.js +338 -338
  82. package/wwwroot/_content/MindExecution.Shared/js/marked.min.js +69 -69
  83. package/wwwroot/_content/MindExecution.Shared/js/mind-map-animated-image-preview.js +270 -270
  84. package/wwwroot/_content/MindExecution.Shared/js/mind-map-automation-edge-motion.js +170 -170
  85. package/wwwroot/_content/MindExecution.Shared/js/mind-map-board-render-ownership.js +81 -81
  86. package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js +10506 -10506
  87. package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js.backup +1059 -0
  88. package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-hotpath.js +902 -902
  89. package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +24637 -24637
  90. package/wwwroot/_content/MindExecution.Shared/js/mind-map-dev-guards.js +325 -325
  91. package/wwwroot/_content/MindExecution.Shared/js/mind-map-dnd.js +1491 -1491
  92. package/wwwroot/_content/MindExecution.Shared/js/mind-map-dnd.js.bak +434 -0
  93. package/wwwroot/_content/MindExecution.Shared/js/mind-map-glow-shader.js +70 -70
  94. package/wwwroot/_content/MindExecution.Shared/js/mind-map-image-policy.js +218 -218
  95. package/wwwroot/_content/MindExecution.Shared/js/mind-map-interactions.js +7078 -7078
  96. package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-plan-worker.js +160 -160
  97. package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-renderer.js +9958 -9958
  98. package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-video-placeholder.js +107 -107
  99. package/wwwroot/_content/MindExecution.Shared/js/mind-map-logic-workers.js +1004 -1004
  100. package/wwwroot/_content/MindExecution.Shared/js/mind-map-menu-manager.js +1351 -1351
  101. package/wwwroot/_content/MindExecution.Shared/js/mind-map-multi-select.js +865 -865
  102. package/wwwroot/_content/MindExecution.Shared/js/mind-map-node-search-worker.js +554 -554
  103. package/wwwroot/_content/MindExecution.Shared/js/mind-map-nodes.js +4744 -4744
  104. package/wwwroot/_content/MindExecution.Shared/js/mind-map-normal-boundary-optimizer.js +624 -624
  105. package/wwwroot/_content/MindExecution.Shared/js/mind-map-object-manager.js +241 -241
  106. package/wwwroot/_content/MindExecution.Shared/js/mind-map-object-manager.js.backup +372 -0
  107. package/wwwroot/_content/MindExecution.Shared/js/mind-map-pipeline.js +2290 -2290
  108. package/wwwroot/_content/MindExecution.Shared/js/mind-map-remote-codecs.js +202 -202
  109. package/wwwroot/_content/MindExecution.Shared/js/mind-map-render-plan.js +1971 -1971
  110. package/wwwroot/_content/MindExecution.Shared/js/mind-map-text-lod-system.js +93 -93
  111. package/wwwroot/_content/MindExecution.Shared/js/mind-map-texture-factory.js +2391 -2391
  112. package/wwwroot/_content/MindExecution.Shared/js/mind-map-texture-factory.js.backup +1258 -0
  113. package/wwwroot/_content/MindExecution.Shared/js/mind-map-video-playback-controls.js +95 -95
  114. package/wwwroot/_content/MindExecution.Shared/js/mind-map-visibility-worker.js +895 -895
  115. package/wwwroot/_content/MindExecution.Shared/js/mindmap-toolbar.js +636 -636
  116. package/wwwroot/_content/MindExecution.Shared/js/native-drop-handler.js +45 -45
  117. package/wwwroot/_content/MindExecution.Shared/js/plan-master.js +117 -117
  118. package/wwwroot/_content/MindExecution.Shared/js/renderers/CSS3DRenderer.js +114 -114
  119. package/wwwroot/_content/MindExecution.Shared/js/texture-worker-manager.js +10 -10
  120. package/wwwroot/_content/MindExecution.Shared/js/three.min.js +6 -6
  121. package/wwwroot/_content/MindExecution.Shared/js/token-manager.js +7 -7
  122. package/wwwroot/_content/MindExecution.Shared/js/troika-bundle.js +6 -6
  123. package/wwwroot/_content/MindExecution.Shared/js/troika-bundle.js.map +2 -2
  124. package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/css/all.min.css +8 -8
  125. package/wwwroot/_content/MindExecution.Shared/models/vocab.txt +30522 -30522
  126. package/wwwroot/_framework/{Google.Protobuf.33g2gb5is0.dll → Google.Protobuf.9h59ukbel7.dll} +0 -0
  127. package/wwwroot/_framework/{MindExecution.Core.z100xo4mg0.dll → MindExecution.Core.xxsj2s456b.dll} +0 -0
  128. package/wwwroot/_framework/{MindExecution.Kernel.i9cldrx8yc.dll → MindExecution.Kernel.5jofnc0wrd.dll} +0 -0
  129. package/wwwroot/_framework/{MindExecution.Plugins.Admin.48lzqddb0a.dll → MindExecution.Plugins.Admin.t7m4jnqjg3.dll} +0 -0
  130. package/wwwroot/_framework/{MindExecution.Plugins.Business.7m8u1q142p.dll → MindExecution.Plugins.Business.6yjlhhavap.dll} +0 -0
  131. package/wwwroot/_framework/{MindExecution.Plugins.Concept.cl5wmr53od.dll → MindExecution.Plugins.Concept.iikqq5zxu0.dll} +0 -0
  132. package/wwwroot/_framework/{MindExecution.Plugins.Directory.slipi39041.dll → MindExecution.Plugins.Directory.c5ribyne4m.dll} +0 -0
  133. package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.qfge05l671.dll → MindExecution.Plugins.PlanMaster.365bbuifr9.dll} +0 -0
  134. package/wwwroot/_framework/{MindExecution.Plugins.YouTube.tn7v29ut77.dll → MindExecution.Plugins.YouTube.ax415cilpk.dll} +0 -0
  135. package/wwwroot/_framework/MindExecution.Shared.21e2nvf86u.dll +0 -0
  136. package/wwwroot/_framework/{MindExecution.Web.rwawrxxk38.dll → MindExecution.Web.ppgm8rey59.dll} +0 -0
  137. package/wwwroot/_framework/{System.Collections.23yxgetbju.dll → System.Collections.zyvbaq6mpd.dll} +0 -0
  138. package/wwwroot/_framework/blazor.boot.json +25 -25
  139. package/wwwroot/_headers +40 -40
  140. package/wwwroot/_redirects +1 -1
  141. package/wwwroot/index.html +772 -772
  142. package/wwwroot/js/marketing-tool.js +180 -180
  143. package/wwwroot/manifest.webmanifest +23 -23
  144. package/wwwroot/service-worker-assets.js +109 -81
  145. package/wwwroot/service-worker.js +33 -33
  146. package/wwwroot/_framework/MindExecution.Shared.rjqlf0umjn.dll +0 -0
@@ -1,1971 +1,1971 @@
1
- (function () {
2
- 'use strict';
3
-
4
- const BUILD_ID = '20260817-grid-distance-fade-v45';
5
- const FRAME_SAMPLE_LIMIT = 240;
6
- const INITIAL_LINE_TEXTURE_ROWS = 1024;
7
- const GPU_WARM_RETRY_DELAY_MS = 120;
8
- const IMAGE_ATLAS_TILE_SIZE = 128;
9
- const IMAGE_ATLAS_UPLOAD_SETTLE_MS = 1000;
10
- const IMAGE_ATLAS_UPLOAD_MAX_WAIT_MS = 3500;
11
- const LOCAL_SNAP_GRID_FADE_START_Z = 9000;
12
- const LOCAL_SNAP_GRID_FADE_END_Z = 30000;
13
- const frameSampleStates = new WeakMap();
14
- const residentLinePrewarmStates = new WeakMap();
15
- const residentTransitionStates = new WeakMap();
16
- const cssMediaFrameDomStates = new WeakMap();
17
- const imageAtlasUploadStates = new WeakMap();
18
- let cssMediaFrameDomReuseCount = 0;
19
- let cssMediaFrameDomApplyCount = 0;
20
- const RESIDENT_CSS_CACHE_TEXT_TYPES = new Set(['text', 'note', 'memo', 'markdown', 'code', 'csv-table']);
21
- const VIEW_SYNC_SECTION_KEYS = [
22
- 'fullResSetup', 'fullResImages', 'fullResCssQueue', 'fullResHandoff', 'fullResOther',
23
- 'lodCleanup', 'lodNodeScan', 'lodResidentApply', 'lodLinePatch', 'lodImageInstances',
24
- 'lodPositionPatch', 'lodFallbacks', 'lodOther'
25
- ];
26
- const CAMERA_ONLY_WEBGL_BLOCKERS = Object.freeze({
27
- NotCameraOnly: 1 << 0,
28
- Css3dCameraPathUnavailable: 1 << 1,
29
- WebglDisabled: 1 << 2,
30
- BoardLoading: 1 << 3,
31
- ResidentLod: 1 << 4,
32
- NonCameraUpdate: 1 << 5,
33
- ThemeAnimation: 1 << 6,
34
- WebglTheme: 1 << 7,
35
- CssCoverageIncomplete: 1 << 8,
36
- FullResHandoff: 1 << 9,
37
- ResidentMeshVisible: 1 << 10,
38
- ImageVisual: 1 << 11,
39
- AnimatedImageStatus: 1 << 12,
40
- CursorVisual: 1 << 13,
41
- DebugVisual: 1 << 14,
42
- FullResGlVisual: 1 << 15
43
- });
44
- const CAMERA_ONLY_WEBGL_BLOCKER_NAMES = Object.freeze([
45
- [CAMERA_ONLY_WEBGL_BLOCKERS.NotCameraOnly, 'not-camera-only'],
46
- [CAMERA_ONLY_WEBGL_BLOCKERS.Css3dCameraPathUnavailable, 'css3d-camera-path-unavailable'],
47
- [CAMERA_ONLY_WEBGL_BLOCKERS.WebglDisabled, 'webgl-disabled'],
48
- [CAMERA_ONLY_WEBGL_BLOCKERS.BoardLoading, 'board-loading'],
49
- [CAMERA_ONLY_WEBGL_BLOCKERS.ResidentLod, 'resident-lod'],
50
- [CAMERA_ONLY_WEBGL_BLOCKERS.NonCameraUpdate, 'non-camera-update'],
51
- [CAMERA_ONLY_WEBGL_BLOCKERS.ThemeAnimation, 'theme-animation'],
52
- [CAMERA_ONLY_WEBGL_BLOCKERS.WebglTheme, 'webgl-theme'],
53
- [CAMERA_ONLY_WEBGL_BLOCKERS.CssCoverageIncomplete, 'css-coverage-incomplete'],
54
- [CAMERA_ONLY_WEBGL_BLOCKERS.FullResHandoff, 'fullres-handoff'],
55
- [CAMERA_ONLY_WEBGL_BLOCKERS.ResidentMeshVisible, 'resident-mesh-visible'],
56
- [CAMERA_ONLY_WEBGL_BLOCKERS.ImageVisual, 'image-visual'],
57
- [CAMERA_ONLY_WEBGL_BLOCKERS.AnimatedImageStatus, 'animated-image-status'],
58
- [CAMERA_ONLY_WEBGL_BLOCKERS.CursorVisual, 'cursor-visual'],
59
- [CAMERA_ONLY_WEBGL_BLOCKERS.DebugVisual, 'debug-visual'],
60
- [CAMERA_ONLY_WEBGL_BLOCKERS.FullResGlVisual, 'fullres-gl-visual']
61
- ]);
62
-
63
- function isWheelOnlyCameraNavigation(module) {
64
- const hasWheelZoom = module?.isZooming === true || module?._wheelZoomBurstActive === true;
65
- if (!hasWheelZoom) return false;
66
- return !(
67
- module?.isPanning === true ||
68
- module?._panSmoothingActive === true ||
69
- module?.isDraggingNode === true ||
70
- module?.isDraggingMultipleNodes === true ||
71
- module?.isResizing === true ||
72
- module?.isWindowResizing === true
73
- );
74
- }
75
-
76
- function getLocalSnapGridDistanceOpacity(cameraZ) {
77
- const parsedCameraZ = Math.abs(Number(cameraZ));
78
- const safeCameraZ = Number.isFinite(parsedCameraZ) ? Math.max(1, parsedCameraZ) : 1;
79
- const baseOpacity = Math.max(
80
- 0.38,
81
- Math.min(0.64, safeCameraZ <= 1800 ? 0.60 : 0.60 - ((safeCameraZ - 1800) / 36000))
82
- );
83
- if (safeCameraZ <= LOCAL_SNAP_GRID_FADE_START_Z) {
84
- return baseOpacity;
85
- }
86
- if (safeCameraZ >= LOCAL_SNAP_GRID_FADE_END_Z) {
87
- return 0;
88
- }
89
-
90
- const fadeProgress = (safeCameraZ - LOCAL_SNAP_GRID_FADE_START_Z) /
91
- (LOCAL_SNAP_GRID_FADE_END_Z - LOCAL_SNAP_GRID_FADE_START_Z);
92
- const smoothProgress = fadeProgress * fadeProgress * (3 - (2 * fadeProgress));
93
- return baseOpacity * (1 - smoothProgress);
94
- }
95
-
96
- function shouldUseInteractiveRendererDpr(module, frameState = null) {
97
- const wheelOnlyCameraNavigation = isWheelOnlyCameraNavigation(module);
98
- return !!(
99
- ((frameState?.isCameraMoving === true || module?._cameraMovingThisFrame === true) &&
100
- !wheelOnlyCameraNavigation) ||
101
- module?.isPanning === true ||
102
- module?._panSmoothingActive === true ||
103
- module?.isDraggingNode === true ||
104
- module?.isDraggingMultipleNodes === true ||
105
- module?.isResizing === true ||
106
- module?.isWindowResizing === true
107
- );
108
- }
109
-
110
- function isRendererDprInteractionActive(module, frameState = null) {
111
- return shouldUseInteractiveRendererDpr(module, frameState) ||
112
- module?.isZooming === true ||
113
- module?._wheelZoomBurstActive === true;
114
- }
115
-
116
- function getCameraOnlyWebglBlockerMask(module, frameState = null) {
117
- const renderer = module?.lodRenderer || null;
118
- let blockers = 0;
119
- if (frameState?.isCameraNavigationOnlyInteractiveFrame !== true) {
120
- blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.NotCameraOnly;
121
- }
122
- if (frameState?.canUseCss3dCameraFastPath !== true) {
123
- blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.Css3dCameraPathUnavailable;
124
- }
125
- if (frameState?.isWebglRenderEnabled !== true) {
126
- blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.WebglDisabled;
127
- }
128
- if (frameState?.isBoardLoading === true) {
129
- blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.BoardLoading;
130
- }
131
- if (frameState?.isInLodMode === true || renderer?.isInLODMode !== false) {
132
- blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.ResidentLod;
133
- }
134
- if (frameState?.hasNonCameraNavigationForcedUpdate === true) {
135
- blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.NonCameraUpdate;
136
- }
137
- if (frameState?.themeAnimatedThisFrame === true || module?._forceThemeAnimationFrame === true) {
138
- blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.ThemeAnimation;
139
- }
140
- if (module?.currentThemeObject?.userData?.localSnapGrid !== true) {
141
- blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.WebglTheme;
142
- }
143
-
144
- const visibleCount = Number(module?._visibleIds?.size || 0);
145
- const nearCssVisibleCount = Number(renderer?._nearCssVisibleIds?.size || 0);
146
- const activeFullResCssCount = Number(renderer?._activeFullResCssNodeIds?.size || 0);
147
- const pendingFullResCssCount = Number(renderer?._fullResCssPendingReadyIds?.size || 0);
148
- const hasCompleteCssCoverage =
149
- nearCssVisibleCount === visibleCount &&
150
- activeFullResCssCount === visibleCount &&
151
- pendingFullResCssCount === 0 &&
152
- (visibleCount === 0 || !!renderer?._lastNearCssNoWorkKey);
153
- if (!hasCompleteCssCoverage) {
154
- blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.CssCoverageIncomplete;
155
- }
156
-
157
- // The full-res motion optimizer owns this cached proof: only CSS-backed,
158
- // unselected text-like nodes enter the set after their whole GL group is
159
- // hidden. Images, media, selected nodes, and open agent consoles remain
160
- // outside it and therefore fail closed without a scene traversal here.
161
- const motionHiddenGlCount = Number(renderer?._fullResMotionHiddenGlIds?.size || 0);
162
- if (motionHiddenGlCount !== visibleCount) {
163
- blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.FullResGlVisual;
164
- }
165
-
166
- const fullResHandoffActive =
167
- renderer?._fullResHandoffActive === true ||
168
- renderer?._hasCss3dQueueItems?.() === true ||
169
- renderer?._css3dProcessing === true;
170
- if (fullResHandoffActive) {
171
- blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.FullResHandoff;
172
- }
173
-
174
- const residentMeshVisible =
175
- renderer?.instancedHaloMesh?.visible === true ||
176
- renderer?.instancedMesh?.visible === true ||
177
- renderer?.instancedBorderLineMesh?.visible === true ||
178
- renderer?.instancedLineMesh?.visible === true ||
179
- renderer?.instancedConsoleMesh?.visible === true ||
180
- renderer?.instancedImageMesh?.visible === true;
181
- if (residentMeshVisible) {
182
- blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.ResidentMeshVisible;
183
- }
184
- if (Number(renderer?._fullResImageVisualIds?.size || 0) > 0) {
185
- blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.ImageVisual;
186
- }
187
- if (Number(module?._activeImageStatusTextures?.size || 0) > 0) {
188
- blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.AnimatedImageStatus;
189
- }
190
- if (module?.cursorMesh?.visible === true) {
191
- blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.CursorVisual;
192
- }
193
- if (Number(module?.debugGroup?.children?.length || 0) > 0) {
194
- blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.DebugVisual;
195
- }
196
- return blockers;
197
- }
198
-
199
- function getCameraOnlyWebglBlockerNames(mask) {
200
- const normalizedMask = Number(mask || 0);
201
- return CAMERA_ONLY_WEBGL_BLOCKER_NAMES
202
- .filter(([flag]) => (normalizedMask & flag) !== 0)
203
- .map(([, name]) => name);
204
- }
205
-
206
- function configureImageAtlasTexture(texture, THREE) {
207
- if (!texture || !THREE) return texture;
208
- if ('colorSpace' in texture && THREE.SRGBColorSpace) texture.colorSpace = THREE.SRGBColorSpace;
209
- else if ('encoding' in texture && THREE.sRGBEncoding) texture.encoding = THREE.sRGBEncoding;
210
- texture.minFilter = THREE.LinearFilter;
211
- texture.magFilter = THREE.LinearFilter;
212
- texture.wrapS = THREE.ClampToEdgeWrapping;
213
- texture.wrapT = THREE.ClampToEdgeWrapping;
214
- texture.flipY = false;
215
- texture.generateMipmaps = false;
216
- texture.needsUpdate = true;
217
- return texture;
218
- }
219
-
220
- function getImageAtlasOutputColorChunk(THREE) {
221
- const chunk = THREE?.ShaderChunk?.colorspace_fragment
222
- ? '#include <colorspace_fragment>'
223
- : (THREE?.ShaderChunk?.encodings_fragment ? '#include <encodings_fragment>' : '');
224
- globalThis.MindCanvasDevGuards?.assert?.(chunk.length > 0,
225
- 'resident-image-output-color-chunk-missing', { threeRevision: String(THREE?.REVISION || 'unknown') });
226
- return chunk;
227
- }
228
-
229
- function syncCommittedResidentTextCount(renderer, hasResidentInstances, forceResident) {
230
- if (forceResident !== true || !hasResidentInstances || renderer?._lodUsesVisibleSubset === true ||
231
- renderer?._instancesDirty === true || renderer?._isNodeArrayDirty === true) return -1;
232
- const count = Number(renderer?.instanceData?.nodeIds?.length || 0);
233
- renderer._cachedEligibleTextLikeCount = count;
234
- renderer._lastNodeCount = count;
235
- return count;
236
- }
237
-
238
- function clearFullResImageVisuals(renderer, nodeObjectsById) {
239
- const tracked = renderer?._fullResImageVisualIds;
240
- if (!tracked) return;
241
- for (const nodeId of tracked) {
242
- const entry = nodeObjectsById?.get?.(nodeId) || null;
243
- if (entry) renderer._hideImageLodFullVisual?.(entry);
244
- }
245
- if (renderer.isInLODMode === true) {
246
- const residentIds = renderer.imageInstanceData?.nodeIds || [];
247
- for (let i = 0; i < residentIds.length; i++) {
248
- const nodeId = residentIds[i];
249
- if (!nodeId || tracked.has(nodeId)) continue;
250
- const entry = nodeObjectsById?.get?.(nodeId) || null;
251
- if (entry) renderer._hideImageLodFullVisual?.(entry);
252
- }
253
- }
254
- tracked.clear();
255
- }
256
-
257
- function isFullResMotionOptimizationActive(module) {
258
- return (module?._viewSyncMotionActive === true ||
259
- module?.isPanning === true ||
260
- module?.isZooming === true ||
261
- module?._fullResMotionFrozen === true) &&
262
- module?.isDraggingNode !== true &&
263
- module?.isDraggingMultipleNodes !== true &&
264
- module?.isResizing !== true &&
265
- module?.isWindowResizing !== true;
266
- }
267
-
268
- function buildFullResKey(
269
- lodBand,
270
- visibilityVersion,
271
- selectionKey,
272
- nodeCount,
273
- visibleCount,
274
- nearVisibleCount,
275
- allowedCssCount,
276
- css3dEnabled,
277
- module,
278
- renderer) {
279
- return [
280
- String(lodBand || ''),
281
- Number(visibilityVersion || 0),
282
- String(selectionKey || ''),
283
- Number(nodeCount || 0),
284
- Number(visibleCount || 0),
285
- Number(nearVisibleCount || 0),
286
- Number(allowedCssCount || 0),
287
- css3dEnabled === false ? 'css3d:off' : 'css3d:on',
288
- String(module?.draggedNodeId || ''),
289
- String(module?._textOverlayV2State?.editing?.nodeId || ''),
290
- String(module?._editingOverlayState?.nodeId || ''),
291
- String(module?._textOverlayV2State?.selectionNodeId || ''),
292
- String(renderer?._getCurrentHoveredNodeId?.(module) || ''),
293
- isFullResMotionOptimizationActive(module) ? 'motion:on' : 'motion:off'
294
- ].join('|');
295
- }
296
-
297
- function hasPendingFullResWork(renderer, module, bandChanged, cssReadinessDrift) {
298
- return !renderer || !module ||
299
- bandChanged === true ||
300
- cssReadinessDrift === true ||
301
- renderer._hasCss3dQueueItems?.() === true ||
302
- Number(renderer._css3dQueuedMap?.size || 0) > 0 ||
303
- renderer._css3dProcessing === true ||
304
- Number(renderer._nearEntryBoostFrames || 0) > 0 ||
305
- renderer._fullResHandoffActive === true ||
306
- module._cssParentRepairNeeded === true ||
307
- module._css3dVisualChangedThisFrame === true ||
308
- module._css3dVisualChangedSinceLastRender === true ||
309
- Number(module._cssTransformDirtyIds?.size || 0) > 0;
310
- }
311
-
312
- function shouldSkipStableFullRes(renderer, module, key, bandChanged) {
313
- const canSkip = !!key &&
314
- renderer?._lastNearCssNoWorkKey === key &&
315
- hasPendingFullResWork(renderer, module, bandChanged, false) !== true;
316
-
317
- if (renderer) {
318
- renderer._lastFullResStablePlanSkipped = canSkip;
319
- if (canSkip) {
320
- renderer._fullResStablePlanSkipCount = Number(renderer._fullResStablePlanSkipCount || 0) + 1;
321
- }
322
- }
323
-
324
- return canSkip;
325
- }
326
-
327
- function commitStableFullRes(renderer, module, key, bandChanged, cssReadinessDrift) {
328
- if (!key || renderer?._lastNearCssNoWorkKey !== key ||
329
- hasPendingFullResWork(renderer, module, bandChanged, cssReadinessDrift)) {
330
- if (renderer) renderer._lastFullResStablePlanSkipped = false;
331
- return false;
332
- }
333
-
334
- renderer._lastNearCssNoWorkKey = key;
335
- renderer._lastFullResStablePlanSkipped = false;
336
- return true;
337
- }
338
-
339
- function recordStableFullRes(renderer, module, key, bandChanged, cssReadinessDrift) {
340
- if (!renderer || !key || hasPendingFullResWork(renderer, module, bandChanged, cssReadinessDrift)) {
341
- if (renderer) renderer._lastNearCssNoWorkKey = '';
342
- return false;
343
- }
344
-
345
- renderer._lastNearCssNoWorkKey = key;
346
- renderer._lastFullResStablePlanSkipped = false;
347
- return true;
348
- }
349
-
350
- function getLineModelSource(model) {
351
- return model?._visibleContent ?? model?.response ?? model?.Response ??
352
- model?.content ?? model?.Content ?? model?.text ?? model?.Text ?? '';
353
- }
354
-
355
- function getPreparedLineData(renderer, entry, width, height) {
356
- const prepared = entry?._lodResidentPreparedLine || null;
357
- const model = entry?.model || null;
358
- const nodeId = model?.id || model?.Id || '';
359
- const element = entry?.cssObject?.element || null;
360
- if (!prepared || !model || !nodeId ||
361
- prepared.data !== renderer?.lineDataCache?.get?.(nodeId) ||
362
- prepared.model !== model ||
363
- prepared.width !== Number(width || 0) ||
364
- prepared.height !== Number(height || 0) ||
365
- prepared.source !== getLineModelSource(model) ||
366
- prepared.prompt !== (model?.prompt ?? model?.Prompt ?? '') ||
367
- prepared.elementClass !== String(element?.className || '') ||
368
- prepared.rootClass !== String(globalThis.document?.documentElement?.className || '') ||
369
- prepared.viewportWidth !== Number(globalThis.innerWidth || 0) ||
370
- prepared.viewportHeight !== Number(globalThis.innerHeight || 0)) {
371
- return null;
372
- }
373
- return prepared.data;
374
- }
375
-
376
- function rememberPreparedLine(renderer, entry, width, height, data) {
377
- const model = entry?.model || null;
378
- const element = entry?.cssObject?.element || null;
379
- if (!model || !data) return data || null;
380
- entry._lodResidentPreparedLine = {
381
- data,
382
- model,
383
- width: Number(width || 0),
384
- height: Number(height || 0),
385
- source: getLineModelSource(model),
386
- prompt: model?.prompt ?? model?.Prompt ?? '',
387
- elementClass: String(element?.className || ''),
388
- rootClass: String(globalThis.document?.documentElement?.className || ''),
389
- viewportWidth: Number(globalThis.innerWidth || 0),
390
- viewportHeight: Number(globalThis.innerHeight || 0)
391
- };
392
- return data;
393
- }
394
-
395
- function resolveResidentLineData(renderer, entry, width, height, allowExact, maxSamples, lineHeight, padding) {
396
- const prepared = getPreparedLineData(renderer, entry, width, height);
397
- if (prepared) return prepared;
398
- const model = entry?.model || null;
399
- if (!renderer || !model) return null;
400
- if (allowExact === true) {
401
- return rememberPreparedLine(renderer, entry, width, height,
402
- renderer._getLineDataForNode?.(model, entry.lodSeed, width, height, entry));
403
- }
404
- renderer._residentLineFallbackUsed = true;
405
- const safeLineHeight = Math.max(1, Number(lineHeight || 1));
406
- const safePadding = Math.max(0, Number(padding || 0));
407
- const maxLines = Math.max(1, Math.min(
408
- Number(maxSamples || 1),
409
- Math.floor(Math.max(safeLineHeight, Number(height || 0) - safePadding * 2) / safeLineHeight)
410
- ));
411
- const fallback = renderer._computeFallbackLineData?.(entry.lodSeed, maxLines) || { lineCount: 0, lineLengths: [] };
412
- return {
413
- lineCount: Number(fallback.lineCount || 0),
414
- lineLengths: fallback.lineLengths || [],
415
- lineHeightPx: safeLineHeight,
416
- paddingX: safePadding,
417
- paddingY: safePadding
418
- };
419
- }
420
-
421
- function isPrewarmInteractionActive(module) {
422
- return module?.isPanning === true || module?.isZooming === true ||
423
- module?._panSmoothingActive === true || module?._viewSyncMotionActive === true ||
424
- module?._cameraMovingThisFrame === true ||
425
- module?.isDraggingNode === true || module?.isDraggingMultipleNodes === true ||
426
- module?.isResizing === true || module?.isWindowResizing === true;
427
- }
428
-
429
- function prepareImageAtlasCapacity(renderer, imageCount) {
430
- if (!renderer?.imageAtlasCanvas || Number(renderer.imageAtlasSlots?.size || 0) > 0) return false;
431
- let columns = 8;
432
- const targetSlots = Math.max(1, Number(imageCount || 0) * 2);
433
- while (columns < 32 && columns * columns < targetSlots) columns *= 2;
434
- const size = columns * IMAGE_ATLAS_TILE_SIZE;
435
- renderer.imageAtlasColumns = columns;
436
- renderer.imageAtlasSize = size;
437
- renderer.imageAtlasMaxSlots = columns * columns;
438
- if (renderer.imageAtlasCanvas.width === size && renderer.imageAtlasCanvas.height === size) return false;
439
- renderer.imageAtlasCanvas.width = size;
440
- renderer.imageAtlasCanvas.height = size;
441
- const context = renderer.imageAtlasCanvas.getContext?.('2d', { alpha: false }) || null;
442
- if (context) {
443
- context.fillStyle = '#eef2f7';
444
- context.fillRect(0, 0, size, size);
445
- }
446
- const THREE = globalThis.THREE;
447
- const previousTexture = renderer.imageAtlasTexture || null;
448
- if (THREE?.CanvasTexture) {
449
- const nextTexture = new THREE.CanvasTexture(renderer.imageAtlasCanvas);
450
- nextTexture.minFilter = previousTexture?.minFilter ?? THREE.LinearFilter;
451
- nextTexture.magFilter = previousTexture?.magFilter ?? THREE.LinearFilter;
452
- nextTexture.wrapS = previousTexture?.wrapS ?? THREE.ClampToEdgeWrapping;
453
- nextTexture.wrapT = previousTexture?.wrapT ?? THREE.ClampToEdgeWrapping;
454
- nextTexture.flipY = previousTexture?.flipY ?? false;
455
- nextTexture.generateMipmaps = previousTexture?.generateMipmaps ?? false;
456
- if ('colorSpace' in nextTexture && previousTexture?.colorSpace) {
457
- nextTexture.colorSpace = previousTexture.colorSpace;
458
- } else if ('encoding' in nextTexture && previousTexture?.encoding != null) {
459
- nextTexture.encoding = previousTexture.encoding;
460
- }
461
- nextTexture.needsUpdate = true;
462
- renderer.imageAtlasTexture = nextTexture;
463
- const atlasUniform = renderer.instancedImageMesh?.material?.uniforms?.uImageAtlas || null;
464
- if (atlasUniform) atlasUniform.value = nextTexture;
465
- previousTexture?.dispose?.();
466
- } else if (previousTexture) {
467
- previousTexture.needsUpdate = true;
468
- }
469
- renderer._residentGpuWarmKey = '';
470
- renderer._residentGpuWarmOffscreenComplete = false;
471
- renderer._residentImageAtlasWarmVersion = -1;
472
- return true;
473
- }
474
-
475
- function prepareImageAtlasForEntries(renderer, entries) {
476
- let imageCount = 0;
477
- for (const entry of entries || []) {
478
- const model = entry?.model || null;
479
- const contentType = String(model?.contentType ?? model?.ContentType ?? '').toLowerCase();
480
- if (contentType === 'video') {
481
- imageCount++;
482
- continue;
483
- }
484
- if (contentType === 'image') {
485
- if (globalThis.MindMapNodes?.isAnimatedGifImageNodeModel?.(model) !== true) imageCount++;
486
- continue;
487
- }
488
- if (contentType === 'embed') {
489
- const urls = globalThis.MindMapNodes?.getNodeImageAssetUrls?.(model) || null;
490
- if (urls?.thumbnailUrl || urls?.snapshotUrl || urls?.previewImageUrl) imageCount++;
491
- }
492
- }
493
- return prepareImageAtlasCapacity(renderer, imageCount);
494
- }
495
-
496
- function uploadImageAtlasTile(renderer, slot, canvas) {
497
- const webglRenderer = renderer?.renderer || null;
498
- const gl = renderer?.gl || webglRenderer?.getContext?.() || null;
499
- const texture = renderer?.imageAtlasTexture || null;
500
- if (!webglRenderer?.initTexture || !gl || !texture || !canvas || !(slot?.slotIndex >= 0)) return false;
501
-
502
- let savedTexture = null;
503
- let savedFlipY = null;
504
- let savedPremultiply = null;
505
- let savedColorspace = null;
506
- try {
507
- webglRenderer.initTexture(texture);
508
- const handle = webglRenderer.properties?.get?.(texture)?.__webglTexture || null;
509
- if (!handle) return false;
510
- savedTexture = gl.getParameter(gl.TEXTURE_BINDING_2D);
511
- savedFlipY = gl.getParameter(gl.UNPACK_FLIP_Y_WEBGL);
512
- savedPremultiply = gl.getParameter(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL);
513
- savedColorspace = gl.getParameter(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL);
514
- const columns = Math.max(1, Number(renderer.imageAtlasColumns || 1));
515
- const x = (slot.slotIndex % columns) * IMAGE_ATLAS_TILE_SIZE;
516
- const y = Math.floor(slot.slotIndex / columns) * IMAGE_ATLAS_TILE_SIZE;
517
- gl.bindTexture(gl.TEXTURE_2D, handle);
518
- gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
519
- gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
520
- gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);
521
- gl.texSubImage2D(gl.TEXTURE_2D, 0, x, y, gl.RGBA, gl.UNSIGNED_BYTE, canvas);
522
- renderer._imageAtlasTileUploadCount = Number(renderer._imageAtlasTileUploadCount || 0) + 1;
523
- renderer._residentGpuWarmKey = '';
524
- renderer._residentImageAtlasWarmVersion = -1;
525
- return true;
526
- } catch {
527
- return false;
528
- } finally {
529
- if (savedFlipY !== null) gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, savedFlipY);
530
- if (savedPremultiply !== null) gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, savedPremultiply);
531
- if (savedColorspace !== null) gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, savedColorspace);
532
- if (savedTexture !== null) gl.bindTexture(gl.TEXTURE_2D, savedTexture);
533
- }
534
- }
535
-
536
- function scheduleImageAtlasUpload(renderer, module = renderer?._module) {
537
- if (!renderer?.imageAtlasTexture || renderer?._disposed === true) return false;
538
- const now = typeof performance !== 'undefined' ? performance.now() : Date.now();
539
- let state = imageAtlasUploadStates.get(renderer);
540
- if (!state) {
541
- state = { timer: 0, startedAt: now, pending: false, epoch: 0 };
542
- imageAtlasUploadStates.set(renderer, state);
543
- }
544
- state.pending = true;
545
- state.epoch = Number(renderer._residentStaticPreviewEpoch || 0);
546
- if (!(state.startedAt > 0)) state.startedAt = now;
547
- if (state.timer) clearTimeout(state.timer);
548
- const elapsedMs = Math.max(0, now - state.startedAt);
549
- const delayMs = Math.max(0, Math.min(
550
- IMAGE_ATLAS_UPLOAD_SETTLE_MS,
551
- IMAGE_ATLAS_UPLOAD_MAX_WAIT_MS - elapsedMs
552
- ));
553
- state.timer = setTimeout(() => {
554
- state.timer = 0;
555
- if (!state.pending || renderer._disposed === true ||
556
- state.epoch !== Number(renderer._residentStaticPreviewEpoch || 0)) return;
557
- state.pending = false;
558
- state.startedAt = 0;
559
- if (!renderer.imageAtlasTexture) return;
560
- renderer.imageAtlasTexture.needsUpdate = true;
561
- renderer._imageAtlasTextureUploadCount = Number(renderer._imageAtlasTextureUploadCount || 0) + 1;
562
- const activeModule = renderer._module || module;
563
- if (activeModule) {
564
- activeModule._forceUpdateFrames = Math.max(Number(activeModule._forceUpdateFrames || 0), 1);
565
- activeModule.requestAnimationWake?.('image-atlas-texture-upload');
566
- }
567
- }, delayMs);
568
- return true;
569
- }
570
-
571
- function clearScheduledImageAtlasUpload(renderer) {
572
- const state = imageAtlasUploadStates.get(renderer);
573
- if (state?.timer) clearTimeout(state.timer);
574
- imageAtlasUploadStates.delete(renderer);
575
- }
576
-
577
- function fallbackBatch(renderer, fallbackIds, limit = 12) {
578
- const ids = Array.from(fallbackIds || []);
579
- const safeLimit = Math.max(1, Number(limit || 1));
580
- if (ids.length <= safeLimit) return ids;
581
- const cursor = Math.max(0, Number(renderer?._residentFallbackCleanupCursor || 0)) % ids.length;
582
- const batch = [];
583
- for (let i = 0; i < safeLimit; i++) batch.push(ids[(cursor + i) % ids.length]);
584
- if (renderer) renderer._residentFallbackCleanupCursor = (cursor + safeLimit) % ids.length;
585
- return batch;
586
- }
587
-
588
- function reuseCssMediaFrameDom(cssObject, width, height, hasContextSourcePins = false) {
589
- const wrapper = cssObject?.element || null;
590
- const isMedia = wrapper?.classList?.contains?.('node-type-image') === true ||
591
- wrapper?.classList?.contains?.('node-type-video') === true ||
592
- wrapper?.classList?.contains?.('node-type-embed') === true;
593
- if (!isMedia || !wrapper?.style) return false;
594
-
595
- const inner = wrapper.firstElementChild || null;
596
- const content = inner?.querySelector?.('.node-content-wrapper') || null;
597
- const response = inner?.querySelector?.('.node-response') || null;
598
- const surface = inner?.querySelector?.('img,video,canvas.mind-map-video-proxy,iframe,.embed-card,.embed-iframe-shell') || null;
599
- const resolutionScale = Math.max(1, Number(cssObject?.userData?.resolutionScale || 1));
600
- const worldWidth = Math.max(1, Math.round(Number(width || 1)));
601
- const worldHeight = Math.max(1, Math.round(Number(height || 1)));
602
- const scaledWidth = worldWidth * resolutionScale;
603
- const scaledHeight = worldHeight * resolutionScale;
604
- const state = cssMediaFrameDomStates.get(cssObject) || null;
605
- const structureMatches = !!state && state.wrapper === wrapper && state.inner === inner &&
606
- state.content === content && state.response === response && state.surface === surface &&
607
- state.innerChildren === Number(inner?.childElementCount ?? inner?.children?.length ?? 0) &&
608
- state.contentChildren === Number(content?.childElementCount ?? content?.children?.length ?? 0);
609
- const frameMatches = structureMatches && state.width === worldWidth && state.height === worldHeight &&
610
- state.resolutionScale === resolutionScale && state.hasContextSourcePins === (hasContextSourcePins === true);
611
- const frameStylesReady = wrapper.style.width === `${scaledWidth}px` && wrapper.style.height === `${scaledHeight}px` &&
612
- (!inner?.style || (inner.style.width === `${worldWidth}px` && inner.style.height === `${worldHeight}px`));
613
-
614
- if (frameMatches && frameStylesReady) {
615
- cssMediaFrameDomReuseCount++;
616
- return true;
617
- }
618
-
619
- cssMediaFrameDomStates.set(cssObject, {
620
- wrapper,
621
- inner,
622
- content,
623
- response,
624
- surface,
625
- innerChildren: Number(inner?.childElementCount ?? inner?.children?.length ?? 0),
626
- contentChildren: Number(content?.childElementCount ?? content?.children?.length ?? 0),
627
- width: worldWidth,
628
- height: worldHeight,
629
- resolutionScale,
630
- hasContextSourcePins: hasContextSourcePins === true
631
- });
632
- cssMediaFrameDomApplyCount++;
633
- return false;
634
- }
635
-
636
- function reuseStableVisibleCss(renderer, entry, module, nodeIdValue, options = {}) {
637
- const cssObject = entry?.cssObject || null;
638
- const element = cssObject?.element || null;
639
- const nodeId = String(nodeIdValue || entry?.model?.id || entry?.model?.Id || entry?.glObject?.userData?.nodeId || '').trim();
640
- const cssScene = module?.cssScene || module?.scene || null;
641
- const allowResident = options.allowResident === true;
642
- if (!nodeId || !element || entry?.isCssDirty === true || entry?.currentType !== 'CSS' ||
643
- cssObject.visible !== true || cssObject.userData?._residentTransitionPrepared === true ||
644
- cssObject.userData?._fullResFringePrepared === true ||
645
- (!allowResident && renderer?.isInLODMode === true) || (cssScene && cssObject.parent !== cssScene) ||
646
- element.style?.display === 'none' || element.style?.visibility === 'hidden' || element.style?.opacity === '0' ||
647
- module?._cssParentRepairNeeded === true || module?._cssTransformDirtyIds?.has?.(nodeId) === true) return false;
648
-
649
- const selectedNodeId = String(module?.selectedNodeIdJs || module?.selectedNodeId || '').trim();
650
- const editingNodeId = String(module?._textOverlayV2State?.editing?.nodeId || module?._editingOverlayState?.nodeId || '').trim();
651
- if (selectedNodeId === nodeId || module?.multiSelectedNodeIds?.has?.(nodeId) === true ||
652
- module?.draggedNodeId === nodeId || editingNodeId === nodeId ||
653
- renderer?._getCurrentHoveredNodeId?.(module) === nodeId) return false;
654
-
655
- const isHigh = options.isHighDetail === true;
656
- if (typeof renderer?._areCss3dDetailTargetsAtLevel === 'function') {
657
- if (renderer._areCss3dDetailTargetsAtLevel(entry, isHigh) !== true) return false;
658
- } else {
659
- const inner = element.querySelector?.('.node-container') || null;
660
- const targets = inner && inner !== element ? [element, inner] : [element];
661
- for (const target of targets) {
662
- if (!target?.classList || target.classList.contains(isHigh ? 'lod-high' : 'lod-low') !== true ||
663
- target.classList.contains(isHigh ? 'lod-low' : 'lod-high') === true) return false;
664
- }
665
- }
666
- if (isHigh && (typeof renderer?._isCss3dSourceSuspended === 'function'
667
- ? renderer._isCss3dSourceSuspended(entry) === true
668
- : (element.matches?.('[data-text-overlay-source-suspended],.mind-map-text-overlay-source-suspended,.mind-map-v2-source-suspended') === true ||
669
- element.querySelector?.('[data-text-overlay-source-suspended],.mind-map-text-overlay-source-suspended,.mind-map-v2-source-suspended')))) return false;
670
-
671
- const contentType = String(entry?.model?.contentType ?? entry?.model?.ContentType ?? '').trim().toLowerCase();
672
- if (contentType === 'image' || contentType === 'video') {
673
- const media = element.querySelector?.('img,video') || null;
674
- const source = media?.getAttribute?.('src') || media?.currentSrc || media?.src || '';
675
- if (!media || !source) return false;
676
- } else if (contentType === 'embed' &&
677
- !element.querySelector?.('.embed-card,.embed-frame,.embed-iframe-shell')) return false;
678
-
679
- renderer?._nearCssVisibleIds?.add?.(nodeId);
680
- if (renderer) renderer._fullResCssStableReuseCount = Number(renderer._fullResCssStableReuseCount || 0) + 1;
681
- return true;
682
- }
683
-
684
- function reuseActiveCssMediaFallback(renderer, entry, module) {
685
- const cssObject = entry?.cssObject || null;
686
- const element = cssObject?.element || null;
687
- const nodeId = String(entry?.model?.id || entry?.model?.Id || entry?.glObject?.userData?.nodeId || '').trim();
688
- const cssScene = module?.cssScene || module?.scene || null;
689
- if (!nodeId || !element || entry?.isCssDirty === true || cssObject.visible !== true ||
690
- !renderer?._lodImageCssFallbackNodeIds?.has?.(nodeId) ||
691
- (cssScene && cssObject.parent !== cssScene) || element.style?.display === 'none' ||
692
- element.style?.visibility === 'hidden' || element.style?.opacity === '0') return false;
693
- if (String(module?.selectedNodeIdJs || module?.selectedNodeId || '') === nodeId ||
694
- module?.multiSelectedNodeIds?.has?.(nodeId) === true || module?.draggedNodeId === nodeId ||
695
- renderer?._getCurrentHoveredNodeId?.(module) === nodeId) return false;
696
- return true;
697
- }
698
-
699
- function invalidateAnimatedGifCssFallbackCandidateCache(renderer) {
700
- if (!renderer) return;
701
- renderer._animatedGifFallbackCandidateCacheValid = false;
702
- }
703
-
704
- function invalidateActiveCssMediaFallbackCountCache(renderer) {
705
- if (!renderer) return;
706
- renderer._activeCssMediaFallbackCountCacheValid = false;
707
- }
708
-
709
- function markLodImageCssFallbacksChanged(renderer) {
710
- if (!renderer) return;
711
- renderer._lodImageCssFallbackRevision =
712
- Number(renderer._lodImageCssFallbackRevision || 0) + 1;
713
- invalidateAnimatedGifCssFallbackCandidateCache(renderer);
714
- invalidateActiveCssMediaFallbackCountCache(renderer);
715
- }
716
-
717
- function createTrackedLodImageCssFallbackSet(renderer) {
718
- return new class extends Set {
719
- add(value) {
720
- if (!this.has(value)) {
721
- super.add(value);
722
- markLodImageCssFallbacksChanged(renderer);
723
- }
724
- return this;
725
- }
726
-
727
- delete(value) {
728
- const deleted = super.delete(value);
729
- if (deleted) markLodImageCssFallbacksChanged(renderer);
730
- return deleted;
731
- }
732
-
733
- clear() {
734
- if (this.size <= 0) return;
735
- super.clear();
736
- markLodImageCssFallbacksChanged(renderer);
737
- }
738
- }();
739
- }
740
-
741
- function getActiveCssMediaFallbackCountCached(renderer, module) {
742
- if (!renderer) return 0;
743
- const nodeObjectsById = module?.nodeObjectsById || renderer?._module?.nodeObjectsById || null;
744
- const fallbackRevision = Number(renderer?._lodImageCssFallbackRevision || 0);
745
- const fallbackCount = Number(renderer?._lodImageCssFallbackNodeIds?.size || 0);
746
- if (fallbackCount <= 0) {
747
- renderer._activeCssMediaFallbackCountCacheNodeMap = nodeObjectsById;
748
- renderer._activeCssMediaFallbackCountCacheRevision = fallbackRevision;
749
- renderer._activeCssMediaFallbackCountCacheFallbackCount = 0;
750
- renderer._activeCssMediaFallbackCountCacheValue = 0;
751
- renderer._activeCssMediaFallbackCountCacheValid = true;
752
- return 0;
753
- }
754
- if (renderer._activeCssMediaFallbackCountCacheValid === true &&
755
- renderer._activeCssMediaFallbackCountCacheNodeMap === nodeObjectsById &&
756
- Number(renderer._activeCssMediaFallbackCountCacheRevision || 0) === fallbackRevision &&
757
- Number(renderer._activeCssMediaFallbackCountCacheFallbackCount || 0) === fallbackCount) {
758
- renderer._activeCssMediaFallbackCountCacheHitCount =
759
- Number(renderer._activeCssMediaFallbackCountCacheHitCount || 0) + 1;
760
- return Number(renderer._activeCssMediaFallbackCountCacheValue || 0);
761
- }
762
-
763
- const activeFallbackCount =
764
- Number(renderer._getActiveCssMediaLodFallbackCount?.(module) || 0);
765
- renderer._activeCssMediaFallbackCountScanCount =
766
- Number(renderer._activeCssMediaFallbackCountScanCount || 0) + 1;
767
- renderer._activeCssMediaFallbackCountCacheNodeMap = nodeObjectsById;
768
- renderer._activeCssMediaFallbackCountCacheRevision = fallbackRevision;
769
- renderer._activeCssMediaFallbackCountCacheFallbackCount = fallbackCount;
770
- renderer._activeCssMediaFallbackCountCacheValue = activeFallbackCount;
771
- renderer._activeCssMediaFallbackCountCacheValid = true;
772
- return activeFallbackCount;
773
- }
774
-
775
- function hasAnimatedGifCssFallbackCandidates(renderer, module, isAnimatedGifModel, selectionKey = '') {
776
- const nodeObjectsById = module?.nodeObjectsById || renderer?._module?.nodeObjectsById || null;
777
- if (!nodeObjectsById || typeof isAnimatedGifModel !== 'function') return false;
778
- const visibilityVersion = Number(module?._visibilityVersion || 0);
779
- const fallbackRevision = Number(renderer?._lodImageCssFallbackRevision || 0);
780
- const fallbackCount = Number(renderer?._lodImageCssFallbackNodeIds?.size || 0);
781
- const residentDirtySerial = Number(renderer?._instancesDirtySerial || 0);
782
- const normalizedSelectionKey = String(selectionKey || '');
783
- if (renderer?._animatedGifFallbackCandidateCacheValid === true &&
784
- renderer._animatedGifFallbackCandidateNodeMap === nodeObjectsById &&
785
- Number(renderer._animatedGifFallbackCandidateVisibilityVersion || 0) === visibilityVersion &&
786
- Number(renderer._animatedGifFallbackCandidateFallbackRevision || 0) === fallbackRevision &&
787
- Number(renderer._animatedGifFallbackCandidateFallbackCount || 0) === fallbackCount &&
788
- Number(renderer._animatedGifFallbackCandidateResidentDirtySerial || 0) === residentDirtySerial &&
789
- String(renderer._animatedGifFallbackCandidateSelectionKey || '') === normalizedSelectionKey) {
790
- renderer._animatedGifFallbackCandidateCacheHitCount =
791
- Number(renderer._animatedGifFallbackCandidateCacheHitCount || 0) + 1;
792
- return renderer._animatedGifFallbackCandidateCacheValue === true;
793
- }
794
-
795
- renderer._animatedGifFallbackCandidateScanCount =
796
- Number(renderer._animatedGifFallbackCandidateScanCount || 0) + 1;
797
- const isGifId = (value) => {
798
- const nodeId = String(value || '').trim();
799
- if (nodeId) {
800
- renderer._animatedGifFallbackCandidateNodeVisitCount =
801
- Number(renderer._animatedGifFallbackCandidateNodeVisitCount || 0) + 1;
802
- }
803
- return !!nodeId && isAnimatedGifModel(nodeObjectsById.get(nodeId)?.model) === true;
804
- };
805
- const scan = (ids) => {
806
- if (!ids) return false;
807
- for (const nodeId of ids) if (isGifId(nodeId)) return true;
808
- return false;
809
- };
810
- const visibleIds = module?._visibleIds || null;
811
- const result =
812
- scan(visibleIds) ||
813
- (module?._prevVisibleIds !== visibleIds && scan(module?._prevVisibleIds)) ||
814
- isGifId(module?.selectedNodeIdJs) ||
815
- scan(module?.multiSelectedNodeIds) ||
816
- scan(renderer?._lodImageCssFallbackNodeIds);
817
- renderer._animatedGifFallbackCandidateNodeMap = nodeObjectsById;
818
- renderer._animatedGifFallbackCandidateVisibilityVersion = visibilityVersion;
819
- renderer._animatedGifFallbackCandidateFallbackRevision = fallbackRevision;
820
- renderer._animatedGifFallbackCandidateFallbackCount = fallbackCount;
821
- renderer._animatedGifFallbackCandidateResidentDirtySerial = residentDirtySerial;
822
- renderer._animatedGifFallbackCandidateSelectionKey = normalizedSelectionKey;
823
- renderer._animatedGifFallbackCandidateCacheValue = result === true;
824
- renderer._animatedGifFallbackCandidateCacheValid = true;
825
- return result === true;
826
- }
827
-
828
- function hasActionableResidentLineDetails(renderer, module, lodBand) {
829
- const nodeIds = renderer?.instanceData?.nodeIds || [];
830
- return nodeIds.length > 0 && renderer?._hasPendingLineDetailRestore?.(lodBand) === true &&
831
- areResidentLinesPrepared(renderer, module?.nodeObjectsById, nodeIds);
832
- }
833
-
834
- function hasResidentDirtyWork(renderer, camera, module, resolveLodBand, buildSelectionKey, isAnimatedGifModel) {
835
- if (!renderer) return false;
836
- const lodBand = camera && typeof resolveLodBand === 'function'
837
- ? resolveLodBand(Number(camera.position?.z || 0))
838
- : renderer._currentLodBand;
839
- const hasTypedResidentDirtyWork =
840
- renderer._instancesDirty === true || renderer._imageInstancesDirty === true ||
841
- renderer._positionsOnlyDirty === true || renderer._isNodeArrayDirty === true ||
842
- Number(renderer._dirtyPositionIds?.size || 0) > 0 || Number(renderer._pendingSelectionRefreshIds?.size || 0) > 0 ||
843
- renderer._imageAtlasRebuildPending === true || Number(renderer._imageAtlasQueuedIds?.size || 0) > 0 ||
844
- Number(renderer._imageAtlasLoadingIds?.size || 0) > 0 || Number(renderer._imageAtlasBatchReadyIds?.size || 0) > 0 ||
845
- renderer._imageAtlasBatchActive === true || renderer._lodCleanupPending === true ||
846
- renderer._deferLineRestorePending === true || hasActionableResidentLineDetails(renderer, module, lodBand) ||
847
- Number(renderer._pendingLodVisibilityVersion ?? -1) >= 0 || renderer._fullResHandoffActive === true ||
848
- renderer.isLoading === true || module?.isLoading === true || renderer._hasResidentLodInstances?.() !== true;
849
- if (hasTypedResidentDirtyWork) {
850
- invalidateAnimatedGifCssFallbackCandidateCache(renderer);
851
- return true;
852
- }
853
- const selectionKey = typeof buildSelectionKey === 'function'
854
- ? buildSelectionKey(module?.multiSelectedNodeIds || null, module?.selectedNodeIdJs || null)
855
- : '';
856
- if (renderer._lastAppliedLodSelectionKey !== selectionKey) {
857
- invalidateAnimatedGifCssFallbackCandidateCache(renderer);
858
- return true;
859
- }
860
- const usesCssImageFallbacks = renderer._shouldUseCssImageFallbackInResidentLod?.(module, lodBand) === true;
861
- const usesAnimatedGifFallbacks = hasAnimatedGifCssFallbackCandidates(
862
- renderer,
863
- module,
864
- isAnimatedGifModel,
865
- selectionKey
866
- );
867
- const fallbackCount = Number(renderer._lodImageCssFallbackNodeIds?.size || 0);
868
- if (!usesAnimatedGifFallbacks && fallbackCount <= 0) return false;
869
- const activeFallbackCount = getActiveCssMediaFallbackCountCached(renderer, module);
870
- return (usesAnimatedGifFallbacks && activeFallbackCount <= 0) ||
871
- (fallbackCount > 0 && (!(usesCssImageFallbacks || usesAnimatedGifFallbacks) || activeFallbackCount <= 0));
872
- }
873
-
874
- function hasPendingNearCssWarmup(renderer, module, buildSelectionKey, isCss3dEnabled, supportsCss3dModel) {
875
- if (!renderer || renderer.isInLODMode !== false) return false;
876
- if (renderer._css3dProcessing === true || Number(renderer._css3dQueuedMap?.size || 0) > 0 ||
877
- renderer._hasCss3dQueueItems?.() === true || Number(renderer._nearEntryBoostFrames || 0) > 0) return true;
878
- const moduleRef = module || renderer._module || null;
879
- const visibleIds = renderer._getNearVisibleIds?.(moduleRef) || null;
880
- const nodeObjectsById = moduleRef?.nodeObjectsById || null;
881
- if (!visibleIds || !nodeObjectsById || visibleIds.size === 0) return false;
882
- const selectionKey = buildSelectionKey?.(moduleRef?.multiSelectedNodeIds || null, moduleRef?.selectedNodeIdJs || null) || '';
883
- const stableKey = buildFullResKey(renderer._currentLodBand, moduleRef?._visibilityVersion || 0, selectionKey,
884
- nodeObjectsById.size, visibleIds.size, renderer._nearCssVisibleIds?.size || 0,
885
- renderer._activeFullResCssNodeIds?.size || 0, isCss3dEnabled?.(moduleRef) !== false, moduleRef, renderer);
886
- if (stableKey && renderer._lastNearCssNoWorkKey === stableKey) return false;
887
- for (const nodeId of visibleIds) {
888
- if (renderer._nearCssVisibleIds?.has?.(nodeId)) continue;
889
- const entry = nodeObjectsById.get(nodeId);
890
- if (entry?.glObject && supportsCss3dModel?.(entry.model) === true) return true;
891
- }
892
- return false;
893
- }
894
-
895
- function resetPreparedLayoutRecord(record) {
896
- if (!record?.layoutPrepared) return;
897
- const cssObject = record.cssObject;
898
- const element = record.element;
899
- if (cssObject?.userData) cssObject.userData._residentTransitionPrepared = false;
900
- record.layoutPrepared = false;
901
- if (cssObject?.visible !== true && element?.style) {
902
- element.style.setProperty?.('display', 'none', 'important');
903
- element.style.setProperty?.('visibility', 'visible', 'important');
904
- element.style.setProperty?.('opacity', '1', 'important');
905
- element.style.setProperty?.('pointer-events', record.pointerEvents || 'auto', 'important');
906
- }
907
- }
908
-
909
- function clearTransitionRecords(state) {
910
- if (!state) return;
911
- state.layoutEpoch = Number(state.layoutEpoch || 0) + 1;
912
- if (state.layoutRetryTimer) clearTimeout(state.layoutRetryTimer);
913
- for (const record of state.parked?.values?.() || []) resetPreparedLayoutRecord(record);
914
- state.parked?.clear?.();
915
- state.layoutQueue = null;
916
- state.layoutCursor = 0;
917
- state.layoutScheduled = false;
918
- state.layoutFrameScheduled = false;
919
- state.layoutRetryTimer = null;
920
- }
921
-
922
- function getTransitionState(renderer, module, nodeObjectsById) {
923
- let state = residentTransitionStates.get(renderer);
924
- if (!state || state.module !== module || state.nodeObjectsById !== nodeObjectsById) {
925
- clearTransitionRecords(state);
926
- state = {
927
- renderer, module, nodeObjectsById, active: false, selectionKey: '', parked: new Map(),
928
- layoutQueue: null, layoutCursor: 0, layoutScheduled: false, layoutFrameScheduled: false,
929
- layoutRetryTimer: null, layoutEpoch: 0
930
- };
931
- residentTransitionStates.set(renderer, state);
932
- }
933
- return state;
934
- }
935
-
936
- function getResidentCssCacheKind(entry) {
937
- const model = entry?.model || null;
938
- const contentType = String(model?.contentType ?? model?.ContentType ?? '').trim().toLowerCase();
939
- if (contentType === 'image') return 'image';
940
- if (contentType === 'video' || contentType === 'embed' || contentType === 'templatelauncher') return contentType;
941
- if (RESIDENT_CSS_CACHE_TEXT_TYPES.has(contentType)) return 'text';
942
- const metadata = model?.metadata || model?.Metadata || null;
943
- const nodeType = String(model?.nodeType ?? model?.NodeType ?? '').toLowerCase();
944
- const semanticType = String(metadata?.SemanticType ?? metadata?.semanticType ?? '');
945
- const agentId = metadata?.agentId ?? metadata?.AgentId;
946
- return nodeType.startsWith('agent_') || semanticType === 'MindCanvasAgent' || semanticType === 'AgentCommand' ||
947
- semanticType === 'BusinessAutomationNode' || (agentId != null && String(agentId).trim() !== '') ? 'text' : null;
948
- }
949
-
950
- function cacheResidentCssEntry(state, entry, nodeId, kind) {
951
- const cssObject = entry?.cssObject || null;
952
- if (!state?.active || !kind || entry?.isCssDirty === true || !cssObject?.element) return false;
953
- const cssScene = state.module?.cssScene || state.module?.scene || null;
954
- if (!cssScene || (cssObject.parent != null && cssObject.parent !== cssScene)) return false;
955
- const id = String(nodeId || '');
956
- const previous = state.parked.get(id) || null;
957
- if (previous?.layoutPrepared === true &&
958
- (previous.cssObject !== cssObject || previous.element !== cssObject.element)) resetPreparedLayoutRecord(previous);
959
- state.parked.set(id, {
960
- nodeId: id,
961
- entry, cssObject, element: cssObject.element, parent: cssObject.parent, kind,
962
- pointerEvents: previous?.pointerEvents ?? cssObject.element.style?.pointerEvents ?? '',
963
- layoutEligible: previous?.layoutEligible === true,
964
- layoutPrepared: previous?.layoutPrepared === true && previous.cssObject === cssObject && previous.element === cssObject.element,
965
- selectionKey: state.selectionKey,
966
- ...getEntryContentState(entry)
967
- });
968
- state.layoutQueue = null;
969
- return true;
970
- }
971
-
972
- function cachePreparedResidentCss(renderer, entry, module, nodeObjectsById) {
973
- const state = residentTransitionStates.get(renderer);
974
- if (!state || state.module !== module || state.nodeObjectsById !== nodeObjectsById) return false;
975
- const nodeId = entry?.model?.id || entry?.model?.Id || entry?.glObject?.userData?.nodeId || '';
976
- const cached = cacheResidentCssEntry(state, entry, nodeId, getResidentCssCacheKind(entry));
977
- if (cached) {
978
- const record = state.parked.get(String(nodeId || ''));
979
- if (record) record.layoutEligible = true;
980
- scheduleResidentCssLayoutWarm(renderer, module, nodeObjectsById);
981
- }
982
- return cached;
983
- }
984
-
985
- function beginResidentCssTransition(renderer, module, nodeObjectsById, previousBand, nextBand, selectionKey) {
986
- if (!renderer || !module || !nodeObjectsById) return false;
987
- const state = getTransitionState(renderer, module, nodeObjectsById);
988
- const enteringResident = previousBand === 'NORMAL' && nextBand === 'MID';
989
- const returningFullRes = (previousBand === 'MID' || previousBand === 'FAR') && nextBand === 'NORMAL';
990
- if (enteringResident) {
991
- clearTransitionRecords(state);
992
- state.active = true;
993
- state.selectionKey = String(selectionKey || '');
994
- } else if (!returningFullRes) {
995
- clearTransitionRecords(state);
996
- state.active = false;
997
- state.selectionKey = '';
998
- }
999
- return enteringResident || (returningFullRes && state.active);
1000
- }
1001
-
1002
- function getEntryContentState(entry) {
1003
- const model = entry?.model || null;
1004
- return {
1005
- model,
1006
- source: model?._visibleContent ?? model?.response ?? model?.Response ?? model?.content ?? model?.Content ?? '',
1007
- prompt: model?.prompt ?? model?.Prompt ?? '',
1008
- width: Number(model?.width || model?.Width || 0),
1009
- height: Number(model?.height || model?.Height || 0),
1010
- media: model?.thumbnailUrl ?? model?.ThumbnailUrl ?? model?.displayUrl ?? model?.DisplayUrl ?? ''
1011
- };
1012
- }
1013
-
1014
- function parkFullResCss(renderer, entry, module, nodeObjectsById, selectionKey, kind = 'text') {
1015
- const cssObject = entry?.cssObject || null;
1016
- const element = cssObject?.element || null;
1017
- const nodeId = String(entry?.model?.id || entry?.model?.Id || entry?.glObject?.userData?.nodeId || '').trim();
1018
- if (!renderer || !cssObject || !element || !nodeId) return false;
1019
- const state = getTransitionState(renderer, module, nodeObjectsById);
1020
- let cached = false;
1021
- if (state.active && state.selectionKey === String(selectionKey || '') && entry.isCssDirty !== true) {
1022
- cached = cacheResidentCssEntry(state, entry, nodeId, kind);
1023
- if (cached) {
1024
- const record = state.parked.get(nodeId);
1025
- if (record) record.layoutEligible = true;
1026
- renderer._residentCssParkCount = Number(renderer._residentCssParkCount || 0) + 1;
1027
- }
1028
- }
1029
- cssObject.visible = false;
1030
- entry.currentType = 'GL';
1031
- if (element.style?.display !== 'none') {
1032
- element.style?.setProperty?.('display', 'none', 'important');
1033
- }
1034
- if (cached && !state.layoutRetryTimer) {
1035
- const epoch = state.layoutEpoch;
1036
- state.layoutRetryTimer = setTimeout(() => {
1037
- state.layoutRetryTimer = null;
1038
- if (residentTransitionStates.get(renderer) === state && state.layoutEpoch === epoch) {
1039
- scheduleResidentCssLayoutWarm(renderer, module, nodeObjectsById);
1040
- }
1041
- }, 0);
1042
- }
1043
- return true;
1044
- }
1045
-
1046
- function scheduleResidentCssLayoutWarm(renderer, module, nodeObjectsById) {
1047
- const state = residentTransitionStates.get(renderer);
1048
- if (!state?.active || state.module !== module || state.nodeObjectsById !== nodeObjectsById ||
1049
- renderer?._disposed === true || renderer?.isInLODMode !== true || module?.isLoading === true) return false;
1050
- const visibleIds = module?._visibleIds || module?._prevVisibleIds || renderer?._visibleIds || null;
1051
- if (visibleIds?.size > 0) {
1052
- for (const nodeId of visibleIds) {
1053
- const record = state.parked.get(String(nodeId || ''));
1054
- if (record) record.layoutEligible = true;
1055
- }
1056
- }
1057
- if (isPrewarmInteractionActive(module)) {
1058
- if (!state.layoutRetryTimer) {
1059
- const epoch = state.layoutEpoch;
1060
- state.layoutRetryTimer = setTimeout(() => {
1061
- state.layoutRetryTimer = null;
1062
- if (residentTransitionStates.get(renderer) === state && state.layoutEpoch === epoch) {
1063
- scheduleResidentCssLayoutWarm(renderer, module, nodeObjectsById);
1064
- }
1065
- }, 80);
1066
- }
1067
- return false;
1068
- }
1069
- if (state.layoutScheduled || state.layoutFrameScheduled) return false;
1070
- if (!state.layoutQueue) {
1071
- state.layoutQueue = [];
1072
- state.layoutCursor = 0;
1073
- for (const record of state.parked.values()) {
1074
- if (record.layoutEligible === true && record.layoutPrepared !== true) state.layoutQueue.push(record);
1075
- }
1076
- }
1077
- if (state.layoutCursor >= state.layoutQueue.length) {
1078
- state.layoutQueue = null;
1079
- return false;
1080
- }
1081
-
1082
- const epoch = state.layoutEpoch;
1083
- state.layoutScheduled = true;
1084
- const run = () => {
1085
- state.layoutScheduled = false;
1086
- if (residentTransitionStates.get(renderer) !== state || state.layoutEpoch !== epoch || !state.active ||
1087
- renderer?._disposed === true || renderer?.isInLODMode !== true || renderer?._module !== module ||
1088
- module?.nodeObjectsById !== nodeObjectsById || module?.isLoading === true) return;
1089
- if (isPrewarmInteractionActive(module)) {
1090
- state.layoutQueue = null;
1091
- scheduleResidentCssLayoutWarm(renderer, module, nodeObjectsById);
1092
- return;
1093
- }
1094
-
1095
- // Visibility can expand while the wheel is still settling after
1096
- // NORMAL -> MID. Refresh from the latest set during idle so those
1097
- // CSS owners are not created synchronously on MID -> NORMAL.
1098
- const latestVisibleIds = module?._visibleIds || module?._prevVisibleIds || renderer?._visibleIds || null;
1099
- const latestPriority = latestVisibleIds?.size > 0
1100
- ? renderer?._getNearVisiblePriority?.(latestVisibleIds, nodeObjectsById, module?.camera)
1101
- : null;
1102
- if (Array.isArray(latestPriority) && latestPriority.length > 0) {
1103
- renderer?._queueCss3dPrewarm?.(latestPriority, nodeObjectsById, module, 'MID');
1104
- }
1105
- if (residentTransitionStates.get(renderer) !== state || state.layoutEpoch !== epoch ||
1106
- !Array.isArray(state.layoutQueue)) return;
1107
- const layoutQueue = state.layoutQueue;
1108
-
1109
- const startedAt = performance.now();
1110
- let prepared = 0;
1111
- while (state.layoutCursor < layoutQueue.length && prepared < 4 &&
1112
- (prepared === 0 || performance.now() - startedAt < 2)) {
1113
- const record = layoutQueue[state.layoutCursor++];
1114
- if (state.parked.get(record.nodeId) !== record || record.entry?.isCssDirty === true ||
1115
- record.cssObject?.visible === true || !record.element?.style) continue;
1116
- record.cssObject.userData = record.cssObject.userData || {};
1117
- record.cssObject.userData._residentTransitionPrepared = true;
1118
- record.element.style.setProperty?.('visibility', 'visible', 'important');
1119
- record.element.style.setProperty?.('opacity', '0', 'important');
1120
- record.element.style.setProperty?.('pointer-events', 'none', 'important');
1121
- record.element.style.setProperty?.('display', 'block', 'important');
1122
- record.layoutPrepared = true;
1123
- prepared++;
1124
- }
1125
- if (prepared > 0) {
1126
- renderer._residentCssLayoutWarmCount = Number(renderer._residentCssLayoutWarmCount || 0) + prepared;
1127
- module._css3dVisualChangedThisFrame = true;
1128
- module._css3dVisualChangedSinceLastRender = true;
1129
- }
1130
- if (state.layoutQueue !== layoutQueue) return;
1131
- if (state.layoutCursor < layoutQueue.length) {
1132
- state.layoutFrameScheduled = true;
1133
- const continueWarm = () => {
1134
- state.layoutFrameScheduled = false;
1135
- if (residentTransitionStates.get(renderer) === state && state.layoutEpoch === epoch) {
1136
- scheduleResidentCssLayoutWarm(renderer, module, nodeObjectsById);
1137
- }
1138
- };
1139
- if (typeof globalThis.requestAnimationFrame === 'function') globalThis.requestAnimationFrame(continueWarm);
1140
- else setTimeout(continueWarm, 16);
1141
- } else {
1142
- state.layoutQueue = null;
1143
- }
1144
- };
1145
- if (typeof globalThis.requestIdleCallback === 'function') globalThis.requestIdleCallback(run, { timeout: 120 });
1146
- else setTimeout(run, 16);
1147
- return true;
1148
- }
1149
-
1150
- function parkReadyResidentImage(renderer, entry, module, nodeObjectsById, selectionKey, nodeId, animatedGif, selected, interactiveOwner) {
1151
- if (animatedGif === true || selected === true || interactiveOwner === true ||
1152
- renderer?._hasActiveImageLodInstance?.(nodeId) !== true) return false;
1153
- parkFullResCss(renderer, entry, module, nodeObjectsById, selectionKey, 'image');
1154
- renderer._hideImageLodFullVisual?.(entry);
1155
- renderer._setGlowVisibility?.(entry, false);
1156
- return true;
1157
- }
1158
-
1159
- function restoreParkedFullResCss(renderer, entry, module, nodeObjectsById, selectionKey, lodBand, nodeIdValue) {
1160
- if (!renderer || lodBand !== 'NORMAL') return false;
1161
- const state = residentTransitionStates.get(renderer);
1162
- const nodeId = String(nodeIdValue || entry?.model?.id || entry?.model?.Id || '').trim();
1163
- const record = state?.parked?.get?.(nodeId) || null;
1164
- const current = getEntryContentState(entry);
1165
- const cssScene = module?.cssScene || module?.scene || null;
1166
- const valid = !!record && state.module === module && state.nodeObjectsById === nodeObjectsById &&
1167
- record.entry === entry && record.model === current.model && record.cssObject === entry?.cssObject &&
1168
- record.element === entry?.cssObject?.element && cssScene &&
1169
- (record.parent == null || record.parent === cssScene) &&
1170
- (entry.cssObject.parent == null || entry.cssObject.parent === cssScene) && entry.isCssDirty !== true &&
1171
- record.selectionKey === String(selectionKey || '') && record.source === current.source &&
1172
- record.prompt === current.prompt && record.width === current.width && record.height === current.height &&
1173
- record.media === current.media;
1174
- if (!valid) {
1175
- if (record) {
1176
- resetPreparedLayoutRecord(record);
1177
- state.parked.delete(nodeId);
1178
- }
1179
- if (state?.active) renderer._residentCssRestoreMissCount = Number(renderer._residentCssRestoreMissCount || 0) + 1;
1180
- return false;
1181
- }
1182
-
1183
- const cssObject = record.cssObject;
1184
- const element = record.element;
1185
- const layoutPrepared = record.layoutPrepared === true && cssObject.userData?._residentTransitionPrepared === true;
1186
- if (renderer._promoteFullResCssFringePrepared?.(entry) !== true) {
1187
- renderer._clearFullResCssFringePrepared?.(entry);
1188
- }
1189
- if (cssObject.userData) delete cssObject.userData._fullResFringeCreated;
1190
- if (cssObject.userData) cssObject.userData._residentTransitionPrepared = false;
1191
- if (cssObject.parent !== cssScene) cssScene.add?.(cssObject);
1192
- if (entry.glObject) {
1193
- entry.glObject.updateWorldMatrix?.(true, false);
1194
- entry.glObject.matrixWorld?.decompose?.(renderer._tmpWorldPos, renderer._tmpWorldQuat, renderer._tmpWorldScale);
1195
- if (renderer._tmpWorldPos) cssObject.position?.copy?.(renderer._tmpWorldPos);
1196
- if (renderer._tmpWorldQuat) cssObject.quaternion?.copy?.(renderer._tmpWorldQuat);
1197
- entry.glObject.visible = true;
1198
- if (entry.bodyMesh) entry.bodyMesh.visible = false;
1199
- if (entry.tailMesh) entry.tailMesh.visible = false;
1200
- }
1201
- cssObject.visible = true;
1202
- if (!layoutPrepared && element.style?.display !== 'block') element.style?.setProperty?.('display', 'block', 'important');
1203
- if (element.style?.visibility !== 'visible') element.style?.setProperty?.('visibility', 'visible', 'important');
1204
- if (element.style?.opacity !== '1') element.style?.setProperty?.('opacity', '1', 'important');
1205
- if (layoutPrepared) element.style?.setProperty?.('pointer-events', record.pointerEvents || 'auto', 'important');
1206
- if (element.style?.transition !== 'none') element.style?.setProperty?.('transition', 'none', 'important');
1207
- const rootStyle = element.firstElementChild?.style || null;
1208
- if (rootStyle && rootStyle.getPropertyValue?.('content-visibility') !== 'visible') {
1209
- rootStyle.setProperty?.('content-visibility', 'visible', 'important');
1210
- rootStyle.setProperty?.('contain-intrinsic-size', 'auto', 'important');
1211
- }
1212
- cssObject.updateMatrixWorld?.(true);
1213
- entry.currentType = 'CSS';
1214
- renderer._setCss3dLodClass?.(entry, renderer._shouldUseHighCss3dDetail?.(entry, module) !== false);
1215
- renderer._nearCssVisibleIds?.add?.(nodeId);
1216
- if (record.kind === 'image') renderer._syncCssImageBodyBridge?.(entry, module);
1217
- if (record.kind === 'video') globalThis.MindMapCss3DManager?.syncVideoNodeVisibilityPlayback?.(entry.model, cssObject, true);
1218
- if (typeof renderer._deleteLodImageCssFallbackNodeId === 'function') {
1219
- renderer._deleteLodImageCssFallbackNodeId(nodeId);
1220
- } else {
1221
- renderer._lodImageCssFallbackNodeIds?.delete?.(nodeId);
1222
- invalidateAnimatedGifCssFallbackCandidateCache(renderer);
1223
- invalidateActiveCssMediaFallbackCountCache(renderer);
1224
- }
1225
- state.parked.delete(nodeId);
1226
- renderer._residentCssRestoreCount = Number(renderer._residentCssRestoreCount || 0) + 1;
1227
- module._css3dVisualChangedThisFrame = true;
1228
- module._css3dVisualChangedSinceLastRender = true;
1229
- return true;
1230
- }
1231
-
1232
- function completeFullResTransition(renderer, allowedCssCount) {
1233
- if (!renderer || Number(renderer._nearCssVisibleIds?.size || 0) < Number(allowedCssCount || 0) ||
1234
- renderer._hasCss3dQueueItems?.() === true || Number(renderer._css3dQueuedMap?.size || 0) > 0) return false;
1235
- if (renderer._nearEntryBoostFrames > 0) renderer._residentBoostClearCount = Number(renderer._residentBoostClearCount || 0) + 1;
1236
- renderer._nearEntryBoostFrames = 0;
1237
- const state = residentTransitionStates.get(renderer);
1238
- if (state) {
1239
- clearTransitionRecords(state);
1240
- state.active = false;
1241
- }
1242
- return true;
1243
- }
1244
-
1245
- function ensureResidentLineDetails(renderer, lodBand) {
1246
- if (!renderer || lodBand !== 'MID') return false;
1247
- if (renderer.lineDataDirty === true || renderer._lineDetailsPatchPending === true) {
1248
- renderer._markLineDetailsDirty?.();
1249
- return false;
1250
- }
1251
- renderer._residentStableLineReuseCount = Number(renderer._residentStableLineReuseCount || 0) + 1;
1252
- if (renderer.instancedLineMesh) renderer.instancedLineMesh.visible = renderer._shouldShowInstancedLineMesh?.(lodBand) === true;
1253
- return true;
1254
- }
1255
-
1256
- function reusePreparedImageInstances(renderer, state) {
1257
- if (renderer?.isInLODMode !== false || renderer?._imageInstancesDirtyReason !== 'image-slot-invalidated' ||
1258
- state?.imageCandidateIds?.size !== state?.imagePreparedIds?.size) return false;
1259
- const priorIds = Array.isArray(renderer.imageInstanceData?.nodeIds) ? renderer.imageInstanceData.nodeIds : [];
1260
- if (priorIds.length !== state.imagePreparedIds.size) return false;
1261
- for (let i = 0; i < priorIds.length; i++) {
1262
- const nodeId = priorIds[i];
1263
- if (!state.imagePreparedIds.has(nodeId) || renderer.imageAtlasSlots?.get?.(nodeId)?.ready !== true) return false;
1264
- }
1265
- renderer._clearImageInstancesDirty?.();
1266
- renderer._residentImageBufferReuseCount = Number(renderer._residentImageBufferReuseCount || 0) + 1;
1267
- return true;
1268
- }
1269
-
1270
- function prepareIdleResidentImageInstances(state) {
1271
- const renderer = state?.renderer;
1272
- const module = state?.module;
1273
- const nodeObjectsById = state?.nodeObjectsById;
1274
- if (!renderer || !module || !nodeObjectsById || renderer._disposed === true ||
1275
- renderer._module !== module || module.nodeObjectsById !== nodeObjectsById ||
1276
- renderer.isInLODMode !== false || module.isLoading === true ||
1277
- isPrewarmInteractionActive(module) || renderer._hasPendingImageAtlasWork?.() === true ||
1278
- state.imageCandidateIds?.size !== state.imagePreparedIds?.size ||
1279
- typeof renderer._updateImageInstanceData !== 'function' ||
1280
- typeof renderer._applyImageInstanceData !== 'function') return false;
1281
-
1282
- const committedIds = Array.isArray(renderer.imageInstanceData?.nodeIds)
1283
- ? renderer.imageInstanceData.nodeIds
1284
- : [];
1285
- const committedSet = new Set(committedIds);
1286
- let missingPreparedImage = false;
1287
- for (const nodeId of state.imagePreparedIds) {
1288
- if (!committedSet.has(nodeId)) {
1289
- missingPreparedImage = true;
1290
- break;
1291
- }
1292
- }
1293
- if (!missingPreparedImage && renderer._imageInstancesDirty !== true) return false;
1294
-
1295
- renderer._updateImageInstanceData(nodeObjectsById, true);
1296
- renderer._applyImageInstanceData();
1297
- renderer._lastAppliedImageAtlasSignature =
1298
- renderer._pendingImageAtlasPatchSignature ||
1299
- renderer._buildImageAtlasPatchSignature?.() || '';
1300
- renderer._pendingImageAtlasPatchSignature = '';
1301
- renderer._imageAtlasRebuildPending = false;
1302
- renderer._imageAtlasRebuildDeferredUntil = 0;
1303
- renderer._clearImageInstancesDirty?.();
1304
- renderer._syncResidentCountsAfterDelta?.();
1305
- if (renderer.instancedImageMesh) renderer.instancedImageMesh.visible = false;
1306
- renderer._residentGpuWarmKey = '';
1307
- renderer._residentGpuWarmOffscreenComplete = false;
1308
- renderer._residentImageIdlePatchCount = Number(renderer._residentImageIdlePatchCount || 0) + 1;
1309
- return true;
1310
- }
1311
-
1312
- function stagePreparedResidentLineRow(state, entry, lineData) {
1313
- const renderer = state?.renderer;
1314
- const model = entry?.model || null;
1315
- const nodeId = String(model?.id || model?.Id || '');
1316
- const nodeIds = renderer?.instanceData?.nodeIds;
1317
- const geometry = renderer?.instancedMesh?.geometry || null;
1318
- const lineCountAttr = geometry?.getAttribute?.('instanceLineCount') || null;
1319
- const lineHeightAttr = geometry?.getAttribute?.('instanceLineHeightPx') || null;
1320
- const linePaddingAttr = geometry?.getAttribute?.('instanceLinePaddingPx') || null;
1321
- const lineDataArray = renderer?.lineDataArray || null;
1322
- const rowCount = Number(renderer?.lineTextureRows || 0);
1323
- if (!nodeId || !Array.isArray(nodeIds) || !lineData || !lineCountAttr || !lineHeightAttr ||
1324
- !linePaddingAttr || !lineDataArray || rowCount <= 0) return false;
1325
- if (state.lineNodeIds !== nodeIds) {
1326
- state.lineNodeIds = nodeIds;
1327
- state.lineIndexById = new Map();
1328
- for (let i = 0; i < nodeIds.length; i++) state.lineIndexById.set(String(nodeIds[i] || ''), i);
1329
- }
1330
- const index = state.lineIndexById.get(nodeId);
1331
- const rowWidth = Math.floor(lineDataArray.length / rowCount);
1332
- if (!Number.isInteger(index) || index < 0 || index >= lineCountAttr.count || rowWidth <= 0) return false;
1333
- const lineCounts = renderer.instanceData.lineCounts || (renderer.instanceData.lineCounts = []);
1334
- const lineLengths = renderer.instanceData.lineLengths || (renderer.instanceData.lineLengths = []);
1335
- const lineHeights = renderer.instanceData.lineHeights || (renderer.instanceData.lineHeights = []);
1336
- const linePaddings = renderer.instanceData.linePaddings || (renderer.instanceData.linePaddings = []);
1337
- const lineCount = Number(lineData.lineCount || 0);
1338
- const lineHeight = Number(lineData.lineHeightPx || 24);
1339
- const paddingX = Number(lineData.paddingX || 0);
1340
- const paddingY = Number(lineData.paddingY || 0);
1341
- lineCounts[index] = lineCount;
1342
- lineHeights[index] = lineHeight;
1343
- linePaddings[index * 2] = paddingX;
1344
- linePaddings[index * 2 + 1] = paddingY;
1345
- lineCountAttr.setX(index, lineCount);
1346
- lineHeightAttr.setX(index, lineHeight);
1347
- linePaddingAttr.setXY(index, paddingX, paddingY);
1348
- const base = index * rowWidth;
1349
- for (let j = 0; j < rowWidth; j++) {
1350
- const value = Number(lineData.lineLengths?.[j] || 0);
1351
- lineLengths[base + j] = value;
1352
- lineDataArray[base + j] = Math.max(0, Math.min(255, Math.round(value * 255)));
1353
- }
1354
- state.lineRowsStaged = true;
1355
- state.preparedLineRowCount = Number(state.preparedLineRowCount || 0) + 1;
1356
- return true;
1357
- }
1358
-
1359
- function commitPreparedResidentLineRows(state) {
1360
- if (!state?.lineRowsStaged) return false;
1361
- const renderer = state.renderer;
1362
- const geometry = renderer?.instancedMesh?.geometry || null;
1363
- const lineCountAttr = geometry?.getAttribute?.('instanceLineCount') || null;
1364
- const lineHeightAttr = geometry?.getAttribute?.('instanceLineHeightPx') || null;
1365
- const linePaddingAttr = geometry?.getAttribute?.('instanceLinePaddingPx') || null;
1366
- if (!lineCountAttr || !lineHeightAttr || !linePaddingAttr || !renderer?.lineDataTexture) return false;
1367
- lineCountAttr.needsUpdate = true;
1368
- lineHeightAttr.needsUpdate = true;
1369
- linePaddingAttr.needsUpdate = true;
1370
- renderer.lineDataTexture.needsUpdate = true;
1371
- renderer.lineDataDirty = false;
1372
- renderer._lineDetailsPatchPending = false;
1373
- renderer._lastInstanceCount = Number(renderer.instanceData?.nodeIds?.length || 0);
1374
- renderer._residentGpuWarmKey = '';
1375
- renderer._residentLineBufferPrewarmCount = Number(state.preparedLineRowCount || 0);
1376
- state.lineRowsStaged = false;
1377
- return true;
1378
- }
1379
-
1380
- function prepareIdleResidentBuffers(state) {
1381
- const renderer = state?.renderer;
1382
- const module = state?.module;
1383
- const nodeObjectsById = state?.nodeObjectsById;
1384
- if (!renderer || !module || !nodeObjectsById || renderer._disposed === true ||
1385
- renderer._module !== module || module.nodeObjectsById !== nodeObjectsById ||
1386
- renderer.isInLODMode !== false || renderer._hasResidentLodInstances?.() === true ||
1387
- module.isLoading === true || isPrewarmInteractionActive(module) ||
1388
- typeof renderer._updateInstanceData !== 'function' || typeof renderer._applyInstanceData !== 'function') return false;
1389
- renderer._residentBuildPhase = 'initial-build';
1390
- renderer._updateInstanceData(nodeObjectsById);
1391
- renderer._applyInstanceData();
1392
- renderer._syncResidentCountsAfterDelta?.();
1393
- renderer._lineDetailsPatchPending = renderer._residentLineFallbackUsed === true;
1394
- renderer._clearInstancesDirty?.();
1395
- renderer._clearImageInstancesDirty?.();
1396
- renderer._positionsOnlyDirty = false;
1397
- renderer._dirtyPositionIds?.clear?.();
1398
- renderer._residentRebuildPending = false;
1399
- renderer._residentRebuildDeferredUntil = 0;
1400
- renderer._noteResidentFullBuild?.('initial-build', 'MID');
1401
- renderer._residentIdleBuildCount = Number(renderer._residentIdleBuildCount || 0) + 1;
1402
- renderer._residentLineBufferPrewarmCount = Number(renderer.instanceData?.nodeIds?.length || 0);
1403
- renderer._residentGpuWarmKey = '';
1404
- [renderer.instancedMesh, renderer.instancedBorderLineMesh, renderer.instancedLineMesh,
1405
- renderer.instancedHaloMesh, renderer.instancedConsoleMesh, renderer.instancedImageMesh]
1406
- .filter(Boolean).forEach(mesh => { mesh.visible = false; });
1407
- renderer._setInstancedAgentBadgeVisibility?.(false);
1408
- renderer._setInstancedFarInsetBorderVisibility?.(false);
1409
- return renderer._hasResidentLodInstances?.() === true;
1410
- }
1411
-
1412
- function retryResidentPreparation(state, delay = 80) {
1413
- if (!state || state.retryTimer) return;
1414
- state.retryTimer = setTimeout(() => {
1415
- state.retryTimer = null;
1416
- if (residentLinePrewarmStates.get(state.renderer) !== state || state.renderer?._disposed === true ||
1417
- state.renderer?._module !== state.module || state.module?.nodeObjectsById !== state.nodeObjectsById) return;
1418
- scheduleResidentLinePrewarm(state.renderer, state.module, state.nodeObjectsById);
1419
- }, delay);
1420
- }
1421
-
1422
- function queueResidentLinePrewarm(state) {
1423
- if (!state || state.scheduled || state.complete) return;
1424
- state.scheduled = true;
1425
- const run = deadline => {
1426
- state.scheduled = false;
1427
- if (residentLinePrewarmStates.get(state.renderer) !== state || state.renderer?._disposed === true ||
1428
- state.renderer?._module !== state.module || state.module?.nodeObjectsById !== state.nodeObjectsById) return;
1429
- if (state.module?.isLoading === true ||
1430
- state.key !== `${Number(state.renderer?._instancesDirtySerial || 0)}:${Number(state.nodeObjectsById.size || 0)}` ||
1431
- isPrewarmInteractionActive(state.module)) {
1432
- retryResidentPreparation(state);
1433
- return;
1434
- }
1435
- if (!state.entries) state.entries = Array.from(state.nodeObjectsById.values());
1436
- const startedAt = performance.now();
1437
- let processed = 0;
1438
- while (state.cursor < state.entries.length && processed < 4) {
1439
- const entry = state.entries[state.cursor++];
1440
- const model = entry?.model || null;
1441
- const contentType = String(model?.contentType ?? model?.ContentType ?? '').toLowerCase();
1442
- if (model && !['image', 'video', 'youtube', 'pdf', 'audio', 'webpage', 'iframe'].includes(contentType)) {
1443
- const width = Number(model.width || 400);
1444
- const height = Number(model.height || 200);
1445
- if (entry.lodSeed === undefined) entry.lodSeed = Math.random() * 100;
1446
- if (!getPreparedLineData(state.renderer, entry, width, height)) {
1447
- rememberPreparedLine(state.renderer, entry, width, height,
1448
- state.renderer._getLineDataForNode?.(model, entry.lodSeed, width, height, entry));
1449
- }
1450
- stagePreparedResidentLineRow(state, entry,
1451
- getPreparedLineData(state.renderer, entry, width, height));
1452
- state.prepared++;
1453
- } else if (model && contentType === 'image') {
1454
- const nodeId = String(model.id || model.Id || '');
1455
- if (nodeId) state.imageCandidateIds.add(nodeId);
1456
- const slot = state.imagePass > 0 ? state.renderer._ensureImageLodThumbnail?.(entry) || null : null;
1457
- if (slot?.ready === true) {
1458
- if (nodeId) state.imagePreparedIds.add(nodeId);
1459
- } else {
1460
- state.pendingImageEntries.push(entry);
1461
- }
1462
- }
1463
- processed++;
1464
- if (performance.now() - startedAt >= 3 && Number(deadline?.timeRemaining?.() || 0) < 1) break;
1465
- }
1466
- if (state.cursor >= state.entries.length) {
1467
- if (state.pendingImageEntries.length > 0 && state.imagePass < 20) {
1468
- const isFirstImagePass = state.imagePass === 0;
1469
- if (isFirstImagePass) commitPreparedResidentLineRows(state);
1470
- if (isFirstImagePass) prepareImageAtlasCapacity(state.renderer, state.imageCandidateIds.size);
1471
- state.entries = Array.from(new Set(state.pendingImageEntries));
1472
- state.pendingImageEntries.length = 0;
1473
- state.cursor = 0;
1474
- state.imagePass++;
1475
- if (isFirstImagePass) {
1476
- queueResidentLinePrewarm(state);
1477
- } else {
1478
- setTimeout(() => {
1479
- if (residentLinePrewarmStates.get(state.renderer) === state) queueResidentLinePrewarm(state);
1480
- }, 250);
1481
- }
1482
- return;
1483
- }
1484
- prepareIdleResidentBuffers(state);
1485
- commitPreparedResidentLineRows(state);
1486
- state.complete = true;
1487
- state.renderer._residentLinePrewarmCount = state.prepared;
1488
- state.renderer._residentImagePrewarmCount = state.imagePreparedIds.size;
1489
- state.renderer._residentImagePrewarmCandidateCount = state.imageCandidateIds.size;
1490
- state.renderer._residentImagePrewarmComplete = state.pendingImageEntries.length === 0;
1491
- if (state.renderer.isInLODMode === true && state.renderer._lineDetailsPatchPending === true) {
1492
- state.renderer._markLineDetailsDirty?.();
1493
- }
1494
- prepareIdleResidentImageInstances(state);
1495
- queueResidentGpuWarm(state);
1496
- state.renderer._scheduleFullResCssFringePrewarm?.(state.nodeObjectsById, state.module);
1497
- return;
1498
- }
1499
- queueResidentLinePrewarm(state);
1500
- };
1501
- if (typeof globalThis.requestIdleCallback === 'function') {
1502
- globalThis.requestIdleCallback(run, { timeout: 120 });
1503
- } else {
1504
- setTimeout(() => run({ timeRemaining: () => 3, didTimeout: true }), 16);
1505
- }
1506
- }
1507
-
1508
- function getResidentGpuKey(renderer) {
1509
- const geometryKey = [renderer?.instancedMesh, renderer?.instancedBorderLineMesh, renderer?.instancedLineMesh,
1510
- renderer?.instancedHaloMesh, renderer?.instancedConsoleMesh, renderer?.instancedImageMesh]
1511
- .map(mesh => String(mesh?.geometry?.uuid || '-')).join(',');
1512
- return `${Number(renderer?._residentGpuContextGeneration || 0)}:` +
1513
- `${String(renderer?.lineDataTexture?.uuid || '-')}/${Number(renderer?.lineDataTexture?.version || 0)}:` +
1514
- `${String(renderer?.imageAtlasTexture?.uuid || '-')}/${Number(renderer?.imageAtlasTexture?.version || 0)}:` +
1515
- `${Number(renderer?.lineTextureRows || 0)}:${geometryKey}`;
1516
- }
1517
-
1518
- function invalidateResidentGpuWarm(renderer) {
1519
- if (!renderer) return;
1520
- renderer._residentGpuContextGeneration = Number(renderer._residentGpuContextGeneration || 0) + 1;
1521
- renderer._residentGpuWarmKey = '';
1522
- renderer._residentGpuWarmComplete = false;
1523
- renderer._residentGpuWarmOffscreenComplete = false;
1524
- renderer._residentImageAtlasWarmVersion = -1;
1525
- }
1526
-
1527
- function ensureResidentGpuContextTracking(renderer) {
1528
- const canvas = renderer?.renderer?.domElement || null;
1529
- if (!canvas?.addEventListener || renderer._residentGpuContextCanvas === canvas) return;
1530
- const previousCanvas = renderer._residentGpuContextCanvas;
1531
- if (previousCanvas?.removeEventListener) {
1532
- previousCanvas.removeEventListener('webglcontextlost', renderer._residentGpuContextLostHandler);
1533
- previousCanvas.removeEventListener('webglcontextrestored', renderer._residentGpuContextRestoredHandler);
1534
- }
1535
- const lost = () => {
1536
- renderer._residentGpuContextLost = true;
1537
- invalidateResidentGpuWarm(renderer);
1538
- };
1539
- const restored = () => {
1540
- renderer._residentGpuContextLost = false;
1541
- invalidateResidentGpuWarm(renderer);
1542
- setTimeout(() => {
1543
- const state = residentLinePrewarmStates.get(renderer);
1544
- if (state && renderer?._disposed !== true) queueResidentGpuWarm(state);
1545
- }, 0);
1546
- };
1547
- canvas.addEventListener('webglcontextlost', lost);
1548
- canvas.addEventListener('webglcontextrestored', restored);
1549
- renderer._residentGpuContextCanvas = canvas;
1550
- renderer._residentGpuContextLostHandler = lost;
1551
- renderer._residentGpuContextRestoredHandler = restored;
1552
- }
1553
-
1554
- function renderResidentWarmScene(webglRenderer, THREE, warmScene, warmCamera) {
1555
- const gl = webglRenderer?.getContext?.();
1556
- if (!gl || gl.isContextLost?.() === true) return false;
1557
- if (typeof webglRenderer.getRenderTarget !== 'function' || typeof webglRenderer.setRenderTarget !== 'function' ||
1558
- typeof webglRenderer.render !== 'function' || !THREE?.WebGLRenderTarget) return null;
1559
- const previousTarget = webglRenderer.getRenderTarget();
1560
- const previousFace = webglRenderer.getActiveCubeFace?.() ?? 0;
1561
- const previousMip = webglRenderer.getActiveMipmapLevel?.() ?? 0;
1562
- const warmTarget = new THREE.WebGLRenderTarget(1, 1, { depthBuffer: false, stencilBuffer: false });
1563
- if (warmTarget.texture) {
1564
- warmTarget.texture.generateMipmaps = false;
1565
- const encoding = previousTarget?.texture?.encoding ?? webglRenderer.outputEncoding;
1566
- if (encoding != null) warmTarget.texture.encoding = encoding;
1567
- }
1568
- try {
1569
- webglRenderer.setRenderTarget(warmTarget);
1570
- webglRenderer.render(warmScene, warmCamera);
1571
- return gl.isContextLost?.() !== true;
1572
- } finally {
1573
- try {
1574
- webglRenderer.setRenderTarget(previousTarget, previousFace, previousMip);
1575
- } finally {
1576
- warmTarget.dispose?.();
1577
- }
1578
- }
1579
- }
1580
-
1581
- function retryResidentGpuWarm(state) {
1582
- if (!state || state.gpuRetryTimer) return;
1583
- state.gpuRetryTimer = setTimeout(() => {
1584
- state.gpuRetryTimer = null;
1585
- if (residentLinePrewarmStates.get(state.renderer) === state) queueResidentGpuWarm(state);
1586
- }, GPU_WARM_RETRY_DELAY_MS);
1587
- }
1588
-
1589
- function queueResidentGpuWarm(state) {
1590
- if (!state?.complete || state.gpuScheduled) return;
1591
- const renderer = state.renderer;
1592
- if (residentLinePrewarmStates.get(renderer) !== state || renderer?._disposed === true ||
1593
- renderer?._module !== state.module || state.module?.nodeObjectsById !== state.nodeObjectsById ||
1594
- state.module?.isLoading === true ||
1595
- state.key !== `${Number(renderer?._instancesDirtySerial || 0)}:${Number(state.nodeObjectsById.size || 0)}`) return;
1596
- if (isPrewarmInteractionActive(state.module)) {
1597
- retryResidentGpuWarm(state);
1598
- return;
1599
- }
1600
- const webglRenderer = renderer?.renderer || null;
1601
- ensureResidentGpuContextTracking(renderer);
1602
- const gl = webglRenderer?.getContext?.();
1603
- if (renderer?._residentGpuContextLost === true || gl?.isContextLost?.() === true) return;
1604
- const gpuKey = getResidentGpuKey(renderer);
1605
- if (!webglRenderer || renderer._residentGpuWarmKey === gpuKey) return;
1606
- if (renderer._hasPendingImageAtlasWork?.() === true) {
1607
- retryResidentGpuWarm(state);
1608
- return;
1609
- }
1610
- state.gpuScheduled = true;
1611
- const run = () => {
1612
- state.gpuScheduled = false;
1613
- if (residentLinePrewarmStates.get(renderer) !== state || renderer?._disposed === true ||
1614
- renderer?._module !== state.module || state.module?.nodeObjectsById !== state.nodeObjectsById ||
1615
- state.module?.isLoading === true || state.key !== `${Number(renderer._instancesDirtySerial || 0)}:${Number(state.nodeObjectsById.size || 0)}`) return;
1616
- if (isPrewarmInteractionActive(state.module) || renderer._hasPendingImageAtlasWork?.() === true) {
1617
- retryResidentGpuWarm(state);
1618
- return;
1619
- }
1620
- if (renderer?._residentGpuContextLost === true || webglRenderer?.getContext?.()?.isContextLost?.() === true) return;
1621
- try {
1622
- if (renderer.lineDataTexture) webglRenderer.initTexture?.(renderer.lineDataTexture);
1623
- if (renderer.imageAtlasTexture && Number(renderer.imageAtlasSlots?.size || 0) > 0) {
1624
- webglRenderer.initTexture?.(renderer.imageAtlasTexture);
1625
- renderer._residentImageAtlasWarmVersion = Number(renderer.imageAtlasTexture.version || 0);
1626
- }
1627
- const THREE = globalThis.THREE;
1628
- if (THREE?.Scene && typeof webglRenderer.compile === 'function' && state.module?.camera) {
1629
- const warmScene = new THREE.Scene();
1630
- try {
1631
- [renderer.instancedMesh, renderer.instancedBorderLineMesh, renderer.instancedLineMesh,
1632
- renderer.instancedHaloMesh, renderer.instancedConsoleMesh, renderer.instancedImageMesh]
1633
- .filter(Boolean)
1634
- .forEach(mesh => {
1635
- const clone = mesh.clone?.();
1636
- if (!clone) return;
1637
- clone.visible = true;
1638
- clone.frustumCulled = false;
1639
- warmScene.add(clone);
1640
- });
1641
- const warmCamera = state.module.camera.clone?.() || state.module.camera;
1642
- webglRenderer.compile(warmScene, warmCamera);
1643
- const offscreenResult = renderResidentWarmScene(webglRenderer, THREE, warmScene, warmCamera);
1644
- if (offscreenResult === false) return;
1645
- renderer._residentGpuWarmOffscreenComplete = offscreenResult === true;
1646
- } finally {
1647
- warmScene.clear?.();
1648
- }
1649
- }
1650
- renderer._residentGpuWarmKey = getResidentGpuKey(renderer);
1651
- renderer._residentGpuWarmComplete = true;
1652
- reusePreparedImageInstances(renderer, state);
1653
- state.gpuFailureCount = 0;
1654
- } catch (error) {
1655
- console.warn('[RenderPlan] Resident GPU warmup deferred.', error);
1656
- state.gpuFailureCount = Number(state.gpuFailureCount || 0) + 1;
1657
- if (state.gpuFailureCount <= 3) retryResidentGpuWarm(state);
1658
- }
1659
- };
1660
- if (typeof globalThis.requestIdleCallback === 'function') {
1661
- globalThis.requestIdleCallback(run, { timeout: 300 });
1662
- } else {
1663
- setTimeout(run, 32);
1664
- }
1665
- }
1666
-
1667
- function scheduleResidentLinePrewarm(renderer, module, nodeObjectsById) {
1668
- if (!renderer || !module || !nodeObjectsById?.values || module.isLoading === true) return;
1669
- scheduleResidentCssLayoutWarm(renderer, module, nodeObjectsById);
1670
- const key = `${Number(renderer._instancesDirtySerial || 0)}:${Number(nodeObjectsById.size || 0)}`;
1671
- let state = residentLinePrewarmStates.get(renderer);
1672
- if (!state || state.key !== key || state.nodeObjectsById !== nodeObjectsById) {
1673
- state = {
1674
- renderer, module, nodeObjectsById, key, entries: null, cursor: 0, prepared: 0,
1675
- scheduled: false, retryTimer: null, complete: false, gpuScheduled: false, gpuRetryTimer: null, gpuFailureCount: 0,
1676
- imagePass: 0, imageCandidateIds: new Set(), imagePreparedIds: new Set(), pendingImageEntries: []
1677
- };
1678
- residentLinePrewarmStates.set(renderer, state);
1679
- }
1680
- if (state.complete && renderer.isInLODMode === false &&
1681
- renderer._imageInstancesDirtyReason === 'image-slot-invalidated') {
1682
- const staleImageEntries = [];
1683
- for (const nodeId of state.imageCandidateIds) {
1684
- if (renderer.imageAtlasSlots?.get?.(nodeId)?.ready === true) continue;
1685
- const entry = nodeObjectsById.get?.(nodeId) || null;
1686
- if (entry) {
1687
- state.imagePreparedIds.delete(nodeId);
1688
- staleImageEntries.push(entry);
1689
- }
1690
- }
1691
- if (staleImageEntries.length > 0) {
1692
- state.entries = staleImageEntries;
1693
- state.cursor = 0;
1694
- state.complete = false;
1695
- state.imagePass = 1;
1696
- state.pendingImageEntries.length = 0;
1697
- }
1698
- }
1699
- queueResidentLinePrewarm(state);
1700
- if (state.complete) {
1701
- prepareIdleResidentImageInstances(state);
1702
- queueResidentGpuWarm(state);
1703
- renderer._scheduleFullResCssFringePrewarm?.(nodeObjectsById, module);
1704
- }
1705
- }
1706
-
1707
- function areResidentLinesPrepared(renderer, nodeObjectsById, nodeIds) {
1708
- if (!renderer || !nodeObjectsById?.get || !Array.isArray(nodeIds)) return false;
1709
- for (let i = 0; i < nodeIds.length; i++) {
1710
- const entry = nodeObjectsById.get(nodeIds[i]);
1711
- const model = entry?.model || null;
1712
- if (!model || !getPreparedLineData(renderer, entry, model.width || 400, model.height || 200)) return false;
1713
- }
1714
- return true;
1715
- }
1716
-
1717
- function initialLineTextureRows(maxInstances) {
1718
- return Math.min(Math.max(1, Number(maxInstances || 1)), INITIAL_LINE_TEXTURE_ROWS);
1719
- }
1720
-
1721
- function ensureLineTextureCapacity(renderer, requiredCount, width) {
1722
- const currentRows = Number(renderer?.lineTextureRows || 0);
1723
- const maxRows = Math.max(1, Number(renderer?.maxInstances || requiredCount || 1));
1724
- if (!renderer || Number(requiredCount || 0) <= currentRows || currentRows >= maxRows) return false;
1725
- let nextRows = Math.max(INITIAL_LINE_TEXTURE_ROWS, currentRows || 1);
1726
- while (nextRows < requiredCount && nextRows < maxRows) nextRows *= 2;
1727
- nextRows = Math.min(nextRows, maxRows);
1728
- const THREE = globalThis.THREE;
1729
- if (!THREE?.DataTexture) return false;
1730
- const rowWidth = Math.max(1, Number(width || 1));
1731
- const data = new Uint8Array(nextRows * rowWidth);
1732
- data.set(renderer.lineDataArray?.subarray?.(0, data.length) || []);
1733
- const previous = renderer.lineDataTexture || null;
1734
- const texture = new THREE.DataTexture(data, rowWidth, nextRows, THREE.RedFormat, THREE.UnsignedByteType);
1735
- texture.minFilter = previous?.minFilter ?? THREE.NearestFilter;
1736
- texture.magFilter = previous?.magFilter ?? THREE.NearestFilter;
1737
- texture.wrapS = previous?.wrapS ?? THREE.ClampToEdgeWrapping;
1738
- texture.wrapT = previous?.wrapT ?? THREE.ClampToEdgeWrapping;
1739
- texture.needsUpdate = true;
1740
- renderer.lineDataArray = data;
1741
- renderer.lineDataTexture = texture;
1742
- renderer.lineTextureRows = nextRows;
1743
- renderer._residentGpuWarmKey = '';
1744
- const uniforms = renderer.instancedLineMesh?.material?.uniforms || null;
1745
- if (uniforms?.uLineDataTex) uniforms.uLineDataTex.value = texture;
1746
- if (uniforms?.uLineDataSize?.value?.set) uniforms.uLineDataSize.value.set(rowWidth, nextRows);
1747
- previous?.dispose?.();
1748
- return true;
1749
- }
1750
-
1751
- function getFrameSampleState(renderer) {
1752
- let state = frameSampleStates.get(renderer);
1753
- if (!state) {
1754
- state = { samples: new Array(FRAME_SAMPLE_LIMIT), cursor: 0, count: 0 };
1755
- frameSampleStates.set(renderer, state);
1756
- }
1757
- return state;
1758
- }
1759
-
1760
- function recordFrame(renderer, profile) {
1761
- if (!renderer || !profile) return;
1762
- const state = getFrameSampleState(renderer);
1763
- const sections = profile.sections || {};
1764
- let viewSyncMs = 0;
1765
- for (let i = 0; i < VIEW_SYNC_SECTION_KEYS.length; i++) {
1766
- viewSyncMs += Number(sections[VIEW_SYNC_SECTION_KEYS[i]] || 0);
1767
- }
1768
- const sample = state.samples[state.cursor] || {};
1769
- sample.frameMs = Number(profile.durationMs || 0);
1770
- sample.visibilityMs = Number(sections.visibility || 0);
1771
- sample.viewSyncMs = viewSyncMs;
1772
- sample.css3dRenderMs = Number(sections.css3dRender || 0);
1773
- sample.stableFullResSkipped = renderer._lastFullResStablePlanSkipped === true;
1774
- state.samples[state.cursor] = sample;
1775
- state.cursor = (state.cursor + 1) % FRAME_SAMPLE_LIMIT;
1776
- state.count = Math.min(FRAME_SAMPLE_LIMIT, state.count + 1);
1777
- }
1778
-
1779
- function beginFrame(renderer) {
1780
- if (renderer) renderer._lastFullResStablePlanSkipped = false;
1781
- }
1782
-
1783
- function percentile(state, field, ratio) {
1784
- if (!state?.count) return 0;
1785
- const values = [];
1786
- for (let i = 0; i < state.count; i++) {
1787
- const value = Number(state.samples[i]?.[field] || 0);
1788
- if (Number.isFinite(value)) values.push(value);
1789
- }
1790
- if (values.length === 0) return 0;
1791
- values.sort((a, b) => a - b);
1792
- return Number(values[Math.max(0, Math.ceil(values.length * ratio) - 1)].toFixed(2));
1793
- }
1794
-
1795
- function getImageAtlasProbe(renderer) {
1796
- const canvas = renderer?.imageAtlasCanvas || null;
1797
- const readyEntry = Array.from(renderer?.imageAtlasSlots?.entries?.() || [])
1798
- .find(([, slot]) => slot?.ready === true) || null;
1799
- if (!canvas || !readyEntry) return '-';
1800
- try {
1801
- const slot = readyEntry[1];
1802
- const columns = Number(renderer.imageAtlasColumns || 1);
1803
- const tile = Math.max(1, Math.floor(Number(canvas.width || 1) / columns));
1804
- const col = Number(slot.slotIndex || 0) % columns;
1805
- const row = Math.floor(Number(slot.slotIndex || 0) / columns);
1806
- const context = canvas.getContext?.('2d', { alpha: false }) || null;
1807
- const pixel = context?.getImageData?.(
1808
- Math.min(canvas.width - 1, Math.floor(col * tile + tile * 0.5)),
1809
- Math.min(canvas.height - 1, Math.floor(row * tile + tile * 0.5)), 1, 1)?.data;
1810
- let colored = 0;
1811
- let sampled = 0;
1812
- for (const [, candidate] of Array.from(renderer.imageAtlasSlots.entries()).slice(0, 24)) {
1813
- if (candidate?.ready !== true) continue;
1814
- const candidateCol = Number(candidate.slotIndex || 0) % columns;
1815
- const candidateRow = Math.floor(Number(candidate.slotIndex || 0) / columns);
1816
- const sample = context?.getImageData?.(
1817
- Math.min(canvas.width - 1, Math.floor(candidateCol * tile + tile * 0.5)),
1818
- Math.min(canvas.height - 1, Math.floor(candidateRow * tile + tile * 0.5)), 1, 1)?.data;
1819
- if (sample) {
1820
- sampled++;
1821
- if (Math.abs(sample[0] - 238) + Math.abs(sample[1] - 242) + Math.abs(sample[2] - 247) > 12) colored++;
1822
- }
1823
- }
1824
- const cpuUv = Array.from(renderer?.imageInstanceData?.uvRects || []).slice(0, 4)
1825
- .map(value => Number(value || 0).toFixed(4)).join(',');
1826
- const uvAttr = renderer?.instancedImageMesh?.geometry?.getAttribute?.('instanceUvRect') || null;
1827
- const gpuUv = uvAttr && uvAttr.count > 0
1828
- ? [uvAttr.getX(0), uvAttr.getY(0), uvAttr.getZ(0), uvAttr.getW(0)]
1829
- .map(value => Number(value || 0).toFixed(4)).join(',')
1830
- : '-';
1831
- return pixel ? `${pixel[0]},${pixel[1]},${pixel[2]} · color ${colored}/${sampled} · uv ${cpuUv}/${gpuUv}` : '-';
1832
- } catch { return 'blocked'; }
1833
- }
1834
-
1835
- function getDiagnostics(renderer) {
1836
- const state = renderer ? frameSampleStates.get(renderer) : null;
1837
- let stableFullResSampleCount = 0;
1838
- for (let i = 0; i < Number(state?.count || 0); i++) {
1839
- if (state.samples[i]?.stableFullResSkipped === true) stableFullResSampleCount++;
1840
- }
1841
- return {
1842
- build: BUILD_ID,
1843
- stableFullResSkipCount: Number(renderer?._fullResStablePlanSkipCount || 0),
1844
- skippedLastPlan: renderer?._lastFullResStablePlanSkipped === true,
1845
- sampleCount: Number(state?.count || 0),
1846
- stableFullResSampleCount,
1847
- frameP50Ms: percentile(state, 'frameMs', 0.50),
1848
- frameP95Ms: percentile(state, 'frameMs', 0.95),
1849
- visibilityP95Ms: percentile(state, 'visibilityMs', 0.95),
1850
- viewSyncP95Ms: percentile(state, 'viewSyncMs', 0.95),
1851
- css3dRenderP95Ms: percentile(state, 'css3dRenderMs', 0.95),
1852
- fullResCssStableReuseCount: Number(renderer?._fullResCssStableReuseCount || 0),
1853
- cssMediaFrameDomReuseCount,
1854
- cssMediaFrameDomApplyCount,
1855
- residentLinePrewarmCount: Number(renderer?._residentLinePrewarmCount || 0),
1856
- residentLineBufferPrewarmCount: Number(renderer?._residentLineBufferPrewarmCount || 0),
1857
- residentIdleBuildCount: Number(renderer?._residentIdleBuildCount || 0),
1858
- residentImagePrewarmCount: Number(renderer?._residentImagePrewarmCount || 0),
1859
- residentImagePrewarmCandidateCount: Number(renderer?._residentImagePrewarmCandidateCount || 0),
1860
- residentImageBufferReuseCount: Number(renderer?._residentImageBufferReuseCount || 0),
1861
- residentImageIdlePatchCount: Number(renderer?._residentImageIdlePatchCount || 0),
1862
- residentImageInstanceCount: Number(renderer?.instancedImageMesh?.geometry?.instanceCount || 0),
1863
- residentImageMeshVisible: renderer?.instancedImageMesh?.visible === true,
1864
- residentImageAtlasReadyCount: Array.from(renderer?.imageAtlasSlots?.values?.() || [])
1865
- .filter(slot => slot?.ready === true).length,
1866
- residentImageAtlasProbe: getImageAtlasProbe(renderer),
1867
- residentBuildPhase: String(renderer?._residentBuildPhase || ''),
1868
- residentFullBuildCount: Number(renderer?._residentFullBuildCount || 0),
1869
- residentLastFullBuildReason: String(renderer?._lastResidentFullBuildReason || ''),
1870
- residentInstancesDirtyReason: renderer?._instancesDirty === true
1871
- ? String(renderer?._instancesDirtyReason || 'unknown')
1872
- : '',
1873
- residentInstancesDirtySerial: Number(renderer?._instancesDirtySerial || 0),
1874
- residentLastNodeCount: Number(renderer?._lastNodeCount || 0),
1875
- residentEligibleTextLikeCount: Number(renderer?._cachedEligibleTextLikeCount || 0),
1876
- residentBufferNodeCount: Number(renderer?.instanceData?.nodeIds?.length || 0),
1877
- residentCssParkCount: Number(renderer?._residentCssParkCount || 0),
1878
- residentCssRestoreCount: Number(renderer?._residentCssRestoreCount || 0),
1879
- residentCssRestoreMissCount: Number(renderer?._residentCssRestoreMissCount || 0),
1880
- residentCssLayoutWarmCount: Number(renderer?._residentCssLayoutWarmCount || 0),
1881
- fullResCssFringePrewarmCount: Number(renderer?._fullResCssFringePrewarmCount || 0),
1882
- fullResCssFringePrewarmCandidateCount: Number(renderer?._fullResCssFringePrewarmCandidateCount || 0),
1883
- fullResCssFringeLayoutWarmCount: Number(renderer?._fullResCssFringeLayoutWarmCount || 0),
1884
- residentStableLineReuseCount: Number(renderer?._residentStableLineReuseCount || 0),
1885
- residentBoostClearCount: Number(renderer?._residentBoostClearCount || 0),
1886
- animatedGifFallbackCandidateScanCount: Number(renderer?._animatedGifFallbackCandidateScanCount || 0),
1887
- animatedGifFallbackCandidateCacheHitCount: Number(renderer?._animatedGifFallbackCandidateCacheHitCount || 0),
1888
- activeCssMediaFallbackCountScanCount: Number(renderer?._activeCssMediaFallbackCountScanCount || 0),
1889
- activeCssMediaFallbackCountCacheHitCount: Number(renderer?._activeCssMediaFallbackCountCacheHitCount || 0),
1890
- lineTextureRows: Number(renderer?.lineTextureRows || 0),
1891
- residentGpuWarmComplete: !!renderer &&
1892
- renderer._hasPendingImageAtlasWork?.() !== true &&
1893
- renderer._residentGpuWarmKey === getResidentGpuKey(renderer),
1894
- residentGpuBufferWarmComplete: !!renderer && renderer._residentGpuWarmOffscreenComplete === true &&
1895
- renderer._residentGpuWarmKey === getResidentGpuKey(renderer),
1896
- residentAtlasWarmComplete: !!renderer && Number(renderer.imageAtlasSlots?.size || 0) > 0 &&
1897
- renderer._hasPendingImageAtlasWork?.() !== true &&
1898
- Number(renderer._residentImageAtlasWarmVersion ?? -1) === Number(renderer.imageAtlasTexture?.version || 0)
1899
- };
1900
- }
1901
-
1902
- function resetDiagnostics(renderer) {
1903
- if (!renderer) return;
1904
- frameSampleStates.delete(renderer);
1905
- renderer._fullResStablePlanSkipCount = 0;
1906
- renderer._lastFullResStablePlanSkipped = false;
1907
- renderer._fullResCssStableReuseCount = 0;
1908
- cssMediaFrameDomReuseCount = 0;
1909
- cssMediaFrameDomApplyCount = 0;
1910
- }
1911
-
1912
- window.MindMapRenderPlan = Object.freeze({
1913
- configureImageAtlasTexture,
1914
- getImageAtlasOutputColorChunk,
1915
- getLocalSnapGridDistanceOpacity,
1916
- shouldUseInteractiveRendererDpr,
1917
- isRendererDprInteractionActive,
1918
- getCameraOnlyWebglBlockerMask,
1919
- getCameraOnlyWebglBlockerNames,
1920
- syncCommittedResidentTextCount,
1921
- clearFullResImageVisuals,
1922
- buildFullResKey,
1923
- shouldSkipStableFullRes,
1924
- commitStableFullRes,
1925
- recordStableFullRes,
1926
- scheduleResidentLinePrewarm,
1927
- resolveResidentLineData,
1928
- getPreparedLineData,
1929
- areResidentLinesPrepared,
1930
- initialLineTextureRows,
1931
- ensureLineTextureCapacity,
1932
- renderResidentWarmScene,
1933
- prepareImageAtlasCapacity,
1934
- prepareImageAtlasForEntries,
1935
- uploadImageAtlasTile,
1936
- scheduleImageAtlasUpload,
1937
- clearScheduledImageAtlasUpload,
1938
- fallbackBatch,
1939
- reuseCssMediaFrameDom,
1940
- reuseStableVisibleCss,
1941
- reuseActiveCssMediaFallback,
1942
- hasAnimatedGifCssFallbackCandidates,
1943
- invalidateAnimatedGifCssFallbackCandidateCache,
1944
- getActiveCssMediaFallbackCountCached,
1945
- invalidateActiveCssMediaFallbackCountCache,
1946
- markLodImageCssFallbacksChanged,
1947
- createTrackedLodImageCssFallbackSet,
1948
- hasActionableResidentLineDetails,
1949
- hasResidentDirtyWork,
1950
- hasPendingNearCssWarmup,
1951
- reusePreparedImageInstances,
1952
- prepareIdleResidentImageInstances,
1953
- stagePreparedResidentLineRow,
1954
- commitPreparedResidentLineRows,
1955
- prepareIdleResidentBuffers,
1956
- beginResidentCssTransition,
1957
- cachePreparedResidentCss,
1958
- scheduleResidentCssLayoutWarm,
1959
- parkFullResCss,
1960
- parkReadyResidentImage,
1961
- restoreParkedFullResCss,
1962
- completeFullResTransition,
1963
- ensureResidentLineDetails,
1964
- beginFrame,
1965
- recordFrame,
1966
- getDiagnostics,
1967
- resetDiagnostics
1968
- });
1969
-
1970
- window.MindCanvasBuildInfo?.registerPart?.('renderPlan', BUILD_ID);
1971
- })();
1
+ (function () {
2
+ 'use strict';
3
+
4
+ const BUILD_ID = '20260817-grid-distance-fade-v45';
5
+ const FRAME_SAMPLE_LIMIT = 240;
6
+ const INITIAL_LINE_TEXTURE_ROWS = 1024;
7
+ const GPU_WARM_RETRY_DELAY_MS = 120;
8
+ const IMAGE_ATLAS_TILE_SIZE = 128;
9
+ const IMAGE_ATLAS_UPLOAD_SETTLE_MS = 1000;
10
+ const IMAGE_ATLAS_UPLOAD_MAX_WAIT_MS = 3500;
11
+ const LOCAL_SNAP_GRID_FADE_START_Z = 9000;
12
+ const LOCAL_SNAP_GRID_FADE_END_Z = 30000;
13
+ const frameSampleStates = new WeakMap();
14
+ const residentLinePrewarmStates = new WeakMap();
15
+ const residentTransitionStates = new WeakMap();
16
+ const cssMediaFrameDomStates = new WeakMap();
17
+ const imageAtlasUploadStates = new WeakMap();
18
+ let cssMediaFrameDomReuseCount = 0;
19
+ let cssMediaFrameDomApplyCount = 0;
20
+ const RESIDENT_CSS_CACHE_TEXT_TYPES = new Set(['text', 'note', 'memo', 'markdown', 'code', 'csv-table']);
21
+ const VIEW_SYNC_SECTION_KEYS = [
22
+ 'fullResSetup', 'fullResImages', 'fullResCssQueue', 'fullResHandoff', 'fullResOther',
23
+ 'lodCleanup', 'lodNodeScan', 'lodResidentApply', 'lodLinePatch', 'lodImageInstances',
24
+ 'lodPositionPatch', 'lodFallbacks', 'lodOther'
25
+ ];
26
+ const CAMERA_ONLY_WEBGL_BLOCKERS = Object.freeze({
27
+ NotCameraOnly: 1 << 0,
28
+ Css3dCameraPathUnavailable: 1 << 1,
29
+ WebglDisabled: 1 << 2,
30
+ BoardLoading: 1 << 3,
31
+ ResidentLod: 1 << 4,
32
+ NonCameraUpdate: 1 << 5,
33
+ ThemeAnimation: 1 << 6,
34
+ WebglTheme: 1 << 7,
35
+ CssCoverageIncomplete: 1 << 8,
36
+ FullResHandoff: 1 << 9,
37
+ ResidentMeshVisible: 1 << 10,
38
+ ImageVisual: 1 << 11,
39
+ AnimatedImageStatus: 1 << 12,
40
+ CursorVisual: 1 << 13,
41
+ DebugVisual: 1 << 14,
42
+ FullResGlVisual: 1 << 15
43
+ });
44
+ const CAMERA_ONLY_WEBGL_BLOCKER_NAMES = Object.freeze([
45
+ [CAMERA_ONLY_WEBGL_BLOCKERS.NotCameraOnly, 'not-camera-only'],
46
+ [CAMERA_ONLY_WEBGL_BLOCKERS.Css3dCameraPathUnavailable, 'css3d-camera-path-unavailable'],
47
+ [CAMERA_ONLY_WEBGL_BLOCKERS.WebglDisabled, 'webgl-disabled'],
48
+ [CAMERA_ONLY_WEBGL_BLOCKERS.BoardLoading, 'board-loading'],
49
+ [CAMERA_ONLY_WEBGL_BLOCKERS.ResidentLod, 'resident-lod'],
50
+ [CAMERA_ONLY_WEBGL_BLOCKERS.NonCameraUpdate, 'non-camera-update'],
51
+ [CAMERA_ONLY_WEBGL_BLOCKERS.ThemeAnimation, 'theme-animation'],
52
+ [CAMERA_ONLY_WEBGL_BLOCKERS.WebglTheme, 'webgl-theme'],
53
+ [CAMERA_ONLY_WEBGL_BLOCKERS.CssCoverageIncomplete, 'css-coverage-incomplete'],
54
+ [CAMERA_ONLY_WEBGL_BLOCKERS.FullResHandoff, 'fullres-handoff'],
55
+ [CAMERA_ONLY_WEBGL_BLOCKERS.ResidentMeshVisible, 'resident-mesh-visible'],
56
+ [CAMERA_ONLY_WEBGL_BLOCKERS.ImageVisual, 'image-visual'],
57
+ [CAMERA_ONLY_WEBGL_BLOCKERS.AnimatedImageStatus, 'animated-image-status'],
58
+ [CAMERA_ONLY_WEBGL_BLOCKERS.CursorVisual, 'cursor-visual'],
59
+ [CAMERA_ONLY_WEBGL_BLOCKERS.DebugVisual, 'debug-visual'],
60
+ [CAMERA_ONLY_WEBGL_BLOCKERS.FullResGlVisual, 'fullres-gl-visual']
61
+ ]);
62
+
63
+ function isWheelOnlyCameraNavigation(module) {
64
+ const hasWheelZoom = module?.isZooming === true || module?._wheelZoomBurstActive === true;
65
+ if (!hasWheelZoom) return false;
66
+ return !(
67
+ module?.isPanning === true ||
68
+ module?._panSmoothingActive === true ||
69
+ module?.isDraggingNode === true ||
70
+ module?.isDraggingMultipleNodes === true ||
71
+ module?.isResizing === true ||
72
+ module?.isWindowResizing === true
73
+ );
74
+ }
75
+
76
+ function getLocalSnapGridDistanceOpacity(cameraZ) {
77
+ const parsedCameraZ = Math.abs(Number(cameraZ));
78
+ const safeCameraZ = Number.isFinite(parsedCameraZ) ? Math.max(1, parsedCameraZ) : 1;
79
+ const baseOpacity = Math.max(
80
+ 0.38,
81
+ Math.min(0.64, safeCameraZ <= 1800 ? 0.60 : 0.60 - ((safeCameraZ - 1800) / 36000))
82
+ );
83
+ if (safeCameraZ <= LOCAL_SNAP_GRID_FADE_START_Z) {
84
+ return baseOpacity;
85
+ }
86
+ if (safeCameraZ >= LOCAL_SNAP_GRID_FADE_END_Z) {
87
+ return 0;
88
+ }
89
+
90
+ const fadeProgress = (safeCameraZ - LOCAL_SNAP_GRID_FADE_START_Z) /
91
+ (LOCAL_SNAP_GRID_FADE_END_Z - LOCAL_SNAP_GRID_FADE_START_Z);
92
+ const smoothProgress = fadeProgress * fadeProgress * (3 - (2 * fadeProgress));
93
+ return baseOpacity * (1 - smoothProgress);
94
+ }
95
+
96
+ function shouldUseInteractiveRendererDpr(module, frameState = null) {
97
+ const wheelOnlyCameraNavigation = isWheelOnlyCameraNavigation(module);
98
+ return !!(
99
+ ((frameState?.isCameraMoving === true || module?._cameraMovingThisFrame === true) &&
100
+ !wheelOnlyCameraNavigation) ||
101
+ module?.isPanning === true ||
102
+ module?._panSmoothingActive === true ||
103
+ module?.isDraggingNode === true ||
104
+ module?.isDraggingMultipleNodes === true ||
105
+ module?.isResizing === true ||
106
+ module?.isWindowResizing === true
107
+ );
108
+ }
109
+
110
+ function isRendererDprInteractionActive(module, frameState = null) {
111
+ return shouldUseInteractiveRendererDpr(module, frameState) ||
112
+ module?.isZooming === true ||
113
+ module?._wheelZoomBurstActive === true;
114
+ }
115
+
116
+ function getCameraOnlyWebglBlockerMask(module, frameState = null) {
117
+ const renderer = module?.lodRenderer || null;
118
+ let blockers = 0;
119
+ if (frameState?.isCameraNavigationOnlyInteractiveFrame !== true) {
120
+ blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.NotCameraOnly;
121
+ }
122
+ if (frameState?.canUseCss3dCameraFastPath !== true) {
123
+ blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.Css3dCameraPathUnavailable;
124
+ }
125
+ if (frameState?.isWebglRenderEnabled !== true) {
126
+ blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.WebglDisabled;
127
+ }
128
+ if (frameState?.isBoardLoading === true) {
129
+ blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.BoardLoading;
130
+ }
131
+ if (frameState?.isInLodMode === true || renderer?.isInLODMode !== false) {
132
+ blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.ResidentLod;
133
+ }
134
+ if (frameState?.hasNonCameraNavigationForcedUpdate === true) {
135
+ blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.NonCameraUpdate;
136
+ }
137
+ if (frameState?.themeAnimatedThisFrame === true || module?._forceThemeAnimationFrame === true) {
138
+ blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.ThemeAnimation;
139
+ }
140
+ if (module?.currentThemeObject?.userData?.localSnapGrid !== true) {
141
+ blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.WebglTheme;
142
+ }
143
+
144
+ const visibleCount = Number(module?._visibleIds?.size || 0);
145
+ const nearCssVisibleCount = Number(renderer?._nearCssVisibleIds?.size || 0);
146
+ const activeFullResCssCount = Number(renderer?._activeFullResCssNodeIds?.size || 0);
147
+ const pendingFullResCssCount = Number(renderer?._fullResCssPendingReadyIds?.size || 0);
148
+ const hasCompleteCssCoverage =
149
+ nearCssVisibleCount === visibleCount &&
150
+ activeFullResCssCount === visibleCount &&
151
+ pendingFullResCssCount === 0 &&
152
+ (visibleCount === 0 || !!renderer?._lastNearCssNoWorkKey);
153
+ if (!hasCompleteCssCoverage) {
154
+ blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.CssCoverageIncomplete;
155
+ }
156
+
157
+ // The full-res motion optimizer owns this cached proof: only CSS-backed,
158
+ // unselected text-like nodes enter the set after their whole GL group is
159
+ // hidden. Images, media, selected nodes, and open agent consoles remain
160
+ // outside it and therefore fail closed without a scene traversal here.
161
+ const motionHiddenGlCount = Number(renderer?._fullResMotionHiddenGlIds?.size || 0);
162
+ if (motionHiddenGlCount !== visibleCount) {
163
+ blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.FullResGlVisual;
164
+ }
165
+
166
+ const fullResHandoffActive =
167
+ renderer?._fullResHandoffActive === true ||
168
+ renderer?._hasCss3dQueueItems?.() === true ||
169
+ renderer?._css3dProcessing === true;
170
+ if (fullResHandoffActive) {
171
+ blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.FullResHandoff;
172
+ }
173
+
174
+ const residentMeshVisible =
175
+ renderer?.instancedHaloMesh?.visible === true ||
176
+ renderer?.instancedMesh?.visible === true ||
177
+ renderer?.instancedBorderLineMesh?.visible === true ||
178
+ renderer?.instancedLineMesh?.visible === true ||
179
+ renderer?.instancedConsoleMesh?.visible === true ||
180
+ renderer?.instancedImageMesh?.visible === true;
181
+ if (residentMeshVisible) {
182
+ blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.ResidentMeshVisible;
183
+ }
184
+ if (Number(renderer?._fullResImageVisualIds?.size || 0) > 0) {
185
+ blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.ImageVisual;
186
+ }
187
+ if (Number(module?._activeImageStatusTextures?.size || 0) > 0) {
188
+ blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.AnimatedImageStatus;
189
+ }
190
+ if (module?.cursorMesh?.visible === true) {
191
+ blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.CursorVisual;
192
+ }
193
+ if (Number(module?.debugGroup?.children?.length || 0) > 0) {
194
+ blockers |= CAMERA_ONLY_WEBGL_BLOCKERS.DebugVisual;
195
+ }
196
+ return blockers;
197
+ }
198
+
199
+ function getCameraOnlyWebglBlockerNames(mask) {
200
+ const normalizedMask = Number(mask || 0);
201
+ return CAMERA_ONLY_WEBGL_BLOCKER_NAMES
202
+ .filter(([flag]) => (normalizedMask & flag) !== 0)
203
+ .map(([, name]) => name);
204
+ }
205
+
206
+ function configureImageAtlasTexture(texture, THREE) {
207
+ if (!texture || !THREE) return texture;
208
+ if ('colorSpace' in texture && THREE.SRGBColorSpace) texture.colorSpace = THREE.SRGBColorSpace;
209
+ else if ('encoding' in texture && THREE.sRGBEncoding) texture.encoding = THREE.sRGBEncoding;
210
+ texture.minFilter = THREE.LinearFilter;
211
+ texture.magFilter = THREE.LinearFilter;
212
+ texture.wrapS = THREE.ClampToEdgeWrapping;
213
+ texture.wrapT = THREE.ClampToEdgeWrapping;
214
+ texture.flipY = false;
215
+ texture.generateMipmaps = false;
216
+ texture.needsUpdate = true;
217
+ return texture;
218
+ }
219
+
220
+ function getImageAtlasOutputColorChunk(THREE) {
221
+ const chunk = THREE?.ShaderChunk?.colorspace_fragment
222
+ ? '#include <colorspace_fragment>'
223
+ : (THREE?.ShaderChunk?.encodings_fragment ? '#include <encodings_fragment>' : '');
224
+ globalThis.MindCanvasDevGuards?.assert?.(chunk.length > 0,
225
+ 'resident-image-output-color-chunk-missing', { threeRevision: String(THREE?.REVISION || 'unknown') });
226
+ return chunk;
227
+ }
228
+
229
+ function syncCommittedResidentTextCount(renderer, hasResidentInstances, forceResident) {
230
+ if (forceResident !== true || !hasResidentInstances || renderer?._lodUsesVisibleSubset === true ||
231
+ renderer?._instancesDirty === true || renderer?._isNodeArrayDirty === true) return -1;
232
+ const count = Number(renderer?.instanceData?.nodeIds?.length || 0);
233
+ renderer._cachedEligibleTextLikeCount = count;
234
+ renderer._lastNodeCount = count;
235
+ return count;
236
+ }
237
+
238
+ function clearFullResImageVisuals(renderer, nodeObjectsById) {
239
+ const tracked = renderer?._fullResImageVisualIds;
240
+ if (!tracked) return;
241
+ for (const nodeId of tracked) {
242
+ const entry = nodeObjectsById?.get?.(nodeId) || null;
243
+ if (entry) renderer._hideImageLodFullVisual?.(entry);
244
+ }
245
+ if (renderer.isInLODMode === true) {
246
+ const residentIds = renderer.imageInstanceData?.nodeIds || [];
247
+ for (let i = 0; i < residentIds.length; i++) {
248
+ const nodeId = residentIds[i];
249
+ if (!nodeId || tracked.has(nodeId)) continue;
250
+ const entry = nodeObjectsById?.get?.(nodeId) || null;
251
+ if (entry) renderer._hideImageLodFullVisual?.(entry);
252
+ }
253
+ }
254
+ tracked.clear();
255
+ }
256
+
257
+ function isFullResMotionOptimizationActive(module) {
258
+ return (module?._viewSyncMotionActive === true ||
259
+ module?.isPanning === true ||
260
+ module?.isZooming === true ||
261
+ module?._fullResMotionFrozen === true) &&
262
+ module?.isDraggingNode !== true &&
263
+ module?.isDraggingMultipleNodes !== true &&
264
+ module?.isResizing !== true &&
265
+ module?.isWindowResizing !== true;
266
+ }
267
+
268
+ function buildFullResKey(
269
+ lodBand,
270
+ visibilityVersion,
271
+ selectionKey,
272
+ nodeCount,
273
+ visibleCount,
274
+ nearVisibleCount,
275
+ allowedCssCount,
276
+ css3dEnabled,
277
+ module,
278
+ renderer) {
279
+ return [
280
+ String(lodBand || ''),
281
+ Number(visibilityVersion || 0),
282
+ String(selectionKey || ''),
283
+ Number(nodeCount || 0),
284
+ Number(visibleCount || 0),
285
+ Number(nearVisibleCount || 0),
286
+ Number(allowedCssCount || 0),
287
+ css3dEnabled === false ? 'css3d:off' : 'css3d:on',
288
+ String(module?.draggedNodeId || ''),
289
+ String(module?._textOverlayV2State?.editing?.nodeId || ''),
290
+ String(module?._editingOverlayState?.nodeId || ''),
291
+ String(module?._textOverlayV2State?.selectionNodeId || ''),
292
+ String(renderer?._getCurrentHoveredNodeId?.(module) || ''),
293
+ isFullResMotionOptimizationActive(module) ? 'motion:on' : 'motion:off'
294
+ ].join('|');
295
+ }
296
+
297
+ function hasPendingFullResWork(renderer, module, bandChanged, cssReadinessDrift) {
298
+ return !renderer || !module ||
299
+ bandChanged === true ||
300
+ cssReadinessDrift === true ||
301
+ renderer._hasCss3dQueueItems?.() === true ||
302
+ Number(renderer._css3dQueuedMap?.size || 0) > 0 ||
303
+ renderer._css3dProcessing === true ||
304
+ Number(renderer._nearEntryBoostFrames || 0) > 0 ||
305
+ renderer._fullResHandoffActive === true ||
306
+ module._cssParentRepairNeeded === true ||
307
+ module._css3dVisualChangedThisFrame === true ||
308
+ module._css3dVisualChangedSinceLastRender === true ||
309
+ Number(module._cssTransformDirtyIds?.size || 0) > 0;
310
+ }
311
+
312
+ function shouldSkipStableFullRes(renderer, module, key, bandChanged) {
313
+ const canSkip = !!key &&
314
+ renderer?._lastNearCssNoWorkKey === key &&
315
+ hasPendingFullResWork(renderer, module, bandChanged, false) !== true;
316
+
317
+ if (renderer) {
318
+ renderer._lastFullResStablePlanSkipped = canSkip;
319
+ if (canSkip) {
320
+ renderer._fullResStablePlanSkipCount = Number(renderer._fullResStablePlanSkipCount || 0) + 1;
321
+ }
322
+ }
323
+
324
+ return canSkip;
325
+ }
326
+
327
+ function commitStableFullRes(renderer, module, key, bandChanged, cssReadinessDrift) {
328
+ if (!key || renderer?._lastNearCssNoWorkKey !== key ||
329
+ hasPendingFullResWork(renderer, module, bandChanged, cssReadinessDrift)) {
330
+ if (renderer) renderer._lastFullResStablePlanSkipped = false;
331
+ return false;
332
+ }
333
+
334
+ renderer._lastNearCssNoWorkKey = key;
335
+ renderer._lastFullResStablePlanSkipped = false;
336
+ return true;
337
+ }
338
+
339
+ function recordStableFullRes(renderer, module, key, bandChanged, cssReadinessDrift) {
340
+ if (!renderer || !key || hasPendingFullResWork(renderer, module, bandChanged, cssReadinessDrift)) {
341
+ if (renderer) renderer._lastNearCssNoWorkKey = '';
342
+ return false;
343
+ }
344
+
345
+ renderer._lastNearCssNoWorkKey = key;
346
+ renderer._lastFullResStablePlanSkipped = false;
347
+ return true;
348
+ }
349
+
350
+ function getLineModelSource(model) {
351
+ return model?._visibleContent ?? model?.response ?? model?.Response ??
352
+ model?.content ?? model?.Content ?? model?.text ?? model?.Text ?? '';
353
+ }
354
+
355
+ function getPreparedLineData(renderer, entry, width, height) {
356
+ const prepared = entry?._lodResidentPreparedLine || null;
357
+ const model = entry?.model || null;
358
+ const nodeId = model?.id || model?.Id || '';
359
+ const element = entry?.cssObject?.element || null;
360
+ if (!prepared || !model || !nodeId ||
361
+ prepared.data !== renderer?.lineDataCache?.get?.(nodeId) ||
362
+ prepared.model !== model ||
363
+ prepared.width !== Number(width || 0) ||
364
+ prepared.height !== Number(height || 0) ||
365
+ prepared.source !== getLineModelSource(model) ||
366
+ prepared.prompt !== (model?.prompt ?? model?.Prompt ?? '') ||
367
+ prepared.elementClass !== String(element?.className || '') ||
368
+ prepared.rootClass !== String(globalThis.document?.documentElement?.className || '') ||
369
+ prepared.viewportWidth !== Number(globalThis.innerWidth || 0) ||
370
+ prepared.viewportHeight !== Number(globalThis.innerHeight || 0)) {
371
+ return null;
372
+ }
373
+ return prepared.data;
374
+ }
375
+
376
+ function rememberPreparedLine(renderer, entry, width, height, data) {
377
+ const model = entry?.model || null;
378
+ const element = entry?.cssObject?.element || null;
379
+ if (!model || !data) return data || null;
380
+ entry._lodResidentPreparedLine = {
381
+ data,
382
+ model,
383
+ width: Number(width || 0),
384
+ height: Number(height || 0),
385
+ source: getLineModelSource(model),
386
+ prompt: model?.prompt ?? model?.Prompt ?? '',
387
+ elementClass: String(element?.className || ''),
388
+ rootClass: String(globalThis.document?.documentElement?.className || ''),
389
+ viewportWidth: Number(globalThis.innerWidth || 0),
390
+ viewportHeight: Number(globalThis.innerHeight || 0)
391
+ };
392
+ return data;
393
+ }
394
+
395
+ function resolveResidentLineData(renderer, entry, width, height, allowExact, maxSamples, lineHeight, padding) {
396
+ const prepared = getPreparedLineData(renderer, entry, width, height);
397
+ if (prepared) return prepared;
398
+ const model = entry?.model || null;
399
+ if (!renderer || !model) return null;
400
+ if (allowExact === true) {
401
+ return rememberPreparedLine(renderer, entry, width, height,
402
+ renderer._getLineDataForNode?.(model, entry.lodSeed, width, height, entry));
403
+ }
404
+ renderer._residentLineFallbackUsed = true;
405
+ const safeLineHeight = Math.max(1, Number(lineHeight || 1));
406
+ const safePadding = Math.max(0, Number(padding || 0));
407
+ const maxLines = Math.max(1, Math.min(
408
+ Number(maxSamples || 1),
409
+ Math.floor(Math.max(safeLineHeight, Number(height || 0) - safePadding * 2) / safeLineHeight)
410
+ ));
411
+ const fallback = renderer._computeFallbackLineData?.(entry.lodSeed, maxLines) || { lineCount: 0, lineLengths: [] };
412
+ return {
413
+ lineCount: Number(fallback.lineCount || 0),
414
+ lineLengths: fallback.lineLengths || [],
415
+ lineHeightPx: safeLineHeight,
416
+ paddingX: safePadding,
417
+ paddingY: safePadding
418
+ };
419
+ }
420
+
421
+ function isPrewarmInteractionActive(module) {
422
+ return module?.isPanning === true || module?.isZooming === true ||
423
+ module?._panSmoothingActive === true || module?._viewSyncMotionActive === true ||
424
+ module?._cameraMovingThisFrame === true ||
425
+ module?.isDraggingNode === true || module?.isDraggingMultipleNodes === true ||
426
+ module?.isResizing === true || module?.isWindowResizing === true;
427
+ }
428
+
429
+ function prepareImageAtlasCapacity(renderer, imageCount) {
430
+ if (!renderer?.imageAtlasCanvas || Number(renderer.imageAtlasSlots?.size || 0) > 0) return false;
431
+ let columns = 8;
432
+ const targetSlots = Math.max(1, Number(imageCount || 0) * 2);
433
+ while (columns < 32 && columns * columns < targetSlots) columns *= 2;
434
+ const size = columns * IMAGE_ATLAS_TILE_SIZE;
435
+ renderer.imageAtlasColumns = columns;
436
+ renderer.imageAtlasSize = size;
437
+ renderer.imageAtlasMaxSlots = columns * columns;
438
+ if (renderer.imageAtlasCanvas.width === size && renderer.imageAtlasCanvas.height === size) return false;
439
+ renderer.imageAtlasCanvas.width = size;
440
+ renderer.imageAtlasCanvas.height = size;
441
+ const context = renderer.imageAtlasCanvas.getContext?.('2d', { alpha: false }) || null;
442
+ if (context) {
443
+ context.fillStyle = '#eef2f7';
444
+ context.fillRect(0, 0, size, size);
445
+ }
446
+ const THREE = globalThis.THREE;
447
+ const previousTexture = renderer.imageAtlasTexture || null;
448
+ if (THREE?.CanvasTexture) {
449
+ const nextTexture = new THREE.CanvasTexture(renderer.imageAtlasCanvas);
450
+ nextTexture.minFilter = previousTexture?.minFilter ?? THREE.LinearFilter;
451
+ nextTexture.magFilter = previousTexture?.magFilter ?? THREE.LinearFilter;
452
+ nextTexture.wrapS = previousTexture?.wrapS ?? THREE.ClampToEdgeWrapping;
453
+ nextTexture.wrapT = previousTexture?.wrapT ?? THREE.ClampToEdgeWrapping;
454
+ nextTexture.flipY = previousTexture?.flipY ?? false;
455
+ nextTexture.generateMipmaps = previousTexture?.generateMipmaps ?? false;
456
+ if ('colorSpace' in nextTexture && previousTexture?.colorSpace) {
457
+ nextTexture.colorSpace = previousTexture.colorSpace;
458
+ } else if ('encoding' in nextTexture && previousTexture?.encoding != null) {
459
+ nextTexture.encoding = previousTexture.encoding;
460
+ }
461
+ nextTexture.needsUpdate = true;
462
+ renderer.imageAtlasTexture = nextTexture;
463
+ const atlasUniform = renderer.instancedImageMesh?.material?.uniforms?.uImageAtlas || null;
464
+ if (atlasUniform) atlasUniform.value = nextTexture;
465
+ previousTexture?.dispose?.();
466
+ } else if (previousTexture) {
467
+ previousTexture.needsUpdate = true;
468
+ }
469
+ renderer._residentGpuWarmKey = '';
470
+ renderer._residentGpuWarmOffscreenComplete = false;
471
+ renderer._residentImageAtlasWarmVersion = -1;
472
+ return true;
473
+ }
474
+
475
+ function prepareImageAtlasForEntries(renderer, entries) {
476
+ let imageCount = 0;
477
+ for (const entry of entries || []) {
478
+ const model = entry?.model || null;
479
+ const contentType = String(model?.contentType ?? model?.ContentType ?? '').toLowerCase();
480
+ if (contentType === 'video') {
481
+ imageCount++;
482
+ continue;
483
+ }
484
+ if (contentType === 'image') {
485
+ if (globalThis.MindMapNodes?.isAnimatedGifImageNodeModel?.(model) !== true) imageCount++;
486
+ continue;
487
+ }
488
+ if (contentType === 'embed') {
489
+ const urls = globalThis.MindMapNodes?.getNodeImageAssetUrls?.(model) || null;
490
+ if (urls?.thumbnailUrl || urls?.snapshotUrl || urls?.previewImageUrl) imageCount++;
491
+ }
492
+ }
493
+ return prepareImageAtlasCapacity(renderer, imageCount);
494
+ }
495
+
496
+ function uploadImageAtlasTile(renderer, slot, canvas) {
497
+ const webglRenderer = renderer?.renderer || null;
498
+ const gl = renderer?.gl || webglRenderer?.getContext?.() || null;
499
+ const texture = renderer?.imageAtlasTexture || null;
500
+ if (!webglRenderer?.initTexture || !gl || !texture || !canvas || !(slot?.slotIndex >= 0)) return false;
501
+
502
+ let savedTexture = null;
503
+ let savedFlipY = null;
504
+ let savedPremultiply = null;
505
+ let savedColorspace = null;
506
+ try {
507
+ webglRenderer.initTexture(texture);
508
+ const handle = webglRenderer.properties?.get?.(texture)?.__webglTexture || null;
509
+ if (!handle) return false;
510
+ savedTexture = gl.getParameter(gl.TEXTURE_BINDING_2D);
511
+ savedFlipY = gl.getParameter(gl.UNPACK_FLIP_Y_WEBGL);
512
+ savedPremultiply = gl.getParameter(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL);
513
+ savedColorspace = gl.getParameter(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL);
514
+ const columns = Math.max(1, Number(renderer.imageAtlasColumns || 1));
515
+ const x = (slot.slotIndex % columns) * IMAGE_ATLAS_TILE_SIZE;
516
+ const y = Math.floor(slot.slotIndex / columns) * IMAGE_ATLAS_TILE_SIZE;
517
+ gl.bindTexture(gl.TEXTURE_2D, handle);
518
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
519
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
520
+ gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);
521
+ gl.texSubImage2D(gl.TEXTURE_2D, 0, x, y, gl.RGBA, gl.UNSIGNED_BYTE, canvas);
522
+ renderer._imageAtlasTileUploadCount = Number(renderer._imageAtlasTileUploadCount || 0) + 1;
523
+ renderer._residentGpuWarmKey = '';
524
+ renderer._residentImageAtlasWarmVersion = -1;
525
+ return true;
526
+ } catch {
527
+ return false;
528
+ } finally {
529
+ if (savedFlipY !== null) gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, savedFlipY);
530
+ if (savedPremultiply !== null) gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, savedPremultiply);
531
+ if (savedColorspace !== null) gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, savedColorspace);
532
+ if (savedTexture !== null) gl.bindTexture(gl.TEXTURE_2D, savedTexture);
533
+ }
534
+ }
535
+
536
+ function scheduleImageAtlasUpload(renderer, module = renderer?._module) {
537
+ if (!renderer?.imageAtlasTexture || renderer?._disposed === true) return false;
538
+ const now = typeof performance !== 'undefined' ? performance.now() : Date.now();
539
+ let state = imageAtlasUploadStates.get(renderer);
540
+ if (!state) {
541
+ state = { timer: 0, startedAt: now, pending: false, epoch: 0 };
542
+ imageAtlasUploadStates.set(renderer, state);
543
+ }
544
+ state.pending = true;
545
+ state.epoch = Number(renderer._residentStaticPreviewEpoch || 0);
546
+ if (!(state.startedAt > 0)) state.startedAt = now;
547
+ if (state.timer) clearTimeout(state.timer);
548
+ const elapsedMs = Math.max(0, now - state.startedAt);
549
+ const delayMs = Math.max(0, Math.min(
550
+ IMAGE_ATLAS_UPLOAD_SETTLE_MS,
551
+ IMAGE_ATLAS_UPLOAD_MAX_WAIT_MS - elapsedMs
552
+ ));
553
+ state.timer = setTimeout(() => {
554
+ state.timer = 0;
555
+ if (!state.pending || renderer._disposed === true ||
556
+ state.epoch !== Number(renderer._residentStaticPreviewEpoch || 0)) return;
557
+ state.pending = false;
558
+ state.startedAt = 0;
559
+ if (!renderer.imageAtlasTexture) return;
560
+ renderer.imageAtlasTexture.needsUpdate = true;
561
+ renderer._imageAtlasTextureUploadCount = Number(renderer._imageAtlasTextureUploadCount || 0) + 1;
562
+ const activeModule = renderer._module || module;
563
+ if (activeModule) {
564
+ activeModule._forceUpdateFrames = Math.max(Number(activeModule._forceUpdateFrames || 0), 1);
565
+ activeModule.requestAnimationWake?.('image-atlas-texture-upload');
566
+ }
567
+ }, delayMs);
568
+ return true;
569
+ }
570
+
571
+ function clearScheduledImageAtlasUpload(renderer) {
572
+ const state = imageAtlasUploadStates.get(renderer);
573
+ if (state?.timer) clearTimeout(state.timer);
574
+ imageAtlasUploadStates.delete(renderer);
575
+ }
576
+
577
+ function fallbackBatch(renderer, fallbackIds, limit = 12) {
578
+ const ids = Array.from(fallbackIds || []);
579
+ const safeLimit = Math.max(1, Number(limit || 1));
580
+ if (ids.length <= safeLimit) return ids;
581
+ const cursor = Math.max(0, Number(renderer?._residentFallbackCleanupCursor || 0)) % ids.length;
582
+ const batch = [];
583
+ for (let i = 0; i < safeLimit; i++) batch.push(ids[(cursor + i) % ids.length]);
584
+ if (renderer) renderer._residentFallbackCleanupCursor = (cursor + safeLimit) % ids.length;
585
+ return batch;
586
+ }
587
+
588
+ function reuseCssMediaFrameDom(cssObject, width, height, hasContextSourcePins = false) {
589
+ const wrapper = cssObject?.element || null;
590
+ const isMedia = wrapper?.classList?.contains?.('node-type-image') === true ||
591
+ wrapper?.classList?.contains?.('node-type-video') === true ||
592
+ wrapper?.classList?.contains?.('node-type-embed') === true;
593
+ if (!isMedia || !wrapper?.style) return false;
594
+
595
+ const inner = wrapper.firstElementChild || null;
596
+ const content = inner?.querySelector?.('.node-content-wrapper') || null;
597
+ const response = inner?.querySelector?.('.node-response') || null;
598
+ const surface = inner?.querySelector?.('img,video,canvas.mind-map-video-proxy,iframe,.embed-card,.embed-iframe-shell') || null;
599
+ const resolutionScale = Math.max(1, Number(cssObject?.userData?.resolutionScale || 1));
600
+ const worldWidth = Math.max(1, Math.round(Number(width || 1)));
601
+ const worldHeight = Math.max(1, Math.round(Number(height || 1)));
602
+ const scaledWidth = worldWidth * resolutionScale;
603
+ const scaledHeight = worldHeight * resolutionScale;
604
+ const state = cssMediaFrameDomStates.get(cssObject) || null;
605
+ const structureMatches = !!state && state.wrapper === wrapper && state.inner === inner &&
606
+ state.content === content && state.response === response && state.surface === surface &&
607
+ state.innerChildren === Number(inner?.childElementCount ?? inner?.children?.length ?? 0) &&
608
+ state.contentChildren === Number(content?.childElementCount ?? content?.children?.length ?? 0);
609
+ const frameMatches = structureMatches && state.width === worldWidth && state.height === worldHeight &&
610
+ state.resolutionScale === resolutionScale && state.hasContextSourcePins === (hasContextSourcePins === true);
611
+ const frameStylesReady = wrapper.style.width === `${scaledWidth}px` && wrapper.style.height === `${scaledHeight}px` &&
612
+ (!inner?.style || (inner.style.width === `${worldWidth}px` && inner.style.height === `${worldHeight}px`));
613
+
614
+ if (frameMatches && frameStylesReady) {
615
+ cssMediaFrameDomReuseCount++;
616
+ return true;
617
+ }
618
+
619
+ cssMediaFrameDomStates.set(cssObject, {
620
+ wrapper,
621
+ inner,
622
+ content,
623
+ response,
624
+ surface,
625
+ innerChildren: Number(inner?.childElementCount ?? inner?.children?.length ?? 0),
626
+ contentChildren: Number(content?.childElementCount ?? content?.children?.length ?? 0),
627
+ width: worldWidth,
628
+ height: worldHeight,
629
+ resolutionScale,
630
+ hasContextSourcePins: hasContextSourcePins === true
631
+ });
632
+ cssMediaFrameDomApplyCount++;
633
+ return false;
634
+ }
635
+
636
+ function reuseStableVisibleCss(renderer, entry, module, nodeIdValue, options = {}) {
637
+ const cssObject = entry?.cssObject || null;
638
+ const element = cssObject?.element || null;
639
+ const nodeId = String(nodeIdValue || entry?.model?.id || entry?.model?.Id || entry?.glObject?.userData?.nodeId || '').trim();
640
+ const cssScene = module?.cssScene || module?.scene || null;
641
+ const allowResident = options.allowResident === true;
642
+ if (!nodeId || !element || entry?.isCssDirty === true || entry?.currentType !== 'CSS' ||
643
+ cssObject.visible !== true || cssObject.userData?._residentTransitionPrepared === true ||
644
+ cssObject.userData?._fullResFringePrepared === true ||
645
+ (!allowResident && renderer?.isInLODMode === true) || (cssScene && cssObject.parent !== cssScene) ||
646
+ element.style?.display === 'none' || element.style?.visibility === 'hidden' || element.style?.opacity === '0' ||
647
+ module?._cssParentRepairNeeded === true || module?._cssTransformDirtyIds?.has?.(nodeId) === true) return false;
648
+
649
+ const selectedNodeId = String(module?.selectedNodeIdJs || module?.selectedNodeId || '').trim();
650
+ const editingNodeId = String(module?._textOverlayV2State?.editing?.nodeId || module?._editingOverlayState?.nodeId || '').trim();
651
+ if (selectedNodeId === nodeId || module?.multiSelectedNodeIds?.has?.(nodeId) === true ||
652
+ module?.draggedNodeId === nodeId || editingNodeId === nodeId ||
653
+ renderer?._getCurrentHoveredNodeId?.(module) === nodeId) return false;
654
+
655
+ const isHigh = options.isHighDetail === true;
656
+ if (typeof renderer?._areCss3dDetailTargetsAtLevel === 'function') {
657
+ if (renderer._areCss3dDetailTargetsAtLevel(entry, isHigh) !== true) return false;
658
+ } else {
659
+ const inner = element.querySelector?.('.node-container') || null;
660
+ const targets = inner && inner !== element ? [element, inner] : [element];
661
+ for (const target of targets) {
662
+ if (!target?.classList || target.classList.contains(isHigh ? 'lod-high' : 'lod-low') !== true ||
663
+ target.classList.contains(isHigh ? 'lod-low' : 'lod-high') === true) return false;
664
+ }
665
+ }
666
+ if (isHigh && (typeof renderer?._isCss3dSourceSuspended === 'function'
667
+ ? renderer._isCss3dSourceSuspended(entry) === true
668
+ : (element.matches?.('[data-text-overlay-source-suspended],.mind-map-text-overlay-source-suspended,.mind-map-v2-source-suspended') === true ||
669
+ element.querySelector?.('[data-text-overlay-source-suspended],.mind-map-text-overlay-source-suspended,.mind-map-v2-source-suspended')))) return false;
670
+
671
+ const contentType = String(entry?.model?.contentType ?? entry?.model?.ContentType ?? '').trim().toLowerCase();
672
+ if (contentType === 'image' || contentType === 'video') {
673
+ const media = element.querySelector?.('img,video') || null;
674
+ const source = media?.getAttribute?.('src') || media?.currentSrc || media?.src || '';
675
+ if (!media || !source) return false;
676
+ } else if (contentType === 'embed' &&
677
+ !element.querySelector?.('.embed-card,.embed-frame,.embed-iframe-shell')) return false;
678
+
679
+ renderer?._nearCssVisibleIds?.add?.(nodeId);
680
+ if (renderer) renderer._fullResCssStableReuseCount = Number(renderer._fullResCssStableReuseCount || 0) + 1;
681
+ return true;
682
+ }
683
+
684
+ function reuseActiveCssMediaFallback(renderer, entry, module) {
685
+ const cssObject = entry?.cssObject || null;
686
+ const element = cssObject?.element || null;
687
+ const nodeId = String(entry?.model?.id || entry?.model?.Id || entry?.glObject?.userData?.nodeId || '').trim();
688
+ const cssScene = module?.cssScene || module?.scene || null;
689
+ if (!nodeId || !element || entry?.isCssDirty === true || cssObject.visible !== true ||
690
+ !renderer?._lodImageCssFallbackNodeIds?.has?.(nodeId) ||
691
+ (cssScene && cssObject.parent !== cssScene) || element.style?.display === 'none' ||
692
+ element.style?.visibility === 'hidden' || element.style?.opacity === '0') return false;
693
+ if (String(module?.selectedNodeIdJs || module?.selectedNodeId || '') === nodeId ||
694
+ module?.multiSelectedNodeIds?.has?.(nodeId) === true || module?.draggedNodeId === nodeId ||
695
+ renderer?._getCurrentHoveredNodeId?.(module) === nodeId) return false;
696
+ return true;
697
+ }
698
+
699
+ function invalidateAnimatedGifCssFallbackCandidateCache(renderer) {
700
+ if (!renderer) return;
701
+ renderer._animatedGifFallbackCandidateCacheValid = false;
702
+ }
703
+
704
+ function invalidateActiveCssMediaFallbackCountCache(renderer) {
705
+ if (!renderer) return;
706
+ renderer._activeCssMediaFallbackCountCacheValid = false;
707
+ }
708
+
709
+ function markLodImageCssFallbacksChanged(renderer) {
710
+ if (!renderer) return;
711
+ renderer._lodImageCssFallbackRevision =
712
+ Number(renderer._lodImageCssFallbackRevision || 0) + 1;
713
+ invalidateAnimatedGifCssFallbackCandidateCache(renderer);
714
+ invalidateActiveCssMediaFallbackCountCache(renderer);
715
+ }
716
+
717
+ function createTrackedLodImageCssFallbackSet(renderer) {
718
+ return new class extends Set {
719
+ add(value) {
720
+ if (!this.has(value)) {
721
+ super.add(value);
722
+ markLodImageCssFallbacksChanged(renderer);
723
+ }
724
+ return this;
725
+ }
726
+
727
+ delete(value) {
728
+ const deleted = super.delete(value);
729
+ if (deleted) markLodImageCssFallbacksChanged(renderer);
730
+ return deleted;
731
+ }
732
+
733
+ clear() {
734
+ if (this.size <= 0) return;
735
+ super.clear();
736
+ markLodImageCssFallbacksChanged(renderer);
737
+ }
738
+ }();
739
+ }
740
+
741
+ function getActiveCssMediaFallbackCountCached(renderer, module) {
742
+ if (!renderer) return 0;
743
+ const nodeObjectsById = module?.nodeObjectsById || renderer?._module?.nodeObjectsById || null;
744
+ const fallbackRevision = Number(renderer?._lodImageCssFallbackRevision || 0);
745
+ const fallbackCount = Number(renderer?._lodImageCssFallbackNodeIds?.size || 0);
746
+ if (fallbackCount <= 0) {
747
+ renderer._activeCssMediaFallbackCountCacheNodeMap = nodeObjectsById;
748
+ renderer._activeCssMediaFallbackCountCacheRevision = fallbackRevision;
749
+ renderer._activeCssMediaFallbackCountCacheFallbackCount = 0;
750
+ renderer._activeCssMediaFallbackCountCacheValue = 0;
751
+ renderer._activeCssMediaFallbackCountCacheValid = true;
752
+ return 0;
753
+ }
754
+ if (renderer._activeCssMediaFallbackCountCacheValid === true &&
755
+ renderer._activeCssMediaFallbackCountCacheNodeMap === nodeObjectsById &&
756
+ Number(renderer._activeCssMediaFallbackCountCacheRevision || 0) === fallbackRevision &&
757
+ Number(renderer._activeCssMediaFallbackCountCacheFallbackCount || 0) === fallbackCount) {
758
+ renderer._activeCssMediaFallbackCountCacheHitCount =
759
+ Number(renderer._activeCssMediaFallbackCountCacheHitCount || 0) + 1;
760
+ return Number(renderer._activeCssMediaFallbackCountCacheValue || 0);
761
+ }
762
+
763
+ const activeFallbackCount =
764
+ Number(renderer._getActiveCssMediaLodFallbackCount?.(module) || 0);
765
+ renderer._activeCssMediaFallbackCountScanCount =
766
+ Number(renderer._activeCssMediaFallbackCountScanCount || 0) + 1;
767
+ renderer._activeCssMediaFallbackCountCacheNodeMap = nodeObjectsById;
768
+ renderer._activeCssMediaFallbackCountCacheRevision = fallbackRevision;
769
+ renderer._activeCssMediaFallbackCountCacheFallbackCount = fallbackCount;
770
+ renderer._activeCssMediaFallbackCountCacheValue = activeFallbackCount;
771
+ renderer._activeCssMediaFallbackCountCacheValid = true;
772
+ return activeFallbackCount;
773
+ }
774
+
775
+ function hasAnimatedGifCssFallbackCandidates(renderer, module, isAnimatedGifModel, selectionKey = '') {
776
+ const nodeObjectsById = module?.nodeObjectsById || renderer?._module?.nodeObjectsById || null;
777
+ if (!nodeObjectsById || typeof isAnimatedGifModel !== 'function') return false;
778
+ const visibilityVersion = Number(module?._visibilityVersion || 0);
779
+ const fallbackRevision = Number(renderer?._lodImageCssFallbackRevision || 0);
780
+ const fallbackCount = Number(renderer?._lodImageCssFallbackNodeIds?.size || 0);
781
+ const residentDirtySerial = Number(renderer?._instancesDirtySerial || 0);
782
+ const normalizedSelectionKey = String(selectionKey || '');
783
+ if (renderer?._animatedGifFallbackCandidateCacheValid === true &&
784
+ renderer._animatedGifFallbackCandidateNodeMap === nodeObjectsById &&
785
+ Number(renderer._animatedGifFallbackCandidateVisibilityVersion || 0) === visibilityVersion &&
786
+ Number(renderer._animatedGifFallbackCandidateFallbackRevision || 0) === fallbackRevision &&
787
+ Number(renderer._animatedGifFallbackCandidateFallbackCount || 0) === fallbackCount &&
788
+ Number(renderer._animatedGifFallbackCandidateResidentDirtySerial || 0) === residentDirtySerial &&
789
+ String(renderer._animatedGifFallbackCandidateSelectionKey || '') === normalizedSelectionKey) {
790
+ renderer._animatedGifFallbackCandidateCacheHitCount =
791
+ Number(renderer._animatedGifFallbackCandidateCacheHitCount || 0) + 1;
792
+ return renderer._animatedGifFallbackCandidateCacheValue === true;
793
+ }
794
+
795
+ renderer._animatedGifFallbackCandidateScanCount =
796
+ Number(renderer._animatedGifFallbackCandidateScanCount || 0) + 1;
797
+ const isGifId = (value) => {
798
+ const nodeId = String(value || '').trim();
799
+ if (nodeId) {
800
+ renderer._animatedGifFallbackCandidateNodeVisitCount =
801
+ Number(renderer._animatedGifFallbackCandidateNodeVisitCount || 0) + 1;
802
+ }
803
+ return !!nodeId && isAnimatedGifModel(nodeObjectsById.get(nodeId)?.model) === true;
804
+ };
805
+ const scan = (ids) => {
806
+ if (!ids) return false;
807
+ for (const nodeId of ids) if (isGifId(nodeId)) return true;
808
+ return false;
809
+ };
810
+ const visibleIds = module?._visibleIds || null;
811
+ const result =
812
+ scan(visibleIds) ||
813
+ (module?._prevVisibleIds !== visibleIds && scan(module?._prevVisibleIds)) ||
814
+ isGifId(module?.selectedNodeIdJs) ||
815
+ scan(module?.multiSelectedNodeIds) ||
816
+ scan(renderer?._lodImageCssFallbackNodeIds);
817
+ renderer._animatedGifFallbackCandidateNodeMap = nodeObjectsById;
818
+ renderer._animatedGifFallbackCandidateVisibilityVersion = visibilityVersion;
819
+ renderer._animatedGifFallbackCandidateFallbackRevision = fallbackRevision;
820
+ renderer._animatedGifFallbackCandidateFallbackCount = fallbackCount;
821
+ renderer._animatedGifFallbackCandidateResidentDirtySerial = residentDirtySerial;
822
+ renderer._animatedGifFallbackCandidateSelectionKey = normalizedSelectionKey;
823
+ renderer._animatedGifFallbackCandidateCacheValue = result === true;
824
+ renderer._animatedGifFallbackCandidateCacheValid = true;
825
+ return result === true;
826
+ }
827
+
828
+ function hasActionableResidentLineDetails(renderer, module, lodBand) {
829
+ const nodeIds = renderer?.instanceData?.nodeIds || [];
830
+ return nodeIds.length > 0 && renderer?._hasPendingLineDetailRestore?.(lodBand) === true &&
831
+ areResidentLinesPrepared(renderer, module?.nodeObjectsById, nodeIds);
832
+ }
833
+
834
+ function hasResidentDirtyWork(renderer, camera, module, resolveLodBand, buildSelectionKey, isAnimatedGifModel) {
835
+ if (!renderer) return false;
836
+ const lodBand = camera && typeof resolveLodBand === 'function'
837
+ ? resolveLodBand(Number(camera.position?.z || 0))
838
+ : renderer._currentLodBand;
839
+ const hasTypedResidentDirtyWork =
840
+ renderer._instancesDirty === true || renderer._imageInstancesDirty === true ||
841
+ renderer._positionsOnlyDirty === true || renderer._isNodeArrayDirty === true ||
842
+ Number(renderer._dirtyPositionIds?.size || 0) > 0 || Number(renderer._pendingSelectionRefreshIds?.size || 0) > 0 ||
843
+ renderer._imageAtlasRebuildPending === true || Number(renderer._imageAtlasQueuedIds?.size || 0) > 0 ||
844
+ Number(renderer._imageAtlasLoadingIds?.size || 0) > 0 || Number(renderer._imageAtlasBatchReadyIds?.size || 0) > 0 ||
845
+ renderer._imageAtlasBatchActive === true || renderer._lodCleanupPending === true ||
846
+ renderer._deferLineRestorePending === true || hasActionableResidentLineDetails(renderer, module, lodBand) ||
847
+ Number(renderer._pendingLodVisibilityVersion ?? -1) >= 0 || renderer._fullResHandoffActive === true ||
848
+ renderer.isLoading === true || module?.isLoading === true || renderer._hasResidentLodInstances?.() !== true;
849
+ if (hasTypedResidentDirtyWork) {
850
+ invalidateAnimatedGifCssFallbackCandidateCache(renderer);
851
+ return true;
852
+ }
853
+ const selectionKey = typeof buildSelectionKey === 'function'
854
+ ? buildSelectionKey(module?.multiSelectedNodeIds || null, module?.selectedNodeIdJs || null)
855
+ : '';
856
+ if (renderer._lastAppliedLodSelectionKey !== selectionKey) {
857
+ invalidateAnimatedGifCssFallbackCandidateCache(renderer);
858
+ return true;
859
+ }
860
+ const usesCssImageFallbacks = renderer._shouldUseCssImageFallbackInResidentLod?.(module, lodBand) === true;
861
+ const usesAnimatedGifFallbacks = hasAnimatedGifCssFallbackCandidates(
862
+ renderer,
863
+ module,
864
+ isAnimatedGifModel,
865
+ selectionKey
866
+ );
867
+ const fallbackCount = Number(renderer._lodImageCssFallbackNodeIds?.size || 0);
868
+ if (!usesAnimatedGifFallbacks && fallbackCount <= 0) return false;
869
+ const activeFallbackCount = getActiveCssMediaFallbackCountCached(renderer, module);
870
+ return (usesAnimatedGifFallbacks && activeFallbackCount <= 0) ||
871
+ (fallbackCount > 0 && (!(usesCssImageFallbacks || usesAnimatedGifFallbacks) || activeFallbackCount <= 0));
872
+ }
873
+
874
+ function hasPendingNearCssWarmup(renderer, module, buildSelectionKey, isCss3dEnabled, supportsCss3dModel) {
875
+ if (!renderer || renderer.isInLODMode !== false) return false;
876
+ if (renderer._css3dProcessing === true || Number(renderer._css3dQueuedMap?.size || 0) > 0 ||
877
+ renderer._hasCss3dQueueItems?.() === true || Number(renderer._nearEntryBoostFrames || 0) > 0) return true;
878
+ const moduleRef = module || renderer._module || null;
879
+ const visibleIds = renderer._getNearVisibleIds?.(moduleRef) || null;
880
+ const nodeObjectsById = moduleRef?.nodeObjectsById || null;
881
+ if (!visibleIds || !nodeObjectsById || visibleIds.size === 0) return false;
882
+ const selectionKey = buildSelectionKey?.(moduleRef?.multiSelectedNodeIds || null, moduleRef?.selectedNodeIdJs || null) || '';
883
+ const stableKey = buildFullResKey(renderer._currentLodBand, moduleRef?._visibilityVersion || 0, selectionKey,
884
+ nodeObjectsById.size, visibleIds.size, renderer._nearCssVisibleIds?.size || 0,
885
+ renderer._activeFullResCssNodeIds?.size || 0, isCss3dEnabled?.(moduleRef) !== false, moduleRef, renderer);
886
+ if (stableKey && renderer._lastNearCssNoWorkKey === stableKey) return false;
887
+ for (const nodeId of visibleIds) {
888
+ if (renderer._nearCssVisibleIds?.has?.(nodeId)) continue;
889
+ const entry = nodeObjectsById.get(nodeId);
890
+ if (entry?.glObject && supportsCss3dModel?.(entry.model) === true) return true;
891
+ }
892
+ return false;
893
+ }
894
+
895
+ function resetPreparedLayoutRecord(record) {
896
+ if (!record?.layoutPrepared) return;
897
+ const cssObject = record.cssObject;
898
+ const element = record.element;
899
+ if (cssObject?.userData) cssObject.userData._residentTransitionPrepared = false;
900
+ record.layoutPrepared = false;
901
+ if (cssObject?.visible !== true && element?.style) {
902
+ element.style.setProperty?.('display', 'none', 'important');
903
+ element.style.setProperty?.('visibility', 'visible', 'important');
904
+ element.style.setProperty?.('opacity', '1', 'important');
905
+ element.style.setProperty?.('pointer-events', record.pointerEvents || 'auto', 'important');
906
+ }
907
+ }
908
+
909
+ function clearTransitionRecords(state) {
910
+ if (!state) return;
911
+ state.layoutEpoch = Number(state.layoutEpoch || 0) + 1;
912
+ if (state.layoutRetryTimer) clearTimeout(state.layoutRetryTimer);
913
+ for (const record of state.parked?.values?.() || []) resetPreparedLayoutRecord(record);
914
+ state.parked?.clear?.();
915
+ state.layoutQueue = null;
916
+ state.layoutCursor = 0;
917
+ state.layoutScheduled = false;
918
+ state.layoutFrameScheduled = false;
919
+ state.layoutRetryTimer = null;
920
+ }
921
+
922
+ function getTransitionState(renderer, module, nodeObjectsById) {
923
+ let state = residentTransitionStates.get(renderer);
924
+ if (!state || state.module !== module || state.nodeObjectsById !== nodeObjectsById) {
925
+ clearTransitionRecords(state);
926
+ state = {
927
+ renderer, module, nodeObjectsById, active: false, selectionKey: '', parked: new Map(),
928
+ layoutQueue: null, layoutCursor: 0, layoutScheduled: false, layoutFrameScheduled: false,
929
+ layoutRetryTimer: null, layoutEpoch: 0
930
+ };
931
+ residentTransitionStates.set(renderer, state);
932
+ }
933
+ return state;
934
+ }
935
+
936
+ function getResidentCssCacheKind(entry) {
937
+ const model = entry?.model || null;
938
+ const contentType = String(model?.contentType ?? model?.ContentType ?? '').trim().toLowerCase();
939
+ if (contentType === 'image') return 'image';
940
+ if (contentType === 'video' || contentType === 'embed' || contentType === 'templatelauncher') return contentType;
941
+ if (RESIDENT_CSS_CACHE_TEXT_TYPES.has(contentType)) return 'text';
942
+ const metadata = model?.metadata || model?.Metadata || null;
943
+ const nodeType = String(model?.nodeType ?? model?.NodeType ?? '').toLowerCase();
944
+ const semanticType = String(metadata?.SemanticType ?? metadata?.semanticType ?? '');
945
+ const agentId = metadata?.agentId ?? metadata?.AgentId;
946
+ return nodeType.startsWith('agent_') || semanticType === 'MindCanvasAgent' || semanticType === 'AgentCommand' ||
947
+ semanticType === 'BusinessAutomationNode' || (agentId != null && String(agentId).trim() !== '') ? 'text' : null;
948
+ }
949
+
950
+ function cacheResidentCssEntry(state, entry, nodeId, kind) {
951
+ const cssObject = entry?.cssObject || null;
952
+ if (!state?.active || !kind || entry?.isCssDirty === true || !cssObject?.element) return false;
953
+ const cssScene = state.module?.cssScene || state.module?.scene || null;
954
+ if (!cssScene || (cssObject.parent != null && cssObject.parent !== cssScene)) return false;
955
+ const id = String(nodeId || '');
956
+ const previous = state.parked.get(id) || null;
957
+ if (previous?.layoutPrepared === true &&
958
+ (previous.cssObject !== cssObject || previous.element !== cssObject.element)) resetPreparedLayoutRecord(previous);
959
+ state.parked.set(id, {
960
+ nodeId: id,
961
+ entry, cssObject, element: cssObject.element, parent: cssObject.parent, kind,
962
+ pointerEvents: previous?.pointerEvents ?? cssObject.element.style?.pointerEvents ?? '',
963
+ layoutEligible: previous?.layoutEligible === true,
964
+ layoutPrepared: previous?.layoutPrepared === true && previous.cssObject === cssObject && previous.element === cssObject.element,
965
+ selectionKey: state.selectionKey,
966
+ ...getEntryContentState(entry)
967
+ });
968
+ state.layoutQueue = null;
969
+ return true;
970
+ }
971
+
972
+ function cachePreparedResidentCss(renderer, entry, module, nodeObjectsById) {
973
+ const state = residentTransitionStates.get(renderer);
974
+ if (!state || state.module !== module || state.nodeObjectsById !== nodeObjectsById) return false;
975
+ const nodeId = entry?.model?.id || entry?.model?.Id || entry?.glObject?.userData?.nodeId || '';
976
+ const cached = cacheResidentCssEntry(state, entry, nodeId, getResidentCssCacheKind(entry));
977
+ if (cached) {
978
+ const record = state.parked.get(String(nodeId || ''));
979
+ if (record) record.layoutEligible = true;
980
+ scheduleResidentCssLayoutWarm(renderer, module, nodeObjectsById);
981
+ }
982
+ return cached;
983
+ }
984
+
985
+ function beginResidentCssTransition(renderer, module, nodeObjectsById, previousBand, nextBand, selectionKey) {
986
+ if (!renderer || !module || !nodeObjectsById) return false;
987
+ const state = getTransitionState(renderer, module, nodeObjectsById);
988
+ const enteringResident = previousBand === 'NORMAL' && nextBand === 'MID';
989
+ const returningFullRes = (previousBand === 'MID' || previousBand === 'FAR') && nextBand === 'NORMAL';
990
+ if (enteringResident) {
991
+ clearTransitionRecords(state);
992
+ state.active = true;
993
+ state.selectionKey = String(selectionKey || '');
994
+ } else if (!returningFullRes) {
995
+ clearTransitionRecords(state);
996
+ state.active = false;
997
+ state.selectionKey = '';
998
+ }
999
+ return enteringResident || (returningFullRes && state.active);
1000
+ }
1001
+
1002
+ function getEntryContentState(entry) {
1003
+ const model = entry?.model || null;
1004
+ return {
1005
+ model,
1006
+ source: model?._visibleContent ?? model?.response ?? model?.Response ?? model?.content ?? model?.Content ?? '',
1007
+ prompt: model?.prompt ?? model?.Prompt ?? '',
1008
+ width: Number(model?.width || model?.Width || 0),
1009
+ height: Number(model?.height || model?.Height || 0),
1010
+ media: model?.thumbnailUrl ?? model?.ThumbnailUrl ?? model?.displayUrl ?? model?.DisplayUrl ?? ''
1011
+ };
1012
+ }
1013
+
1014
+ function parkFullResCss(renderer, entry, module, nodeObjectsById, selectionKey, kind = 'text') {
1015
+ const cssObject = entry?.cssObject || null;
1016
+ const element = cssObject?.element || null;
1017
+ const nodeId = String(entry?.model?.id || entry?.model?.Id || entry?.glObject?.userData?.nodeId || '').trim();
1018
+ if (!renderer || !cssObject || !element || !nodeId) return false;
1019
+ const state = getTransitionState(renderer, module, nodeObjectsById);
1020
+ let cached = false;
1021
+ if (state.active && state.selectionKey === String(selectionKey || '') && entry.isCssDirty !== true) {
1022
+ cached = cacheResidentCssEntry(state, entry, nodeId, kind);
1023
+ if (cached) {
1024
+ const record = state.parked.get(nodeId);
1025
+ if (record) record.layoutEligible = true;
1026
+ renderer._residentCssParkCount = Number(renderer._residentCssParkCount || 0) + 1;
1027
+ }
1028
+ }
1029
+ cssObject.visible = false;
1030
+ entry.currentType = 'GL';
1031
+ if (element.style?.display !== 'none') {
1032
+ element.style?.setProperty?.('display', 'none', 'important');
1033
+ }
1034
+ if (cached && !state.layoutRetryTimer) {
1035
+ const epoch = state.layoutEpoch;
1036
+ state.layoutRetryTimer = setTimeout(() => {
1037
+ state.layoutRetryTimer = null;
1038
+ if (residentTransitionStates.get(renderer) === state && state.layoutEpoch === epoch) {
1039
+ scheduleResidentCssLayoutWarm(renderer, module, nodeObjectsById);
1040
+ }
1041
+ }, 0);
1042
+ }
1043
+ return true;
1044
+ }
1045
+
1046
+ function scheduleResidentCssLayoutWarm(renderer, module, nodeObjectsById) {
1047
+ const state = residentTransitionStates.get(renderer);
1048
+ if (!state?.active || state.module !== module || state.nodeObjectsById !== nodeObjectsById ||
1049
+ renderer?._disposed === true || renderer?.isInLODMode !== true || module?.isLoading === true) return false;
1050
+ const visibleIds = module?._visibleIds || module?._prevVisibleIds || renderer?._visibleIds || null;
1051
+ if (visibleIds?.size > 0) {
1052
+ for (const nodeId of visibleIds) {
1053
+ const record = state.parked.get(String(nodeId || ''));
1054
+ if (record) record.layoutEligible = true;
1055
+ }
1056
+ }
1057
+ if (isPrewarmInteractionActive(module)) {
1058
+ if (!state.layoutRetryTimer) {
1059
+ const epoch = state.layoutEpoch;
1060
+ state.layoutRetryTimer = setTimeout(() => {
1061
+ state.layoutRetryTimer = null;
1062
+ if (residentTransitionStates.get(renderer) === state && state.layoutEpoch === epoch) {
1063
+ scheduleResidentCssLayoutWarm(renderer, module, nodeObjectsById);
1064
+ }
1065
+ }, 80);
1066
+ }
1067
+ return false;
1068
+ }
1069
+ if (state.layoutScheduled || state.layoutFrameScheduled) return false;
1070
+ if (!state.layoutQueue) {
1071
+ state.layoutQueue = [];
1072
+ state.layoutCursor = 0;
1073
+ for (const record of state.parked.values()) {
1074
+ if (record.layoutEligible === true && record.layoutPrepared !== true) state.layoutQueue.push(record);
1075
+ }
1076
+ }
1077
+ if (state.layoutCursor >= state.layoutQueue.length) {
1078
+ state.layoutQueue = null;
1079
+ return false;
1080
+ }
1081
+
1082
+ const epoch = state.layoutEpoch;
1083
+ state.layoutScheduled = true;
1084
+ const run = () => {
1085
+ state.layoutScheduled = false;
1086
+ if (residentTransitionStates.get(renderer) !== state || state.layoutEpoch !== epoch || !state.active ||
1087
+ renderer?._disposed === true || renderer?.isInLODMode !== true || renderer?._module !== module ||
1088
+ module?.nodeObjectsById !== nodeObjectsById || module?.isLoading === true) return;
1089
+ if (isPrewarmInteractionActive(module)) {
1090
+ state.layoutQueue = null;
1091
+ scheduleResidentCssLayoutWarm(renderer, module, nodeObjectsById);
1092
+ return;
1093
+ }
1094
+
1095
+ // Visibility can expand while the wheel is still settling after
1096
+ // NORMAL -> MID. Refresh from the latest set during idle so those
1097
+ // CSS owners are not created synchronously on MID -> NORMAL.
1098
+ const latestVisibleIds = module?._visibleIds || module?._prevVisibleIds || renderer?._visibleIds || null;
1099
+ const latestPriority = latestVisibleIds?.size > 0
1100
+ ? renderer?._getNearVisiblePriority?.(latestVisibleIds, nodeObjectsById, module?.camera)
1101
+ : null;
1102
+ if (Array.isArray(latestPriority) && latestPriority.length > 0) {
1103
+ renderer?._queueCss3dPrewarm?.(latestPriority, nodeObjectsById, module, 'MID');
1104
+ }
1105
+ if (residentTransitionStates.get(renderer) !== state || state.layoutEpoch !== epoch ||
1106
+ !Array.isArray(state.layoutQueue)) return;
1107
+ const layoutQueue = state.layoutQueue;
1108
+
1109
+ const startedAt = performance.now();
1110
+ let prepared = 0;
1111
+ while (state.layoutCursor < layoutQueue.length && prepared < 4 &&
1112
+ (prepared === 0 || performance.now() - startedAt < 2)) {
1113
+ const record = layoutQueue[state.layoutCursor++];
1114
+ if (state.parked.get(record.nodeId) !== record || record.entry?.isCssDirty === true ||
1115
+ record.cssObject?.visible === true || !record.element?.style) continue;
1116
+ record.cssObject.userData = record.cssObject.userData || {};
1117
+ record.cssObject.userData._residentTransitionPrepared = true;
1118
+ record.element.style.setProperty?.('visibility', 'visible', 'important');
1119
+ record.element.style.setProperty?.('opacity', '0', 'important');
1120
+ record.element.style.setProperty?.('pointer-events', 'none', 'important');
1121
+ record.element.style.setProperty?.('display', 'block', 'important');
1122
+ record.layoutPrepared = true;
1123
+ prepared++;
1124
+ }
1125
+ if (prepared > 0) {
1126
+ renderer._residentCssLayoutWarmCount = Number(renderer._residentCssLayoutWarmCount || 0) + prepared;
1127
+ module._css3dVisualChangedThisFrame = true;
1128
+ module._css3dVisualChangedSinceLastRender = true;
1129
+ }
1130
+ if (state.layoutQueue !== layoutQueue) return;
1131
+ if (state.layoutCursor < layoutQueue.length) {
1132
+ state.layoutFrameScheduled = true;
1133
+ const continueWarm = () => {
1134
+ state.layoutFrameScheduled = false;
1135
+ if (residentTransitionStates.get(renderer) === state && state.layoutEpoch === epoch) {
1136
+ scheduleResidentCssLayoutWarm(renderer, module, nodeObjectsById);
1137
+ }
1138
+ };
1139
+ if (typeof globalThis.requestAnimationFrame === 'function') globalThis.requestAnimationFrame(continueWarm);
1140
+ else setTimeout(continueWarm, 16);
1141
+ } else {
1142
+ state.layoutQueue = null;
1143
+ }
1144
+ };
1145
+ if (typeof globalThis.requestIdleCallback === 'function') globalThis.requestIdleCallback(run, { timeout: 120 });
1146
+ else setTimeout(run, 16);
1147
+ return true;
1148
+ }
1149
+
1150
+ function parkReadyResidentImage(renderer, entry, module, nodeObjectsById, selectionKey, nodeId, animatedGif, selected, interactiveOwner) {
1151
+ if (animatedGif === true || selected === true || interactiveOwner === true ||
1152
+ renderer?._hasActiveImageLodInstance?.(nodeId) !== true) return false;
1153
+ parkFullResCss(renderer, entry, module, nodeObjectsById, selectionKey, 'image');
1154
+ renderer._hideImageLodFullVisual?.(entry);
1155
+ renderer._setGlowVisibility?.(entry, false);
1156
+ return true;
1157
+ }
1158
+
1159
+ function restoreParkedFullResCss(renderer, entry, module, nodeObjectsById, selectionKey, lodBand, nodeIdValue) {
1160
+ if (!renderer || lodBand !== 'NORMAL') return false;
1161
+ const state = residentTransitionStates.get(renderer);
1162
+ const nodeId = String(nodeIdValue || entry?.model?.id || entry?.model?.Id || '').trim();
1163
+ const record = state?.parked?.get?.(nodeId) || null;
1164
+ const current = getEntryContentState(entry);
1165
+ const cssScene = module?.cssScene || module?.scene || null;
1166
+ const valid = !!record && state.module === module && state.nodeObjectsById === nodeObjectsById &&
1167
+ record.entry === entry && record.model === current.model && record.cssObject === entry?.cssObject &&
1168
+ record.element === entry?.cssObject?.element && cssScene &&
1169
+ (record.parent == null || record.parent === cssScene) &&
1170
+ (entry.cssObject.parent == null || entry.cssObject.parent === cssScene) && entry.isCssDirty !== true &&
1171
+ record.selectionKey === String(selectionKey || '') && record.source === current.source &&
1172
+ record.prompt === current.prompt && record.width === current.width && record.height === current.height &&
1173
+ record.media === current.media;
1174
+ if (!valid) {
1175
+ if (record) {
1176
+ resetPreparedLayoutRecord(record);
1177
+ state.parked.delete(nodeId);
1178
+ }
1179
+ if (state?.active) renderer._residentCssRestoreMissCount = Number(renderer._residentCssRestoreMissCount || 0) + 1;
1180
+ return false;
1181
+ }
1182
+
1183
+ const cssObject = record.cssObject;
1184
+ const element = record.element;
1185
+ const layoutPrepared = record.layoutPrepared === true && cssObject.userData?._residentTransitionPrepared === true;
1186
+ if (renderer._promoteFullResCssFringePrepared?.(entry) !== true) {
1187
+ renderer._clearFullResCssFringePrepared?.(entry);
1188
+ }
1189
+ if (cssObject.userData) delete cssObject.userData._fullResFringeCreated;
1190
+ if (cssObject.userData) cssObject.userData._residentTransitionPrepared = false;
1191
+ if (cssObject.parent !== cssScene) cssScene.add?.(cssObject);
1192
+ if (entry.glObject) {
1193
+ entry.glObject.updateWorldMatrix?.(true, false);
1194
+ entry.glObject.matrixWorld?.decompose?.(renderer._tmpWorldPos, renderer._tmpWorldQuat, renderer._tmpWorldScale);
1195
+ if (renderer._tmpWorldPos) cssObject.position?.copy?.(renderer._tmpWorldPos);
1196
+ if (renderer._tmpWorldQuat) cssObject.quaternion?.copy?.(renderer._tmpWorldQuat);
1197
+ entry.glObject.visible = true;
1198
+ if (entry.bodyMesh) entry.bodyMesh.visible = false;
1199
+ if (entry.tailMesh) entry.tailMesh.visible = false;
1200
+ }
1201
+ cssObject.visible = true;
1202
+ if (!layoutPrepared && element.style?.display !== 'block') element.style?.setProperty?.('display', 'block', 'important');
1203
+ if (element.style?.visibility !== 'visible') element.style?.setProperty?.('visibility', 'visible', 'important');
1204
+ if (element.style?.opacity !== '1') element.style?.setProperty?.('opacity', '1', 'important');
1205
+ if (layoutPrepared) element.style?.setProperty?.('pointer-events', record.pointerEvents || 'auto', 'important');
1206
+ if (element.style?.transition !== 'none') element.style?.setProperty?.('transition', 'none', 'important');
1207
+ const rootStyle = element.firstElementChild?.style || null;
1208
+ if (rootStyle && rootStyle.getPropertyValue?.('content-visibility') !== 'visible') {
1209
+ rootStyle.setProperty?.('content-visibility', 'visible', 'important');
1210
+ rootStyle.setProperty?.('contain-intrinsic-size', 'auto', 'important');
1211
+ }
1212
+ cssObject.updateMatrixWorld?.(true);
1213
+ entry.currentType = 'CSS';
1214
+ renderer._setCss3dLodClass?.(entry, renderer._shouldUseHighCss3dDetail?.(entry, module) !== false);
1215
+ renderer._nearCssVisibleIds?.add?.(nodeId);
1216
+ if (record.kind === 'image') renderer._syncCssImageBodyBridge?.(entry, module);
1217
+ if (record.kind === 'video') globalThis.MindMapCss3DManager?.syncVideoNodeVisibilityPlayback?.(entry.model, cssObject, true);
1218
+ if (typeof renderer._deleteLodImageCssFallbackNodeId === 'function') {
1219
+ renderer._deleteLodImageCssFallbackNodeId(nodeId);
1220
+ } else {
1221
+ renderer._lodImageCssFallbackNodeIds?.delete?.(nodeId);
1222
+ invalidateAnimatedGifCssFallbackCandidateCache(renderer);
1223
+ invalidateActiveCssMediaFallbackCountCache(renderer);
1224
+ }
1225
+ state.parked.delete(nodeId);
1226
+ renderer._residentCssRestoreCount = Number(renderer._residentCssRestoreCount || 0) + 1;
1227
+ module._css3dVisualChangedThisFrame = true;
1228
+ module._css3dVisualChangedSinceLastRender = true;
1229
+ return true;
1230
+ }
1231
+
1232
+ function completeFullResTransition(renderer, allowedCssCount) {
1233
+ if (!renderer || Number(renderer._nearCssVisibleIds?.size || 0) < Number(allowedCssCount || 0) ||
1234
+ renderer._hasCss3dQueueItems?.() === true || Number(renderer._css3dQueuedMap?.size || 0) > 0) return false;
1235
+ if (renderer._nearEntryBoostFrames > 0) renderer._residentBoostClearCount = Number(renderer._residentBoostClearCount || 0) + 1;
1236
+ renderer._nearEntryBoostFrames = 0;
1237
+ const state = residentTransitionStates.get(renderer);
1238
+ if (state) {
1239
+ clearTransitionRecords(state);
1240
+ state.active = false;
1241
+ }
1242
+ return true;
1243
+ }
1244
+
1245
+ function ensureResidentLineDetails(renderer, lodBand) {
1246
+ if (!renderer || lodBand !== 'MID') return false;
1247
+ if (renderer.lineDataDirty === true || renderer._lineDetailsPatchPending === true) {
1248
+ renderer._markLineDetailsDirty?.();
1249
+ return false;
1250
+ }
1251
+ renderer._residentStableLineReuseCount = Number(renderer._residentStableLineReuseCount || 0) + 1;
1252
+ if (renderer.instancedLineMesh) renderer.instancedLineMesh.visible = renderer._shouldShowInstancedLineMesh?.(lodBand) === true;
1253
+ return true;
1254
+ }
1255
+
1256
+ function reusePreparedImageInstances(renderer, state) {
1257
+ if (renderer?.isInLODMode !== false || renderer?._imageInstancesDirtyReason !== 'image-slot-invalidated' ||
1258
+ state?.imageCandidateIds?.size !== state?.imagePreparedIds?.size) return false;
1259
+ const priorIds = Array.isArray(renderer.imageInstanceData?.nodeIds) ? renderer.imageInstanceData.nodeIds : [];
1260
+ if (priorIds.length !== state.imagePreparedIds.size) return false;
1261
+ for (let i = 0; i < priorIds.length; i++) {
1262
+ const nodeId = priorIds[i];
1263
+ if (!state.imagePreparedIds.has(nodeId) || renderer.imageAtlasSlots?.get?.(nodeId)?.ready !== true) return false;
1264
+ }
1265
+ renderer._clearImageInstancesDirty?.();
1266
+ renderer._residentImageBufferReuseCount = Number(renderer._residentImageBufferReuseCount || 0) + 1;
1267
+ return true;
1268
+ }
1269
+
1270
+ function prepareIdleResidentImageInstances(state) {
1271
+ const renderer = state?.renderer;
1272
+ const module = state?.module;
1273
+ const nodeObjectsById = state?.nodeObjectsById;
1274
+ if (!renderer || !module || !nodeObjectsById || renderer._disposed === true ||
1275
+ renderer._module !== module || module.nodeObjectsById !== nodeObjectsById ||
1276
+ renderer.isInLODMode !== false || module.isLoading === true ||
1277
+ isPrewarmInteractionActive(module) || renderer._hasPendingImageAtlasWork?.() === true ||
1278
+ state.imageCandidateIds?.size !== state.imagePreparedIds?.size ||
1279
+ typeof renderer._updateImageInstanceData !== 'function' ||
1280
+ typeof renderer._applyImageInstanceData !== 'function') return false;
1281
+
1282
+ const committedIds = Array.isArray(renderer.imageInstanceData?.nodeIds)
1283
+ ? renderer.imageInstanceData.nodeIds
1284
+ : [];
1285
+ const committedSet = new Set(committedIds);
1286
+ let missingPreparedImage = false;
1287
+ for (const nodeId of state.imagePreparedIds) {
1288
+ if (!committedSet.has(nodeId)) {
1289
+ missingPreparedImage = true;
1290
+ break;
1291
+ }
1292
+ }
1293
+ if (!missingPreparedImage && renderer._imageInstancesDirty !== true) return false;
1294
+
1295
+ renderer._updateImageInstanceData(nodeObjectsById, true);
1296
+ renderer._applyImageInstanceData();
1297
+ renderer._lastAppliedImageAtlasSignature =
1298
+ renderer._pendingImageAtlasPatchSignature ||
1299
+ renderer._buildImageAtlasPatchSignature?.() || '';
1300
+ renderer._pendingImageAtlasPatchSignature = '';
1301
+ renderer._imageAtlasRebuildPending = false;
1302
+ renderer._imageAtlasRebuildDeferredUntil = 0;
1303
+ renderer._clearImageInstancesDirty?.();
1304
+ renderer._syncResidentCountsAfterDelta?.();
1305
+ if (renderer.instancedImageMesh) renderer.instancedImageMesh.visible = false;
1306
+ renderer._residentGpuWarmKey = '';
1307
+ renderer._residentGpuWarmOffscreenComplete = false;
1308
+ renderer._residentImageIdlePatchCount = Number(renderer._residentImageIdlePatchCount || 0) + 1;
1309
+ return true;
1310
+ }
1311
+
1312
+ function stagePreparedResidentLineRow(state, entry, lineData) {
1313
+ const renderer = state?.renderer;
1314
+ const model = entry?.model || null;
1315
+ const nodeId = String(model?.id || model?.Id || '');
1316
+ const nodeIds = renderer?.instanceData?.nodeIds;
1317
+ const geometry = renderer?.instancedMesh?.geometry || null;
1318
+ const lineCountAttr = geometry?.getAttribute?.('instanceLineCount') || null;
1319
+ const lineHeightAttr = geometry?.getAttribute?.('instanceLineHeightPx') || null;
1320
+ const linePaddingAttr = geometry?.getAttribute?.('instanceLinePaddingPx') || null;
1321
+ const lineDataArray = renderer?.lineDataArray || null;
1322
+ const rowCount = Number(renderer?.lineTextureRows || 0);
1323
+ if (!nodeId || !Array.isArray(nodeIds) || !lineData || !lineCountAttr || !lineHeightAttr ||
1324
+ !linePaddingAttr || !lineDataArray || rowCount <= 0) return false;
1325
+ if (state.lineNodeIds !== nodeIds) {
1326
+ state.lineNodeIds = nodeIds;
1327
+ state.lineIndexById = new Map();
1328
+ for (let i = 0; i < nodeIds.length; i++) state.lineIndexById.set(String(nodeIds[i] || ''), i);
1329
+ }
1330
+ const index = state.lineIndexById.get(nodeId);
1331
+ const rowWidth = Math.floor(lineDataArray.length / rowCount);
1332
+ if (!Number.isInteger(index) || index < 0 || index >= lineCountAttr.count || rowWidth <= 0) return false;
1333
+ const lineCounts = renderer.instanceData.lineCounts || (renderer.instanceData.lineCounts = []);
1334
+ const lineLengths = renderer.instanceData.lineLengths || (renderer.instanceData.lineLengths = []);
1335
+ const lineHeights = renderer.instanceData.lineHeights || (renderer.instanceData.lineHeights = []);
1336
+ const linePaddings = renderer.instanceData.linePaddings || (renderer.instanceData.linePaddings = []);
1337
+ const lineCount = Number(lineData.lineCount || 0);
1338
+ const lineHeight = Number(lineData.lineHeightPx || 24);
1339
+ const paddingX = Number(lineData.paddingX || 0);
1340
+ const paddingY = Number(lineData.paddingY || 0);
1341
+ lineCounts[index] = lineCount;
1342
+ lineHeights[index] = lineHeight;
1343
+ linePaddings[index * 2] = paddingX;
1344
+ linePaddings[index * 2 + 1] = paddingY;
1345
+ lineCountAttr.setX(index, lineCount);
1346
+ lineHeightAttr.setX(index, lineHeight);
1347
+ linePaddingAttr.setXY(index, paddingX, paddingY);
1348
+ const base = index * rowWidth;
1349
+ for (let j = 0; j < rowWidth; j++) {
1350
+ const value = Number(lineData.lineLengths?.[j] || 0);
1351
+ lineLengths[base + j] = value;
1352
+ lineDataArray[base + j] = Math.max(0, Math.min(255, Math.round(value * 255)));
1353
+ }
1354
+ state.lineRowsStaged = true;
1355
+ state.preparedLineRowCount = Number(state.preparedLineRowCount || 0) + 1;
1356
+ return true;
1357
+ }
1358
+
1359
+ function commitPreparedResidentLineRows(state) {
1360
+ if (!state?.lineRowsStaged) return false;
1361
+ const renderer = state.renderer;
1362
+ const geometry = renderer?.instancedMesh?.geometry || null;
1363
+ const lineCountAttr = geometry?.getAttribute?.('instanceLineCount') || null;
1364
+ const lineHeightAttr = geometry?.getAttribute?.('instanceLineHeightPx') || null;
1365
+ const linePaddingAttr = geometry?.getAttribute?.('instanceLinePaddingPx') || null;
1366
+ if (!lineCountAttr || !lineHeightAttr || !linePaddingAttr || !renderer?.lineDataTexture) return false;
1367
+ lineCountAttr.needsUpdate = true;
1368
+ lineHeightAttr.needsUpdate = true;
1369
+ linePaddingAttr.needsUpdate = true;
1370
+ renderer.lineDataTexture.needsUpdate = true;
1371
+ renderer.lineDataDirty = false;
1372
+ renderer._lineDetailsPatchPending = false;
1373
+ renderer._lastInstanceCount = Number(renderer.instanceData?.nodeIds?.length || 0);
1374
+ renderer._residentGpuWarmKey = '';
1375
+ renderer._residentLineBufferPrewarmCount = Number(state.preparedLineRowCount || 0);
1376
+ state.lineRowsStaged = false;
1377
+ return true;
1378
+ }
1379
+
1380
+ function prepareIdleResidentBuffers(state) {
1381
+ const renderer = state?.renderer;
1382
+ const module = state?.module;
1383
+ const nodeObjectsById = state?.nodeObjectsById;
1384
+ if (!renderer || !module || !nodeObjectsById || renderer._disposed === true ||
1385
+ renderer._module !== module || module.nodeObjectsById !== nodeObjectsById ||
1386
+ renderer.isInLODMode !== false || renderer._hasResidentLodInstances?.() === true ||
1387
+ module.isLoading === true || isPrewarmInteractionActive(module) ||
1388
+ typeof renderer._updateInstanceData !== 'function' || typeof renderer._applyInstanceData !== 'function') return false;
1389
+ renderer._residentBuildPhase = 'initial-build';
1390
+ renderer._updateInstanceData(nodeObjectsById);
1391
+ renderer._applyInstanceData();
1392
+ renderer._syncResidentCountsAfterDelta?.();
1393
+ renderer._lineDetailsPatchPending = renderer._residentLineFallbackUsed === true;
1394
+ renderer._clearInstancesDirty?.();
1395
+ renderer._clearImageInstancesDirty?.();
1396
+ renderer._positionsOnlyDirty = false;
1397
+ renderer._dirtyPositionIds?.clear?.();
1398
+ renderer._residentRebuildPending = false;
1399
+ renderer._residentRebuildDeferredUntil = 0;
1400
+ renderer._noteResidentFullBuild?.('initial-build', 'MID');
1401
+ renderer._residentIdleBuildCount = Number(renderer._residentIdleBuildCount || 0) + 1;
1402
+ renderer._residentLineBufferPrewarmCount = Number(renderer.instanceData?.nodeIds?.length || 0);
1403
+ renderer._residentGpuWarmKey = '';
1404
+ [renderer.instancedMesh, renderer.instancedBorderLineMesh, renderer.instancedLineMesh,
1405
+ renderer.instancedHaloMesh, renderer.instancedConsoleMesh, renderer.instancedImageMesh]
1406
+ .filter(Boolean).forEach(mesh => { mesh.visible = false; });
1407
+ renderer._setInstancedAgentBadgeVisibility?.(false);
1408
+ renderer._setInstancedFarInsetBorderVisibility?.(false);
1409
+ return renderer._hasResidentLodInstances?.() === true;
1410
+ }
1411
+
1412
+ function retryResidentPreparation(state, delay = 80) {
1413
+ if (!state || state.retryTimer) return;
1414
+ state.retryTimer = setTimeout(() => {
1415
+ state.retryTimer = null;
1416
+ if (residentLinePrewarmStates.get(state.renderer) !== state || state.renderer?._disposed === true ||
1417
+ state.renderer?._module !== state.module || state.module?.nodeObjectsById !== state.nodeObjectsById) return;
1418
+ scheduleResidentLinePrewarm(state.renderer, state.module, state.nodeObjectsById);
1419
+ }, delay);
1420
+ }
1421
+
1422
+ function queueResidentLinePrewarm(state) {
1423
+ if (!state || state.scheduled || state.complete) return;
1424
+ state.scheduled = true;
1425
+ const run = deadline => {
1426
+ state.scheduled = false;
1427
+ if (residentLinePrewarmStates.get(state.renderer) !== state || state.renderer?._disposed === true ||
1428
+ state.renderer?._module !== state.module || state.module?.nodeObjectsById !== state.nodeObjectsById) return;
1429
+ if (state.module?.isLoading === true ||
1430
+ state.key !== `${Number(state.renderer?._instancesDirtySerial || 0)}:${Number(state.nodeObjectsById.size || 0)}` ||
1431
+ isPrewarmInteractionActive(state.module)) {
1432
+ retryResidentPreparation(state);
1433
+ return;
1434
+ }
1435
+ if (!state.entries) state.entries = Array.from(state.nodeObjectsById.values());
1436
+ const startedAt = performance.now();
1437
+ let processed = 0;
1438
+ while (state.cursor < state.entries.length && processed < 4) {
1439
+ const entry = state.entries[state.cursor++];
1440
+ const model = entry?.model || null;
1441
+ const contentType = String(model?.contentType ?? model?.ContentType ?? '').toLowerCase();
1442
+ if (model && !['image', 'video', 'youtube', 'pdf', 'audio', 'webpage', 'iframe'].includes(contentType)) {
1443
+ const width = Number(model.width || 400);
1444
+ const height = Number(model.height || 200);
1445
+ if (entry.lodSeed === undefined) entry.lodSeed = Math.random() * 100;
1446
+ if (!getPreparedLineData(state.renderer, entry, width, height)) {
1447
+ rememberPreparedLine(state.renderer, entry, width, height,
1448
+ state.renderer._getLineDataForNode?.(model, entry.lodSeed, width, height, entry));
1449
+ }
1450
+ stagePreparedResidentLineRow(state, entry,
1451
+ getPreparedLineData(state.renderer, entry, width, height));
1452
+ state.prepared++;
1453
+ } else if (model && contentType === 'image') {
1454
+ const nodeId = String(model.id || model.Id || '');
1455
+ if (nodeId) state.imageCandidateIds.add(nodeId);
1456
+ const slot = state.imagePass > 0 ? state.renderer._ensureImageLodThumbnail?.(entry) || null : null;
1457
+ if (slot?.ready === true) {
1458
+ if (nodeId) state.imagePreparedIds.add(nodeId);
1459
+ } else {
1460
+ state.pendingImageEntries.push(entry);
1461
+ }
1462
+ }
1463
+ processed++;
1464
+ if (performance.now() - startedAt >= 3 && Number(deadline?.timeRemaining?.() || 0) < 1) break;
1465
+ }
1466
+ if (state.cursor >= state.entries.length) {
1467
+ if (state.pendingImageEntries.length > 0 && state.imagePass < 20) {
1468
+ const isFirstImagePass = state.imagePass === 0;
1469
+ if (isFirstImagePass) commitPreparedResidentLineRows(state);
1470
+ if (isFirstImagePass) prepareImageAtlasCapacity(state.renderer, state.imageCandidateIds.size);
1471
+ state.entries = Array.from(new Set(state.pendingImageEntries));
1472
+ state.pendingImageEntries.length = 0;
1473
+ state.cursor = 0;
1474
+ state.imagePass++;
1475
+ if (isFirstImagePass) {
1476
+ queueResidentLinePrewarm(state);
1477
+ } else {
1478
+ setTimeout(() => {
1479
+ if (residentLinePrewarmStates.get(state.renderer) === state) queueResidentLinePrewarm(state);
1480
+ }, 250);
1481
+ }
1482
+ return;
1483
+ }
1484
+ prepareIdleResidentBuffers(state);
1485
+ commitPreparedResidentLineRows(state);
1486
+ state.complete = true;
1487
+ state.renderer._residentLinePrewarmCount = state.prepared;
1488
+ state.renderer._residentImagePrewarmCount = state.imagePreparedIds.size;
1489
+ state.renderer._residentImagePrewarmCandidateCount = state.imageCandidateIds.size;
1490
+ state.renderer._residentImagePrewarmComplete = state.pendingImageEntries.length === 0;
1491
+ if (state.renderer.isInLODMode === true && state.renderer._lineDetailsPatchPending === true) {
1492
+ state.renderer._markLineDetailsDirty?.();
1493
+ }
1494
+ prepareIdleResidentImageInstances(state);
1495
+ queueResidentGpuWarm(state);
1496
+ state.renderer._scheduleFullResCssFringePrewarm?.(state.nodeObjectsById, state.module);
1497
+ return;
1498
+ }
1499
+ queueResidentLinePrewarm(state);
1500
+ };
1501
+ if (typeof globalThis.requestIdleCallback === 'function') {
1502
+ globalThis.requestIdleCallback(run, { timeout: 120 });
1503
+ } else {
1504
+ setTimeout(() => run({ timeRemaining: () => 3, didTimeout: true }), 16);
1505
+ }
1506
+ }
1507
+
1508
+ function getResidentGpuKey(renderer) {
1509
+ const geometryKey = [renderer?.instancedMesh, renderer?.instancedBorderLineMesh, renderer?.instancedLineMesh,
1510
+ renderer?.instancedHaloMesh, renderer?.instancedConsoleMesh, renderer?.instancedImageMesh]
1511
+ .map(mesh => String(mesh?.geometry?.uuid || '-')).join(',');
1512
+ return `${Number(renderer?._residentGpuContextGeneration || 0)}:` +
1513
+ `${String(renderer?.lineDataTexture?.uuid || '-')}/${Number(renderer?.lineDataTexture?.version || 0)}:` +
1514
+ `${String(renderer?.imageAtlasTexture?.uuid || '-')}/${Number(renderer?.imageAtlasTexture?.version || 0)}:` +
1515
+ `${Number(renderer?.lineTextureRows || 0)}:${geometryKey}`;
1516
+ }
1517
+
1518
+ function invalidateResidentGpuWarm(renderer) {
1519
+ if (!renderer) return;
1520
+ renderer._residentGpuContextGeneration = Number(renderer._residentGpuContextGeneration || 0) + 1;
1521
+ renderer._residentGpuWarmKey = '';
1522
+ renderer._residentGpuWarmComplete = false;
1523
+ renderer._residentGpuWarmOffscreenComplete = false;
1524
+ renderer._residentImageAtlasWarmVersion = -1;
1525
+ }
1526
+
1527
+ function ensureResidentGpuContextTracking(renderer) {
1528
+ const canvas = renderer?.renderer?.domElement || null;
1529
+ if (!canvas?.addEventListener || renderer._residentGpuContextCanvas === canvas) return;
1530
+ const previousCanvas = renderer._residentGpuContextCanvas;
1531
+ if (previousCanvas?.removeEventListener) {
1532
+ previousCanvas.removeEventListener('webglcontextlost', renderer._residentGpuContextLostHandler);
1533
+ previousCanvas.removeEventListener('webglcontextrestored', renderer._residentGpuContextRestoredHandler);
1534
+ }
1535
+ const lost = () => {
1536
+ renderer._residentGpuContextLost = true;
1537
+ invalidateResidentGpuWarm(renderer);
1538
+ };
1539
+ const restored = () => {
1540
+ renderer._residentGpuContextLost = false;
1541
+ invalidateResidentGpuWarm(renderer);
1542
+ setTimeout(() => {
1543
+ const state = residentLinePrewarmStates.get(renderer);
1544
+ if (state && renderer?._disposed !== true) queueResidentGpuWarm(state);
1545
+ }, 0);
1546
+ };
1547
+ canvas.addEventListener('webglcontextlost', lost);
1548
+ canvas.addEventListener('webglcontextrestored', restored);
1549
+ renderer._residentGpuContextCanvas = canvas;
1550
+ renderer._residentGpuContextLostHandler = lost;
1551
+ renderer._residentGpuContextRestoredHandler = restored;
1552
+ }
1553
+
1554
+ function renderResidentWarmScene(webglRenderer, THREE, warmScene, warmCamera) {
1555
+ const gl = webglRenderer?.getContext?.();
1556
+ if (!gl || gl.isContextLost?.() === true) return false;
1557
+ if (typeof webglRenderer.getRenderTarget !== 'function' || typeof webglRenderer.setRenderTarget !== 'function' ||
1558
+ typeof webglRenderer.render !== 'function' || !THREE?.WebGLRenderTarget) return null;
1559
+ const previousTarget = webglRenderer.getRenderTarget();
1560
+ const previousFace = webglRenderer.getActiveCubeFace?.() ?? 0;
1561
+ const previousMip = webglRenderer.getActiveMipmapLevel?.() ?? 0;
1562
+ const warmTarget = new THREE.WebGLRenderTarget(1, 1, { depthBuffer: false, stencilBuffer: false });
1563
+ if (warmTarget.texture) {
1564
+ warmTarget.texture.generateMipmaps = false;
1565
+ const encoding = previousTarget?.texture?.encoding ?? webglRenderer.outputEncoding;
1566
+ if (encoding != null) warmTarget.texture.encoding = encoding;
1567
+ }
1568
+ try {
1569
+ webglRenderer.setRenderTarget(warmTarget);
1570
+ webglRenderer.render(warmScene, warmCamera);
1571
+ return gl.isContextLost?.() !== true;
1572
+ } finally {
1573
+ try {
1574
+ webglRenderer.setRenderTarget(previousTarget, previousFace, previousMip);
1575
+ } finally {
1576
+ warmTarget.dispose?.();
1577
+ }
1578
+ }
1579
+ }
1580
+
1581
+ function retryResidentGpuWarm(state) {
1582
+ if (!state || state.gpuRetryTimer) return;
1583
+ state.gpuRetryTimer = setTimeout(() => {
1584
+ state.gpuRetryTimer = null;
1585
+ if (residentLinePrewarmStates.get(state.renderer) === state) queueResidentGpuWarm(state);
1586
+ }, GPU_WARM_RETRY_DELAY_MS);
1587
+ }
1588
+
1589
+ function queueResidentGpuWarm(state) {
1590
+ if (!state?.complete || state.gpuScheduled) return;
1591
+ const renderer = state.renderer;
1592
+ if (residentLinePrewarmStates.get(renderer) !== state || renderer?._disposed === true ||
1593
+ renderer?._module !== state.module || state.module?.nodeObjectsById !== state.nodeObjectsById ||
1594
+ state.module?.isLoading === true ||
1595
+ state.key !== `${Number(renderer?._instancesDirtySerial || 0)}:${Number(state.nodeObjectsById.size || 0)}`) return;
1596
+ if (isPrewarmInteractionActive(state.module)) {
1597
+ retryResidentGpuWarm(state);
1598
+ return;
1599
+ }
1600
+ const webglRenderer = renderer?.renderer || null;
1601
+ ensureResidentGpuContextTracking(renderer);
1602
+ const gl = webglRenderer?.getContext?.();
1603
+ if (renderer?._residentGpuContextLost === true || gl?.isContextLost?.() === true) return;
1604
+ const gpuKey = getResidentGpuKey(renderer);
1605
+ if (!webglRenderer || renderer._residentGpuWarmKey === gpuKey) return;
1606
+ if (renderer._hasPendingImageAtlasWork?.() === true) {
1607
+ retryResidentGpuWarm(state);
1608
+ return;
1609
+ }
1610
+ state.gpuScheduled = true;
1611
+ const run = () => {
1612
+ state.gpuScheduled = false;
1613
+ if (residentLinePrewarmStates.get(renderer) !== state || renderer?._disposed === true ||
1614
+ renderer?._module !== state.module || state.module?.nodeObjectsById !== state.nodeObjectsById ||
1615
+ state.module?.isLoading === true || state.key !== `${Number(renderer._instancesDirtySerial || 0)}:${Number(state.nodeObjectsById.size || 0)}`) return;
1616
+ if (isPrewarmInteractionActive(state.module) || renderer._hasPendingImageAtlasWork?.() === true) {
1617
+ retryResidentGpuWarm(state);
1618
+ return;
1619
+ }
1620
+ if (renderer?._residentGpuContextLost === true || webglRenderer?.getContext?.()?.isContextLost?.() === true) return;
1621
+ try {
1622
+ if (renderer.lineDataTexture) webglRenderer.initTexture?.(renderer.lineDataTexture);
1623
+ if (renderer.imageAtlasTexture && Number(renderer.imageAtlasSlots?.size || 0) > 0) {
1624
+ webglRenderer.initTexture?.(renderer.imageAtlasTexture);
1625
+ renderer._residentImageAtlasWarmVersion = Number(renderer.imageAtlasTexture.version || 0);
1626
+ }
1627
+ const THREE = globalThis.THREE;
1628
+ if (THREE?.Scene && typeof webglRenderer.compile === 'function' && state.module?.camera) {
1629
+ const warmScene = new THREE.Scene();
1630
+ try {
1631
+ [renderer.instancedMesh, renderer.instancedBorderLineMesh, renderer.instancedLineMesh,
1632
+ renderer.instancedHaloMesh, renderer.instancedConsoleMesh, renderer.instancedImageMesh]
1633
+ .filter(Boolean)
1634
+ .forEach(mesh => {
1635
+ const clone = mesh.clone?.();
1636
+ if (!clone) return;
1637
+ clone.visible = true;
1638
+ clone.frustumCulled = false;
1639
+ warmScene.add(clone);
1640
+ });
1641
+ const warmCamera = state.module.camera.clone?.() || state.module.camera;
1642
+ webglRenderer.compile(warmScene, warmCamera);
1643
+ const offscreenResult = renderResidentWarmScene(webglRenderer, THREE, warmScene, warmCamera);
1644
+ if (offscreenResult === false) return;
1645
+ renderer._residentGpuWarmOffscreenComplete = offscreenResult === true;
1646
+ } finally {
1647
+ warmScene.clear?.();
1648
+ }
1649
+ }
1650
+ renderer._residentGpuWarmKey = getResidentGpuKey(renderer);
1651
+ renderer._residentGpuWarmComplete = true;
1652
+ reusePreparedImageInstances(renderer, state);
1653
+ state.gpuFailureCount = 0;
1654
+ } catch (error) {
1655
+ console.warn('[RenderPlan] Resident GPU warmup deferred.', error);
1656
+ state.gpuFailureCount = Number(state.gpuFailureCount || 0) + 1;
1657
+ if (state.gpuFailureCount <= 3) retryResidentGpuWarm(state);
1658
+ }
1659
+ };
1660
+ if (typeof globalThis.requestIdleCallback === 'function') {
1661
+ globalThis.requestIdleCallback(run, { timeout: 300 });
1662
+ } else {
1663
+ setTimeout(run, 32);
1664
+ }
1665
+ }
1666
+
1667
+ function scheduleResidentLinePrewarm(renderer, module, nodeObjectsById) {
1668
+ if (!renderer || !module || !nodeObjectsById?.values || module.isLoading === true) return;
1669
+ scheduleResidentCssLayoutWarm(renderer, module, nodeObjectsById);
1670
+ const key = `${Number(renderer._instancesDirtySerial || 0)}:${Number(nodeObjectsById.size || 0)}`;
1671
+ let state = residentLinePrewarmStates.get(renderer);
1672
+ if (!state || state.key !== key || state.nodeObjectsById !== nodeObjectsById) {
1673
+ state = {
1674
+ renderer, module, nodeObjectsById, key, entries: null, cursor: 0, prepared: 0,
1675
+ scheduled: false, retryTimer: null, complete: false, gpuScheduled: false, gpuRetryTimer: null, gpuFailureCount: 0,
1676
+ imagePass: 0, imageCandidateIds: new Set(), imagePreparedIds: new Set(), pendingImageEntries: []
1677
+ };
1678
+ residentLinePrewarmStates.set(renderer, state);
1679
+ }
1680
+ if (state.complete && renderer.isInLODMode === false &&
1681
+ renderer._imageInstancesDirtyReason === 'image-slot-invalidated') {
1682
+ const staleImageEntries = [];
1683
+ for (const nodeId of state.imageCandidateIds) {
1684
+ if (renderer.imageAtlasSlots?.get?.(nodeId)?.ready === true) continue;
1685
+ const entry = nodeObjectsById.get?.(nodeId) || null;
1686
+ if (entry) {
1687
+ state.imagePreparedIds.delete(nodeId);
1688
+ staleImageEntries.push(entry);
1689
+ }
1690
+ }
1691
+ if (staleImageEntries.length > 0) {
1692
+ state.entries = staleImageEntries;
1693
+ state.cursor = 0;
1694
+ state.complete = false;
1695
+ state.imagePass = 1;
1696
+ state.pendingImageEntries.length = 0;
1697
+ }
1698
+ }
1699
+ queueResidentLinePrewarm(state);
1700
+ if (state.complete) {
1701
+ prepareIdleResidentImageInstances(state);
1702
+ queueResidentGpuWarm(state);
1703
+ renderer._scheduleFullResCssFringePrewarm?.(nodeObjectsById, module);
1704
+ }
1705
+ }
1706
+
1707
+ function areResidentLinesPrepared(renderer, nodeObjectsById, nodeIds) {
1708
+ if (!renderer || !nodeObjectsById?.get || !Array.isArray(nodeIds)) return false;
1709
+ for (let i = 0; i < nodeIds.length; i++) {
1710
+ const entry = nodeObjectsById.get(nodeIds[i]);
1711
+ const model = entry?.model || null;
1712
+ if (!model || !getPreparedLineData(renderer, entry, model.width || 400, model.height || 200)) return false;
1713
+ }
1714
+ return true;
1715
+ }
1716
+
1717
+ function initialLineTextureRows(maxInstances) {
1718
+ return Math.min(Math.max(1, Number(maxInstances || 1)), INITIAL_LINE_TEXTURE_ROWS);
1719
+ }
1720
+
1721
+ function ensureLineTextureCapacity(renderer, requiredCount, width) {
1722
+ const currentRows = Number(renderer?.lineTextureRows || 0);
1723
+ const maxRows = Math.max(1, Number(renderer?.maxInstances || requiredCount || 1));
1724
+ if (!renderer || Number(requiredCount || 0) <= currentRows || currentRows >= maxRows) return false;
1725
+ let nextRows = Math.max(INITIAL_LINE_TEXTURE_ROWS, currentRows || 1);
1726
+ while (nextRows < requiredCount && nextRows < maxRows) nextRows *= 2;
1727
+ nextRows = Math.min(nextRows, maxRows);
1728
+ const THREE = globalThis.THREE;
1729
+ if (!THREE?.DataTexture) return false;
1730
+ const rowWidth = Math.max(1, Number(width || 1));
1731
+ const data = new Uint8Array(nextRows * rowWidth);
1732
+ data.set(renderer.lineDataArray?.subarray?.(0, data.length) || []);
1733
+ const previous = renderer.lineDataTexture || null;
1734
+ const texture = new THREE.DataTexture(data, rowWidth, nextRows, THREE.RedFormat, THREE.UnsignedByteType);
1735
+ texture.minFilter = previous?.minFilter ?? THREE.NearestFilter;
1736
+ texture.magFilter = previous?.magFilter ?? THREE.NearestFilter;
1737
+ texture.wrapS = previous?.wrapS ?? THREE.ClampToEdgeWrapping;
1738
+ texture.wrapT = previous?.wrapT ?? THREE.ClampToEdgeWrapping;
1739
+ texture.needsUpdate = true;
1740
+ renderer.lineDataArray = data;
1741
+ renderer.lineDataTexture = texture;
1742
+ renderer.lineTextureRows = nextRows;
1743
+ renderer._residentGpuWarmKey = '';
1744
+ const uniforms = renderer.instancedLineMesh?.material?.uniforms || null;
1745
+ if (uniforms?.uLineDataTex) uniforms.uLineDataTex.value = texture;
1746
+ if (uniforms?.uLineDataSize?.value?.set) uniforms.uLineDataSize.value.set(rowWidth, nextRows);
1747
+ previous?.dispose?.();
1748
+ return true;
1749
+ }
1750
+
1751
+ function getFrameSampleState(renderer) {
1752
+ let state = frameSampleStates.get(renderer);
1753
+ if (!state) {
1754
+ state = { samples: new Array(FRAME_SAMPLE_LIMIT), cursor: 0, count: 0 };
1755
+ frameSampleStates.set(renderer, state);
1756
+ }
1757
+ return state;
1758
+ }
1759
+
1760
+ function recordFrame(renderer, profile) {
1761
+ if (!renderer || !profile) return;
1762
+ const state = getFrameSampleState(renderer);
1763
+ const sections = profile.sections || {};
1764
+ let viewSyncMs = 0;
1765
+ for (let i = 0; i < VIEW_SYNC_SECTION_KEYS.length; i++) {
1766
+ viewSyncMs += Number(sections[VIEW_SYNC_SECTION_KEYS[i]] || 0);
1767
+ }
1768
+ const sample = state.samples[state.cursor] || {};
1769
+ sample.frameMs = Number(profile.durationMs || 0);
1770
+ sample.visibilityMs = Number(sections.visibility || 0);
1771
+ sample.viewSyncMs = viewSyncMs;
1772
+ sample.css3dRenderMs = Number(sections.css3dRender || 0);
1773
+ sample.stableFullResSkipped = renderer._lastFullResStablePlanSkipped === true;
1774
+ state.samples[state.cursor] = sample;
1775
+ state.cursor = (state.cursor + 1) % FRAME_SAMPLE_LIMIT;
1776
+ state.count = Math.min(FRAME_SAMPLE_LIMIT, state.count + 1);
1777
+ }
1778
+
1779
+ function beginFrame(renderer) {
1780
+ if (renderer) renderer._lastFullResStablePlanSkipped = false;
1781
+ }
1782
+
1783
+ function percentile(state, field, ratio) {
1784
+ if (!state?.count) return 0;
1785
+ const values = [];
1786
+ for (let i = 0; i < state.count; i++) {
1787
+ const value = Number(state.samples[i]?.[field] || 0);
1788
+ if (Number.isFinite(value)) values.push(value);
1789
+ }
1790
+ if (values.length === 0) return 0;
1791
+ values.sort((a, b) => a - b);
1792
+ return Number(values[Math.max(0, Math.ceil(values.length * ratio) - 1)].toFixed(2));
1793
+ }
1794
+
1795
+ function getImageAtlasProbe(renderer) {
1796
+ const canvas = renderer?.imageAtlasCanvas || null;
1797
+ const readyEntry = Array.from(renderer?.imageAtlasSlots?.entries?.() || [])
1798
+ .find(([, slot]) => slot?.ready === true) || null;
1799
+ if (!canvas || !readyEntry) return '-';
1800
+ try {
1801
+ const slot = readyEntry[1];
1802
+ const columns = Number(renderer.imageAtlasColumns || 1);
1803
+ const tile = Math.max(1, Math.floor(Number(canvas.width || 1) / columns));
1804
+ const col = Number(slot.slotIndex || 0) % columns;
1805
+ const row = Math.floor(Number(slot.slotIndex || 0) / columns);
1806
+ const context = canvas.getContext?.('2d', { alpha: false }) || null;
1807
+ const pixel = context?.getImageData?.(
1808
+ Math.min(canvas.width - 1, Math.floor(col * tile + tile * 0.5)),
1809
+ Math.min(canvas.height - 1, Math.floor(row * tile + tile * 0.5)), 1, 1)?.data;
1810
+ let colored = 0;
1811
+ let sampled = 0;
1812
+ for (const [, candidate] of Array.from(renderer.imageAtlasSlots.entries()).slice(0, 24)) {
1813
+ if (candidate?.ready !== true) continue;
1814
+ const candidateCol = Number(candidate.slotIndex || 0) % columns;
1815
+ const candidateRow = Math.floor(Number(candidate.slotIndex || 0) / columns);
1816
+ const sample = context?.getImageData?.(
1817
+ Math.min(canvas.width - 1, Math.floor(candidateCol * tile + tile * 0.5)),
1818
+ Math.min(canvas.height - 1, Math.floor(candidateRow * tile + tile * 0.5)), 1, 1)?.data;
1819
+ if (sample) {
1820
+ sampled++;
1821
+ if (Math.abs(sample[0] - 238) + Math.abs(sample[1] - 242) + Math.abs(sample[2] - 247) > 12) colored++;
1822
+ }
1823
+ }
1824
+ const cpuUv = Array.from(renderer?.imageInstanceData?.uvRects || []).slice(0, 4)
1825
+ .map(value => Number(value || 0).toFixed(4)).join(',');
1826
+ const uvAttr = renderer?.instancedImageMesh?.geometry?.getAttribute?.('instanceUvRect') || null;
1827
+ const gpuUv = uvAttr && uvAttr.count > 0
1828
+ ? [uvAttr.getX(0), uvAttr.getY(0), uvAttr.getZ(0), uvAttr.getW(0)]
1829
+ .map(value => Number(value || 0).toFixed(4)).join(',')
1830
+ : '-';
1831
+ return pixel ? `${pixel[0]},${pixel[1]},${pixel[2]} · color ${colored}/${sampled} · uv ${cpuUv}/${gpuUv}` : '-';
1832
+ } catch { return 'blocked'; }
1833
+ }
1834
+
1835
+ function getDiagnostics(renderer) {
1836
+ const state = renderer ? frameSampleStates.get(renderer) : null;
1837
+ let stableFullResSampleCount = 0;
1838
+ for (let i = 0; i < Number(state?.count || 0); i++) {
1839
+ if (state.samples[i]?.stableFullResSkipped === true) stableFullResSampleCount++;
1840
+ }
1841
+ return {
1842
+ build: BUILD_ID,
1843
+ stableFullResSkipCount: Number(renderer?._fullResStablePlanSkipCount || 0),
1844
+ skippedLastPlan: renderer?._lastFullResStablePlanSkipped === true,
1845
+ sampleCount: Number(state?.count || 0),
1846
+ stableFullResSampleCount,
1847
+ frameP50Ms: percentile(state, 'frameMs', 0.50),
1848
+ frameP95Ms: percentile(state, 'frameMs', 0.95),
1849
+ visibilityP95Ms: percentile(state, 'visibilityMs', 0.95),
1850
+ viewSyncP95Ms: percentile(state, 'viewSyncMs', 0.95),
1851
+ css3dRenderP95Ms: percentile(state, 'css3dRenderMs', 0.95),
1852
+ fullResCssStableReuseCount: Number(renderer?._fullResCssStableReuseCount || 0),
1853
+ cssMediaFrameDomReuseCount,
1854
+ cssMediaFrameDomApplyCount,
1855
+ residentLinePrewarmCount: Number(renderer?._residentLinePrewarmCount || 0),
1856
+ residentLineBufferPrewarmCount: Number(renderer?._residentLineBufferPrewarmCount || 0),
1857
+ residentIdleBuildCount: Number(renderer?._residentIdleBuildCount || 0),
1858
+ residentImagePrewarmCount: Number(renderer?._residentImagePrewarmCount || 0),
1859
+ residentImagePrewarmCandidateCount: Number(renderer?._residentImagePrewarmCandidateCount || 0),
1860
+ residentImageBufferReuseCount: Number(renderer?._residentImageBufferReuseCount || 0),
1861
+ residentImageIdlePatchCount: Number(renderer?._residentImageIdlePatchCount || 0),
1862
+ residentImageInstanceCount: Number(renderer?.instancedImageMesh?.geometry?.instanceCount || 0),
1863
+ residentImageMeshVisible: renderer?.instancedImageMesh?.visible === true,
1864
+ residentImageAtlasReadyCount: Array.from(renderer?.imageAtlasSlots?.values?.() || [])
1865
+ .filter(slot => slot?.ready === true).length,
1866
+ residentImageAtlasProbe: getImageAtlasProbe(renderer),
1867
+ residentBuildPhase: String(renderer?._residentBuildPhase || ''),
1868
+ residentFullBuildCount: Number(renderer?._residentFullBuildCount || 0),
1869
+ residentLastFullBuildReason: String(renderer?._lastResidentFullBuildReason || ''),
1870
+ residentInstancesDirtyReason: renderer?._instancesDirty === true
1871
+ ? String(renderer?._instancesDirtyReason || 'unknown')
1872
+ : '',
1873
+ residentInstancesDirtySerial: Number(renderer?._instancesDirtySerial || 0),
1874
+ residentLastNodeCount: Number(renderer?._lastNodeCount || 0),
1875
+ residentEligibleTextLikeCount: Number(renderer?._cachedEligibleTextLikeCount || 0),
1876
+ residentBufferNodeCount: Number(renderer?.instanceData?.nodeIds?.length || 0),
1877
+ residentCssParkCount: Number(renderer?._residentCssParkCount || 0),
1878
+ residentCssRestoreCount: Number(renderer?._residentCssRestoreCount || 0),
1879
+ residentCssRestoreMissCount: Number(renderer?._residentCssRestoreMissCount || 0),
1880
+ residentCssLayoutWarmCount: Number(renderer?._residentCssLayoutWarmCount || 0),
1881
+ fullResCssFringePrewarmCount: Number(renderer?._fullResCssFringePrewarmCount || 0),
1882
+ fullResCssFringePrewarmCandidateCount: Number(renderer?._fullResCssFringePrewarmCandidateCount || 0),
1883
+ fullResCssFringeLayoutWarmCount: Number(renderer?._fullResCssFringeLayoutWarmCount || 0),
1884
+ residentStableLineReuseCount: Number(renderer?._residentStableLineReuseCount || 0),
1885
+ residentBoostClearCount: Number(renderer?._residentBoostClearCount || 0),
1886
+ animatedGifFallbackCandidateScanCount: Number(renderer?._animatedGifFallbackCandidateScanCount || 0),
1887
+ animatedGifFallbackCandidateCacheHitCount: Number(renderer?._animatedGifFallbackCandidateCacheHitCount || 0),
1888
+ activeCssMediaFallbackCountScanCount: Number(renderer?._activeCssMediaFallbackCountScanCount || 0),
1889
+ activeCssMediaFallbackCountCacheHitCount: Number(renderer?._activeCssMediaFallbackCountCacheHitCount || 0),
1890
+ lineTextureRows: Number(renderer?.lineTextureRows || 0),
1891
+ residentGpuWarmComplete: !!renderer &&
1892
+ renderer._hasPendingImageAtlasWork?.() !== true &&
1893
+ renderer._residentGpuWarmKey === getResidentGpuKey(renderer),
1894
+ residentGpuBufferWarmComplete: !!renderer && renderer._residentGpuWarmOffscreenComplete === true &&
1895
+ renderer._residentGpuWarmKey === getResidentGpuKey(renderer),
1896
+ residentAtlasWarmComplete: !!renderer && Number(renderer.imageAtlasSlots?.size || 0) > 0 &&
1897
+ renderer._hasPendingImageAtlasWork?.() !== true &&
1898
+ Number(renderer._residentImageAtlasWarmVersion ?? -1) === Number(renderer.imageAtlasTexture?.version || 0)
1899
+ };
1900
+ }
1901
+
1902
+ function resetDiagnostics(renderer) {
1903
+ if (!renderer) return;
1904
+ frameSampleStates.delete(renderer);
1905
+ renderer._fullResStablePlanSkipCount = 0;
1906
+ renderer._lastFullResStablePlanSkipped = false;
1907
+ renderer._fullResCssStableReuseCount = 0;
1908
+ cssMediaFrameDomReuseCount = 0;
1909
+ cssMediaFrameDomApplyCount = 0;
1910
+ }
1911
+
1912
+ window.MindMapRenderPlan = Object.freeze({
1913
+ configureImageAtlasTexture,
1914
+ getImageAtlasOutputColorChunk,
1915
+ getLocalSnapGridDistanceOpacity,
1916
+ shouldUseInteractiveRendererDpr,
1917
+ isRendererDprInteractionActive,
1918
+ getCameraOnlyWebglBlockerMask,
1919
+ getCameraOnlyWebglBlockerNames,
1920
+ syncCommittedResidentTextCount,
1921
+ clearFullResImageVisuals,
1922
+ buildFullResKey,
1923
+ shouldSkipStableFullRes,
1924
+ commitStableFullRes,
1925
+ recordStableFullRes,
1926
+ scheduleResidentLinePrewarm,
1927
+ resolveResidentLineData,
1928
+ getPreparedLineData,
1929
+ areResidentLinesPrepared,
1930
+ initialLineTextureRows,
1931
+ ensureLineTextureCapacity,
1932
+ renderResidentWarmScene,
1933
+ prepareImageAtlasCapacity,
1934
+ prepareImageAtlasForEntries,
1935
+ uploadImageAtlasTile,
1936
+ scheduleImageAtlasUpload,
1937
+ clearScheduledImageAtlasUpload,
1938
+ fallbackBatch,
1939
+ reuseCssMediaFrameDom,
1940
+ reuseStableVisibleCss,
1941
+ reuseActiveCssMediaFallback,
1942
+ hasAnimatedGifCssFallbackCandidates,
1943
+ invalidateAnimatedGifCssFallbackCandidateCache,
1944
+ getActiveCssMediaFallbackCountCached,
1945
+ invalidateActiveCssMediaFallbackCountCache,
1946
+ markLodImageCssFallbacksChanged,
1947
+ createTrackedLodImageCssFallbackSet,
1948
+ hasActionableResidentLineDetails,
1949
+ hasResidentDirtyWork,
1950
+ hasPendingNearCssWarmup,
1951
+ reusePreparedImageInstances,
1952
+ prepareIdleResidentImageInstances,
1953
+ stagePreparedResidentLineRow,
1954
+ commitPreparedResidentLineRows,
1955
+ prepareIdleResidentBuffers,
1956
+ beginResidentCssTransition,
1957
+ cachePreparedResidentCss,
1958
+ scheduleResidentCssLayoutWarm,
1959
+ parkFullResCss,
1960
+ parkReadyResidentImage,
1961
+ restoreParkedFullResCss,
1962
+ completeFullResTransition,
1963
+ ensureResidentLineDetails,
1964
+ beginFrame,
1965
+ recordFrame,
1966
+ getDiagnostics,
1967
+ resetDiagnostics
1968
+ });
1969
+
1970
+ window.MindCanvasBuildInfo?.registerPart?.('renderPlan', BUILD_ID);
1971
+ })();