From 140e3b9f0757b8bc413c4b13f060f24f5eebd03c Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Sat, 4 Jul 2026 12:38:10 -0500 Subject: docs(spec): sort formal specs into docs/specs/ with lifecycle status Moved the seven formal specs from docs/design/ into docs/specs/, each stamped with a lifecycle status heading: four IMPLEMENTED (bluetooth, net-other-interfaces, audio, instrument-console), one CANCELLED (file-manager-swallow), two DRAFT (desktop-settings, timer). Rewrote the seven todo.org links to the new paths. The two -spec.org files without the spec spine (waybar-network-module, waybar-timer-module) stayed in docs/design/ as notes. --- docs/design/2026-07-03-audio-panel-spec.org | 160 ---------------------------- 1 file changed, 160 deletions(-) delete mode 100644 docs/design/2026-07-03-audio-panel-spec.org (limited to 'docs/design/2026-07-03-audio-panel-spec.org') diff --git a/docs/design/2026-07-03-audio-panel-spec.org b/docs/design/2026-07-03-audio-panel-spec.org deleted file mode 100644 index 16a087d..0000000 --- a/docs/design/2026-07-03-audio-panel-spec.org +++ /dev/null @@ -1,160 +0,0 @@ -#+TITLE: Audio Panel — the pulsemixer console -#+AUTHOR: Craig Jennings -#+DATE: 2026-07-03 -#+TODO: TODO | DONE -#+TODO: DRAFT READY DOING | IMPLEMENTED SUPERSEDED CANCELLED - -* IMPLEMENTED Status -:PROPERTIES: -:ID: 71f556c6-ee02-47cc-a3be-68c8289380f3 -:END: -- [2026-07-03 Fri] IMPLEMENTED — built in a no-approvals speedrun in the - dotfiles repo (branch panel-bugfixing): engine (pactl), presenter, GTK - panel, PTT arming, bar indicator, and the bar/keybind wiring, across four - commits 65e5bb0..9601420. 102 unit tests + a passing AT-SPI smoke on velox. - All five Decisions below resolved. Live-eyeball validation (visual polish, - PTT-in-a-meeting, fader feel, the master-mute hardware key) is the one open - follow-up, tracked as a manual-testing task in todo.org. -- [2026-07-03 Fri] DRAFT — stub from the todo.org task "Audio panel spec" - (roam ask 2026-07-02) plus the 2026-07-03 waybar/sound design discussion. - Written to iterate alongside the prototype - (=working/sound-panel/sound-panel-prototype.html=). Spine is present; the - Decisions and Design detail get filled in as we go. - -* Metadata - -| Field | Value | -|--------+---------------------------------------------------| -| Status | implemented | -|--------+---------------------------------------------------| -| Owner | Craig Jennings | -|--------+---------------------------------------------------| -| Repo | dotfiles | -|--------+---------------------------------------------------| -| Kin | net panel + bt panel (architecture + aesthetic | -| | donors), desktop-settings panel (sibling) | -|--------+---------------------------------------------------| - -* Problem - -Audio control today is the pyprland audio scratchpad (Super+A) — a floating -pulsemixer TUI — plus scattered bar affordances: =pulseaudio= (volume, click -to mute sink), =pulseaudio#mic= (mic glyph + mic-toggle), Super+M audio-cycle -ring, Super+Shift+A mic-toggle. There's no single glanceable surface that -shows every sink and source, lets you set the default output/input, and -carries the meeting-grade mic controls Craig wants (a clean muted mode and a -hold-to-talk mode). The net + bluetooth panels set the pattern for exactly -this shape; audio is the third instrument in the family. - -* Goals - -1. One panel, opened from the bar's sound glyph, exposing the full pulsemixer - surface: every sink and source, per-device volume, per-device mute, and - switching the default output and input. -2. Replace the pyprland audio scratchpad (Super+A) as the primary audio UI. -3. Mic modes for meetings: *live*, *muted*, and *push-to-talk* (mic stays - muted except while Space is held, releasing re-mutes). -4. A *master quick-mute* — one action mutes all output — reachable from the - faceplate and a keybind. -5. Instrument-console aesthetic and architecture consistent with net + bt: - same faceplate, lamps, engraved sections, console keys, needle gauges, - verify-everything contract. -6. The bar glyph reflects live state: speaker + three arcs normally, a - speaker-with-✕ when muted (Craig's called glyphs). - -* Design sketch - -Prototype: =working/sound-panel/sound-panel-prototype.html= (the reference for -layout + idioms below). - -** Surface (from the prototype) - -- *Faceplate* — status lamp, sound glyph, state word (PLAYBACK / MUTED), a - MUTED badge, the SND·01 unit label, and the *master quick-mute switch* - (same switch idiom as net wifi / bt power), plus the close ✕. -- *OUTPUTS section* — one row per sink. Row body click = set default (gold - DEF tag). A machined fader sets that sink's volume; the trailing glyph - mutes just that device. Active/default row is emphasized (cream name, gold - lamp/glyph). -- *INPUTS section* — one row per source, same idioms. -- *Mic mode* — three console keys: LIVE / MUTED / PUSH·TALK. Push-to-talk - keeps the mic muted (red IN needle) and un-mutes only while Space is held. -- *Twin VU needles* — output level + input level, the sound analog of net - throughput and bt battery gauges. Needle goes red when its side is muted. - -** Architecture — clone the net/bt panel stack - -- GTK4 + gtk4-layer-shell, Blueprint =.blp= → committed =.ui= (=make ui=, - dev-only build dep). -- Humble-object split: a GTK-free PanelModel presenter (unit-tested like the - net/bt PanelModels) + thin composite-widget pages. Backing actions in a - GTK-free =audio.py= that shells to the audio control layer (pactl / - wpctl / pulsemixer — pick below), TDD'd with fake binaries. -- One gated AT-SPI smoke (=run-panel-smoke.sh= pattern). -- Shared instrument-console palette CSS asset (the one net/bt/settings all - load) — do not duplicate the palette block. -- Code lives in dotfiles =audio/= sibling to =net/= (src-layout, tests in - =tests/audio/=). - -* Decisions (Craig) - -** DONE Audio control backend — pactl vs wpctl vs pulsemixer -CLOSED: [2026-07-03 Fri] -Resolved: =pactl= (the engine module is =pactl.py=). Both ratio and velox run -PipeWire with the pipewire-pulse compat layer and no PulseAudio daemon, so -pactl and wpctl hit the same graph — but =pactl -f json= gives structured, -name-addressable output where wpctl offers only a volatile-id tree. Reads go -through =pactl -f json list sinks|sources= + =get-default-*=; writes target -devices by stable name behind an argv-charset guard. - -** DONE Push-to-talk mechanism under Wayland (feasibility — phase 1) -CLOSED: [2026-07-03 Fri] -Resolved: route (a), Hyprland dynamic binds. The phase-1 spike confirmed all -three primitives on velox (Hyprland 0.55.4): =hyprctl keyword bind/unbind= -adds and removes a bind live, =bindr= fires on release, and =pactl -set-source-mute @DEFAULT_SOURCE@ 0|1= toggles the mic cleanly. =ptt.py= arms a -press bind (un-mute) + a bindr (re-mute) on entering PTT mode and unbinds on -leaving, so the talk key isn't grabbed globally otherwise. No evdev needed. -Documented behavior: while PTT is armed, the talk key is the talk key. - -** DONE Quick-mute keybind + scope -CLOSED: [2026-07-03 Fri] -Resolved: the XF86AudioMute hardware key (Super+Shift+M turned out to be taken -by the monocle-layout bind, so the spec's assumption was wrong). The mute key -now runs =audio quick-mute=, which mutes every output (master), not just the -default sink — identical on a single-sink machine, correct on a multi-sink -one. Also reachable from the faceplate master switch and the panel. Scope: -master mute of all sinks, with verify-after-apply per sink. - -** DONE Bar glyph click map -CLOSED: [2026-07-03 Fri] -Resolved with the low-regret wiring: kept the existing =pulseaudio= waybar -module (left-click mute, scroll volume — no regression) and repointed its -right-click from the retired pulsemixer scratchpad to =audio-panel=. So: left -= mute, right = open panel, scroll = volume. A fuller =custom/audio= indicator -(state-following speaker glyph + its own click map) is built and tested -(=indicator.py= + =waybar-audio=) but stays unwired until the new bar glyph -gets a live eyeball — the swap is a one-line waybar edit when Craig's ready. - -** DONE Fate of the existing audio affordances -CLOSED: [2026-07-03 Fri] -Resolved: Super+A repurposed from =pypr toggle audio= (the pulsemixer -scratchpad) to =audio-panel= — the panel is the primary audio UI now, so the -scratchpad is retired. Its definition still sits in the machine-local -=pyprland.toml= (not stowed) and can be deleted by hand. Kept: =pulseaudio= + -=pulseaudio#mic= waybar modules (glance + scroll + the mic-mute glance), -Super+M cycle, Super+Shift+A + XF86AudioMicMute mic-toggle. Changed: -XF86AudioMute → master quick-mute (see the quick-mute decision above). - -* Implementation phases - -1. Push-to-talk feasibility spike (decision above) — the one unknown; settle - the mechanism before committing the mic-mode design. -2. =audio.py= backings (list/get/set/mute/default for sinks + sources) — - pure engine, TDD with a fake audio backend. -3. PanelModel presenter (rows, default tracking, mic modes, master mute, - verify-after-apply) — unit-tested, no GTK. -4. Blueprint UI + sound bar glyph (normal / muted / ptt states) + open/close - wiring; shared palette css; AT-SPI smoke. -5. Bar-affordance consolidation per the decision above; retire the Super+A - scratchpad; keybinds. -- cgit v1.2.3