@mindexec/cli 0.2.307 → 0.2.309
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 +1 -1
- package/wwwroot/_content/MindExecution.Shared/css/mind-map-overrides.css +29 -6
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js +19 -3
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +339 -15
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-interactions.js +1 -1
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-renderer.js +49 -10
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-text-overlay-v2.js +48 -20
- package/wwwroot/index.html +3 -3
- package/wwwroot/service-worker-assets.js +8 -8
- package/wwwroot/service-worker.js +1 -1
package/package.json
CHANGED
|
@@ -1484,17 +1484,36 @@ html.mindcanvas-platform-apple .css3d-resolution-wrapper.is-automation-relation-
|
|
|
1484
1484
|
|
|
1485
1485
|
.mind-map-text-overlay-v2-card.is-passive {
|
|
1486
1486
|
pointer-events: none;
|
|
1487
|
-
/*
|
|
1488
|
-
|
|
1487
|
+
/* Passive overlay paints screen-space chrome for text-like nodes so the
|
|
1488
|
+
user does not see CSS3D's camera-scaled hard card edge in NEAR. */
|
|
1489
1489
|
contain: layout style;
|
|
1490
1490
|
overflow: visible;
|
|
1491
|
-
background:
|
|
1492
|
-
background-color:
|
|
1491
|
+
background: rgba(255, 255, 255, 0.985) !important;
|
|
1492
|
+
background-color: rgba(255, 255, 255, 0.985) !important;
|
|
1493
1493
|
background-image: none !important;
|
|
1494
|
+
border: 1px solid rgba(55, 65, 81, 0.28) !important;
|
|
1495
|
+
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.05) !important;
|
|
1496
|
+
border-radius: 2px !important;
|
|
1497
|
+
outline: none !important;
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
.mind-map-text-overlay-v2-card.is-passive[data-content-type="memo"],
|
|
1501
|
+
.mind-map-text-overlay-v2-card.is-passive[data-content-type="note"] {
|
|
1502
|
+
border-color: rgba(55, 65, 81, 0.18) !important;
|
|
1503
|
+
border-radius: 6px !important;
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
.mind-map-text-overlay-v2-card.is-passive[data-content-type="code"],
|
|
1507
|
+
.mind-map-text-overlay-v2-card.is-passive[data-content-type="text"],
|
|
1508
|
+
.mind-map-text-overlay-v2-card.is-passive[data-content-type="markdown"] {
|
|
1509
|
+
border-radius: 1px !important;
|
|
1494
1510
|
}
|
|
1495
1511
|
|
|
1496
1512
|
.mind-map-text-overlay-v2-card.is-passive .mind-map-text-overlay-v2-body {
|
|
1497
1513
|
pointer-events: auto;
|
|
1514
|
+
text-rendering: auto;
|
|
1515
|
+
-webkit-font-smoothing: auto;
|
|
1516
|
+
-moz-osx-font-smoothing: auto;
|
|
1498
1517
|
}
|
|
1499
1518
|
|
|
1500
1519
|
.mind-map-text-overlay-v2-shell {
|
|
@@ -3413,7 +3432,7 @@ html body .css3d-resolution-wrapper > .map-node-bubble,
|
|
|
3413
3432
|
html body .css3d-resolution-wrapper > .map-node-note,
|
|
3414
3433
|
html body .css3d-resolution-wrapper > .map-node-code,
|
|
3415
3434
|
html body .css3d-resolution-wrapper > .map-node-memo:not(.map-node-agent):not(.map-node-automation):not(.map-node-template-card):not(.map-node-remote-fleet) {
|
|
3416
|
-
border: 1px solid rgba(17, 24, 39, 0.
|
|
3435
|
+
border: 1px solid rgba(17, 24, 39, 0.22) !important;
|
|
3417
3436
|
-webkit-box-shadow: none !important;
|
|
3418
3437
|
box-shadow: none !important;
|
|
3419
3438
|
-webkit-filter: none !important;
|
|
@@ -3464,7 +3483,7 @@ html body .css3d-resolution-wrapper > .map-node-agent:not(.map-node-template-car
|
|
|
3464
3483
|
html body .css3d-resolution-wrapper > .map-node-automation:not(.map-node-template-card):not(.map-node-remote-fleet),
|
|
3465
3484
|
html body .mind-map-text-overlay-v2-shell.type-text,
|
|
3466
3485
|
html body .mind-map-text-overlay-v2-shell.type-markdown {
|
|
3467
|
-
border: 1px solid rgba(17, 24, 39, 0.
|
|
3486
|
+
border: 1px solid rgba(17, 24, 39, 0.22) !important;
|
|
3468
3487
|
-webkit-box-shadow: none !important;
|
|
3469
3488
|
box-shadow: none !important;
|
|
3470
3489
|
-webkit-filter: none !important;
|
|
@@ -3556,6 +3575,10 @@ html body .css3d-resolution-wrapper.lod-low.node-type-memo .map-node-memo__shell
|
|
|
3556
3575
|
html body .css3d-resolution-wrapper.lod-low > .map-node-agent .map-node-memo__shell,
|
|
3557
3576
|
html body .css3d-resolution-wrapper.lod-low > .map-node-automation .map-node-memo__shell {
|
|
3558
3577
|
background: transparent !important;
|
|
3578
|
+
color: transparent !important;
|
|
3579
|
+
font-size: 0 !important;
|
|
3580
|
+
line-height: 0 !important;
|
|
3581
|
+
text-shadow: none !important;
|
|
3559
3582
|
padding: 0 !important;
|
|
3560
3583
|
border: 0 !important;
|
|
3561
3584
|
overflow: hidden !important;
|
|
@@ -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 = '20260621-
|
|
8
|
+
const MINDMAP_CORE_BUILD_ID = '20260621-near-lod-pixel-snap-v790';
|
|
9
9
|
const CanvasPhase = Object.freeze({
|
|
10
10
|
Booting: 'booting',
|
|
11
11
|
BoardFileLoading: 'board-file-loading',
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
});
|
|
78
78
|
const CanvasPhaseSet = new Set(Object.values(CanvasPhase));
|
|
79
79
|
const VIEWPORT_METRICS_POLL_INTERVAL = 480;
|
|
80
|
-
const PASSIVE_DOM_OVERLAY_RUNTIME_ENABLED =
|
|
80
|
+
const PASSIVE_DOM_OVERLAY_RUNTIME_ENABLED = true;
|
|
81
81
|
const PASSIVE_OVERLAY_ZOOM_DEFER_VISIBLE_THRESHOLD = 24;
|
|
82
82
|
const PASSIVE_OVERLAY_INTERACTIVE_REFRESH_INTERVAL_MS = 48;
|
|
83
83
|
const PASSIVE_OVERLAY_INTERACTIVE_DENSE_REFRESH_INTERVAL_MS = 72;
|
|
@@ -9023,6 +9023,16 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
|
|
|
9023
9023
|
const overlayV2State = useTextOverlayV2 && shouldTrackTextOverlayDirty
|
|
9024
9024
|
? (this._textOverlayV2State || null)
|
|
9025
9025
|
: null;
|
|
9026
|
+
let hasVisibleOverlayV2Card = false;
|
|
9027
|
+
if (overlayV2State?.cards?.forEach) {
|
|
9028
|
+
overlayV2State.cards.forEach(card => {
|
|
9029
|
+
if (hasVisibleOverlayV2Card || !card || card.style.display === 'none') {
|
|
9030
|
+
return;
|
|
9031
|
+
}
|
|
9032
|
+
|
|
9033
|
+
hasVisibleOverlayV2Card = true;
|
|
9034
|
+
});
|
|
9035
|
+
}
|
|
9026
9036
|
const hasOverlayV2DirtyState = !!(
|
|
9027
9037
|
overlayV2State && (
|
|
9028
9038
|
overlayV2State.dirtyLayout === true ||
|
|
@@ -9033,6 +9043,12 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
|
|
|
9033
9043
|
);
|
|
9034
9044
|
const hasOverlayFocus = hasFocusedTextOverlay || hasEditingOverlay;
|
|
9035
9045
|
const hasMotionBlockingOverlayFocus = hasEditingOverlay;
|
|
9046
|
+
const shouldCleanupInactivePassiveOverlay =
|
|
9047
|
+
useTextOverlayV2 &&
|
|
9048
|
+
hasVisibleOverlayV2Card === true &&
|
|
9049
|
+
shouldRenderPassiveDomTextOverlay !== true &&
|
|
9050
|
+
hasLiveInteractiveDomOverlay !== true &&
|
|
9051
|
+
!hasOverlayFocus;
|
|
9036
9052
|
const visibleOverlayCount = isPassiveDomOverlayRuntimeEnabled
|
|
9037
9053
|
? Math.max(
|
|
9038
9054
|
Number(this._visibleIds?.size || 0),
|
|
@@ -9563,7 +9579,7 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
|
|
|
9563
9579
|
const shouldSyncTextOverlays =
|
|
9564
9580
|
effectiveOverlayDirty === true ||
|
|
9565
9581
|
(useTextOverlayV2
|
|
9566
|
-
? (hasOverlayV2DirtyState || shouldRefreshPassiveDomTextOverlay || shouldFinalizePassiveOverlayLayout || (hasMotionBlockingOverlayFocus && shouldUpdateCss3d))
|
|
9582
|
+
? (hasOverlayV2DirtyState || shouldCleanupInactivePassiveOverlay || shouldRefreshPassiveDomTextOverlay || shouldFinalizePassiveOverlayLayout || (hasMotionBlockingOverlayFocus && shouldUpdateCss3d))
|
|
9567
9583
|
: (hasMotionBlockingOverlayFocus && shouldUpdateCss3d));
|
|
9568
9584
|
const shouldAttemptPassiveOverlayCameraFastPath =
|
|
9569
9585
|
useTextOverlayV2 &&
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
const CSS_IMAGE_PROMOTION_MAX_PER_FRAME = 4;
|
|
15
15
|
const CSS_IMAGE_PROMOTION_BUDGET_MS = 4;
|
|
16
16
|
const CSS_IMAGE_BLOB_CACHE_LIMIT = 160;
|
|
17
|
+
const CSS_VIDEO_BLOB_CACHE_LIMIT = 48;
|
|
17
18
|
const CSS_IMAGE_DISPLAY_MAX_CONCURRENCY = 8;
|
|
18
19
|
const CSS3D_TEXT_NODE_RESOLUTION_SCALE = 1.0;
|
|
19
20
|
const CSS3D_MEDIA_NODE_RESOLUTION_SCALE = 1.0;
|
|
@@ -26,6 +27,8 @@
|
|
|
26
27
|
let _cssImagePromotionTimer = 0;
|
|
27
28
|
let _cssImageBlobUrlCache = new Map();
|
|
28
29
|
let _cssImageBlobUrlPending = new Map();
|
|
30
|
+
let _cssVideoBlobUrlCache = new Map();
|
|
31
|
+
let _cssVideoBlobUrlPending = new Map();
|
|
29
32
|
let _cssImageDisplayQueue = [];
|
|
30
33
|
let _cssImageDisplayActiveCount = 0;
|
|
31
34
|
let _cssImageDisplayPumpScheduled = false;
|
|
@@ -1314,6 +1317,13 @@
|
|
|
1314
1317
|
return !normalized || normalized.startsWith('image/');
|
|
1315
1318
|
}
|
|
1316
1319
|
|
|
1320
|
+
function isCssVideoContentType(value) {
|
|
1321
|
+
const normalized = String(value || '').split(';')[0].trim().toLowerCase();
|
|
1322
|
+
return !normalized
|
|
1323
|
+
|| normalized.startsWith('video/')
|
|
1324
|
+
|| normalized === 'application/octet-stream';
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1317
1327
|
function isDirectCssMediaUrl(url) {
|
|
1318
1328
|
const normalized = normalizeCssMediaUrl(url).toLowerCase();
|
|
1319
1329
|
return normalized.startsWith('http://')
|
|
@@ -1677,6 +1687,129 @@
|
|
|
1677
1687
|
);
|
|
1678
1688
|
}
|
|
1679
1689
|
|
|
1690
|
+
function getCss3dVideoElement(cssObject) {
|
|
1691
|
+
const element = cssObject?.element || null;
|
|
1692
|
+
if (element?.tagName === 'VIDEO') {
|
|
1693
|
+
return element;
|
|
1694
|
+
}
|
|
1695
|
+
return element?.querySelector?.('video') || null;
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
function isCss3dVideoElementLowDetail(videoEl, cssObject = null) {
|
|
1699
|
+
const element = cssObject?.element || null;
|
|
1700
|
+
const root = element?.classList?.contains?.('css3d-resolution-wrapper') === true
|
|
1701
|
+
? element
|
|
1702
|
+
: videoEl?.closest?.('.css3d-resolution-wrapper') || element?.closest?.('.css3d-resolution-wrapper') || null;
|
|
1703
|
+
const isVideoWrapper = root?.classList?.contains?.('node-type-video') === true ||
|
|
1704
|
+
videoEl?.tagName === 'VIDEO';
|
|
1705
|
+
return isVideoWrapper === true &&
|
|
1706
|
+
root?.classList?.contains?.('lod-high') !== true;
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1709
|
+
function getCss3dVideoDeferredSource(videoEl, nodeModel) {
|
|
1710
|
+
return normalizeCssMediaUrl(
|
|
1711
|
+
videoEl?.dataset?.lodSuspendedSrc
|
|
1712
|
+
|| videoEl?.dataset?.resolvedMediaSourceUrl
|
|
1713
|
+
|| videoEl?.dataset?.mediaSourceUrl
|
|
1714
|
+
|| videoEl?.currentSrc
|
|
1715
|
+
|| videoEl?.getAttribute?.('src')
|
|
1716
|
+
|| nodeModel?.response
|
|
1717
|
+
|| nodeModel?.Response
|
|
1718
|
+
|| ''
|
|
1719
|
+
);
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
function rememberCss3dVideoSourceForLod(videoEl, nodeModel) {
|
|
1723
|
+
if (!videoEl?.dataset) {
|
|
1724
|
+
return '';
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
const source = getCss3dVideoDeferredSource(videoEl, nodeModel);
|
|
1728
|
+
if (source) {
|
|
1729
|
+
videoEl.dataset.lodSuspendedSrc = source;
|
|
1730
|
+
}
|
|
1731
|
+
return source;
|
|
1732
|
+
}
|
|
1733
|
+
|
|
1734
|
+
function suspendCss3dVideoSourceForLod(nodeModel, cssObject) {
|
|
1735
|
+
const contentTypeLower = String(nodeModel?.contentType ?? nodeModel?.ContentType ?? '').toLowerCase();
|
|
1736
|
+
if (contentTypeLower !== 'video') {
|
|
1737
|
+
return false;
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
const videoEl = getCss3dVideoElement(cssObject);
|
|
1741
|
+
if (!videoEl) {
|
|
1742
|
+
return false;
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
rememberVideoNodeRuntimePlayback(nodeModel, videoEl);
|
|
1746
|
+
rememberCss3dVideoSourceForLod(videoEl, nodeModel);
|
|
1747
|
+
if (videoEl.dataset) {
|
|
1748
|
+
if (!videoEl.dataset.lodSuspendedPreload) {
|
|
1749
|
+
videoEl.dataset.lodSuspendedPreload = videoEl.getAttribute('preload') || videoEl.preload || 'metadata';
|
|
1750
|
+
}
|
|
1751
|
+
videoEl.dataset.lodMediaSuspended = 'true';
|
|
1752
|
+
videoEl.dataset.videoResumePending = 'false';
|
|
1753
|
+
videoEl.dataset.visibilityPaused = 'false';
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
if (!videoEl.paused) {
|
|
1757
|
+
videoEl.pause?.();
|
|
1758
|
+
}
|
|
1759
|
+
stopCss3dVideoCanvasProxyForVisibility(videoEl);
|
|
1760
|
+
|
|
1761
|
+
const hadSource = !!videoEl.getAttribute('src');
|
|
1762
|
+
videoEl.removeAttribute('src');
|
|
1763
|
+
videoEl.preload = 'none';
|
|
1764
|
+
if (hadSource && typeof videoEl.load === 'function') {
|
|
1765
|
+
try {
|
|
1766
|
+
videoEl.load();
|
|
1767
|
+
} catch { }
|
|
1768
|
+
}
|
|
1769
|
+
|
|
1770
|
+
return true;
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1773
|
+
function resumeCss3dVideoSourceForLod(nodeModel, cssObject, options = {}) {
|
|
1774
|
+
const contentTypeLower = String(nodeModel?.contentType ?? nodeModel?.ContentType ?? '').toLowerCase();
|
|
1775
|
+
if (contentTypeLower !== 'video') {
|
|
1776
|
+
return false;
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
const videoEl = getCss3dVideoElement(cssObject);
|
|
1780
|
+
if (!videoEl) {
|
|
1781
|
+
return false;
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
const preferredSource = getCss3dVideoDeferredSource(videoEl, nodeModel);
|
|
1785
|
+
if (videoEl.dataset) {
|
|
1786
|
+
videoEl.dataset.lodMediaSuspended = 'false';
|
|
1787
|
+
}
|
|
1788
|
+
videoEl.preload = videoEl.dataset?.lodSuspendedPreload || 'metadata';
|
|
1789
|
+
|
|
1790
|
+
if (!preferredSource) {
|
|
1791
|
+
return false;
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
if (isLocalCssMediaReference(preferredSource) || getLocalCssMediaId(nodeModel, preferredSource)) {
|
|
1795
|
+
videoEl.dataset.mediaSourceUrl = getLocalCssMediaReference(nodeModel, preferredSource);
|
|
1796
|
+
videoEl.dataset.resolvedMediaSourceUrl = '';
|
|
1797
|
+
if (options.resolveLocal !== false) {
|
|
1798
|
+
void resolveLocalCssMediaSource(videoEl, nodeModel, contentTypeLower);
|
|
1799
|
+
}
|
|
1800
|
+
return true;
|
|
1801
|
+
}
|
|
1802
|
+
|
|
1803
|
+
void setCssVideoElementSource(videoEl, nodeModel, preferredSource, { load: true });
|
|
1804
|
+
return true;
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
function syncCss3dVideoLodMediaSource(nodeModel, cssObject, isHigh) {
|
|
1808
|
+
return isHigh === true
|
|
1809
|
+
? resumeCss3dVideoSourceForLod(nodeModel, cssObject)
|
|
1810
|
+
: suspendCss3dVideoSourceForLod(nodeModel, cssObject);
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1680
1813
|
function isLocalCssMediaReference(url) {
|
|
1681
1814
|
const text = String(url || '').trim();
|
|
1682
1815
|
if (!text) {
|
|
@@ -1770,6 +1903,14 @@
|
|
|
1770
1903
|
delete metadata.localFileResolveError;
|
|
1771
1904
|
|
|
1772
1905
|
mediaEl.dataset.resolvedMediaSourceUrl = objectUrl;
|
|
1906
|
+
if (isCss3dVideoElementLowDetail(mediaEl, { element: mediaEl })) {
|
|
1907
|
+
mediaEl.dataset.lodSuspendedSrc = objectUrl;
|
|
1908
|
+
suspendCss3dVideoSourceForLod(nodeModel, { element: mediaEl });
|
|
1909
|
+
setAssetRefreshState(nodeModel, '', '');
|
|
1910
|
+
syncMediaLoadingRowForElement(mediaEl, nodeModel, contentTypeLower);
|
|
1911
|
+
return true;
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1773
1914
|
if (mediaEl.getAttribute('src') !== objectUrl) {
|
|
1774
1915
|
delete mediaEl.dataset.videoCanvasProxyFailed;
|
|
1775
1916
|
mediaEl.src = objectUrl;
|
|
@@ -2761,11 +2902,17 @@
|
|
|
2761
2902
|
return false;
|
|
2762
2903
|
}
|
|
2763
2904
|
|
|
2764
|
-
const videoEl = cssObject
|
|
2905
|
+
const videoEl = getCss3dVideoElement(cssObject);
|
|
2765
2906
|
const state = getCss3dVideoProxyState(videoEl);
|
|
2766
2907
|
if (!videoEl || !state) {
|
|
2767
2908
|
return false;
|
|
2768
2909
|
}
|
|
2910
|
+
if (videoEl.dataset?.lodMediaSuspended === 'true') {
|
|
2911
|
+
state.active = false;
|
|
2912
|
+
applyCss3dVideoProxySurfaceMode(state, false);
|
|
2913
|
+
cancelCss3dVideoCanvasProxyLoop(state);
|
|
2914
|
+
return false;
|
|
2915
|
+
}
|
|
2769
2916
|
|
|
2770
2917
|
bindCss3dVideoCanvasProxyLifecycle(videoEl, nodeModel, cssObject);
|
|
2771
2918
|
|
|
@@ -3068,7 +3215,7 @@
|
|
|
3068
3215
|
return false;
|
|
3069
3216
|
}
|
|
3070
3217
|
|
|
3071
|
-
const videoEl = cssObject
|
|
3218
|
+
const videoEl = getCss3dVideoElement(cssObject);
|
|
3072
3219
|
if (!videoEl) {
|
|
3073
3220
|
return false;
|
|
3074
3221
|
}
|
|
@@ -3093,6 +3240,13 @@
|
|
|
3093
3240
|
return false;
|
|
3094
3241
|
}
|
|
3095
3242
|
|
|
3243
|
+
if (isCss3dVideoElementLowDetail(videoEl, cssObject)) {
|
|
3244
|
+
suspendCss3dVideoSourceForLod(nodeModel, cssObject);
|
|
3245
|
+
return false;
|
|
3246
|
+
}
|
|
3247
|
+
|
|
3248
|
+
resumeCss3dVideoSourceForLod(nodeModel, cssObject);
|
|
3249
|
+
|
|
3096
3250
|
if (intent !== 'play' || videoEl.dataset?.userPaused === 'true') {
|
|
3097
3251
|
if (videoEl.dataset) {
|
|
3098
3252
|
videoEl.dataset.visibilityPaused = 'false';
|
|
@@ -3353,6 +3507,30 @@
|
|
|
3353
3507
|
}
|
|
3354
3508
|
}
|
|
3355
3509
|
|
|
3510
|
+
function touchCssVideoBlobCacheEntry(sourceUrl, entry) {
|
|
3511
|
+
if (!sourceUrl || !entry) return;
|
|
3512
|
+
entry.lastAccessAt = getCssImagePromotionNow();
|
|
3513
|
+
if (_cssVideoBlobUrlCache.get(sourceUrl) === entry) {
|
|
3514
|
+
_cssVideoBlobUrlCache.delete(sourceUrl);
|
|
3515
|
+
}
|
|
3516
|
+
_cssVideoBlobUrlCache.set(sourceUrl, entry);
|
|
3517
|
+
}
|
|
3518
|
+
|
|
3519
|
+
function evictCssVideoBlobCache() {
|
|
3520
|
+
while (_cssVideoBlobUrlCache.size > CSS_VIDEO_BLOB_CACHE_LIMIT) {
|
|
3521
|
+
const oldestKey = _cssVideoBlobUrlCache.keys().next().value;
|
|
3522
|
+
if (!oldestKey) {
|
|
3523
|
+
break;
|
|
3524
|
+
}
|
|
3525
|
+
|
|
3526
|
+
const entry = _cssVideoBlobUrlCache.get(oldestKey);
|
|
3527
|
+
_cssVideoBlobUrlCache.delete(oldestKey);
|
|
3528
|
+
if (entry?.objectUrl) {
|
|
3529
|
+
try { URL.revokeObjectURL(entry.objectUrl); } catch { }
|
|
3530
|
+
}
|
|
3531
|
+
}
|
|
3532
|
+
}
|
|
3533
|
+
|
|
3356
3534
|
function getCssMediaFetchOptions(targetUrl) {
|
|
3357
3535
|
const normalized = String(targetUrl || '').trim().toLowerCase();
|
|
3358
3536
|
if (!normalized || normalized.startsWith('blob:') || normalized.startsWith('data:') || normalized.startsWith('file:')) {
|
|
@@ -3434,6 +3612,63 @@
|
|
|
3434
3612
|
}
|
|
3435
3613
|
}
|
|
3436
3614
|
|
|
3615
|
+
async function resolveCssVideoDisplaySource(targetUrl) {
|
|
3616
|
+
const normalized = normalizeCssMediaUrl(targetUrl);
|
|
3617
|
+
if (!normalized) {
|
|
3618
|
+
return '';
|
|
3619
|
+
}
|
|
3620
|
+
|
|
3621
|
+
if (!isLoopbackCssAssetUrl(normalized)) {
|
|
3622
|
+
return normalized;
|
|
3623
|
+
}
|
|
3624
|
+
|
|
3625
|
+
const cached = _cssVideoBlobUrlCache.get(normalized);
|
|
3626
|
+
if (cached?.objectUrl) {
|
|
3627
|
+
touchCssVideoBlobCacheEntry(normalized, cached);
|
|
3628
|
+
return cached.objectUrl;
|
|
3629
|
+
}
|
|
3630
|
+
|
|
3631
|
+
const existingPending = _cssVideoBlobUrlPending.get(normalized);
|
|
3632
|
+
if (existingPending) {
|
|
3633
|
+
return await existingPending;
|
|
3634
|
+
}
|
|
3635
|
+
|
|
3636
|
+
const pendingFetch = (async () => {
|
|
3637
|
+
const response = await fetch(normalized, getCssMediaFetchOptions(normalized));
|
|
3638
|
+
if (!response.ok) {
|
|
3639
|
+
throw new Error(`HTTP ${response.status}`);
|
|
3640
|
+
}
|
|
3641
|
+
|
|
3642
|
+
const contentType = response.headers?.get?.('content-type') || '';
|
|
3643
|
+
if (!isCssVideoContentType(contentType)) {
|
|
3644
|
+
throw new Error(`Unexpected video content-type: ${contentType || 'unknown'}`);
|
|
3645
|
+
}
|
|
3646
|
+
|
|
3647
|
+
const blob = await response.blob();
|
|
3648
|
+
if (!isCssVideoContentType(blob?.type || contentType)) {
|
|
3649
|
+
throw new Error(`Unexpected video blob type: ${blob?.type || contentType || 'unknown'}`);
|
|
3650
|
+
}
|
|
3651
|
+
|
|
3652
|
+
const objectUrl = URL.createObjectURL(blob);
|
|
3653
|
+
const entry = {
|
|
3654
|
+
objectUrl,
|
|
3655
|
+
lastAccessAt: getCssImagePromotionNow()
|
|
3656
|
+
};
|
|
3657
|
+
_cssVideoBlobUrlCache.set(normalized, entry);
|
|
3658
|
+
evictCssVideoBlobCache();
|
|
3659
|
+
return objectUrl;
|
|
3660
|
+
})();
|
|
3661
|
+
|
|
3662
|
+
_cssVideoBlobUrlPending.set(normalized, pendingFetch);
|
|
3663
|
+
try {
|
|
3664
|
+
return await pendingFetch;
|
|
3665
|
+
} finally {
|
|
3666
|
+
if (_cssVideoBlobUrlPending.get(normalized) === pendingFetch) {
|
|
3667
|
+
_cssVideoBlobUrlPending.delete(normalized);
|
|
3668
|
+
}
|
|
3669
|
+
}
|
|
3670
|
+
}
|
|
3671
|
+
|
|
3437
3672
|
function scheduleCssImageDisplayQueuePump() {
|
|
3438
3673
|
if (_cssImageDisplayPumpScheduled) {
|
|
3439
3674
|
return;
|
|
@@ -3545,6 +3780,60 @@
|
|
|
3545
3780
|
});
|
|
3546
3781
|
}
|
|
3547
3782
|
|
|
3783
|
+
async function setCssVideoElementSource(mediaEl, nodeModel, targetUrl, options = {}) {
|
|
3784
|
+
if (!mediaEl) return false;
|
|
3785
|
+
|
|
3786
|
+
const normalized = normalizeCssMediaUrl(targetUrl);
|
|
3787
|
+
if (!normalized) {
|
|
3788
|
+
mediaEl.dataset.mediaSourceUrl = '';
|
|
3789
|
+
mediaEl.dataset.resolvedMediaSourceUrl = '';
|
|
3790
|
+
mediaEl.removeAttribute('src');
|
|
3791
|
+
if (options.load !== false && typeof mediaEl.load === 'function') {
|
|
3792
|
+
try { mediaEl.load(); } catch { }
|
|
3793
|
+
}
|
|
3794
|
+
return false;
|
|
3795
|
+
}
|
|
3796
|
+
|
|
3797
|
+
const previousCanonical = String(mediaEl.dataset.mediaSourceUrl || '').trim();
|
|
3798
|
+
mediaEl.dataset.mediaSourceUrl = normalized;
|
|
3799
|
+
if (previousCanonical !== normalized) {
|
|
3800
|
+
mediaEl.dataset.assetRefreshAttempted = '';
|
|
3801
|
+
}
|
|
3802
|
+
|
|
3803
|
+
try {
|
|
3804
|
+
const resolvedDisplaySource = await resolveCssVideoDisplaySource(normalized);
|
|
3805
|
+
if (String(mediaEl.dataset.mediaSourceUrl || '').trim() !== normalized) {
|
|
3806
|
+
return false;
|
|
3807
|
+
}
|
|
3808
|
+
|
|
3809
|
+
const currentDisplaySource = String(mediaEl.getAttribute('src') || '').trim();
|
|
3810
|
+
if (currentDisplaySource !== resolvedDisplaySource) {
|
|
3811
|
+
delete mediaEl.dataset.videoCanvasProxyFailed;
|
|
3812
|
+
mediaEl.setAttribute('src', resolvedDisplaySource);
|
|
3813
|
+
if (options.load !== false && typeof mediaEl.load === 'function') {
|
|
3814
|
+
try { mediaEl.load(); } catch { }
|
|
3815
|
+
}
|
|
3816
|
+
}
|
|
3817
|
+
|
|
3818
|
+
mediaEl.dataset.resolvedMediaSourceUrl = resolvedDisplaySource;
|
|
3819
|
+
return true;
|
|
3820
|
+
} catch (error) {
|
|
3821
|
+
if (String(mediaEl.dataset.mediaSourceUrl || '').trim() !== normalized) {
|
|
3822
|
+
return false;
|
|
3823
|
+
}
|
|
3824
|
+
|
|
3825
|
+
mediaEl.dataset.resolvedMediaSourceUrl = '';
|
|
3826
|
+
mediaEl.removeAttribute('src');
|
|
3827
|
+
if (options.load !== false && typeof mediaEl.load === 'function') {
|
|
3828
|
+
try { mediaEl.load(); } catch { }
|
|
3829
|
+
}
|
|
3830
|
+
setAssetRefreshState(nodeModel, 'failed', 'Video asset is missing or unavailable');
|
|
3831
|
+
syncMediaLoadingRowForElement(mediaEl, nodeModel, 'video');
|
|
3832
|
+
warn('[MindMapCss3DManager] Failed to prepare video source', normalized, error);
|
|
3833
|
+
return false;
|
|
3834
|
+
}
|
|
3835
|
+
}
|
|
3836
|
+
|
|
3548
3837
|
function maybeResolveOriginalCssImageSource(mediaEl, nodeModel, contentTypeLower, options = {}) {
|
|
3549
3838
|
if (!mediaEl || contentTypeLower !== 'image') return;
|
|
3550
3839
|
if (options.bypassPreviewHold !== true && shouldPreferCssImagePreviewSource(nodeModel)) return;
|
|
@@ -3607,6 +3896,14 @@
|
|
|
3607
3896
|
|
|
3608
3897
|
if (contentTypeLower === 'video'
|
|
3609
3898
|
&& (isLocalCssMediaReference(currentSource) || getLocalCssMediaId(nodeModel, currentSource))) {
|
|
3899
|
+
if (isCss3dVideoElementLowDetail(mediaEl, { element: mediaEl })) {
|
|
3900
|
+
mediaEl.dataset.mediaSourceUrl = getLocalCssMediaReference(nodeModel, currentSource);
|
|
3901
|
+
mediaEl.dataset.resolvedMediaSourceUrl = '';
|
|
3902
|
+
mediaEl.dataset.lodSuspendedSrc = currentSource;
|
|
3903
|
+
suspendCss3dVideoSourceForLod(nodeModel, { element: mediaEl });
|
|
3904
|
+
return;
|
|
3905
|
+
}
|
|
3906
|
+
|
|
3610
3907
|
if (mediaEl.dataset.localFileResolveAttempted === '1') {
|
|
3611
3908
|
return;
|
|
3612
3909
|
}
|
|
@@ -3666,12 +3963,16 @@
|
|
|
3666
3963
|
|
|
3667
3964
|
nodeModel.response = normalized;
|
|
3668
3965
|
nodeModel.Response = normalized;
|
|
3669
|
-
mediaEl
|
|
3670
|
-
|
|
3671
|
-
|
|
3966
|
+
if (contentTypeLower === 'video' && isCss3dVideoElementLowDetail(mediaEl, { element: mediaEl })) {
|
|
3967
|
+
mediaEl.dataset.mediaSourceUrl = normalized;
|
|
3968
|
+
mediaEl.dataset.resolvedMediaSourceUrl = '';
|
|
3969
|
+
mediaEl.dataset.lodSuspendedSrc = normalized;
|
|
3970
|
+
suspendCss3dVideoSourceForLod(nodeModel, { element: mediaEl });
|
|
3971
|
+
return;
|
|
3972
|
+
}
|
|
3672
3973
|
|
|
3673
|
-
if (contentTypeLower === 'video'
|
|
3674
|
-
mediaEl
|
|
3974
|
+
if (contentTypeLower === 'video') {
|
|
3975
|
+
await setCssVideoElementSource(mediaEl, nodeModel, normalized, { load: true });
|
|
3675
3976
|
}
|
|
3676
3977
|
} catch (error) {
|
|
3677
3978
|
setAssetRefreshState(nodeModel, 'failed', 'Fresh link request did not succeed');
|
|
@@ -3831,6 +4132,9 @@
|
|
|
3831
4132
|
syncMediaLoadingRowForElement(mediaEl, nodeModel, contentTypeLower);
|
|
3832
4133
|
mediaEl.dataset.assetRefreshAttempted = '';
|
|
3833
4134
|
if (contentTypeLower === 'video') {
|
|
4135
|
+
if (mediaEl.dataset?.lodMediaSuspended === 'true') {
|
|
4136
|
+
return;
|
|
4137
|
+
}
|
|
3834
4138
|
const playPromise = mediaEl.play?.();
|
|
3835
4139
|
if (playPromise?.catch) {
|
|
3836
4140
|
playPromise.catch(() => { });
|
|
@@ -3863,6 +4167,9 @@
|
|
|
3863
4167
|
if (contentTypeLower !== 'video') {
|
|
3864
4168
|
return;
|
|
3865
4169
|
}
|
|
4170
|
+
if (mediaEl.dataset?.lodMediaSuspended === 'true') {
|
|
4171
|
+
return;
|
|
4172
|
+
}
|
|
3866
4173
|
|
|
3867
4174
|
const metadata = ensureCssMediaMetadata(nodeModel);
|
|
3868
4175
|
const message = describeVideoElementError();
|
|
@@ -3876,6 +4183,9 @@
|
|
|
3876
4183
|
};
|
|
3877
4184
|
|
|
3878
4185
|
const handleMediaError = async () => {
|
|
4186
|
+
if (contentTypeLower === 'video' && mediaEl.dataset?.lodMediaSuspended === 'true') {
|
|
4187
|
+
return;
|
|
4188
|
+
}
|
|
3879
4189
|
if (contentTypeLower === 'image') {
|
|
3880
4190
|
mediaEl.dataset.mediaReady = '0';
|
|
3881
4191
|
mediaEl.style.opacity = '0';
|
|
@@ -3897,6 +4207,9 @@
|
|
|
3897
4207
|
|
|
3898
4208
|
if (contentTypeLower === 'video') {
|
|
3899
4209
|
mediaEl.onstalled = () => {
|
|
4210
|
+
if (mediaEl.dataset?.lodMediaSuspended === 'true') {
|
|
4211
|
+
return;
|
|
4212
|
+
}
|
|
3900
4213
|
void tryRefreshCssMediaSource(mediaEl, nodeModel, contentTypeLower);
|
|
3901
4214
|
};
|
|
3902
4215
|
mediaEl.onloadedmetadata = handleReady;
|
|
@@ -22698,17 +23011,14 @@
|
|
|
22698
23011
|
video.dataset.resolvedMediaSourceUrl = '';
|
|
22699
23012
|
video.dataset.assetRefreshAttempted = '';
|
|
22700
23013
|
video.dataset.localFileResolveAttempted = '';
|
|
22701
|
-
|
|
22702
|
-
|
|
22703
|
-
} else {
|
|
22704
|
-
video.src = normalizedContent;
|
|
22705
|
-
}
|
|
23014
|
+
video.dataset.lodSuspendedSrc = normalizedContent;
|
|
23015
|
+
video.dataset.lodMediaSuspended = 'true';
|
|
22706
23016
|
}
|
|
22707
23017
|
video.muted = true;
|
|
22708
23018
|
video.loop = true;
|
|
22709
23019
|
video.autoplay = false;
|
|
22710
23020
|
video.playsInline = true;
|
|
22711
|
-
video.preload = '
|
|
23021
|
+
video.preload = 'none';
|
|
22712
23022
|
video.autoplay = ensureVideoNodePlaybackState(nodeModel, video) === 'play';
|
|
22713
23023
|
video.style.cssText = `position: absolute; left: 0; top: 0; width: calc(100% + var(--mind-media-surface-bleed, 0px)); height: calc(100% + var(--mind-media-surface-bleed, 0px)); min-width: calc(100% + var(--mind-media-surface-bleed, 0px)); min-height: calc(100% + var(--mind-media-surface-bleed, 0px)); max-width: none; max-height: none; object-fit: cover; object-position: center center; pointer-events: none; display: block; background: transparent; border: 0; outline: 0;`;
|
|
22714
23024
|
video.ondragstart = (e) => e.preventDefault();
|
|
@@ -23405,6 +23715,12 @@
|
|
|
23405
23715
|
mediaEl.dataset.assetRefreshAttempted = '';
|
|
23406
23716
|
if (contentTypeLower === 'image') {
|
|
23407
23717
|
void setCssImageElementSource(mediaEl, nodeModel, content);
|
|
23718
|
+
} else if (contentTypeLower === 'video' && isCss3dVideoElementLowDetail(mediaEl, cssObject)) {
|
|
23719
|
+
const normalizedContent = normalizeCssMediaUrl(content);
|
|
23720
|
+
mediaEl.dataset.mediaSourceUrl = normalizedContent;
|
|
23721
|
+
mediaEl.dataset.resolvedMediaSourceUrl = mediaEl.dataset.resolvedMediaSourceUrl || '';
|
|
23722
|
+
mediaEl.dataset.lodSuspendedSrc = normalizedContent;
|
|
23723
|
+
syncCss3dVideoLodMediaSource(nodeModel, cssObject, false);
|
|
23408
23724
|
} else if (isLocalCssMediaReference(content) || getLocalCssMediaId(nodeModel, content)) {
|
|
23409
23725
|
mediaEl.dataset.mediaSourceUrl = getLocalCssMediaReference(nodeModel, content);
|
|
23410
23726
|
mediaEl.dataset.resolvedMediaSourceUrl = '';
|
|
@@ -23414,7 +23730,9 @@
|
|
|
23414
23730
|
delete mediaEl.dataset.videoCanvasProxyFailed;
|
|
23415
23731
|
mediaEl.src = content;
|
|
23416
23732
|
}
|
|
23417
|
-
if (contentTypeLower === 'video' &&
|
|
23733
|
+
if (contentTypeLower === 'video' &&
|
|
23734
|
+
mediaEl.dataset?.lodMediaSuspended !== 'true' &&
|
|
23735
|
+
typeof mediaEl.load === 'function') {
|
|
23418
23736
|
mediaEl.load();
|
|
23419
23737
|
}
|
|
23420
23738
|
}
|
|
@@ -23428,7 +23746,12 @@
|
|
|
23428
23746
|
}
|
|
23429
23747
|
}
|
|
23430
23748
|
if (contentTypeLower === 'video') {
|
|
23431
|
-
|
|
23749
|
+
if (isCss3dVideoElementLowDetail(mediaEl, cssObject)) {
|
|
23750
|
+
syncCss3dVideoLodMediaSource(nodeModel, cssObject, false);
|
|
23751
|
+
} else {
|
|
23752
|
+
syncCss3dVideoLodMediaSource(nodeModel, cssObject, true);
|
|
23753
|
+
syncCss3dVideoCanvasProxy(nodeModel, cssObject);
|
|
23754
|
+
}
|
|
23432
23755
|
}
|
|
23433
23756
|
const loadingEl = el.querySelector(`[id^="node-loading-"]`);
|
|
23434
23757
|
if (loadingEl) {
|
|
@@ -23893,6 +24216,7 @@
|
|
|
23893
24216
|
hasMountedEmbedIframe: hasMountedEmbedIframe,
|
|
23894
24217
|
shouldConsumeEmbedPointerEvent: shouldConsumeEmbedPointerEvent,
|
|
23895
24218
|
syncCss3dContent: syncCss3dContent,
|
|
24219
|
+
syncCss3dVideoLodMediaSource: syncCss3dVideoLodMediaSource,
|
|
23896
24220
|
syncCss3dScrollFromElement: syncCss3dScrollFromElement,
|
|
23897
24221
|
syncCss3dScrollFromModel: syncCss3dScrollFromModel,
|
|
23898
24222
|
syncCss3dMediaNodeFrame: syncCss3dMediaNodeFrame,
|
|
@@ -7405,7 +7405,7 @@ window.MindMapInteractions = (function () {
|
|
|
7405
7405
|
caret-color: #1f2937;
|
|
7406
7406
|
box-sizing: border-box; /* User Request */
|
|
7407
7407
|
overflow-y: auto; /* User Request */
|
|
7408
|
-
-webkit-font-smoothing:
|
|
7408
|
+
-webkit-font-smoothing: auto;
|
|
7409
7409
|
text-rendering: auto;
|
|
7410
7410
|
white-space: pre-wrap;
|
|
7411
7411
|
overflow-wrap: break-word;
|
|
@@ -13,13 +13,13 @@
|
|
|
13
13
|
// LOD thresholds (explicit bands)
|
|
14
14
|
const LOD_THRESHOLDS = {
|
|
15
15
|
NEAR: 4500, // ~4500: DOM overlay + CSS3D
|
|
16
|
-
NORMAL:
|
|
17
|
-
MID:
|
|
16
|
+
NORMAL: 4500, // Legacy alias; NORMAL no longer keeps a scaled CSS3D band.
|
|
17
|
+
MID: 4500, // 4500~30000: resident instanced nodes + line silhouettes
|
|
18
18
|
FAR: 30000 // 30000~: nodes only (lines hidden)
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
// Backward-compatible pivot (used by legacy LOD switch)
|
|
22
|
-
const LOD_THRESHOLD_FAR = LOD_THRESHOLDS.MID; // Switch to LOD past this
|
|
22
|
+
const LOD_THRESHOLD_FAR = LOD_THRESHOLDS.MID; // Switch to resident LOD past this
|
|
23
23
|
const LOD_THRESHOLD_NEAR = LOD_THRESHOLDS.MID; // Switch to full-res before this
|
|
24
24
|
function isDocumentHidden() {
|
|
25
25
|
return typeof document !== 'undefined' && document.visibilityState === 'hidden';
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
// ▲▲▲ [Usage] ▲▲▲
|
|
52
52
|
|
|
53
53
|
// Procedural line rendering settings
|
|
54
|
-
const LOD_RENDERER_BUILD_ID = '20260621-
|
|
54
|
+
const LOD_RENDERER_BUILD_ID = '20260621-near-lod-pixel-snap-v790';
|
|
55
55
|
const DirtyKind = Object.freeze({
|
|
56
56
|
ResidentFullRebuild: 'resident-full-rebuild',
|
|
57
57
|
ResidentPatch: 'resident-patch',
|
|
@@ -4476,15 +4476,47 @@ const LOD_RENDERER_BUILD_ID = '20260621-soft-fullres-edge-v780';
|
|
|
4476
4476
|
|
|
4477
4477
|
_setCss3dLodClass(entry, isHigh) {
|
|
4478
4478
|
this._setNodeDetailLevel(entry, isHigh ? 'HIGH' : 'LOW');
|
|
4479
|
+
if (getNodeContentType(entry?.model) === 'video' &&
|
|
4480
|
+
window.MindMapCss3DManager?.syncCss3dVideoLodMediaSource) {
|
|
4481
|
+
window.MindMapCss3DManager.syncCss3dVideoLodMediaSource(entry.model, entry.cssObject, isHigh === true);
|
|
4482
|
+
}
|
|
4483
|
+
}
|
|
4484
|
+
|
|
4485
|
+
_restoreVisibleCss3dHighDetailForNear(nodeObjectsById, module, lodBand) {
|
|
4486
|
+
if (lodBand !== 'NEAR' || !nodeObjectsById) {
|
|
4487
|
+
return 0;
|
|
4488
|
+
}
|
|
4489
|
+
|
|
4490
|
+
let restoredCount = 0;
|
|
4491
|
+
for (const entry of nodeObjectsById.values()) {
|
|
4492
|
+
const cssElement = entry?.cssObject?.element || null;
|
|
4493
|
+
if (!cssElement ||
|
|
4494
|
+
entry.cssObject?.visible !== true ||
|
|
4495
|
+
cssElement.style.display === 'none' ||
|
|
4496
|
+
!cssElement.classList?.contains?.('lod-low')) {
|
|
4497
|
+
continue;
|
|
4498
|
+
}
|
|
4499
|
+
|
|
4500
|
+
this._setCss3dLodClass(entry, true);
|
|
4501
|
+
restoredCount++;
|
|
4502
|
+
}
|
|
4503
|
+
|
|
4504
|
+
if (restoredCount > 0 && module) {
|
|
4505
|
+
module._css3dVisualChangedThisFrame = true;
|
|
4506
|
+
module._css3dVisualChangedSinceLastRender = true;
|
|
4507
|
+
}
|
|
4508
|
+
|
|
4509
|
+
return restoredCount;
|
|
4479
4510
|
}
|
|
4480
4511
|
|
|
4481
4512
|
_shouldUseHighCss3dDetail(entry, module) {
|
|
4482
4513
|
const cameraZ = Number(module?.camera?.position?.z || 0);
|
|
4483
|
-
const
|
|
4484
|
-
if (
|
|
4514
|
+
const cameraBand = getLodBandForCameraZ(cameraZ);
|
|
4515
|
+
if (cameraBand === 'NEAR') {
|
|
4485
4516
|
return true;
|
|
4486
4517
|
}
|
|
4487
4518
|
|
|
4519
|
+
const lodBand = this._currentLodBand || cameraBand;
|
|
4488
4520
|
const nodeId = String(entry?.model?.id || entry?.model?.Id || entry?.glObject?.userData?.nodeId || '').trim();
|
|
4489
4521
|
const selectedNodeId = String(module?.selectedNodeIdJs || module?.selectedNodeId || '').trim();
|
|
4490
4522
|
if (nodeId && selectedNodeId && nodeId === selectedNodeId) {
|
|
@@ -4775,12 +4807,18 @@ const LOD_RENDERER_BUILD_ID = '20260621-soft-fullres-edge-v780';
|
|
|
4775
4807
|
}
|
|
4776
4808
|
// ▲▲▲ [FIX] ▲▲▲
|
|
4777
4809
|
|
|
4778
|
-
|
|
4810
|
+
const shouldUseHighCss3dDetail = this._shouldUseHighCss3dDetail(entry, module);
|
|
4811
|
+
this._setCss3dLodClass(entry, shouldUseHighCss3dDetail);
|
|
4779
4812
|
|
|
4780
4813
|
// ▼▼▼ [CRITICAL] Sync content BEFORE making CSS visible ▼▼▼
|
|
4781
4814
|
// Prevents one-frame display of stale/blurred text while dirty DOM is being updated.
|
|
4782
4815
|
const cssMediaEl = entry.cssObject.element?.querySelector?.('img,video') || null;
|
|
4783
|
-
const
|
|
4816
|
+
const isLowDetailVideoProxy =
|
|
4817
|
+
getNodeContentType(model) === 'video' &&
|
|
4818
|
+
shouldUseHighCss3dDetail !== true;
|
|
4819
|
+
const needsInitialMediaSync = !!cssMediaEl &&
|
|
4820
|
+
!cssMediaEl.getAttribute('src') &&
|
|
4821
|
+
isLowDetailVideoProxy !== true;
|
|
4784
4822
|
if ((entry.isCssDirty || needsInitialMediaSync) && window.MindMapCss3DManager?.syncCss3dContent) {
|
|
4785
4823
|
window.MindMapCss3DManager.syncCss3dContent(model, entry.cssObject);
|
|
4786
4824
|
entry.isCssDirty = false; // sync 완료 후 clean
|
|
@@ -5743,7 +5781,7 @@ const LOD_RENDERER_BUILD_ID = '20260621-soft-fullres-edge-v780';
|
|
|
5743
5781
|
return;
|
|
5744
5782
|
}
|
|
5745
5783
|
|
|
5746
|
-
// Explicit bands: NEAR(DOM overlay + CSS3D),
|
|
5784
|
+
// Explicit bands: NEAR(DOM overlay + CSS3D), MID(resident nodes+lines), FAR(nodes only)
|
|
5747
5785
|
const shouldUseLOD = lodBand === 'MID' || lodBand === 'FAR';
|
|
5748
5786
|
perfMode = shouldUseLOD ? 'lod' : 'fullres';
|
|
5749
5787
|
const isLodPanFrame = shouldUseLOD &&
|
|
@@ -5925,7 +5963,7 @@ const LOD_RENDERER_BUILD_ID = '20260621-soft-fullres-edge-v780';
|
|
|
5925
5963
|
|
|
5926
5964
|
} else {
|
|
5927
5965
|
perfTime('fullResSetup', () => {
|
|
5928
|
-
// Full-res: NEAR
|
|
5966
|
+
// Full-res: NEAR only. NORMAL is intentionally collapsed into resident MID.
|
|
5929
5967
|
const tNearStart = performance.now();
|
|
5930
5968
|
if (this.instancedHaloMesh) this.instancedHaloMesh.visible = false;
|
|
5931
5969
|
if (this.instancedConsoleMesh) this.instancedConsoleMesh.visible = false;
|
|
@@ -6000,6 +6038,7 @@ const LOD_RENDERER_BUILD_ID = '20260621-soft-fullres-edge-v780';
|
|
|
6000
6038
|
// ▼▼▼ [Fix] Keep CSS3D visibility synced while panning in near mode ▼▼▼
|
|
6001
6039
|
if (!this.isInLODMode) {
|
|
6002
6040
|
this._currentLodBand = lodBand;
|
|
6041
|
+
this._restoreVisibleCss3dHighDetailForNear(nodeObjectsById, module, lodBand);
|
|
6003
6042
|
const visibleIds = this._getNearVisibleIds(module);
|
|
6004
6043
|
if (!visibleIds || visibleIds.size === 0) {
|
|
6005
6044
|
perfTime('fullResHandoff', () => {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
const DEBUG = false;
|
|
5
|
-
const PASSIVE_DOM_OVERLAY_ENABLED =
|
|
5
|
+
const PASSIVE_DOM_OVERLAY_ENABLED = true;
|
|
6
6
|
const DEFAULT_OVERLAY_SCROLLABLE_SELECTOR = '.node-response, .note-content, .markdown-body, .prose, .note-textarea, .code-body, .code-content, .pdf-content, .text-content, .file-content, .map-node-memo__body, .map-node-memo__body-view, .map-node-memo__agent-plan-body, .map-node-memo__agent-console-body, pre, code';
|
|
7
7
|
const PASSIVE_OVERLAY_NEAR_EXIT_GRACE_MS = 220;
|
|
8
8
|
const PASSIVE_OVERLAY_CANDIDATE_GRACE_MS = 160;
|
|
@@ -265,15 +265,15 @@
|
|
|
265
265
|
const cameraZ = Number(module?.camera?.position?.z || 0);
|
|
266
266
|
const thresholds = globalThis.LODRenderer?.LOD_THRESHOLDS || {
|
|
267
267
|
NEAR: 4500,
|
|
268
|
-
NORMAL:
|
|
269
|
-
MID:
|
|
268
|
+
NORMAL: 4500,
|
|
269
|
+
MID: 4500,
|
|
270
270
|
FAR: 30000
|
|
271
271
|
};
|
|
272
272
|
|
|
273
273
|
if (cameraZ >= Number(thresholds.FAR || 25000)) {
|
|
274
274
|
return 'FAR';
|
|
275
275
|
}
|
|
276
|
-
if (cameraZ >= Number(thresholds.MID || thresholds.NORMAL ||
|
|
276
|
+
if (cameraZ >= Number(thresholds.MID || thresholds.NORMAL || 4500)) {
|
|
277
277
|
return 'MID';
|
|
278
278
|
}
|
|
279
279
|
if (cameraZ >= Number(thresholds.NORMAL || thresholds.NEAR || 4500)) {
|
|
@@ -336,7 +336,7 @@
|
|
|
336
336
|
state.passiveNearStickyUntil = 0;
|
|
337
337
|
}
|
|
338
338
|
|
|
339
|
-
return
|
|
339
|
+
return false;
|
|
340
340
|
}
|
|
341
341
|
|
|
342
342
|
function shouldUseVisiblePassiveOverlayCandidates(module) {
|
|
@@ -956,10 +956,6 @@
|
|
|
956
956
|
return false;
|
|
957
957
|
}
|
|
958
958
|
|
|
959
|
-
if (entry && supportsTextOverlayEntry(entry)) {
|
|
960
|
-
return false;
|
|
961
|
-
}
|
|
962
|
-
|
|
963
959
|
return true;
|
|
964
960
|
}
|
|
965
961
|
|
|
@@ -1298,6 +1294,29 @@
|
|
|
1298
1294
|
return Math.max(baseZIndex, candidate + baseZIndex);
|
|
1299
1295
|
}
|
|
1300
1296
|
|
|
1297
|
+
function getDevicePixelRatio() {
|
|
1298
|
+
const dpr = Number(globalThis?.devicePixelRatio || 1);
|
|
1299
|
+
return Number.isFinite(dpr) && dpr > 0 ? Math.min(4, Math.max(1, dpr)) : 1;
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
function snapScreenPixel(value, dpr = getDevicePixelRatio()) {
|
|
1303
|
+
const numeric = Number(value || 0);
|
|
1304
|
+
if (!Number.isFinite(numeric)) {
|
|
1305
|
+
return 0;
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
return Math.round(numeric * dpr) / dpr;
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
function snapScreenLength(value, dpr = getDevicePixelRatio()) {
|
|
1312
|
+
const numeric = Number(value || 0);
|
|
1313
|
+
if (!Number.isFinite(numeric)) {
|
|
1314
|
+
return 1;
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
return Math.max(1 / dpr, Math.round(Math.max(1 / dpr, numeric) * dpr) / dpr);
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1301
1320
|
function applyPlacement(module, element, rect, zIndex, entry = null) {
|
|
1302
1321
|
if (!module || !element || !rect) {
|
|
1303
1322
|
return;
|
|
@@ -1305,8 +1324,13 @@
|
|
|
1305
1324
|
|
|
1306
1325
|
const baseWidth = Math.max(1, Number(rect.baseWidth || rect.width || 1));
|
|
1307
1326
|
const baseHeight = Math.max(1, Number(rect.baseHeight || rect.height || 1));
|
|
1308
|
-
const
|
|
1309
|
-
const
|
|
1327
|
+
const dpr = getDevicePixelRatio();
|
|
1328
|
+
const left = snapScreenPixel(rect.left || 0, dpr);
|
|
1329
|
+
const top = snapScreenPixel(rect.top || 0, dpr);
|
|
1330
|
+
const width = snapScreenLength(rect.width || baseWidth || 1, dpr);
|
|
1331
|
+
const height = snapScreenLength(rect.height || baseHeight || 1, dpr);
|
|
1332
|
+
const scaleX = width / baseWidth;
|
|
1333
|
+
const scaleY = height / baseHeight;
|
|
1310
1334
|
const preferCssZoom = shouldPreferOverlayCssZoom(module, entry);
|
|
1311
1335
|
const canUseZoom =
|
|
1312
1336
|
preferCssZoom &&
|
|
@@ -1318,10 +1342,10 @@
|
|
|
1318
1342
|
const shell = element.firstElementChild || null;
|
|
1319
1343
|
|
|
1320
1344
|
element.style.display = 'block';
|
|
1321
|
-
element.style.left = `${
|
|
1322
|
-
element.style.top = `${
|
|
1323
|
-
element.style.width = `${
|
|
1324
|
-
element.style.height = `${
|
|
1345
|
+
element.style.left = `${left}px`;
|
|
1346
|
+
element.style.top = `${top}px`;
|
|
1347
|
+
element.style.width = `${width}px`;
|
|
1348
|
+
element.style.height = `${height}px`;
|
|
1325
1349
|
element.style.transform = '';
|
|
1326
1350
|
element.style.zoom = '';
|
|
1327
1351
|
applyScrollbarScaleCompensation(element, scaleX, scaleY);
|
|
@@ -1336,14 +1360,18 @@
|
|
|
1336
1360
|
applyScrollbarScaleCompensation(shell, scaleX, scaleY);
|
|
1337
1361
|
|
|
1338
1362
|
if (canUseZoom) {
|
|
1339
|
-
shell.style.zoom = `${scaleX}`;
|
|
1363
|
+
shell.style.zoom = `${Math.max(0.01, Math.round(scaleX * 100000) / 100000)}`;
|
|
1340
1364
|
module._overlayDebugPlacementZoomCount = Number(module._overlayDebugPlacementZoomCount || 0) + 1;
|
|
1341
1365
|
} else {
|
|
1342
|
-
|
|
1366
|
+
const snappedScaleX = Math.max(0.01, Math.round(scaleX * 100000) / 100000);
|
|
1367
|
+
const snappedScaleY = Math.max(0.01, Math.round(scaleY * 100000) / 100000);
|
|
1368
|
+
shell.style.transform = `scale(${snappedScaleX}, ${snappedScaleY})`;
|
|
1343
1369
|
module._overlayDebugPlacementTransformCount = Number(module._overlayDebugPlacementTransformCount || 0) + 1;
|
|
1344
1370
|
}
|
|
1345
1371
|
} else if (!canUseZoom) {
|
|
1346
|
-
|
|
1372
|
+
const snappedScaleX = Math.max(0.01, Math.round(scaleX * 100000) / 100000);
|
|
1373
|
+
const snappedScaleY = Math.max(0.01, Math.round(scaleY * 100000) / 100000);
|
|
1374
|
+
element.style.transform = `scale(${snappedScaleX}, ${snappedScaleY})`;
|
|
1347
1375
|
module._overlayDebugPlacementTransformCount = Number(module._overlayDebugPlacementTransformCount || 0) + 1;
|
|
1348
1376
|
}
|
|
1349
1377
|
element.style.zIndex = String(resolveOverlayZIndex(entry, zIndex));
|
|
@@ -1932,8 +1960,8 @@
|
|
|
1932
1960
|
copyStyle(null, readComputedStyleValue(computed, null, 'text-wrap'), 'text-wrap');
|
|
1933
1961
|
copyStyle(null, readComputedStyleValue(computed, null, 'text-wrap-mode'), 'text-wrap-mode');
|
|
1934
1962
|
copyStyle(null, readComputedStyleValue(computed, null, 'text-wrap-style'), 'text-wrap-style');
|
|
1935
|
-
targetElement.style.setProperty('-webkit-font-smoothing', '
|
|
1936
|
-
targetElement.style.setProperty('-moz-osx-font-smoothing', '
|
|
1963
|
+
targetElement.style.setProperty('-webkit-font-smoothing', 'auto');
|
|
1964
|
+
targetElement.style.setProperty('-moz-osx-font-smoothing', 'auto');
|
|
1937
1965
|
}
|
|
1938
1966
|
|
|
1939
1967
|
function getTypographySyncChildren(element) {
|
package/wwwroot/index.html
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
<title>MindExec | Business Execution OS for solo builders</title>
|
|
8
8
|
<meta name="description" content="MindExec is an AI business execution OS for solo builders who want to turn notes, research, assets, and repeatable execution Skills into revenue-producing work." />
|
|
9
9
|
<base href="/" />
|
|
10
|
-
<link rel="stylesheet" href="_content/MindExecution.Shared/css/app.css?v=20260621-
|
|
11
|
-
<link rel="stylesheet" href="_content/MindExecution.Shared/css/mind-map-overrides.css?v=20260621-
|
|
10
|
+
<link rel="stylesheet" href="_content/MindExecution.Shared/css/app.css?v=20260621-near-lod-pixel-snap-v790" />
|
|
11
|
+
<link rel="stylesheet" href="_content/MindExecution.Shared/css/mind-map-overrides.css?v=20260621-near-lod-pixel-snap-v790" />
|
|
12
12
|
<!-- ??좎뜦堉??Font Awesome (local) ??좎뜦堉??-->
|
|
13
13
|
<link rel="stylesheet" href="_content/MindExecution.Shared/lib/font-awesome/css/all.min.css" />
|
|
14
14
|
<!-- ??좎뜦堉??-->
|
|
@@ -579,7 +579,7 @@
|
|
|
579
579
|
}
|
|
580
580
|
|
|
581
581
|
const base = '_content/MindExecution.Shared/js/';
|
|
582
|
-
const scriptVersion = '20260621-
|
|
582
|
+
const scriptVersion = '20260621-near-lod-pixel-snap-v790';
|
|
583
583
|
const scriptUrl = (script) => `${base}${script}?v=${scriptVersion}`;
|
|
584
584
|
console.log(`[Script Loader] Shared JS version: ${scriptVersion}`);
|
|
585
585
|
const criticalScripts = [
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
self.assetsManifest = {
|
|
2
|
-
"version": "
|
|
2
|
+
"version": "qR19js7U",
|
|
3
3
|
"assets": [
|
|
4
4
|
{
|
|
5
5
|
"hash": "sha256-+CSYMcqLNTsq3VnH11jgYyOCCdxvHzL74CBmo4sCmMU=",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"url": "_content/MindExecution.Shared/css/app.css"
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
|
-
"hash": "sha256-
|
|
45
|
+
"hash": "sha256-uUo6RfwT80RrRI95nGw6SISUrer/BE9+7P3yVivBYXQ=",
|
|
46
46
|
"url": "_content/MindExecution.Shared/css/mind-map-overrides.css"
|
|
47
47
|
},
|
|
48
48
|
{
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"url": "_content/MindExecution.Shared/js/marked.min.js"
|
|
79
79
|
},
|
|
80
80
|
{
|
|
81
|
-
"hash": "sha256-
|
|
81
|
+
"hash": "sha256-5WxowCqXOM5gcHZIaCotoNvWIC1paUc/UWdcQ0tqaXo=",
|
|
82
82
|
"url": "_content/MindExecution.Shared/js/mind-map-core.js"
|
|
83
83
|
},
|
|
84
84
|
{
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"url": "_content/MindExecution.Shared/js/mind-map-core.js.backup"
|
|
87
87
|
},
|
|
88
88
|
{
|
|
89
|
-
"hash": "sha256-
|
|
89
|
+
"hash": "sha256-1hnC4MKgwN6Nsz5+5t3Kjy6m/3kfaI7QNMFKaS8H/hA=",
|
|
90
90
|
"url": "_content/MindExecution.Shared/js/mind-map-css3d-manager.js"
|
|
91
91
|
},
|
|
92
92
|
{
|
|
@@ -106,7 +106,7 @@
|
|
|
106
106
|
"url": "_content/MindExecution.Shared/js/mind-map-glow-shader.js"
|
|
107
107
|
},
|
|
108
108
|
{
|
|
109
|
-
"hash": "sha256-
|
|
109
|
+
"hash": "sha256-iqbrsttHQqhuGvTIj1yVbjF79M218kbqXCZ3R1iyg/Y=",
|
|
110
110
|
"url": "_content/MindExecution.Shared/js/mind-map-interactions.js"
|
|
111
111
|
},
|
|
112
112
|
{
|
|
@@ -114,7 +114,7 @@
|
|
|
114
114
|
"url": "_content/MindExecution.Shared/js/mind-map-lod-plan-worker.js"
|
|
115
115
|
},
|
|
116
116
|
{
|
|
117
|
-
"hash": "sha256-
|
|
117
|
+
"hash": "sha256-Nct6u0jhFqOSEzDDBROMfhB4SvUw0yb2DK065toNffk=",
|
|
118
118
|
"url": "_content/MindExecution.Shared/js/mind-map-lod-renderer.js"
|
|
119
119
|
},
|
|
120
120
|
{
|
|
@@ -154,7 +154,7 @@
|
|
|
154
154
|
"url": "_content/MindExecution.Shared/js/mind-map-text-lod-system.js"
|
|
155
155
|
},
|
|
156
156
|
{
|
|
157
|
-
"hash": "sha256-
|
|
157
|
+
"hash": "sha256-zGfIZ50rYA0nDkeMNB+wv2WRhssu6lHXb5ERwvLbcq4=",
|
|
158
158
|
"url": "_content/MindExecution.Shared/js/mind-map-text-overlay-v2.js"
|
|
159
159
|
},
|
|
160
160
|
{
|
|
@@ -834,7 +834,7 @@
|
|
|
834
834
|
"url": "image-manifest.json"
|
|
835
835
|
},
|
|
836
836
|
{
|
|
837
|
-
"hash": "sha256-
|
|
837
|
+
"hash": "sha256-5IzHBpG6V4csffSXfPHWC7BKgybKjT61K0dk0XOOvWE=",
|
|
838
838
|
"url": "index.html"
|
|
839
839
|
},
|
|
840
840
|
{
|