@mindexec/cli 0.2.479 → 0.2.481

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 (25) hide show
  1. package/electron/main.cjs +11 -1
  2. package/electron/source-smoke.mjs +8 -1
  3. package/electron/windows-package-smoke.mjs +2 -0
  4. package/package.json +1 -1
  5. package/remote-fast/osx-arm64/mindexec-remote-fast.dll +0 -0
  6. package/remote-fast/osx-x64/mindexec-remote-fast.dll +0 -0
  7. package/remote-fast/win-x64/mindexec-remote-fast.dll +0 -0
  8. package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js +28 -6
  9. package/wwwroot/_content/MindExecution.Shared/js/mind-map-interactions.js +106 -112
  10. package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-renderer.js +3 -1
  11. package/wwwroot/_content/MindExecution.Shared/js/mind-map-nodes.js +49 -22
  12. package/wwwroot/_framework/{MindExecution.Core.xxsj2s456b.dll → MindExecution.Core.2r5s0vx16i.dll} +0 -0
  13. package/wwwroot/_framework/{MindExecution.Kernel.5jofnc0wrd.dll → MindExecution.Kernel.8y4azlvjyi.dll} +0 -0
  14. package/wwwroot/_framework/{MindExecution.Plugins.Admin.t7m4jnqjg3.dll → MindExecution.Plugins.Admin.dtzk93cn6n.dll} +0 -0
  15. package/wwwroot/_framework/{MindExecution.Plugins.Business.6yjlhhavap.dll → MindExecution.Plugins.Business.uyqiv67u0q.dll} +0 -0
  16. package/wwwroot/_framework/{MindExecution.Plugins.Concept.iikqq5zxu0.dll → MindExecution.Plugins.Concept.5w50lskzj6.dll} +0 -0
  17. package/wwwroot/_framework/{MindExecution.Plugins.Directory.c5ribyne4m.dll → MindExecution.Plugins.Directory.a8isl4htud.dll} +0 -0
  18. package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.365bbuifr9.dll → MindExecution.Plugins.PlanMaster.imbm6hfih7.dll} +0 -0
  19. package/wwwroot/_framework/{MindExecution.Plugins.YouTube.ax415cilpk.dll → MindExecution.Plugins.YouTube.ua03os14kk.dll} +0 -0
  20. package/wwwroot/_framework/{MindExecution.Shared.21e2nvf86u.dll → MindExecution.Shared.yxk1a55sjz.dll} +0 -0
  21. package/wwwroot/_framework/{MindExecution.Web.ppgm8rey59.dll → MindExecution.Web.9bmh8f8s3k.dll} +0 -0
  22. package/wwwroot/_framework/blazor.boot.json +21 -21
  23. package/wwwroot/index.html +1 -1
  24. package/wwwroot/service-worker-assets.js +27 -27
  25. package/wwwroot/service-worker.js +1 -1
package/electron/main.cjs CHANGED
@@ -304,6 +304,10 @@ function initializeProductUpdates() {
304
304
  });
305
305
  }
306
306
 
307
+ function getDesktopWindowTitle() {
308
+ return `MindExec ${app.getVersion()}`;
309
+ }
310
+
307
311
  function createMainWindow() {
308
312
  const hiddenSmokeMode = process.env.MINDEXEC_DESKTOP_SMOKE === '1';
309
313
  const window = new BrowserWindow({
@@ -314,7 +318,7 @@ function createMainWindow() {
314
318
  show: !hiddenSmokeMode,
315
319
  autoHideMenuBar: true,
316
320
  backgroundColor: '#f8fafc',
317
- title: 'MindExec',
321
+ title: getDesktopWindowTitle(),
318
322
  icon: resolveDesktopIconPath(),
319
323
  webPreferences: {
320
324
  preload: path.join(__dirname, 'preload.cjs'),
@@ -325,6 +329,11 @@ function createMainWindow() {
325
329
  }
326
330
  });
327
331
 
332
+ window.on('page-title-updated', (event) => {
333
+ event.preventDefault();
334
+ window.setTitle(getDesktopWindowTitle());
335
+ });
336
+
328
337
  window.webContents.setWindowOpenHandler(() => ({
329
338
  action: 'allow',
330
339
  overrideBrowserWindowOptions: {
@@ -446,6 +455,7 @@ async function launchDesktop() {
446
455
  appVersion: app.getVersion(),
447
456
  bridgeVersion: status.version || null,
448
457
  runtimeMode: 'bundled',
458
+ windowTitle: window.getTitle(),
449
459
  bridgePort: activeBridgePort,
450
460
  remoteHubPort: activeRemoteHubPort,
451
461
  workspace: activeWorkspace,
@@ -15,7 +15,14 @@ const serverSource = fs.readFileSync(path.join(packageRoot, 'server.js'), 'utf8'
15
15
 
16
16
  assert.equal(packageJson.build?.appId, 'com.mindexec.desktop', 'Stable desktop appId is required.');
17
17
  assert.equal(packageJson.build?.productName, 'MindExec', 'Desktop product name changed unexpectedly.');
18
- assert.match(mainSource, /title:\s*'MindExec'/, 'The Electron window title must use the MindExec app brand.');
18
+ assert.match(mainSource, /function getDesktopWindowTitle\(\)/,
19
+ 'The Electron window title must derive from one version-aware helper.');
20
+ assert.match(mainSource, /`MindExec \$\{app\.getVersion\(\)\}`/,
21
+ 'The Electron window title must show the packaged app version.');
22
+ assert.match(mainSource, /title:\s*getDesktopWindowTitle\(\)/,
23
+ 'The initial Electron window title must use the version-aware title.');
24
+ assert.match(mainSource, /page-title-updated[\s\S]{0,220}preventDefault\(\)[\s\S]{0,220}setTitle\(getDesktopWindowTitle\(\)\)/,
25
+ 'Blazor page titles must not replace the version-aware desktop title.');
19
26
  assert.equal(packageJson.build?.extraMetadata?.main, 'electron/main.cjs', 'Packaged Electron entry point is missing.');
20
27
  assert.equal(packageJson.build?.asar, false, 'Bundled runtime executables require an unpacked app directory.');
21
28
  assert.ok(packageJson.files?.includes('electron/'), 'The npm package must include the Electron source contract.');
@@ -126,6 +126,8 @@ try {
126
126
  assert.equal(result.appVersion, packageJson.version, 'Electron app version does not match the npm package version.');
127
127
  assert.equal(result.bridgeVersion, packageJson.version, 'Bundled LocalBridge version does not match Electron.');
128
128
  assert.equal(result.runtimeMode, 'bundled', 'Electron did not use its bundled runtime.');
129
+ assert.equal(result.windowTitle, `MindExec ${packageJson.version}`,
130
+ 'Packaged Electron did not keep the version visible in the title bar.');
129
131
  assert.equal(result.bridgePort, bridgePort, 'Packaged shell did not use the requested Bridge port.');
130
132
  assert.equal(result.remoteHubPort, remoteHubPort, 'Packaged shell did not use the requested RemoteHub port.');
131
133
  assert.equal(path.resolve(result.workspace), path.resolve(workspace), 'Packaged Electron did not restore the saved workspace.');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindexec/cli",
3
- "version": "0.2.479",
3
+ "version": "0.2.481",
4
4
  "description": "MindExec local runtime and bridge CLI",
5
5
  "main": "server.js",
6
6
  "type": "module",
@@ -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 = '20260822-particle-60fps-motion-v872';
8
+ const MINDMAP_CORE_BUILD_ID = '20260824-css3d-viewport-owner-v873';
9
9
  const CanvasPhase = Object.freeze({
10
10
  Booting: 'booting',
11
11
  BoardFileLoading: 'board-file-loading',
@@ -2325,13 +2325,19 @@
2325
2325
  isSelected,
2326
2326
  isOnScreen,
2327
2327
  isVisibleInFrustum: entry.isVisibleInFrustum !== false,
2328
- cssVisible: entry.currentType === 'CSS'
2329
- && entry.cssObject?.visible !== false
2328
+ cssVisible: !!entry.cssObject && !!wrapperElement
2329
+ && entry.cssObject.visible !== false
2330
2330
  && wrapperElement?.style?.display !== 'none',
2331
2331
  glVisible: entry.glObject ? entry.glObject.visible !== false : false,
2332
2332
  bodyVisible: entry.bodyMesh ? entry.bodyMesh.visible !== false : false,
2333
- cssVisibleWithGlRenderableOverlap: entry.currentType === 'CSS'
2334
- && entry.cssObject?.visible !== false
2333
+ domVisibleWhileCurrentTypeGl: entry.currentType === 'GL'
2334
+ && !!entry.cssObject
2335
+ && !!wrapperElement
2336
+ && entry.cssObject.visible !== false
2337
+ && wrapperElement?.style?.display !== 'none',
2338
+ cssVisibleWithGlRenderableOverlap: !!entry.cssObject
2339
+ && !!wrapperElement
2340
+ && entry.cssObject.visible !== false
2335
2341
  && wrapperElement?.style?.display !== 'none'
2336
2342
  && visibleGlRenderables.length > 0,
2337
2343
  visibleGlRenderableCount: visibleGlRenderables.length,
@@ -4617,6 +4623,10 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
4617
4623
  // This avoids unnecessary heavy stabilization/LOD work on same-size tab return.
4618
4624
  if (!sizeUnchanged) {
4619
4625
  MindMapInteractions.onResize(this);
4626
+ } else {
4627
+ MindMapInteractions.syncViewportMetrics?.(this, {
4628
+ reason: 'same-size-route-reentry'
4629
+ });
4620
4630
  }
4621
4631
 
4622
4632
  if (this.lodRenderer) {
@@ -7166,6 +7176,13 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
7166
7176
  shouldUpdateCss3d &&
7167
7177
  canUseCss3dCameraFastPath !== true;
7168
7178
  if (shouldRenderCss3dFrame) {
7179
+ const viewportRepaired = window.MindMapInteractions?.syncViewportBeforeFullCssRender?.(
7180
+ this,
7181
+ 'main-full-css3d-render'
7182
+ ) === true;
7183
+ if (viewportRepaired) {
7184
+ this.renderer?.render?.(this.scene, this.camera);
7185
+ }
7169
7186
  // Fix browser scroll jitter
7170
7187
  const cssEl = this.cssRenderer.domElement;
7171
7188
  if (cssEl.scrollTop !== 0 || cssEl.scrollLeft !== 0) {
@@ -7836,7 +7853,8 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
7836
7853
  window.MindMapInteractions.syncViewportMetrics(this, {
7837
7854
  force,
7838
7855
  hideDuringResize: false,
7839
- scheduleReveal: false
7856
+ scheduleReveal: false,
7857
+ reason: 'canvas-show'
7840
7858
  });
7841
7859
  }
7842
7860
 
@@ -8119,6 +8137,10 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
8119
8137
  const liveNodeCount = Number(this.nodeObjectsById?.size || 0);
8120
8138
 
8121
8139
  try {
8140
+ window.MindMapInteractions?.syncViewportBeforeFullCssRender?.(
8141
+ this,
8142
+ 'project-thumbnail-capture'
8143
+ );
8122
8144
  this.camera.updateProjectionMatrix?.();
8123
8145
  this.camera.updateMatrixWorld?.(true);
8124
8146
  if (typeof this.updateVisibility === 'function') {
@@ -307,11 +307,33 @@ window.MindMapInteractions = (function () {
307
307
  return getViewportMetrics(module);
308
308
  }
309
309
 
310
+ function getCssRendererViewportSize(module) {
311
+ const size = module?.cssRenderer?.getSize?.() || null;
312
+ return {
313
+ width: Math.max(0, Number(size?.width || 0)),
314
+ height: Math.max(0, Number(size?.height || 0))
315
+ };
316
+ }
317
+
318
+ function isCssRendererViewportSizeStale(module, metrics) {
319
+ if (!module?.cssRenderer || !metrics) {
320
+ return false;
321
+ }
322
+
323
+ const rendererSize = getCssRendererViewportSize(module);
324
+ return Math.abs(rendererSize.width - metrics.width) > 1 ||
325
+ Math.abs(rendererSize.height - metrics.height) > 1;
326
+ }
327
+
310
328
  function haveViewportMetricsChanged(module, metrics, force = false) {
311
329
  if (force) {
312
330
  return true;
313
331
  }
314
332
 
333
+ if (isCssRendererViewportSizeStale(module, metrics)) {
334
+ return true;
335
+ }
336
+
315
337
  const lastWidth = Number(module?._lastViewportWidth || 0);
316
338
  const lastHeight = Number(module?._lastViewportHeight || 0);
317
339
  const lastLeft = Number(module?._lastViewportLeft || 0);
@@ -387,6 +409,7 @@ window.MindMapInteractions = (function () {
387
409
  let frameCount = 0;
388
410
  const stabilizeFrames = () => {
389
411
  if (module.scene && module.camera) {
412
+ syncViewportBeforeFullCssRender(module, 'viewport-reveal');
390
413
  module.renderer?.render?.(module.scene, module.camera);
391
414
  module.cssRenderer?.render?.(module.cssScene || module.scene, module.camera);
392
415
  }
@@ -422,7 +445,9 @@ window.MindMapInteractions = (function () {
422
445
  const {
423
446
  force = false,
424
447
  hideDuringResize = false,
425
- scheduleReveal = false
448
+ scheduleReveal = false,
449
+ warmCaches = true,
450
+ reason = 'viewport-metrics-change'
426
451
  } = options;
427
452
 
428
453
  const metrics = getViewportMetrics(module);
@@ -430,13 +455,16 @@ window.MindMapInteractions = (function () {
430
455
  return false;
431
456
  }
432
457
 
458
+ const previousCssRendererSize = getCssRendererViewportSize(module);
459
+ const cssRendererViewportWasStale = isCssRendererViewportSizeStale(module, metrics);
433
460
  if (!haveViewportMetricsChanged(module, metrics, force)) {
434
461
  return false;
435
462
  }
436
463
 
437
464
  const prevWidth = Number(module._lastViewportWidth || 0);
438
465
  const prevHeight = Number(module._lastViewportHeight || 0);
439
- const sizeChanged = force || metrics.width !== prevWidth || metrics.height !== prevHeight;
466
+ const sizeChanged = force || cssRendererViewportWasStale ||
467
+ metrics.width !== prevWidth || metrics.height !== prevHeight;
440
468
 
441
469
  storeViewportMetrics(module, metrics);
442
470
 
@@ -470,7 +498,19 @@ window.MindMapInteractions = (function () {
470
498
  module.targetZ = module.camera.position.z;
471
499
  }
472
500
 
473
- if (sizeChanged && scheduleReveal) {
501
+ if (cssRendererViewportWasStale) {
502
+ window.MindCanvasTrace?.emit?.('renderer.viewport.repaired', {
503
+ reason,
504
+ previousWidth: previousCssRendererSize.width,
505
+ previousHeight: previousCssRendererSize.height,
506
+ width: metrics.width,
507
+ height: metrics.height
508
+ });
509
+ }
510
+
511
+ if (warmCaches !== true) {
512
+ module._forceUpdateFrames = Math.max(Number(module._forceUpdateFrames || 0), 1);
513
+ } else if (sizeChanged && scheduleReveal) {
474
514
  resizeEndTimer = setTimeout(() => {
475
515
  warmViewportCaches(module);
476
516
  revealViewportCanvases(module);
@@ -482,6 +522,15 @@ window.MindMapInteractions = (function () {
482
522
  return true;
483
523
  }
484
524
 
525
+ function syncViewportBeforeFullCssRender(module, reason = 'full-css3d-render') {
526
+ return syncViewportMetrics(module, {
527
+ hideDuringResize: false,
528
+ scheduleReveal: false,
529
+ warmCaches: false,
530
+ reason
531
+ });
532
+ }
533
+
485
534
  function syncTextOverlaysNow(module) {
486
535
  if (!module) {
487
536
  return;
@@ -499,6 +548,7 @@ window.MindMapInteractions = (function () {
499
548
 
500
549
  if (module.cssRenderer && isCss3dEnabled && shouldRenderCss3dInLod) {
501
550
  try {
551
+ const viewportRepaired = syncViewportBeforeFullCssRender(module, 'immediate-css3d-sync');
502
552
  if (isCss3dTransformSyncEnabled) {
503
553
  window.MindMapCss3DManager?.update?.(module);
504
554
  }
@@ -507,6 +557,9 @@ window.MindMapInteractions = (function () {
507
557
  if (cssEl.scrollTop !== 0) cssEl.scrollTop = 0;
508
558
  if (cssEl.scrollLeft !== 0) cssEl.scrollLeft = 0;
509
559
  }
560
+ if (viewportRepaired) {
561
+ module.renderer?.render?.(module.scene, module.camera);
562
+ }
510
563
  module.cssRenderer.render(module.cssScene || module.scene, module.camera);
511
564
  } catch (error) {
512
565
  console.warn('[MindMapInteractions] Immediate CSS3D sync failed:', error);
@@ -1346,17 +1399,32 @@ window.MindMapInteractions = (function () {
1346
1399
  }
1347
1400
 
1348
1401
  // ▼▼▼ [New] Helper to clean up an in-progress edit node ▼▼▼
1349
- /**
1350
- * Checks whether there is a node currently being edited in CSS3D mode.
1351
- * If found, switches it back to WebGL.
1352
- * Called when the user clicks the background or presses Escape.
1353
- */
1354
- function cleanupCss3dNode(module) {
1402
+ /**
1403
+ * Checks whether there is a node currently being edited in CSS3D mode.
1404
+ * If found, commits it and releases ordinary MID/FAR nodes to resident rendering.
1405
+ * Called when the user clicks the background or presses Escape.
1406
+ */
1407
+ function shouldReleaseCss3dOwnershipToResident(module, entry) {
1408
+ if (!module?.lodRenderer || !entry) {
1409
+ return false;
1410
+ }
1411
+
1412
+ const cameraZ = Number(module.camera?.position?.z || 0);
1413
+ const lodThreshold = Number(
1414
+ window.LODRenderer?.LOD_THRESHOLDS?.MID ??
1415
+ window.LODRenderer?.LOD_THRESHOLD_NEAR ??
1416
+ 9000
1417
+ );
1418
+ const isLivePortalCssNode =
1419
+ window.LODRenderer?.isLivePortalCssLodModel?.(entry.model) === true;
1420
+ return cameraZ >= lodThreshold && isLivePortalCssNode !== true;
1421
+ }
1422
+
1423
+ function cleanupCss3dNode(module, preferredNodeId = null) {
1355
1424
  if (!module || !module.nodeObjectsById || !isTextInteractionActive(module)) return;
1356
-
1357
- // // [Cleanup] 선택된 노드가 있으면 우선 정리 (전체 순회 최소화)
1358
- const activeId = module.selectedNodeIdJs;
1359
- const isHighMode = (module.camera?.position?.z || 0) < 5000;
1425
+
1426
+ // Commit the node that owned the interaction before selection state changes.
1427
+ const activeId = preferredNodeId || module.selectedNodeIdJs;
1360
1428
 
1361
1429
  const processCleanup = (nodeId) => {
1362
1430
  const entry = module.nodeObjectsById.get(nodeId);
@@ -1441,22 +1509,13 @@ window.MindMapInteractions = (function () {
1441
1509
  }
1442
1510
  }
1443
1511
 
1444
- if (!isHighMode && entry.currentType === 'CSS') {
1445
- console.log(`[Interactions] Cleaning up CSS3D node ${nodeId} due to background click or Escape key.`);
1446
- window.MindMapNodes.switchToWebGL(module, nodeId);
1447
- }
1448
-
1449
- // ▼▼▼ [FIX] 편집 종료 후 LOD 시스템에 상태 변경 알림 ▼▼▼
1450
- entry.isCssDirty = true;
1512
+ // ▼▼▼ [FIX] 편집 종료 LOD 시스템에 상태 변경 알림 ▼▼▼
1513
+ entry.isCssDirty = true;
1451
1514
 
1452
- // LOD 모드(MID/FAR) 경우 CSS3D를 즉시 숨김
1453
- const cameraZ = module.camera?.position?.z || 0;
1454
- const lodThreshold = Number(window.LODRenderer?.LOD_THRESHOLDS?.MID ?? window.LODRenderer?.LOD_THRESHOLD_NEAR ?? 12000);
1455
- const isInLodMode = cameraZ >= lodThreshold;
1456
-
1457
- if (isInLodMode && module.lodRenderer) {
1515
+ if (shouldReleaseCss3dOwnershipToResident(module, entry)) {
1458
1516
  // CSS3D 즉시 숨김
1459
1517
  module.lodRenderer._hideNodeCss3d(entry);
1518
+ module.lodRenderer._hideGlBodyOnly?.(entry);
1460
1519
 
1461
1520
  // 인스턴스 데이터 재빌드 트리거
1462
1521
  module.lodRenderer.requestResidentPatch?.('update-node', nodeId);
@@ -1478,8 +1537,8 @@ window.MindMapInteractions = (function () {
1478
1537
  }
1479
1538
  }
1480
1539
 
1481
- // HIGH 모드에서는 CSS3D 유지, LOW 모드에서는 WebGL 전환 완료
1482
- module.isEditingNote = false;
1540
+ // Full-res keeps CSS3D ownership; MID/FAR releases it to the resident renderer.
1541
+ module.isEditingNote = false;
1483
1542
  }
1484
1543
  // ▲▲▲ [New] ▲▲▲
1485
1544
 
@@ -3352,19 +3411,6 @@ window.MindMapInteractions = (function () {
3352
3411
  });
3353
3412
  module._embedInteractivityNodeIds = selectedIds;
3354
3413
  }
3355
- function switchPreviousSelectedNoteToWebGL(module, respectHighMode = true) {
3356
- if (!module?.selectedNodeIdJs) return;
3357
- const prevEntry = module.nodeObjectsById?.get(module.selectedNodeIdJs);
3358
- if (!prevEntry || prevEntry.model.contentType !== 'note') return;
3359
-
3360
- if (respectHighMode) {
3361
- const cameraZ = module.camera?.position?.z || 0;
3362
- if (cameraZ < 5000) return; // HIGH 모드에서는 CSS3D 유지
3363
- }
3364
-
3365
- window.MindMapNodes.switchToWebGL(module, module.selectedNodeIdJs);
3366
- }
3367
-
3368
3414
  function setSingleSelection(module, nodeId, notifyBlazor = true) {
3369
3415
  if (MindMapNodes.applySingleSelection) {
3370
3416
  MindMapNodes.applySingleSelection(module, nodeId, { notifyBlazor, bringToFront: true });
@@ -3500,10 +3546,6 @@ window.MindMapInteractions = (function () {
3500
3546
  }
3501
3547
 
3502
3548
  schedulePrimaryClickAction(module, () => {
3503
- if (module.selectedNodeIdJs && module.selectedNodeIdJs !== nodeId) {
3504
- switchPreviousSelectedNoteToWebGL(module, false);
3505
- }
3506
-
3507
3549
  if (!isMultiSelecting) {
3508
3550
  window.MindMapNodes?.bringNodeToFront?.(module, nodeId);
3509
3551
  }
@@ -3871,38 +3913,17 @@ window.MindMapInteractions = (function () {
3871
3913
  return;
3872
3914
  }
3873
3915
 
3874
- // Security: before starting a non-panning interaction, switch any editing (CSS3D) nodes back to WebGL
3875
- // Only do this for node drag, selection box, background click, etc.
3876
- // ▼▼▼ [Changed] HIGH 모드(cameraZ < 4000)에서는 CSS3D 유지 ▼▼▼
3877
- if (module.isEditingNote) {
3878
- const cameraZ = module.camera?.position?.z || 0;
3879
- const isHighMode = cameraZ < 5000;
3880
-
3881
- // ▼▼▼ [Fix] 편집 중인 노드(테두리, 리사이즈 핸들 등) 조작 시 편집 모드 유지 ▼▼▼
3882
- const targetNode = target.closest?.('[data-node-id]');
3883
- const clickedId = targetNode?.dataset?.nodeId;
3884
- const isSelf = (clickedId && clickedId === module.selectedNodeIdJs);
3885
-
3886
- if (isSelf) {
3887
- // 편집 모드 유지 (리사이즈 등을 위해)
3888
- } else {
3889
- if (!isHighMode) {
3890
- // LOW 모드에서만 WebGL로 전환
3891
- module.nodeObjectsById.forEach((entry, nodeId) => {
3892
- if (entry.currentType === 'CSS') {
3893
- console.warn(`[Interactions] Force-switching node ${nodeId} from CSS back to WebGL (LOW mode).`);
3894
- window.MindMapNodes.switchToWebGL(module, nodeId);
3895
- }
3896
- });
3897
- } else {
3898
- console.log(`[Interactions] HIGH mode - keeping CSS3D (cameraZ=${cameraZ.toFixed(0)})`);
3899
- }
3900
- module.isEditingNote = false;
3901
- }
3902
- // ▲▲▲ [Fix] ▲▲▲
3903
- }
3904
- // ▲▲▲ [Changed] ▲▲▲
3905
- // --- end security switch-back ---
3916
+ // Editing ownership is committed by cleanupCss3dNode(). Selection itself
3917
+ // must not switch a canonical full-res CSS3D node to WebGL.
3918
+ if (module.isEditingNote) {
3919
+ const targetNode = target.closest?.('[data-node-id]');
3920
+ const clickedId = targetNode?.dataset?.nodeId;
3921
+ const isSelf = (clickedId && clickedId === module.selectedNodeIdJs);
3922
+
3923
+ if (!isSelf) {
3924
+ module.isEditingNote = false;
3925
+ }
3926
+ }
3906
3927
 
3907
3928
  // Security: when mouse-down starts, explicitly reset any previous interaction state
3908
3929
  // A prior interaction may not have completed; reset before starting a new one
@@ -4175,10 +4196,7 @@ window.MindMapInteractions = (function () {
4175
4196
  nodeEntry.cssObject.element.style.pointerEvents = 'none';
4176
4197
  }
4177
4198
 
4178
- if (module.selectedNodeIdJs) {
4179
- switchPreviousSelectedNoteToWebGL(module, true);
4180
- }
4181
- setSingleSelection(module, clickedNodeId, true);
4199
+ setSingleSelection(module, clickedNodeId, true);
4182
4200
  }
4183
4201
  // ▲▲▲ [Fix] ▲▲▲
4184
4202
  }
@@ -4610,7 +4628,6 @@ window.MindMapInteractions = (function () {
4610
4628
 
4611
4629
  // 기존 선택된 노드가 있다면 해제 (단일 선택 모드 전환)
4612
4630
  if (!isMultiModifier && (module.selectedNodeIdJs || module.multiSelectedNodeIds.size > 0)) {
4613
- // switchPreviousSelectedNoteToWebGL(module, true); // clearSelectionState 내부에서 처리되거나 필요 없음
4614
4631
  clearSelectionState(module, { notifyBlazor: true, hideMenu: true, hideMultiSelect: true });
4615
4632
  }
4616
4633
 
@@ -5117,11 +5134,10 @@ window.MindMapInteractions = (function () {
5117
5134
 
5118
5135
  if (shouldRunBackgroundPrimaryClick) {
5119
5136
  schedulePrimaryClickAction(module, () => {
5137
+ // Commit/release the interaction owner before clearing the selection id.
5138
+ cleanupCss3dNode(module, oldSelectedNodeId);
5120
5139
  clearSelectionState(module, { notifyBlazor: true, hideMenu: true, hideMultiSelect: true });
5121
5140
 
5122
- // Use cleanupCss3dNode instead of blurActiveEditable
5123
- cleanupCss3dNode(module);
5124
-
5125
5141
  // Blur global-input-textarea (and other focused inputs)
5126
5142
  if (document.activeElement && (document.activeElement.tagName === 'TEXTAREA' || document.activeElement.tagName === 'INPUT')) {
5127
5143
  // Use helper defined in index.html
@@ -5161,19 +5177,6 @@ window.MindMapInteractions = (function () {
5161
5177
  }
5162
5178
  }
5163
5179
 
5164
- if (oldSelectedNodeId && module.selectedNodeIdJs !== oldSelectedNodeId) {
5165
- const prevEntry = module.nodeObjectsById.get(oldSelectedNodeId);
5166
- if (prevEntry && prevEntry.model.contentType === 'note') {
5167
- // ▼▼▼ [Changed] HIGH 모드에서는 WebGL 전환 스킵 ▼▼▼
5168
- const cameraZ = module.camera?.position?.z || 0;
5169
- const isHighMode = cameraZ < 5000;
5170
- if (!isHighMode) {
5171
- MindMapNodes.switchToWebGL(module, oldSelectedNodeId);
5172
- }
5173
- // ▲▲▲ [Changed] ▲▲▲
5174
- }
5175
- }
5176
-
5177
5180
  }
5178
5181
  // 4) Stop single-node drag
5179
5182
  else if (module.isDraggingNode && module.draggedNodeObject) {
@@ -5239,10 +5242,6 @@ window.MindMapInteractions = (function () {
5239
5242
  }
5240
5243
  } else {
5241
5244
  schedulePrimaryClickAction(module, () => {
5242
- if (module.selectedNodeIdJs && module.selectedNodeIdJs !== clickedNodeId) {
5243
- switchPreviousSelectedNoteToWebGL(module, false);
5244
- }
5245
-
5246
5245
  if (isMultiSelecting) {
5247
5246
  if (module.multiSelectedNodeIds.has(clickedNodeId)) {
5248
5247
  module.multiSelectedNodeIds.delete(clickedNodeId);
@@ -5361,10 +5360,6 @@ window.MindMapInteractions = (function () {
5361
5360
  }
5362
5361
  } else {
5363
5362
  schedulePrimaryClickAction(module, () => {
5364
- if (module.selectedNodeIdJs && module.selectedNodeIdJs !== clickedNodeId) {
5365
- switchPreviousSelectedNoteToWebGL(module, false);
5366
- }
5367
-
5368
5363
  if (isMultiSelecting) {
5369
5364
  if (module.multiSelectedNodeIds.has(clickedNodeId)) {
5370
5365
  module.multiSelectedNodeIds.delete(clickedNodeId);
@@ -7637,14 +7632,12 @@ window.MindMapInteractions = (function () {
7637
7632
  // 성능 저하를 유발하는 문제 해결
7638
7633
  nodeEntry.isCssDirty = true; // CSS3D 콘텐츠 재동기화 필요 표시
7639
7634
 
7640
- // LOD 모드(MID/FAR)인 경우 CSS3D를 즉시 숨김
7641
- const cameraZ = module.camera?.position?.z || 0;
7642
- const lodThreshold = Number(window.LODRenderer?.LOD_THRESHOLDS?.MID ?? window.LODRenderer?.LOD_THRESHOLD_NEAR ?? 12000);
7643
- const isInLodMode = cameraZ >= lodThreshold;
7644
-
7645
- if (isInLodMode && module.lodRenderer) {
7635
+ const cameraZ = module.camera?.position?.z || 0;
7636
+
7637
+ if (shouldReleaseCss3dOwnershipToResident(module, nodeEntry)) {
7646
7638
  // CSS3D 즉시 숨김
7647
7639
  module.lodRenderer._hideNodeCss3d(nodeEntry);
7640
+ module.lodRenderer._hideGlBodyOnly?.(nodeEntry);
7648
7641
 
7649
7642
  // 인스턴스 데이터 재빌드 트리거
7650
7643
  module.lodRenderer.requestResidentPatch?.('update-node', nodeEntry.model?.id || nodeEntry.model?.Id);
@@ -7844,6 +7837,7 @@ window.MindMapInteractions = (function () {
7844
7837
  },
7845
7838
  onResize: onResize,
7846
7839
  syncViewportMetrics: syncViewportMetrics,
7840
+ syncViewportBeforeFullCssRender: syncViewportBeforeFullCssRender,
7847
7841
  // ▼▼▼ [New] Expose selectNode and startEditingNode ▼▼▼
7848
7842
  selectNodeById: function (module, nodeId, options = {}) {
7849
7843
  const normalizedId = String(nodeId || '').trim();
@@ -51,7 +51,7 @@
51
51
  // ▲▲▲ [Usage] ▲▲▲
52
52
 
53
53
  // Procedural line rendering settings
54
- const LOD_RENDERER_BUILD_ID = '20260728-resident-cache-v848';
54
+ const LOD_RENDERER_BUILD_ID = '20260824-css3d-owner-v849';
55
55
  const DirtyKind = Object.freeze({
56
56
  ResidentFullRebuild: 'resident-full-rebuild',
57
57
  ResidentPatch: 'resident-patch',
@@ -10263,6 +10263,8 @@
10263
10263
  window.LODRenderer.LOD_THRESHOLDS = { ...LOD_THRESHOLDS };
10264
10264
  window.LODRenderer.LOD_THRESHOLD_FAR = LOD_THRESHOLD_FAR;
10265
10265
  window.LODRenderer.LOD_THRESHOLD_NEAR = LOD_THRESHOLD_NEAR;
10266
+ window.LODRenderer.supportsCss3dNodeModel = supportsCss3dNodeModel;
10267
+ window.LODRenderer.isLivePortalCssLodModel = isLivePortalCssLodModel;
10266
10268
  window.LODRenderer.DIRTY_KIND = DirtyKind;
10267
10269
  window.LODRenderer.DEBUG_CONSTANTS = {
10268
10270
  build: LOD_RENDERER_BUILD_ID,
@@ -105,7 +105,7 @@
105
105
 
106
106
  const cameraZ = Number(module?.camera?.position?.z ?? module?.targetZ ?? 0);
107
107
  const thresholds = window.LODRenderer?.LOD_THRESHOLDS || null;
108
- const midThreshold = Number(thresholds?.MID ?? window.LODRenderer?.LOD_THRESHOLD_NEAR ?? 4500);
108
+ const midThreshold = Number(thresholds?.MID ?? window.LODRenderer?.LOD_THRESHOLD_NEAR ?? 9000);
109
109
  if (Number.isFinite(cameraZ) && Number.isFinite(midThreshold) && cameraZ >= midThreshold) {
110
110
  return false;
111
111
  }
@@ -4329,27 +4329,25 @@
4329
4329
  return;
4330
4330
  }
4331
4331
 
4332
- // ▼▼▼ [Changed] HIGH 모드(CSS3D 유효 구간)에서는 WebGL로 전환 금지 ▼▼▼
4333
- const cameraZ = module.camera?.position?.z || 0;
4334
- const threshold = 4000;
4335
- if (cameraZ < threshold) {
4336
- const supportsCss3d = nodeEntry.model.contentType === 'text' ||
4337
- nodeEntry.model.contentType === 'note' ||
4338
- nodeEntry.model.contentType === 'memo' ||
4339
- nodeEntry.model.contentType === 'markdown' ||
4340
- nodeEntry.model.contentType === 'code' ||
4341
- nodeEntry.model.contentType === 'csv-table' ||
4342
- nodeEntry.model.contentType === 'image' ||
4343
- nodeEntry.model.contentType === 'video' ||
4344
- nodeEntry.model.contentType === 'embed';
4345
- if (supportsCss3d) {
4346
- console.log(`[MindMapNodes] SwitchToWebGL(${nodeId}) SKIPPED (HIGH Mode - Keeping CSS3D).`);
4347
- return;
4348
- }
4332
+ const cameraZ = Number(module.camera?.position?.z || 0);
4333
+ const midThreshold = Number(
4334
+ window.LODRenderer?.LOD_THRESHOLDS?.MID ??
4335
+ window.LODRenderer?.LOD_THRESHOLD_NEAR ??
4336
+ 9000
4337
+ );
4338
+ const isLivePortalCssNode =
4339
+ window.LODRenderer?.isLivePortalCssLodModel?.(nodeEntry.model) === true;
4340
+
4341
+ // Renderer ownership follows the canonical LOD band, not selection.
4342
+ // NEAR/NORMAL and live portal nodes keep their CSS3D source mounted.
4343
+ if (cameraZ < midThreshold || isLivePortalCssNode) {
4344
+ return;
4349
4345
  }
4350
- // ▲▲▲ [Changed] ▲▲▲
4351
4346
 
4352
- if (nodeEntry.currentType === 'GL') {
4347
+ const cssElement = nodeEntry.cssObject?.element || null;
4348
+ const hasVisibleCssOwnership = nodeEntry.cssObject?.visible === true ||
4349
+ (!!nodeEntry.cssObject?.parent && cssElement?.style?.display !== 'none');
4350
+ if (nodeEntry.currentType === 'GL' && !hasVisibleCssOwnership) {
4353
4351
  flushPendingGlRenderOrder(module, nodeEntry);
4354
4352
  log(`[MindMapNodes] SwitchToWebGL(${nodeId}) SKIPPED (Already in GL mode).`);
4355
4353
  return;
@@ -4407,8 +4405,18 @@
4407
4405
 
4408
4406
  const cssPos = nodeEntry.cssObject.position;
4409
4407
  // [Fix] Force Z=0 to eliminate parallax
4410
- nodeEntry.glObject.position.set(cssPos.x, cssPos.y, 0);
4411
- if (nodeEntry.glObject) {
4408
+ nodeEntry.glObject?.position?.set?.(cssPos.x, cssPos.y, 0);
4409
+ let ownershipReleased = false;
4410
+ if (module.lodRenderer?._hideNodeCss3d) {
4411
+ module.lodRenderer._hideNodeCss3d(nodeEntry);
4412
+ module.lodRenderer._hideGlBodyOnly?.(nodeEntry);
4413
+ module.lodRenderer.requestVisualRefresh?.('css3d-owner-release');
4414
+ ownershipReleased = true;
4415
+ } else if (nodeEntry.glObject) {
4416
+ nodeEntry.cssObject.visible = false;
4417
+ if (cssElement) {
4418
+ cssElement.style.display = 'none';
4419
+ }
4412
4420
  ensureNodeMeshCache(nodeEntry);
4413
4421
  nodeEntry.glObject.visible = true;
4414
4422
  const body = nodeEntry.bodyMesh;
@@ -4416,12 +4424,31 @@
4416
4424
  if (body) body.visible = true;
4417
4425
  if (tail) tail.visible = true;
4418
4426
  setNodeScrollbarVisibility(nodeEntry, Number(nodeEntry.model?.maxScroll || 0) > 0);
4427
+ ownershipReleased = true;
4428
+ }
4429
+
4430
+ if (!ownershipReleased) {
4431
+ warn(`[MindMapNodes] SwitchToWebGL(${nodeId}) deferred: no resident or WebGL owner is available.`);
4432
+ return;
4419
4433
  }
4420
4434
 
4421
4435
  nodeEntry.currentType = 'GL';
4436
+ module._forceUpdateFrames = Math.max(Number(module._forceUpdateFrames || 0), 1);
4422
4437
  log(`[MindMapNodes] ✓ Node ${nodeId} is now in WebGL mode`);
4423
4438
 
4424
4439
  await updateNodeContent(module, nodeId, nodeEntry.model.response, nodeEntry.model.width, nodeEntry.model.height);
4440
+
4441
+ const cssDomStillVisible = nodeEntry.cssObject?.visible === true ||
4442
+ (!!nodeEntry.cssObject?.parent && cssElement?.style?.display !== 'none');
4443
+ window.MindCanvasDevGuards?.assert?.(
4444
+ cssDomStillVisible !== true,
4445
+ 'renderer-css3d-gl-owner-overlap',
4446
+ {
4447
+ nodeId,
4448
+ cameraZ,
4449
+ currentType: nodeEntry.currentType
4450
+ }
4451
+ );
4425
4452
  }
4426
4453
 
4427
4454
  // ▼▼▼ [New] Update node content type (used for converting text to note) ▼▼▼
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "mainAssemblyName": "MindExecution.Web",
3
3
  "resources": {
4
- "hash": "sha256-qpH6Ma5NxLdwrBBJ/L3iPc/2zG1coZJYk6xkFeHu1yM=",
4
+ "hash": "sha256-mXWbB+r0wD5ixhld4+MKtYH4yPbQ7mRkmT7v8rgb2+E=",
5
5
  "fingerprinting": {
6
6
  "Google.Protobuf.9h59ukbel7.dll": "Google.Protobuf.dll",
7
7
  "Markdig.d1j7v41cl1.dll": "Markdig.dll",
@@ -122,16 +122,16 @@
122
122
  "System.brmz7yk5qh.dll": "System.dll",
123
123
  "netstandard.b50t77veor.dll": "netstandard.dll",
124
124
  "System.Private.CoreLib.wflwsce1yq.dll": "System.Private.CoreLib.dll",
125
- "MindExecution.Core.xxsj2s456b.dll": "MindExecution.Core.dll",
126
- "MindExecution.Kernel.5jofnc0wrd.dll": "MindExecution.Kernel.dll",
127
- "MindExecution.Plugins.Admin.t7m4jnqjg3.dll": "MindExecution.Plugins.Admin.dll",
128
- "MindExecution.Plugins.Business.6yjlhhavap.dll": "MindExecution.Plugins.Business.dll",
129
- "MindExecution.Plugins.Concept.iikqq5zxu0.dll": "MindExecution.Plugins.Concept.dll",
130
- "MindExecution.Plugins.Directory.c5ribyne4m.dll": "MindExecution.Plugins.Directory.dll",
131
- "MindExecution.Plugins.PlanMaster.365bbuifr9.dll": "MindExecution.Plugins.PlanMaster.dll",
132
- "MindExecution.Plugins.YouTube.ax415cilpk.dll": "MindExecution.Plugins.YouTube.dll",
133
- "MindExecution.Shared.21e2nvf86u.dll": "MindExecution.Shared.dll",
134
- "MindExecution.Web.ppgm8rey59.dll": "MindExecution.Web.dll",
125
+ "MindExecution.Core.2r5s0vx16i.dll": "MindExecution.Core.dll",
126
+ "MindExecution.Kernel.8y4azlvjyi.dll": "MindExecution.Kernel.dll",
127
+ "MindExecution.Plugins.Admin.dtzk93cn6n.dll": "MindExecution.Plugins.Admin.dll",
128
+ "MindExecution.Plugins.Business.uyqiv67u0q.dll": "MindExecution.Plugins.Business.dll",
129
+ "MindExecution.Plugins.Concept.5w50lskzj6.dll": "MindExecution.Plugins.Concept.dll",
130
+ "MindExecution.Plugins.Directory.a8isl4htud.dll": "MindExecution.Plugins.Directory.dll",
131
+ "MindExecution.Plugins.PlanMaster.imbm6hfih7.dll": "MindExecution.Plugins.PlanMaster.dll",
132
+ "MindExecution.Plugins.YouTube.ua03os14kk.dll": "MindExecution.Plugins.YouTube.dll",
133
+ "MindExecution.Shared.yxk1a55sjz.dll": "MindExecution.Shared.dll",
134
+ "MindExecution.Web.9bmh8f8s3k.dll": "MindExecution.Web.dll",
135
135
  "dotnet.native.566r55w3xu.js": "dotnet.native.js",
136
136
  "dotnet.native.x6q5aixc38.wasm": "dotnet.native.wasm",
137
137
  "dotnet.js": "dotnet.js",
@@ -276,18 +276,18 @@
276
276
  "System.Xml.XDocument.sn51jas17n.dll": "sha256-GNI2kFgFmPTwzuzwUn8gxK+AzGLUWRJFdg9JzIbrybQ=",
277
277
  "System.brmz7yk5qh.dll": "sha256-CfM2miyj1KHApFmqMdLYWio3S/jrdON2pW9Xr2nTwlo=",
278
278
  "netstandard.b50t77veor.dll": "sha256-//jQGOXjb8ET8WtXgOJrAxLx6E7zDJ5RjRRutwkvmxo=",
279
- "MindExecution.Core.xxsj2s456b.dll": "sha256-uzTPf1yvTCunc39ykMPvPEuAIxvNZM4TEJNycxCg6fY=",
280
- "MindExecution.Kernel.5jofnc0wrd.dll": "sha256-8VDveBicr2orZisFaztAg5a/nt80HDRS81+S7PT/ROM=",
281
- "MindExecution.Plugins.Business.6yjlhhavap.dll": "sha256-Pk1GbR57U59MEbxO8jQQPWs+FMNPKL3oW3SWfxB3PPE=",
282
- "MindExecution.Plugins.Concept.iikqq5zxu0.dll": "sha256-phdKuE+I1H+J7wAh0aUNejWKG/P9SqxoCWNw+lafcCo=",
283
- "MindExecution.Plugins.PlanMaster.365bbuifr9.dll": "sha256-6/EU8a8T/YU/gGzmKzKk7oa/JDV7aljp1AlCJy+Ow3w=",
284
- "MindExecution.Shared.21e2nvf86u.dll": "sha256-hvYai1+mJU08ECi/s5lghcNB6tlamHfO/TqNO9DiI3w=",
285
- "MindExecution.Web.ppgm8rey59.dll": "sha256-HbKsqgHbYSJeoiQLgabISECR/bBtMWj8ojjcvR0hMEE="
279
+ "MindExecution.Core.2r5s0vx16i.dll": "sha256-Hji7EvwLtfgPOiDYgH4DHXZibPhbdWcYiGPG4NjYCWg=",
280
+ "MindExecution.Kernel.8y4azlvjyi.dll": "sha256-cKFcW5yNWguo2InCvgpimy5t/MhGZ2f5zITqvF99lvg=",
281
+ "MindExecution.Plugins.Business.uyqiv67u0q.dll": "sha256-BqDkv3XHSL10h0Lda9sJCj4NVrhijSowakl9dgGKCzk=",
282
+ "MindExecution.Plugins.Concept.5w50lskzj6.dll": "sha256-1UKv7Dxs0goKcQOkSsYBdhbE7Vp5Oy4YpqvXOtzEMHM=",
283
+ "MindExecution.Plugins.PlanMaster.imbm6hfih7.dll": "sha256-pgGCEAp8dmn511srw7KD/2fctoAJgnHAzcvGWbhoWG4=",
284
+ "MindExecution.Shared.yxk1a55sjz.dll": "sha256-Ru7/Qulj+40HqtPdqDs5O6dNvshmQ6JngyipwN4/dcs=",
285
+ "MindExecution.Web.9bmh8f8s3k.dll": "sha256-Na9Tbn6PRhJ3L72qs5aIn+/ahlhtzZIxWc7r8G/vAtk="
286
286
  },
287
287
  "lazyAssembly": {
288
- "MindExecution.Plugins.Admin.t7m4jnqjg3.dll": "sha256-h6eePrT2PjCuijOqL44A0iHxFZ/lBr1Bz8MObEyvems=",
289
- "MindExecution.Plugins.Directory.c5ribyne4m.dll": "sha256-EAMxoZl/5UCiM1XasoGXQzYTK0MfPYEjzJe23rXr9M0=",
290
- "MindExecution.Plugins.YouTube.ax415cilpk.dll": "sha256-0vtb5+eLPDa8On/YfdvqCoJHPg3Bsxn9m9ejqVHFg2c="
288
+ "MindExecution.Plugins.Admin.dtzk93cn6n.dll": "sha256-UQfkrWbcBYN30pXQ3RWIZqQwygXIvaBBqc/H6hqiTyE=",
289
+ "MindExecution.Plugins.Directory.a8isl4htud.dll": "sha256-tp9XZ/Nxysn/xuTsD8lsKyJt++V8GjSkjsXm++ZxhVk=",
290
+ "MindExecution.Plugins.YouTube.ua03os14kk.dll": "sha256-Rjxv6t01L71frLHXiB3nNEeuVc9CK7OOYtF8UwUyhSI="
291
291
  }
292
292
  },
293
293
  "cacheBootResources": true,
@@ -614,7 +614,7 @@
614
614
  }
615
615
 
616
616
  const base = '_content/MindExecution.Shared/js/';
617
- const scriptVersion = '20260823-compact-organic-v2-v984';
617
+ const scriptVersion = '20260824-css3d-viewport-owner-v985';
618
618
  const scriptUrl = (script) => `${base}${script}?v=${scriptVersion}`;
619
619
  console.log(`[Script Loader] Shared JS version: ${scriptVersion}`);
620
620
  const criticalScripts = [
@@ -1,5 +1,5 @@
1
1
  self.assetsManifest = {
2
- "version": "/IXWXXqO",
2
+ "version": "TXjYyM9d",
3
3
  "assets": [
4
4
  {
5
5
  "hash": "sha256-+CSYMcqLNTsq3VnH11jgYyOCCdxvHzL74CBmo4sCmMU=",
@@ -90,7 +90,7 @@ self.assetsManifest = {
90
90
  "url": "_content/MindExecution.Shared/js/mind-map-board-render-ownership.js"
91
91
  },
92
92
  {
93
- "hash": "sha256-Zg3spK1Ei6cgOAty49u1YEH2Duy6MgjroPjK4+YulmE=",
93
+ "hash": "sha256-LRUAnzz0htMlmLIhr3eJ7a3i7pqIj61sTqiAcWJVT6c=",
94
94
  "url": "_content/MindExecution.Shared/js/mind-map-core.js"
95
95
  },
96
96
  {
@@ -126,7 +126,7 @@ self.assetsManifest = {
126
126
  "url": "_content/MindExecution.Shared/js/mind-map-image-policy.js"
127
127
  },
128
128
  {
129
- "hash": "sha256-MNC1OM1PiIW3yCLtMScPNDgweZbm5WWwB4e61VefC/s=",
129
+ "hash": "sha256-uVMRzWHkDDBBe6tm3VjH4cljpWgBZMQbPwLqDUoRCks=",
130
130
  "url": "_content/MindExecution.Shared/js/mind-map-interactions.js"
131
131
  },
132
132
  {
@@ -134,7 +134,7 @@ self.assetsManifest = {
134
134
  "url": "_content/MindExecution.Shared/js/mind-map-lod-plan-worker.js"
135
135
  },
136
136
  {
137
- "hash": "sha256-3Yk1Pb4/9wi97b1qDQJpX5E14wkNJfx5IVSNX9pkYww=",
137
+ "hash": "sha256-2qu9aDwp1HJEuBvzN2H0SrxtTVX1d/2odbeih3fXE1Y=",
138
138
  "url": "_content/MindExecution.Shared/js/mind-map-lod-renderer.js"
139
139
  },
140
140
  {
@@ -158,7 +158,7 @@ self.assetsManifest = {
158
158
  "url": "_content/MindExecution.Shared/js/mind-map-node-search-worker.js"
159
159
  },
160
160
  {
161
- "hash": "sha256-PXsPkLP/90ZPO16kreoeNdxcEty52wTtHS1njbDR1tg=",
161
+ "hash": "sha256-b7RtKlV7JrBOoYFt4TpehEFuE6ydN0GaIpkWDMN3pxQ=",
162
162
  "url": "_content/MindExecution.Shared/js/mind-map-nodes.js"
163
163
  },
164
164
  {
@@ -446,44 +446,44 @@ self.assetsManifest = {
446
446
  "url": "_framework/MimeMapping.og9ys58ylm.dll"
447
447
  },
448
448
  {
449
- "hash": "sha256-uzTPf1yvTCunc39ykMPvPEuAIxvNZM4TEJNycxCg6fY=",
450
- "url": "_framework/MindExecution.Core.xxsj2s456b.dll"
449
+ "hash": "sha256-Hji7EvwLtfgPOiDYgH4DHXZibPhbdWcYiGPG4NjYCWg=",
450
+ "url": "_framework/MindExecution.Core.2r5s0vx16i.dll"
451
451
  },
452
452
  {
453
- "hash": "sha256-8VDveBicr2orZisFaztAg5a/nt80HDRS81+S7PT/ROM=",
454
- "url": "_framework/MindExecution.Kernel.5jofnc0wrd.dll"
453
+ "hash": "sha256-cKFcW5yNWguo2InCvgpimy5t/MhGZ2f5zITqvF99lvg=",
454
+ "url": "_framework/MindExecution.Kernel.8y4azlvjyi.dll"
455
455
  },
456
456
  {
457
- "hash": "sha256-h6eePrT2PjCuijOqL44A0iHxFZ/lBr1Bz8MObEyvems=",
458
- "url": "_framework/MindExecution.Plugins.Admin.t7m4jnqjg3.dll"
457
+ "hash": "sha256-UQfkrWbcBYN30pXQ3RWIZqQwygXIvaBBqc/H6hqiTyE=",
458
+ "url": "_framework/MindExecution.Plugins.Admin.dtzk93cn6n.dll"
459
459
  },
460
460
  {
461
- "hash": "sha256-Pk1GbR57U59MEbxO8jQQPWs+FMNPKL3oW3SWfxB3PPE=",
462
- "url": "_framework/MindExecution.Plugins.Business.6yjlhhavap.dll"
461
+ "hash": "sha256-BqDkv3XHSL10h0Lda9sJCj4NVrhijSowakl9dgGKCzk=",
462
+ "url": "_framework/MindExecution.Plugins.Business.uyqiv67u0q.dll"
463
463
  },
464
464
  {
465
- "hash": "sha256-phdKuE+I1H+J7wAh0aUNejWKG/P9SqxoCWNw+lafcCo=",
466
- "url": "_framework/MindExecution.Plugins.Concept.iikqq5zxu0.dll"
465
+ "hash": "sha256-1UKv7Dxs0goKcQOkSsYBdhbE7Vp5Oy4YpqvXOtzEMHM=",
466
+ "url": "_framework/MindExecution.Plugins.Concept.5w50lskzj6.dll"
467
467
  },
468
468
  {
469
- "hash": "sha256-EAMxoZl/5UCiM1XasoGXQzYTK0MfPYEjzJe23rXr9M0=",
470
- "url": "_framework/MindExecution.Plugins.Directory.c5ribyne4m.dll"
469
+ "hash": "sha256-tp9XZ/Nxysn/xuTsD8lsKyJt++V8GjSkjsXm++ZxhVk=",
470
+ "url": "_framework/MindExecution.Plugins.Directory.a8isl4htud.dll"
471
471
  },
472
472
  {
473
- "hash": "sha256-6/EU8a8T/YU/gGzmKzKk7oa/JDV7aljp1AlCJy+Ow3w=",
474
- "url": "_framework/MindExecution.Plugins.PlanMaster.365bbuifr9.dll"
473
+ "hash": "sha256-pgGCEAp8dmn511srw7KD/2fctoAJgnHAzcvGWbhoWG4=",
474
+ "url": "_framework/MindExecution.Plugins.PlanMaster.imbm6hfih7.dll"
475
475
  },
476
476
  {
477
- "hash": "sha256-0vtb5+eLPDa8On/YfdvqCoJHPg3Bsxn9m9ejqVHFg2c=",
478
- "url": "_framework/MindExecution.Plugins.YouTube.ax415cilpk.dll"
477
+ "hash": "sha256-Rjxv6t01L71frLHXiB3nNEeuVc9CK7OOYtF8UwUyhSI=",
478
+ "url": "_framework/MindExecution.Plugins.YouTube.ua03os14kk.dll"
479
479
  },
480
480
  {
481
- "hash": "sha256-hvYai1+mJU08ECi/s5lghcNB6tlamHfO/TqNO9DiI3w=",
482
- "url": "_framework/MindExecution.Shared.21e2nvf86u.dll"
481
+ "hash": "sha256-Ru7/Qulj+40HqtPdqDs5O6dNvshmQ6JngyipwN4/dcs=",
482
+ "url": "_framework/MindExecution.Shared.yxk1a55sjz.dll"
483
483
  },
484
484
  {
485
- "hash": "sha256-HbKsqgHbYSJeoiQLgabISECR/bBtMWj8ojjcvR0hMEE=",
486
- "url": "_framework/MindExecution.Web.ppgm8rey59.dll"
485
+ "hash": "sha256-Na9Tbn6PRhJ3L72qs5aIn+/ahlhtzZIxWc7r8G/vAtk=",
486
+ "url": "_framework/MindExecution.Web.9bmh8f8s3k.dll"
487
487
  },
488
488
  {
489
489
  "hash": "sha256-IsZJ91/OW+fHzNqIgEc7Y072ns8z9dGritiSyvR9Wgc=",
@@ -802,7 +802,7 @@ self.assetsManifest = {
802
802
  "url": "_framework/Websocket.Client.vapounvmnl.dll"
803
803
  },
804
804
  {
805
- "hash": "sha256-QpzbegZyuJEiGjE8Xg733cjveSZK8WQRZ+AC26HqmU0=",
805
+ "hash": "sha256-WvsgoQTqkn6gicUIMbadHK3hWH9MBshwEhAMOUntDlA=",
806
806
  "url": "_framework/blazor.boot.json"
807
807
  },
808
808
  {
@@ -878,7 +878,7 @@ self.assetsManifest = {
878
878
  "url": "icon-512.png"
879
879
  },
880
880
  {
881
- "hash": "sha256-BCsNqsKxlO3eMDAKU195xlCzvYQFYDK+j38r2/AFfA0=",
881
+ "hash": "sha256-XIPqZA6H2ppZ5Zp3LOjsqPkqGof0dFQG5DGQFMF2Bpg=",
882
882
  "url": "index.html"
883
883
  },
884
884
  {
@@ -1,4 +1,4 @@
1
- /* Manifest version: /IXWXXqO */
1
+ /* Manifest version: TXjYyM9d */
2
2
  // Hosted deployments should prefer the network over stale offline caches.
3
3
  // This service worker immediately clears old Blazor offline caches and unregisters itself.
4
4