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 |
|
true |
|
|
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:-
On
.content-area: Addcontain: layout style;— isolates the main content + queue panel from affecting header/sidebar/footer layout. Do NOT usecontain: stricthere because strict includes size containment which would break the flex layout. -
On
.main-panel: Addcontain: 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. -
On
.main-panel > *: Addcontain: 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. -
On
body div.sidebar: Addcontain: layout style paint;— sidebar is a fixed-width element that shouldn't affect main panel layout. -
On
.bottom-bar: Addcontain: 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.
cover-grid-styles.ts:
- On
:host: Addcontain: layout style;(already hasoverflow: hidden) - On
.grid-scroll-container: Addcontain: paint;andwill-change: transform;— this is the actual scroll container for the album grid.will-change: transformpromotes it to its own GPU layer so scrolling is composited.contain: paintcreates a new stacking context. - On
.album-card: Addcontent-visibility: auto;withcontain-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: Addcontain: layout style; - On
lit-virtualizer: Addcontain: paint;andwill-change: transform;— the virtualizer element is the scroller for the track list.
queue-panel.ts (in static styles):
- On
:hostor the scroll container: Addcontain: layout style paint; - On
lit-virtualizer: Addcontain: paint;andwill-change: transform;
artists-view.ts (in static styles):
- On
:host: Addcontain: layout style; - On the grid virtualizer parent scroll container: Add
contain: paint;andwill-change: transform;
genres-view.ts (in static styles):
- Same pattern as artists-view.
playlist-view.ts (in static styles):
- On
:host: Addcontain: layout style; - On
.playlist-list(the native scroll container): Addcontain: paint;andwill-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.
<success_criteria>
- CSS
containproperty present on all 6 scroll component:hostelements - CSS
will-change: transformpresent on all 6 scroll containers (not hosts) - CSS
contain: stricton.main-panelin index.css - CSS
content-visibility: autoon.album-cardin cover-grid-styles - No visual regressions (popups, context menus, dropdowns all work)
- Build succeeds </success_criteria>