Skip to content

feat: virtual scrolling for gallery grid view#3170

Open
msedek wants to merge 1 commit intorommapp:masterfrom
msedek:pr/gallery-virtual-scroll
Open

feat: virtual scrolling for gallery grid view#3170
msedek wants to merge 1 commit intorommapp:masterfrom
msedek:pr/gallery-virtual-scroll

Conversation

@msedek
Copy link
Copy Markdown

@msedek msedek commented Mar 24, 2026

Summary

Implements row-based virtual scrolling for the gallery card grid using @tanstack/vue-virtual, addressing the performance issue described in #1426 and #3161.

Problem

When browsing a platform with 1000+ ROMs, the infinite scroll keeps appending GameCard components to the DOM. After scrolling 500+ cards (~25,000 DOM nodes), clicking a game freezes the browser as Vue destroys all components at once.

Solution

  • Replace the flat v-for over filteredRoms with useWindowVirtualizer from @tanstack/vue-virtual
  • ROMs are grouped into rows based on responsive column count (derived from Vuetify breakpoints + view settings)
  • Only visible rows + 5 overscan rows are rendered in DOM
  • At 1000 ROMs with 6 columns: ~60 cards in DOM instead of 1000

What changed

  • frontend/src/views/Gallery/Platform.vue — template and script
  • frontend/package.json — added @tanstack/vue-virtual dependency

What didn't change

  • ROM store, GameCard component, infinite scroll fetch logic, selection logic — all untouched
  • List/table view (currentView == 2) — unchanged

Test plan

  • Browse a platform with 1000+ ROMs — should render smoothly
  • Scroll through all ROMs — only visible cards in DOM (inspect Elements tab)
  • Click a game after scrolling 500+ cards — instant navigation, no freeze
  • Responsive: resize window — columns adjust correctly
  • View switching (small/big/list) — all views work
  • Multi-select with shift-click — selection logic preserved

Tested with 5,600 ROMs across 12 platforms (largest: NES with 1,366 ROMs).

AI-assisted: Claude was used for research and implementation.

Closes #3161

Copy link
Copy Markdown
Member

@zurdi15 zurdi15 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you fix the Typescript check

Also, is it possible for you to sign the commit? It's OK otherwise

@gantoine gantoine added the on-hold Pending further research or blocked by another issue label Mar 26, 2026
@msedek msedek force-pushed the pr/gallery-virtual-scroll branch from 7aa8072 to c74aecd Compare March 28, 2026 15:44
Replace flat v-for iteration with TanStack Virtual window
virtualizer for the gallery cards view. Rows are virtualized
so only visible rows are rendered, reducing DOM nodes from
hundreds to a few dozen.

Changes:
- Add @tanstack/vue-virtual dependency
- Compute grid columns from Vuetify breakpoints
- Virtualize rows with useWindowVirtualizer
- Map flat ROM list to virtual grid cells via getRomForCell()
- Cast virtualRow.key to String for vue-tsc compatibility

Signed-off-by: Miguel Sedek <miguelsedek@gmail.com>
@msedek msedek force-pushed the pr/gallery-virtual-scroll branch from d53e9af to 73a9922 Compare March 28, 2026 16:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

on-hold Pending further research or blocked by another issue

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Performance] Virtual scrolling for gallery grid view using @tanstack/vue-virtual

3 participants