feedBack/static/v3
byrongamatos d214837b0d feat(v3): DOM-virtualize the Songs grid (#636 item 3 stage 2)
The v3 Songs grid appended every scrolled page and never released nodes,
so card-node count grew unbounded with scroll depth (24 → 624 → 2001 for a
2000-song library). Replace it with a windowed/recycled render: only the
visible window (± overscan) is in the DOM while a #v3-songs-gridsizer
element sized to ceil(total/cols)*rowH gives the scrollbar full-library
geometry; #v3-songs-grid is absolutely positioned to the first visible row.

- state.songs is a sparse, absolutely-indexed store filled a page at a time
  by ensureWindow(): the stage-1 keyset cursor for contiguous forward scroll
  (O(page)), OFFSET page= for jumps/restore/non-keyset providers. _loadPage
  shares an in-flight promise per page and an epoch guard discards a stale
  fetch that lands after a reset.
- A–Z rail seeks directly via sort_letters cumulative counts (O(1), no
  page-through); bounded scan fallback for legacy providers without it.
- Snapshot/restore is now scrollTop-based (geometry is stable). Select mode,
  accuracy badges, ⋮ menu, plugin card actions, and tree/folder coexistence
  survive cards recycling; renderWindow re-renders when select mode toggles.
- Plugins get window.v3Songs.visibleCards() + a v3:library-window-rendered
  event instead of assuming all cards are present (highway-stutter lesson).

Verified in a browser against a seeded 2001-song library: DOM bounded to
~60 nodes while the count reads "2001 songs", rail jump lands on the target
row, selection survives recycling, scroll-restore exact. Codex-reviewed
(3 findings fixed: stale-fetch epoch guard, await-in-flight page promise,
select-mode resync on cached re-entry).

Frontend-only. Tests: tests/browser/v3-grid-virtualization.spec.ts pins the
bounded-DOM invariant + direct rail jump; tests/js/v3_az_rail.test.js and
v3_songs_scroll.test.js updated to the new wiring.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 11:58:11 +02:00
..
avatars Clean release snapshot 2026-06-16 18:47:13 +02:00
brand Clean release snapshot 2026-06-16 18:47:13 +02:00
pedals Clean release snapshot 2026-06-16 18:47:13 +02:00
audio-routing.js rename: slopsmith → feedBack, byron → got-feedBack (#537) 2026-06-23 11:03:01 +02:00
badges.js rename: slopsmith → feedBack, byron → got-feedBack (#537) 2026-06-23 11:03:01 +02:00
brand.js Clean release snapshot 2026-06-16 18:47:13 +02:00
card-actions-core.js rename: slopsmith → feedBack, byron → got-feedBack (#537) 2026-06-23 11:03:01 +02:00
dashboard.js rename: slopsmith → feedBack, byron → got-feedBack (#537) 2026-06-23 11:03:01 +02:00
feedbarcade.js rename: slopsmith → feedBack, byron → got-feedBack (#537) 2026-06-23 11:03:01 +02:00
index.html fix(player): reliable Escape "Back" + resumable, optionally-confirmed song exit (#619) 2026-06-28 12:32:33 +02:00
lessons.js rename: slopsmith → feedBack, byron → got-feedBack (#537) 2026-06-23 11:03:01 +02:00
live-guitar-tone-source.js rename: slopsmith → feedBack, byron → got-feedBack (#537) 2026-06-23 11:03:01 +02:00
live-performance-hud.js fix(v3): reset live performance HUD on backward seek / restart (#607) 2026-06-27 00:47:43 +02:00
manifest.json Clean release snapshot 2026-06-16 18:47:13 +02:00
notifications.js rename: slopsmith → feedBack, byron → got-feedBack (#537) 2026-06-23 11:03:01 +02:00
onboarding-tour.js rename: slopsmith → feedBack, byron → got-feedBack (#537) 2026-06-23 11:03:01 +02:00
overlay-active.png Clean release snapshot 2026-06-16 18:47:13 +02:00
overlay-inactive.png Clean release snapshot 2026-06-16 18:47:13 +02:00
pedal-cables.js rename: slopsmith → feedBack, byron → got-feedBack (#537) 2026-06-23 11:03:01 +02:00
pedal-default.svg Clean release snapshot 2026-06-16 18:47:13 +02:00
pedal-frame.svg Clean release snapshot 2026-06-16 18:47:13 +02:00
player-chrome.js fix(v3): add "Show 'Up Next'" toggle so the player pill can be turned off (#612) 2026-06-27 13:16:31 +02:00
playlists.js feat(v3): content-dependent playlist covers + custom art (#626) 2026-06-28 14:10:15 +02:00
plugins-page.js rename: slopsmith → feedBack, byron → got-feedBack (#537) 2026-06-23 11:03:01 +02:00
profile.js feat(onboarding): amp-sim opt-in choice + use_amp_sims setting (#631) 2026-06-29 00:13:28 +02:00
progress.js rename: slopsmith → feedBack, byron → got-feedBack (#537) 2026-06-23 11:03:01 +02:00
progression-core.js rename: slopsmith → feedBack, byron → got-feedBack (#537) 2026-06-23 11:03:01 +02:00
scoreboard-pref.js fix(highway): user-selectable scoreboard to stop duplicate HUDs 2026-06-19 20:56:38 +02:00
settings.js fix(player): reliable Escape "Back" + resumable, optionally-confirmed song exit (#619) 2026-06-28 12:32:33 +02:00
shell.js feat(v3): promote Audio Engine to a first-class sidebar entry (after Settings) (#613) 2026-06-27 18:16:36 +02:00
shop.js rename: slopsmith → feedBack, byron → got-feedBack (#537) 2026-06-23 11:03:01 +02:00
songs.js feat(v3): DOM-virtualize the Songs grid (#636 item 3 stage 2) 2026-06-29 11:58:11 +02:00
stats-recorder.js rename: slopsmith → feedBack, byron → got-feedBack (#537) 2026-06-23 11:03:01 +02:00
theme-core.js rename: slopsmith → feedBack, byron → got-feedBack (#537) 2026-06-23 11:03:01 +02:00
tuner-core.js Clean release snapshot 2026-06-16 18:47:13 +02:00
v3.css feat(v3): DOM-virtualize the Songs grid (#636 item 3 stage 2) 2026-06-29 11:58:11 +02:00
venue-instrument-pov.js Clean release snapshot 2026-06-16 18:47:13 +02:00
venue-mood-fx.js rename: slopsmith → feedBack, byron → got-feedBack (#537) 2026-06-23 11:03:01 +02:00
venue-scene-3d.js rename: slopsmith → feedBack, byron → got-feedBack (#537) 2026-06-23 11:03:01 +02:00
venue-viz.js Clean release snapshot 2026-06-16 18:47:13 +02:00