From 7483eb390188005e54d1e5f1e9d2789b64ad8fe4 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Sun, 19 Jul 2026 21:50:08 -0500 Subject: chore: version active working artifacts I made working/ a versioned home for in-progress project artifacts and moved disposable scratch to temp/. This preserves the full music UI design history and the deferred EAT XTWINOPS upstream patch. --- .gitattributes | 2 + .gitignore | 4 +- working/eat-sixel-patch/eat-xtwinops.patch | 46 + .../eat-sixel-patch/rulesets-companion-note.org | 5 + .../eat-sixel-patch/takuzu-original-bug-report.org | 17 + ...7-19-music-config-ui-remodel-render-fixture.svg | 87 ++ .../2026-07-19-music-config-ui-remodel-spec.org | 923 +++++++++++++ working/music-svg-app-design/README.org | 426 ++++++ .../assets/vinyl-placeholder.svg | 20 + working/music-svg-app-design/concept-board.html | 25 + .../concepts/01-champagne-receiver.png | Bin 0 -> 2064469 bytes .../concepts/02-le-mans-night-cluster.png | Bin 0 -> 2451131 bytes .../concepts/03-geneva-playback-chronograph.png | Bin 0 -> 3097288 bytes .../concepts/04-mastering-room-reel-console.png | Bin 0 -> 2243918 bytes .../concepts/05-perpetual-calendar-salon.png | Bin 0 -> 2360111 bytes .../06-transatlantic-broadcast-navigator.png | Bin 0 -> 1897511 bytes .../07-functional-black-glass-receiver.png | Bin 0 -> 1890841 bytes .../concepts/08-functional-black-glass-flipped.png | Bin 0 -> 1804000 bytes .../concepts/09-functional-black-glass-retro.png | Bin 0 -> 2226236 bytes .../concepts/10-warm-black-glass-player-volume.png | Bin 0 -> 1872741 bytes .../11-illuminated-black-glass-controls.png | Bin 0 -> 1950069 bytes .../12-consolidated-functional-receiver.png | Bin 0 -> 1884863 bytes .../13-black-silver-chronograph-receiver.png | Bin 0 -> 2119461 bytes .../14-corrected-luxury-chronograph-receiver.png | Bin 0 -> 2061668 bytes .../concepts/15-champagne-brass-digital-hifi.png | Bin 0 -> 2010447 bytes .../16-champagne-aluminum-radio-groups.png | Bin 0 -> 1995487 bytes .../concepts/17-dupre-coltrane-scrollbar.png | Bin 0 -> 2027803 bytes .../concepts/18-dupre-branding-control-study.png | Bin 0 -> 2071824 bytes .../concepts/19a-dupre-playlist-state.png | Bin 0 -> 2013519 bytes .../concepts/19b-dupre-radio-state.png | Bin 0 -> 1954409 bytes .../20-dupre-playlist-radio-comparison.png | Bin 0 -> 3976510 bytes .../concepts/20a-dupre-long-playlist.png | Bin 0 -> 2051749 bytes .../concepts/20b-dupre-compact-radio.png | Bin 0 -> 2015466 bytes .../21-dupre-semantic-controls-comparison.png | Bin 0 -> 4015119 bytes .../concepts/21a-dupre-mode-lamps-playlist.png | Bin 0 -> 2084254 bytes .../concepts/21b-dupre-two-on-air-radio.png | Bin 0 -> 2015323 bytes .../concepts/22-dupre-identity-bay-comparison.png | Bin 0 -> 4029125 bytes .../concepts/22a-dupre-identity-bay-playlist.png | Bin 0 -> 2091641 bytes .../concepts/22b-dupre-identity-bay-radio.png | Bin 0 -> 2024997 bytes .../concepts/23-dupre-swapped-info-comparison.png | Bin 0 -> 3733539 bytes .../concepts/23a-dupre-swapped-info-playlist.png | Bin 0 -> 1959413 bytes .../concepts/23b-dupre-swapped-info-radio.png | Bin 0 -> 1860779 bytes .../concepts/24-dupre-full-brass-vu-comparison.png | Bin 0 -> 3843296 bytes .../concepts/24a-dupre-full-brass-vu-playlist.png | Bin 0 -> 2013020 bytes .../concepts/24b-dupre-full-brass-vu-radio.png | Bin 0 -> 1911285 bytes .../25-dupre-seamless-flush-comparison.png | Bin 0 -> 3847925 bytes .../concepts/25a-dupre-seamless-flush-playlist.png | Bin 0 -> 2037192 bytes .../concepts/25b-dupre-seamless-flush-radio.png | Bin 0 -> 1895006 bytes .../26-dupre-studios-rounded-chrome-comparison.png | Bin 0 -> 3795106 bytes .../26a-dupre-studios-rounded-chrome-playlist.png | Bin 0 -> 1979416 bytes .../26b-dupre-studios-rounded-chrome-radio.png | Bin 0 -> 1896697 bytes ...re-studios-leather-analog-header-comparison.png | Bin 0 -> 4153861 bytes ...upre-studios-leather-analog-header-playlist.png | Bin 0 -> 2148939 bytes ...b-dupre-studios-leather-analog-header-radio.png | Bin 0 -> 2101436 bytes ...-dupre-studios-balanced-controls-comparison.png | Bin 0 -> 4163731 bytes ...8a-dupre-studios-balanced-controls-playlist.png | Bin 0 -> 2144998 bytes .../28b-dupre-studios-balanced-controls-radio.png | Bin 0 -> 2111994 bytes .../29a-dupre-studios-brass-seek-playlist.png | Bin 0 -> 2176613 bytes .../29a-dupre-studios-brass-seek-playlist.xcf | Bin 0 -> 2303994 bytes .../30a-dupre-studios-user-refined-playlist.png | Bin 0 -> 2288732 bytes .../music-svg-app-design/music-svg-directions.html | 35 + ...026-07-19-music-config-ui-remodel-benchmark.org | 61 + ...-07-19-music-config-ui-remodel-prototype-1.html | 1450 ++++++++++++++++++++ .../references/29-alignment-guide.png | Bin 0 -> 2328747 bytes .../references/dupre-gallery-tall.png | Bin 0 -> 2154502 bytes .../references/dupre-gallery.png | Bin 0 -> 287964 bytes .../references/waybar-redesign-tall.png | Bin 0 -> 735385 bytes .../references/waybar-redesign.png | Bin 0 -> 205084 bytes 68 files changed, 3100 insertions(+), 1 deletion(-) create mode 100644 .gitattributes create mode 100644 working/eat-sixel-patch/eat-xtwinops.patch create mode 100644 working/eat-sixel-patch/rulesets-companion-note.org create mode 100644 working/eat-sixel-patch/takuzu-original-bug-report.org create mode 100644 working/music-svg-app-design/2026-07-19-music-config-ui-remodel-render-fixture.svg create mode 100644 working/music-svg-app-design/2026-07-19-music-config-ui-remodel-spec.org create mode 100644 working/music-svg-app-design/README.org create mode 100644 working/music-svg-app-design/assets/vinyl-placeholder.svg create mode 100644 working/music-svg-app-design/concept-board.html create mode 100644 working/music-svg-app-design/concepts/01-champagne-receiver.png create mode 100644 working/music-svg-app-design/concepts/02-le-mans-night-cluster.png create mode 100644 working/music-svg-app-design/concepts/03-geneva-playback-chronograph.png create mode 100644 working/music-svg-app-design/concepts/04-mastering-room-reel-console.png create mode 100644 working/music-svg-app-design/concepts/05-perpetual-calendar-salon.png create mode 100644 working/music-svg-app-design/concepts/06-transatlantic-broadcast-navigator.png create mode 100644 working/music-svg-app-design/concepts/07-functional-black-glass-receiver.png create mode 100644 working/music-svg-app-design/concepts/08-functional-black-glass-flipped.png create mode 100644 working/music-svg-app-design/concepts/09-functional-black-glass-retro.png create mode 100644 working/music-svg-app-design/concepts/10-warm-black-glass-player-volume.png create mode 100644 working/music-svg-app-design/concepts/11-illuminated-black-glass-controls.png create mode 100644 working/music-svg-app-design/concepts/12-consolidated-functional-receiver.png create mode 100644 working/music-svg-app-design/concepts/13-black-silver-chronograph-receiver.png create mode 100644 working/music-svg-app-design/concepts/14-corrected-luxury-chronograph-receiver.png create mode 100644 working/music-svg-app-design/concepts/15-champagne-brass-digital-hifi.png create mode 100644 working/music-svg-app-design/concepts/16-champagne-aluminum-radio-groups.png create mode 100644 working/music-svg-app-design/concepts/17-dupre-coltrane-scrollbar.png create mode 100644 working/music-svg-app-design/concepts/18-dupre-branding-control-study.png create mode 100644 working/music-svg-app-design/concepts/19a-dupre-playlist-state.png create mode 100644 working/music-svg-app-design/concepts/19b-dupre-radio-state.png create mode 100644 working/music-svg-app-design/concepts/20-dupre-playlist-radio-comparison.png create mode 100644 working/music-svg-app-design/concepts/20a-dupre-long-playlist.png create mode 100644 working/music-svg-app-design/concepts/20b-dupre-compact-radio.png create mode 100644 working/music-svg-app-design/concepts/21-dupre-semantic-controls-comparison.png create mode 100644 working/music-svg-app-design/concepts/21a-dupre-mode-lamps-playlist.png create mode 100644 working/music-svg-app-design/concepts/21b-dupre-two-on-air-radio.png create mode 100644 working/music-svg-app-design/concepts/22-dupre-identity-bay-comparison.png create mode 100644 working/music-svg-app-design/concepts/22a-dupre-identity-bay-playlist.png create mode 100644 working/music-svg-app-design/concepts/22b-dupre-identity-bay-radio.png create mode 100644 working/music-svg-app-design/concepts/23-dupre-swapped-info-comparison.png create mode 100644 working/music-svg-app-design/concepts/23a-dupre-swapped-info-playlist.png create mode 100644 working/music-svg-app-design/concepts/23b-dupre-swapped-info-radio.png create mode 100644 working/music-svg-app-design/concepts/24-dupre-full-brass-vu-comparison.png create mode 100644 working/music-svg-app-design/concepts/24a-dupre-full-brass-vu-playlist.png create mode 100644 working/music-svg-app-design/concepts/24b-dupre-full-brass-vu-radio.png create mode 100644 working/music-svg-app-design/concepts/25-dupre-seamless-flush-comparison.png create mode 100644 working/music-svg-app-design/concepts/25a-dupre-seamless-flush-playlist.png create mode 100644 working/music-svg-app-design/concepts/25b-dupre-seamless-flush-radio.png create mode 100644 working/music-svg-app-design/concepts/26-dupre-studios-rounded-chrome-comparison.png create mode 100644 working/music-svg-app-design/concepts/26a-dupre-studios-rounded-chrome-playlist.png create mode 100644 working/music-svg-app-design/concepts/26b-dupre-studios-rounded-chrome-radio.png create mode 100644 working/music-svg-app-design/concepts/27-dupre-studios-leather-analog-header-comparison.png create mode 100644 working/music-svg-app-design/concepts/27a-dupre-studios-leather-analog-header-playlist.png create mode 100644 working/music-svg-app-design/concepts/27b-dupre-studios-leather-analog-header-radio.png create mode 100644 working/music-svg-app-design/concepts/28-dupre-studios-balanced-controls-comparison.png create mode 100644 working/music-svg-app-design/concepts/28a-dupre-studios-balanced-controls-playlist.png create mode 100644 working/music-svg-app-design/concepts/28b-dupre-studios-balanced-controls-radio.png create mode 100644 working/music-svg-app-design/concepts/29a-dupre-studios-brass-seek-playlist.png create mode 100644 working/music-svg-app-design/concepts/29a-dupre-studios-brass-seek-playlist.xcf create mode 100644 working/music-svg-app-design/concepts/30a-dupre-studios-user-refined-playlist.png create mode 100644 working/music-svg-app-design/music-svg-directions.html create mode 100644 working/music-svg-app-design/prototypes/2026-07-19-music-config-ui-remodel-benchmark.org create mode 100644 working/music-svg-app-design/prototypes/2026-07-19-music-config-ui-remodel-prototype-1.html create mode 100644 working/music-svg-app-design/references/29-alignment-guide.png create mode 100644 working/music-svg-app-design/references/dupre-gallery-tall.png create mode 100644 working/music-svg-app-design/references/dupre-gallery.png create mode 100644 working/music-svg-app-design/references/waybar-redesign-tall.png create mode 100644 working/music-svg-app-design/references/waybar-redesign.png diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..fd4eb2ad --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Unified diff context lines can carry a required trailing space marker. +working/**/*.patch whitespace=-blank-at-eol diff --git a/.gitignore b/.gitignore index 16ada780..b92678f9 100644 --- a/.gitignore +++ b/.gitignore @@ -110,4 +110,6 @@ todo.org # Claude Code: task archive (follows todo file privacy) /archive/task-archive.org takuzu-stats.eld -/working/ + +# disposable project-local scratch; active task artifacts live in versioned working/ +/temp/ diff --git a/working/eat-sixel-patch/eat-xtwinops.patch b/working/eat-sixel-patch/eat-xtwinops.patch new file mode 100644 index 00000000..4347d729 --- /dev/null +++ b/working/eat-sixel-patch/eat-xtwinops.patch @@ -0,0 +1,46 @@ +--- a/eat.el ++++ b/eat.el +@@ -2809,6 +2809,33 @@ + (funcall (eat--t-term-input-fn eat--t-term) eat--t-term + "\e[>0;0;0c"))))) + ++(defun eat--t-send-window-size-report (n) ++ "Respond to XTWINOPS window size report request N. ++ ++N is 14 (text area size in pixels), 16 (cell size in pixels) or 18 ++\(text area size in characters). Other operations are ignored. ++Multiplexers like tmux send \\='CSI 14 t\\=' to discover the cell ++pixel size they need before they will emit Sixel to a terminal." ++ (let ((disp (eat--t-term-display eat--t-term))) ++ (pcase n ++ (14 ++ (funcall (eat--t-term-input-fn eat--t-term) eat--t-term ++ (format "\e[4;%i;%it" ++ (* (eat--t-disp-height disp) ++ (eat--t-term-char-height eat--t-term)) ++ (* (eat--t-disp-width disp) ++ (eat--t-term-char-width eat--t-term))))) ++ (16 ++ (funcall (eat--t-term-input-fn eat--t-term) eat--t-term ++ (format "\e[6;%i;%it" ++ (eat--t-term-char-height eat--t-term) ++ (eat--t-term-char-width eat--t-term)))) ++ (18 ++ (funcall (eat--t-term-input-fn eat--t-term) eat--t-term ++ (format "\e[8;%i;%it" ++ (eat--t-disp-height disp) ++ (eat--t-disp-width disp))))))) ++ + (defun eat--t-send-graphics-attrs (attr operation) + "Send graphics attributes. + +@@ -3632,6 +3659,9 @@ + ;; CSI s. + (`((?s) nil nil) + (eat--t-save-cur)) ++ ;; CSI t. ++ (`((?t) nil ((,n))) ++ (eat--t-send-window-size-report n)) + ;; CSI u. + (`((?u) nil nil) + (eat--t-restore-cur))))))) diff --git a/working/eat-sixel-patch/rulesets-companion-note.org b/working/eat-sixel-patch/rulesets-companion-note.org new file mode 100644 index 00000000..2df33273 --- /dev/null +++ b/working/eat-sixel-patch/rulesets-companion-note.org @@ -0,0 +1,5 @@ +#+TITLE: EAT XTWINOPS patch companion note +#+SOURCE: from rulesets +#+DATE: 2026-07-13 10:58:54 -0500 + +EAT XTWINOPS patch (companion file eat-xtwinops.patch, sent separately just now): verified live on ratio 2026-07-13, this makes sixel images render AND persist in tmux inside EAT. Root cause chain: tmux 3.7b has native sixel but refuses to transmit unless it knows the client's cell pixel size; it asks via CSI 14 t (XTWINOPS), which EAT 0.9.4 silently ignores (its CSI dispatch has no 't' case). The patch adds eat--t-send-window-size-report answering CSI 14/16/18 t from eat--t-term-char-width/height and the display dims — same fields EAT's own XTSMGRAPHICS reply already uses. With it, tmux learns the geometry at client attach, ingests raw sixel into its grid, and re-emits on every redraw — images survive window switches, scrolling, and resizing (Craig verified visually). Needs on the emacsd side: (1) a durable home for the patch — the elpa file is version-pinned, so likely a load-path shadow or an advice-free vendored fix, your call, plus wiring so both daily drivers load it (velox verified ready: same tmux build, imagemagick present); (2) written test-first per testing.md when productionizing — this was a timeboxed spike, treat the diff as evidence not deliverable; (3) strongly consider sending it upstream to EAT (codeberg akib/emacs-eat) so 0.9.5+ ships it stock. tmux side is separate (two conf lines, handoff sent to dotfiles). Ask rulesets for the full investigation log if useful. diff --git a/working/eat-sixel-patch/takuzu-original-bug-report.org b/working/eat-sixel-patch/takuzu-original-bug-report.org new file mode 100644 index 00000000..02107a88 --- /dev/null +++ b/working/eat-sixel-patch/takuzu-original-bug-report.org @@ -0,0 +1,17 @@ +#+TITLE: Bug/investigate: images from Claude Code don't display in th +#+SOURCE: from takuzu +#+DATE: 2026-07-11 14:41:39 -0500 + +Bug/investigate: images from Claude Code don't display in the EAT terminal. + +Context: running Claude Code inside EAT (eat 0.9.4 from elpa). When the agent posts an image to the terminal, nothing renders — Craig can't see it. + +Finding: EAT *does* have Sixel image support. eat.el defines eat-sixel-scale, eat-sixel-aspect-ratio, eat-sixel-render-formats, and a full Sixel decode/render path (sixel-buffer, sixel-palette, sixel-render-format, etc.). So the capability exists; this isn't a plain 'EAT can't do images' limitation. + +Likely causes to check: +1. Protocol mismatch: Claude Code CLI probably emits the kitty graphics protocol or the iTerm2 inline-image protocol (OSC 1337), NOT Sixel. EAT renders Sixel only, so a kitty/iTerm image sequence is dropped. Confirm which protocol Claude Code uses (env like TERM, or its terminal-capability detection) and whether it can be told to emit Sixel. +2. Sixel render-format availability: eat-sixel-render-formats lists preferred render backends; if none is available in this Emacs build, Sixel silently won't display. Test EAT with a known-good sixel image (e.g. img2sixel output) to confirm EAT-side rendering works at all. + +Repro: in an EAT session, have Claude Code (or any tool) post an image; observe nothing renders. Next step: identify the emitted escape sequence (capture raw bytes) to confirm protocol. + +From the takuzu session, 2026-07-11 — surfaced because the agent kept posting game screenshots the terminal couldn't show. diff --git a/working/music-svg-app-design/2026-07-19-music-config-ui-remodel-render-fixture.svg b/working/music-svg-app-design/2026-07-19-music-config-ui-remodel-render-fixture.svg new file mode 100644 index 00000000..aad6f746 --- /dev/null +++ b/working/music-svg-app-design/2026-07-19-music-config-ui-remodel-render-fixture.svg @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + A CHICKEN WITH ITS HEAD CUT OFF — REMASTERED ANNIVERSARY EDITION + THE MAGNETIC FIELDS AND THE LONG-LOST ORCHESTRA + 69 LOVE SONGS: THE COMPLETE THREE-VOLUME COLLECTION + MERGE RECORDS + 1999 + + 01:30 + + + + 02:59 + + + + PLAYLIST + | + 69 LOVE SONGS — COMPLETE + 69 TRACKS + + + + + + 01ABSOLUTELY CUCKOO — THE MAGNETIC FIELDS02:02 + 02I DON’T BELIEVE IN THE SUN — THE MAGNETIC FIELDS02:50 + 03ALL MY LITTLE WORDS — THE MAGNETIC FIELDS02:03 + + + + 04A CHICKEN WITH ITS HEAD CUT OFF — THE MAGNETIC FIELDS02:59 + + + 05(I’M) DAZOTA — THE MAGNETIC FIELDS02:38 + 06I DON’T WANT TO GET OVER YOU — THE MAGNETIC FIELDS02:50 + 07COME BACK FROM SAN FRANCISCO — THE MAGNETIC FIELDS02:37 + 08THE LUCKIEST GUY ON THE LOWER EAST SIDE — THE MAGNETIC FIELDS01:32 + 09LET’S PRETEND WE’RE BUNNY RABBITS — THE MAGNETIC FIELDS02:10 + 10THE CACTUS WHERE YOUR HEART SHOULD BE — THE MAGNETIC FIELDS02:38 + 11I THINK I NEED A NEW HEART — THE MAGNETIC FIELDS02:58 + 12THE BOOK OF LOVE — THE MAGNETIC FIELDS02:56 + 13FIDO, YOUR LEASH IS TOO LONG — THE MAGNETIC FIELDS02:13 + 14HOW FUCKING ROMANTIC — THE MAGNETIC FIELDS00:58 + + + + + + + + + + + + + + + + + + + + + diff --git a/working/music-svg-app-design/2026-07-19-music-config-ui-remodel-spec.org b/working/music-svg-app-design/2026-07-19-music-config-ui-remodel-spec.org new file mode 100644 index 00000000..6e68e104 --- /dev/null +++ b/working/music-svg-app-design/2026-07-19-music-config-ui-remodel-spec.org @@ -0,0 +1,923 @@ +#+TITLE: Music Config UI Remodel — Spec +#+AUTHOR: Craig Jennings +#+DATE: 2026-07-19 +#+TODO: TODO | DONE +#+TODO: DRAFT READY DOING | IMPLEMENTED SUPERSEDED CANCELLED + +* DRAFT Music Config UI Remodel +:PROPERTIES: +:ID: bcbb9342-1884-4281-8821-89b06f6f8793 +:END: +- 2026-07-19 Sun @ 16:03:13 -0500 — drafted from the approved Dupre Studios design session. + +** Prototype iterations + +The design session started with working HTML directions, moved through six +distinct visual concepts, and then refined one receiver layout through paired +playlist/radio boards. The last board is Craig's GIMP refinement and is the +visual authority for this spec. + +- [[file:music-svg-directions.html][Initial working SVG directions]] +- [[file:concept-board.html][Six-direction comparison board]] +- [[file:concepts/01-champagne-receiver.png][01 Champagne Receiver]] +- [[file:concepts/02-le-mans-night-cluster.png][02 Le Mans Night Cluster]] +- [[file:concepts/03-geneva-playback-chronograph.png][03 Geneva Playback Chronograph]] +- [[file:concepts/04-mastering-room-reel-console.png][04 Mastering Room Reel Console]] +- [[file:concepts/05-perpetual-calendar-salon.png][05 Perpetual Calendar Salon]] +- [[file:concepts/06-transatlantic-broadcast-navigator.png][06 Transatlantic Broadcast Navigator]] +- [[file:concepts/07-functional-black-glass-receiver.png][07 Functional black-glass receiver]] +- [[file:concepts/08-functional-black-glass-flipped.png][08 Playlist-flipped receiver]] +- [[file:concepts/09-functional-black-glass-retro.png][09 Warmer retro receiver]] +- [[file:concepts/10-warm-black-glass-player-volume.png][10 Player-volume receiver]] +- [[file:concepts/11-illuminated-black-glass-controls.png][11 Illuminated controls]] +- [[file:concepts/12-consolidated-functional-receiver.png][12 Consolidated functional receiver]] +- [[file:concepts/13-black-silver-chronograph-receiver.png][13 Black-silver chronograph]] +- [[file:concepts/14-corrected-luxury-chronograph-receiver.png][14 Corrected luxury chronograph]] +- [[file:concepts/15-champagne-brass-digital-hifi.png][15 Champagne digital hi-fi]] +- [[file:concepts/16-champagne-aluminum-radio-groups.png][16 Explicit radio grouping]] +- [[file:concepts/17-dupre-coltrane-scrollbar.png][17 Long-playlist and scrollbar stress test]] +- [[file:concepts/18-dupre-branding-control-study.png][18 Branding and control study]] +- [[file:concepts/19a-dupre-playlist-state.png][19a Playlist state]] and [[file:concepts/19b-dupre-radio-state.png][19b radio state]] +- [[file:concepts/20-dupre-playlist-radio-comparison.png][20 Long playlist / compact radio comparison]] +- [[file:concepts/21-dupre-semantic-controls-comparison.png][21 Semantic control comparison]] +- [[file:concepts/22-dupre-identity-bay-comparison.png][22 Identity-bay comparison]] +- [[file:concepts/23-dupre-swapped-info-comparison.png][23 Swapped information comparison]] +- [[file:concepts/24-dupre-full-brass-vu-comparison.png][24 Full-brass VU comparison]] +- [[file:concepts/25-dupre-seamless-flush-comparison.png][25 Seamless flush comparison]] +- [[file:concepts/26-dupre-studios-rounded-chrome-comparison.png][26 Dupre Studios comparison]] +- [[file:concepts/27-dupre-studios-leather-analog-header-comparison.png][27 Leather and analog-header comparison]] +- [[file:concepts/28-dupre-studios-balanced-controls-comparison.png][28 Balanced-control comparison]] +- [[file:concepts/29a-dupre-studios-brass-seek-playlist.png][29 Brass seek-thumb pass]] +- [[file:concepts/30a-dupre-studios-user-refined-playlist.png][30 Craig's near-final playlist board (visual authority)]] +- [[file:prototypes/2026-07-19-music-config-ui-remodel-prototype-1.html][31 Functional local-playlist / radio prototype (acceptance candidate)]] + +* Metadata +| Status | Not ready — first review found one functional-prototype blocker | +|----------+------------------------------------------------------------------------| +| Owner | Craig Jennings | +|----------+------------------------------------------------------------------------| +| Reviewer | Craig Jennings | +|----------+------------------------------------------------------------------------| +| Related | [[file:../../todo.org][music: SVG player application design and delivery]]; [[file:../../docs/specs/2026-07-06-fancy-music-player-ui-spec.org][implemented fancy player spec]]; [[file:../../docs/specs/music-config-without-emms-spec.org][EMMS-free architecture spec]] | +|----------+------------------------------------------------------------------------| + +* Summary + +Replace the current text-and-image EMMS playlist surface with a realistic +Dupre Studios receiver rendered inside Emacs. The interface uses a raster skin +for leather, glass, brass, and machined controls, then draws all changing +information and illumination in SVG. Emacs Lisp remains the application +runtime and maps the SVG surface to the existing music-config commands. + +The remodel preserves the plain and fancy text views as fallbacks. It does not +change M3U ownership, radio-browser behavior, or the current EMMS playback model. + +* Problem / Context + +The implemented fancy player improved names, artwork, and progress, but it is +still a text playlist with a multi-line overlay. It cannot present the player +as one coherent instrument. Controls are key hints rather than controls, +playlist management is visually detached from playback, and active state is +limited to text faces and a character-cell progress bar. + +Craig wants a bottom-docked application that looks like a manufactured object: +black leather, black glass, champagne brass, lit analog meters, and discreet +controls. The beauty has to explain state. A lamp, depressed key, moving +needle, seek position, or selected row must correspond to real music-config or +mpv behavior. Decorative AM/FM, tone, power, reload, manual URL, and other +unsupported faceplate controls are prohibited. + +The final 1916×821 board settles the visual direction. The remaining design +problem is how to preserve its realism without baking live state into a picture. +An all-vector redraw would lose much of the leather and metal detail. A single +clickable PNG would preserve the appearance but freeze track data, meter state, +playlist rows, and button feedback. The chosen design separates the physical +object from its information and behavior. + +* Goals and Non-Goals + +** Goals + +- Match Craig's near-final board closely enough that the running player reads as + the same manufactured receiver, not a simplified diagram of it. +- Preserve the full music-config workflow: playback, seek, player volume, + playlist browsing and persistence, radio search, repeat/single/random/consume, + reordering, add, new, load, save, and delete. +- Make every visible state honest. Meter needles use real program levels, + volume lamps use mpv volume, progress uses mpv position, and mode lamps use + current mode state. +- Keep the hot path compact: album information and controls on the left, + fourteen playlist rows and playlist actions on the right. +- Keep keyboard operation complete while adding direct mouse interaction. +- Preserve the existing text render for TTY frames, unsupported SVG builds, and + opt-out/rollback. +- Keep the renderer independent of EMMS objects so the planned EMMS-free/VAMP + work can replace the controller without replacing the visual layer. + +** Non-Goals + +- No music library browser, tag editor, lyrics view, waveform editor, or album + collection database. +- No streaming-service integration. +- No fake receiver functions such as AM/FM tuning, bass, treble, speakers, or + power. +- No permanent faceplate controls for reload, editing the M3U file, or manual URL + entry. Existing keyboard and M-x access may remain. +- No all-vector imitation of leather, brushed metal, or photographic reflections. +- No EMMS removal or VAMP extraction in this project. Those remain separate + architecture efforts. +- No alternate narrow/mobile layout in v1. The player scales as one panoramic + instrument. + +** Scope tiers + +- v1: neutral raster skin, SVG renderer, dedicated graphical view buffer, + complete keyboard/mouse command surface, playlist viewport, seek, persistent + mpv volume, real stereo VU telemetry, local-file and radio states, diagnostics, + fallbacks, tests, and live verification. +- Out of scope: library browsing, ratings, per-track menus, editable metadata, + alternate skins, responsive reflow, and remote control. +- vNext: multiple visual skins, a narrower alternate layout, richer motion + transitions, and reuse in a future standalone VAMP package. + +* Design + +** User view + +F10 opens the player in the existing bottom side-window position. In a +graphical frame with the remodel enabled, the buffer is the Dupre Studios +receiver. The same keys still work. The visible buttons also work with the +mouse, the playlist scrolls inside its fourteen-row aperture, and selecting a +row starts that track. + +A local file shows album art, title, artist, album, label, and year on separate +lines when those fields exist. It shows elapsed and total time with a draggable +seek control. A live station shows station art and two ON AIR indications: one +under the art and one in the active station row. It never shows a seek control +or invented time for a stream. Missing metadata produces no placeholder word. + +The interface behaves like hardware. Play/Pause sits depressed and glows green +while playing. Momentary transport controls brighten while pressed. Active +play modes illuminate the circumference of their brass buttons. Volume lamps +fill continuously to the current mpv volume. VU needles move from the actual +left and right audio levels. + +The interaction model is available in the [[file:prototypes/2026-07-19-music-config-ui-remodel-prototype-1.html][functional browser prototype]]. It +switches between a 69-track local fixture and an 18-station radio fixture and +wires transport, playback modes, radio search, playlist actions, row selection, +seek, volume, wheel/keyboard browsing, scrollbar drag, empty state, and delete +confirmation. Its built-in twelve-check behavior pass is green. Craig's +hands-on acceptance remains the last prototype gate. + +** Research and visual sources + +The design session compared NAD restraint, Marshall's black-and-brass control +language, McIntosh black glass and meter hierarchy, vintage stereo transport +controls, automobile instrument clusters, and black/silver chronographs. The +useful lessons were consistent: controls need one visual family, status lights +need stable color meaning, labels belong on the faceplate, and ornament should +make state easier to read. + +The local Dupre references are the implementation sources: + +- [[file:references/dupre-gallery.png][Dupre component gallery capture]] +- [[file:references/waybar-redesign.png][Waybar redesign capture]] +- [[file:README.org][Design-session decisions and critique log]] +- [[file:concepts/30a-dupre-studios-user-refined-playlist.png][Near-final visual authority]] +- [[file:../../../code/archsetup/docs/prototypes/gallery-widget.el][svg.el Dupre renderer proof of concept]] + +** Canonical geometry + +The source canvas is 1916×821 with a viewBox of =0 0 1916 821=. The renderer +preserves that aspect ratio and scales it to the available window width. It +does not reflow the playlist under the controls or move controls at runtime. +Extra vertical room stays black below the instrument. A window too short for +legible rendering falls back to the existing fancy text view rather than +shrinking controls into unusable targets. + +Craig's final board defines the visual positions. Phase 1 records them in one +geometry table, including every visual rectangle, label anchor, hit target, and +playlist row. Rendering and hit testing use the same constants. No second +hand-maintained map is allowed. + +The principal regions are: + +| Region | Approximate source bounds | +|------------------------+---------------------------| +| Complete instrument | 0,0 to 1916,821 | +| Player upper glass | 50,50 to 1170,368 | +| Lower brass deck | 69,372 to 1147,744 | +| Playlist glass | 1170,52 to 1862,744 | +| Branding field | 150,115 to 500,275 | +| Artwork | 609,108 to 755,281 | +| Metadata | 780,100 to 1125,275 | +| Seek / ON AIR line | 608,302 to 1125,330 | +| Playlist viewport | 1175,126 to 1835,658 | +| Playlist actions | 1173,671 to 1850,733 | + +Exact measured values replace these orientation bounds in the geometry table. + +** Rendering layers + +The SVG is a scene graph with four layers. + +1. The physical shell is raster. It contains the leather chassis, compressed + seams, black glass texture, fine low-contrast champagne micro-brush, recessed + grooves, fixed branding, + engraved labels, neutral control bodies, neutral volume knob, and empty VU + scales. The application embeds the assets with =svg-embed= and caches their + encoded data for the Emacs session. + +2. Static vector geometry supplies clip paths, hit-region outlines used only in + debug mode, row separators, and any simple lines that need to stay sharp at + different scales. + +3. Dynamic SVG supplies album/station art, metadata, playlist header and rows, + progress, brass seek thumb, scrollbar, transport glyphs, pressed states, + lamps, VU needles, and meter light. No live text, needle, lamp, selected row, + scrollbar, or progress state is baked into the raster shell. + +4. Emacs Lisp supplies behavior. SVG rendered through librsvg does not run + browser JavaScript. A buffer-local keymap receives mouse events, + =posn-object-x-y= returns pixel coordinates inside the displayed image, and + one scale transform maps them back to the source coordinate system. + +The near-final PNG cannot be embedded unchanged. Phase 1 creates a neutral +layered source by removing metadata, playlist text, active lamps, VU needles, +progress, and selection from the final board. The source stays editable. The +editable source stays one full-resolution instrument. Runtime rendering uses +three aligned image regions: upper player glass, lower control deck, and +playlist. A compact control sprite sheet and neutral VU face supplement those +regions. The current 1916×821 art is treated as a two-times source for a typical +roughly 958×410 rendered dock. Opaque runtime crops may be exported at their +display size after a PNG/JPEG visual comparison. V1 does not upscale beyond the +native source pixels. + +** Module and state boundary + +The SVG view lives in a new =modules/music-svg-ui.el= module. It requires +=svg=, =dom=, and ordinary Emacs image support, but it does not require EMMS. +Its pure entry points accept plain data: + +- =cj/music-svg-render= takes a state snapshot and viewport. +- =cj/music-svg-hit-target= maps source coordinates to an action description. +- =cj/music-svg-truncate= fits display text to a fixed pixel/character budget. +- =cj/music-svg-scrollbar= computes thumb length and position. +- =cj/music-svg-vu-angle= maps a smoothed dB value to the meter scale. + +=modules/music-config.el= remains the controller. It builds an ephemeral +=cj/music-ui-state= snapshot from the current EMMS playlist and player state, +then dispatches renderer actions back to existing commands. The snapshot owns +no durable music data. EMMS and M3U files remain authoritative in v1. + +The snapshot contains: + +- playback status and track kind +- current track identity and metadata +- art path, elapsed time, duration, and seekability +- playlist name/file, total count, rows, selected index, and viewport offset +- repeat, single, random, and consume state +- player volume +- left/right meter values +- transient pressed/focused target + +The graphical view is a dedicated =*Music Player*= special-mode buffer. The +hidden EMMS playlist buffer continues to own playlist markers and track order. +Controller helpers translate a visible row index to an EMMS buffer position +before selection, playback, reorder, or deletion. This avoids making a single +image character pretend to be fourteen editable EMMS rows, and it leaves a +clean seam for the EMMS-free state API later. + +** Metadata and typography + +Berkeley Mono is the default instrument typeface because it is the Dupre token +font and is installed on the target system. Missing font support falls back to +=monospace=. The cursive Dupre Studios mark remains raster in the physical +shell. + +Title, artist, album, label, and year each get one line. Empty values disappear +without closing the line spacing above them. The title receives the largest +width budget and truncates with a literal ellipsis. The renderer uses the +fixed-width font metrics and the measured metadata box, not a guessed character +count from the current window. + +The playlist shows fourteen one-line rows. Each row is number, title, artist, +and duration on one line. The row text truncates before the duration column. +Inactive text is soft white. The active row is amber and carries the triangular +play marker. There are no decorative status dots. + +The header is the only coffee/cream instrument card. It shows the current +collection or search name and item count, but never labels the source as a +playlist or radio. Four concealed warm-light pools are part of the static skin, +but the text is SVG because the name and count change. Its champagne surface is +smooth metal with a fine linear micro-brush, never coarse or wavy wood grain. + +** Playlist viewport + +The UI keeps a buffer-local first-visible index. The current track is kept in +view after track changes unless the user is actively browsing elsewhere. Mouse +wheel moves three rows. Up/Down moves the UI cursor one row. Page Up/Page Down +moves fourteen. Home/End goes to the first/last track. A row click selects and +starts that track. The existing keyboard play command remains available. + +For =N= tracks and fourteen visible rows, the scrollbar thumb fraction is +=min(1, 14/N)=. Its position is =offset/(N-14)= when =N > 14=. Dragging the +thumb changes the viewport but never changes the playing track. No scrollbar +appears for fourteen or fewer tracks. + +** Control behavior + +The visible controls map to existing behavior: + +| Surface | Action | +|---------------+--------| +| PREV | =cj/music-previous= | +| PLAY/PAUSE | start selected/current track, or =emms-pause= while playing | +| STOP | =emms-stop= | +| NEXT | =cj/music-next= | +| REPEAT | =emms-toggle-repeat-playlist= | +| SINGLE | =emms-toggle-repeat-track= | +| RANDOM | =emms-toggle-random-playlist= | +| CONSUME | =cj/music-toggle-consume= | +| NAME | =cj/music-radio-search-by-name= | +| TAGS | =cj/music-radio-search-by-tag= | +| ADD | =cj/music-fuzzy-select-and-add= | +| NEW | =cj/music-playlist-clear=, including its file-association reset | +| LOAD | =cj/music-playlist-load= | +| SAVE | =cj/music-playlist-save= | +| DELETE | =cj/music-delete-playlist= with its existing strong confirmation | + +Mouse press immediately renders the physical pressed state. Release inside the +same target dispatches the command. Release elsewhere cancels it. The +Play/Pause key remains depressed while playback is active. PREV and NEXT only +brighten during a press. STOP has no latched light. + +The four play-mode controls are alternate-action pushbuttons, not lamps or +rotary controls. Each has an unmarked spun-brass cap matching the volume cap, a +fixed collar, and a narrow dark travel seam; the faceplate label identifies its +function. Off stands slightly proud and casts a small lower shadow. On sits +nearly flush, collapses that shadow, and illuminates a thin desaturated-green +ring inside the cap/collar gap. Play/Pause uses the same warm instrument green +through its cut-out symbol with a tight internal bloom; the depressed key +remains the primary playing cue. + +The SVG mode retains the full existing keyboard surface, including commands not +placed on the faceplate: manual station creation, reload, edit, append to another +playlist, shuffle, track removal, and track reordering. Which-key/help text +documents those commands. The faceplate stays limited to the approved controls. + +** Seek and volume + +Local files show elapsed time, total duration, an amber progress line, and a +narrow vertical machined-brass grip. Clicking or dragging the slider sends an +mpv =seek= command in +=absolute-percent= mode. The displayed thumb is computed from mpv =time-pos= +and =duration=. While dragging, the local preview follows the pointer; the next +mpv response confirms or corrects it. + +URL tracks always use the radio presentation. The slider and times disappear. +One red =ON AIR= line appears under the station art, and the active playlist row +contains the second =ON AIR=. No other ON AIR label is rendered. + +Player volume is separate from the system mixer. Add +=cj/music-player-volume=, default 100, and apply it to every new mpv process. +The knob has no number or pointer. Its equally spaced lamps show the stored +0–100 value. Click/drag around the arc sets volume, the mouse wheel changes it +by five, and the existing +/− bindings call the same player-volume commands. +Setting volume writes mpv's =volume= property and updates the stored value so a +track change does not reset it. + +Every volume position is one fixed lamp well. Dark and illuminated states use +the same center and mounting bezel; the lit state replaces the dark lens rather +than adding another dot or adjacent glow. The neutral raster skin contains no +baked lamp cores or light spill. + +** Real VU telemetry + +mpv starts with a labeled FFmpeg audio filter: + +#+begin_src text +--af-add=@meter:lavfi=[astats=metadata=1:reset=1:measure_perchannel=RMS_level+Peak_level:measure_overall=none] +#+end_src + +The UI reads =af-metadata/meter= over mpv JSON IPC. FFmpeg supplies +=lavfi.astats.1.RMS_level= and =lavfi.astats.2.RMS_level= (plus peak values). +Mono duplicates channel one to both meters. Missing or nonnumeric data rests +the needles and records one diagnostic; it never invents motion. + +This path was verified locally on 2026-07-19 with mpv 0.41.0 and FFmpeg 8.1.2. +A synthetic stereo source returned distinct left/right RMS and peak values +through the labeled property. The official references are: + +- [[https://mpv.io/manual/master/#command-interface-af-metadata][mpv af-metadata property]] +- [[https://ffmpeg.org/ffmpeg-filters.html#astats-1][FFmpeg astats filter]] + +The renderer maps dB to the printed meter scale (−40 through +3). A 300 ms +attack and slower 600 ms release approximate a physical VU movement. Values +below the scale rest at the left stop. Values above +3 clamp at the right stop. + +Telemetry uses one persistent, nonblocking IPC connection with request IDs and +line-buffered JSON replies. It polls only while the player view is visible and +audio is running. It closes when playback stops or the view is hidden. The +existing one-shot IPC helpers remain valid for infrequent commands. + +** Refresh and render budget + +Hooks trigger immediate redraws for track, playlist, playback, mode, and art +changes. Progress updates four times per second while a seekable file plays. +Meters target ten updates per second while visible and playing. Paused, stopped, +hidden, and TTY states run no animation timer. + +The [[file:prototypes/2026-07-19-music-config-ui-remodel-benchmark.org][prototype benchmark]] measured full-image and tiled refresh for one minute +each at the real dock size. Full refresh failed at 133.616 ms median and +139.822 ms p95. A display-sized lower-deck tile passed at 35.513 ms median and +38.221 ms p95. The application therefore uses three aligned images: upper +player glass, lower control deck, and playlist. Each image includes the +matching raster crop. Meter ticks refresh only the lower deck; hooks refresh +the other regions. The source geometry and user-visible layout do not change. + +** Errors and empty states + +An empty queue shows the receiver, =UNTITLED=, =0 TRACKS=, and fourteen blank +rows. Playlist actions and radio search remain enabled. Transport, seek, and +mode actions that require a track are visibly inactive and report a short +message if invoked by key. + +Missing artwork uses the existing vinyl placeholder. Missing metadata is +omitted. The UI never displays =Unknown=, =N/A=, a raw nil, or a raw stream URL +as program information. + +If SVG, librsvg, the raster shell, or a minimum legible viewport is unavailable, +F10 opens the implemented fancy/text playlist instead and reports why once. If +mpv IPC is unavailable, seek, volume telemetry, and meters disable without +stopping playback. A command reports the failed operation and the next step, +for example: =Music seek unavailable: mpv IPC socket is not connected; start a +track and try again.= + +=M-x cj/music-ui-doctor= reports graphical/SVG support, resolved assets and font, +view size, last render time, mpv socket state, meter filter state, telemetry +timer state, and the last telemetry error. It does not log private file paths +or stream URLs unless called with a debug prefix. + +* Alternatives Considered + +** Hybrid raster skin plus dynamic SVG (chosen) + +- Good, because it preserves the leather, glass, brass grain, and machined + highlights from the approved board while keeping every changing value honest. +- Bad, because the neutral raster source and SVG geometry must stay aligned. +- Neutral, because the result is still one SVG application document even though + the document embeds raster assets. + +** Rebuild the complete receiver as vector geometry + +- Good, because every surface would scale without raster limits and theme tokens + could recolor everything. +- Bad, because reproducing leather, brushed brass, glass, and irregular reflected + light would take much longer and would look less like the approved board. +- Neutral, because simple Dupre controls still supply useful vector geometry + inside the hybrid renderer. + +** Use the final PNG as one clickable background + +- Good, because it would match the approved image immediately. +- Bad, because the PNG contains one track, one playlist, lit volume segments, + meter needles, progress, and button state. Painting over those areas would + flatten the material texture and produce visible patches. +- Neutral, because a cleaned neutral derivative of the PNG is the chosen shell. + +** Browser/xwidget application + +- Good, because browser SVG supports native DOM events and partial element + updates. +- Bad, because it introduces a browser runtime inside Emacs, complicates window + integration, and weakens TTY and configuration portability. +- Neutral, because browser prototypes remain useful before the svg.el port. + +** Replace the EMMS playlist buffer in place + +- Good, because no second buffer name or adapter is needed. +- Bad, because EMMS commands depend on point and text markers while the SVG is + one displayed image glyph. Mixing invisible rows and image coordinates would + be brittle. +- Neutral, because the dedicated view still delegates every operation to the + existing EMMS buffer in v1. + +* Decisions [10/10] + +** DONE Hybrid raster/SVG rendering +- Context: the final board's realism comes from material texture and reflected + light, while live state must remain replaceable. +- Decision: We will embed a neutral raster skin in an SVG scene and render all + changing information, needles, lights, and selection as SVG. +- Consequences: easier, the running UI can closely match the board. Harder, the + asset export and SVG geometry need one measured coordinate system. + +** DONE Craig's final board is the visual authority +- Context: the design session produced many useful directions, but implementation + needs one source for proportion and material treatment. +- Decision: We will use concept 30, Craig's 1916×821 GIMP refinement, as the + layout and appearance authority. +- Consequences: easier, visual disputes can be checked against one board. Harder, + the radio state must be derived without drifting from that hardware. + +** DONE Neutral physical shell +- Context: the final flattened PNG contains transient information and active + state. +- Decision: We will create an editable neutral source and export a clean shell, + control sprites, and neutral VU face. No live state remains in those assets. +- Consequences: easier, texture stays realistic. Harder, Phase 1 includes careful + image cleanup before application code can look finished. + +** DONE Dedicated graphical view buffer +- Context: EMMS playlist operations are point/marker based and cannot treat one + SVG image as fourteen text rows. +- Decision: We will render into =*Music Player*= and use controller adapters to + operate on the hidden EMMS playlist buffer. +- Consequences: easier, the SVG renderer stays clean and future-backend ready. + Harder, selection and reorder commands need explicit index-to-marker adapters. + +** DONE One geometry table for drawing and input +- Context: separate hand-maintained visual and hit maps will drift. +- Decision: We will measure the final board once and derive rendering, hit tests, + clipping, and scaling from the same constants. +- Consequences: easier, controls stay clickable after scaling. Harder, geometry + extraction is a named deliverable rather than ad hoc coordinates in draw code. + +** DONE Direct control semantics +- Context: every faceplate control must perform real music-config behavior. +- Decision: We will map the approved transport, modes, radio search, playlist + actions, seek, and volume controls directly to their existing commands or the + named mpv additions in this spec. +- Consequences: easier, the interface is self-explanatory. Harder, commands not + approved for the faceplate remain keyboard/M-x only and need discoverable help. + +** DONE Persistent per-player volume +- Context: the existing +/- path can change the system mixer, while the design's + knob is the player's volume and mpv restarts for each track. +- Decision: We will store volume in music-config, write mpv's volume property, + and apply the stored value when every new mpv process starts. +- Consequences: easier, the knob is truthful and track changes preserve level. + Harder, one more piece of runtime state must stay synchronized with mpv. + +** DONE Real meter data through mpv astats +- Context: random needle animation would violate the design's functional-lighting + rule. +- Decision: We will read left/right RMS metadata from a labeled FFmpeg astats + filter over mpv IPC and apply physical needle smoothing. +- Consequences: easier, the VUs convey real program level. Harder, a visible + view needs a small persistent IPC telemetry client and bounded refresh timer. + +** DONE Current text views remain fallbacks +- Context: TTY frames and SVG/asset failures need a usable player, and the + implemented fancy text UI already works. +- Decision: We will add an SVG enable flag and fall back to the current fancy or + plain text path without changing M3U or playback state. +- Consequences: easier, rollout and rollback are safe. Harder, the text path + remains maintained alongside the SVG application. + +** DONE Three-region render path after measurement +- Context: =svg-possibly-update-image= rerasterizes an SVG image, so ten full + receiver renders per second may exceed the dock's CPU budget. +- Decision: The prototype benchmark measured the full receiver at 133.616 ms + median / 139.822 ms p95 and the display-sized lower-deck tile at 35.513 ms + median / 38.221 ms p95. We will use three aligned regions and refresh only + the lower deck at meter cadence. +- Consequences: easier, meter animation passes the render budget with margin. + Harder, the renderer places three images and the asset export must hide their + boundaries exactly. + +* Review findings [0/1] + +** TODO The final interaction model has no working two-state prototype :blocking: + +The design session produced extensive static boards and established concept 30 +as the visual authority, but the final geometry has not been exercised as a +working local-playlist and radio prototype. That leaves click targets, drag +behavior, playlist scrolling, long-text clipping, local/radio state changes, +and the full-image render budget unproven. Starting implementation now would +make the first build phase answer product and performance questions that belong +in the design gate. + +Smallest resolution: create one functional prototype using concept 30's +geometry and neutral skin. It may be a browser prototype or an Emacs SVG proof, +but it must switch between a long local playlist and a live-radio fixture; wire +transport, modes, radio search, playlist actions, row and scrollbar navigation, +seek, and volume interaction; show all pressed and latched states; stress long +metadata; and record one minute of render timing at the intended dock size. +Link the accepted prototype under Prototype iterations and Design, record any +geometry or performance changes here, then repeat spec review. + +Progress on 2026-07-19: [[file:prototypes/2026-07-19-music-config-ui-remodel-prototype-1.html][prototype 1]] now supplies both fixtures and the named +interactions; its twelve-check behavior pass is green. The [[file:prototypes/2026-07-19-music-config-ui-remodel-benchmark.org][librsvg benchmark]] +records a full-render failure and a passing lower-deck tile, so the spec now +requires the three-region renderer. Craig's hands-on acceptance is the only +remaining part of this finding. + +* Implementation phases + +** Phase 1 — Neutral skin and geometry manifest + +Create the editable neutral source from concept 30. Export aligned upper-glass, +lower-deck, and playlist crops plus control sprites and the VU face under final +dated asset names. Record measured +source rectangles, anchors, clip boxes, and hit targets in one Lisp geometry +table. Add an asset/geometry debug command that renders target outlines over the +skin. The phase ends with a static SVG in Emacs that matches the final board and +contains no baked live state. + +** Phase 2 — Pure SVG renderer and view mode + +Add =modules/music-svg-ui.el=, the state structs, pure layout helpers, raster +embedding cache, text clipping, dynamic node construction, and +=cj/music-svg-mode=. F10 can show/hide the static graphical view while the +existing fancy/text path remains available. Add unit tests for scale transforms, +hit testing, truncation, scrollbar math, mode colors, and VU angle mapping. + +** Phase 3 — Controller snapshot and playlist viewport + +Build state snapshots from EMMS without exposing EMMS objects to the renderer. +Render metadata, album art, header, fourteen rows, selection, and the exact +scrollbar. Implement keyboard and mouse scrolling, row selection/play, and +index-to-EMMS-marker adapters. Characterize existing reorder/removal behavior +before routing those keys through the graphical view. + +** Phase 4 — Transport, modes, radio search, and playlist actions + +Wire the approved faceplate controls and pressed/latched rendering. Preserve +the remaining keyboard-only commands and add a concise help surface. Cover +empty-queue behavior, destructive Delete confirmation, command errors, and +state refresh hooks. The phase ends with a complete functional control surface +using the existing backend. + +** Phase 5 — Seek and persistent mpv volume + +Add player-owned volume state and apply it on process start. Route +/−, wheel, +click, and drag through the same volume setters. Add absolute seek and drag +confirmation using mpv time/duration. Render local progress and the exact brass +thumb. Unit-test value/coordinate mapping and use a fake IPC ledger for command +order. + +** Phase 6 — Stereo telemetry and timed refresh + +Add the labeled astats filter, persistent nonblocking telemetry connection, +JSON request/reply routing, meter parsing, dB mapping, and needle ballistics. +Run progress and meter timers only while visible and active. Measure the render +budget for one minute and use the documented three-region fallback if needed. +Test with the synthetic no-audio-output source used during spec research. + +** Phase 7 — Radio state, failures, and diagnostics + +Render the matched live-radio state with exactly two ON AIR labels and no seek +surface. Handle missing art/metadata, unavailable SVG/assets/font, lost mpv IPC, +missing meter metadata, hidden-window timer shutdown, and an empty queue. Add +=cj/music-ui-doctor= and verify that fallback never mutates playback or playlist +state. + +** Phase 8 — Integration, documentation, and live verification + +Run the focused music tests, batch load, byte compilation, TTY fallback, and GUI +daemon verification. Exercise a long local playlist, a short radio playlist, +seek, volume across track changes, every control, scrolling, reorder, deletion, +and one-hour timer stability. Update music documentation and key hints. Make +the SVG view the graphical default only after Craig accepts the live result. + +* Acceptance criteria + +- [ ] F10 opens the Dupre Studios receiver in the bottom side window on a + graphical frame and toggles it closed without changing playback. +- [ ] The running receiver matches concept 30 in proportion, material character, + spacing, typography, and control placement at the normal dock size. +- [ ] Leather, glass, brass, fixed engraving, and neutral hardware come from the + raster skin; live information and illumination are not baked into it. +- [ ] The UI remains fully usable from the keyboard. +- [ ] Every visible button maps to the command named in this spec. +- [ ] Pressed, playing, and latched mode states are physically and chromatically + distinct. +- [ ] Local metadata uses separate lines and omits missing values. No visible + program field says Unknown or N/A. +- [ ] Long metadata and playlist rows truncate with an ellipsis before colliding + with adjacent fields. +- [ ] The analog header card shows only the collection/search name and item + count; it never adds a PLAYLIST or RADIO type label. +- [ ] Champagne surfaces use a fine low-contrast metallic micro-brush and never + read as wood grain. +- [ ] The playlist shows fourteen one-line rows with artist inline, selected row + amber, and a functional scrollbar whose size and position follow the formulas. +- [ ] Mouse wheel, keyboard navigation, scrollbar drag, row click/play, reorder, + and removal operate on the intended EMMS tracks. +- [ ] ADD, NEW, LOAD, SAVE, and DELETE preserve current playlist/M3U semantics. +- [ ] DELETE uses the existing strong confirmation and reports which playlist was + deleted. +- [ ] A local track displays actual elapsed/duration and supports click/drag seek. +- [ ] The seek thumb is brass and its position comes from mpv state. +- [ ] A live station has no slider or times and shows exactly two ON AIR labels. +- [ ] The volume knob controls mpv, not the system mixer, and persists across + track changes. +- [ ] Volume segments fill cumulatively to the stored mpv volume and have no + numeric display. +- [ ] VU needles use distinct real left/right RMS values, rest on missing data, + and never use random animation. +- [ ] Paused, stopped, hidden, and TTY states run no meter/progress timer. +- [ ] Full or tiled rendering meets the median/95th-percentile budget during a + one-minute meter run. +- [ ] Empty playlist, missing art, missing metadata, missing SVG/assets, and lost + mpv IPC each have the fallback or actionable error defined in this spec. +- [ ] =cj/music-ui-doctor= reports the renderer and telemetry state without + exposing file paths or stream URLs by default. +- [ ] Setting the SVG enable flag off restores the implemented fancy/text UI. +- [ ] Existing music-config tests pass, and new pure tests cover geometry, + snapshots, hit targets, clipping, scrolling, volume, seek, meter mapping, and + timer lifecycle. +- [ ] Craig accepts both a long local-playlist state and a live-radio state in the + real Emacs side window before the SVG view becomes the default. + +* Readiness dimensions + +- Data model & ownership: EMMS and M3U remain authoritative. The SVG snapshot, + pressed target, viewport offset, meter smoothing, and render timing are + generated runtime state. Player volume is music-config runtime state applied + to each mpv process. Raster source assets are project-authored and versioned. +- Errors, empty states & failure: defined in the Errors and empty states section. + Playback continues if rendering or meter telemetry fails. Destructive + playlist deletion retains the existing strong confirmation. +- Security & privacy: no credentials are added. Diagnostics omit local paths and + stream URLs by default. Album art and radio favicons stay in the existing + local cache. +- Observability: =cj/music-ui-doctor= exposes assets, font, viewport, render + timing, socket/filter/timer state, and last telemetry error. The UI itself + exposes player state through lamps, needles, progress, and selection. +- Performance & scale: fourteen visible rows from playlists tested through at + least 1,000 tracks. SVG refresh has explicit median/95th-percentile budgets, + a one-minute test, and a pre-approved tiled fallback. Hidden views do no timed + work. +- Reuse & lost opportunities: reuses the current music commands, EMMS state, + M3U/radio/art code, bottom side window, Dupre tokens, =svg.el=, and the gallery + widget proof. It deliberately does not wait for the EMMS-free/VAMP rewrite. +- Architecture fit & weak points: new renderer module is pure at its boundary; + music-config owns EMMS adaptation and mpv effects. Weak points are raster/SVG + alignment, point-based EMMS adapters, full-image rerasterization, and telemetry + lifecycle. Geometry sharing, adapter tests, tiled fallback, and visibility- + scoped IPC mitigate them. +- Config surface: add =cj/music-svg-ui= (boolean, default off until live acceptance, + then on) and =cj/music-player-volume= (integer 0–100, default 100). Keep + =cj/music-fancy-ui= as the fallback selector. Refresh rates and geometry are + internal until real use proves a customization need. +- Documentation plan: update music-config commentary/docstrings, F10/keybinding + notes, the music VERIFY task, and the design README. The final spec and dated + runtime assets remain linked from the parent task. +- Dev tooling: use the existing ERT/byte-compile commands, focused music test + files, Emacs daemon live verification, and a deterministic synthetic mpv meter + script/fixture with =ao=null=. No network or audible output in the normal + suite. +- Rollout, compatibility & rollback: SVG is additive and initially disabled. + Fallback is automatic. Rollback is setting =cj/music-svg-ui= nil or reverting + the new renderer/controller changes; M3U files and cached art do not migrate. +- External APIs & deps: built-in Emacs 30.2 =svg.el= and librsvg are the render + path. mpv 0.41 and FFmpeg 8.1 were checked locally. Official mpv and FFmpeg + documentation confirms labeled audio-filter metadata and astats keys. + +* Risks, Rabbit Holes, and Drawbacks + +- Cleaning a neutral skin from a flattened final board can produce visible + texture patches. Keep the layered source, use broad material samples rather + than small clone spots, and approve the neutral shell before wiring state. +- Full-image librsvg refresh may be too expensive at meter cadence. Measure in + the prototype. Use the specified three-region split rather than lowering the + meter to a decorative crawl. +- EMMS commands expect point in the playlist buffer. Keep every index-to-marker + translation in one controller adapter and test reorder/remove against the same + logical track. +- SVG text metrics can differ from Emacs face metrics. Use the installed Dupre + fixed-width font, fixed boxes, clipping paths, and visual stress fixtures with + long titles. +- An mpv filter may fail for an unusual audio format. Playback wins: leave the + meter at rest, show the failure in the doctor, and never stop the track. +- The raster skin limits infinite scaling and alternate themes. V1 targets the + current dock and approved aesthetic. Multiple skins and responsive reflow are + separate work. + +* Testing / Verification / Rollout + +Pure ERT tests cover layout transforms, geometry/hit agreement, text fitting, +playlist window/scrollbar math, state-to-color mapping, volume/seek conversion, +VU dB/angle mapping, ballistics, and timer state. Controller tests use an EMMS +fixture or stubs and an mpv IPC ledger so they do not play sound. + +Integration tests build representative local and radio snapshots, render SVG +strings, and assert required IDs, text, clip paths, and state classes. They do +not use pixel-perfect screenshots as the main contract because librsvg/font +versions can change antialiasing. A small set of manual reference screenshots +supports the visual acceptance step. + +The live pass runs in the real bottom side window with the normal long playlist +and a radio playlist. It covers every faceplate control, keyboard parity, +scrolling, long strings, seek, persistent volume, two-channel meters, exactly two +ON AIR states, hidden-window timer shutdown, and fallback. The SVG flag changes +to default-on only after that pass. + +* References / Appendix + +- [[file:../../docs/specs/2026-07-06-fancy-music-player-ui-spec.org][Implemented fancy music-player UI spec]] +- [[file:../../docs/specs/music-config-without-emms-spec.org][Music-config without EMMS architecture spec]] +- [[file:README.org][Music SVG design record]] +- [[file:concepts/30a-dupre-studios-user-refined-playlist.png][Near-final playlist board]] +- [[file:prototypes/2026-07-19-music-config-ui-remodel-prototype-1.html][Functional two-state prototype]] +- [[file:prototypes/2026-07-19-music-config-ui-remodel-benchmark.org][Prototype librsvg benchmark]] +- [[https://www.gnu.org/software/emacs/manual/html_node/elisp/SVG-Images.html][Emacs Lisp SVG images]] +- [[https://mpv.io/manual/master/#json-ipc][mpv JSON IPC]] +- [[https://mpv.io/manual/master/#command-interface-af-metadata][mpv audio-filter metadata]] +- [[https://ffmpeg.org/ffmpeg-filters.html#astats-1][FFmpeg astats]] + +* Review and iteration history + +** 2026-07-19 Sun @ 19:11:57 -0500 — Codex (emacs-d) — hardware-depth correction +- What: changed the upper boundary of the lower deck from a raised champagne + rim to a dark glass reveal descending into the brass faceplate. Unified all + four play-mode and both radio-search controls as blank, circularly machined + brass pushbutton caps. Removed the returned search glyphs and expanded then + tightened the source crop to preserve the volume knob's complete black + knurled skirt without importing the old faceplate halo. +- Why: the prior neutral-faceplate overlay flattened the glass/metal depth, + allowed the small-control treatments to diverge, and clipped the knob at a + perfect circle that hid its physical knurling. These changes restore a + believable assembly hierarchy while retaining state-owned lamps. +- Artifacts: updated [[file:prototypes/2026-07-19-music-config-ui-remodel-prototype-1.html][functional prototype 1]]; twelve-check interaction regression green. + +** 2026-07-19 Sun @ 18:43:00 -0500 — Codex (emacs-d) — prototype refinement +- What: replaced the baked lower-deck faceplate with a neutral SVG-owned + champagne micro-brush surface, then restored only the approved volume knob + through a circular crop. Re-engraved the fixed control labels on the new + surface and reduced the volume arc to small dark wells with state-owned amber + cores and local glow. Verified both local and radio layouts and reran the + twelve-check headless interaction pass successfully. +- Why: masking individual source-image lamps left visible baked illumination and + made the faceplate look patched. Owning the complete neutral deck surface in + SVG removes the conflicting lamp state and the woodlike raster grain while + retaining the realistic machined knob from the approved visual authority. +- Artifacts: updated [[file:prototypes/2026-07-19-music-config-ui-remodel-prototype-1.html][functional prototype 1]]; local and radio state screenshots. + +** 2026-07-19 Sun @ 18:39:41 -0500 — Codex (emacs-d) — prototype refinement +- What: applied Craig's second hands-on pass. Removed source-type words and the + separator from the analog card; changed radio fixture naming to =NAME SEARCH=; + replaced the circular seek ornament with a vertical machined-brass grip; + removed all mode-cap glyphs and matched their smooth spun-brass finish to the + volume cap; and rebuilt the volume arc as dark recessed wells whose amber core + and glow exist only for lit positions. +- Why: the card should identify the current collection/search rather than report + an internal playlist/radio type. The prior seek coin had no hardware model, + the mode symbols duplicated their faceplate labels, and baked light spill made + some nominally dark volume positions glow. The spec now also rejects coarse, + wavy champagne texture that reads as wood grain. +- Artifacts: updated [[file:prototypes/2026-07-19-music-config-ui-remodel-prototype-1.html][functional prototype 1]]; Craig's 18:29–18:32 screenshots. + +** 2026-07-19 Sun @ 18:19:28 -0500 — Codex (emacs-d) — prototype refinement +- What: incorporated Craig's first hands-on notes. Rebuilt play modes as + alternate-action brass pushbuttons with engraved glyphs, visible travel, and + a restrained inset green ring; tightened Play/Pause illumination; aligned + each volume lamp's dark and lit state to one physical well; restored four + concealed warm-light pools on a darker coffee/cream playlist card; and made + the prototype's synthetic-VU / production-signal distinction explicit. +- Why: the prior controls read as glowing domes, the green looked like a neon + outline, the flattened source and live volume arcs produced double lamps, and + the playlist card had lost its analog illumination model. Production VUs + remain tied to real mpv astats RMS data as already specified. +- Artifacts: updated [[file:prototypes/2026-07-19-music-config-ui-remodel-prototype-1.html][functional prototype 1]]; Craig's 17:59–18:03 screenshots. + +** 2026-07-19 Sun @ 17:56:27 -0500 — Codex (emacs-d) — prototype author +- What: built functional prototype 1 from concept 30 with local and radio + fixtures, all approved faceplate controls, long-string stress data, exactly + fourteen visible rows, scrollbar and seek/volume drag, pressed/latched states, + empty/delete flows, keyboard navigation, and synthetic stereo needle motion. + Its built-in twelve-check behavior pass is green. Measured librsvg for one + minute per path: full receiver 133.616 ms median / 139.822 ms p95 (fail), + display-sized lower deck 35.513 ms median / 38.221 ms p95 (pass). +- Why: this supplies the interaction and performance evidence requested by the + first review finding. The measured result makes the three-region renderer a + requirement rather than a contingency. Craig's hands-on prototype acceptance + remains pending, so the finding stays open and the spec stays DRAFT. +- Artifacts: [[file:prototypes/2026-07-19-music-config-ui-remodel-prototype-1.html][functional prototype 1]]; [[file:prototypes/2026-07-19-music-config-ui-remodel-benchmark.org][benchmark record]]; + [[file:2026-07-19-music-config-ui-remodel-render-fixture.svg][full-render fixture template]]. + +** 2026-07-19 Sun @ 16:16:57 -0500 — Codex (emacs-d) — reviewer +- What: completed the first implementation-readiness review after reading the + current music-config render, EMMS playlist, radio, mpv IPC, and volume paths. + Assigned =Not ready= and recorded one blocking finding: the approved final + board is static, so its two application states, hit/drag/scroll behavior, and + rendering budget have not passed the project's functional-prototype gate. +- Why: the architecture, ownership, failure handling, telemetry source, rollout, + acceptance criteria, and eight phase boundaries are otherwise specific enough + to implement. A working prototype is the smallest remaining test of the + design rather than an invitation to redesign it during Phase 1. +- Artifacts: =* Review findings [0/1]= in this spec; source checks in + =modules/music-config.el=; Dupre =gallery-widget.el= SVG proof; verified mpv + =af-metadata/meter= / FFmpeg =astats= telemetry path. + +** 2026-07-19 Sun @ 16:03:13 -0500 — Codex (emacs-d) — author +- What: drafted the Music Config UI Remodel spec from Craig's selected concept, + manual GIMP refinement, and hybrid raster/SVG decision. Verified the real VU + telemetry path against the installed mpv/FFmpeg stack and primary docs. +- Why: the visual design is settled closely enough to define the renderer, + controller boundary, interaction surface, phases, and test contract before + implementation. +- Artifacts: [[file:concepts/30a-dupre-studios-user-refined-playlist.png][concept 30]]; local mpv astats IPC check; parent music SVG task. diff --git a/working/music-svg-app-design/README.org b/working/music-svg-app-design/README.org new file mode 100644 index 00000000..5ef6d67d --- /dev/null +++ b/working/music-svg-app-design/README.org @@ -0,0 +1,426 @@ +#+TITLE: Music SVG Application Design Working Set +#+AUTHOR: Craig Jennings + +* Purpose + +Six functional HTML/SVG prototypes for the music-config application design session. +They explore the Dupre chronometer, hi-fi stereo, and automobile-dashboard visual +language while preserving the current player, queue, radio, and playlist workflows. + +This directory owns the complete in-progress remodel package while the design +continues. The implementation spec is +[[file:2026-07-19-music-config-ui-remodel-spec.org][2026-07-19-music-config-ui-remodel-spec.org]]. +The current interactive and rendering evidence lives under [[file:prototypes/][prototypes/]]. +Concept boards, source artwork, and visual references stay beside them so local +iteration does not depend on files scattered through =docs/=. When the design +is accepted, the spec, prototypes, benchmark, render fixture, and selected final +assets graduate together to their permanent =docs/= and =assets/= homes. + +The selected receiver now has a final interaction candidate at +[[file:prototypes/2026-07-19-music-config-ui-remodel-prototype-1.html][prototypes/2026-07-19-music-config-ui-remodel-prototype-1.html]]. It uses +concept 30 as the physical shell and overlays the changing local-playlist and +radio state. The paired [[file:prototypes/2026-07-19-music-config-ui-remodel-benchmark.org][librsvg benchmark]] makes the three-region production +renderer mandatory: full-instrument meter refresh missed the budget, while the +lower control tile passed. + +* Inputs + +- [[file:../../docs/specs/2026-07-06-fancy-music-player-ui-spec.org][Existing music player UI spec]] +- [[file:../../docs/specs/music-config-without-emms-spec.org][EMMS-free architecture spec]] +- [[file:../../../code/archsetup/docs/prototypes/panel-widget-gallery.html][Dupre panel-widget gallery]] +- [[file:../../../code/archsetup/docs/prototypes/waybar-redesign-prototype.html][Waybar redesign prototype]] + +* Prototype Directions + +1. Gold-pinstripe tuner console +2. Touring-car instrument cluster +3. Chronometer record deck +4. Studio rack and tape machine +5. Perpetual-calendar salon receiver +6. Mission-control radio navigator + +* High-Fidelity Concept Boards — Iteration Two + +The second pass deliberately separates visual design from implementation. These +boards establish materials, lighting, silhouette, hierarchy, and instrument +semantics before the selected direction is translated into Dupre components. + +1. [[file:concepts/01-champagne-receiver.png][Champagne Receiver]] +2. [[file:concepts/02-le-mans-night-cluster.png][Le Mans Night Cluster]] +3. [[file:concepts/03-geneva-playback-chronograph.png][Geneva Playback Chronograph]] +4. [[file:concepts/04-mastering-room-reel-console.png][Mastering Room Reel Console]] +5. [[file:concepts/05-perpetual-calendar-salon.png][Perpetual Calendar Salon]] +6. [[file:concepts/06-transatlantic-broadcast-navigator.png][Transatlantic Broadcast Navigator]] +7. [[file:concepts/07-functional-black-glass-receiver.png][Functional Black Glass Receiver]] +8. [[file:concepts/08-functional-black-glass-flipped.png][Functional Black Glass Receiver — flipped]] +9. [[file:concepts/09-functional-black-glass-retro.png][Functional Black Glass Receiver — retro]] +10. [[file:concepts/10-warm-black-glass-player-volume.png][Warm Black Glass Receiver — player volume]] +11. [[file:concepts/11-illuminated-black-glass-controls.png][Illuminated Black Glass Receiver — varied controls]] +12. [[file:concepts/12-consolidated-functional-receiver.png][Consolidated Functional Receiver]] +13. [[file:concepts/13-black-silver-chronograph-receiver.png][Black and Silver Chronograph Receiver]] +14. [[file:concepts/14-corrected-luxury-chronograph-receiver.png][Corrected Luxury Chronograph Receiver]] +15. [[file:concepts/15-champagne-brass-digital-hifi.png][Champagne-Brass Digital Hi-Fi]] +16. [[file:concepts/16-champagne-aluminum-radio-groups.png][Champagne-Aluminum Radio Groups]] +17. [[file:concepts/17-dupre-coltrane-scrollbar.png][Dupre Coltrane Scrollbar State]] +18. [[file:concepts/18-dupre-branding-control-study.png][Dupre Branding and Compact-Control Study]] +19. [[file:concepts/19a-dupre-playlist-state.png][Dupre Playlist State]] / [[file:concepts/19b-dupre-radio-state.png][Dupre Radio State]] +20. [[file:concepts/20-dupre-playlist-radio-comparison.png][Dupre Long-Playlist / Compact-Radio Comparison]] ([[file:concepts/20a-dupre-long-playlist.png][playlist source]] / [[file:concepts/20b-dupre-compact-radio.png][radio source]]) +21. [[file:concepts/21-dupre-semantic-controls-comparison.png][Dupre Semantic-Controls Comparison]] ([[file:concepts/21a-dupre-mode-lamps-playlist.png][playlist source]] / [[file:concepts/21b-dupre-two-on-air-radio.png][radio source]]) + +- [[file:concept-board.html][Open the six-board review sheet]] + +The original functional HTML pass remains at +[[file:music-svg-directions.html][music-svg-directions.html]] for interaction and +workflow reference; it is not the material-design target. + +* Current Design Decisions + +- Beauty must communicate real application function; no decorative controls. +- Preserve the Champagne Receiver's now-playing, progress, transport, queue, + and playlist-management regions as the functional nucleus. +- Remove AM/FM, tone, speaker, loudness, power, and other receiver controls + without a =music-config.el= command or state. +- Target a compact panoramic panel in the bottom portion of a predominantly + portrait Emacs frame; playlist and player controls must sit side by side. +- Prefer a neutral black-glass, warm-meter, polished-chrome language with + restrained warm metal and tactile black leather; keep whitespace low without + returning to clutter. Do not use cold blue illumination. +- Permanent radio controls map only to the implemented name and tag searches. + Manual URL entry remains an Emacs command rather than faceplate hardware. +- Place the player on the left and playlist on the right. +- The dots around the volume knob are a cumulative illuminated scale driven by + actual volume; the last lit dot is the precise pointer. They never chase or + flash. +- The knob controls dedicated mpv player volume rather than the system mixer. + Persist the level in Emacs, pass it to each newly started per-track mpv + process, and read/write mpv's =volume= property over the existing IPC socket. +- Drive the stereo VU meter from real mpv audio analysis. A labeled lavfi + =astats= filter exposes per-channel RMS and peak readings through + =af-metadata/