@mindexec/cli 0.2.27 → 0.2.28

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindexec/cli",
3
- "version": "0.2.27",
3
+ "version": "0.2.28",
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 = '20260613-cursor-blink-v206';
8
+ const MINDMAP_CORE_BUILD_ID = '20260613-dom-cursor-v207';
9
9
  const CanvasPhase = Object.freeze({
10
10
  Booting: 'booting',
11
11
  BoardFileLoading: 'board-file-loading',
@@ -83,7 +83,7 @@
83
83
  const PASSIVE_OVERLAY_INTERACTIVE_DENSE_VISIBLE_THRESHOLD = 40;
84
84
  const PASSIVE_OVERLAY_IDLE_DELAY_MS = 500;
85
85
  const PASSIVE_OVERLAY_PAN_IDLE_DELAY_MS = 500;
86
- const CURSOR_BLINK_INTERVAL_MS = 500;
86
+ const CURSOR_DOM_BLINK_DURATION_MS = 1000;
87
87
  const HOME_CAMERA_NORMAL_MID_Z = 8250;
88
88
  const HOME_DENSE_CLUSTER_MIN_CELL_SIZE = 1200;
89
89
  const HOME_DENSE_CLUSTER_MAX_CELL_SIZE = 3600;
@@ -235,6 +235,111 @@
235
235
  });
236
236
  }
237
237
 
238
+ let cursorDomStyleInstalled = false;
239
+
240
+ function ensureCursorDomStyle() {
241
+ if (cursorDomStyleInstalled || typeof document === 'undefined') {
242
+ return;
243
+ }
244
+
245
+ if (document.getElementById('mind-map-cursor-dom-style')) {
246
+ cursorDomStyleInstalled = true;
247
+ return;
248
+ }
249
+
250
+ const style = document.createElement('style');
251
+ style.id = 'mind-map-cursor-dom-style';
252
+ style.textContent = `
253
+ @keyframes mindMapCursorDomBlink {
254
+ 0%, 49% { opacity: 1; }
255
+ 50%, 100% { opacity: 0; }
256
+ }
257
+ .mind-map-cursor-dom {
258
+ position: absolute;
259
+ left: 0;
260
+ top: 0;
261
+ width: 20px;
262
+ height: 20px;
263
+ box-sizing: border-box;
264
+ border-top: 4px solid #000;
265
+ border-left: 4px solid #000;
266
+ pointer-events: none;
267
+ z-index: 2147483000;
268
+ animation: mindMapCursorDomBlink ${CURSOR_DOM_BLINK_DURATION_MS}ms steps(1, end) infinite;
269
+ will-change: transform;
270
+ contain: layout style paint;
271
+ }
272
+ `;
273
+ document.head?.appendChild(style);
274
+ cursorDomStyleInstalled = true;
275
+ }
276
+
277
+ function ensureCursorDomElement(module) {
278
+ if (!module?.container || typeof document === 'undefined') {
279
+ return null;
280
+ }
281
+
282
+ ensureCursorDomStyle();
283
+
284
+ if (module.cursorDomElement?.isConnected) {
285
+ return module.cursorDomElement;
286
+ }
287
+
288
+ const element = document.createElement('div');
289
+ element.className = 'mind-map-cursor-dom';
290
+ element.setAttribute('aria-hidden', 'true');
291
+ module.container.appendChild(element);
292
+ module.cursorDomElement = element;
293
+ module._lastCursorDomPositionKey = '';
294
+ return element;
295
+ }
296
+
297
+ function updateCursorDomElement(module) {
298
+ if (!module?.container || !module.camera || !module.cursorPosition) {
299
+ return false;
300
+ }
301
+
302
+ const element = ensureCursorDomElement(module);
303
+ if (!element) {
304
+ return false;
305
+ }
306
+
307
+ const width = Math.max(1, Number(module.container.clientWidth || 0));
308
+ const height = Math.max(1, Number(module.container.clientHeight || 0));
309
+ const camera = module.camera;
310
+ const cursor = module.cursorPosition;
311
+ const vfov = (camera.fov * Math.PI) / 180;
312
+ const viewHeight = 2 * Math.tan(vfov / 2) * camera.position.z;
313
+ const viewWidth = viewHeight * camera.aspect;
314
+ const ndcX = ((cursor.x - camera.position.x) * 2) / viewWidth;
315
+ const ndcY = ((cursor.y - camera.position.y) * 2) / viewHeight;
316
+ const x = ((ndcX + 1) / 2) * width;
317
+ const y = ((1 - ndcY) / 2) * height;
318
+ const visible = ndcX >= -1.1 && ndcX <= 1.1 && ndcY >= -1.1 && ndcY <= 1.1;
319
+ const positionKey = `${visible ? 1 : 0}|${Math.round(x)}|${Math.round(y)}|${width}|${height}`;
320
+
321
+ if (positionKey === module._lastCursorDomPositionKey) {
322
+ return false;
323
+ }
324
+
325
+ module._lastCursorDomPositionKey = positionKey;
326
+ element.style.display = visible ? 'block' : 'none';
327
+ if (visible) {
328
+ element.style.transform = `translate3d(${x.toFixed(2)}px, ${y.toFixed(2)}px, 0)`;
329
+ }
330
+ return true;
331
+ }
332
+
333
+ function removeCursorDomElement(module) {
334
+ if (module?.cursorDomElement) {
335
+ module.cursorDomElement.remove();
336
+ module.cursorDomElement = null;
337
+ }
338
+ if (module) {
339
+ module._lastCursorDomPositionKey = '';
340
+ }
341
+ }
342
+
238
343
  function shouldYieldWorkSlice(sliceStartedAt, processedCount, budgetMs, minItems, maxItems) {
239
344
  if (processedCount < minItems) {
240
345
  return false;
@@ -2498,8 +2603,8 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
2498
2603
  this.cursorMesh = null;
2499
2604
  this.cursorMaterial = null;
2500
2605
  this.cursorLineMaterial = null;
2501
- this._cursorBlinkVisible = true;
2502
- this._lastCursorBlinkAt = 0;
2606
+ this.cursorDomElement = null;
2607
+ this._lastCursorDomPositionKey = '';
2503
2608
  this._viewStatePersistTimer = null;
2504
2609
  this._pendingViewStateSnapshot = null;
2505
2610
  this._pendingViewStateKey = null;
@@ -3006,6 +3111,8 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
3006
3111
  this.container = target;
3007
3112
  this.dotNetHelper = helper;
3008
3113
  window.dotNetHelper = helper; // Expose globally for NativeDropHandler access
3114
+ ensureCursorDomElement(this);
3115
+ updateCursorDomElement(this);
3009
3116
  if (this.useTextOverlayV2 && window.MindMapTextOverlayV2?.init) {
3010
3117
  window.MindMapTextOverlayV2.init(this);
3011
3118
  }
@@ -3081,19 +3188,19 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
3081
3188
  const thickness = 4; // Cursor thickness
3082
3189
 
3083
3190
  // Mesh material (background / thickness)
3084
- this.cursorMaterial = new THREE.MeshBasicMaterial({
3085
- color: 0xffffff,
3086
- transparent: true,
3087
- opacity: 1.0,
3088
- depthTest: false
3089
- });
3090
-
3091
- // Line material (centerline)
3092
- this.cursorLineMaterial = new THREE.LineBasicMaterial({
3093
- color: 0xffffff,
3094
- transparent: false,
3095
- opacity: 1,
3096
- depthTest: false
3191
+ this.cursorMaterial = new THREE.MeshBasicMaterial({
3192
+ color: 0x000000,
3193
+ transparent: true,
3194
+ opacity: 1.0,
3195
+ depthTest: false
3196
+ });
3197
+
3198
+ // Line material (centerline)
3199
+ this.cursorLineMaterial = new THREE.LineBasicMaterial({
3200
+ color: 0x000000,
3201
+ transparent: false,
3202
+ opacity: 1,
3203
+ depthTest: false
3097
3204
  });
3098
3205
 
3099
3206
  // Mesh geometry (vertical/horizontal bars)
@@ -3120,9 +3227,10 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
3120
3227
  line.position.z = 0; // [Fix] Z=0 for parallax elimination
3121
3228
  line.renderOrder = 9999;
3122
3229
  this.cursorMesh.add(line);
3123
-
3124
- this.cursorMesh.position.set(0, 0, 0); // [Fix] Z=0 for parallax elimination
3125
- this.cursorMesh.renderOrder = 9999;
3230
+
3231
+ this.cursorMesh.position.set(0, 0, 0); // [Fix] Z=0 for parallax elimination
3232
+ this.cursorMesh.renderOrder = 9999;
3233
+ this.cursorMesh.visible = false;
3126
3234
  this.scene.add(this.cursorMesh);
3127
3235
 
3128
3236
  if (this.updateCursorPosition) {
@@ -3229,7 +3337,10 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
3229
3337
  }
3230
3338
 
3231
3339
  // 4. [중요] 강제 리사이즈 호출 (초기화 시점의 0x0 사이즈 보정)
3232
- setTimeout(() => {
3340
+ ensureCursorDomElement(this);
3341
+ updateCursorDomElement(this);
3342
+
3343
+ setTimeout(() => {
3233
3344
  if (this && this.onWindowResize) {
3234
3345
  console.log("[Init] Forcing resize to fix 0 height issue");
3235
3346
  this.onWindowResize();
@@ -5062,41 +5173,9 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
5062
5173
  allowAnimation: shouldAnimateImageStatusTextures
5063
5174
  });
5064
5175
 
5065
- // 5. Cursor Animation
5176
+ // 5. Cursor DOM position
5066
5177
  // ----------------------------------------------------------------
5067
- let cursorAnimatedThisFrame = false;
5068
- let cursorBlinkWakeDelayMs = Number.POSITIVE_INFINITY;
5069
- const hasCursorBlinkTarget = !!(this.cursorMesh && this.cursorMaterial);
5070
- if (hasCursorBlinkTarget) {
5071
- if (this.cursorMesh.visible !== (this._cursorBlinkVisible === true)) {
5072
- this.cursorMesh.visible = this._cursorBlinkVisible === true;
5073
- cursorAnimatedThisFrame = true;
5074
- }
5075
-
5076
- const previousBlinkAt = Number(this._lastCursorBlinkAt || 0);
5077
- if (!Number.isFinite(previousBlinkAt) || previousBlinkAt <= 0) {
5078
- this._lastCursorBlinkAt = frameStart;
5079
- this._cursorBlinkVisible = true;
5080
- if (this.cursorMesh.visible !== true) {
5081
- this.cursorMesh.visible = true;
5082
- cursorAnimatedThisFrame = true;
5083
- }
5084
- } else {
5085
- const elapsedBlinkMs = Math.max(0, frameStart - previousBlinkAt);
5086
- if (elapsedBlinkMs >= CURSOR_BLINK_INTERVAL_MS) {
5087
- const elapsedBlinkSteps = Math.max(1, Math.floor(elapsedBlinkMs / CURSOR_BLINK_INTERVAL_MS));
5088
- if ((elapsedBlinkSteps % 2) === 1) {
5089
- this._cursorBlinkVisible = this._cursorBlinkVisible !== true;
5090
- }
5091
- this._lastCursorBlinkAt = previousBlinkAt + (elapsedBlinkSteps * CURSOR_BLINK_INTERVAL_MS);
5092
- this.cursorMesh.visible = this._cursorBlinkVisible === true;
5093
- cursorAnimatedThisFrame = true;
5094
- }
5095
- }
5096
-
5097
- const nextBlinkInMs = CURSOR_BLINK_INTERVAL_MS - Math.max(0, frameStart - Number(this._lastCursorBlinkAt || frameStart));
5098
- cursorBlinkWakeDelayMs = Math.max(1, Math.min(CURSOR_BLINK_INTERVAL_MS, Math.ceil(nextBlinkInMs)));
5099
- }
5178
+ updateCursorDomElement(this);
5100
5179
 
5101
5180
  // 6. Theme Animation
5102
5181
  // ----------------------------------------------------------------
@@ -5145,21 +5224,13 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
5145
5224
  // 7. Render
5146
5225
  // ----------------------------------------------------------------
5147
5226
  _profileSection('css3dSync');
5148
- const hasContinuousThemeAnimationFrame =
5149
- allowContinuousThemeAnimationThisFrame === true &&
5150
- (
5151
- shouldForceGpuParticleAnimation === true ||
5152
- (isThemeAnimationEnabled === true && isContinuousTheme === true)
5153
- );
5154
5227
  const shouldRenderWebglFrame =
5155
5228
  isWebglRenderEnabled &&
5156
5229
  (
5157
5230
  isBoardLoading === true ||
5158
5231
  shouldUpdate === true ||
5159
5232
  isInteractiveFrame === true ||
5160
- themeAnimatedThisFrame === true ||
5161
- cursorAnimatedThisFrame === true ||
5162
- hasContinuousThemeAnimationFrame === true
5233
+ themeAnimatedThisFrame === true
5163
5234
  );
5164
5235
  if (shouldRenderWebglFrame) {
5165
5236
  this.renderer.render(this.scene, this.camera);
@@ -5488,38 +5559,17 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
5488
5559
  isInteractiveFrame !== true &&
5489
5560
  shouldUpdate !== true &&
5490
5561
  themeAnimatedThisFrame !== true &&
5491
- cursorAnimatedThisFrame !== true &&
5492
5562
  shouldRenderWebglFrame !== true &&
5493
5563
  shouldRenderCss3dFrame !== true &&
5494
5564
  shouldSyncTextOverlays !== true &&
5495
5565
  hasPendingAnimationWakeWork !== true;
5496
5566
  if (shouldParkIdleAnimationLoop) {
5497
- if (hasCursorBlinkTarget) {
5498
- nextAnimationLoopDelayMs = cursorBlinkWakeDelayMs;
5499
- this._lastAnimationLoopDelayMs = nextAnimationLoopDelayMs;
5500
- this._animationLoopExecuting = false;
5501
- this._scheduleAnimationLoop(loop, nextAnimationLoopDelayMs);
5502
- return;
5503
- }
5504
-
5505
5567
  this._lastAnimationLoopDelayMs = -1;
5506
5568
  this._animationLoopExecuting = false;
5507
5569
  return;
5508
5570
  }
5509
5571
 
5510
- const shouldDelayAfterCursorOnlyFrame =
5511
- cursorAnimatedThisFrame === true &&
5512
- shouldCaptureFramePerf !== true &&
5513
- isBoardLoading !== true &&
5514
- isInteractiveFrame !== true &&
5515
- shouldUpdate !== true &&
5516
- themeAnimatedThisFrame !== true &&
5517
- hasContinuousThemeAnimationFrame !== true &&
5518
- shouldRenderCss3dFrame !== true &&
5519
- shouldSyncTextOverlays !== true &&
5520
- hasPendingAnimationWakeWork !== true &&
5521
- hasCursorBlinkTarget === true;
5522
- nextAnimationLoopDelayMs = shouldDelayAfterCursorOnlyFrame ? cursorBlinkWakeDelayMs : 0;
5572
+ nextAnimationLoopDelayMs = 0;
5523
5573
  this._lastAnimationLoopDelayMs = nextAnimationLoopDelayMs;
5524
5574
  this._animationLoopExecuting = false;
5525
5575
  this._scheduleAnimationLoop(loop, nextAnimationLoopDelayMs);
@@ -5658,8 +5708,9 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
5658
5708
 
5659
5709
  this.cursorPosition.set(snappedX, snappedY, 0);
5660
5710
  if (this.cursorMesh) {
5661
- this.cursorMesh.position.set(snappedX, snappedY, 0); // [Fix] Z=0 for parallax elimination
5662
- }
5711
+ this.cursorMesh.position.set(snappedX, snappedY, 0); // [Fix] Z=0 for parallax elimination
5712
+ }
5713
+ updateCursorDomElement(this);
5663
5714
 
5664
5715
  if (moveCamera) {
5665
5716
  let targetCenterX = snappedX;
@@ -5788,6 +5839,7 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
5788
5839
  cleanupAndDispose() {
5789
5840
  if (!this.container) return;
5790
5841
  this.pauseAnimationLoop();
5842
+ removeCursorDomElement(this);
5791
5843
  if (this._viewStatePersistTimer) {
5792
5844
  clearTimeout(this._viewStatePersistTimer);
5793
5845
  this._viewStatePersistTimer = null;
@@ -558,7 +558,7 @@
558
558
  }
559
559
 
560
560
  const base = '_content/MindExecution.Shared/js/';
561
- const scriptVersion = '20260613-cursor-blink-remote-icon-v493';
561
+ const scriptVersion = '20260613-dom-cursor-v494';
562
562
  const scriptUrl = (script) => `${base}${script}?v=${scriptVersion}`;
563
563
  console.log(`[Script Loader] Shared JS version: ${scriptVersion}`);
564
564
  const criticalScripts = [
@@ -1,5 +1,5 @@
1
1
  self.assetsManifest = {
2
- "version": "dzmlSBJx",
2
+ "version": "m4oKu8Nx",
3
3
  "assets": [
4
4
  {
5
5
  "hash": "sha256-+CSYMcqLNTsq3VnH11jgYyOCCdxvHzL74CBmo4sCmMU=",
@@ -78,7 +78,7 @@
78
78
  "url": "_content/MindExecution.Shared/js/marked.min.js"
79
79
  },
80
80
  {
81
- "hash": "sha256-LtkB8IRvIm+FJDH5Kx4zNth2hyesdL4YqTPJylSkcHY=",
81
+ "hash": "sha256-UeeqiZXN9Iv1e/DRq1gyWRCbQUwzduNrpf5aSQido00=",
82
82
  "url": "_content/MindExecution.Shared/js/mind-map-core.js"
83
83
  },
84
84
  {
@@ -834,7 +834,7 @@
834
834
  "url": "image-manifest.json"
835
835
  },
836
836
  {
837
- "hash": "sha256-6JYaZ2X3Gg9XoAZomsa4QjcmaQDb7YpKcGVGvxLSXTg=",
837
+ "hash": "sha256-6CFY94JBwL0ucGyOLKGUhtHcboWlYd/I3J3bnSVjxjM=",
838
838
  "url": "index.html"
839
839
  },
840
840
  {
@@ -1,4 +1,4 @@
1
- /* Manifest version: dzmlSBJx */
1
+ /* Manifest version: m4oKu8Nx */
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