Files
yellowjacket/.planning/phases/14-performance-optimization/14-01-PLAN.md
T

9.0 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
14-performance-optimization 01 execute 1
frontend/src/components/cover-grid/cover-grid-styles.ts
frontend/src/components/track-list/track-list.ts
frontend/src/components/queue-panel/queue-panel.ts
frontend/src/components/artists-view/artists-view.ts
frontend/src/components/genres-view/genres-view.ts
frontend/src/components/playlist-view/playlist-view.ts
frontend/index.css
true
PERF-SCROLL-01
PERF-SCROLL-02
truths artifacts key_links
All scroll containers use CSS contain to limit browser layout/paint scope
Virtualizer scroll containers are GPU-promoted for composited scrolling
The main content area uses CSS containment to isolate layout from sidebar/header/footer
Album cards use content-visibility auto to skip rendering when off-screen
path provides contains
frontend/src/components/cover-grid/cover-grid-styles.ts CSS contain and will-change on scroll containers, content-visibility on album cards contain:
path provides contains
frontend/src/components/track-list/track-list.ts CSS contain and will-change on virtualizer host contain:
path provides contains
frontend/src/components/queue-panel/queue-panel.ts CSS contain on queue panel scroll area contain:
path provides contains
frontend/index.css CSS containment on .main-panel and .content-area contain:
from to via pattern
frontend/index.css .main-panel CSS contain: strict on layout boundary contain:\s*(strict|layout)
from to via pattern
cover-grid-styles.ts .grid-scroll-container will-change: transform for GPU compositing will-change
Add CSS containment, GPU layer promotion, and content-visibility to all scroll containers and layout boundaries for dramatically smoother scrolling performance.

Purpose: The browser currently cannot optimize layout/paint for any component — no contain, no will-change, no content-visibility anywhere. Adding these CSS properties allows the browser to skip layout recalculation for off-screen content and use GPU-composited scrolling for list containers.

Output: All scroll-heavy components have CSS containment; scrolling moves to the compositor thread where possible.

<execution_context> @/home/caleb/.config/opencode/get-shit-done/workflows/execute-plan.md @/home/caleb/.config/opencode/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @frontend/index.css @frontend/src/components/cover-grid/cover-grid-styles.ts Task 1: Add CSS containment to app shell layout boundaries frontend/index.css Add CSS containment properties to the app shell layout to isolate layout recalculation boundaries:
  1. On .content-area: Add contain: layout style; — isolates the main content + queue panel from affecting header/sidebar/footer layout. Do NOT use contain: strict here because strict includes size containment which would break the flex layout.

  2. On .main-panel: Add contain: strict; — the main panel has explicit dimensions (flex: 1, overflow: hidden) so strict containment (layout + size + paint + style) is safe and maximally beneficial. This means any DOM changes inside the main panel cannot trigger layout recalculation outside it.

  3. On .main-panel > *: Add contain: layout style paint; — each view component inside main-panel gets paint containment (creates new stacking context, isolates paint) plus layout containment. Do NOT add size containment since height: 100% needs to resolve from parent.

  4. On body div.sidebar: Add contain: layout style paint; — sidebar is a fixed-width element that shouldn't affect main panel layout.

  5. On .bottom-bar: Add contain: layout style; — footer has fixed height, isolate from content reflows.

Do NOT add will-change to the app shell elements — those are for scroll containers only (Task 2). The app builds successfully: cd frontend && npx vite build --mode development 2>&1 | tail -5 Visual check: all layout areas still render correctly (no collapsed panels, no overflow issues). App shell layout boundaries have CSS containment isolating layout recalculation between header, sidebar, main panel, and footer.

Task 2: Add GPU promotion and containment to all scroll containers frontend/src/components/cover-grid/cover-grid-styles.ts frontend/src/components/track-list/track-list.ts frontend/src/components/queue-panel/queue-panel.ts frontend/src/components/artists-view/artists-view.ts frontend/src/components/genres-view/genres-view.ts frontend/src/components/playlist-view/playlist-view.ts Add CSS containment and GPU layer promotion to every scroll container and virtualized list component. The goal is to make scrolling happen on the GPU compositor thread rather than the main thread.

cover-grid-styles.ts:

  • On :host: Add contain: layout style; (already has overflow: hidden)
  • On .grid-scroll-container: Add contain: paint; and will-change: transform; — this is the actual scroll container for the album grid. will-change: transform promotes it to its own GPU layer so scrolling is composited. contain: paint creates a new stacking context.
  • On .album-card: Add content-visibility: auto; with contain-intrinsic-size: auto var(--card-width, 176px) auto calc(var(--card-width, 176px) + 40px); — this tells the browser to skip rendering album cards that are not in the viewport. The intrinsic size hint prevents layout shift. Note: lit-virtualizer already handles virtualization, but content-visibility provides an additional browser-native layer for cards near the viewport edges that are rendered but not visible.

track-list.ts (in static styles):

  • On :host: Add contain: layout style;
  • On lit-virtualizer: Add contain: paint; and will-change: transform; — the virtualizer element is the scroller for the track list.

queue-panel.ts (in static styles):

  • On :host or the scroll container: Add contain: layout style paint;
  • On lit-virtualizer: Add contain: paint; and will-change: transform;

artists-view.ts (in static styles):

  • On :host: Add contain: layout style;
  • On the grid virtualizer parent scroll container: Add contain: paint; and will-change: transform;

genres-view.ts (in static styles):

  • Same pattern as artists-view.

playlist-view.ts (in static styles):

  • On :host: Add contain: layout style;
  • On .playlist-list (the native scroll container): Add contain: paint; and will-change: transform; — even though this isn't virtualized, GPU compositing still helps scrolling.

Important: Do NOT add will-change: transform to :host elements — only to actual scroll containers. will-change on non-scrolling elements wastes GPU memory. Only apply it to elements with overflow-y: auto/scroll.

Important: Verify that contain: paint doesn't clip absolutely-positioned tooltips/popups that need to overflow. Context menus and popups use wa-popup which are appended to the shadow root, so they should still work. But verify this. cd frontend && npx vite build --mode development 2>&1 | tail -5 completes without errors. Run the app and test: (1) scroll the track list rapidly — should feel smoother, (2) scroll the album grid — should feel smoother, (3) right-click a track — context menu should still appear correctly and not be clipped, (4) open a cover grid album dropdown — should still work and not be clipped by contain: paint. All 6 scroll-heavy components have CSS containment on hosts and will-change: transform on scroll containers for GPU-composited scrolling. Content-visibility on album cards skips rendering for off-viewport cards.

After both tasks: 1. `cd frontend && npx vite build --mode development` builds without errors 2. App starts and all views render correctly 3. Scrolling in track list, album grid, queue panel, artists, genres, playlists all work without visual artifacts 4. Context menus, popups, and tooltips are not clipped by paint containment 5. Album grid dropdown (expanded album) still renders correctly between grid splits

<success_criteria>

  • CSS contain property present on all 6 scroll component :host elements
  • CSS will-change: transform present on all 6 scroll containers (not hosts)
  • CSS contain: strict on .main-panel in index.css
  • CSS content-visibility: auto on .album-card in cover-grid-styles
  • No visual regressions (popups, context menus, dropdowns all work)
  • Build succeeds </success_criteria>
After completion, create `.planning/phases/14-performance-optimization/14-01-SUMMARY.md`