Record Phase 0 design decisions in PLAN.md

This commit is contained in:
Daniel Harvey
2026-05-17 21:03:50 -04:00
parent 22e6092d26
commit 7d059da9ca
+3 -7
View File
@@ -59,7 +59,7 @@ Phase 0 sub-items decompose into worktree-sized tracks. 0.1 is the foundation ev
- **Right:** dark navy panel with three concentric pulsing rings (CSS keyframe `pulse-ring`), a frosted "Now Playing" card (label + blinking dot + track title + sub + animated waveform bars), and the stat row (47+ / 2 / ∞).
- **Why it matters:** This is the page. Hero is what a first-time visitor sees, and it is the only sub-item that wires the new design back into the live audio system — making the design feel inhabited rather than decorative.
- **Shape:**
- **Now-Playing data source:** `Home.razor` consumes `[CascadingParameter] IPlayerService Player` (cascaded by `AudioPlayerProvider` from `MainLayout`). The card binds to `Player.IsLoaded`, `Player.IsPlaying`, `Player.CurrentTime`, `Player.Duration`. **`IPlayerService` does not currently expose the selected `TrackEntity` as a public property**`AudioPlayerService` stores it internally but only fires `OnTrackSelected` as a side effect. Phase 0 needs `IPlayerService.CurrentTrack { get; }` (nullable `TrackEntity`) added and a backing field surfaced in `AudioPlayerService`. This is a small, additive interface change — no consumer reads it today.
- **Now-Playing data source:** `Home.razor` consumes `[CascadingParameter] IPlayerService Player` (cascaded by `AudioPlayerProvider` from `MainLayout`). The card binds to `Player.IsLoaded`, `Player.IsPlaying`, `Player.CurrentTime`, `Player.Duration`. `IPlayerService` does not currently expose the selected `TrackEntity` as a public property — add `IPlayerService.CurrentTrack { get; }` (nullable `TrackEntity`) and surface the backing field in `AudioPlayerService`. Additive, no existing consumer is affected — implement it as part of this sub-item without a separate approval gate.
- **Empty state:** when `Player.CurrentTrack is null`, render a placeholder ("Nothing playing — pick a track" or similar) inside the card with the same chrome but no waveform animation. The card is permanent layout, not conditional on selection.
- **Animated waveform bars:** Phase 0 uses the wireframe's pure-CSS `wave-dance` keyframe animation with randomised `--h-lo` / `--h-hi` / `--dur` per bar — driven by no real audio data. A later phase can wire `SpectrumAnalyzer` data through `AudioInteropService.GetSpectrumData()` to drive bar heights, but that path is already used by `SpectrumVisualizer.razor` in the dock and duplicating it here is out of scope.
- **Stat row:** static markup with hard-coded "47+", "2", "∞" and TODO comments. The first two could plausibly become real numbers (track count, member count from a future identity model) — flag those at the markup site for Phase 2/identity work to pick up.
@@ -86,17 +86,13 @@ Phase 0 sub-items decompose into worktree-sized tracks. 0.1 is the foundation ev
- **Footer:** new site-wide affordance. Site root `MainLayout.razor` is the right home for it (after `MudMainContent`, before the closing `MudLayout`). Use `Pages.AllPages` for the link list to keep the source of truth in one place.
- **Scoped CSS:** these sections are home-page-specific decorative styling. Use `Home.razor.css` (scoped stylesheet) for anything that doesn't generalise; reserve `deepdrft-styles.css` for things genuinely shared across pages.
- **Prerequisite:** 0.1 (palette + fonts).
- **Constraint:** The footer added to `MainLayout.razor` renders on **every** page, including `/tracks`. Verify it does not collide with `AudioPlayerBar.razor`'s dock — the dock is the bottom-fixed surface; the footer must be in the document flow above it and not visually conflict when both are present. If conflict is unavoidable, hide the footer when the player is loaded (`@if (Player?.IsLoaded != true)`) and surface a question for Daniel before committing the suppression.
- **Constraint:** The footer added to `MainLayout.razor` renders on **every** page, including `/tracks`. The dock is the bottom-fixed surface; the footer must be in the document flow above it. **Confirmed:** the `AudioPlayerBar` already starts minimized (`_isMinimized = true`) and expands only on track selection — footer coexistence is acceptable as-is. No suppression logic needed.
### 0.5 Dark theme harmony pass
- **What:** Review the existing "Lowcountry Summer Nights" `PaletteDark` against the Phase 0 light palette and update it so the dark variant feels like a sibling of the new design vocabulary rather than the old one. The current dark palette is coral/sunset/firefly-gold over deep twilight — that may or may not still read as cohesive once the light side has been pulled to navy/green/off-white.
- **Why it matters:** Dark mode is a first-class affordance (cookie-persisted, prerender-aware). If the dark theme reads as a different product after 0.10.4 land, the toggle becomes a surprise rather than a preference. This sub-item is the explicit budget for re-harmonising it instead of letting drift accumulate.
- **Shape:**
- **Option A (conservative):** keep the coral/twilight palette, retune saturation and contrast so it sits next to the navy/green light theme without dissonance. Cheapest; preserves the existing dark-mode identity.
- **Option B (mirror):** rebuild the dark palette as a dark-navy ground (e.g. `--navy` itself as background, deeper navy as surface, `--green-accent` as primary accent, an off-white text). Visually consistent with the light theme; loses the bespoke "lowcountry" character.
- **Option C (third palette):** invent a new dark identity that descends from the light palette's lineage but feels like night rather than day — e.g. deep teal-green ground, warm-cream text, navy-coral accent. Most work; most distinctive.
- Recommend Option B for Phase 0 unless Daniel signals attachment to the coral/lowcountry identity. The dark theme then becomes "Drft After Dark" or similar — naming is a Daniel call.
- **Shape:** **Confirmed: Option B (mirror).** Rebuild the dark palette as a dark-navy ground — `--navy` as background, deeper navy as surface, `--green-accent` as primary accent, `--white` (#FAFAF8) as text. Visually consistent with the light theme; the "Lowcountry Summer Nights" coral/sunset identity is retired. Adjust contrast values so text and interactive targets meet WCAG thresholds on the darker ground — the light palette's tokens are a starting point, not a direct copy.
- **Prerequisite:** 0.10.4 ideally landed so the harmony evaluation has the actual artefact to look at. Can run in a sketch worktree against 0.1 alone if speed matters.
- **Constraint:** The dark-mode cookie + `PersistentComponentState` round-trip is untouched. Only the palette values in `PaletteDark` and the `.deepdrft-theme-dark` CSS-variable block change. Do not refactor the toggle, the cookie service, or the prerender bridge — those are tested and load-bearing.