diff --git a/PLAN.md b/PLAN.md index ec206e8..3f34c5f 100644 --- a/PLAN.md +++ b/PLAN.md @@ -462,10 +462,10 @@ across all three; the Session-doesn't-use-the-scaffold asymmetry is the key cons works around. **Architectural spine.** **One boolean, multiple observers** (memory: *one source, multiple views*). -Recommended home: **widen `WaveformVisualizerControlState` with a `TheaterMode` flag** (Option A — the -object is already scoped, session-persistent, observed via its `Changed` event, gated on the same +State home (OQ3, resolved): **widen `WaveformVisualizerControlState` with a `TheaterMode` flag** — +the object is already scoped, session-persistent, observed via its `Changed` event, gated on the same `LavaEnabled || WaveformEnabled` the Theater button reads, and *explicitly designed to widen by adding a -field + default*); the SRP-purist alternative is a dedicated `TheaterModeState` holder (Option B). The +field + default*. The **detail pages own only the content `@if`** (each page gates the fragments it renders, so the scaffold stays Theater-unaware and Session is covered the same way); the **player bar owns only the enlargement** (reads `CurrentTrack.Release` — `Title`/`ImagePath`/`EntryKey`/`Medium`, all already on the DTO — and @@ -482,17 +482,14 @@ existing theme-aware aliases (`--deepdrft-page-surface`/`-text`/`-text-muted`), visible only when `LavaEnabled || WaveformEnabled`, disabled until interactive, with an on/off active state. Material `Theaters` glyph for v1 (bespoke `DDIcons` deferred — Phase 17 OQ7 precedent). -**Open questions for Daniel (spec §9) — none block a first cut, but several are genuine product calls:** -(OQ1) Theater icon — Material `Theaters` vs. bespoke (recommend Material now); (OQ2) bar enlargement when -nothing is playing — page's release vs. playing-release-only (recommend playing-only, keeps the seam -clean); (OQ3) state home — Option A widen vs. Option B dedicated holder; (OQ4) back link stays in Theater -(recommend keep — it's navigation chrome); (OQ5) persistence — session-scoped/reset-on-reload vs. cookie -(recommend session-scoped, matches visualizer-state precedent); (OQ6) Theater on the home hero/NowPlaying -panel too, or detail-pages-only (recommend detail-pages-only for v1, as scoped). +**Open questions — all six resolved (Daniel, 2026-06-20; spec §9).** OQ1: Material `Theaters` glyph for +v1. OQ2: playing-release only — bar stays a pure function of player state. OQ3: Option A — widen +`WaveformVisualizerControlState` with a `TheaterMode` flag. OQ4: top action row (back, lava, theater) +stays visible — it's controls, not content. OQ5: session-scoped, resets to OFF on fresh page load. +OQ6: detail-pages-only for v1; no Theater affordance on the home hero. -**Status: proposed — awaiting Daniel sign-off on §9 before scoping waves.** Cold-start once signed off; -no dependency on any in-flight phase (Phases 11/16/17 — the player bar, queue, and visualizer it builds -on — are all complete). +**Status: scoped and approved — Phase 20, Wave 1.** Cold-start; no dependency on any in-flight phase +(Phases 11/16/17 — the player bar, queue, and visualizer it builds on — are all complete). --- diff --git a/product-notes/phase-20-theater-mode.md b/product-notes/phase-20-theater-mode.md index 3b71417..99f277a 100644 --- a/product-notes/phase-20-theater-mode.md +++ b/product-notes/phase-20-theater-mode.md @@ -1,6 +1,6 @@ # Phase 20 — Theater Mode (public Release Detail views) -Product spec. Status: **proposed, awaiting Daniel sign-off on the open questions in §9.** +Product spec. Status: **scoped and approved for implementation — Phase 20, Wave 1** (Daniel sign-off 2026-06-20; all §9 open questions resolved). Surface: **public listener site only** (`DeepDrftPublic` / `DeepDrftPublic.Client`). No CMS (`DeepDrftManager`) change. No API, data, or schema change — Theater Mode is a pure presentation-layer feature riding data the player already carries. @@ -72,10 +72,10 @@ this. 4. **Disabled until interactive** (`!RendererInfo.IsInteractive`) — same guard the lava-lamp button and Play buttons already carry, so it does nothing during prerender. -**Iconography:** Material `Theaters` (a film-strip glyph) is the obvious stock choice and reads as -"theater" immediately. A bespoke `DDIcons` glyph in the hand-rolled house style is the higher-craft -option but is **not** required for v1 (this matches the Phase 17 OQ7 precedent — Material icons now, -bespoke later). **Open question OQ1 (§9).** +**Iconography:** Material `Theaters` (a film-strip glyph). A bespoke `DDIcons` glyph in the +hand-rolled house style is the higher-craft option but is **not** required for v1 (this matches the +Phase 17 OQ7 precedent — Material icons now, bespoke later). **Resolved: Material `Theaters` for v1 +(OQ1, Daniel 2026-06-20).** --- @@ -134,13 +134,10 @@ state without the detail page reaching across to it. **Edge — Theater ON but nothing playing:** the bar's enlargement keys off `CurrentTrack?.Release`. If no track is playing (the listener opened the page and toggled Theater without pressing play), there is no -current release to surface in the bar. **Open question OQ2 (§9):** does Theater Mode surface *the page's* -release in the bar even when not playing (the page knows its release), or only the *playing* release -(simpler, but the bar shows nothing extra until play starts)? Recommendation: **playing-release only** — -keeps the bar a pure function of player state and avoids a detail-page→bar data push that would -re-entangle the two. The listener who toggles Theater is almost always already listening; the visualizer -itself is blank until a track resolves, so a blank-ish enlarged bar in that rare pre-play window is -coherent. +current release to surface in the bar. **Resolved (OQ2, Daniel 2026-06-20): playing-release only** — +the bar stays a pure function of player state; no detail-page→bar data push. The listener who toggles +Theater is almost always already listening; the visualizer itself is blank until a track resolves, so a +blank-ish enlarged bar in that rare pre-play window is coherent. --- @@ -174,11 +171,11 @@ Two viable homes for the boolean: (`LavaEnabled || WaveformEnabled`) to know whether to show the button, so the two are coupled at the read site anyway. -**Steer: Option A.** The visualizer-control state is already the "how the visualizer presents" object, +**Resolved (OQ3, Daniel 2026-06-20): Option A** — widen `WaveformVisualizerControlState` with a +`TheaterMode` flag. The visualizer-control state is already the "how the visualizer presents" object, Theater Mode is a visualizer-presentation concern, and the object was explicitly designed to widen this -way. Option B is the defensible SRP-purist alternative if Daniel wants the visualizer dials kept -pristine. **Open question OQ3 (§9).** Final structural call is staff-engineer's at implementation -(matching the standing convention on `IQueueService`-shape decisions). +way. Final structural call is staff-engineer's at implementation (matching the standing convention on +`IQueueService`-shape decisions). **Why this satisfies SOLID / the "cleanly separated concerns" constraint:** - **Single source of truth, multiple observers.** One boolean; the three pages observe it for the @@ -247,31 +244,26 @@ convention. **No new per-component dark overrides.** Concretely: --- -## 9. Open questions (Daniel decisions, not implementation calls) +## 9. Open questions — all resolved (Daniel, 2026-06-20) -- **OQ1 — Theater toggle icon.** Material `Theaters` (film-strip) for v1, or commission a bespoke - `DDIcons` glyph in the hand-rolled house style? *Recommend: Material `Theaters` now, bespoke deferred - (Phase 17 OQ7 precedent).* — **product call.** -- **OQ2 — bar enlargement when nothing is playing.** Surface the *page's* release in the bar even with no - current track (needs a page→bar data path), or only the *playing* release (bar stays a pure function of - player state)? *Recommend: playing-release only.* — **product + architecture call; the recommendation - keeps the SOLID seam clean, so it leans toward an implementation default unless Daniel wants the - page's release shown pre-play.** -- **OQ3 — state home.** Extend `WaveformVisualizerControlState` with `TheaterMode` (Option A, - recommended) or a dedicated `TheaterModeState` holder (Option B, SRP-purist)? — *Structural; - staff-engineer's final call, but Daniel may have a taste here.* -- **OQ4 — does the back link stay in Theater Mode?** Recommendation keeps it (it is navigation chrome, - not release content). Confirm Daniel agrees the top action row (back + lava + theater) is "controls," - not "content." *Recommend: keep.* — **product call, low-stakes.** -- **OQ5 — persistence scope.** Theater Mode follows the visualizer-state convention: persists across SPA - navigation within a session, resets to OFF on a fresh page load (F5). Confirm that is the wanted - behavior (vs. a cookie that remembers Theater across reloads). *Recommend: session-scoped, reset on - reload — matches the visualizer-control-state precedent; no cookie round-trip.* — **product call.** -- **OQ6 — Theater on the home hero / NowPlaying panel?** The `WaveformVisualizerControlPopover` also - appears on the home hero's NowPlaying panel (mode C). This spec scopes Theater Mode to the **three - Release Detail views only** (Daniel's framing). Flag: should the home hero get a Theater affordance - too, or is it deliberately detail-pages-only? *Recommend: detail-pages-only for v1, as scoped.* — - **product call, adjacent.** +All six open questions are resolved. Every resolution matches the spec's recommendation. + +- **OQ1 — Theater toggle icon. RESOLVED: Material `Theaters` (film-strip) for v1.** Bespoke `DDIcons` + glyph deferred (Phase 17 OQ7 precedent). +- **OQ2 — bar enlargement when nothing is playing. RESOLVED: playing-release only.** The bar stays a + pure function of player state; no page→bar data path. The listener who opens Theater without pressing + play sees a blank-ish enlarged bar — coherent, because the visualizer itself is also blank. +- **OQ3 — state home. RESOLVED: Option A — widen `WaveformVisualizerControlState` with a `TheaterMode` + flag.** Theater Mode is a visualizer-presentation concern; the object was explicitly designed to widen + this way. Staff-engineer makes the final structural call at implementation. +- **OQ4 — back link in Theater Mode. RESOLVED: stays visible.** The top action row (back, lava-lamp, + theater) is controls, not release content — it remains in Theater Mode. +- **OQ5 — persistence scope. RESOLVED: session-scoped, resets to OFF on fresh page load.** Persists + across SPA navigation within a session; a full reload (F5) resets it to OFF. Matches the + visualizer-control-state precedent; no cookie round-trip. +- **OQ6 — Theater on the home hero / NowPlaying panel. RESOLVED: detail-pages-only for v1.** The three + Release Detail views are the scope; the home hero's `WaveformVisualizerControlPopover` does not get a + Theater affordance in this phase. --- @@ -295,7 +287,7 @@ convention. **No new per-component dark overrides.** Concretely: 8. No API / data / schema change. No CMS change. The enlarged bar reads only `CurrentTrack.Release` fields the DTO already carries. 9. Theater Mode persists across SPA navigation within a session and resets to OFF on a fresh page load - (per OQ5, if confirmed). + (OQ5, confirmed). ---