Files
Panama/docs/superpowers/specs/2026-08-24-accessibility-redesign.md
T

71 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Accessibility redesign — everything that's real
Approved mock: `home-mocks/accessibility.html` (scratchpad, :8642). Spec wins over mock on
conflict. Tabless leaf stays.
## Goals
1. **Magnifier keybinds**: Super+= / Super+- / Super+0 step the zoom from anywhere, through the
shell so the stored preference stays truthful and the OSD shows the level. Mechanism: the
binds call `qs ipc call accessibility zoom in|out|reset`; a new IPC target routes to
`Accessibility.stepZoom()`, which computes (×1.25 steps, clamp to the schema's 1.05.0),
commits through the normal verified-preference path, and posts the OSD. No new script; a
dead shell means dead zoom keys, which is honest (everything else in the shell is dead too).
2. **Reduce motion becomes true**: `Theme.qml`'s `dur*` tokens gate on
`Settings.animationsEnabled` (0 when off) so the bar/dock/OSD/panels genuinely still.
3. **Visual alerts**: new schema key `visualAlerts` (bool, def false, group `accessibility`);
when on, a one-shot screen-edge flash (per-screen overlay, single animation per event,
never looping) fires wherever `Notifs.playBell` decides a notification sounds (including
when the audible bell is skipped for `sound: false` apps? No — the flash follows the same
eligibility as the bell EXCEPT the eventSounds gate: visual alerts are for people who can't
hear the bell, so the flash fires on bell-eligible notifications even when event sounds are
off. Pin that.)
4. **Honest Orca control**: running state (pgrep poll on page open + after actions),
Start/Stop; the a11y-bus readiness line. No gsettings screen-reader toggle (gsd-owned,
inert — refused).
5. **The primitives get accessible**: `SliderRow`, `ToggleRow`, `SwitchRow`, `ActionRow`,
`ChoiceRow`, `SegmentRow`, `SettingRow` (activatable), `OptionPickerRow`, `PickerRow`
gain `Accessible.role`/`Accessible.name` (from label; detail as description),
`activeFocusOnTab` on the interactive element, key handling (Space/Enter activates,
Left/Right steps sliders and segments), and a visible focus indicator (the titlebar
close-button border pattern). No API or visual-at-rest changes.
6. **Page rebuilt** per mock: Vision / Motion / Hearing / Keyboard & pointer / Screen reader;
`dimStrength` gated on `dimInactive`; magnifier "1× is off" honesty (schema gains
`unit: "×"`-style display via the page detail — fix the dead `zeroLabel`); the honesty box
for sticky/slow/bounce with the probed-not-assumed copy; mono-audio NOT YET row; "Open
Keyboard" jump.
7. Cleanups: `DESKTOP-PARITY.md`'s stale AccessX claim corrected; search entries for
magnifier/zoom/orca/screen reader/high contrast/reduce motion/visual alerts.
Non-goals: mono audio (deferred with the on-page honesty), sticky/slow/bounce/hover/mouse
keys (refused with receipts), gsettings `enable-animations`/`screen-reader-enabled` writes
(inert), shell text scaling.
## Ownership
- **A**: `config/PreferenceSchema.qml` (visualAlerts; magnifierFactor detail/unit fix),
`config/dot/hypr/keybinds.lua` (three zoom binds — CHECK for collisions with existing
Super+=/-/0 binds first; pick free chords and update the mock copy via B if needed),
`shell.qml` (accessibility IPC target), `services/Accessibility.qml` (stepZoom, orcaRunning
+ start/stop, poll discipline), `services/Notifs.qml` (flash trigger signal per goal 3),
NEW `modules/notifications/VisualBell.qml` (+ per-screen wiring in shell.qml),
`config/dot/hypr/DESKTOP-PARITY.md` (stale claim), `services/OsdState.qml`/`OsdModel.js`
only if the zoom OSD needs a new kind (coordinate with C on osd-model-contract).
- **B**: the nine row primitives (accessibility additions only — zero API/visual-at-rest
change), `modules/settings/AccessibilityPage.qml` rebuild (+ any new components + qmldir).
Reuse KeycapChord for the chord display.
- **C**: `services/SettingsSearch.qml`, NEW `tests/quickshell/accessibility-contract` (page
structure; zoom IPC path commits through the verified-preference path and never calls
hyprctl keyword; visual bell one-shot — no `loops: Animation.Infinite`, no Timer-driven
repeat; flash follows bell eligibility but not the eventSounds gate; primitives carry
Accessible.name + activeFocusOnTab — sweep all nine files; Orca control uses process state,
never gsettings), `osd-model-contract` (zoom kind if added), reconcile any contract pinning
Theme durations or the primitives' file contents, backlog Phase 14, README count
(174 → 175 expected), docs/commands regen at the end (schema changed).
Hard rules: no live mutations (no zoom application, no orca start/stop, no gsettings writes,
no hyprctl keyword/reload); hermetic stubs only; valid QML at every save (primitives are used
by EVERY page — a broken SliderRow takes the whole settings app down, so B edits them one at
a time with a reload-check between each). B programs against A's pinned APIs; A updates this
spec before changing them.