From e2eac64dce16bd0860f8a8586e94cfbe68602a41 Mon Sep 17 00:00:00 2001 From: BoulderBadgeDad Date: Wed, 3 Jun 2026 11:09:02 -0700 Subject: [PATCH] Artist Map v2: de-lag one-island genre view + move island nav to top-left MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Focused islands now render from the high-res buffer (one cheap crisp blit) instead of redrawing every bubble each frame for the bob. In one-island mode the buffer already covers just that island at high resolution, so this is crisp AND cheap — kills the genre lag. Bob/shove stay live only for small views (zoomed-in subsets, explore) where per-frame redraw is cheap. (Overflow threshold 650→140; the loop parks once the island bakes.) - Fewer bubbles per island (maxPerIsland 500→300) — less cramped, lighter bloom. - Island nav bar moved from bottom-center to top-left (clears the genre sidebar + toolbar). 64 JS integrity tests pass. --- webui/static/discover.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/webui/static/discover.js b/webui/static/discover.js index 7f7ebead..245d5c3c 100644 --- a/webui/static/discover.js +++ b/webui/static/discover.js @@ -5122,7 +5122,7 @@ function _artMapLayoutIslands(groups, opts = {}) { _artMap._islands = []; const nodeR = opts.nodeR || (_artMap.WATCHLIST_R * 0.22); const gap = opts.gap || (_artMap.BUFFER * 2.2); - const cap = opts.maxPerIsland || 500; + const cap = opts.maxPerIsland || 300; let pid = 0; const islands = groups.map(g => { @@ -5291,9 +5291,12 @@ function _artMapUpdateIslandNav() { if (!nav) { nav = document.createElement('div'); nav.id = 'artmap-island-nav'; - nav.style.cssText = 'position:absolute;bottom:18px;left:50%;transform:translateX(-50%);display:flex;align-items:center;gap:14px;padding:8px 14px;background:rgba(16,12,28,0.82);backdrop-filter:blur(10px);border:1px solid rgba(168,85,247,0.25);border-radius:999px;z-index:30;box-shadow:0 6px 24px rgba(0,0,0,0.45);user-select:none;'; container.appendChild(nav); } + // Position top-left, clearing the genre sidebar (when shown) and the toolbar. + const sb = document.getElementById('artmap-genre-sidebar'); + const sbW = (sb && sb.style.display !== 'none') ? (sb.offsetWidth || 0) : 0; + nav.style.cssText = `position:absolute;top:64px;left:${sbW + 16}px;display:flex;align-items:center;gap:12px;padding:7px 12px;background:rgba(16,12,28,0.82);backdrop-filter:blur(10px);border:1px solid rgba(168,85,247,0.25);border-radius:14px;z-index:30;box-shadow:0 6px 24px rgba(0,0,0,0.45);user-select:none;`; const idx = _artMap._focusIdx || 0; const isl = islands[idx]; const btn = 'width:30px;height:30px;border-radius:50%;border:1px solid rgba(255,255,255,0.18);background:rgba(255,255,255,0.06);color:#fff;font-size:13px;cursor:pointer;display:flex;align-items:center;justify-content:center;'; @@ -5521,10 +5524,12 @@ function _artMapRebuildBuffer() { const bz = _artMap.zoom; let liveN = 0; for (const n of visible) { if (!n._isLabel && (n.radius || 0) * bz >= _artMap.LIVE_PX) liveN++; } - // A single focused island (≤ maxPerIsland 500) should render via the crisp - // live layer; only fall back to baking-everything when there are clearly more - // bubbles than the live layer can draw. - _artMap._liveOverflow = liveN > 650; + // In one-island mode the buffer already covers just the focused island at + // high resolution, so let the BUFFER own any non-trivial crowd (one cheap + // crisp blit, no per-frame redraw → no lag). The live layer + bob/shove only + // take over for small views (zoomed-in subsets, explore) where redrawing a + // handful of bubbles each frame is cheap. + _artMap._liveOverflow = liveN > 140; octx.scale(scale, scale); octx.translate(-minX, -minY);