@mindexec/cli 0.2.430 → 0.2.432

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,572 @@
1
+ (function () {
2
+ 'use strict';
3
+
4
+ const BUILD_ID = '20260712-stable-fullres-plan-v12';
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 frameSampleStates = new WeakMap();
10
+ const residentLinePrewarmStates = new WeakMap();
11
+ const VIEW_SYNC_SECTION_KEYS = [
12
+ 'fullResSetup', 'fullResImages', 'fullResCssQueue', 'fullResHandoff', 'fullResOther',
13
+ 'lodCleanup', 'lodNodeScan', 'lodResidentApply', 'lodImageInstances',
14
+ 'lodPositionPatch', 'lodFallbacks', 'lodOther'
15
+ ];
16
+
17
+ function isFullResMotionOptimizationActive(module) {
18
+ return (module?._viewSyncMotionActive === true ||
19
+ module?.isPanning === true ||
20
+ module?.isZooming === true ||
21
+ module?._fullResMotionFrozen === true) &&
22
+ module?.isDraggingNode !== true &&
23
+ module?.isDraggingMultipleNodes !== true &&
24
+ module?.isResizing !== true &&
25
+ module?.isWindowResizing !== true;
26
+ }
27
+
28
+ function buildFullResKey(
29
+ lodBand,
30
+ visibilityVersion,
31
+ selectionKey,
32
+ nodeCount,
33
+ visibleCount,
34
+ nearVisibleCount,
35
+ allowedCssCount,
36
+ css3dEnabled,
37
+ module,
38
+ renderer) {
39
+ return [
40
+ String(lodBand || ''),
41
+ Number(visibilityVersion || 0),
42
+ String(selectionKey || ''),
43
+ Number(nodeCount || 0),
44
+ Number(visibleCount || 0),
45
+ Number(nearVisibleCount || 0),
46
+ Number(allowedCssCount || 0),
47
+ css3dEnabled === false ? 'css3d:off' : 'css3d:on',
48
+ String(module?.draggedNodeId || ''),
49
+ String(module?._textOverlayV2State?.editing?.nodeId || ''),
50
+ String(module?._editingOverlayState?.nodeId || ''),
51
+ String(module?._textOverlayV2State?.selectionNodeId || ''),
52
+ String(renderer?._getCurrentHoveredNodeId?.(module) || ''),
53
+ isFullResMotionOptimizationActive(module) ? 'motion:on' : 'motion:off'
54
+ ].join('|');
55
+ }
56
+
57
+ function hasPendingFullResWork(renderer, module, bandChanged, cssReadinessDrift) {
58
+ return !renderer || !module ||
59
+ bandChanged === true ||
60
+ cssReadinessDrift === true ||
61
+ renderer._hasCss3dQueueItems?.() === true ||
62
+ Number(renderer._css3dQueuedMap?.size || 0) > 0 ||
63
+ renderer._css3dProcessing === true ||
64
+ Number(renderer._nearEntryBoostFrames || 0) > 0 ||
65
+ renderer._fullResHandoffActive === true ||
66
+ module._fullResMotionFrozen === true ||
67
+ module._cssParentRepairNeeded === true ||
68
+ module._css3dVisualChangedThisFrame === true ||
69
+ module._css3dVisualChangedSinceLastRender === true ||
70
+ Number(module._cssTransformDirtyIds?.size || 0) > 0;
71
+ }
72
+
73
+ function shouldSkipStableFullRes(renderer, module, key, bandChanged) {
74
+ const canSkip = !!key &&
75
+ renderer?._lastNearCssNoWorkKey === key &&
76
+ hasPendingFullResWork(renderer, module, bandChanged, false) !== true;
77
+
78
+ if (renderer) {
79
+ renderer._lastFullResStablePlanSkipped = canSkip;
80
+ if (canSkip) {
81
+ renderer._fullResStablePlanSkipCount = Number(renderer._fullResStablePlanSkipCount || 0) + 1;
82
+ }
83
+ }
84
+
85
+ return canSkip;
86
+ }
87
+
88
+ function commitStableFullRes(renderer, module, key, bandChanged, cssReadinessDrift) {
89
+ if (!key || renderer?._lastNearCssNoWorkKey !== key ||
90
+ hasPendingFullResWork(renderer, module, bandChanged, cssReadinessDrift)) {
91
+ if (renderer) renderer._lastFullResStablePlanSkipped = false;
92
+ return false;
93
+ }
94
+
95
+ renderer._lastNearCssNoWorkKey = key;
96
+ renderer._lastFullResStablePlanSkipped = false;
97
+ return true;
98
+ }
99
+
100
+ function getLineModelSource(model) {
101
+ return model?._visibleContent ?? model?.response ?? model?.Response ??
102
+ model?.content ?? model?.Content ?? model?.text ?? model?.Text ?? '';
103
+ }
104
+
105
+ function getPreparedLineData(renderer, entry, width, height) {
106
+ const prepared = entry?._lodResidentPreparedLine || null;
107
+ const model = entry?.model || null;
108
+ const nodeId = model?.id || model?.Id || '';
109
+ const element = entry?.cssObject?.element || null;
110
+ if (!prepared || !model || !nodeId ||
111
+ prepared.data !== renderer?.lineDataCache?.get?.(nodeId) ||
112
+ prepared.model !== model ||
113
+ prepared.width !== Number(width || 0) ||
114
+ prepared.height !== Number(height || 0) ||
115
+ prepared.source !== getLineModelSource(model) ||
116
+ prepared.prompt !== (model?.prompt ?? model?.Prompt ?? '') ||
117
+ prepared.elementClass !== String(element?.className || '') ||
118
+ prepared.rootClass !== String(globalThis.document?.documentElement?.className || '') ||
119
+ prepared.viewportWidth !== Number(globalThis.innerWidth || 0) ||
120
+ prepared.viewportHeight !== Number(globalThis.innerHeight || 0)) {
121
+ return null;
122
+ }
123
+ return prepared.data;
124
+ }
125
+
126
+ function rememberPreparedLine(renderer, entry, width, height, data) {
127
+ const model = entry?.model || null;
128
+ const element = entry?.cssObject?.element || null;
129
+ if (!model || !data) return data || null;
130
+ entry._lodResidentPreparedLine = {
131
+ data,
132
+ model,
133
+ width: Number(width || 0),
134
+ height: Number(height || 0),
135
+ source: getLineModelSource(model),
136
+ prompt: model?.prompt ?? model?.Prompt ?? '',
137
+ elementClass: String(element?.className || ''),
138
+ rootClass: String(globalThis.document?.documentElement?.className || ''),
139
+ viewportWidth: Number(globalThis.innerWidth || 0),
140
+ viewportHeight: Number(globalThis.innerHeight || 0)
141
+ };
142
+ return data;
143
+ }
144
+
145
+ function resolveResidentLineData(renderer, entry, width, height, allowExact, maxSamples, lineHeight, padding) {
146
+ const prepared = getPreparedLineData(renderer, entry, width, height);
147
+ if (prepared) return prepared;
148
+ const model = entry?.model || null;
149
+ if (!renderer || !model) return null;
150
+ if (allowExact === true) {
151
+ return rememberPreparedLine(renderer, entry, width, height,
152
+ renderer._getLineDataForNode?.(model, entry.lodSeed, width, height, entry));
153
+ }
154
+ renderer._residentLineFallbackUsed = true;
155
+ const safeLineHeight = Math.max(1, Number(lineHeight || 1));
156
+ const safePadding = Math.max(0, Number(padding || 0));
157
+ const maxLines = Math.max(1, Math.min(
158
+ Number(maxSamples || 1),
159
+ Math.floor(Math.max(safeLineHeight, Number(height || 0) - safePadding * 2) / safeLineHeight)
160
+ ));
161
+ const fallback = renderer._computeFallbackLineData?.(entry.lodSeed, maxLines) || { lineCount: 0, lineLengths: [] };
162
+ return {
163
+ lineCount: Number(fallback.lineCount || 0),
164
+ lineLengths: fallback.lineLengths || [],
165
+ lineHeightPx: safeLineHeight,
166
+ paddingX: safePadding,
167
+ paddingY: safePadding
168
+ };
169
+ }
170
+
171
+ function isPrewarmInteractionActive(module) {
172
+ return module?.isPanning === true || module?.isZooming === true ||
173
+ module?.isDraggingNode === true || module?.isDraggingMultipleNodes === true ||
174
+ module?.isResizing === true || module?.isWindowResizing === true;
175
+ }
176
+
177
+ function prepareImageAtlasCapacity(renderer, imageCount) {
178
+ if (!renderer?.imageAtlasCanvas || Number(renderer.imageAtlasSlots?.size || 0) > 0) return false;
179
+ let columns = 8;
180
+ const targetSlots = Math.max(1, Number(imageCount || 0) * 2);
181
+ while (columns < 32 && columns * columns < targetSlots) columns *= 2;
182
+ const size = columns * IMAGE_ATLAS_TILE_SIZE;
183
+ renderer.imageAtlasColumns = columns;
184
+ renderer.imageAtlasSize = size;
185
+ renderer.imageAtlasMaxSlots = columns * columns;
186
+ if (renderer.imageAtlasCanvas.width === size && renderer.imageAtlasCanvas.height === size) return false;
187
+ renderer.imageAtlasCanvas.width = size;
188
+ renderer.imageAtlasCanvas.height = size;
189
+ const context = renderer.imageAtlasCanvas.getContext?.('2d', { alpha: false }) || null;
190
+ if (context) {
191
+ context.fillStyle = '#eef2f7';
192
+ context.fillRect(0, 0, size, size);
193
+ }
194
+ if (renderer.imageAtlasTexture) renderer.imageAtlasTexture.needsUpdate = true;
195
+ renderer._residentGpuWarmKey = '';
196
+ return true;
197
+ }
198
+
199
+ function fallbackBatch(renderer, fallbackIds, limit = 12) {
200
+ const ids = Array.from(fallbackIds || []);
201
+ const safeLimit = Math.max(1, Number(limit || 1));
202
+ if (ids.length <= safeLimit) return ids;
203
+ const cursor = Math.max(0, Number(renderer?._residentFallbackCleanupCursor || 0)) % ids.length;
204
+ const batch = [];
205
+ for (let i = 0; i < safeLimit; i++) batch.push(ids[(cursor + i) % ids.length]);
206
+ if (renderer) renderer._residentFallbackCleanupCursor = (cursor + safeLimit) % ids.length;
207
+ return batch;
208
+ }
209
+
210
+ function reusePreparedImageInstances(renderer, state) {
211
+ if (renderer?.isInLODMode !== false || renderer?._imageInstancesDirtyReason !== 'image-slot-invalidated' ||
212
+ state?.imageCandidateIds?.size !== state?.imagePreparedIds?.size) return false;
213
+ const priorIds = Array.isArray(renderer.imageInstanceData?.nodeIds) ? renderer.imageInstanceData.nodeIds : [];
214
+ if (priorIds.length !== state.imagePreparedIds.size) return false;
215
+ for (let i = 0; i < priorIds.length; i++) {
216
+ const nodeId = priorIds[i];
217
+ if (!state.imagePreparedIds.has(nodeId) || renderer.imageAtlasSlots?.get?.(nodeId)?.ready !== true) return false;
218
+ }
219
+ renderer._clearImageInstancesDirty?.();
220
+ renderer._residentImageBufferReuseCount = Number(renderer._residentImageBufferReuseCount || 0) + 1;
221
+ return true;
222
+ }
223
+
224
+ function queueResidentLinePrewarm(state) {
225
+ if (!state || state.scheduled || state.complete) return;
226
+ state.scheduled = true;
227
+ const run = deadline => {
228
+ state.scheduled = false;
229
+ if (residentLinePrewarmStates.get(state.renderer) !== state || state.renderer?._disposed === true ||
230
+ state.renderer?._module !== state.module ||
231
+ state.module?.nodeObjectsById !== state.nodeObjectsById ||
232
+ state.module?.isLoading === true ||
233
+ state.key !== `${Number(state.renderer?._instancesDirtySerial || 0)}:${Number(state.nodeObjectsById.size || 0)}` ||
234
+ isPrewarmInteractionActive(state.module)) {
235
+ return;
236
+ }
237
+ if (!state.entries) state.entries = Array.from(state.nodeObjectsById.values());
238
+ const startedAt = performance.now();
239
+ let processed = 0;
240
+ while (state.cursor < state.entries.length && processed < 4) {
241
+ const entry = state.entries[state.cursor++];
242
+ const model = entry?.model || null;
243
+ const contentType = String(model?.contentType ?? model?.ContentType ?? '').toLowerCase();
244
+ if (model && !['image', 'video', 'youtube', 'pdf', 'audio', 'webpage', 'iframe'].includes(contentType)) {
245
+ const width = Number(model.width || 400);
246
+ const height = Number(model.height || 200);
247
+ if (entry.lodSeed === undefined) entry.lodSeed = Math.random() * 100;
248
+ if (!getPreparedLineData(state.renderer, entry, width, height)) {
249
+ rememberPreparedLine(state.renderer, entry, width, height,
250
+ state.renderer._getLineDataForNode?.(model, entry.lodSeed, width, height, entry));
251
+ }
252
+ state.prepared++;
253
+ } else if (model && contentType === 'image') {
254
+ const nodeId = String(model.id || model.Id || '');
255
+ if (nodeId) state.imageCandidateIds.add(nodeId);
256
+ const slot = state.imagePass > 0 ? state.renderer._ensureImageLodThumbnail?.(entry) || null : null;
257
+ if (slot?.ready === true) {
258
+ if (nodeId) state.imagePreparedIds.add(nodeId);
259
+ } else {
260
+ state.pendingImageEntries.push(entry);
261
+ }
262
+ }
263
+ processed++;
264
+ if (performance.now() - startedAt >= 3 && Number(deadline?.timeRemaining?.() || 0) < 1) break;
265
+ }
266
+ if (state.cursor >= state.entries.length) {
267
+ if (state.pendingImageEntries.length > 0 && state.imagePass < 20) {
268
+ const isFirstImagePass = state.imagePass === 0;
269
+ if (isFirstImagePass) prepareImageAtlasCapacity(state.renderer, state.imageCandidateIds.size);
270
+ state.entries = Array.from(new Set(state.pendingImageEntries));
271
+ state.pendingImageEntries.length = 0;
272
+ state.cursor = 0;
273
+ state.imagePass++;
274
+ if (isFirstImagePass) {
275
+ queueResidentLinePrewarm(state);
276
+ } else {
277
+ setTimeout(() => {
278
+ if (residentLinePrewarmStates.get(state.renderer) === state) queueResidentLinePrewarm(state);
279
+ }, 250);
280
+ }
281
+ return;
282
+ }
283
+ state.complete = true;
284
+ state.renderer._residentLinePrewarmCount = state.prepared;
285
+ state.renderer._residentImagePrewarmCount = state.imagePreparedIds.size;
286
+ state.renderer._residentImagePrewarmCandidateCount = state.imageCandidateIds.size;
287
+ state.renderer._residentImagePrewarmComplete = state.pendingImageEntries.length === 0;
288
+ if (state.renderer.isInLODMode === true && state.renderer._lineDetailsPatchPending === true) {
289
+ state.renderer._markLineDetailsDirty?.();
290
+ }
291
+ queueResidentGpuWarm(state);
292
+ return;
293
+ }
294
+ queueResidentLinePrewarm(state);
295
+ };
296
+ if (typeof globalThis.requestIdleCallback === 'function') {
297
+ globalThis.requestIdleCallback(run, { timeout: 120 });
298
+ } else {
299
+ setTimeout(() => run({ timeRemaining: () => 3, didTimeout: true }), 16);
300
+ }
301
+ }
302
+
303
+ function getResidentGpuKey(renderer) {
304
+ return `${Number(renderer?.lineDataTexture?.version || 0)}:${Number(renderer?.imageAtlasTexture?.version || 0)}:${Number(renderer?.lineTextureRows || 0)}`;
305
+ }
306
+
307
+ function retryResidentGpuWarm(state) {
308
+ if (!state || state.gpuRetryTimer) return;
309
+ state.gpuRetryTimer = setTimeout(() => {
310
+ state.gpuRetryTimer = null;
311
+ if (residentLinePrewarmStates.get(state.renderer) === state) queueResidentGpuWarm(state);
312
+ }, GPU_WARM_RETRY_DELAY_MS);
313
+ }
314
+
315
+ function queueResidentGpuWarm(state) {
316
+ if (!state?.complete || state.gpuScheduled) return;
317
+ const renderer = state.renderer;
318
+ if (residentLinePrewarmStates.get(renderer) !== state || renderer?._disposed === true ||
319
+ renderer?._module !== state.module || state.module?.nodeObjectsById !== state.nodeObjectsById ||
320
+ state.module?.isLoading === true ||
321
+ state.key !== `${Number(renderer?._instancesDirtySerial || 0)}:${Number(state.nodeObjectsById.size || 0)}`) return;
322
+ if (isPrewarmInteractionActive(state.module)) {
323
+ retryResidentGpuWarm(state);
324
+ return;
325
+ }
326
+ const webglRenderer = renderer?.renderer || null;
327
+ const gpuKey = getResidentGpuKey(renderer);
328
+ if (!webglRenderer || renderer._residentGpuWarmKey === gpuKey) return;
329
+ if (renderer._hasPendingImageAtlasWork?.() === true) {
330
+ retryResidentGpuWarm(state);
331
+ return;
332
+ }
333
+ state.gpuScheduled = true;
334
+ const run = () => {
335
+ state.gpuScheduled = false;
336
+ if (residentLinePrewarmStates.get(renderer) !== state || renderer?._disposed === true ||
337
+ renderer?._module !== state.module || state.module?.nodeObjectsById !== state.nodeObjectsById ||
338
+ state.module?.isLoading === true || state.key !== `${Number(renderer._instancesDirtySerial || 0)}:${Number(state.nodeObjectsById.size || 0)}`) return;
339
+ if (isPrewarmInteractionActive(state.module) || renderer._hasPendingImageAtlasWork?.() === true) {
340
+ retryResidentGpuWarm(state);
341
+ return;
342
+ }
343
+ try {
344
+ if (renderer.lineDataTexture) webglRenderer.initTexture?.(renderer.lineDataTexture);
345
+ if (renderer.imageAtlasTexture && Number(renderer.imageAtlasSlots?.size || 0) > 0) {
346
+ webglRenderer.initTexture?.(renderer.imageAtlasTexture);
347
+ renderer._residentImageAtlasWarmVersion = Number(renderer.imageAtlasTexture.version || 0);
348
+ }
349
+ const THREE = globalThis.THREE;
350
+ if (THREE?.Scene && typeof webglRenderer.compile === 'function' && state.module?.camera) {
351
+ const warmScene = new THREE.Scene();
352
+ [renderer.instancedMesh, renderer.instancedBorderLineMesh, renderer.instancedLineMesh,
353
+ renderer.instancedHaloMesh, renderer.instancedConsoleMesh, renderer.instancedImageMesh]
354
+ .filter(Boolean)
355
+ .forEach(mesh => {
356
+ const clone = mesh.clone?.();
357
+ if (!clone) return;
358
+ clone.visible = true;
359
+ clone.frustumCulled = false;
360
+ warmScene.add(clone);
361
+ });
362
+ webglRenderer.compile(warmScene, state.module.camera);
363
+ warmScene.clear?.();
364
+ }
365
+ renderer._residentGpuWarmKey = getResidentGpuKey(renderer);
366
+ renderer._residentGpuWarmComplete = true;
367
+ reusePreparedImageInstances(renderer, state);
368
+ state.gpuFailureCount = 0;
369
+ } catch (error) {
370
+ console.warn('[RenderPlan] Resident GPU warmup deferred.', error);
371
+ state.gpuFailureCount = Number(state.gpuFailureCount || 0) + 1;
372
+ if (state.gpuFailureCount <= 3) retryResidentGpuWarm(state);
373
+ }
374
+ };
375
+ if (typeof globalThis.requestIdleCallback === 'function') {
376
+ globalThis.requestIdleCallback(run, { timeout: 300 });
377
+ } else {
378
+ setTimeout(run, 32);
379
+ }
380
+ }
381
+
382
+ function scheduleResidentLinePrewarm(renderer, module, nodeObjectsById) {
383
+ if (!renderer || !module || !nodeObjectsById?.values || module.isLoading === true) return;
384
+ const key = `${Number(renderer._instancesDirtySerial || 0)}:${Number(nodeObjectsById.size || 0)}`;
385
+ let state = residentLinePrewarmStates.get(renderer);
386
+ if (!state || state.key !== key || state.nodeObjectsById !== nodeObjectsById) {
387
+ const entries = Array.from(nodeObjectsById.values());
388
+ const imageCandidateIds = new Set();
389
+ for (let i = 0; i < entries.length; i++) {
390
+ const model = entries[i]?.model || null;
391
+ if (String(model?.contentType ?? model?.ContentType ?? '').toLowerCase() !== 'image') continue;
392
+ const nodeId = String(model?.id || model?.Id || '');
393
+ if (nodeId) imageCandidateIds.add(nodeId);
394
+ }
395
+ prepareImageAtlasCapacity(renderer, imageCandidateIds.size);
396
+ state = {
397
+ renderer, module, nodeObjectsById, key, entries, cursor: 0, prepared: 0,
398
+ scheduled: false, complete: false, gpuScheduled: false, gpuRetryTimer: null, gpuFailureCount: 0,
399
+ imagePass: 0, imageCandidateIds, imagePreparedIds: new Set(), pendingImageEntries: []
400
+ };
401
+ residentLinePrewarmStates.set(renderer, state);
402
+ }
403
+ if (state.complete && renderer.isInLODMode === false &&
404
+ renderer._imageInstancesDirtyReason === 'image-slot-invalidated') {
405
+ const staleImageEntries = [];
406
+ for (const nodeId of state.imageCandidateIds) {
407
+ if (renderer.imageAtlasSlots?.get?.(nodeId)?.ready === true) continue;
408
+ const entry = nodeObjectsById.get?.(nodeId) || null;
409
+ if (entry) {
410
+ state.imagePreparedIds.delete(nodeId);
411
+ staleImageEntries.push(entry);
412
+ }
413
+ }
414
+ if (staleImageEntries.length > 0) {
415
+ state.entries = staleImageEntries;
416
+ state.cursor = 0;
417
+ state.complete = false;
418
+ state.imagePass = 1;
419
+ state.pendingImageEntries.length = 0;
420
+ }
421
+ }
422
+ queueResidentLinePrewarm(state);
423
+ if (state.complete) queueResidentGpuWarm(state);
424
+ }
425
+
426
+ function areResidentLinesPrepared(renderer, nodeObjectsById, nodeIds) {
427
+ if (!renderer || !nodeObjectsById?.get || !Array.isArray(nodeIds)) return false;
428
+ for (let i = 0; i < nodeIds.length; i++) {
429
+ const entry = nodeObjectsById.get(nodeIds[i]);
430
+ const model = entry?.model || null;
431
+ if (!model || !getPreparedLineData(renderer, entry, model.width || 400, model.height || 200)) return false;
432
+ }
433
+ return true;
434
+ }
435
+
436
+ function initialLineTextureRows(maxInstances) {
437
+ return Math.min(Math.max(1, Number(maxInstances || 1)), INITIAL_LINE_TEXTURE_ROWS);
438
+ }
439
+
440
+ function ensureLineTextureCapacity(renderer, requiredCount, width) {
441
+ const currentRows = Number(renderer?.lineTextureRows || 0);
442
+ const maxRows = Math.max(1, Number(renderer?.maxInstances || requiredCount || 1));
443
+ if (!renderer || Number(requiredCount || 0) <= currentRows || currentRows >= maxRows) return false;
444
+ let nextRows = Math.max(INITIAL_LINE_TEXTURE_ROWS, currentRows || 1);
445
+ while (nextRows < requiredCount && nextRows < maxRows) nextRows *= 2;
446
+ nextRows = Math.min(nextRows, maxRows);
447
+ const THREE = globalThis.THREE;
448
+ if (!THREE?.DataTexture) return false;
449
+ const rowWidth = Math.max(1, Number(width || 1));
450
+ const data = new Uint8Array(nextRows * rowWidth);
451
+ data.set(renderer.lineDataArray?.subarray?.(0, data.length) || []);
452
+ const previous = renderer.lineDataTexture || null;
453
+ const texture = new THREE.DataTexture(data, rowWidth, nextRows, THREE.RedFormat, THREE.UnsignedByteType);
454
+ texture.minFilter = previous?.minFilter ?? THREE.NearestFilter;
455
+ texture.magFilter = previous?.magFilter ?? THREE.NearestFilter;
456
+ texture.wrapS = previous?.wrapS ?? THREE.ClampToEdgeWrapping;
457
+ texture.wrapT = previous?.wrapT ?? THREE.ClampToEdgeWrapping;
458
+ texture.needsUpdate = true;
459
+ renderer.lineDataArray = data;
460
+ renderer.lineDataTexture = texture;
461
+ renderer.lineTextureRows = nextRows;
462
+ renderer._residentGpuWarmKey = '';
463
+ const uniforms = renderer.instancedLineMesh?.material?.uniforms || null;
464
+ if (uniforms?.uLineDataTex) uniforms.uLineDataTex.value = texture;
465
+ if (uniforms?.uLineDataSize?.value?.set) uniforms.uLineDataSize.value.set(rowWidth, nextRows);
466
+ previous?.dispose?.();
467
+ return true;
468
+ }
469
+
470
+ function getFrameSampleState(renderer) {
471
+ let state = frameSampleStates.get(renderer);
472
+ if (!state) {
473
+ state = { samples: new Array(FRAME_SAMPLE_LIMIT), cursor: 0, count: 0 };
474
+ frameSampleStates.set(renderer, state);
475
+ }
476
+ return state;
477
+ }
478
+
479
+ function recordFrame(renderer, profile) {
480
+ if (!renderer || !profile) return;
481
+ const state = getFrameSampleState(renderer);
482
+ const sections = profile.sections || {};
483
+ let viewSyncMs = 0;
484
+ for (let i = 0; i < VIEW_SYNC_SECTION_KEYS.length; i++) {
485
+ viewSyncMs += Number(sections[VIEW_SYNC_SECTION_KEYS[i]] || 0);
486
+ }
487
+ const sample = state.samples[state.cursor] || {};
488
+ sample.frameMs = Number(profile.durationMs || 0);
489
+ sample.visibilityMs = Number(sections.visibility || 0);
490
+ sample.viewSyncMs = viewSyncMs;
491
+ sample.css3dRenderMs = Number(sections.css3dRender || 0);
492
+ sample.stableFullResSkipped = renderer._lastFullResStablePlanSkipped === true;
493
+ state.samples[state.cursor] = sample;
494
+ state.cursor = (state.cursor + 1) % FRAME_SAMPLE_LIMIT;
495
+ state.count = Math.min(FRAME_SAMPLE_LIMIT, state.count + 1);
496
+ }
497
+
498
+ function beginFrame(renderer) {
499
+ if (renderer) renderer._lastFullResStablePlanSkipped = false;
500
+ }
501
+
502
+ function percentile(state, field, ratio) {
503
+ if (!state?.count) return 0;
504
+ const values = [];
505
+ for (let i = 0; i < state.count; i++) {
506
+ const value = Number(state.samples[i]?.[field] || 0);
507
+ if (Number.isFinite(value)) values.push(value);
508
+ }
509
+ if (values.length === 0) return 0;
510
+ values.sort((a, b) => a - b);
511
+ return Number(values[Math.max(0, Math.ceil(values.length * ratio) - 1)].toFixed(2));
512
+ }
513
+
514
+ function getDiagnostics(renderer) {
515
+ const state = renderer ? frameSampleStates.get(renderer) : null;
516
+ let stableFullResSampleCount = 0;
517
+ for (let i = 0; i < Number(state?.count || 0); i++) {
518
+ if (state.samples[i]?.stableFullResSkipped === true) stableFullResSampleCount++;
519
+ }
520
+ return {
521
+ build: BUILD_ID,
522
+ stableFullResSkipCount: Number(renderer?._fullResStablePlanSkipCount || 0),
523
+ skippedLastPlan: renderer?._lastFullResStablePlanSkipped === true,
524
+ sampleCount: Number(state?.count || 0),
525
+ stableFullResSampleCount,
526
+ frameP50Ms: percentile(state, 'frameMs', 0.50),
527
+ frameP95Ms: percentile(state, 'frameMs', 0.95),
528
+ visibilityP95Ms: percentile(state, 'visibilityMs', 0.95),
529
+ viewSyncP95Ms: percentile(state, 'viewSyncMs', 0.95),
530
+ css3dRenderP95Ms: percentile(state, 'css3dRenderMs', 0.95),
531
+ residentLinePrewarmCount: Number(renderer?._residentLinePrewarmCount || 0),
532
+ residentImagePrewarmCount: Number(renderer?._residentImagePrewarmCount || 0),
533
+ residentImagePrewarmCandidateCount: Number(renderer?._residentImagePrewarmCandidateCount || 0),
534
+ residentImageBufferReuseCount: Number(renderer?._residentImageBufferReuseCount || 0),
535
+ lineTextureRows: Number(renderer?.lineTextureRows || 0),
536
+ residentGpuWarmComplete: !!renderer &&
537
+ renderer._hasPendingImageAtlasWork?.() !== true &&
538
+ renderer._residentGpuWarmKey === getResidentGpuKey(renderer),
539
+ residentAtlasWarmComplete: !!renderer && Number(renderer.imageAtlasSlots?.size || 0) > 0 &&
540
+ renderer._hasPendingImageAtlasWork?.() !== true &&
541
+ Number(renderer._residentImageAtlasWarmVersion ?? -1) === Number(renderer.imageAtlasTexture?.version || 0)
542
+ };
543
+ }
544
+
545
+ function resetDiagnostics(renderer) {
546
+ if (!renderer) return;
547
+ frameSampleStates.delete(renderer);
548
+ renderer._fullResStablePlanSkipCount = 0;
549
+ renderer._lastFullResStablePlanSkipped = false;
550
+ }
551
+
552
+ window.MindMapRenderPlan = Object.freeze({
553
+ buildFullResKey,
554
+ shouldSkipStableFullRes,
555
+ commitStableFullRes,
556
+ scheduleResidentLinePrewarm,
557
+ resolveResidentLineData,
558
+ getPreparedLineData,
559
+ areResidentLinesPrepared,
560
+ initialLineTextureRows,
561
+ ensureLineTextureCapacity,
562
+ prepareImageAtlasCapacity,
563
+ fallbackBatch,
564
+ reusePreparedImageInstances,
565
+ beginFrame,
566
+ recordFrame,
567
+ getDiagnostics,
568
+ resetDiagnostics
569
+ });
570
+
571
+ window.MindCanvasBuildInfo?.registerPart?.('renderPlan', BUILD_ID);
572
+ })();
@@ -31,19 +31,76 @@
31
31
  }
32
32
 
33
33
  function CSS3DRenderer(){
34
- var _width, _height; var _widthHalf, _heightHalf; var cache = { camera:{ fov:0, style:'' }, objects: new WeakMap() };
35
- var domElement = document.createElement('div'); domElement.style.overflow = 'hidden'; this.domElement = domElement;
36
- var cameraElement = document.createElement('div'); cameraElement.style.webkitTransformStyle = cameraElement.style.transformStyle = 'preserve-3d'; cameraElement.style.pointerEvents = 'none'; domElement.appendChild(cameraElement);
37
-
34
+ var _width, _height, _widthHalf, _heightHalf;
35
+ var cache = { camera:{ fov:0, style:'' }, objects: new WeakMap() };
36
+ var domElement = document.createElement('div');
37
+ domElement.style.overflow = 'hidden';
38
+ this.domElement = domElement;
39
+ var cameraElement = document.createElement('div');
40
+ cameraElement.style.webkitTransformStyle = cameraElement.style.transformStyle = 'preserve-3d';
41
+ cameraElement.style.pointerEvents = 'none';
42
+ domElement.appendChild(cameraElement);
43
+
38
44
  this.getSize = function(){ return { width:_width, height:_height }; };
39
45
  this.getCameraElement = function(){ return cameraElement; };
40
- this.setSize = function(width, height){ _width=width; _height=height; _widthHalf=_width/2; _heightHalf=_height/2; domElement.style.width=width+'px'; domElement.style.height=height+'px'; cameraElement.style.width=width+'px'; cameraElement.style.height=height+'px'; };
46
+ this.setSize = function(width, height){
47
+ _width=width; _height=height; _widthHalf=_width/2; _heightHalf=_height/2;
48
+ domElement.style.width=width+'px'; domElement.style.height=height+'px';
49
+ cameraElement.style.width=width+'px'; cameraElement.style.height=height+'px';
50
+ };
51
+
41
52
  function getCameraCSSMatrix(matrix){ var e=matrix.elements; return 'matrix3d('+epsilon(e[0])+','+epsilon(-e[1])+','+epsilon(e[2])+','+epsilon(e[3])+','+epsilon(e[4])+','+epsilon(-e[5])+','+epsilon(e[6])+','+epsilon(e[7])+','+epsilon(e[8])+','+epsilon(-e[9])+','+epsilon(e[10])+','+epsilon(e[11])+','+epsilon(e[12])+','+epsilon(-e[13])+','+epsilon(e[14])+','+epsilon(e[15])+')'; }
42
- function getObjectCSSMatrix(matrix){ var e=matrix.elements; var m='matrix3d('+epsilon(e[0])+','+epsilon(e[1])+','+epsilon(e[2])+','+epsilon(e[3])+','+epsilon(-e[4])+','+epsilon(-e[5])+','+epsilon(-e[6])+','+epsilon(-e[7])+','+epsilon(e[8])+','+epsilon(e[9])+','+epsilon(e[10])+','+epsilon(e[11])+','+epsilon(e[12])+','+epsilon(e[13])+','+epsilon(e[14])+','+epsilon(e[15])+')'; return m; }
43
- function renderObject(object, scene, camera, cameraCSSMatrix){ if (object.isCSS3DObject){ var style=getObjectCSSMatrix(object.matrixWorld); var display=object.visible ? '' : 'none'; var element=object.element; var cached=cache.objects.get(object); var changed=false; if (cached===undefined || cached.style!==style){ element.style.webkitTransform=element.style.transform=style; changed=true; } if (cached===undefined || cached.display!==display){ element.style.display=display; changed=true; } if (changed){ cache.objects.set(object, { style, display }); } if (element.parentNode !== cameraElement){ cameraElement.appendChild(element); } } for (var i=0,l=object.children.length;i<l;i++){ renderObject(object.children[i], scene, camera, cameraCSSMatrix); } }
44
- function renderCameraOnly(renderer, camera){ var fov=camera.projectionMatrix.elements[5]*_heightHalf; if (cache.camera.fov!==fov){ renderer.domElement.style.webkitPerspective=renderer.domElement.style.perspective=fov+'px'; cache.camera.fov=fov; } if (camera.parent===null) camera.updateMatrixWorld(); var cameraCSSMatrix='translateZ('+fov+'px)'+getCameraCSSMatrix(camera.matrixWorldInverse); var style=cameraCSSMatrix+'translate('+_widthHalf+'px,'+_heightHalf+'px)'; if (cache.camera.style!==style){ cameraElement.style.webkitTransform=cameraElement.style.transform=style; cache.camera.style=style; } return cameraCSSMatrix; }
45
- this.renderCamera = function(camera){ renderCameraOnly(this, camera); };
46
- this.render = function(scene, camera){ if (scene.autoUpdate===true) scene.updateMatrixWorld(); var cameraCSSMatrix=renderCameraOnly(this, camera); renderObject(scene, scene, camera, cameraCSSMatrix); };
53
+ function getObjectCSSMatrix(matrix){ var e=matrix.elements; return 'matrix3d('+epsilon(e[0])+','+epsilon(e[1])+','+epsilon(e[2])+','+epsilon(e[3])+','+epsilon(-e[4])+','+epsilon(-e[5])+','+epsilon(-e[6])+','+epsilon(-e[7])+','+epsilon(e[8])+','+epsilon(e[9])+','+epsilon(e[10])+','+epsilon(e[11])+','+epsilon(e[12])+','+epsilon(e[13])+','+epsilon(e[14])+','+epsilon(e[15])+')'; }
54
+ function hasMatrixChanged(elements, values){
55
+ if (!values) return true;
56
+ for (var i=0;i<16;i++) if (epsilon(elements[i])!==values[i]) return true;
57
+ return false;
58
+ }
59
+ function copyMatrix(elements, values){
60
+ var next=values || new Float64Array(16);
61
+ for (var i=0;i<16;i++) next[i]=epsilon(elements[i]);
62
+ return next;
63
+ }
64
+ function renderObject(object){
65
+ if (object.isCSS3DObject){
66
+ var visible=object.visible===true;
67
+ var display=visible ? '' : 'none';
68
+ var element=object.element;
69
+ var cached=cache.objects.get(object);
70
+ if (cached===undefined){
71
+ cached={ element:null, matrix:null, display:null };
72
+ cache.objects.set(object,cached);
73
+ }
74
+ var elementChanged=cached.element!==element;
75
+ var becameVisible=visible && cached.display==='none';
76
+ if (visible && (elementChanged || becameVisible || hasMatrixChanged(object.matrixWorld.elements,cached.matrix))){
77
+ var style=getObjectCSSMatrix(object.matrixWorld);
78
+ element.style.webkitTransform=element.style.transform=style;
79
+ cached.matrix=copyMatrix(object.matrixWorld.elements,cached.matrix);
80
+ }
81
+ if (elementChanged || cached.display!==display) element.style.display=display;
82
+ cached.element=element;
83
+ cached.display=display;
84
+ if (element.parentNode!==cameraElement) cameraElement.appendChild(element);
85
+ }
86
+ for (var i=0,l=object.children.length;i<l;i++) renderObject(object.children[i]);
87
+ }
88
+ function renderCameraOnly(renderer, camera, matrixWorldIsCurrent){
89
+ var fov=camera.projectionMatrix.elements[5]*_heightHalf;
90
+ if (cache.camera.fov!==fov){
91
+ renderer.domElement.style.webkitPerspective=renderer.domElement.style.perspective=fov+'px';
92
+ cache.camera.fov=fov;
93
+ }
94
+ if (matrixWorldIsCurrent!==true && camera.parent===null) camera.updateMatrixWorld();
95
+ var cameraCSSMatrix='translateZ('+fov+'px)'+getCameraCSSMatrix(camera.matrixWorldInverse);
96
+ var style=cameraCSSMatrix+'translate('+_widthHalf+'px,'+_heightHalf+'px)';
97
+ if (cache.camera.style!==style){
98
+ cameraElement.style.webkitTransform=cameraElement.style.transform=style;
99
+ cache.camera.style=style;
100
+ }
101
+ }
102
+ this.renderCamera = function(camera, matrixWorldIsCurrent){ renderCameraOnly(this, camera, matrixWorldIsCurrent); };
103
+ this.render = function(scene, camera){ if (scene.autoUpdate===true) scene.updateMatrixWorld(); renderCameraOnly(this, camera, false); renderObject(scene); };
47
104
  }
48
105
 
49
106
  window.CSS3DObject = CSS3DObject; window.CSS3DSprite = CSS3DSprite; window.CSS3DRenderer = CSS3DRenderer;