@mindexec/cli 0.2.453 → 0.2.455

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 (33) hide show
  1. package/electron/main.cjs +12 -0
  2. package/electron/source-smoke.mjs +15 -0
  3. package/package.json +2 -2
  4. package/remote-fast/osx-arm64/mindexec-remote-fast.dll +0 -0
  5. package/remote-fast/osx-x64/mindexec-remote-fast.dll +0 -0
  6. package/remote-fast/win-x64/mindexec-remote-fast.dll +0 -0
  7. package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js +210 -244
  8. package/wwwroot/_content/MindExecution.Shared/js/mind-map-interactions.js +77 -103
  9. package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-renderer.js +5 -7
  10. package/wwwroot/_content/MindExecution.Shared/js/mind-map-logic-workers.js +9 -3
  11. package/wwwroot/_content/MindExecution.Shared/js/mind-map-render-plan.js +294 -12
  12. package/wwwroot/_framework/{MindExecution.Core.9h7x2mjn0w.dll → MindExecution.Core.3y861y22o4.dll} +0 -0
  13. package/wwwroot/_framework/{MindExecution.Kernel.8te3ay3qs6.dll → MindExecution.Kernel.182clfthnx.dll} +0 -0
  14. package/wwwroot/_framework/{MindExecution.Plugins.Admin.imt43kggvu.dll → MindExecution.Plugins.Admin.ghxhrm0vf5.dll} +0 -0
  15. package/wwwroot/_framework/{MindExecution.Plugins.Business.26yozgyvan.dll → MindExecution.Plugins.Business.doimlros51.dll} +0 -0
  16. package/wwwroot/_framework/{MindExecution.Plugins.Concept.k7fd1qvmfx.dll → MindExecution.Plugins.Concept.hp54u7s3y5.dll} +0 -0
  17. package/wwwroot/_framework/{MindExecution.Plugins.Directory.88ng22x3y0.dll → MindExecution.Plugins.Directory.wjfnb1nk3b.dll} +0 -0
  18. package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.ll20yqlc09.dll → MindExecution.Plugins.PlanMaster.447psj7gxo.dll} +0 -0
  19. package/wwwroot/_framework/{MindExecution.Plugins.YouTube.gqu5xngvav.dll → MindExecution.Plugins.YouTube.7f551zknhn.dll} +0 -0
  20. package/wwwroot/_framework/{MindExecution.Shared.6ivt1fatt3.dll → MindExecution.Shared.aftyr3f4lo.dll} +0 -0
  21. package/wwwroot/_framework/{MindExecution.Web.7tki7xqpt0.dll → MindExecution.Web.tkj3z0fg8f.dll} +0 -0
  22. package/wwwroot/_framework/blazor.boot.json +21 -21
  23. package/wwwroot/app-icon-1024.png +0 -0
  24. package/wwwroot/apple-touch-icon.png +0 -0
  25. package/wwwroot/favicon-32x32.png +0 -0
  26. package/wwwroot/favicon.ico +0 -0
  27. package/wwwroot/icon-192.png +0 -0
  28. package/wwwroot/icon-512.png +0 -0
  29. package/wwwroot/index.html +8 -4
  30. package/wwwroot/manifest.webmanifest +21 -19
  31. package/wwwroot/mindexec-favicon-v2.png +0 -0
  32. package/wwwroot/service-worker-assets.js +51 -31
  33. package/wwwroot/service-worker.js +1 -1
@@ -5,7 +5,7 @@
5
5
  const DEBUG = false;
6
6
  const FPS_DEBUG = false;
7
7
  const FRAME_PERF_DEBUG = false;
8
- const MINDMAP_CORE_BUILD_ID = '20260728-world-grid-spotlight-v860';
8
+ const MINDMAP_CORE_BUILD_ID = '20260728-camera-render-policy-v865';
9
9
  const CanvasPhase = Object.freeze({
10
10
  Booting: 'booting',
11
11
  BoardFileLoading: 'board-file-loading',
@@ -87,6 +87,7 @@
87
87
  const CURSOR_DOM_BLINK_DURATION_MS = 1000;
88
88
  const RENDER_DEBUG_METRICS_CACHE_MS = 250;
89
89
  const ANIMATION_IDLE_LOW_FPS_DELAY_MS = 500;
90
+ const WHEEL_ZOOM_BURST_QUIET_FRAME_LIMIT = 12;
90
91
  const HOME_CAMERA_NORMAL_MID_Z = 8250;
91
92
  const HOME_DENSE_CLUSTER_MIN_CELL_SIZE = 1200;
92
93
  const HOME_DENSE_CLUSTER_MAX_CELL_SIZE = 3600;
@@ -117,7 +118,6 @@
117
118
  const LOCAL_SNAP_GRID_COMPOSITOR_SCALE_MIN = 0.8;
118
119
  const LOCAL_SNAP_GRID_COMPOSITOR_SCALE_MAX = 1.5;
119
120
  const CAMERA_STATIONARY_INTERACTION_FRAME_DELAY_MS = 48;
120
- const CAMERA_ZOOM_END_DELAY_MS = 150;
121
121
  const CAMERA_MOTION_GLOBAL_STYLE_CLASS_ENABLED = false;
122
122
  const CAMERA_DENSE_GLOBAL_STYLE_CLASS_ENABLED = false;
123
123
  const PIPELINE_PROFILE_SECTION_KEYS = Object.freeze([
@@ -543,6 +543,15 @@
543
543
  );
544
544
  }
545
545
 
546
+ function hasActiveTextOverlaySurface(module) {
547
+ return !!(
548
+ hasPassiveOverlaySelectionSurface(module) === true ||
549
+ String(module?._textOverlayV2State?.editing?.nodeId || '').trim() ||
550
+ String(module?._editingOverlayState?.nodeId || '').trim() ||
551
+ module?.isEditingNote === true
552
+ );
553
+ }
554
+
546
555
  function hasPassiveOverlayMotionWork(module) {
547
556
  if (PASSIVE_DOM_OVERLAY_RUNTIME_ENABLED !== true) {
548
557
  return false;
@@ -1492,7 +1501,10 @@
1492
1501
  overlayLayoutChanged: moduleInstance._overlayDebugLayoutChanged === true,
1493
1502
  overlayContentChanged: moduleInstance._overlayDebugContentChanged === true,
1494
1503
  overlayForceRefresh: moduleInstance._overlayDebugForceRefresh === true,
1495
- cameraMotionFastPathStatus: moduleInstance._lastImmediateCameraFeedbackStatus || null,
1504
+ wheelCanonicalFrame: {
1505
+ consumeCount: Number(moduleInstance._wheelCanonicalConsumeCount || 0),
1506
+ lastInputToFrameLatencyMs: Number(moduleInstance._lastWheelInputToFrameLatencyMs || 0)
1507
+ },
1496
1508
  metricsSnapshotMs: Number(metricsSnapshotMs.toFixed(2)),
1497
1509
  metricsSnapshotCached: false,
1498
1510
  metricsSnapshotAgeMs: 0,
@@ -3083,6 +3095,8 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
3083
3095
  this._panSmoothingActive = false;
3084
3096
  this._resetPanLerpDeltaOnNextFrame = false;
3085
3097
  this._currentDpr = null;
3098
+ this._deferredDprTimer = null;
3099
+ this._lastInteractiveDprAt = 0;
3086
3100
  this._lastViewportWidth = 0;
3087
3101
  this._lastViewportHeight = 0;
3088
3102
  this._lastViewportDpr = 0;
@@ -3200,6 +3214,8 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
3200
3214
  this._nodeFrameDebugLayer = null;
3201
3215
  this._nodeFrameDebugSnapshot = null;
3202
3216
  this._wasZoomingLastFrame = false;
3217
+ this._wheelZoomBurstActive = false;
3218
+ this._wheelZoomBurstQuietFrames = 0;
3203
3219
  this._wasPanningLastFrame = false;
3204
3220
  this._wasCameraMovingLastFrame = false;
3205
3221
  this._wasResizingLastFrame = false;
@@ -3207,11 +3223,8 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
3207
3223
  this._ctrlWheelScrollInputTime = 0;
3208
3224
  this._ctrlWheelScrollLastDeltaY = 0;
3209
3225
  this._cameraNavigationOverlayInputTime = 0;
3210
- this._lastImmediateCameraFeedbackStatus = null;
3211
- this._immediateCameraFeedbackCount = 0;
3212
- this._immediateCameraFeedbackCss3dCount = 0;
3213
- this._immediateCameraFeedbackWebglCount = 0;
3214
- this._immediateCameraFeedbackEdgeCount = 0;
3226
+ this._wheelCanonicalConsumeCount = 0;
3227
+ this._lastWheelInputToFrameLatencyMs = 0;
3215
3228
  // Match background-themes.js 'XYGrid' size1.
3216
3229
  this.GRID_SIZE = 10;
3217
3230
  // ?�▲??[Changed] ?�▲??
@@ -4310,156 +4323,6 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
4310
4323
  }
4311
4324
  }
4312
4325
 
4313
- applyImmediateCameraNavigationFeedback(reason = 'camera-navigation-input', options = {}) {
4314
- const immediateOptions = options && typeof options === 'object' ? options : {};
4315
- const shouldRenderImmediateCss3d = immediateOptions.renderCss3d !== false;
4316
- const shouldRenderImmediateWebgl = immediateOptions.renderWebgl !== false;
4317
- const shouldSyncImmediateMotionGrid = immediateOptions.syncMotionGrid !== false;
4318
- const shouldSyncImmediateLocalSnapGrid = immediateOptions.syncLocalSnapGrid !== false;
4319
- const shouldSyncImmediateAutomationEdges = immediateOptions.syncAutomationEdges !== false;
4320
- const now = typeof performance !== 'undefined' && typeof performance.now === 'function'
4321
- ? performance.now()
4322
- : Date.now();
4323
- const status = {
4324
- used: false,
4325
- reason: String(reason || 'camera-navigation-input'),
4326
- css3dCamera: false,
4327
- automationEdges: false,
4328
- motionGrid: false,
4329
- localSnapGrid: false,
4330
- webgl: false,
4331
- skippedReason: '',
4332
- webglSkippedReason: '',
4333
- options: {
4334
- renderCss3d: shouldRenderImmediateCss3d,
4335
- renderWebgl: shouldRenderImmediateWebgl,
4336
- syncMotionGrid: shouldSyncImmediateMotionGrid,
4337
- syncLocalSnapGrid: shouldSyncImmediateLocalSnapGrid,
4338
- syncAutomationEdges: shouldSyncImmediateAutomationEdges
4339
- },
4340
- count: Number(this._immediateCameraFeedbackCount || 0),
4341
- updatedAt: now
4342
- };
4343
-
4344
- const finish = (skippedReason = '') => {
4345
- status.skippedReason = skippedReason;
4346
- this._lastImmediateCameraFeedbackStatus = status;
4347
- return status.used === true;
4348
- };
4349
-
4350
- if (!this.camera || this._animationLoopExecuting === true || this.isLoading === true) {
4351
- return finish('runtime-busy');
4352
- }
4353
-
4354
- const nextX = Number(this.targetX ?? this.camera.position.x);
4355
- const nextY = Number(this.targetY ?? this.camera.position.y);
4356
- const nextZ = Number(this.targetZ ?? this.camera.position.z);
4357
- if (!Number.isFinite(nextX) || !Number.isFinite(nextY) || !Number.isFinite(nextZ)) {
4358
- return finish('invalid-target');
4359
- }
4360
-
4361
- const currentX = Number(this.camera.position.x || 0);
4362
- const currentY = Number(this.camera.position.y || 0);
4363
- const currentZ = Number(this.camera.position.z || 0);
4364
- if (Math.abs(nextX - currentX) < 0.001 &&
4365
- Math.abs(nextY - currentY) < 0.001 &&
4366
- Math.abs(nextZ - currentZ) < 0.001) {
4367
- return finish('unchanged');
4368
- }
4369
-
4370
- this.camera.position.set(nextX, nextY, nextZ);
4371
- this.camera.updateMatrixWorld(true);
4372
- this._viewStatePersistAfterMotion = true;
4373
- this._cameraMovingThisFrame = true;
4374
- this._immediateCameraFeedbackCount = Number(this._immediateCameraFeedbackCount || 0) + 1;
4375
- status.used = true;
4376
- status.count = this._immediateCameraFeedbackCount;
4377
-
4378
- const flags = this.renderDebugFlags || getRenderDebugFlagsSnapshot();
4379
- const isCss3dEnabled = flags.enableCss3d !== false;
4380
- const hasFocusedTextOverlay = !!(
4381
- String(this._textOverlayV2State?.selectionNodeId || '').trim() ||
4382
- String(this._selectableTextOverlayNodeId || '').trim()
4383
- );
4384
- const hasEditingOverlay = !!(
4385
- String(this._textOverlayV2State?.editing?.nodeId || '').trim() ||
4386
- String(this._editingOverlayState?.nodeId || '').trim() ||
4387
- this.isEditingNote === true
4388
- );
4389
- const isNodeInteracting = !!(
4390
- this.isDraggingNode ||
4391
- this.isDraggingMultipleNodes ||
4392
- this.isResizing ||
4393
- this.isScrollbarDragging ||
4394
- this.isSelecting
4395
- );
4396
- const hasCss3dDirtyTransforms = !!(
4397
- this._cssParentRepairNeeded === true ||
4398
- this._css3dVisualChangedThisFrame === true ||
4399
- this._css3dVisualChangedSinceLastRender === true ||
4400
- (this._cssTransformDirtyIds?.size || 0) > 0
4401
- );
4402
- const canRenderCss3dCamera = !!(
4403
- shouldRenderImmediateCss3d === true &&
4404
- this.cssRenderer &&
4405
- typeof this.cssRenderer.renderCamera === 'function' &&
4406
- isCss3dEnabled === true &&
4407
- this.lodRenderer?.isInLODMode !== true &&
4408
- !isNodeInteracting &&
4409
- !hasFocusedTextOverlay &&
4410
- !hasEditingOverlay &&
4411
- !hasCss3dDirtyTransforms &&
4412
- this.isWindowResizing !== true
4413
- );
4414
-
4415
- if (canRenderCss3dCamera === true) {
4416
- this.cssRenderer.renderCamera(this.camera, true);
4417
- this._immediateCameraFeedbackCss3dCount = Number(this._immediateCameraFeedbackCss3dCount || 0) + 1;
4418
- status.css3dCamera = true;
4419
- status.css3dCount = this._immediateCameraFeedbackCss3dCount;
4420
- }
4421
-
4422
- const canRenderWebglCamera = !!(
4423
- shouldRenderImmediateWebgl === true &&
4424
- this.renderer &&
4425
- this.scene &&
4426
- flags.enableWebglRender !== false &&
4427
- this.isLoading !== true &&
4428
- (this.lodRenderer?.isInLODMode === true || status.css3dCamera !== true)
4429
- );
4430
- if (canRenderWebglCamera === true) {
4431
- try {
4432
- this.renderer.render(this.scene, this.camera);
4433
- status.webgl = true;
4434
- this._immediateCameraFeedbackWebglCount = Number(this._immediateCameraFeedbackWebglCount || 0) + 1;
4435
- status.webglCount = this._immediateCameraFeedbackWebglCount;
4436
- } catch (err) {
4437
- status.webglError = err?.message || String(err || 'unknown');
4438
- }
4439
- } else if (shouldRenderImmediateWebgl !== true) {
4440
- status.webglSkippedReason = 'feedback-option';
4441
- }
4442
-
4443
- if (shouldSyncImmediateMotionGrid === true &&
4444
- this._shouldTouchMotionGridLayerForCameraNavigation?.() === true) {
4445
- status.motionGrid = this._syncMotionGridLayerForCameraNavigation?.() === true;
4446
- }
4447
-
4448
- if (shouldSyncImmediateLocalSnapGrid === true) {
4449
- status.localSnapGrid = syncLocalSnapGridForCameraNavigation(this, true) === true;
4450
- }
4451
-
4452
- if (shouldSyncImmediateAutomationEdges === true &&
4453
- syncBusinessAutomationEdgesForCameraNavigation(this, true, false) === true) {
4454
- this._immediateCameraFeedbackEdgeCount = Number(this._immediateCameraFeedbackEdgeCount || 0) + 1;
4455
- status.automationEdges = true;
4456
- status.edgeCount = this._immediateCameraFeedbackEdgeCount;
4457
- }
4458
-
4459
- this._lastImmediateCameraFeedbackStatus = status;
4460
- return true;
4461
- }
4462
-
4463
4326
  getCurrentBoardId() {
4464
4327
  return window.mindMap?.activeBoardId || _currentBoardId || null;
4465
4328
  }
@@ -5067,20 +4930,40 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
5067
4930
  return Math.min(devicePixelRatio, interactive ? 1.25 : 2.0);
5068
4931
  }
5069
4932
 
5070
- _scheduleDeferredRendererPixelRatioApply(delayMs = 260) {
4933
+ _scheduleDeferredRendererPixelRatioApply(delayMs = 260, waitMs = delayMs) {
5071
4934
  if (this._deferredDprTimer) {
5072
- clearTimeout(this._deferredDprTimer);
4935
+ return;
5073
4936
  }
5074
4937
 
5075
4938
  this._deferredDprTimer = setTimeout(() => {
5076
4939
  this._deferredDprTimer = null;
5077
- if (this.isZooming || this.isPanning || this._panSmoothingActive || this.isDraggingNode || this.isDraggingMultipleNodes || this.isResizing || this.isWindowResizing) {
5078
- this._scheduleDeferredRendererPixelRatioApply(delayMs);
4940
+ const now = performance.now();
4941
+ const isInteractionActive =
4942
+ window.MindMapRenderPlan?.isRendererDprInteractionActive?.(this) === true;
4943
+ if (isInteractionActive) {
4944
+ this._lastInteractiveDprAt = now;
4945
+ }
4946
+ const elapsedSinceInteraction = Math.max(
4947
+ 0,
4948
+ now - Number(this._lastInteractiveDprAt || now)
4949
+ );
4950
+ if (isInteractionActive || elapsedSinceInteraction < delayMs) {
4951
+ this._scheduleDeferredRendererPixelRatioApply(
4952
+ delayMs,
4953
+ Math.max(16, delayMs - elapsedSinceInteraction)
4954
+ );
5079
4955
  return;
5080
4956
  }
5081
4957
 
4958
+ this._lastInteractiveDprAt = 0;
4959
+ const previousDpr = this._currentDpr;
5082
4960
  this._applyRendererPixelRatio(false);
5083
- }, delayMs);
4961
+ if (this._currentDpr !== previousDpr) {
4962
+ // setSize() changes the drawing buffer. Own one canonical
4963
+ // post-restore render even when the animation loop was parked.
4964
+ this._forceUpdateFrames = Math.max(this._forceUpdateFrames || 0, 1);
4965
+ }
4966
+ }, waitMs);
5084
4967
  }
5085
4968
 
5086
4969
  _applyRendererPixelRatio(interactive = false) {
@@ -5090,13 +4973,20 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
5090
4973
 
5091
4974
  const desiredDpr = this._getDesiredPixelRatio(interactive);
5092
4975
  if (interactive) {
5093
- // Drop DPR immediately while panning/zooming; restore it only after motion settles.
4976
+ // Keep one low-DPR drawing buffer for the whole navigation burst.
4977
+ // The single timer uses the last active frame timestamp, so it
4978
+ // neither churns timers nor restores between physical-wheel gaps.
4979
+ this._lastInteractiveDprAt = performance.now();
5094
4980
  if (!this._deferredDprTimer) {
5095
4981
  this._scheduleDeferredRendererPixelRatioApply();
5096
4982
  }
5097
4983
  if (this._currentDpr !== null && this._currentDpr <= desiredDpr + 0.001) {
5098
4984
  return;
5099
4985
  }
4986
+ } else if (this._deferredDprTimer &&
4987
+ this._currentDpr !== null &&
4988
+ this._currentDpr <= this._getDesiredPixelRatio(true) + 0.001) {
4989
+ return;
5100
4990
  }
5101
4991
 
5102
4992
  if (this._currentDpr === desiredDpr) {
@@ -5966,7 +5856,7 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
5966
5856
  }
5967
5857
 
5968
5858
  this._animationLoopRunning = true;
5969
- const loop = async () => {
5859
+ const loop = () => {
5970
5860
  if (this._animationLoopRunning !== true) {
5971
5861
  return;
5972
5862
  }
@@ -6045,14 +5935,31 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
6045
5935
  }
6046
5936
  : () => { };
6047
5937
 
6048
- const lastImmediateCameraFeedbackAtFrameStart = this._lastImmediateCameraFeedbackStatus || null;
6049
- const lastImmediateCameraFeedbackAgeAtFrameStart =
6050
- frameStart - Number(lastImmediateCameraFeedbackAtFrameStart?.updatedAt || 0);
6051
- const hasFreshImmediateCameraFeedbackAtFrameStart = !!(
6052
- lastImmediateCameraFeedbackAtFrameStart?.used === true &&
6053
- lastImmediateCameraFeedbackAgeAtFrameStart >= 0 &&
6054
- lastImmediateCameraFeedbackAgeAtFrameStart <= 120
6055
- );
5938
+ const consumedWheelZoomThisFrame =
5939
+ window.MindMapInteractions?.consumePendingWheelZoom?.(this, frameStart) === true;
5940
+ const wheelZoomBurstStartedThisFrame =
5941
+ consumedWheelZoomThisFrame === true &&
5942
+ this._wheelZoomBurstActive !== true;
5943
+ let wheelZoomBurstSettledThisFrame = false;
5944
+ if (consumedWheelZoomThisFrame === true) {
5945
+ this._wheelZoomBurstActive = true;
5946
+ this._wheelZoomBurstQuietFrames = 0;
5947
+ } else if (this._wheelZoomBurstActive === true) {
5948
+ this._wheelZoomBurstQuietFrames =
5949
+ Math.max(0, Number(this._wheelZoomBurstQuietFrames || 0)) + 1;
5950
+ const shouldSettleWheelZoomBurst =
5951
+ isIdleCadenceFrame === true ||
5952
+ (
5953
+ this.useAnimation60Fps === true &&
5954
+ this._wheelZoomBurstQuietFrames >= WHEEL_ZOOM_BURST_QUIET_FRAME_LIMIT
5955
+ );
5956
+ if (shouldSettleWheelZoomBurst === true) {
5957
+ this._wheelZoomBurstActive = false;
5958
+ this._wheelZoomBurstQuietFrames = 0;
5959
+ wheelZoomBurstSettledThisFrame = true;
5960
+ }
5961
+ }
5962
+ _profileSection('wheelInput');
6056
5963
 
6057
5964
  // 1. Camera Movement Interpolation
6058
5965
  // ----------------------------------------------------------------
@@ -6105,7 +6012,6 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
6105
6012
  const deltaMove = this.camera.position.distanceToSquared(this._tmpOldCamPos);
6106
6013
  const didCameraPositionChange = deltaMove > 0.0001;
6107
6014
  const isCameraMoving = didCameraPositionChange ||
6108
- hasFreshImmediateCameraFeedbackAtFrameStart ||
6109
6015
  (isPanSmoothingActive && remainingPanDistance > panSnapWorldThreshold);
6110
6016
  if (isCameraMoving) {
6111
6017
  this._viewStatePersistAfterMotion = true;
@@ -6128,16 +6034,14 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
6128
6034
  if (typeof this.prevIsCameraMoving === 'undefined') this.prevIsCameraMoving = false;
6129
6035
  const wasZoomingLastFrame = this._wasZoomingLastFrame === true;
6130
6036
 
6131
- // ?�▼??[Fix] �?종료 쿨다??- ???�력 ???�정 ?�간 ?��??�▼??
6132
- // _zoomInputTime?� interactions.js?�서 ???�력 ???�정??
6133
- const zoomNow = frameStart;
6134
- const lastZoomInput = this._zoomInputTime || 0;
6135
- const timeSinceLastInput = zoomNow - lastZoomInput;
6136
-
6137
- if (this.isZooming && !isCameraMoving && timeSinceLastInput > CAMERA_ZOOM_END_DELAY_MS) {
6037
+ // Keep the input frame in zoom mode, then end on the first
6038
+ // canonical frame that consumes no additional wheel input.
6039
+ if (this.isZooming &&
6040
+ !isCameraMoving &&
6041
+ consumedWheelZoomThisFrame !== true) {
6138
6042
  this.isZooming = false;
6139
6043
  if (FRAME_PERF_DEBUG) {
6140
- console.log(`[Perf] Zoom ended (${timeSinceLastInput.toFixed(0)}ms since last input)`);
6044
+ console.log('[Perf] Zoom ended on the first no-input canonical frame');
6141
6045
  }
6142
6046
  const moduleRef = this;
6143
6047
  const scheduleWillChangeOff = (typeof requestIdleCallback === 'function')
@@ -6201,11 +6105,18 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
6201
6105
  const panEndedThisFrame = wasPanningLastFrame && !this.isPanning;
6202
6106
  const cameraEndedThisFrame = wasCameraMovingLastFrame && !isCameraMoving;
6203
6107
  const resizeEndedThisFrame = wasResizingLastFrame && !this.isResizing;
6108
+ const shouldDeferHeavyFullResZoomFinalize = !!(
6109
+ zoomEndedThisFrame === true &&
6110
+ this._wheelZoomBurstActive === true &&
6111
+ wheelZoomBurstSettledThisFrame !== true &&
6112
+ this.lodRenderer?.isInLODMode !== true
6113
+ );
6204
6114
  this._wasZoomingLastFrame = this.isZooming === true;
6205
6115
  this._wasPanningLastFrame = this.isPanning === true;
6206
6116
  this._wasCameraMovingLastFrame = isCameraMoving === true;
6207
6117
  this._wasResizingLastFrame = this.isResizing === true;
6208
6118
  const shouldFinalizeMotionThisFrame =
6119
+ wheelZoomBurstSettledThisFrame ||
6209
6120
  zoomEndedThisFrame ||
6210
6121
  cameraEndedThisFrame ||
6211
6122
  resizeEndedThisFrame ||
@@ -6213,21 +6124,18 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
6213
6124
  if (shouldFinalizeMotionThisFrame) {
6214
6125
  this._lastMotionEndAt = frameStart;
6215
6126
  if (zoomEndedThisFrame === true) {
6216
- const shouldReconcileLocalSnapGridAfterZoom = !!(
6217
- this._isLocalSnapGridThemeEnabled?.() === true &&
6218
- (
6219
- this._localSnapGridStyleDeferredForZoom === true ||
6220
- this._localSnapGridPointerWakeDeferredForZoom === true
6221
- )
6222
- );
6127
+ // The compositor transform already keeps the grid in the
6128
+ // canonical world coordinate system. Preserve that exact
6129
+ // pose here and let the existing idle cadence refresh the
6130
+ // crisp raster once, so physical-wheel notches cannot
6131
+ // trigger canvas.toDataURL() on every no-input frame.
6223
6132
  this._localSnapGridPointerWakeDeferredForZoom = false;
6224
- if (shouldReconcileLocalSnapGridAfterZoom === true) {
6225
- this._syncLocalSnapGridLayer(true);
6226
- }
6227
6133
  }
6228
6134
  if (cameraEndedThisFrame) {
6229
6135
  this._cameraNavigationOverlayInputTime = 0;
6230
- this._overlayDirty = true;
6136
+ if (hasActiveTextOverlaySurface(this) === true) {
6137
+ this._overlayDirty = true;
6138
+ }
6231
6139
  }
6232
6140
 
6233
6141
  if (this.lodRenderer?.hasPendingLineDetailRestore?.(this.camera, this) === true) {
@@ -6243,12 +6151,25 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
6243
6151
  window.MindMapTextOverlayV2?.invalidateView?.(this);
6244
6152
  }
6245
6153
 
6246
- if (wasLodMotionFrozenLastFrame ||
6154
+ const hasHeavyMotionReconcilePending = !!(
6155
+ wasLodMotionFrozenLastFrame ||
6247
6156
  wasViewStateMotionFrozenLastFrame ||
6248
6157
  this._fullResVisibilityReconcilePending === true ||
6249
6158
  activeRenderDebugFlags.freezeVisibilityDuringMotion === true ||
6250
- activeRenderDebugFlags.freezeLodDuringMotion === true) {
6251
- this._forceUpdateFrames = Math.max(this._forceUpdateFrames || 0, 2);
6159
+ activeRenderDebugFlags.freezeLodDuringMotion === true
6160
+ );
6161
+ if (hasHeavyMotionReconcilePending === true &&
6162
+ shouldDeferHeavyFullResZoomFinalize !== true) {
6163
+ const heavyMotionReconcileForceFrames =
6164
+ wheelZoomBurstSettledThisFrame === true &&
6165
+ this._fullResVisibilityReconcilePending === true &&
6166
+ this.lodRenderer?.isInLODMode !== true
6167
+ ? 1
6168
+ : 2;
6169
+ this._forceUpdateFrames = Math.max(
6170
+ this._forceUpdateFrames || 0,
6171
+ heavyMotionReconcileForceFrames
6172
+ );
6252
6173
  this._overlayDirty = true;
6253
6174
  window.MindMapTextOverlayV2?.invalidateView?.(this);
6254
6175
  }
@@ -6303,16 +6224,10 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
6303
6224
  const isNodeInteracting = this.isDraggingNode || this.isDraggingMultipleNodes || this.isResizing;
6304
6225
  const isBoardLoading = this.isLoading === true;
6305
6226
  const forceUpdateFrames = Math.max(0, Number(this._forceUpdateFrames || 0));
6306
- const panLiveRefreshForceFrames = Math.max(0, Number(this._panLiveRefreshForceFrames || 0));
6307
6227
  const hasForcedUpdate = forceUpdateFrames > 0;
6308
- // Camera navigation wake frames keep the render loop awake; they should not disable motion throttles.
6309
- const hasOnlyCameraNavigationForcedUpdate =
6310
- hasForcedUpdate &&
6311
- panLiveRefreshForceFrames >= forceUpdateFrames &&
6312
- (this.isPanning === true || this.isZooming === true || isCameraMoving === true);
6313
- const hasNonCameraForcedUpdate =
6314
- hasForcedUpdate &&
6315
- hasOnlyCameraNavigationForcedUpdate !== true;
6228
+ // Camera navigation wakes the loop directly. Any remaining forced
6229
+ // frame is semantic work and must stay visible to the planner.
6230
+ const hasNonCameraForcedUpdate = hasForcedUpdate;
6316
6231
  const hasNonCameraNavigationForcedUpdate = hasNonCameraForcedUpdate;
6317
6232
  const isLodModeActive = this.lodRenderer?.isInLODMode === true;
6318
6233
  const residentDirty = isResidentMidFarLodFrame &&
@@ -6383,9 +6298,6 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
6383
6298
  idleUpdateDue);
6384
6299
  if (hasForcedUpdate) {
6385
6300
  this._forceUpdateFrames = Math.max(0, forceUpdateFrames - 1);
6386
- if (panLiveRefreshForceFrames > 0) {
6387
- this._panLiveRefreshForceFrames = Math.max(0, panLiveRefreshForceFrames - 1);
6388
- }
6389
6301
  }
6390
6302
  if (isLodPanVisibilityRefreshDue) {
6391
6303
  this._lastLodPanVisibilityRefreshAt = frameStart;
@@ -6553,8 +6465,7 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
6553
6465
  this.isZooming !== true;
6554
6466
  const fullResZoomStartedThisFrame =
6555
6467
  isFullResMode === true &&
6556
- this.isZooming === true &&
6557
- wasZoomingLastFrame !== true;
6468
+ wheelZoomBurstStartedThisFrame === true;
6558
6469
  const shouldThrottleFullResVisibilityCullingDuringPan =
6559
6470
  isFullResMode === true &&
6560
6471
  isVisibilityCullingEnabled &&
@@ -6686,8 +6597,13 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
6686
6597
  this._preserveVisibleSetThisFrame = true;
6687
6598
  }
6688
6599
  // ?�▲??[Perf] ?�▲?? _profileSection('pipelineVisibilityPlan');
6600
+ const isCameraNavigationActive =
6601
+ window.MindMapRenderPlan?.isRendererDprInteractionActive?.(this, {
6602
+ isCameraMoving
6603
+ }) === true;
6689
6604
  const shouldUseInteractiveDpr =
6690
6605
  isNodeInteracting === true ||
6606
+ isCameraNavigationActive ||
6691
6607
  this.isWindowResizing === true;
6692
6608
  this._applyRendererPixelRatio(shouldUseInteractiveDpr);
6693
6609
  _profileSection('pipelinePixelRatio');
@@ -7095,12 +7011,48 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
7095
7011
  // 7. Render
7096
7012
  // ----------------------------------------------------------------
7097
7013
  _profileSection('css3dSync');
7014
+ const canUseCss3dCameraFastPath = !!(
7015
+ this.cssRenderer &&
7016
+ typeof this.cssRenderer.renderCamera === 'function' &&
7017
+ isCss3dEnabled &&
7018
+ (!isInLodMode || shouldRenderCss3dInLod) &&
7019
+ shouldUpdateCss3d &&
7020
+ (this.isPanning === true || this.isZooming === true || isCameraMoving === true) &&
7021
+ isCameraMoving === true &&
7022
+ !isNodeInteracting &&
7023
+ !hasNonCameraNavigationForcedUpdate &&
7024
+ !hasPendingNearCssWarmup &&
7025
+ !hasMotionBlockingOverlayFocus &&
7026
+ !hasPendingCss3dParentRepair &&
7027
+ this._css3dVisualChangedThisFrame !== true &&
7028
+ this._css3dVisualChangedSinceLastRender !== true &&
7029
+ shouldSyncCss3dTransforms !== true &&
7030
+ lodVisualEpochChangedThisFrame !== true &&
7031
+ this.isWindowResizing !== true
7032
+ );
7098
7033
  const shouldUseAnimationCadenceForWebglFrame =
7099
7034
  isCameraNavigationOnlyInteractiveFrame === true
7100
7035
  ? false
7101
7036
  : shouldUseAnimation60Fps === true;
7037
+ const cameraOnlyWebglBlockerMask =
7038
+ window.MindMapRenderPlan?.getCameraOnlyWebglBlockerMask?.(this, {
7039
+ canUseCss3dCameraFastPath,
7040
+ isCameraNavigationOnlyInteractiveFrame,
7041
+ isWebglRenderEnabled,
7042
+ isBoardLoading,
7043
+ isInLodMode,
7044
+ hasNonCameraNavigationForcedUpdate,
7045
+ themeAnimatedThisFrame
7046
+ }) ?? 1;
7047
+ const canSkipWebglForCameraOnly = cameraOnlyWebglBlockerMask === 0;
7048
+ const cameraOnlyWebglSkipBlockers = shouldCaptureFramePerf
7049
+ ? window.MindMapRenderPlan?.getCameraOnlyWebglBlockerNames?.(
7050
+ cameraOnlyWebglBlockerMask
7051
+ ) || []
7052
+ : null;
7102
7053
  const shouldRenderWebglFrame =
7103
7054
  isWebglRenderEnabled &&
7055
+ canSkipWebglForCameraOnly !== true &&
7104
7056
  (
7105
7057
  isBoardLoading === true ||
7106
7058
  shouldUpdate === true ||
@@ -7108,8 +7060,10 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
7108
7060
  shouldUseAnimationCadenceForWebglFrame === true ||
7109
7061
  themeAnimatedThisFrame === true
7110
7062
  );
7111
- const webglRenderReason = shouldCaptureFramePerf && shouldRenderWebglFrame
7063
+ const webglRenderReason = shouldCaptureFramePerf
7112
7064
  ? (
7065
+ canSkipWebglForCameraOnly === true ? 'camera-only-css3d-skip' :
7066
+ shouldRenderWebglFrame !== true ? '' :
7113
7067
  isBoardLoading === true ? 'board-loading' :
7114
7068
  shouldUpdate === true ? 'update' :
7115
7069
  isInteractiveFrame === true ? 'interactive-frame' :
@@ -7150,7 +7104,10 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
7150
7104
  triangles: 0,
7151
7105
  points: 0,
7152
7106
  lines: 0,
7153
- skipped: true
7107
+ skipped: true,
7108
+ skipReason: canSkipWebglForCameraOnly === true
7109
+ ? 'camera-only-css3d-skip'
7110
+ : 'no-render-work'
7154
7111
  };
7155
7112
  } else if (isBoardLoading) {
7156
7113
  this._lastWebglRenderInfo = { calls: 0, triangles: 0, points: 0, lines: 0 };
@@ -7164,12 +7121,17 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
7164
7121
  const localSnapGridPointerRevision = Math.max(0, Number(this._localSnapGridPointerRevision || 0));
7165
7122
  const hasPendingLocalSnapGridPointerMove =
7166
7123
  Number(this._lastLocalSnapGridPositionRevision ?? -1) !== localSnapGridPointerRevision;
7124
+ const shouldDeferLocalSnapGridRasterUntilBurstSettle = !!(
7125
+ this._localSnapGridStyleDeferredForZoom === true &&
7126
+ wheelZoomBurstSettledThisFrame !== true
7127
+ );
7167
7128
  const shouldUseLocalSnapGridPositionOnly = !!(
7168
7129
  this._localSnapGridLayer?.isConnected &&
7169
7130
  this._lastLocalSnapGridKey &&
7170
7131
  (
7171
7132
  isCameraNavigationOnlyInteractiveFrame === true ||
7172
- hasPendingLocalSnapGridPointerMove === true
7133
+ hasPendingLocalSnapGridPointerMove === true ||
7134
+ shouldDeferLocalSnapGridRasterUntilBurstSettle === true
7173
7135
  )
7174
7136
  );
7175
7137
  syncLocalSnapGridForCameraNavigation(this, shouldUseLocalSnapGridPositionOnly === true);
@@ -7183,37 +7145,15 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
7183
7145
 
7184
7146
  _profileSection('webglRender');
7185
7147
  // ?�▼??[FIX] LOD 모드(MID/FAR)?�서??CSS3D ?�더???�출 건너?�기 ?�▼?? // CSS3D가 모두 display:none?�어???�더?��? 813�?객체�??�회?�면???�간 ?�비
7186
- const lastImmediateCameraFeedback = lastImmediateCameraFeedbackAtFrameStart;
7187
- const lastImmediateCameraFeedbackAgeMs = lastImmediateCameraFeedbackAgeAtFrameStart;
7188
- const hasFreshImmediateCameraFeedback = hasFreshImmediateCameraFeedbackAtFrameStart;
7189
- const canUseCss3dCameraFastPath = !!(
7190
- this.cssRenderer &&
7191
- typeof this.cssRenderer.renderCamera === 'function' &&
7192
- isCss3dEnabled &&
7193
- !isInLodMode &&
7194
- shouldUpdateCss3d &&
7195
- (this.isPanning === true || this.isZooming === true || isCameraMoving === true) &&
7196
- (isCameraMoving === true || hasFreshImmediateCameraFeedback === true) &&
7197
- !isNodeInteracting &&
7198
- !hasNonCameraNavigationForcedUpdate &&
7199
- !hasPendingNearCssWarmup &&
7200
- !hasMotionBlockingOverlayFocus &&
7201
- !hasPendingCss3dParentRepair &&
7202
- this._css3dVisualChangedThisFrame !== true &&
7203
- this._css3dVisualChangedSinceLastRender !== true &&
7204
- shouldSyncCss3dTransforms !== true &&
7205
- lodVisualEpochChangedThisFrame !== true &&
7206
- this.isWindowResizing !== true
7207
- );
7208
7148
  const css3dCameraFastPathBlockers = shouldCaptureFramePerf
7209
7149
  ? [
7210
7150
  !this.cssRenderer ? 'no-css-renderer' : '',
7211
7151
  this.cssRenderer && typeof this.cssRenderer.renderCamera !== 'function' ? 'no-render-camera' : '',
7212
7152
  isCss3dEnabled !== true ? 'css3d-disabled' : '',
7213
- isInLodMode === true ? 'lod-mode' : '',
7153
+ (isInLodMode === true && shouldRenderCss3dInLod !== true) ? 'lod-css3d-not-due' : '',
7214
7154
  shouldUpdateCss3d !== true ? 'css3d-not-due' : '',
7215
7155
  (this.isPanning === true || this.isZooming === true || isCameraMoving === true) ? '' : 'not-camera-motion',
7216
- (isCameraMoving === true || hasFreshImmediateCameraFeedback === true) ? '' : 'no-fresh-camera-motion',
7156
+ isCameraMoving === true ? '' : 'camera-pose-unchanged',
7217
7157
  isNodeInteracting === true ? 'node-interacting' : '',
7218
7158
  hasNonCameraNavigationForcedUpdate === true ? 'non-camera-forced-update' : '',
7219
7159
  hasPendingNearCssWarmup === true ? 'pending-near-css-warmup' : '',
@@ -7251,7 +7191,6 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
7251
7191
  this.cssRenderer.renderCamera(this.camera, true);
7252
7192
  }
7253
7193
  _profileSection('css3dCamera');
7254
- // ?�▲??[FIX] ?�▲?? _profileSection('css3dRender');
7255
7194
 
7256
7195
  const hasBusinessAutomationConnectionDraft =
7257
7196
  this._businessAutomationConnectionDraftActive === true;
@@ -7312,7 +7251,12 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
7312
7251
  } else if (this._businessAutomationEdgesDeferredForMotion === true &&
7313
7252
  hasBusinessAutomationEdgeLayer &&
7314
7253
  window.MindMapCss3DManager?.renderBusinessAutomationEdges &&
7315
- (panEndedThisFrame === true || zoomEndedThisFrame === true || cameraEndedThisFrame === true)) {
7254
+ (
7255
+ wheelZoomBurstSettledThisFrame === true ||
7256
+ panEndedThisFrame === true ||
7257
+ resizeEndedThisFrame === true ||
7258
+ (cameraEndedThisFrame === true && zoomEndedThisFrame !== true)
7259
+ )) {
7316
7260
  window.MindMapCss3DManager.renderBusinessAutomationEdges(this);
7317
7261
  this._businessAutomationEdgesDeferredForMotion = false;
7318
7262
  }
@@ -7474,18 +7418,25 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
7474
7418
  visibilityStableSkip: canSkipVisibilityCullingForStableFrame === true,
7475
7419
  visibilitySkipReason: visibilityCullingSkipReason || this._lastVisibilityCullingSkipReason || '',
7476
7420
  incrementalPanVisibility: isIncrementalPanVisibilityFrame === true,
7477
- freshImmediateCameraFeedback: hasFreshImmediateCameraFeedback === true,
7421
+ consumedWheelZoom: consumedWheelZoomThisFrame === true,
7422
+ wheelZoomBurstStarted: wheelZoomBurstStartedThisFrame === true,
7423
+ wheelZoomBurstActive: this._wheelZoomBurstActive === true,
7424
+ wheelZoomBurstSettled: wheelZoomBurstSettledThisFrame === true,
7425
+ wheelInputToFrameLatencyMs: Number(this._lastWheelInputToFrameLatencyMs || 0),
7478
7426
  cameraNavigationForceFrames: Number(this._forceUpdateFrames || 0),
7479
- panLiveRefreshForceFrames: Number(this._panLiveRefreshForceFrames || 0),
7480
7427
  shouldSyncCss3dTransforms: shouldSyncCss3dTransforms === true,
7481
7428
  shouldRenderCss3d: shouldRenderCss3dFrame === true,
7482
7429
  usedCss3dCameraFastPath: canUseCss3dCameraFastPath === true,
7483
7430
  css3dCameraFastPathBlockers,
7484
- immediateCameraFeedback: this._lastImmediateCameraFeedbackStatus || null,
7485
7431
  shouldSyncTextOverlays: shouldSyncTextOverlays === true,
7486
7432
  usedPassiveOverlayCameraFastPath: usedPassiveOverlayCameraFastPath === true,
7487
7433
  passiveOverlaySuppressed: isPassiveOverlaySuppressed === true,
7434
+ rendererPixelRatio: Number(this._currentDpr || 0),
7435
+ rendererDprInteractive: shouldUseInteractiveDpr === true,
7436
+ rendererDprRestorePending: !!this._deferredDprTimer,
7488
7437
  webglRenderReason,
7438
+ webglCameraOnlySkipped: canSkipWebglForCameraOnly === true,
7439
+ webglCameraOnlySkipBlockers: cameraOnlyWebglSkipBlockers,
7489
7440
  webgl: this._lastWebglRenderInfo || null,
7490
7441
  sections: sectionTimes
7491
7442
  };
@@ -7563,10 +7514,18 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
7563
7514
  this._lastFramePerfProfile = null;
7564
7515
  }
7565
7516
 
7517
+ const isFullResVisibilityReconcileDeferredForWheelBurst = !!(
7518
+ this._fullResVisibilityReconcilePending === true &&
7519
+ this._wheelZoomBurstActive === true &&
7520
+ wheelZoomBurstSettledThisFrame !== true
7521
+ );
7566
7522
  const hasPendingAnimationWakeWork =
7567
7523
  Number(this._forceUpdateFrames || 0) > 0 ||
7568
7524
  this._forceThemeAnimationFrame === true ||
7569
- this._fullResVisibilityReconcilePending === true ||
7525
+ (
7526
+ this._fullResVisibilityReconcilePending === true &&
7527
+ isFullResVisibilityReconcileDeferredForWheelBurst !== true
7528
+ ) ||
7570
7529
  hasPendingNearCssWarmup === true ||
7571
7530
  residentDirtyRequiresUpdate === true ||
7572
7531
  residentBandChanging === true ||
@@ -7587,7 +7546,9 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
7587
7546
  textOverlaySync: shouldSyncTextOverlays === true,
7588
7547
  forceUpdate: Number(this._forceUpdateFrames || 0) > 0,
7589
7548
  forceThemeAnimation: this._forceThemeAnimationFrame === true,
7590
- fullResVisibilityReconcile: this._fullResVisibilityReconcilePending === true,
7549
+ fullResVisibilityReconcile:
7550
+ this._fullResVisibilityReconcilePending === true &&
7551
+ isFullResVisibilityReconcileDeferredForWheelBurst !== true,
7591
7552
  pendingNearCssWarmup: hasPendingNearCssWarmup === true,
7592
7553
  residentDirtyRequiresUpdate: residentDirtyRequiresUpdate === true,
7593
7554
  residentBandChanging: residentBandChanging === true,
@@ -7961,6 +7922,11 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
7961
7922
  clearTimeout(this._viewStatePersistTimer);
7962
7923
  this._viewStatePersistTimer = null;
7963
7924
  }
7925
+ if (this._deferredDprTimer) {
7926
+ clearTimeout(this._deferredDprTimer);
7927
+ this._deferredDprTimer = null;
7928
+ }
7929
+ this._lastInteractiveDprAt = 0;
7964
7930
  this._viewStatePersistNeedsFreshSnapshot = false;
7965
7931
  this._viewStatePersistAfterMotion = false;
7966
7932